Subversion Repositories oidplus

Rev

Rev 424 | Rev 450 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 424 Rev 448
1
/*
1
/*
2
 * OIDplus 2.0
2
 * OIDplus 2.0
3
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
3
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
4
 *
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with 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
7
 * You may obtain a copy of the License at
8
 *
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
 
17
 
18
/*jshint esversion: 6 */
18
/*jshint esversion: 6 */
19
 
19
 
20
// $('#html').jstree();
20
// $('#html').jstree();
21
 
21
 
22
var current_node = "";
22
var current_node = "";
23
var popstate_running = false;
23
var popstate_running = false;
24
// DEFAULT_LANGUAGE will be set by oidplus.min.js.php
24
// DEFAULT_LANGUAGE will be set by oidplus.min.js.php
25
// language_messages will be set by oidplus.min.js.php
25
// language_messages will be set by oidplus.min.js.php
26
// language_tblprefix will be set by oidplus.min.js.php
26
// language_tblprefix will be set by oidplus.min.js.php
27
// csrf_token will be set by oidplus.min.js.php
27
// csrf_token will be set by oidplus.min.js.php
28
 
28
 
29
var pageChangeCallbacks = [];
29
var pageChangeCallbacks = [];
30
var pageChangeRequestCallbacks = [];
30
var pageChangeRequestCallbacks = [];
31
 
31
 
32
function isInternetExplorer() {
32
function isInternetExplorer() {
33
        var ua = window.navigator.userAgent;
33
        var ua = window.navigator.userAgent;
34
        return ((ua.indexOf("MSIE ") > 0) || (ua.indexOf("Trident/") > 0));
34
        return ((ua.indexOf("MSIE ") > 0) || (ua.indexOf("Trident/") > 0));
35
}
35
}
36
 
36
 
37
String.prototype.explode = function (separator, limit) {
37
String.prototype.explode = function (separator, limit) {
38
        // https://stackoverflow.com/questions/4514323/javascript-equivalent-to-php-explode
38
        // https://stackoverflow.com/questions/4514323/javascript-equivalent-to-php-explode
39
        const array = this.split(separator);
39
        const array = this.split(separator);
40
        if (limit !== undefined && array.length >= limit) {
40
        if (limit !== undefined && array.length >= limit) {
41
                array.push(array.splice(limit - 1).join(separator));
41
                array.push(array.splice(limit - 1).join(separator));
42
        }
42
        }
43
        return array;
43
        return array;
44
};
44
};
45
 
45
 
46
String.prototype.htmlentities = function () {
46
String.prototype.htmlentities = function () {
47
        return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');//"
47
        return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');//"
48
};
48
};
49
 
49
 
50
String.prototype.html_entity_decode = function () {
50
String.prototype.html_entity_decode = function () {
51
        return $('<textarea />').html(this).text();
51
        return $('<textarea />').html(this).text();
52
};
52
};
53
 
53
 
54
function getMeta(metaName) {
54
function getMeta(metaName) {
55
        const metas = document.getElementsByTagName('meta');
55
        const metas = document.getElementsByTagName('meta');
56
 
56
 
57
        for (let i = 0; i < metas.length; i++) {
57
        for (let i = 0; i < metas.length; i++) {
58
                if (metas[i].getAttribute('name') === metaName) {
58
                if (metas[i].getAttribute('name') === metaName) {
59
                        return metas[i].getAttribute('content');
59
                        return metas[i].getAttribute('content');
60
                }
60
                }
61
        }
61
        }
62
 
62
 
63
        return '';
63
        return '';
64
}
64
}
65
 
65
 
66
function getOidPlusSystemTitle() {
66
function getOidPlusSystemTitle() {
67
        return getMeta('OIDplus-SystemTitle'); // do not translate
67
        return getMeta('OIDplus-SystemTitle'); // do not translate
68
}
68
}
69
 
69
 
70
function combine_systemtitle_and_pagetitle(systemtitle, pagetitle) {
70
function combine_systemtitle_and_pagetitle(systemtitle, pagetitle) {
71
        // Please also change the function in index.php
71
        // Please also change the function in index.php
72
        if (systemtitle == pagetitle) {
72
        if (systemtitle == pagetitle) {
73
                return systemtitle;
73
                return systemtitle;
74
        } else {
74
        } else {
75
                return pagetitle + ' - ' + systemtitle;
75
                return pagetitle + ' - ' + systemtitle;
76
        }
76
        }
77
}
77
}
78
 
78
 
79
function getSystemUrl(relative) {
79
function getSystemUrl(relative) {
80
        var url = new URL(window.location.href);
80
        var url = new URL(window.location.href);
81
        if (relative) {
81
        if (relative) {
82
                return url.pathname;
82
                return url.pathname;
83
        } else {
83
        } else {
84
                return url.href.substr(0, url.href.length-url.search.length);
84
                return url.href.substr(0, url.href.length-url.search.length);
85
        }
85
        }
86
}
86
}
87
 
87
 
