Passed
Push — master ( 2e15b4...4d50b4 )
by Sébastien
05:22
created

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
// util.js
2
// copyright Sébastien Lucas
3
// https://github.com/seblucas/cops
4
5
/*jshint curly: true, latedef: true, trailing: true, noarg: true, undef: true, browser: true, jquery: true, unused: true, devel: true, loopfunc: true */
6
/*global LRUCache, doT, Bloodhound, postRefresh */
7
8
var templatePage, templateBookDetail, templateMain, templateSuggestion, currentData, before, filterList;
9
10
if (typeof LRUCache != 'undefined') {
11
    console.log('ERROR: LRUCache module not loaded!');
0 ignored issues
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
12
}
13
var cache = new LRUCache(30);
14
15
$.ajaxSetup({
16
    cache: false
17
});
18
19
var copsTypeahead = new Bloodhound({
20
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
21
    queryTokenizer: Bloodhound.tokenizers.whitespace,
22
    limit: 30,
23
    remote: {
24
                url: 'getJSON.php?page=9&search=1&db=%DB&query=%QUERY',
25
                replace: function (url, query) {
26
                    if (currentData.multipleDatabase === 1 && currentData.databaseId === "") {
27
                        return url.replace('%QUERY', query).replace('&db=%DB', "");
28
                    }
29
                    return url.replace('%QUERY', query).replace('%DB', currentData.databaseId);
30
                }
31
            }
32
});
33
34
copsTypeahead.initialize();
35
36
var DEBUG = false;
37
var isPushStateEnabled = window.history && window.history.pushState && window.history.replaceState &&
38
  // pushState isn't reliable on iOS until 5.
39
  !window.navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/);
