source: Dev/trunk/js/sequencerScripts.js @ 182

Last change on this file since 182 was 182, checked in by fpvanagthoven, 13 years ago

Verder gewerkt aan alle scripts. Met uitzondering van:

  • savePipeline().js loopt nog vast
  • loadSession->updateSequencer->updateDividers() gaat niet goed als er geen steps in de pipeline zitten (bijvoorbeeld bij het maken van een nieuwe sessie). Nog check toevoegen of er ook echt wel steps zijn voordat de functie verder gaat naar het maken van een requestString en AJAX calls.
File size: 18.3 KB
Line 
1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5
6var sequencer = {   // GLOBAL VAR TO STORE SEQUENCER SETTINGS!
7    uid: "",                // The unique id of this sequencer (not DB related!). This will help to avoid global var conflicts. Assign this randomly! (STRING)
8    session: {              // Properties of the currently loaded session
9        title: "",              // Title or name (STRING)
10        uid: "",                // Database UID of the current session (STRING)
11        pipeline: {             // Pipeline
12            uids: [],               // Uids of objects in pipeline (STRING)
13            types: [],              // Types of objects in pipeline (STRING)
14            upToDate: []            // Whether or not object displays are up to date (BOOL)
15        }
16    },
17    state: {                // Operating state of the sequencer
18        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.
19        numSteps: 0,            // Number of steps currently drawn in the editor (not necessarily same as number of steps in pipeline!) (INTEGER)
20        loaded: false,          // Whether or not the sequencer content has been updated for the first time (BOOL)
21        selectedStep: {         // Properties of the currently selected step
22            uid: "",                // UID of this step (STRING)
23            index: null               // The 'index' of this step in the current sequencer view (NOT the pipeline!) (INTEGER)
24        }       
25    },
26    settings: {             // Various settings to determine the workings of the sequencer
27        content: {              // Properties related to the content view of the sequencer
28            contentType: "session", // Type of the loaded parent object
29            width: null,            // Width of the viewing area (INTEGER)
30            height: null,           // Height of the viewing area (INTEGER)
31            maxObjects: null,       // The maximum number of content elements to be displayed at once time (INTEGER)
32            orientation: "horizontal"        // Whether the editor should be a vertical or horizontal editor (STRING)
33        },
34        efficientUpdating: true // Whether or not to use selective querying of the database for new step objects. True will only refresh out-of-date steps, False will refresh the whole pipeline
35    }
36}
37
38
39function SubmitToolbox(type) {
40    deselectStep();
41    var c = "objectToCreate="+type;
42    var u = "createObject.php";
43       
44    newAjaxRequest(c, u, function(result) {
45        sequencer.session.pipeline.uids.push(removeNL(result.responseText));
46        sequencer.session.pipeline.types.push(type);
47        sequencer.session.pipeline.upToDate.push(false);
48        updateSequencer();
49    }, true);
50}
51
52function clickStep(uid) {
53    if (uid == sequencer.state.selectedStep.uid) {  // user deselected a currently selected step.
54        deselectStep();
55    }
56    else {
57        if (sequencer.state.selectedStep.uid != undefined && sequencer.state.selectedStep.uid != "") {
58            deselectStep();
59            selectStep(uid);
60        }
61        else {
62            selectStep(uid);
63        }       
64    }
65}
66
67function selectStep(uid) {
68    var element = document.getElementById(uid);
69    if (element) {
70        addClass(element, "selected");
71        var type = sequencer.session.pipeline.types[sequencer.session.pipeline.uids.indexOf(uid)];
72        ajaxInfoRequest(uid, document.getElementById("infoPanelContent"), type);
73        sequencer.state.selectedStep.uid = uid;
74        sequencer.state.selectedStep.index = null;  //Don't know how to do this yet.
75    }
76}
77
78function deleteStep() {
79    // check if a step is selected
80    if (sequencer.state.selectedStep.uid == null) {
81        return;
82    }
83    var uid = sequencer.state.selectedStep.uid;
84    // deselect the step to reset the info panel and selection code
85    deselectStep();
86    // splice the step's data from the pipeline
87    var index = sequencer.session.pipeline.uids.indexOf(uid);
88    if (index >= 0 && index < sequencer.session.pipeline.uids.length) {
89        sequencer.session.pipeline.uids.splice(index, 1);
90        sequencer.session.pipeline.types.splice(index, 1);
91        sequencer.session.pipeline.upToDate.splice(index, 1);
92        // Then delete the step visually
93        var element = document.getElementById(uid);
94        var divider;
95        if (!element.nextSibling) {
96            // the element is at the end of the pipeline
97            // therefore we remove the previous divider.
98            // Note: it could also be the only element left in the pipeline!
99            divider = (element.previousSibling) ? element.previousSibling : false;
100            if (divider != false) {
101                divider.parentNode.removeChild(divider);
102            }
103        }
104        else {
105            // the element is at any position except the last, therefore we remove the next divider
106            divider = (element.nextSibling) ? element.nextSibling : false;
107            if (divider != false) {
108                divider.parentNode.removeChild(divider);
109            }
110        }
111       
112        // Finally, remove the element itself.
113        element.parentNode.removeChild(element);
114        sequencer.state.numSteps--;
115       
116    }
117}
118
119function deselectStep() {
120    if (!sequencer.state.selectedStep.uid) return;
121    var element = document.getElementById(sequencer.state.selectedStep.uid);
122    removeClass(element, "selected");
123    sequencer.state.selectedStep.uid = null;
124    sequencer.state.selectedStep.index = null;
125    var infoPanel = document.getElementById("infoPanelContent");
126    while (infoPanel.firstChild) infoPanel.removeChild(infoPanel.firstChild);
127}
128
129function ajaxInfoRequest(uid, el, type) {
130    var c = "uid="+uid;
131    c += "&type="+type;
132    var u = "getInfo.php";
133    newAjaxRequest(c, u, function(result) {
134        el.innerHTML = result.responseText;
135    }, true);
136}
137
138function updateSequencer() {
139
140    /*
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 */
145    var content = document.getElementById("seqContentWrapper");
146    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
147        // First clear the entire content wrapper, just for safety and in case efficientUpdating is off
148        while (content.firstChild) {
149            content.removeChild(content.firstChild);
150        }
151        // Compose a request string - "uids=1,2,3&types=a,b,c"
152        var requestString = "uids=";
153        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]);
172        }, true);
173    }
174    else {
175        // Pack together all needed updates in one request string, insert responseText.firstChild whenever sequencer.session.pipeline.upToDate[i] == false
176        debugger;
177        var needsUpdating = new Array();
178        // Add steps that need updating to the needsUpdating array (index, uid, type).
179        for (var i = 0; i < sequencer.session.pipeline.uids.length; i++) {
180            if (sequencer.session.pipeline.upToDate[i] == true) continue;
181            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=";
185        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 commas
189        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 commas
194       
195        // perform the AJAX request
196        newAjaxRequest(requestString, "returnStep.php", function(result) {
197            insertNewSteps(result.responseText, needsUpdating);
198        }, true);
199    }
200   
201}
202
203function loadSequencer() {
204    /*
205     * Description:
206     * Load data from hidden fields (put there by PHP), store them in the global var "sequencer" (as well as several initialization properties),
207     * then remove the hidden fields from the HTML document tree.
208     */
209   
210    // Load hidden fields and set required properties in global object var.
211    try {
212       
213        var fPipelineString = document.getElementById("pipelineStringField");
214        var fPipelineTypes = document.getElementById("pipelineTypeField");
215        var fSessionUid = document.getElementById("sessionField");
216        var fSessionTitle = document.getElementById("sessionTitleField");
217   
218        sequencer.session.title = fSessionTitle.value;
219        sequencer.session.uid = fSessionUid.value;
220        sequencer.session.pipeline.uids = stringToArray(fPipelineString.value, ",");
221        sequencer.session.pipeline.types = stringToArray(fPipelineTypes.value, ",");
222        sequencer.session.pipeline.upToDate = new Array();
223       
224        for (var i = 0; i < sequencer.session.pipeline.uids.length; i++) {
225            sequencer.session.pipeline.upToDate.push(true);
226        }
227        sequencer.state.numSteps = 0;
228        sequencer.state.loaded = false;
229        sequencer.settings.content.orientation = "h";
230        sequencer.settings.efficientUpdating = true;
231    }
232    catch (e) {
233        // Alert developer of any errors while setting these variables
234        for (error in e) alert(error.message);
235    }
236   
237    // Then remove the hidden fields from the HTML document
238    var hiddenInputs = document.getElementById("hiddenInputs");
239    hiddenInputs.parentNode.removeChild(hiddenInputs);
240   
241    console.log(sequencer);
242    // finally, run updateSequencer to refresh the visual display of the pipeline
243   
244    updateSequencer();
245}
246
247function insertNewSteps(responseText, needsUpdating) {
248    debugger;
249    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
276function 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);
287   
288    for (var i = 0; i < response.length; i++) {
289        var tempDiv = document.createElement("div");
290        tempDiv.id = response.id;
291        tempDiv.className = "displayStep";
292        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);
298        var divLabel = document.createElement("p");
299        divLabel.innerHTML = response.title;
300        tempDiv.appendChild(divLabel);
301       
302        // 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;
305            if (needsUpdating[j][0] > sequencer.state.numSteps-1) {
306                content.appendChild(tempDiv);
307            }
308            else {
309                content.replaceChild(tempDiv, content.childNodes[j][0]*2);
310            }
311        }
312    }
313}
314
315function updateDividers() {
316    var content = document.getElementById("seqContentWrapper");
317    for (var i = 0; i < content.childNodes.length; i++) {
318        var element = content.childNodes[i];
319        if (!hasClass(element, "displayStep")) {
320            continue;
321        }
322        var lastElement = (element.previousSibling && element.previousSibling.nodeName == "DIV") ? element.previousSibling : false;
323        var nextElement = (element.nextSibling && element.nextSibling.nodeName == "DIV") ? element.nextSibling : false;
324        if (lastElement != false) {
325            if (!hasClass(lastElement, "divider")){
326                var newDivider = document.createElement("div");
327                addClass(newDivider, "divider");
328                addClass(newDivider, sequencer.settings.content.orientation);
329                content.insertBefore(newDivider, element);
330                delete newDivider;
331            }
332        }
333        if (nextElement != false) {
334            if (!hasClass(nextElement, "divider")){
335                var newDivider = document.createElement("div");
336                addClass(newDivider, "divider");
337                addClass(newDivider, sequencer.settings.content.orientation);
338                content.insertBefore(newDivider, nextElement);
339                delete newDivider;
340            }
341        }
342    }
343}
344
345function savePipeline (confirmSave) {
346    var answer;
347    if (confirmSave == true) {
348        answer = confirm("Save changes to pipeline?");
349    }
350    else {
351        answer = true;
352    }
353    if (answer == false) return;
354   
355    var requestString = "uids=";
356    requestString += arrayToString(sequencer.session.pipeline.uids, ",");
357    requestString += "&types=";
358    requestString += arrayToString(sequencer.session.pipeline.types, ",");
359    requestString += "&sessionUid=";
360    requestString += sequencer.session.uid;
361    newAjaxRequest(requestString, "savePipeline.php", function(result){
362        console.log(result.responseText);
363    }, true);
364}
365
366function editStep() {
367    // first save
368   
369    //savePipeline(false);
370   
371    var postForm = document.createElement("form");
372    var type = sequencer.session.pipeline.types[sequencer.session.pipeline.uids.indexOf(sequencer.state.selectedStep.uid)];
373    postForm.action = type.toLowerCase()+"Editor.php";
374    postForm.method = "POST";
375    var objectUid = document.createElement("input");
376    objectUid.type = "hidden";
377    objectUid.name = "objectUid";
378    objectUid.value = sequencer.state.selectedStep.uid;
379    postForm.appendChild(objectUid);
380    postForm.submit();
381}
382
383function moveStep (direction) {
384    // Check if a step is selected
385   
386    if (sequencer.state.selectedStep.uid == null || direction == null) return;
387    // Check if the step is not at either end of the pipeline
388    var index = sequencer.session.pipeline.uids.indexOf(sequencer.state.selectedStep.uid);
389    if ((index < 0) || (index >= sequencer.session.pipeline.uids.length) || (index == 0 && direction == -1) || (index == sequencer.session.pipeline.uids.length - 1 && direction == 1)) {
390        alert("Cannot move out of bounds!");
391        return;
392    }
393   
394    // Find the two elements in the editor content display
395    var content = document.getElementById("seqContentWrapper");
396    var element = document.getElementById(sequencer.session.pipeline.uids[index]);
397    var otherElement = document.getElementById(sequencer.session.pipeline.uids[index+direction]);
398    // First buffer the two elements
399    var tempElement = element.cloneNode(true);
400    var tempOtherElement = otherElement.cloneNode(true);
401    var placeHolderElement = document.createElement("div");
402    placeHolderElement.id = "placeholder_element";
403    content.replaceChild(placeHolderElement, otherElement);
404    content.replaceChild(tempOtherElement, element);
405    content.replaceChild(tempElement, placeHolderElement);
406    //This should work.
407    // A-B     Start positions, backup to tA and tB
408    // A-X     Replace B with placeholder X
409    // B-X     Replace A with tB
410    // B-A     Replace placeholder X with tA.
411    // The two elements are now swapped.
412     
413    // Now swap the array entries.
414    sequencer.session.pipeline.uids[index] = sequencer.session.pipeline.uids.splice(index+direction, 1, sequencer.session.pipeline.uids[index])[0];
415    sequencer.session.pipeline.types[index] = sequencer.session.pipeline.types.splice(index+direction, 1, sequencer.session.pipeline.types[index])[0];
416     
417}
Note: See TracBrowser for help on using the repository browser.