88
function getTreeLoadURL() {
88
function getTreeLoadURL() {
89
        var url = new URL(window.location.href);
89
        var url = new URL(window.location.href);
90
        var goto = url.searchParams.get("goto");
90
        var goto = url.searchParams.get("goto");
91
        return (goto != null) ? "ajax.php?csrf_token="+csrf_token+"&action=tree_load&goto="+encodeURIComponent(goto)
91
        return (goto != null) ? "ajax.php?csrf_token="+csrf_token+"&action=tree_load&goto="+encodeURIComponent(goto)
92
                              : "ajax.php?csrf_token="+csrf_token+"&action=tree_load";
92
                              : "ajax.php?csrf_token="+csrf_token+"&action=tree_load";
93
}
93
}
94
 
94
 
95
function reloadContent() {
95
function reloadContent() {
96
        // window.location.href = "?goto="+encodeURIComponent(current_node);
96
        // window.location.href = "?goto="+encodeURIComponent(current_node);
97
        if (openOidInPanel(current_node, false)) {
97
        if (openOidInPanel(current_node, false)) {
98
                $('#oidtree').jstree("refresh");
98
                $('#oidtree').jstree("refresh");
99
        }
99
        }
100
}
100
}
101
 
101
 
102
function x_rec(x_data, i) {
102
function x_rec(x_data, i) {
103
        $('#oidtree').jstree('open_node', x_data[i], function(e, data) {
103
        $('#oidtree').jstree('open_node', x_data[i], function(e, data) {
104
                if (i+1 < x_data.length) {
104
                if (i+1 < x_data.length) {
105
                        x_rec(x_data, i+1);
105
                        x_rec(x_data, i+1);
106
                } else {
106
                } else {
107
                        popstate_running = true; // don't call openOidInPanel again
107
                        popstate_running = true; // don't call openOidInPanel again
108
                        try {
108
                        try {
109
                                $('#oidtree').jstree('select_node', x_data[i]);
109
                                $('#oidtree').jstree('select_node', x_data[i]);
110
                        } catch (err) {
110
                        } catch (err) {
111
                                popstate_running = false;
111
                                popstate_running = false;
112
                        } finally {
112
                        } finally {
113
                                popstate_running = false;
113
                                popstate_running = false;
114
                        }
114
                        }
115
                }
115
                }
116
        });
116
        });
117
}
117
}
118
 
118
 
119
function performCloseQueryCB() {
119
function performCloseQueryCB() {
120
        for (var i=0; i<pageChangeRequestCallbacks.length; i++) {
120
        for (var i=0; i<pageChangeRequestCallbacks.length; i++) {
121
                if (!pageChangeRequestCallbacks[i][0](pageChangeRequestCallbacks[i][1])) return false;
121
                if (!pageChangeRequestCallbacks[i][0](pageChangeRequestCallbacks[i][1])) return false;
122
        }
122
        }
123
        pageChangeRequestCallbacks = [];
123
        pageChangeRequestCallbacks = [];
124
        return true; // may close
124
        return true; // may close
125
}
125
}
126
 
126
 
127
function performCloseCB() {
127
function performCloseCB() {
128
        for (var i=0; i<pageChangeCallbacks.length; i++) {
128
        for (var i=0; i<pageChangeCallbacks.length; i++) {
129
                pageChangeCallbacks[i][0](pageChangeCallbacks[i][1]);
129
                pageChangeCallbacks[i][0](pageChangeCallbacks[i][1]);
130
        }
130
        }
131
        pageChangeCallbacks = [];
131
        pageChangeCallbacks = [];
132
}
132
}
133
 
133
 