40
41
function debug_log(text) {
42
    if ( DEBUG ) {
43
        console.log(text);
0 ignored issues
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
44
    }
45
}
46
47
/*exported updateCookie */
48
function updateCookie (id) {
49
    if ($(id).prop('pattern') && !$(id).val().match(new RegExp ($(id).prop('pattern')))) {
50
        return;
51
    }
52
    var name = $(id).attr('id');
53
    var value = $(id).val ();
54
    $.cookie(name, value, { expires: 365 });
55
}
56
57
/*exported updateCookieFromCheckbox */
58
function updateCookieFromCheckbox (id) {
59
    var name = $(id).attr('id');
60
    if ((/^style/).test (name)) {
61
        name = "style";
62
    }
63
    if ($(id).is(":checked"))
64
    {
65
        if ($(id).is(':radio')) {
66
            $.cookie(name, $(id).val (), { expires: 365 });
67
        } else {
68
            $.cookie(name, '1', { expires: 365 });
69
        }
70
    }
71
    else
72
    {
73
        $.cookie(name, '0', { expires: 365 });
74
    }
75
}
76
77
/*exported updateCookieFromCheckboxGroup */
78
function updateCookieFromCheckboxGroup (id) {
79
    var name = $(id).attr('name');
80
    var idBase = name.replace (/\[\]/, "");
81
    var group = [];
82
    $(':checkbox[name="' + name + '"]:checked').each (function () {
83
        var id = $(this).attr("id");
84
        group.push (id.replace (idBase + "_", ""));
85
    });
86
    $.cookie(idBase, group.join (), { expires: 365 });
87
}
88
89
90
function elapsed () {
91
    var elapsedTime = new Date () - before;
92
    return "Elapsed : " + elapsedTime;
93
}
94
95
function retourMail(data) {
96
    $("#mailButton :first-child").removeClass ("fas fa-spinner fa-pulse").addClass ("fas fa-envelope");
97
    alert (data);
98
}
99
100
/*exported sendToMailAddress */
101
function sendToMailAddress (component, dataid) {
102
    var email = $.cookie ('email');
103
    if (!$.cookie ('email')) {
104
        email = window.prompt (currentData.c.i18n.customizeEmail, "");
105
        if (email === null)
106
        {
107
            return;
108
        }
109
        $.cookie ('email', email, { expires: 365 });
110
    }
111
    var url = 'sendtomail.php';
112
    if (currentData.databaseId) {
113
        url = url + '?db=' + currentData.databaseId;
114
    }
115
    $("#mailButton :first-child").removeClass ("fas fa-envelope").addClass ("fas fa-spinner fa-pulse");
116
    $.ajax ({'url': url, 'type': 'post', 'data': { 'data':  dataid, 'email': email }, 'success': retourMail});
117
}
118
119
function str_format () {
120
    var s = arguments[0];
121
    for (var i = 0; i < arguments.length - 1; i++) {
122
        var reg = new RegExp("\\{" + i + "\\}", "gm");
123
        s = s.replace(reg, arguments[i + 1]);
124
    }
125
    return s;
126
}
127
128
function isDefined(x) {
129
    return (typeof x !== 'undefined');
130
}
131
132
function getCurrentOption (option) {
133
    if (!$.cookie (option)) {
134
        if (currentData && currentData.c && currentData.c.config && currentData.c.config [option]) {
135
            return currentData.c.config [option];
136
        }
137
    }
138
    return $.cookie (option);
139
}
140
141
/*exported htmlspecialchars */
142
function htmlspecialchars(str) {
143
    return String(str)
144
            .replace(/&/g, '&amp;')
145
            .replace(/"/g, '&quot;')
146
            .replace(/'/g, '&#39;')
147
            .replace(/</g, '&lt;')
148
            .replace(/>/g, '&gt;');
149
}
150
151
/************************************************
152
 * All functions needed to filter the book list by tags
153
 ************************************************
154
 */
155
156
function getTagList () {
157
    var tagList = {};
158
    $(".se").each (function(){
159
        if ($(this).parents (".filtered").length > 0) { return; }
160
        var taglist = $(this).text();
161
162
        var tagarray = taglist.split (",");
163
        for (var i in tagarray) {
164
            if (!tagarray.hasOwnProperty(i)) {
165
                continue;
166
            }
167
            var tag = tagarray [i].replace(/^\s+/g,'').replace(/\s+$/g,'');
168
            tagList [tag] = 1;
169
        }
170
    });
171
    return tagList;
172
}
173
174
function updateFilters () {
175
    var tagList = getTagList ();
176
177
    // If there is already some filters then let's prepare to update the list
178
    $("#filter ul li").each (function () {
179
        var text = $(this).text ();
180
        if (isDefined (tagList [text]) || $(this).attr ('class')) {
181
            tagList [text] = 0;
182
        } else {
183
            tagList [text] = -1;
184
        }
185
    });
186
187
    // Update the filter -1 to remove, 1 to add, 0 already there
188
    for (var tag in tagList) {
189
        if (!tagList.hasOwnProperty(tag)) {
190
            continue;
191
        }
192
        var tagValue = tagList [tag];
193
        if (tagValue === -1) {
194
            $("#filter ul li").filter (function () { return $.text([this]) === tag; }).remove();
0 ignored issues
show
The variable tag is changed by the for-each loop on line 188. Only the value of the last iteration will be visible in this function if it is called outside of the loop.
Loading history...
195
        }
196
        if (tagValue === 1) {
197
            $("#filter ul").append ("<li>" + tag + "</li>");
198
        }
199
    }
200
201
    $("#filter ul").append ("<li>_CLEAR_</li>");
202
203
    // Sort the list alphabetically
204
    $('#filter ul li').sortElements(function(a, b){
205
        return $(a).text() > $(b).text() ? 1 : -1;
206
    });
207
}
208
209
function doFilter () {
210
    $(".books").removeClass("filtered");
211
    if (jQuery.isEmptyObject(filterList)) {
212
        updateFilters ();
213
        return;
214
    }
215
216
    $(".se").each (function(){
217
        var taglist = ", " + $(this).text() + ", ";
218
        var toBeFiltered = false;
219
        for (var filter in filterList) {
220
            if (!filterList.hasOwnProperty(filter)) {
221
                continue;
222
            }
223
            var onlyThisTag = filterList [filter];
224
            filter = ', ' + filter + ', ';
225
            var myreg = new RegExp (filter);
226
            if (myreg.test (taglist)) {
227
                if (onlyThisTag === false) {
228
                    toBeFiltered = true;
229
                }
230
            } else {
231
                if (onlyThisTag === true) {
232
                    toBeFiltered = true;
233
                }
234
            }
235
        }
236
        if (toBeFiltered) { $(this).parents (".books").addClass ("filtered"); }
237
    });
238
239
    // Handle the books with no tags
240
    var atLeastOneTagSelected = false;
241
    for (var filter in filterList) {
242
        if (!filterList.hasOwnProperty(filter)) {
243
            continue;
244
        }
245
        if (filterList[filter] === true) {
246
            atLeastOneTagSelected = true;
247
        }
248
    }
249
    if (atLeastOneTagSelected) {
250
        $(".books").not (":has(span.se)").addClass ("filtered");
251
    }
252
253
    updateFilters ();
254
}
255
256
function handleFilterEvents () {
257
    $("#filter ul").on ("click", "li", function(){
258
        var filter = $(this).text ();
259
        if (filter === "_CLEAR_") {
260
            filterList = {};
261
            $("#filter ul li").removeClass ("filter-exclude");
262
            $("#filter ul li").removeClass ("filter-include");
263
            doFilter ();
264
            return;
265
        }
266
        switch ($(this).attr("class")) {
267
            case "filter-include" :
268
                $(this).attr("class", "filter-exclude");
269
                filterList [filter] = false;
270
                break;
271
            case "filter-exclude" :
272
                $(this).removeClass ("filter-exclude");
273
                delete filterList [filter];
274
                break;
275
            default :
276
                $(this).attr("class", "filter-include");
277
                filterList [filter] = true;
278
                break;
279
        }
280
        doFilter ();
281
    });
282
}
283
284
/************************************************
285
 * Functions to handle Ajax navigation
286
 ************************************************
287
 */
288
289
var updatePage, navigateTo;
290
291
updatePage = function (data) {
292
    var result;
293
    filterList = {};
294
    data.c = currentData.c;
295
    if (false && $("section").length && currentData.isPaginated === 0 &&  data.isPaginated === 0) {
296
        // Partial update (for now disabled)
297
        debug_log ("Partial update");
298
        result = templateMain (data);
299
        $("h1").html (data.title);
300
        $("section").html (result);
301
    } else {
302
        // Full update
303
        result = templatePage (data);
304
        $("body").html (result);
305
    }
306
    document.title = data.title;
307
    currentData = data;
308
    setTimeout( function() { $("input[name=query]").focus(); }, 500 );
309
310
    debug_log (elapsed ());
311
312
    if ($.cookie('toolbar') === '1') { $("#tool").show (); }
313
    if (currentData.containsBook === 1) {
314
        $("#sortForm").show ();
315
        if (getCurrentOption ("html_tag_filter") === "1") {
316
            $("#filter ul").empty ();
317
            updateFilters ();
318
            handleFilterEvents ();
319
        }
320
    } else {
321
        $("#sortForm").hide ();
322
    }
323
324
    $('input[name=query]').typeahead(
325
    {
326
        hint: true,
327
        minLength : 3
328
    },
329
    {
330
        name: 'search',
331
        displayKey: 'title',
332
        templates: {
333
            suggestion: templateSuggestion
334
        },
335
        source: copsTypeahead.ttAdapter()
336
    });
337
338
    $('input[name=query]').bind('typeahead:selected', function(obj, datum) {
339
        if (isPushStateEnabled) {
340
            navigateTo (datum.navlink);
341
        } else {
342
            window.location = datum.navlink;
343
        }
344
    });
345
346
    if(typeof postRefresh == 'function')
347
    { postRefresh(); }
348
};
349
350
navigateTo = function (url) {
351
    $("h1").append (" <i class='fas fa-spinner fa-pulse'></i>");
352
    before = new Date ();
353
    var jsonurl = url.replace ("index", "getJSON");
354
    var cachedData = cache.get (jsonurl);
355
    if (cachedData) {
356
        window.history.pushState(jsonurl, "", url);
357
        updatePage (cachedData);
358
    } else {
359
        $.getJSON(jsonurl, function(data) {
360
            window.history.pushState(jsonurl, "", url);
361
            cache.put (jsonurl, data);
362
            updatePage (data);
363
        });
364
    }
365
};
366
367
function link_Clicked (event) {
368
    var currentLink = $(this);
369
    if (!isPushStateEnabled ||
370
        currentData.page === "19") {
371
        return;
372
    }
373
    event.preventDefault();
374
    var url = currentLink.attr('href');
375
376
    if ($(".mfp-ready").length)
377
    {
378
        $.magnificPopup.close();
379
    }
380
381
    // The bookdetail / about should be displayed in a lightbox
382
    if (getCurrentOption ("use_fancyapps") === "1" &&
383
        (currentLink.hasClass ("fancydetail") || currentLink.hasClass ("fancyabout"))) {
384
        before = new Date ();
385
        var jsonurl = url.replace ("index", "getJSON");
386
        $.getJSON(jsonurl, function(data) {
387
            data.c = currentData.c;
388
            var detail = "";
389
            if (data.page === "16") {
390
                detail = data.fullhtml;
391
            } else {
392
                detail = templateBookDetail (data);
393
            }
394
            $.magnificPopup.open({
395
              items: {
396
                src: detail,
397
                type: 'inline'
398
              }
399
            });
400
            debug_log (elapsed ());
401
        });
402
        return;
403
    }
404
    navigateTo (url);
405
}
406
407
function search_Submitted (event) {
408
    if (!isPushStateEnabled ||
409
        currentData.page === "19") {
410
        return;
411
    }
412
    event.preventDefault();
413
    var url = str_format ("index.php?page=9&current={0}&query={1}&db={2}", currentData.page, encodeURIComponent ($("input[name=query]").val ()), currentData.databaseId);
414
    navigateTo (url);
415
}
416
417
/*exported handleLinks */
418
function handleLinks () {
419
    $("body").on ("click", "a[href^='index']", link_Clicked);
420
    $("body").on ("submit", "#searchForm", search_Submitted);
421
    $("body").on ("click", "#sort", function(){
422
        $('.books').sortElements(function(a, b){
423
            var test = 1;
424
            if ($("#sortorder").val() === "desc")
425
            {
426
                test = -1;
427
            }
428
            return $(a).find ("." + $("#sortchoice").val()).text() > $(b).find ("." + $("#sortchoice").val()).text() ? test : -test;
429
        });
430
    });
431
432
    $("body").on ("click", ".headright", function(){
433
        if ($("#tool").is(":hidden")) {
434
            $("#tool").slideDown("slow");
435
            $("input[name=query]").focus();
436
            $.cookie('toolbar', '1', { expires: 365 });
437
        } else {
438
            $("#tool").slideUp();
439
            $.removeCookie('toolbar');
440
        }
441
    });
442
    $("body").magnificPopup({
443
        delegate: '.fancycover', // child items selector, by clicking on it popup will open
444
        type: 'image',
445
        gallery:{enabled:true, preload: [0,2]},
446
        disableOn: function() {
447
          if( getCurrentOption ("use_fancyapps") === "1" ) {
448
            return true;
449
          }
450
          return false;
451
        }
452
    });
453
}
454
455
window.onpopstate = function(event) {
456
    if (!isDefined (currentData)) {
457
        return;
458
    }
459
460
    before = new Date ();
461
    var data = cache.get (event.state);
462
    updatePage (data);
463
};
464
465
$(document).keydown(function(e){
466
    if (e.keyCode === 37 && $("#prevLink").length > 0) {
467
        navigateTo ($("#prevLink").attr('href'));
468
    }
469
    if (e.keyCode === 39  && $("#nextLink").length > 0) {
470
        navigateTo ($("#nextLink").attr('href'));
471
    }
472
});
473
474
/*exported initiateAjax */
475
function initiateAjax (url, theme) {
476
    $.when($.get('templates/' + theme + '/header.html'),
477
           $.get('templates/' + theme + '/footer.html'),
478
           $.get('templates/' + theme + '/bookdetail.html'),
479
           $.get('templates/' + theme + '/main.html'),
480
           $.get('templates/' + theme + '/page.html'),
481
           $.get('templates/' + theme + '/suggestion.html'),
482
           $.getJSON(url)).done(function(header, footer, bookdetail, main, page, suggestion, data){
483
        templateBookDetail = doT.template (bookdetail [0]);
484
485
        var defMain = {
486
            bookdetail: bookdetail [0]
487
        };
488
489
        templateMain = doT.template (main [0], undefined, defMain);
490
491
        var defPage = {
492
            header: header [0],
493
            footer: footer [0],
494
            main  : main [0],
495
            bookdetail: bookdetail [0]
496
        };
497
498
        templatePage = doT.template (page [0], undefined, defPage);
499
500
        templateSuggestion = doT.template (suggestion [0]);
501
502
        currentData = data [0];
503
504
        updatePage (data [0]);
505
        cache.put (url, data [0]);
506
        if (isPushStateEnabled) {
507
            window.history.replaceState(url, "", window.location);
508
        }
509
        handleLinks ();
510
    });
511
}
512