Completed
Push — master ( 306060...2234f3 )
by Markus
03:46
created

util.js (4 issues)

Labels
Severity

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!');
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
  /** global: navigator */
40
  !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/);
0 ignored issues
show
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
41
42
function debug_log(text) {
43
    if ( DEBUG ) {
44
        console.log(text);
45
    }
46
}
47
48
/*exported updateCookie */
49
function updateCookie (id) {
50
    if ($(id).prop('pattern') && !$(id).val().match(new RegExp ($(id).prop('pattern')))) {
51
        return;
52
    }
53
    var name = $(id).attr('id');
54
    var value = $(id).val ();
55
    $.cookie(name, value, { expires: 365 });
56
}
57
58
/*exported updateCookieFromCheckbox */
59
function updateCookieFromCheckbox (id) {
60
    var name = $(id).attr('id');
61
    if ((/^style/).test (name)) {
62
        name = "style";
63
    }
64
    if ($(id).is(":checked"))
65
    {
66
        if ($(id).is(':radio')) {
67
            $.cookie(name, $(id).val (), { expires: 365 });
68
        } else {
69
            $.cookie(name, '1', { expires: 365 });
70
        }
71
    }
72
    else
73
    {
74
        $.cookie(name, '0', { expires: 365 });
75
    }
76
}
77
78
/*exported updateCookieFromCheckboxGroup */
79
function updateCookieFromCheckboxGroup (id) {
80
    var name = $(id).attr('name');
81
    var idBase = name.replace (/\[\]/, "");
82
    var group = [];
83
    $(':checkbox[name="' + name + '"]:checked').each (function () {
84
        var id = $(this).attr("id");
85
        group.push (id.replace (idBase + "_", ""));
86
    });
87
    $.cookie(idBase, group.join (), { expires: 365 });
88
}
89
90
91
function elapsed () {
92
    var elapsedTime = new Date () - before;
93
    return "Elapsed : " + elapsedTime;
94
}
95
96
function retourMail(data) {
97
    $("#mailButton :first-child").removeClass ("icon-spinner icon-spin").addClass ("icon-envelope");
98
    alert (data);
99
}
100
101
/*exported sendToMailAddress */
102
function sendToMailAddress (component, dataid) {
103
    var email = $.cookie ('email');
104
    if (!$.cookie ('email')) {
105
        email = window.prompt (currentData.c.i18n.customizeEmail, "");
106
        if (email === null)
107
        {
108
            return;
109
        }
110
        $.cookie ('email', email, { expires: 365 });
111
    }
112
    var url = 'sendtomail.php';
113
    if (currentData.databaseId) {
114
        url = url + '?db=' + currentData.databaseId;
115
    }
116
    $("#mailButton :first-child").removeClass ("icon-envelope").addClass ("icon-spinner icon-spin");
117
    $.ajax ({'url': url, 'type': 'post', 'data': { 'data':  dataid, 'email': email }, 'success': retourMail});
118
}
119
120
function str_format () {
121
    var s = arguments[0];
122
    for (var i = 0; i < arguments.length - 1; i++) {
123
        var reg = new RegExp("\\{" + i + "\\}", "gm");
124
        s = s.replace(reg, arguments[i + 1]);
125
    }
126
    return s;
127
}
128
129
function isDefined(x) {
130
    var undefinedVar;
131
    return x !== undefinedVar;
132
}
133
134
function getCurrentOption (option) {
135
    if (!$.cookie (option)) {
136
        if (currentData && currentData.c && currentData.c.config && currentData.c.config [option]) {
137
            return currentData.c.config [option];
138
        }
139
    }
140
    return $.cookie (option);
141
}
142
143
/*exported htmlspecialchars */
144
function htmlspecialchars(str) {
145
    return String(str)
146
            .replace(/&/g, '&amp;')
147
            .replace(/"/g, '&quot;')
148
            .replace(/'/g, '&#39;')
149
            .replace(/</g, '&lt;')
150
            .replace(/>/g, '&gt;');
151
}
152
153
/************************************************
154
 * All functions needed to filter the book list by tags
155
 ************************************************
156
 */
157
158
function getTagList () {
159
    var tagList = {};
160
    $(".se").each (function(){
161
        if ($(this).parents (".filtered").length > 0) { return; }
162
        var taglist = $(this).text();
163
164
        var tagarray = taglist.split (",");
165
        for (var i in tagarray) {
166
            if (!tagarray.hasOwnProperty(i)) {
167
                continue;
168
            }
169
            var tag = tagarray [i].replace(/^\s+/g,'').replace(/\s+$/g,'');
170
            tagList [tag] = 1;
171
        }
172
    });
173
    return tagList;
174
}
175
176
function updateFilters () {
177
    var tagList = getTagList ();
178
179
    // If there is already some filters then let's prepare to update the list
180
    $("#filter ul li").each (function () {
181
        var text = $(this).text ();
182
        if (isDefined (tagList [text]) || $(this).attr ('class')) {
183
            tagList [text] = 0;
184
        } else {
185
            tagList [text] = -1;
186
        }
187
    });
188
189
    // Update the filter -1 to remove, 1 to add, 0 already there
190
    for (var tag in tagList) {
191
        if (!tagList.hasOwnProperty(tag)) {
192
            continue;
193
        }
194
        var tagValue = tagList [tag];
195
        if (tagValue === -1) {
196
            $("#filter ul li").filter (function () { return $.text([this]) === tag; }).remove();
197
        }
198
        if (tagValue === 1) {
199
            $("#filter ul").append ("<li>" + tag + "</li>");
200
        }
201
    }
202
203
    $("#filter ul").append ("<li>_CLEAR_</li>");
204
205
    // Sort the list alphabetically
206
    $('#filter ul li').sortElements(function(a, b){
207
        return $(a).text() > $(b).text() ? 1 : -1;
208
    });
209
}
210
211
function doFilter () {
212
    $(".books").removeClass("filtered");
213
    if (jQuery.isEmptyObject(filterList)) {
214
        updateFilters ();
215
        return;
216
    }
217
218
    $(".se").each (function(){
219
        var taglist = ", " + $(this).text() + ", ";
220
        var toBeFiltered = false;
221
        for (var filter in filterList) {
222
            if (!filterList.hasOwnProperty(filter)) {
223
                continue;
224
            }
225
            var onlyThisTag = filterList [filter];
226
            filter = ', ' + filter + ', ';
227
            var myreg = new RegExp (filter);
228
            if (myreg.test (taglist)) {
229
                if (onlyThisTag === false) {
230
                    toBeFiltered = true;
231
                }
232
            } else {
233
                if (onlyThisTag === true) {
234
                    toBeFiltered = true;
235
                }
236
            }
237
        }
238
        if (toBeFiltered) { $(this).parents (".books").addClass ("filtered"); }
239
    });
240
241
    // Handle the books with no tags
242
    var atLeastOneTagSelected = false;
243
    for (var filter in filterList) {
244
        if (!filterList.hasOwnProperty(filter)) {
245
            continue;
246
        }
247
        if (filterList[filter] === true) {
248
            atLeastOneTagSelected = true;
249
        }
250
    }
251
    if (atLeastOneTagSelected) {
252
        $(".books").not (":has(span.se)").addClass ("filtered");
253
    }
254
255
    updateFilters ();
256
}
257
258
function handleFilterEvents () {
259
    $("#filter ul").on ("click", "li", function(){
260
        var filter = $(this).text ();
261
        if (filter === "_CLEAR_") {
262
            filterList = {};
263
            $("#filter ul li").removeClass ("filter-exclude");
264
            $("#filter ul li").removeClass ("filter-include");
265
            doFilter ();
266
            return;
267
        }
268
        switch ($(this).attr("class")) {
269
            case "filter-include" :
270
                $(this).attr("class", "filter-exclude");
271
                filterList [filter] = false;
272
                break;
273
            case "filter-exclude" :
274
                $(this).removeClass ("filter-exclude");
275
                delete filterList [filter];
276
                break;
277
            default :
278
                $(this).attr("class", "filter-include");
279
                filterList [filter] = true;
280
                break;
281
        }
282
        doFilter ();
283
    });
284
}
285
286
/************************************************
287
 * Functions to handle Ajax navigation
288
 ************************************************
289
 */
290
291
var updatePage, navigateTo;
292
293
updatePage = function (data) {
294
    var result;
295
    filterList = {};
296
    data.c = currentData.c;
297
    if (false && $("section").length && currentData.isPaginated === 0 &&  data.isPaginated === 0) {
298
        // Partial update (for now disabled)
299
        debug_log ("Partial update");
300
        result = templateMain (data);
301
        $("h1").html (data.title);
302
        $("section").html (result);
303
    } else {
304
        // Full update
305
        result = templatePage (data);
306
        $("body").html (result);
307
    }
308
    document.title = data.title;
309
    currentData = data;
310
    setTimeout( function() { $("input[name=query]").focus(); }, 500 );
311
312
    debug_log (elapsed ());
313
314
    if ($.cookie('toolbar') === '1') { $("#tool").show (); }
315
    if (currentData.containsBook === 1) {
316
        $("#sortForm").show ();
317
        if (getCurrentOption ("html_tag_filter") === "1") {
318
            $("#filter ul").empty ();
319
            updateFilters ();
320
            handleFilterEvents ();
321
        }
322
    } else {
323
        $("#sortForm").hide ();
324
    }
325
326
    $('input[name=query]').typeahead(
327
    {
328
        hint: true,
329
        minLength : 3
330
    },
331
    {
332
        name: 'search',
333
        displayKey: 'title',
334
        templates: {
335
            suggestion: templateSuggestion
336
        },
337
        source: copsTypeahead.ttAdapter()
338
    });
339
340
    $('input[name=query]').bind('typeahead:selected', function(obj, datum) {
341
        if (isPushStateEnabled) {
342
            navigateTo (datum.navlink);
343
        } else {
344
            window.location = datum.navlink;
345
        }
346
    });
347
348
    if(typeof postRefresh == 'function')
349
    { postRefresh(); }
350
};
351
352
navigateTo = function (url) {
353
    $("h1").append (" <i class='icon-spinner icon-spin'></i>");
354
    before = new Date ();
355
    var jsonurl = url.replace ("index", "getJSON");
356
    var cachedData = cache.get (jsonurl);
357
    if (cachedData) {
358
        /** global: history */
359
        history.pushState(jsonurl, "", url);
0 ignored issues
show
The variable history seems to be never declared. If this is a global, consider adding a /** global: history */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
360
        updatePage (cachedData);
361
    } else {
362
        $.getJSON(jsonurl, function(data) {
363
            /** global: history */
364
            history.pushState(jsonurl, "", url);
0 ignored issues
show
The variable history seems to be never declared. If this is a global, consider adding a /** global: history */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
365
            cache.put (jsonurl, data);
366
            updatePage (data);
367
        });
368
    }
369
};
370
371
function link_Clicked (event) {
372
    var currentLink = $(this);
373
    if (!isPushStateEnabled ||
374
        currentData.page === "19") {
375
        return;
376
    }
377
    event.preventDefault();
378
    var url = currentLink.attr('href');
379
380
    if ($(".mfp-ready").length)
381
    {
382
        $.magnificPopup.close();
383
    }
384
385
    // The bookdetail / about should be displayed in a lightbox
386
    if (getCurrentOption ("use_fancyapps") === "1" &&
387
        (currentLink.hasClass ("fancydetail") || currentLink.hasClass ("fancyabout"))) {
388
        before = new Date ();
389
        var jsonurl = url.replace ("index", "getJSON");
390
        $.getJSON(jsonurl, function(data) {
391
            data.c = currentData.c;
392
            var detail = "";
393
            if (data.page === "16") {
394
                detail = data.fullhtml;
395
            } else {
396
                detail = templateBookDetail (data);
397
            }
398
            $.magnificPopup.open({
399
              items: {
400
                src: detail,
401
                type: 'inline'
402
              }
403
            });
404
            debug_log (elapsed ());
405
        });
406
        return;
407
    }
408
    navigateTo (url);
409
}
410
411
function search_Submitted (event) {
412
    if (!isPushStateEnabled ||
413
        currentData.page === "19") {
414
        return;
415
    }
416
    event.preventDefault();
417
    var url = str_format ("index.php?page=9&current={0}&query={1}&db={2}", currentData.page, encodeURIComponent ($("input[name=query]").val ()), currentData.databaseId);
418
    navigateTo (url);
419
}
420
421
/*exported handleLinks */
422
function handleLinks () {
423
    $("body").on ("click", "a[href^='index']", link_Clicked);
424
    $("body").on ("submit", "#searchForm", search_Submitted);
425
    $("body").on ("click", "#sort", function(){
426
        $('.books').sortElements(function(a, b){
427
            var test = 1;
428
            if ($("#sortorder").val() === "desc")
429
            {
430
                test = -1;
431
            }
432
            return $(a).find ("." + $("#sortchoice").val()).text() > $(b).find ("." + $("#sortchoice").val()).text() ? test : -test;
433
        });
434
    });
435
436
    $("body").on ("click", ".headright", function(){
437
        if ($("#tool").is(":hidden")) {
438
            $("#tool").slideDown("slow");
439
            $("input[name=query]").focus();
440
            $.cookie('toolbar', '1', { expires: 365 });
441
        } else {
442
            $("#tool").slideUp();
443
            $.removeCookie('toolbar');
444
        }
445
    });
446
    $("body").magnificPopup({
447
        delegate: '.fancycover', // child items selector, by clicking on it popup will open
448
        type: 'image',
449
        gallery:{enabled:true, preload: [0,2]},
450
        disableOn: function() {
451
          if( getCurrentOption ("use_fancyapps") === "1" ) {
452
            return true;
453
          }
454
          return false;
455
        }
456
    });
457
}
458
459
window.onpopstate = function(event) {
460
    if (!isDefined (currentData)) {
461
        return;
462
    }
463
464
    before = new Date ();
465
    var data = cache.get (event.state);
466
    updatePage (data);
467
};
468
469
$(document).keydown(function(e){
470
    if (e.keyCode === 37 && $("#prevLink").length > 0) {
471
        navigateTo ($("#prevLink").attr('href'));
472
    }
473
    if (e.keyCode === 39  && $("#nextLink").length > 0) {
474
        navigateTo ($("#nextLink").attr('href'));
475
    }
476
});
477
478
/*exported initiateAjax */
479
function initiateAjax (url, theme) {
480
    $.when($.get('templates/' + theme + '/header.html'),
481
           $.get('templates/' + theme + '/footer.html'),
482
           $.get('templates/' + theme + '/bookdetail.html'),
483
           $.get('templates/' + theme + '/main.html'),
484
           $.get('templates/' + theme + '/page.html'),
485
           $.get('templates/' + theme + '/suggestion.html'),
486
           $.getJSON(url)).done(function(header, footer, bookdetail, main, page, suggestion, data){
487
        templateBookDetail = doT.template (bookdetail [0]);
488
489
        var defMain = {
490
            bookdetail: bookdetail [0]
491
        };
492
493
        templateMain = doT.template (main [0], undefined, defMain);
494
495
        var defPage = {
496
            header: header [0],
497
            footer: footer [0],
498
            main  : main [0],
499
            bookdetail: bookdetail [0]
500
        };
501
502
        templatePage = doT.template (page [0], undefined, defPage);
503
504
        templateSuggestion = doT.template (suggestion [0]);
505
506
        currentData = data [0];
507
508
        updatePage (data [0]);
509
        cache.put (url, data [0]);
510
        if (isPushStateEnabled) {
511
            history.replaceState(url, "", window.location);
0 ignored issues
show
The variable history seems to be never declared. If this is a global, consider adding a /** global: history */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
512
        }
513
        handleLinks ();
514
    });
515
}
516