134
function openOidInPanel(id, reselect/*=false*/, anchor/*=''*/, force/*=false*/) {
134
function openOidInPanel(id, reselect/*=false*/, anchor/*=''*/, force/*=false*/) {
135
        reselect = (typeof reselect === 'undefined') ? false : reselect;
135
        reselect = (typeof reselect === 'undefined') ? false : reselect;
136
        anchor = (typeof anchor === 'undefined') ? '' : anchor;
136
        anchor = (typeof anchor === 'undefined') ? '' : anchor;
137
        force = (typeof force === 'undefined') ? false : force;
137
        force = (typeof force === 'undefined') ? false : force;
138
 
138
 
139
        var mayClose = performCloseQueryCB();
139
        var mayClose = performCloseQueryCB();
140
        if (!force && !mayClose) return false;
140
        if (!force && !mayClose) return false;
141
 
141
 
142
        performCloseCB();
142
        performCloseCB();
143
 
143
 
144
        if (reselect) {
144
        if (reselect) {
145
                $('#oidtree').jstree('deselect_all');
145
                $('#oidtree').jstree('deselect_all');
146
 
146
 
147
                popstate_running = true; // don't call openOidInPanel during tree selection
147
                popstate_running = true; // don't call openOidInPanel during tree selection
148
                try {
148
                try {
149
                        // If the node is already loaded in the tree, select it
149
                        // If the node is already loaded in the tree, select it
150
                        if (!$('#oidtree').jstree('select_node', id)) {
150
                        if (!$('#oidtree').jstree('select_node', id)) {
151
                                // If the node is not loaded, then we try to search it.
151
                                // If the node is not loaded, then we try to search it.
152
                                // If it can be found, then open all parent nodes and select the node
152
                                // If it can be found, then open all parent nodes and select the node
153
                                $.ajax({
153
                                $.ajax({
154
                                        url:"ajax.php",
154
                                        url:"ajax.php",
155
                                        method:"POST",
155
                                        method:"POST",
156
                                        data:{
156
                                        data:{
157
                                                csrf_token:csrf_token,
157
                                                csrf_token:csrf_token,
158
                                                action:"tree_search",
158
                                                action:"tree_search",
159
                                                search:id
159
                                                search:id
160
                                        },
160
                                        },
161
                                        error:function(jqXHR, textStatus, errorThrown) {
161
                                        error:function(jqXHR, textStatus, errorThrown) {
162
                                                console.error(_L("Error: %1",errorThrown));
162
                                                console.error(_L("Error: %1",errorThrown));
163
                                        },
163
                                        },
164
                                        success:function(data) {
164
                                        success:function(data) {
165
                                                if ("error" in data) {
165
                                                if ("error" in data) {
166
                                                        console.error(data);
166
                                                        console.error(data);
167
                                                } else if ((data instanceof Array) && (data.length > 0)) {
167
                                                } else if ((data instanceof Array) && (data.length > 0)) {
168
                                                        x_rec(data, 0);
168
                                                        x_rec(data, 0);
169
                                                } else {
169
                                                } else {
170
                                                        console.error(data);
170
                                                        console.error(data);
171
                                                }
171
                                                }
172
                                        }
172
                                        }
173
                                });
173
                                });
174
                        }
174
                        }
175
                } catch (err) {
175
                } catch (err) {
176
                        popstate_running = false;
176
                        popstate_running = false;
177
                } finally {
177
                } finally {
178
                        popstate_running = false;
178
                        popstate_running = false;
179
                }
179
                }
180
        }
180
        }
181
 
181
 
182
        // This loads the actual content
182
        // This loads the actual content
183
 
183
 
184
        // document.title = ""; // <-- we may not do this, otherwise Firefox won't
184
        // document.title = ""; // <-- we may not do this, otherwise Firefox won't
185
        //                            show titles in the browser history (right-click
185
        //                            show titles in the browser history (right-click
186
        //                            on back-button), although document.title() is
186
        //                            on back-button), although document.title() is
187
        //                            set inside the AJAX-callback [FirefoxBug?!]
187
        //                            set inside the AJAX-callback [FirefoxBug?!]
188
 
188
 
189
        $('#real_title').html("&nbsp;");
189
        $('#real_title').html("&nbsp;");
190
        $('#real_content').html(_L("Loading..."));
190
        $('#real_content').html(_L("Loading..."));
191
        $('#static_link').attr("href", "index.php?goto="+encodeURIComponent(id));
191
        $('#static_link').attr("href", "index.php?goto="+encodeURIComponent(id));
192
        $("#gotoedit").val(id);
192
        $("#gotoedit").val(id);
193
 
193
 
194
        // Normal opening of a description
194
        // Normal opening of a description
195
        fetch("ajax.php?csrf_token="+csrf_token+"&action=get_description&id="+encodeURIComponent(id))
195
        fetch("ajax.php?csrf_token="+csrf_token+"&action=get_description&id="+encodeURIComponent(id))
196
        .then(function(response) {
196
        .then(function(response) {
197
                response.json()
197
                response.json()
198
                .then(function(data) {
198
                .then(function(data) {
199
                        if ("error" in data) {
199
                        if ("error" in data) {
200
                                alert(_L("Failed to load content: %1",data.error));
200
                                alert(_L("Failed to load content: %1",data.error));
201
                                console.error(data.error);
201
                                console.error(data.error);
202
                                return;
202
                                return;
203
                        }
203
                        }
204
 
204
 
205
                        data.id = id;
205
                        data.id = id;
206
 
206
 
207
                        var state = {
207
                        var state = {
208
                                "node_id":id,
208
                                "node_id":id,
209
                                "titleHTML":(data.icon ? '<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' : '') + data.title.htmlentities(),
209
                                "titleHTML":(data.icon ? '<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' : '') + data.title.htmlentities(),
210
                                "textHTML":data.text,
210
                                "textHTML":data.text,
211
                                "staticlinkHREF":"index.php?goto="+encodeURIComponent(id),
211
                                "staticlinkHREF":"index.php?goto="+encodeURIComponent(id),
212
                        };
212
                        };
213
                        if (current_node != id) {
213
                        if (current_node != id) {
214
                                window.history.pushState(state, data.title, "?goto="+encodeURIComponent(id));
214
                                window.history.pushState(state, data.title, "?goto="+encodeURIComponent(id));
215
                        } else {
215
                        } else {
216
                                window.history.replaceState(state, data.title, "?goto="+encodeURIComponent(id));
216
                                window.history.replaceState(state, data.title, "?goto="+encodeURIComponent(id));
217
                        }
217
                        }
218
 
218
 
219
                        document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
219
                        document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
220
 
220
 
221
                        if (data.icon) {
221
                        if (data.icon) {
222
                                $('#real_title').html('<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' + data.title.htmlentities());
222
                                $('#real_title').html('<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' + data.title.htmlentities());
223
                        } else {
223
                        } else {
224
                                $('#real_title').html(data.title.htmlentities());
224
                                $('#real_title').html(data.title.htmlentities());
225
                        }
225
                        }
226
                        $('#real_content').html(data.text);
226
                        $('#real_content').html(data.text);
227
                        document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
227
                        document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
228
                        current_node = id;
228
                        current_node = id;
229
 
229
 
230
                        if (anchor != '') {
230
                        if (anchor != '') {
231
                                jumpToAnchor(anchor);
231
                                jumpToAnchor(anchor);
232
                        }
232
                        }
233
                })
233
                })
234
                .catch(function(error) {
234
                .catch(function(error) {
235
                        alert(_L("Failed to load content: %1",error));
235
                        alert(_L("Failed to load content: %1",error));
236
                        console.error(error);
236
                        console.error(error);
237
                });
237
                });
238
        })
238
        })
239
        .catch(function(error) {
239
        .catch(function(error) {
240
                alert(_L("Failed to load content: %1",error));
240
                alert(_L("Failed to load content: %1",error));
241
                console.error(error);
241
                console.error(error);
242
        });
242
        });
243
 
243
 
244
        return true;
244
        return true;
245
}
245
}
246
 
246
 
247
// This function opens the "parentID" node, and then selects the "childID" node (which should be beneath the parent node)
247
// This function opens the "parentID" node, and then selects the "childID" node (which should be beneath the parent node)
248
function openAndSelectNode(childID, parentID) {
248
function openAndSelectNode(childID, parentID) {
249
        if ($('#oidtree').jstree(true).get_node(parentID)) {
249
        if ($('#oidtree').jstree(true).get_node(parentID)) {
250
                $('#oidtree').jstree('open_node', parentID, function(e, data) { // open parent node
250
                $('#oidtree').jstree('open_node', parentID, function(e, data) { // open parent node
251
                        if ($('#oidtree').jstree(true).get_node(childID)) { // is the child there?
251
                        if ($('#oidtree').jstree(true).get_node(childID)) { // is the child there?
252
                                $('#oidtree').jstree('deselect_all').jstree('select_node', childID); // select it
252
                                $('#oidtree').jstree('deselect_all').jstree('select_node', childID); // select it
253
                        } else {
253
                        } else {
254
                                // This can happen if the content page contains brand new items which are not in the treeview yet
254
                                // This can happen if the content page contains brand new items which are not in the treeview yet
255
                                $("#gotoedit").val(childID);
255
                                $("#gotoedit").val(childID);
256
                                window.location.href = "?goto="+encodeURIComponent(childID);
256
                                window.location.href = "?goto="+encodeURIComponent(childID);
257
                        }
257
                        }
258
                }, true);
258
                }, true);
259
        } else {
259
        } else {
260
                // This should usually not happen
260
                // This should usually not happen
261
                $("#gotoedit").val(childID);
261
                $("#gotoedit").val(childID);
262
                window.location.href = "?goto="+encodeURIComponent(childID);
262
                window.location.href = "?goto="+encodeURIComponent(childID);
263
        }
263
        }
264
}
264
}
265
 
265
 
266
$(window).on("popstate", function(e) {
266
$(window).on("popstate", function(e) {
267
        if (!performCloseQueryCB()) {
267
        if (!performCloseQueryCB()) {
268
                // TODO: does not work!!! The "back/forward" action will be cancelled, but the browser still thinks it was successful,
268
                // TODO: does not work!!! The "back/forward" action will be cancelled, but the browser still thinks it was successful,
269
                // so if you do it again, you will then jump 2 pages back, etc!
269
                // so if you do it again, you will then jump 2 pages back, etc!
270
                // This does also not help:
270
                // This does also not help:
271
                //window.history.pushState(e.originalEvent.state, e.originalEvent.title, e.originalEvent.url);
271
                //window.history.pushState(e.originalEvent.state, e.originalEvent.title, e.originalEvent.url);
272
                //window.history.forward();
272
                //window.history.forward();
273
                return;
273
                return;
274
        }
274
        }
275
 
275
 
276
        popstate_running = true;
276
        popstate_running = true;
277
        try {
277
        try {
278
                var data = e.originalEvent.state;
278
                var data = e.originalEvent.state;
279
 
279
 
280
                current_node = data.node_id;
280
                current_node = data.node_id;
281
                $("#gotoedit").val(current_node);
281
                $("#gotoedit").val(current_node);
282
                $('#oidtree').jstree('deselect_all').jstree('select_node', data.node_id);
282
                $('#oidtree').jstree('deselect_all').jstree('select_node', data.node_id);
283
                $('#real_title').html(data.titleHTML);
283
                $('#real_title').html(data.titleHTML);
284
                $('#real_content').html(data.textHTML);
284
                $('#real_content').html(data.textHTML);
285
                $('#static_link').attr("href", data.staticlinkHREF);
285
                $('#static_link').attr("href", data.staticlinkHREF);
286
                document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.titleHTML.html_entity_decode());
286
                document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.titleHTML.html_entity_decode());
287
        } catch (err) {
287
        } catch (err) {
288
                popstate_running = false;
288
                popstate_running = false;
289
        } finally {
289
        } finally {
290
                popstate_running = false;
290
                popstate_running = false;
291
        }
291
        }
292
});
292
});
293
 
