Subversion Repositories oidplus

Rev

Rev 1289 | Rev 1349 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 daniel-mar 1
/*
2
 * OIDplus 2.0
781 daniel-mar 3
 * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
4 daniel-mar 4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
 
9 daniel-mar 18
/*jshint esversion: 6 */
19
 
219 daniel-mar 20
// $('#html').jstree();
21
 
833 daniel-mar 22
var bs5Utils = undefined;
23
 
219 daniel-mar 24
var current_node = "";
25
var popstate_running = false;
362 daniel-mar 26
// DEFAULT_LANGUAGE will be set by oidplus.min.js.php
360 daniel-mar 27
// language_messages will be set by oidplus.min.js.php
28
// language_tblprefix will be set by oidplus.min.js.php
424 daniel-mar 29
// csrf_token will be set by oidplus.min.js.php
561 daniel-mar 30
// samesite_policy will bet set by oidplus.min.js.php
219 daniel-mar 31
 
399 daniel-mar 32
var pageChangeCallbacks = [];
33
var pageChangeRequestCallbacks = [];
34
 
839 daniel-mar 35
var pageLoadedCallbacks= {
876 daniel-mar 36
        "anyPageLoad":         [], // this is processed inside both AJAX successful reload and document.ready (at the very end)
839 daniel-mar 37
        "ajaxPageLoad":        [], // inside AJAX successful reload only
38
        "documentReadyBefore": [], // inside document.ready, in the very beginning of the function
39
        "documentReadyAfter":  []  // inside document.ready, in the very end of the function
40
};
833 daniel-mar 41
 
819 daniel-mar 42
var oidplus_menu_width = 450; // In pixels. You can change this at runtime because of the glayoutWorkaroundB() workaround
818 daniel-mar 43
 
839 daniel-mar 44
function executeAllCallbacks(functionsArray) {
45
        functionsArray.forEach(
46
                function(fel) {
47
                        if (typeof fel == 'function') fel();
48
                }
49
        );
50
}
51
 
112 daniel-mar 52
function getOidPlusSystemTitle() {
360 daniel-mar 53
        return getMeta('OIDplus-SystemTitle'); // do not translate
112 daniel-mar 54
}
55
 
5 daniel-mar 56
function combine_systemtitle_and_pagetitle(systemtitle, pagetitle) {
309 daniel-mar 57
        // Please also change the function in index.php
5 daniel-mar 58
        if (systemtitle == pagetitle) {
59
                return systemtitle;
60
        } else {
309 daniel-mar 61
                return pagetitle + ' - ' + systemtitle;
5 daniel-mar 62
        }
63
}
64
 
385 daniel-mar 65
function getSystemUrl(relative) {
1287 daniel-mar 66
        relative = (typeof relative === 'undefined') ? false : relative; // do not translate
385 daniel-mar 67
        var url = new URL(window.location.href);
1287 daniel-mar 68
        var res = relative ? url.pathname : url.href.substr(0, url.href.length-url.search.length);
69
        if (res.endsWith("index.php")) res = res.substring(0, res.lastIndexOf('/')) + "/";
70
        return res;
385 daniel-mar 71
}
72
 
2 daniel-mar 73
function getTreeLoadURL() {
74
        var url = new URL(window.location.href);
75
        var goto = url.searchParams.get("goto");
641 daniel-mar 76
        return (goto != null) ? "ajax.php?csrf_token="+encodeURIComponent(csrf_token)+"&action=tree_load&anticache="+Date.now()+"&goto="+encodeURIComponent(goto)
77
                              : "ajax.php?csrf_token="+encodeURIComponent(csrf_token)+"&action=tree_load&anticache="+Date.now();
2 daniel-mar 78
}
79
 
80
function reloadContent() {
154 daniel-mar 81
        // window.location.href = "?goto="+encodeURIComponent(current_node);
399 daniel-mar 82
        if (openOidInPanel(current_node, false)) {
450 daniel-mar 83
                if(!$('#oidtree').jstree(true).get_node(current_node)) {
84
                        // Avoid that a language change at "oidplus:srvreg_status" won't redirect the user to "oidplus:srv_registration" because of the reselection during refresh
85
                        $('#oidtree').jstree("deselect_all");
86
                }
87
 
399 daniel-mar 88
                $('#oidtree').jstree("refresh");
89
        }
2 daniel-mar 90
}
91
 
