Completed
Push — master ( 42b80d...9c8981 )
by Markus
04:20
created

util.js ➔ ... ➔ $(ꞌ.seꞌ).each   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 7
nc 12
nop 0
dl 0
loc 22
rs 6.9811
c 2
b 1
f 0
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
Debugging Code introduced by
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
  /** global: navigator */
40
  !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/);
0 ignored issues
show
Bug introduced by
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);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
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;
0 ignored issues
show
Bug introduced by
The variable undefinedVar seems to be never initialized.
Loading history...
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();
0 ignored issues
show
introduced by
The variable tag is changed by the for-each loop on line 190. Only the value of the last iteration will be visible in this function if it is called outside of the loop.
Loading history...
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
Bug introduced by
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
Bug introduced by
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
Bug introduced by
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