update_input.js 13.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
(function(requirejs, require, define) {
    define([], function() {
        return {
            'check': check,
            'update': update
        };

        function update(state) {
            var draggables, tempObj;

            draggables = [];

            if (state.config.individualTargets === false) {
                (function(c1) {
                    while (c1 < state.draggables.length) {
                        if (state.draggables[c1].x !== -1) {
17
                            tempObj = {};
18 19 20 21
                            tempObj[state.draggables[c1].id] = [
                                state.draggables[c1].x,
                                state.draggables[c1].y
                            ];
22 23 24
                            draggables.push(tempObj);
                            tempObj = null;
                        }
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
                        c1 += 1;
                    }
                }(0));
            } else {
                (function(c1) {
                    while (c1 < state.targets.length) {
                        (function(c2) {
                            while (c2 < state.targets[c1].draggableList.length) {
                                tempObj = {};

                                if (state.targets[c1].type === 'base') {
                                    tempObj[state.targets[c1].draggableList[c2].id] = state.targets[c1].id;
                                } else {
                                    addTargetRecursively(tempObj, state.targets[c1].draggableList[c2], state.targets[c1]);
                                }
                                draggables.push(tempObj);
                                tempObj = null;

                                c2 += 1;
                            }
                        }(0));
47

48 49 50 51 52 53 54
                        c1 += 1;
                    }
                }(0));
            }

            $('#input_' + state.problemId).val(JSON.stringify(draggables));
        }
55

56 57 58 59 60 61
        function addTargetRecursively(tempObj, draggable, target) {
            if (target.type === 'base') {
                tempObj[draggable.id] = target.id;
            } else {
                tempObj[draggable.id] = {};
                tempObj[draggable.id][target.id] = {};
62

63 64
                addTargetRecursively(tempObj[draggable.id][target.id], target.draggableObj, target.draggableObj.onTarget);
            }
65
        }
66

67 68
    // Check if input has an answer from server. If yes, then position
    // all draggables according to answer.
69 70
        function check(state) {
            var inputElVal;
71

72
            inputElVal = $('#input_' + state.problemId).val();
73

74 75 76
            if (inputElVal.length === 0) {
                return false;
            }
77

78
            repositionDraggables(state, JSON.parse(inputElVal));
79

80 81
            return true;
        }
82

83 84 85 86
        function processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i) {
            var baseDraggableId, baseDraggable, baseTargetId, baseTarget,
                layeredDraggableId, layeredDraggable, layeredTargetId, layeredTarget,
                chain;
87

88
            if (depth === 0) {
89
            // We are at the lowest depth? The end.
90

91 92
                return;
            }
93

94
            if (answerSortedByDepth.hasOwnProperty(depth) === false) {
95
            // We have a depth that ts not valid, we decrease the depth by one.
96
                processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
97

98 99
                return;
            }
100

101
            if (answerSortedByDepth[depth].length <= i) {
102
            // We ran out of answers at this depth, go to the next depth down.
103
                processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
104

105 106
                return;
            }
107

108
            chain = answerSortedByDepth[depth][i];
109

110
            baseDraggableId = Object.keys(chain)[0];
111

112
        // This is a hack. For now we will work with depths 1 and 3.
113 114
            if (depth === 1) {
                baseTargetId = chain[baseDraggableId];
115

116 117
                layeredTargetId = null;
                layeredDraggableId = null;
118

119
            // createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId);
120 121
            } else if (depth === 3) {
                layeredDraggableId = baseDraggableId;
122

123
                layeredTargetId = Object.keys(chain[layeredDraggableId])[0];
124

125
                baseDraggableId = Object.keys(chain[layeredDraggableId][layeredTargetId])[0];
126

127 128
                baseTargetId = chain[layeredDraggableId][layeredTargetId][baseDraggableId];
            }
129

130
            checkBaseDraggable();
131

132
            return;
133

134 135 136 137 138
            function checkBaseDraggable() {
                if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
                    createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId, true, function() {
                        if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
                            console.log('ERROR: Could not successfully create a base draggable on a base target.');
139
                        } else {
140
                            baseTarget = baseDraggable.onTarget;
141

142 143 144 145 146 147 148
                            if ((layeredTargetId === null) || (layeredDraggableId === null)) {
                                processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
                            } else {
                                checklayeredDraggable();
                            }
                        }
                    });
149
                } else {
150 151 152 153 154 155 156
                    baseTarget = baseDraggable.onTarget;

                    if ((layeredTargetId === null) || (layeredDraggableId === null)) {
                        processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
                    } else {
                        checklayeredDraggable();
                    }
157 158
                }
            }
159

160 161 162 163 164 165 166 167
            function checklayeredDraggable() {
                if ((layeredDraggable = getById(state, 'draggables', layeredDraggableId, null, false, layeredTargetId, baseDraggableId, baseTargetId)) === null) {
                    layeredDraggable = getById(state, 'draggables', layeredDraggableId);
                    layeredTarget = null;
                    baseDraggable.targetField.every(function(target) {
                        if (target.id === layeredTargetId) {
                            layeredTarget = target;
                        }
168

169 170
                        return true;
                    });
171

172 173 174 175 176
                    if ((layeredDraggable !== null) && (layeredTarget !== null)) {
                        layeredDraggable.moveDraggableTo('target', layeredTarget, function() {
                            processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
                        });
                    } else {
177
                        processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
178
                    }
179 180
                } else {
                    processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
181
                }
182 183
            }
        }
184