107 daniel-mar 92
function x_rec(x_data, i) {
93
        $('#oidtree').jstree('open_node', x_data[i], function(e, data) {
94
                if (i+1 < x_data.length) {
95
                        x_rec(x_data, i+1);
96
                } else {
114 daniel-mar 97
                        popstate_running = true; // don't call openOidInPanel again
98
                        try {
99
                                $('#oidtree').jstree('select_node', x_data[i]);
100
                        } catch (err) {
101
                                popstate_running = false;
102
                        } finally {
103
                                popstate_running = false;
104
                        }
107 daniel-mar 105
                }
106
        });
107
}
2 daniel-mar 108
 
399 daniel-mar 109
function performCloseQueryCB() {
110
        for (var i=0; i<pageChangeRequestCallbacks.length; i++) {
111
                if (!pageChangeRequestCallbacks[i][0](pageChangeRequestCallbacks[i][1])) return false;
112
        }
113
        pageChangeRequestCallbacks = [];
114
        return true; // may close
115
}
116
 
117
function performCloseCB() {
118
        for (var i=0; i<pageChangeCallbacks.length; i++) {
119
                pageChangeCallbacks[i][0](pageChangeCallbacks[i][1]);
120
        }
121
        pageChangeCallbacks = [];
122
}
123
 
124
function openOidInPanel(id, reselect/*=false*/, anchor/*=''*/, force/*=false*/) {
699 daniel-mar 125
        reselect = (typeof reselect === 'undefined') ? false : reselect; // do not translate
126
        anchor = (typeof anchor === 'undefined') ? '' : anchor; // do not translate
127
        force = (typeof force === 'undefined') ? false : force; // do not translate
150 daniel-mar 128
 
399 daniel-mar 129
        var mayClose = performCloseQueryCB();
130
        if (!force && !mayClose) return false;
131
 
132
        performCloseCB();
405 daniel-mar 133
 
704 daniel-mar 134
        $.xhrPool.abortAll();
135
 
107 daniel-mar 136
        if (reselect) {
2 daniel-mar 137
                $('#oidtree').jstree('deselect_all');
107 daniel-mar 138
 
114 daniel-mar 139
                popstate_running = true; // don't call openOidInPanel during tree selection
140
                try {
141
                        // If the node is already loaded in the tree, select it
142
                        if (!$('#oidtree').jstree('select_node', id)) {
143
                                // If the node is not loaded, then we try to search it.
144
                                // If it can be found, then open all parent nodes and select the node
145
                                $.ajax({
146
                                        url:"ajax.php",
147
                                        method:"POST",
544 daniel-mar 148
                                        beforeSend: function(jqXHR, settings) {
704 daniel-mar 149
                                                //$.xhrPool.abortAll();
544 daniel-mar 150
                                                $.xhrPool.add(jqXHR);
151
                                        },
152
                                        complete: function(jqXHR, text) {
153
                                                $.xhrPool.remove(jqXHR);
154
                                        },
114 daniel-mar 155
                                        data:{
424 daniel-mar 156
                                                csrf_token:csrf_token,
114 daniel-mar 157
                                                action:"tree_search",
641 daniel-mar 158
                                                search:id,
159
                                                anticache:Date.now()
114 daniel-mar 160
                                        },
161
                                        error:function(jqXHR, textStatus, errorThrown) {
544 daniel-mar 162
                                                if (errorThrown == "abort") return;
797 daniel-mar 163
                                                console.error("Tree search failed");
360 daniel-mar 164
                                                console.error(_L("Error: %1",errorThrown));
114 daniel-mar 165
                                        },
166
                                        success:function(data) {
167
                                                if ("error" in data) {
797 daniel-mar 168
                                                        console.error("Tree search failed");
114 daniel-mar 169
                                                        console.error(data);
170
                                                } else if ((data instanceof Array) && (data.length > 0)) {
171
                                                        x_rec(data, 0);
172
                                                } else {
797 daniel-mar 173
                                                        console.error("Tree search failed");
114 daniel-mar 174
                                                        console.error(data);
175
                                                }
176
                                        }
177
                                });
107 daniel-mar 178
                        }
114 daniel-mar 179
                } catch (err) {
180
                        popstate_running = false;
181
                } finally {
182
                        popstate_running = false;
183
                }
2 daniel-mar 184
        }
185
 
114 daniel-mar 186
        // This loads the actual content
187
 
405 daniel-mar 188
        // document.title = ""; // <-- we may not do this, otherwise Firefox won't
189
        //                            show titles in the browser history (right-click
190
        //                            on back-button), although document.title() is
499 daniel-mar 191
        //                            set inside the AJAX-callback [Firefox bug?!]
405 daniel-mar 192
 
2 daniel-mar 193
        $('#real_title').html("&nbsp;");
355 daniel-mar 194
        $('#real_content').html(_L("Loading..."));
1289 daniel-mar 195
        $('#static_link').attr("href", oidplus_webpath_absolute_canonical+"?goto="+encodeURIComponent(id));
183 daniel-mar 196
        $("#gotoedit").val(id);
2 daniel-mar 197
 
198
        // Normal opening of a description
560 daniel-mar 199
        $.ajax({
200
                url:"ajax.php",
201
                method:"GET",
202
                beforeSend: function(jqXHR, settings) {
704 daniel-mar 203
                        //$.xhrPool.abortAll();
560 daniel-mar 204
                        $.xhrPool.add(jqXHR);
205
                },
206
                complete: function(jqXHR, text) {
207
                        $.xhrPool.remove(jqXHR);
208
                },
209
                data:{
210
                        csrf_token:csrf_token,
211
                        action:"get_description",
641 daniel-mar 212
                        id:id,
213
                        anticache:Date.now()
560 daniel-mar 214
                },
215
                error:function(jqXHR, textStatus, errorThrown) {
216
                        if (errorThrown == "abort") return;
833 daniel-mar 217
                        alertError(_L("Failed to load content: %1",errorThrown));
560 daniel-mar 218
                        console.error(_L("Error: %1",errorThrown));
219
                },
220
                success:function(data) {
1292 daniel-mar 221
                        // TODO: Use oidplus_ajax_success(), since this checks the existance of "error" in data, and checks if status>=0
107 daniel-mar 222
                        if ("error" in data) {
833 daniel-mar 223
                                alertError(_L("Failed to load content: %1",data.error));
107 daniel-mar 224
                                console.error(data.error);
560 daniel-mar 225
                        } else if (data.status >= 0) {
226
                                data.id = id;
107 daniel-mar 227
 
560 daniel-mar 228
                                var state = {
229
                                        "node_id":id,
230
                                        "titleHTML":(data.icon ? '<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' : '') + data.title.htmlentities(),
231
                                        "textHTML":data.text,
1289 daniel-mar 232
                                        "staticlinkHREF":oidplus_webpath_absolute_canonical+"?goto="+encodeURIComponent(id),
560 daniel-mar 233
                                };
234
                                if (current_node != id) {
235
                                        window.history.pushState(state, data.title, "?goto="+encodeURIComponent(id));
236
                                } else {
237
                                        window.history.replaceState(state, data.title, "?goto="+encodeURIComponent(id));
238
                                }
2 daniel-mar 239
 
560 daniel-mar 240
                                document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
2 daniel-mar 241
 
560 daniel-mar 242
                                if (data.icon) {
243
                                        $('#real_title').html('<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' + data.title.htmlentities());
244
                                } else {
245
                                        $('#real_title').html(data.title.htmlentities());
246
                                }
247
                                $('#real_content').html(data.text);
248
                                document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
249
                                current_node = id;
405 daniel-mar 250
 
839 daniel-mar 251
                                executeAllCallbacks(pageLoadedCallbacks.anyPageLoad);
252
                                executeAllCallbacks(pageLoadedCallbacks.ajaxPageLoad);
833 daniel-mar 253
 
560 daniel-mar 254
                                if (anchor != '') {
255
                                        jumpToAnchor(anchor);
256
                                }
32 daniel-mar 257
                        } else {
833 daniel-mar 258
                                alertError(_L("Failed to load content: %1",data.status));
560 daniel-mar 259
                                console.error(data);
32 daniel-mar 260
                        }
560 daniel-mar 261
                }
2 daniel-mar 262
        });
399 daniel-mar 263
 
264
        return true;
2 daniel-mar 265
}
266
 
107 daniel-mar 267
// This function opens the "parentID" node, and then selects the "childID" node (which should be beneath the parent node)
2 daniel-mar 268
function openAndSelectNode(childID, parentID) {
269
        if ($('#oidtree').jstree(true).get_node(parentID)) {
107 daniel-mar 270
                $('#oidtree').jstree('open_node', parentID, function(e, data) { // open parent node
2 daniel-mar 271
                        if ($('#oidtree').jstree(true).get_node(childID)) { // is the child there?
107 daniel-mar 272
                                $('#oidtree').jstree('deselect_all').jstree('select_node', childID); // select it
2 daniel-mar 273
                        } else {
274
                                // This can happen if the content page contains brand new items which are not in the treeview yet
183 daniel-mar 275
                                $("#gotoedit").val(childID);
154 daniel-mar 276
                                window.location.href = "?goto="+encodeURIComponent(childID);
2 daniel-mar 277
                        }
278
                }, true);
279
        } else {
280
                // This should usually not happen
183 daniel-mar 281
                $("#gotoedit").val(childID);
154 daniel-mar 282
                window.location.href = "?goto="+encodeURIComponent(childID);
2 daniel-mar 283
        }
284
}
285
 
286
$(window).on("popstate", function(e) {
399 daniel-mar 287
        if (!performCloseQueryCB()) {
288
                // TODO: does not work!!! The "back/forward" action will be cancelled, but the browser still thinks it was successful,
289
                // so if you do it again, you will then jump 2 pages back, etc!
290
                // This does also not help:
291
                //window.history.pushState(e.originalEvent.state, e.originalEvent.title, e.originalEvent.url);
292
                //window.history.forward();
293
                return;
294
        }
295
 
2 daniel-mar 296
        popstate_running = true;
297
        try {
298
                var data = e.originalEvent.state;
299
 
300
                current_node = data.node_id;
327 daniel-mar 301
                $("#gotoedit").val(current_node);
107 daniel-mar 302
                $('#oidtree').jstree('deselect_all').jstree('select_node', data.node_id);
2 daniel-mar 303
                $('#real_title').html(data.titleHTML);
304
                $('#real_content').html(data.textHTML);
305
                $('#static_link').attr("href", data.staticlinkHREF);
112 daniel-mar 306
                document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.titleHTML.html_entity_decode());
2 daniel-mar 307
        } catch (err) {
308
                popstate_running = false;
309
        } finally {
310
                popstate_running = false;
311
        }
312
});
313
 
314
$(document).ready(function () {
876 daniel-mar 315
 
839 daniel-mar 316
        executeAllCallbacks(pageLoadedCallbacks.documentReadyBefore);
876 daniel-mar 317
 
399 daniel-mar 318
        /*
319
        window.onbeforeunload = function(e) {
320
                // TODO: This won't be called because TinyMCE overrides it??
321
                // TODO: when the user accepted the query in performCloseQueryCB(), then the message will be shown again by the browser!
322
                if (!performCloseQueryCB()) {
323
                        // Cancel the event
324
                        e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
325
                        // Chrome requires returnValue to be set
326
                        e.returnValue = '';
327
                } else {
328
                        // the absence of a returnValue property on the event will guarantee the browser unload happens
329
                        delete e['returnValue'];
330
                }
331
        };
332
        */
214 daniel-mar 333
 
829 daniel-mar 334
        if (typeof oidplus_menu_width_uservalue !== 'undefined') {
335
                oidplus_menu_width = oidplus_menu_width_uservalue;
336
        }
337
 
2 daniel-mar 338
        // --- JsTree
339
 
1055 daniel-mar 340
        if ($('#oidtree').length > 0) $('#oidtree')
2 daniel-mar 341
        .jstree({
342
                plugins: ['massload','search','conditionalselect'],
343
                'core' : {
344
                        'data' : {
345
                                "url" : getTreeLoadURL(),
346
                                "data" : function (node) {
347
                                        return { "id" : node.id };
348
                                }
349
                        },
350
                        "multiple": false
351
                },
352
                'conditionalselect' : function (node) {
68 daniel-mar 353
                        if (node.original.conditionalselect !== undefined) {
354
                                return eval(node.original.conditionalselect);
2 daniel-mar 355
                        } else {
399 daniel-mar 356
                                return performCloseQueryCB();
2 daniel-mar 357
                        }
358
                },
359
        })
360
        .on('ready.jstree', function (e, data) {
361
                var url = new URL(window.location.href);
362
                var goto = url.searchParams.get("goto");
363
                if (goto == null) goto = "oidplus:system"; // the page was not called with ?goto=...
1055 daniel-mar 364
                if ($('#gotoedit').length > 0) $("#gotoedit").val(goto);
2 daniel-mar 365
 
107 daniel-mar 366
                // By setting current_node, select_node() will not cause ajax.php?action=get_description to load (since we already loaded the first static content via PHP, for search engines mainly)
2 daniel-mar 367
                // But then we need to set the history state manually
368
                current_node = goto;
100 daniel-mar 369
                window.history.replaceState({
107 daniel-mar 370
                        "node_id":goto,
100 daniel-mar 371
                        "titleHTML":$('#real_title').html(),
372
                        "textHTML":$('#real_content').html(),
1289 daniel-mar 373
                        "staticlinkHREF":oidplus_webpath_absolute_canonical+"?goto="+encodeURIComponent(goto),
113 daniel-mar 374
                }, $('#real_title').html(), "?goto="+encodeURIComponent(goto));
2 daniel-mar 375
 
376
                if (goto != null) data.instance.select_node([goto]);
128 daniel-mar 377
 
643 daniel-mar 378
                setTimeout(glayoutWorkaroundAC, 100);
137 daniel-mar 379
                setTimeout(glayoutWorkaroundB, 100);
2 daniel-mar 380
        })
381
        .on('select_node.jstree', function (node, selected, event) {
120 daniel-mar 382
                mobileNavClose();
95 daniel-mar 383
 
9 daniel-mar 384
                var id = selected.node.id;
114 daniel-mar 385
                if ((!popstate_running) && (current_node != id)) {
399 daniel-mar 386
                        // 4th argument: we force the reload (because in the
387
                        // conditional select above, we already asked if
388
                        // tinyMCE needs to be saved)
389
                        openOidInPanel(id, false, '', true);
2 daniel-mar 390
                }
391
        });
392
 
393
        // --- Layout
394
 
1055 daniel-mar 395
        if ($('#system_title_menu').length > 0) $("#system_title_menu")[0].style.display = "block";
120 daniel-mar 396
 
355 daniel-mar 397
        var tmpObjectTree = _L("OBJECT TREE").replace(/(.{1})/g,"$1<br>");
398
        tmpObjectTree = tmpObjectTree.substring(0, tmpObjectTree.length-"<br>".length);
399
 
1055 daniel-mar 400
        if ($('#oidtree').length > 0) $('#oidtree').addClass('ui-layout-west');
401
        if ($('#content_window').length > 0) $('#content_window').addClass('ui-layout-center');
402
        if ($('#system_title_bar').length > 0) $('#system_title_bar').addClass('ui-layout-north');
403
        if ($('#frames').length > 0) glayout = $('#frames').layout({
120 daniel-mar 404
                north__size:                  40,
405
                north__slidable:              false,
406
                north__closable:              false,
407
                north__resizable:             false,
818 daniel-mar 408
                west__size:                   oidplus_menu_width,
120 daniel-mar 409
                west__spacing_closed:         20,
410
                west__togglerLength_closed:   230,
829 daniel-mar 411
                west__togglerAlign_closed:    "center",
355 daniel-mar 412
                west__togglerContent_closed:  tmpObjectTree,
413
                west__togglerTip_closed:      _L("Open & Pin Menu"),
414
                west__sliderTip:              _L("Slide Open Menu"),
120 daniel-mar 415
                west__slideTrigger_open:      "mouseover",
829 daniel-mar 416
                center__maskContents:         true, // IMPORTANT - enable iframe masking
1055 daniel-mar 417
                onresize_start:               function() { if (typeof handle_glayout_onresize_start == 'function') handle_glayout_onresize_start(); }
120 daniel-mar 418
        });
183 daniel-mar 419
 
1055 daniel-mar 420
        if ($('#gotobox').length == 0) $("#languageBox").css('right', '20px'); // Language Box to the right if there is no goto-box
421
 
422
        if ($('#gotobox').length > 0) $("#gotobox").addClass("mobilehidden");
423
        if ($('#languageBox').length > 0) $("#languageBox").addClass("mobilehidden");
424
        if ($('#gotobox').length > 0) $("#gotobox")[0].style.display = "block";
425
        if ($('#gotoedit').length > 0) $('#gotoedit').keypress(function(event) {
183 daniel-mar 426
                var keycode = (event.keyCode ? event.keyCode : event.which);
427
                if (keycode == '13') {
428
                        gotoButtonClicked();
429
                }
430
        });
833 daniel-mar 431
 
432
        if (typeof Bs5Utils !== "undefined") {
433
                Bs5Utils.defaults.toasts.position = 'top-center';
434
                Bs5Utils.defaults.toasts.stacking = true;
435
                bs5Utils = new Bs5Utils();
436
        }
876 daniel-mar 437
 
839 daniel-mar 438
        executeAllCallbacks(pageLoadedCallbacks.anyPageLoad);
439
        executeAllCallbacks(pageLoadedCallbacks.documentReadyAfter);
376 daniel-mar 440
});
2 daniel-mar 441
 
829 daniel-mar 442
// can be overridden if necessary
443
var handle_glayout_onresize_start = undefined;
444
 
643 daniel-mar 445
function glayoutWorkaroundAC() {
211 daniel-mar 446
        // "Bug A": Sometimes, the design is completely destroyed after reloading the page. It does not help when glayout.resizeAll()
137 daniel-mar 447
        //          is called at the beginning (e.g. during the ready function), and it does not help if we wait 500ms.
448
        //          So we do it all the time. It has probably something to do with slow loading times, since the error
449
        //          does only appear when the page is "blank" for a short while while it is loading.
450
        glayout.resizeAll();
287 daniel-mar 451
 
452
        // "Bug C": With Firefox (And sometimes with Chrome), there is a gap between the content-window (including scroll bars)
453
        //          and the right corner of the screen. Removing the explicit width solves this problem.
561 daniel-mar 454
        $("#content_window")[0].style.removeProperty("width");
643 daniel-mar 455
 
456
        setTimeout(glayoutWorkaroundAC, 100);
137 daniel-mar 457
}
458
 
459
function glayoutWorkaroundB() {
460
        // "Bug B": Sometimes, after reload, weird space between oidtree and content window, because oidtree has size of 438px
818 daniel-mar 461
        $("#oidtree")[0].style.width = oidplus_menu_width + "px";
137 daniel-mar 462
}
463
 
120 daniel-mar 464
function mobileNavClose() {
465
        if ($("#system_title_menu").is(":hidden")) {
466
                return;
467
        }
468
 
469
        $("#oidtree").slideUp("medium").promise().done(function() {
470
                $("#oidtree").addClass("ui-layout-west");
471
                $("#oidtree").show();
185 daniel-mar 472
//              $("#gotobox").hide();
355 daniel-mar 473
//              $("#languageBox").hide();
185 daniel-mar 474
                $("#gotobox").addClass("mobilehidden");
355 daniel-mar 475
                $("#languageBox").addClass("mobilehidden");
120 daniel-mar 476
        });
477
        $("#system_title_menu").removeClass("active");
95 daniel-mar 478
}
479
 
120 daniel-mar 480
function mobileNavOpen() {
481
        $("#oidtree").hide();
482
        $("#oidtree").removeClass("ui-layout-west");
483
        $("#oidtree").slideDown("medium");
185 daniel-mar 484
//      $("#gotobox").show();
355 daniel-mar 485
//      $("#languageBox").show();
185 daniel-mar 486
        $("#gotobox").removeClass("mobilehidden");
355 daniel-mar 487
        $("#languageBox").removeClass("mobilehidden");
120 daniel-mar 488
        $("#system_title_menu").addClass("active");
489
}
490
 
105 daniel-mar 491
function mobileNavButtonClick(sender) {
120 daniel-mar 492
        if ($("#oidtree").hasClass("ui-layout-west")) {
493
                mobileNavOpen();
103 daniel-mar 494
        } else {
120 daniel-mar 495
                mobileNavClose();
103 daniel-mar 496
        }
497
}
105 daniel-mar 498
 
499
function mobileNavButtonHover(sender) {
500
        sender.classList.toggle("hover");
501
}
183 daniel-mar 502
 
503
function gotoButtonClicked() {
704 daniel-mar 504
        openOidInPanel($("#gotoedit").val(), true);
183 daniel-mar 505
}
199 daniel-mar 506
 
355 daniel-mar 507
function setLanguage(lngid) {
1289 daniel-mar 508
        setCookie('LANGUAGE', lngid, 0/*Until browser closes*/, oidplus_webpath_relative);
356 daniel-mar 509
 
1060 daniel-mar 510
        if (current_node == "") return false; // Happens for Setup. Open URL instead.
511
 
356 daniel-mar 512
        $(".lng_flag").each(function(){
513
                $(this).addClass("picture_ghost");
355 daniel-mar 514
        });
675 daniel-mar 515
        $("#lng_flag_"+$.escapeSelector(lngid)).removeClass("picture_ghost");
356 daniel-mar 516
 
517
        if (isInternetExplorer()) {
518
                // Internet Explorer has problems with sending new cookies to new AJAX requests, so we reload the page completely
519
                window.location.reload();
520
        } else {
561 daniel-mar 521
                // TODO: Small detail: The "Go" button also needs to be re-translated
360 daniel-mar 522
                reloadContent();
356 daniel-mar 523
                mobileNavClose();
524
        }
1060 daniel-mar 525
        return true; // we have handled it. Do not follow href=""
355 daniel-mar 526
}
527
 
532 daniel-mar 528
function show_waiting_anim() {
529
        $("#loading").show();
530
}
531
 
532
function hide_waiting_anim() {
533
        $("#loading").hide();
534
}
544 daniel-mar 535
 
536
/* Mini-framework to abort all AJAX requests if a new request is made */
537
 
538
$.xhrPool = [];
539
$.xhrPool.add = function(jqXHR) {
540
        $.xhrPool.push(jqXHR);
541
}
542
$.xhrPool.remove = function(jqXHR) {
543
        var index = $.xhrPool.indexOf(jqXHR);
544
        if (index > -1) {
545
                $.xhrPool.splice(index, 1);
546
        }
547
};
548
$.xhrPool.abortAll = function() {
549
        var calls = Array.from($.xhrPool);
550
        $.each(calls, function(key, value) {
551
                value.abort();
552
        });
553
}
829 daniel-mar 554
 
833 daniel-mar 555
/* Individual alert types */
556
/* TODO: alert() blocks program flow, but alertSuccess() not! Will the mass change have negative effects (e.g. a redirect without the user seeing the toast)? */
557
 
558
function alertSuccess(txt) {
559
        if (typeof bs5Utils !== "undefined") {
560
                bs5Utils.Snack.show('success', _L(txt), delay = 5000, dismissible = true);
561
        } else {
562
                alert(txt);
563
        }
564
}
565
 
566
function alertWarning(txt) {
567
        // TODO: as toast?
568
        alert(txt);
569
}
570
 
571
function alertError(txt) {
572
        // TODO: as toast?
573
        alert(txt);
574
}
1036 daniel-mar 575
 
576
/* AJAX success/error-handling */
577
 
578
function oidplus_ajax_error(jqXHR, textStatus, errorThrown) {
579
        if (errorThrown == "abort") return;
580
        console.error(errorThrown, jqXHR);
581
        alertError(_L("Error: %1", errorThrown));
582
}
583
 
584
function oidplus_ajax_success(data, cb) {
585
        if (typeof data === "object" && "error" in data) {
586
                alertError(_L("Error: %1", data.error));
587
        } else if (typeof data === "object" && data.status >= 0) {
588
                cb(data);
589
        } else {
590
                alertError(_L("Error: %1", data));
591
        }
592
}