293
 
294
$(document).ready(function () {
294
$(document).ready(function () {
295
        /*
295
        /*
296
        window.onbeforeunload = function(e) {
296
        window.onbeforeunload = function(e) {
297
                // TODO: This won't be called because TinyMCE overrides it??
297
                // TODO: This won't be called because TinyMCE overrides it??
298
                // TODO: when the user accepted the query in performCloseQueryCB(), then the message will be shown again by the browser!
298
                // TODO: when the user accepted the query in performCloseQueryCB(), then the message will be shown again by the browser!
299
                if (!performCloseQueryCB()) {
299
                if (!performCloseQueryCB()) {
300
                        // Cancel the event
300
                        // Cancel the event
301
                        e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
301
                        e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
302
                        // Chrome requires returnValue to be set
302
                        // Chrome requires returnValue to be set
303
                        e.returnValue = '';
303
                        e.returnValue = '';
304
                } else {
304
                } else {
305
                        // the absence of a returnValue property on the event will guarantee the browser unload happens
305
                        // the absence of a returnValue property on the event will guarantee the browser unload happens
306
                        delete e['returnValue'];
306
                        delete e['returnValue'];
307
                }
307
                }
308
        };
308
        };
309
        */
309
        */
310
 
310
 
311
        // --- JsTree
311
        // --- JsTree
312
 
312
 
313
        $('#oidtree')
313
        $('#oidtree')
314
        .jstree({
314
        .jstree({
315
                plugins: ['massload','search','conditionalselect'],
315
                plugins: ['massload','search','conditionalselect'],
316
                'core' : {
316
                'core' : {
317
                        'data' : {
317
                        'data' : {
318
                                "url" : getTreeLoadURL(),
318
                                "url" : getTreeLoadURL(),
319
                                "data" : function (node) {
319
                                "data" : function (node) {
320
                                        return { "id" : node.id };
320
                                        return { "id" : node.id };
321
                                }
321
                                }
322
                        },
322
                        },
323
                        "multiple": false
323
                        "multiple": false
324
                },
324
                },
325
                'conditionalselect' : function (node) {
325
                'conditionalselect' : function (node) {
326
                        if (node.original.conditionalselect !== undefined) {
326
                        if (node.original.conditionalselect !== undefined) {
327
                                return eval(node.original.conditionalselect);
327
                                return eval(node.original.conditionalselect);
328
                        } else {
328
                        } else {
329
                                return performCloseQueryCB();
329
                                return performCloseQueryCB();
330
                        }
330
                        }
331
                },
331
                },
332
        })
332
        })
333
        .on('ready.jstree', function (e, data) {
333
        .on('ready.jstree', function (e, data) {
334
                var url = new URL(window.location.href);
334
                var url = new URL(window.location.href);
335
                var goto = url.searchParams.get("goto");
335
                var goto = url.searchParams.get("goto");
336
                if (goto == null) goto = "oidplus:system"; // the page was not called with ?goto=...
336
                if (goto == null) goto = "oidplus:system"; // the page was not called with ?goto=...
337
                $("#gotoedit").val(goto);
337
                $("#gotoedit").val(goto);
338
 
338
 
339
                // 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)
339
                // 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)
340
                // But then we need to set the history state manually
340
                // But then we need to set the history state manually
341
                current_node = goto;
341
                current_node = goto;
342
                window.history.replaceState({
342
                window.history.replaceState({
343
                        "node_id":goto,
343
                        "node_id":goto,
344
                        "titleHTML":$('#real_title').html(),
344
                        "titleHTML":$('#real_title').html(),
345
                        "textHTML":$('#real_content').html(),
345
                        "textHTML":$('#real_content').html(),
346
                        "staticlinkHREF":"index.php?goto="+encodeURIComponent(goto),
346
                        "staticlinkHREF":"index.php?goto="+encodeURIComponent(goto),
347
                }, $('#real_title').html(), "?goto="+encodeURIComponent(goto));
347
                }, $('#real_title').html(), "?goto="+encodeURIComponent(goto));
348
 
348
 
349
                if (goto != null) data.instance.select_node([goto]);
349
                if (goto != null) data.instance.select_node([goto]);
350
 
350
 
351
                setTimeout(glayoutWorkaroundA, 100);
351
                setTimeout(glayoutWorkaroundA, 100);
352
                setTimeout(glayoutWorkaroundB, 100);
352
                setTimeout(glayoutWorkaroundB, 100);
353
        })
353
        })
354
        .on('select_node.jstree', function (node, selected, event) {
354
        .on('select_node.jstree', function (node, selected, event) {
355
                mobileNavClose();
355
                mobileNavClose();
356
 
356
 
357
                var id = selected.node.id;
357
                var id = selected.node.id;
358
                if ((!popstate_running) && (current_node != id)) {
358
                if ((!popstate_running) && (current_node != id)) {
359
                        // 4th argument: we force the reload (because in the
359
                        // 4th argument: we force the reload (because in the
360
                        // conditional select above, we already asked if
360
                        // conditional select above, we already asked if
361
                        // tinyMCE needs to be saved)
361
                        // tinyMCE needs to be saved)
362
                        openOidInPanel(id, false, '', true);
362
                        openOidInPanel(id, false, '', true);
363
                }
363
                }
364
        });
364
        });
365
 
365
 
366
        // --- Layout
366
        // --- Layout
367
 
367
 
368
        document.getElementById('system_title_menu').style.display = "block";
368
        document.getElementById('system_title_menu').style.display = "block";
369
 
369
 
370
        var tmpObjectTree = _L("OBJECT TREE").replace(/(.{1})/g,"$1<br>");
370
        var tmpObjectTree = _L("OBJECT TREE").replace(/(.{1})/g,"$1<br>");
371
        tmpObjectTree = tmpObjectTree.substring(0, tmpObjectTree.length-"<br>".length);
371
        tmpObjectTree = tmpObjectTree.substring(0, tmpObjectTree.length-"<br>".length);
372
 
372
 
373
        $('#oidtree').addClass('ui-layout-west');
373
        $('#oidtree').addClass('ui-layout-west');
374
        $('#content_window').addClass('ui-layout-center');
374
        $('#content_window').addClass('ui-layout-center');
375
        $('#system_title_bar').addClass('ui-layout-north');
375
        $('#system_title_bar').addClass('ui-layout-north');
376
        glayout = $('#frames').layout({
376
        glayout = $('#frames').layout({
377
                north__size:                  40,
377
                north__size:                  40,
378
                north__slidable:              false,
378
                north__slidable:              false,
379
                north__closable:              false,
379
                north__closable:              false,
380
                north__resizable:             false,
380
                north__resizable:             false,
381
                west__size:                   450,
381
                west__size:                   450,
382
                west__spacing_closed:         20,
382
                west__spacing_closed:         20,
383
                west__togglerLength_closed:   230,
383
                west__togglerLength_closed:   230,
384
                west__togglerAlign_closed:    "top",
384
                west__togglerAlign_closed:    "top",
385
                west__togglerContent_closed:  tmpObjectTree,
385
                west__togglerContent_closed:  tmpObjectTree,
386
                west__togglerTip_closed:      _L("Open & Pin Menu"),
386
                west__togglerTip_closed:      _L("Open & Pin Menu"),
387
                west__sliderTip:              _L("Slide Open Menu"),
387
                west__sliderTip:              _L("Slide Open Menu"),
388
                west__slideTrigger_open:      "mouseover",
388
                west__slideTrigger_open:      "mouseover",
389
                center__maskContents:         true // IMPORTANT - enable iframe masking
389
                center__maskContents:         true // IMPORTANT - enable iframe masking
390
        });
390
        });
391
 
391
 
392
        $("#gotobox").addClass("mobilehidden");
392
        $("#gotobox").addClass("mobilehidden");
393
        $("#languageBox").addClass("mobilehidden");
393
        $("#languageBox").addClass("mobilehidden");
394
        document.getElementById('gotobox').style.display = "block";
394
        document.getElementById('gotobox').style.display = "block";
395
        $('#gotoedit').keypress(function(event) {
395
        $('#gotoedit').keypress(function(event) {
396
                var keycode = (event.keyCode ? event.keyCode : event.which);
396
                var keycode = (event.keyCode ? event.keyCode : event.which);
397
                if (keycode == '13') {
397
                if (keycode == '13') {
398
                        gotoButtonClicked();
398
                        gotoButtonClicked();
399
                }
399
                }
400
        });
400
        });
401
});
401
});
402
 
402
 
403
function glayoutWorkaroundA() {
403
function glayoutWorkaroundA() {
404
        // "Bug A": Sometimes, the design is completely destroyed after reloading the page. It does not help when glayout.resizeAll()
404
        // "Bug A": Sometimes, the design is completely destroyed after reloading the page. It does not help when glayout.resizeAll()
405
        //          is called at the beginning (e.g. during the ready function), and it does not help if we wait 500ms.
405
        //          is called at the beginning (e.g. during the ready function), and it does not help if we wait 500ms.
406
        //          So we do it all the time. It has probably something to do with slow loading times, since the error
406
        //          So we do it all the time. It has probably something to do with slow loading times, since the error
407
        //          does only appear when the page is "blank" for a short while while it is loading.
407
        //          does only appear when the page is "blank" for a short while while it is loading.
408
        glayout.resizeAll();
408
        glayout.resizeAll();
409
        setTimeout(glayoutWorkaroundA, 100);
409
        setTimeout(glayoutWorkaroundA, 100);
410
 
410
 
411
        // "Bug C": With Firefox (And sometimes with Chrome), there is a gap between the content-window (including scroll bars)
411
        // "Bug C": With Firefox (And sometimes with Chrome), there is a gap between the content-window (including scroll bars)
412
        //          and the right corner of the screen. Removing the explicit width solves this problem.
412
        //          and the right corner of the screen. Removing the explicit width solves this problem.
413
        document.getElementById("content_window").style.removeProperty("width");
413
        document.getElementById("content_window").style.removeProperty("width");
414
}
414
}
415
 
415
 
416
function glayoutWorkaroundB() {
416
function glayoutWorkaroundB() {
417
        // "Bug B": Sometimes, after reload, weird space between oidtree and content window, because oidtree has size of 438px
417
        // "Bug B": Sometimes, after reload, weird space between oidtree and content window, because oidtree has size of 438px
418
        document.getElementById("oidtree").style.width = "450px";
418
        document.getElementById("oidtree").style.width = "450px";
419
}
419
}
420
 
420
 
421
function mobileNavClose() {
421
function mobileNavClose() {
422
        if ($("#system_title_menu").is(":hidden")) {
422
        if ($("#system_title_menu").is(":hidden")) {
423
                return;
423
                return;
424
        }
424
        }
425
 
425
 
426
        $("#oidtree").slideUp("medium").promise().done(function() {
426
        $("#oidtree").slideUp("medium").promise().done(function() {
427
                $("#oidtree").addClass("ui-layout-west");
427
                $("#oidtree").addClass("ui-layout-west");
428
                $("#oidtree").show();
428
                $("#oidtree").show();
429
//              $("#gotobox").hide();
429
//              $("#gotobox").hide();
430
//              $("#languageBox").hide();
430
//              $("#languageBox").hide();
431
                $("#gotobox").addClass("mobilehidden");
431
                $("#gotobox").addClass("mobilehidden");
432
                $("#languageBox").addClass("mobilehidden");
432
                $("#languageBox").addClass("mobilehidden");
433
        });
433
        });
434
        $("#system_title_menu").removeClass("active");
434
        $("#system_title_menu").removeClass("active");
435
}
435
}
436
 
436
 
437
function mobileNavOpen() {
437
function mobileNavOpen() {
438
        $("#oidtree").hide();
438
        $("#oidtree").hide();
439
        $("#oidtree").removeClass("ui-layout-west");
439
        $("#oidtree").removeClass("ui-layout-west");
440
        $("#oidtree").slideDown("medium");
440
        $("#oidtree").slideDown("medium");
441
//      $("#gotobox").show();
441
//      $("#gotobox").show();
442
//      $("#languageBox").show();
442
//      $("#languageBox").show();
443
        $("#gotobox").removeClass("mobilehidden");
443
        $("#gotobox").removeClass("mobilehidden");
444
        $("#languageBox").removeClass("mobilehidden");
444
        $("#languageBox").removeClass("mobilehidden");
445
        $("#system_title_menu").addClass("active");
445
        $("#system_title_menu").addClass("active");
446
}
446
}
447
 
447
 
448
function mobileNavButtonClick(sender) {
448
function mobileNavButtonClick(sender) {
449
        if ($("#oidtree").hasClass("ui-layout-west")) {
449
        if ($("#oidtree").hasClass("ui-layout-west")) {
450
                mobileNavOpen();
450
                mobileNavOpen();
451
        } else {
451
        } else {
452
                mobileNavClose();
452
                mobileNavClose();
453
        }
453
        }
454
}
454
}
455
 
455
 
456
function mobileNavButtonHover(sender) {
456
function mobileNavButtonHover(sender) {
457
        sender.classList.toggle("hover");
457
        sender.classList.toggle("hover");
458
}
458
}
459
 
459
 
460
function gotoButtonClicked() {
460
function gotoButtonClicked() {
461
        openOidInPanel($("#gotoedit").val(), 1);
461
        openOidInPanel($("#gotoedit").val(), 1);
462
}
462
}
463
 
463
 
464
function jumpToAnchor(anchor) {
464
function jumpToAnchor(anchor) {
465
        window.location.href = "#" + anchor;
465
        window.location.href = "#" + anchor;
466
}
466
}
467
 
467
 
468
function getCookie(cname) {
468
function getCookie(cname) {
469
        // Source: https://www.w3schools.com/js/js_cookies.asp
469
        // Source: https://www.w3schools.com/js/js_cookies.asp
470
        var name = cname + "=";
470
        var name = cname + "=";
471
        var decodedCookie = decodeURIComponent(document.cookie);
471
        var decodedCookie = decodeURIComponent(document.cookie);
472
        var ca = decodedCookie.split(';');
472
        var ca = decodedCookie.split(';');
473
        for(var i = 0; i <ca.length; i++) {
473
        for(var i = 0; i <ca.length; i++) {
474
                var c = ca[i];
474
                var c = ca[i];
475
                while (c.charAt(0) == ' ') {
475
                while (c.charAt(0) == ' ') {
476
                        c = c.substring(1);
476
                        c = c.substring(1);
477
                }
477
                }
478
                if (c.indexOf(name) == 0) {
478
                if (c.indexOf(name) == 0) {
479
                        return c.substring(name.length, c.length);
479
                        return c.substring(name.length, c.length);
480
                }
480
                }
481
        }
481
        }
482
        return undefined;
482
        return undefined;
483
}
483
}
484
 
484
 
485
function setCookie(cname, cvalue, exdays, path) {
485
function setCookie(cname, cvalue, exdays, path) {
486
        var d = new Date();
486
        var d = new Date();
487
        d.setTime(d.getTime() + (exdays*24*60*60*1000));
487
        d.setTime(d.getTime() + (exdays*24*60*60*1000));
488
        var expires = exdays == 0 ? "" : "; expires="+d.toUTCString();
488
        var expires = exdays == 0 ? "" : "; expires="+d.toUTCString();
489
        document.cookie = cname + "=" + cvalue + expires + ";path=" + path;
489
        document.cookie = cname + "=" + cvalue + expires + ";path=" + path;
490
}
490
}
491
 
491
 
492
function setLanguage(lngid) {
492
function setLanguage(lngid) {
493
        setCookie('LANGUAGE', lngid, 0/*Until browser closes*/, location.pathname);
493
        setCookie('LANGUAGE', lngid, 0/*Until browser closes*/, location.pathname);
494
 
494
 
495
        $(".lng_flag").each(function(){
495
        $(".lng_flag").each(function(){
496
                $(this).addClass("picture_ghost");
496
                $(this).addClass("picture_ghost");
497
        });
497
        });
498
        $("#lng_flag_"+lngid).removeClass("picture_ghost");
498
        $("#lng_flag_"+lngid).removeClass("picture_ghost");
499
 
499
 
500
        if (isInternetExplorer()) {
500
        if (isInternetExplorer()) {
501
                // Internet Explorer has problems with sending new cookies to new AJAX requests, so we reload the page completely
501
                // Internet Explorer has problems with sending new cookies to new AJAX requests, so we reload the page completely
502
                window.location.reload();
502
                window.location.reload();
503
        } else {
503
        } else {
504
                reloadContent();
504
                reloadContent();
505
                mobileNavClose();
505
                mobileNavClose();
506
        }
506
        }
507
}
507
}
508
 
508
 
509
function getCurrentLang() {
509
function getCurrentLang() {
510
        // Note: If the argument "?lang=" is used, PHP will automatically set a Cookie, so it is OK when we only check for the cookie
510
        // Note: If the argument "?lang=" is used, PHP will automatically set a Cookie, so it is OK when we only check for the cookie
511
        var lang = getCookie('LANGUAGE');
511
        var lang = getCookie('LANGUAGE');
512
        return (typeof lang != "undefined") ? lang : DEFAULT_LANGUAGE;
512
        return (typeof lang != "undefined") ? lang : DEFAULT_LANGUAGE;
513
}
513
}
514
 
514
 
515
function _L() {
515
function _L() {
516
        var args = Array.prototype.slice.call(arguments);
516
        var args = Array.prototype.slice.call(arguments);
517
        var str = args.shift();
517
        var str = args.shift();
518
 
518
 
519
        var tmp = "";
519
        var tmp = "";
520
        if (typeof language_messages[getCurrentLang()] == "undefined") {
520
        if (typeof language_messages[getCurrentLang()] == "undefined") {
521
                tmp = str;
521
                tmp = str;
522
        } else {
522
        } else {
523
                var msg = language_messages[getCurrentLang()][str];
523
                var msg = language_messages[getCurrentLang()][str];
524
                if (typeof msg != "undefined") {
524
                if (typeof msg != "undefined") {
525
                        tmp = msg;
525
                        tmp = msg;
526
                } else {
526
                } else {
527
                        tmp = str;
527
                        tmp = str;
528
                }
528
                }
529
        }
529
        }
530
 
530
 
531
        tmp = tmp.replace('###', language_tblprefix);
531
        tmp = tmp.replace('###', language_tblprefix);
532
 
532
 
533
        var n = 1;
533
        var n = 1;
534
        while (args.length > 0) {
534
        while (args.length > 0) {
535
                var val = args.shift();
535
                var val = args.shift();
536
                tmp = tmp.replace("%"+n, val);
536
                tmp = tmp.replace("%"+n, val);
537
                n++;
537
                n++;
538
        }
538
        }
539
 
539
 
540
        tmp = tmp.replace("%%", "%");
540
        tmp = tmp.replace("%%", "%");
541
 
541
 
542
        return tmp;
542
        return tmp;
543
}
543
}
544
 
544