185 186
        function createBaseDraggableOnTarget(state, draggableId, targetId, reportError, funcCallback) {
            var draggable, target;
187

188 189 190
            if ((draggable = getById(state, 'draggables', draggableId)) === null) {
                if (reportError !== false) {
                    console.log(
191 192 193 194
                    'ERROR: In answer there exists a ' +
                    'draggable ID "' + draggableId + '". No ' +
                    'draggable with this ID could be found.'
                );
195
                }
196

197 198
                return false;
            }
199

200 201 202
            if ((target = getById(state, 'targets', targetId)) === null) {
                if (reportError !== false) {
                    console.log(
203 204 205 206
                    'ERROR: In answer there exists a target ' +
                    'ID "' + targetId + '". No target with this ' +
                    'ID could be found.'
                );
207
                }
208

209 210
                return false;
            }
211

212
            draggable.moveDraggableTo('target', target, funcCallback);
213

214 215
            return true;
        }
216

217 218
        function processAnswerPositions(state, answer) {
            var draggableId, draggable;
219

220 221 222 223 224 225
            (function(c1) {
                while (c1 < answer.length) {
                    for (draggableId in answer[c1]) {
                        if (answer[c1].hasOwnProperty(draggableId) === false) {
                            continue;
                        }
226

227 228
                        if ((draggable = getById(state, 'draggables', draggableId)) === null) {
                            console.log(
229 230 231 232 233
                            'ERROR: In answer there exists a ' +
                            'draggable ID "' + draggableId + '". No ' +
                            'draggable with this ID could be found.'
                        );

234 235 236 237 238 239 240
                            continue;
                        }

                        draggable.moveDraggableTo('XY', {
                            'x': answer[c1][draggableId][0],
                            'y': answer[c1][draggableId][1]
                        });
241 242
                    }

243
                    c1 += 1;
244
                }
245 246
            }(0));
        }
247

248 249
        function repositionDraggables(state, answer) {
            var answerSortedByDepth, minDepth, maxDepth;
250

251 252 253
            answerSortedByDepth = {};
            minDepth = 1000;
            maxDepth = 0;
254

255 256
            answer.every(function(chain) {
                var depth;
257

258
                depth = findDepth(chain, 0);
259

260 261 262 263 264 265
                if (depth < minDepth) {
                    minDepth = depth;
                }
                if (depth > maxDepth) {
                    maxDepth = depth;
                }
266

267 268 269
                if (answerSortedByDepth.hasOwnProperty(depth) === false) {
                    answerSortedByDepth[depth] = [];
                }
270

271
                answerSortedByDepth[depth].push(chain);
272

273 274
                return true;
            });
275

276 277 278
            if (answer.length === 0) {
                return;
            }
279

280
        // For now we support only one case.
281 282 283
            if ((minDepth < 1) || (maxDepth > 3)) {
                return;
            }
284

285 286 287 288 289
            if (state.config.individualTargets === true) {
                processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, maxDepth, 0);
            } else if (state.config.individualTargets === false) {
                processAnswerPositions(state, answer);
            }
290
        }
291

292 293
        function findDepth(tempObj, depth) {
            var i;
294

295 296 297
            if ($.isPlainObject(tempObj) === false) {
                return depth;
            }
298

299
            depth += 1;
300

301 302 303 304
            for (i in tempObj) {
                if (tempObj.hasOwnProperty(i) === true) {
                    depth = findDepth(tempObj[i], depth);
                }
305 306
            }

307 308
            return depth;
        }
309

310 311 312 313 314 315
        function getById(state, type, id, fromTargetField, inContainer, targetId, baseDraggableId, baseTargetId) {
            return (function(c1) {
                while (c1 < state[type].length) {
                    if (type === 'draggables') {
                        if ((targetId !== undefined) && (inContainer === false) && (baseDraggableId !== undefined) && (baseTargetId !== undefined)) {
                            if (
316 317 318 319 320 321 322
                            (state[type][c1].id === id) &&
                            (state[type][c1].inContainer === false) &&
                            (state[type][c1].onTarget.id === targetId) &&
                            (state[type][c1].onTarget.type === 'on_drag') &&
                            (state[type][c1].onTarget.draggableObj.id === baseDraggableId) &&
                            (state[type][c1].onTarget.draggableObj.onTarget.id === baseTargetId)
                        ) {
323 324 325 326
                                return state[type][c1];
                            }
                        } else if ((targetId !== undefined) && (inContainer === false)) {
                            if (
327 328 329 330
                            (state[type][c1].id === id) &&
                            (state[type][c1].inContainer === false) &&
                            (state[type][c1].onTarget.id === targetId)
                        ) {
331 332 333 334 335 336 337 338 339 340 341 342
                                return state[type][c1];
                            }
                        } else {
                            if (inContainer === false) {
                                if ((state[type][c1].id === id) && (state[type][c1].inContainer === false)) {
                                    return state[type][c1];
                                }
                            } else {
                                if ((state[type][c1].id === id) && (state[type][c1].inContainer === true)) {
                                    return state[type][c1];
                                }
                            }
343
                        }
344 345 346
                    } else { // 'targets'
                        if (fromTargetField === true) {
                            if ((state[type][c1].id === id) && (state[type][c1].type === 'on_drag')) {
347 348 349
                                return state[type][c1];
                            }
                        } else {
350
                            if ((state[type][c1].id === id) && (state[type][c1].type === 'base')) {
351 352 353
                                return state[type][c1];
                            }
                        }
354 355
                    }

356 357
                    c1 += 1;
                }
358

359 360 361 362
                return null;
            }(0));
        }
    }); // End-of: define([], function () {
363
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {