Completed
Push — master ( 2234f3...e72970 )
by Markus
03:52
created

util.js (1 issue)

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
  !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);
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 ("icon-spinner icon-spin").addClass ("icon-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 ("icon-envelope").addClass ("icon-spinner icon-spin");
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
    var undefinedVar;
130
    return x !== undefinedVar;
0 ignored issues
show
The variable undefinedVar seems to be never initialized.
Loading history...
131
}
132
133
function getCurrentOption (option) {
134
    if (!$.cookie (option)) {
135
        if (currentData && currentData.c && currentData.c.config && currentData.c.config [option]) {
136
            return currentData.c.config [option];
137
        }
138
    }
139
    return $.cookie (option);
140
}
141
142
/*exported htmlspecialchars */
143
function htmlspecialchars(str) {
144
    return String(str)
145
            .replace(/&/g, '&amp;')
146
            .replace(/"/g, '&quot;')
147
            .replace(/'/g, '&#39;')
148
            .replace(/</g, '&lt;')
149
            .replace(/>/g, '&gt;');
150
}
151
152
/************************************************
153
 * All functions needed to filter the book list by tags
154
 ************************************************
155
 */
156
157
function getTagList () {
158
    var tagList = {};
159
    $(".se").each (function(){
160
        if ($(this).parents (".filtered").length > 0) { return; }
161
        var taglist = $(this).text();
162
163
        var tagarray = taglist.split (",");
164
        for (var i in tagarray) {
165
            if (!tagarray.hasOwnProperty(i)) {
166
                continue;
167
            }
168
            var tag = tagarray [i].replace(/^\s+/g,'').replace(/\s+$/g,'');
169
            tagList [tag] = 1;
170
        }
171
    });
172
    return tagList;
173
}
174
175
function updateFilters () {
176
    var tagList = getTagList ();
177
178
    // If there is already some filters then let's prepare to update the list
179
    $("#filter ul li").each (function () {
180
        var text = $(this).text ();
181
        if (isDefined (tagList [text]) || $(this).attr ('class')) {
182
            tagList [text] = 0;
183
        } else {
184
            tagList [text] = -1;
185
        }
186
    });
187
188
    // Update the filter -1 to remove, 1 to add, 0 already there
189
    for (var tag in tagList) {
190
        if (!tagList.hasOwnProperty(tag)) {
191
            continue;
192
        }
193
        var tagValue = tagList [tag];
194
        if (tagValue === -1) {
195
            $("#filter ul li").filter (function () { return $.text([this]) === tag; }).remove();
196
        }
197
        if (tagValue === 1) {
198
            $("#filter ul").append ("<li>" + tag + "</li>");
199
        }
200
    }
201
202
    $("#filter ul").append ("<li>_CLEAR_</li>");
203
204
    // Sort the list alphabetically
205
    $('#filter ul li').sortElements(function(a, b){
206
        return $(a).text() > $(b).text() ? 1 : -1;
207
    });
208
}
209
210
function doFilter () {
211
    $(".books").removeClass("filtered");
212
    if (jQuery.isEmptyObject(filterList)) {
213
        updateFilters ();
214
        return;
215
    }
216
217
    $(".se").each (function(){
218
        var taglist = ", " + $(this).text() + ", ";
219
        var toBeFiltered = false;
220
        for (var filter in filterList) {
221
            if (!filterList.hasOwnProperty(filter)) {
222
                continue;
223
            }
224
            var onlyThisTag = filterList [filter];
225
            filter = ', ' + filter + ', ';
226
            var myreg = new RegExp (filter);
227
            if (myreg.test (taglist)) {
228
                if (onlyThisTag === false) {
229
                    toBeFiltered = true;
230
                }
231
            } else {
232
                if (onlyThisTag === true) {
233
                    toBeFiltered = true;
234
                }
235
            }
236
        }
237
        if (toBeFiltered) { $(this).parents (".books").addClass ("filtered"); }
238
    });
239
240
    // Handle the books with no tags
241
    var atLeastOneTagSelected = false;
242
    for (var filter in filterList) {
243
        if (!filterList.hasOwnProperty(filter)) {
244
            continue;
245
        }
246
        if (filterList[filter] === true) {
247
            atLeastOneTagSelected = true;
248
        }
249
    }
250
    if (atLeastOneTagSelected) {
251
        $(".books").not (":has(span.se)").addClass ("filtered");
252
    }
253
254
    updateFilters ();
255
}
256
257
function handleFilterEvents () {
258
    $("#filter ul").on ("click", "li", function(){
259
        var filter = $(this).text ();
260
        if (filter === "_CLEAR_") {
261
            filterList = {};
262
            $("#filter ul li").removeClass ("filter-exclude");
263
            $("#filter ul li").removeClass ("filter-include");
264
            doFilter ();
265
            return;
266
        }
267
        switch ($(this).attr("class")) {
268
            case "filter-include" :
269
                $(this).attr("class", "filter-exclude");
270
                filterList [filter] = false;
271
                break;
272
            case "filter-exclude" :
273
                $(this).removeClass ("filter-exclude");
274
                delete filterList [filter];
275
                break;
276
            default :
277
                $(this).attr("class", "filter-include");
278
                filterList [filter] = true;
279
                break;
280
        }
281
        doFilter ();
282
    });
283
}
284
285
/************************************************
286
 * Functions to handle Ajax navigation
287
 ************************************************
288
 */
289
290
var updatePage, navigateTo;
291
292
updatePage = function (data) {
293
    var result;
294
    filterList = {};
295
    data.c = currentData.c;
296
    if (false && $("section").length && currentData.isPaginated === 0 &&  data.isPaginated === 0) {
297
        // Partial update (for now disabled)
298
        debug_log ("Partial update");
299
        result = templateMain (data);
300
        $("h1").html (data.title);
301
        $("section").html (result);
302
    } else {
303
        // Full update
304
        result = templatePage (data);
305
        $("body").html (result);
306
    }
307
    document.title = data.title;
308
    currentData = data;
309
    setTimeout( function() { $("input[name=query]").focus(); }, 500 );
310
311
    debug_log (elapsed ());
312
313
    if ($.cookie('toolbar') === '1') { $("#tool").show (); }
314
    if (currentData.containsBook === 1) {
315
        $("#sortForm").show ();
316
        if (getCurrentOption ("html_tag_filter") === "1") {
317
            $("#filter ul").empty ();
318
            updateFilters ();
319
            handleFilterEvents ();
320
        }
321
    } else {
322
        $("#sortForm").hide ();
323
    }
324
325
    $('input[name=query]').typeahead(
326
    {
327
        hint: true,
328
        minLength : 3
329
    },
330
    {
331
        name: 'search',
332
        displayKey: 'title',
333
        templates: {
334
            suggestion: templateSuggestion
335
        },
336
        source: copsTypeahead.ttAdapter()
337
    });
338
339
    $('input[name=query]').bind('typeahead:selected', function(obj, datum) {
340
        if (isPushStateEnabled) {
341
            navigateTo (datum.navlink);
342
        } else {
343
            window.location = datum.navlink;
344
        }
345
    });
346
347
    if(typeof postRefresh == 'function')
348
    { postRefresh(); }
349
};
350
351
navigateTo = function (url) {
352
    $("h1").append (" <i class='icon-spinner icon-spin'></i>");
353
    before = new Date ();
354
    var jsonurl = url.replace ("index", "getJSON");
355
    var cachedData = cache.get (jsonurl);
356
    if (cachedData) {
357
        window.history.pushState(jsonurl, "", url);
358
        updatePage (cachedData);
359
    } else {
360
        $.getJSON(jsonurl, function(data) {
361
            window.history.pushState(jsonurl, "", url);
362
            cache.put (jsonurl, data);
363
            updatePage (data);
364
        });
365
    }
366
};
367
368
function link_Clicked (event) {
369
    var currentLink = $(this);
370
    if (!isPushStateEnabled ||
371
        currentData.page === "19") {
372
        return;
373
    }
374
    event.preventDefault();
375
    var url = currentLink.attr('href');
376
377
    if ($(".mfp-ready").length)
378
    {
379
        $.magnificPopup.close();
380
    }
381
382
    // The bookdetail / about should be displayed in a lightbox
383
    if (getCurrentOption ("use_fancyapps") === "1" &&
384
        (currentLink.hasClass ("fancydetail") || currentLink.hasClass ("fancyabout"))) {
385
        before = new Date ();
386
        var jsonurl = url.replace ("index", "getJSON");
387
        $.getJSON(jsonurl, function(data) {
388
            data.c = currentData.c;
389
            var detail = "";
390
            if (data.page === "16") {
391
                detail = data.fullhtml;
392
            } else {
393
                detail = templateBookDetail (data);
394
            }
395
            $.magnificPopup.open({
396
              items: {
397
                src: detail,
398
                type: 'inline'
399
              }
400
            });
401
            debug_log (elapsed ());
402
        });
403
        return;
404
    }
405
    navigateTo (url);
406
}
407
408
function search_Submitted (event) {
409
    if (!isPushStateEnabled ||
410
        currentData.page === "19") {
411
        return;
412
    }
413
    event.preventDefault();
414
    var url = str_format ("index.php?page=9&current={0}&query={1}&db={2}", currentData.page, encodeURIComponent ($("input[name=query]").val ()), currentData.databaseId);
415
    navigateTo (url);
416
}
417
418
/*exported handleLinks */
419
function handleLinks () {
420
    $("body").on ("click", "a[href^='index']", link_Clicked);
421
    $("body").on ("submit", "#searchForm", search_Submitted);
422
    $("body").on ("click", "#sort", function(){
423
        $('.books').sortElements(function(a, b){
424
            var test = 1;
425
            if ($("#sortorder").val() === "desc")
426
            {
427
                test = -1;
428
            }
429
            return $(a).find ("." + $("#sortchoice").val()).text() > $(b).find ("." + $("#sortchoice").val()).text() ? test : -test;
430
        });
431
    });
432
433
    $("body").on ("click", ".headright", function(){
434
        if ($("#tool").is(":hidden")) {
435
            $("#tool").slideDown("slow");
436
            $("input[name=query]").focus();
437
            $.cookie('toolbar', '1', { expires: 365 });
438
        } else {
439
            $("#tool").slideUp();
440
            $.removeCookie('toolbar');
441
        }
442
    });
443
    $("body").magnificPopup({
444
        delegate: '.fancycover', // child items selector, by clicking on it popup will open
445
        type: 'image',
446
        gallery:{enabled:true, preload: [0,2]},
447
        disableOn: function() {
448
          if( getCurrentOption ("use_fancyapps") === "1" ) {
449
            return true;
450
          }
451
          return false;
452
        }
453
    });
454
}
455
456
window.onpopstate = function(event) {
457
    if (!isDefined (currentData)) {
458
        return;
459
    }
460
461
    before = new Date ();
462
    var data = cache.get (event.state);
463
    updatePage (data);
464
};
465
466
$(document).keydown(function(e){
467
    if (e.keyCode === 37 && $("#prevLink").length > 0) {
468
        navigateTo ($("#prevLink").attr('href'));
469
    }
470
    if (e.keyCode === 39  && $("#nextLink").length > 0) {
471
        navigateTo ($("#nextLink").attr('href'));
472
    }
473
});
474
475
/*exported initiateAjax */
476
function initiateAjax (url, theme) {
477
    $.when($.get('templates/' + theme + '/header.html'),
478
           $.get('templates/' + theme + '/footer.html'),
479
           $.get('templates/' + theme + '/bookdetail.html'),
480
           $.get('templates/' + theme + '/main.html'),
481
           $.get('templates/' + theme + '/page.html'),
482
           $.get('templates/' + theme + '/suggestion.html'),
483
           $.getJSON(url)).done(function(header, footer, bookdetail, main, page, suggestion, data){
484
        templateBookDetail = doT.template (bookdetail [0]);
485
486
        var defMain = {
487
            bookdetail: bookdetail [0]
488
        };
489
490
        templateMain = doT.template (main [0], undefined, defMain);
491
492
        var defPage = {
493
            header: header [0],
494
            footer: footer [0],
495
            main  : main [0],
496
            bookdetail: bookdetail [0]
497
        };
498
499
        templatePage = doT.template (page [0], undefined, defPage);
500
501
        templateSuggestion = doT.template (suggestion [0]);
502
503
        currentData = data [0];
504
505
        updatePage (data [0]);
506
        cache.put (url, data [0]);
507
        if (isPushStateEnabled) {
508
            window.history.replaceState(url, "", window.location);
509
        }
510
        handleLinks ();
511
    });
512
}
513