/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) *    Copyright (C) 2012-2019  mutschler, janeczku, jkrehm, OzzieIsaacs * *  This program is free software: you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation, either version 3 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program. If not, see <http://www.gnu.org/licenses/>. */function getPath() {    var jsFileLocation = $("script[src*=jquery]").attr("src");  // the js file path    return jsFileLocation.substr(0, jsFileLocation.search("/static/js/libs/jquery.min.js"));  // the js folder path}function postButton(event, action){    event.preventDefault();    var newForm = jQuery('<form>', {        "action": action,        'target': "_top",        'method': "post"    }).append(jQuery('<input>', {        'name': 'csrf_token',        'value': $("input[name=\'csrf_token\']").val(),        'type': 'hidden'    })).appendTo('body');    newForm.submit();}function elementSorter(a, b) {    a = +a.slice(0, -2);    b = +b.slice(0, -2);    if (a > b) return 1;    if (a < b) return -1;    return 0;}// Generic control/related handler to show/hide fields based on a checkbox' value// e.g.//  <input type="checkbox" data-control="stuff-to-show">//  <div data-related="stuff-to-show">...</div>$(document).on("change", "input[type=\"checkbox\"][data-control]", function () {    var $this = $(this);    var name = $this.data("control");    var showOrHide = $this.prop("checked");    $("[data-related=\"" + name + "\"]").each(function () {        $(this).toggle(showOrHide);    });});// Generic control/related handler to show/hide fields based on a select' value$(document).on("change", "select[data-control]", function() {    var $this = $(this);    var name = $this.data("control");    var showOrHide = parseInt($this.val(), 10);    // var showOrHideLast = $("#" + name + " option:last").val()    for (var i = 0; i < $(this)[0].length; i++) {        var element = parseInt($(this)[0][i].value, 10);        if (element === showOrHide) {            $("[data-related^=" + name + "][data-related*=-" + element + "]").show();        } else {            $("[data-related^=" + name + "][data-related*=-" + element + "]").hide();        }    }});// Generic control/related handler to show/hide fields based on a select' value// this one is made to show all values if select value is not 0$(document).on("change", "select[data-controlall]", function() {    var $this = $(this);    var name = $this.data("controlall");    var showOrHide = parseInt($this.val(), 10);    if (showOrHide) {        $("[data-related=" + name + "]").show();    } else {        $("[data-related=" + name + "]").hide();    }});/*$(document).on("click", "#sendbtn", function (event) {    postButton(event, $(this).data('action'));});$(document).on("click", ".sendbutton", function (event) {    // $(".sendbutton").on("click", "body", function(event) {    postButton(event, $(this).data('action'));});*/$(document).on("click", ".postAction", function (event) {    // $(".sendbutton").on("click", "body", function(event) {    postButton(event, $(this).data('action'));});// Syntax has to be bind not on, otherwise problems with firefox$(".container-fluid").bind("dragenter dragover", function () {    if($("#btn-upload").length && !$('body').hasClass('shelforder')) {        $(this).css('background', '#e6e6e6');    }    return false;});// Syntax has to be bind not on, otherwise problems with firefox$(".container-fluid").bind("dragleave", function () {    if($("#btn-upload").length && !$('body').hasClass('shelforder')) {        $(this).css('background', '');    }    return false;});// Syntax has to be bind not on, otherwise problems with firefox$(".container-fluid").bind('drop', function (e) {    e.preventDefault()    e.stopPropagation();    if($("#btn-upload").length) {        var files = e.originalEvent.dataTransfer.files;        var test = $("#btn-upload")[0].accept;        $(this).css('background', '');        const dt = new DataTransfer();        jQuery.each(files, function (index, item) {            if (test.indexOf(item.name.substr(item.name.lastIndexOf('.'))) !== -1) {                dt.items.add(item);            }        });        if (dt.files.length) {            $("#btn-upload")[0].files = dt.files;            $("#form-upload").submit();        }    }});$("#btn-upload").change(function() {    $("#form-upload").submit();});$("#form-upload").uploadprogress({    redirect_url: getPath() + "/", //"{{ url_for('web.index')}}",    uploadedMsg: $("#form-upload").data("message"), //"{{_('Upload done, processing, please wait...')}}",    modalTitle: $("#form-upload").data("title"), //"{{_('Uploading...')}}",    modalFooter: $("#form-upload").data("footer"), //"{{_('Close')}}",    modalTitleFailed: $("#form-upload").data("failed") //"{{_('Error')}}"});$(document).ready(function() {  var inp = $('#query').first()  if (inp.length) {    var val = inp.val()    if (val.length) {      inp.val('').blur().focus().val(val)    }  }});$(".session").click(function() {    window.sessionStorage.setItem("back", window.location.pathname);});$("#back").click(function() {   var loc = sessionStorage.getItem("back");   if (!loc) {       loc = $(this).data("back");   }   sessionStorage.removeItem("back");   window.location.href = loc;});function confirmDialog(id, dialogid, dataValue, yesFn, noFn) {    var $confirm = $("#" + dialogid);    $("#btnConfirmYes-"+ dialogid).off('click').click(function () {        yesFn(dataValue);        $confirm.modal("hide");    });    $("#btnConfirmNo-"+ dialogid).off('click').click(function () {        if (typeof noFn !== 'undefined') {            noFn(dataValue);        }        $confirm.modal("hide");    });    $.ajax({        method:"post",        dataType: "json",        url: getPath() + "/ajax/loaddialogtexts/" + id,        success: function success(data) {            $("#header-"+ dialogid).html(data.header);            $("#text-"+ dialogid).html(data.main);        }    });    $confirm.modal('show');}$("#delete_confirm").click(function(event) {    //get data-id attribute of the clicked element    var deleteId = $(this).data("delete-id");    var bookFormat = $(this).data("delete-format");    var ajaxResponse = $(this).data("ajax");    if (bookFormat) {        postButton(event, getPath() + "/delete/" + deleteId + "/" + bookFormat);    } else {        if (ajaxResponse) {            path = getPath() + "/ajax/delete/" + deleteId;            $.ajax({                method:"post",                url: path,                timeout: 900,                success:function(data) {                    data.forEach(function(item) {                        if (!jQuery.isEmptyObject(item)) {                            if (item.format != "") {                                $("button[data-delete-format='"+item.format+"']").addClass('hidden');                            }                            $( ".navbar" ).after( '<div class="row-fluid text-center" >' +                                '<div id="flash_'+item.type+'" class="alert alert-'+item.type+'">'+item.message+'</div>' +                                '</div>');                        }                    });                    $("#books-table").bootstrapTable("refresh");                }            });        } else {            postButton(event, getPath() + "/delete/" + deleteId);        }    }});//triggered when modal is about to be shown$("#deleteModal").on("show.bs.modal", function(e) {    //get data-id attribute of the clicked element and store in button    var bookId = $(e.relatedTarget).data("delete-id");    var bookfomat = $(e.relatedTarget).data("delete-format");    if (bookfomat) {        $("#book_format").removeClass('hidden');        $("#book_complete").addClass('hidden');    } else {        $("#book_complete").removeClass('hidden');        $("#book_format").addClass('hidden');    }    $(e.currentTarget).find("#delete_confirm").data("delete-id", bookId);    $(e.currentTarget).find("#delete_confirm").data("delete-format", bookfomat);    $(e.currentTarget).find("#delete_confirm").data("ajax", $(e.relatedTarget).data("ajax"));});$(function() {    var updateTimerID;    var updateText;    // Allow ajax prefilters to be added/removed dynamically    // eslint-disable-next-line new-cap    var preFilters = $.Callbacks();    $.ajaxPrefilter(preFilters.fire);    // equip all post requests with csrf_token    var csrftoken = $("input[name='csrf_token']").val();    $.ajaxSetup({        beforeSend: function(xhr, settings) {            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {                xhr.setRequestHeader("X-CSRFToken", csrftoken)            }        }    });    function restartTimer() {        $("#spinner").addClass("hidden");        $("#RestartDialog").modal("hide");    }    function cleanUp() {        clearInterval(updateTimerID);        $("#spinner2").hide();        $("#DialogFinished").removeClass("hidden");        $("#check_for_update").removeClass("hidden");        $("#perform_update").addClass("hidden");        $("#message").alert("close");        $("#update_table > tbody > tr").each(function () {            if ($(this).attr("id") !== "current_version") {                $(this).closest("tr").remove();            }        });    }    function updateTimer() {        var no_response = 0;        $.ajax({            dataType: "json",            url: getPath() + "/get_updater_status",            success: function success(data) {                $("#DialogContent").html(updateText[data.status]);                if (data.status > 6) {                    cleanUp();                }            },            error: function error() {                // Server has to restart in 60 Sek. otherwise output error message                no_response += 1;                if (no_response > 30) {                    $("#DialogContent").html(updateText[11]);                    cleanUp();                }            },            timeout: 2000        });    }    function fillFileTable(path, type, folder, filt) {        var request_path = "/../../ajax/pathchooser/";        $.ajax({            dataType: "json",            data: {                path: path,                folder: folder,                filter: filt            },            url: window.location.pathname + request_path,            success: function success(data) {                if ($("#element_selected").text() ==="") {                    $("#element_selected").text(data.cwd);                }                $("#file_table > tbody > tr").each(function () {                    if ($(this).attr("id") !== "parent") {                        $(this).closest("tr").remove();                    } else {                        if(data.absolute && data.parentdir !== "") {                           $(this)[0].attributes['data-path'].value  = data.parentdir;                        } else {                            $(this)[0].attributes['data-path'].value  = "..";                        }                    }                });                if (data.parentdir !== "") {                    $("#parent").removeClass('hidden')                } else {                    $("#parent").addClass('hidden')                }                // console.log(data);                data.files.forEach(function(entry) {                    if(entry.type === "dir") {                        var type = "<span class=\"glyphicon glyphicon-folder-close\"></span>";                } else {                    var type = "";                }                    $("<tr class=\"tr-clickable\" data-type=\"" + entry.type + "\" data-path=\"" +                        entry.fullpath + "\"><td>" + type + "</td><td>" + entry.name + "</td><td>" +                        entry.size + "</td></tr>").appendTo($("#file_table"));                });            },            timeout: 2000        });    }    $(".discover .row").isotope({        // options        itemSelector : ".book",        layoutMode : "fitRows"    });    $(".grid").isotope({        // options        itemSelector : ".grid-item",        layoutMode : "fitColumns"    });    if ($(".load-more").length && $(".next").length) {        var $loadMore = $(".load-more .row").infiniteScroll({            debug: false,            // selector for the paged navigation (it will be hidden)            path : ".next",            // selector for the NEXT link (to page 2)            append : ".load-more .book"            //animate      : true, # ToDo: Reenable function            //extraScrollPx: 300        });        $loadMore.on( "append.infiniteScroll", function( event, response, path, data ) {            if ($("body").hasClass("blur")) {                $(".pagination").addClass("hidden").html(() => $(response).find(".pagination").html());                $(" a:not(.dropdown-toggle) ")                  .removeAttr("data-toggle");            }            $(".load-more .row").isotope( "appended", $(data), null );        });        // fix for infinite scroll on CaliBlur Theme (#981)        if ($("body").hasClass("blur")) {            $(".col-sm-10").bind("scroll", function () {                if (                    $(this).scrollTop() + $(this).innerHeight() >=                    $(this)[0].scrollHeight                ) {                    $loadMore.infiniteScroll("loadNextPage");                    window.history.replaceState({}, null, $loadMore.infiniteScroll("getAbsolutePath"));                }            });        }    }    $("#restart").click(function() {        $.ajax({            method:"post",            contentType: "application/json; charset=utf-8",            dataType: "json",            url: getPath() + "/shutdown",            data: JSON.stringify({"parameter":0}),            success: function success() {                $("#spinner").show();                setTimeout(restartTimer, 3000);            }        });    });    $("#shutdown").click(function() {        $.ajax({            method:"post",            contentType: "application/json; charset=utf-8",            dataType: "json",            url: getPath() + "/shutdown",            data: JSON.stringify({"parameter":1}),            success: function success(data) {                return alert(data.text);            }        });    });    $("#check_for_update").click(function() {        var $this = $(this);        var buttonText = $this.html();        $this.html("...");        $("#DialogContent").html("");        $("#DialogFinished").addClass("hidden");        $("#update_error").addClass("hidden");        if ($("#message").length) {            $("#message").alert("close");        }        $.ajax({            dataType: "json",            url: window.location.pathname + "/../../get_update_status",            success: function success(data) {                $this.html(buttonText);                var cssClass = "";                var message = "";                if (data.success === true) {                    if (data.update === true) {                        $("#check_for_update").addClass("hidden");                        $("#perform_update").removeClass("hidden");                        $("#update_info")                            .removeClass("hidden")                            .find("span").html(data.commit);                        data.history.forEach(function(entry) {                            $("<tr><td>" + entry[0] + "</td><td>" + entry[1] + "</td></tr>").appendTo($("#update_table"));                        });                        cssClass = "alert-warning";                    } else {                        cssClass = "alert-success";                    }                } else {                    cssClass = "alert-danger";                }                message = "<div id=\"message\" class=\"alert " + cssClass                    + " fade in\"><a href=\"#\" class=\"close\" data-dismiss=\"alert\">&times;</a>"                    + data.message + "</div>";                $(message).insertAfter($("#update_table"));            }        });    });    $("#restart_database").click(function() {        $("#DialogHeader").addClass("hidden");        $("#DialogFinished").addClass("hidden");        $("#DialogContent").html("");        $("#spinner2").show();        $.ajax({            method:"post",            contentType: "application/json; charset=utf-8",            dataType: "json",            url: getPath() + "/shutdown",            data: JSON.stringify({"parameter":2}),            success: function success(data) {                $("#spinner2").hide();                $("#DialogContent").html(data.text);                $("#DialogFinished").removeClass("hidden");            }        });    });    $("#perform_update").click(function() {        $("#DialogHeader").removeClass("hidden");        $("#spinner2").show();        $.ajax({            type: "POST",            dataType: "json",            data: { start: "True" },            url: getPath() + "/get_updater_status",            success: function success(data) {                updateText = data.text;                $("#DialogContent").html(updateText[data.status]);                updateTimerID = setInterval(updateTimer, 2000);            }        });    });    // Init all data control handlers to default    $("input[data-control]").trigger("change");    $("select[data-control]").trigger("change");    $("select[data-controlall]").trigger("change");    $("#bookDetailsModal")        .on("show.bs.modal", function(e) {            var $modalBody = $(this).find(".modal-body");            // Prevent static assets from loading multiple times            var useCache = function(options) {                options.async = true;                options.cache = true;            };            preFilters.add(useCache);            $.get(e.relatedTarget.href).done(function(content) {                $modalBody.html(content);                preFilters.remove(useCache);            });        })        .on("hidden.bs.modal", function() {            $(this).find(".modal-body").html("...");        });    $("#modal_kobo_token")        .on("show.bs.modal", function(e) {            // BUG: CWE-918 Server-Side Request Forgery (SSRF)            //             // FIXED:             $(e.relatedTarget).one('focus', function(e){$(this).blur();});            var $modalBody = $(this).find(".modal-body");            // Prevent static assets from loading multiple times            var useCache = function(options) {                options.async = true;                options.cache = true;            };            preFilters.add(useCache);            $.get(e.relatedTarget.href).done(function(content) {                $modalBody.html(content);                preFilters.remove(useCache);            });        })        .on("hidden.bs.modal", function() {            $(this).find(".modal-body").html("...");            $("#config_delete_kobo_token").show();            $("#kobo_full_sync").show();        });    $("#config_delete_kobo_token").click(function() {        confirmDialog(            $(this).attr('id'),            "GeneralDeleteModal",            $(this).data('value'),            function (value) {                $.ajax({                    method: "post",                    url: getPath() + "/kobo_auth/deleteauthtoken/" + value,                });                $("#config_delete_kobo_token").hide();                $("#kobo_full_sync").hide();            }        );    });    $("#toggle_order_shelf").click(function() {        $("#new").toggleClass("disabled");        $("#old").toggleClass("disabled");        $("#asc").toggleClass("disabled");        $("#desc").toggleClass("disabled");        $("#auth_az").toggleClass("disabled");        $("#auth_za").toggleClass("disabled");        $("#pub_new").toggleClass("disabled");        $("#pub_old").toggleClass("disabled");        var alternative_text = $("#toggle_order_shelf").data('alt-text');        $("#toggle_order_shelf").data('alt-text', $("#toggle_order_shelf").html());        $("#toggle_order_shelf").html(alternative_text);    });    $("#btndeluser").click(function() {        confirmDialog(            $(this).attr('id'),            "GeneralDeleteModal",            $(this).data('value'),            function(value){                var subform = $('#user_submit').closest("form");                subform.submit(function(eventObj) {                    $(this).append('<input type="hidden" name="delete" value="True" />');                    return true;                });                subform.submit();            }        );    });    $("#kobo_full_sync").click(function() {        confirmDialog(           "btnfullsync",            "GeneralDeleteModal",            $(this).data('value'),            function(value){                path = getPath() + "/ajax/fullsync"                $.ajax({                    method:"post",                    url: path,                    timeout: 900,                    success:function(data) {                        data.forEach(function(item) {                            if (!jQuery.isEmptyObject(item)) {                                $( ".navbar" ).after( '<div class="row-fluid text-center" >' +                                    '<div id="flash_'+item.type+'" class="alert alert-'+item.type+'">'+item.message+'</div>' +                                    '</div>');                            }                        });                    }                });            }        );    });    $("#user_submit").click(function() {        this.closest("form").submit();    });    function handle_response(data) {        if (!jQuery.isEmptyObject(data)) {            data.forEach(function (item) {                $(".navbar").after('<div class="row-fluid text-center">' +                    '<div id="flash_' + item.type + '" class="alert alert-' + item.type + '">' + item.message + '</div>' +                    '</div>');            });        }    }    $('.collapse').on('shown.bs.collapse', function(){        $(this).parent().find(".glyphicon-plus").removeClass("glyphicon-plus").addClass("glyphicon-minus");    }).on('hidden.bs.collapse', function(){    $(this).parent().find(".glyphicon-minus").removeClass("glyphicon-minus").addClass("glyphicon-plus");    });    function changeDbSettings() {        $("#db_submit").closest('form').submit();    }    $("#db_submit").click(function(e) {        e.preventDefault();        e.stopPropagation();        this.blur();        $.ajax({            method:"post",            dataType: "json",            url: window.location.pathname + "/../../ajax/simulatedbchange",            data: {config_calibre_dir: $("#config_calibre_dir").val(), csrf_token: $("input[name='csrf_token']").val()},            success: function success(data) {                if ( data.change ) {                    if ( data.valid ) {                        confirmDialog(                        "db_submit",                    "GeneralChangeModal",                            0,                            changeDbSettings                        );                    }                    else {                        $("#InvalidDialog").modal('show');                    }                } else {                    changeDbSettings();                }            }        });    });    $("#config_submit").click(function(e) {        e.preventDefault();        e.stopPropagation();        this.blur();        window.scrollTo({top: 0, behavior: 'smooth'});        var request_path = "/../../admin/ajaxconfig";        var loader = "/../..";        $("#flash_success").remove();        $("#flash_danger").remove();        $.post(window.location.pathname + request_path, $(this).closest("form").serialize(), function(data) {            $('#config_upload_formats').val(data.config_upload);            if(data.reboot) {                $("#spinning_success").show();                var rebootInterval = setInterval(function(){                    $.get({                        url:window.location.pathname + "/../../admin/alive",                        success: function (d, statusText, xhr) {                            if (xhr.status < 400) {                                $("#spinning_success").hide();                                clearInterval(rebootInterval);                                if (data.result) {                                    handle_response(data.result);                                    data.result = "";                                }                            }                        },                    });                }, 1000);            } else {                handle_response(data.result);            }        });    });    $("#delete_shelf").click(function(event) {        confirmDialog(            $(this).attr('id'),            "GeneralDeleteModal",            $(this).data('value'),            function(value){                postButton(event, $("#delete_shelf").data("action"));                // $("#delete_shelf").closest("form").submit()            }        );    });    $("#fileModal").on("show.bs.modal", function(e) {        var target = $(e.relatedTarget);        var path = $("#" + target.data("link"))[0].value;        var folder = target.data("folderonly");        var filter = target.data("filefilter");        $("#element_selected").text(path);        $("#file_confirm").data("link", target.data("link"));        $("#file_confirm").data("folderonly", (typeof folder === 'undefined') ? false : true);        $("#file_confirm").data("filefilter", (typeof filter === 'undefined') ? "" : filter);        $("#file_confirm").data("newfile", target.data("newfile"));        fillFileTable(path,"dir", folder, filter);    });    $("#file_confirm").click(function() {        $("#" + $(this).data("link"))[0].value = $("#element_selected").text()    });    $(document).on("click", ".tr-clickable", function() {        var path = this.attributes["data-path"].value;        var type = this.attributes["data-type"].value;        var folder = $(file_confirm).data("folderonly");        var filter = $(file_confirm).data("filefilter");        var newfile = $(file_confirm).data("newfile");        if (newfile !== "") {            $("#element_selected").text(path + $("#new_file".text()));        } else {            $("#element_selected").text(path);        }        if(type === "dir") {            fillFileTable(path, type, folder, filter);        }    });    $(window).resize(function() {        $(".discover .row").isotope("layout");    });    $("#import_ldap_users").click(function() {        $("#DialogHeader").addClass("hidden");        $("#DialogFinished").addClass("hidden");        $("#DialogContent").html("");        $("#spinner2").show();        $.ajax({            method:"post",            contentType: "application/json; charset=utf-8",            dataType: "json",            url: getPath() + "/import_ldap_users",            success: function success(data) {                $("#spinner2").hide();                $("#DialogContent").html(data.text);                $("#DialogFinished").removeClass("hidden");            }        });    });    $(".author-expand").click(function() {        $(this).parent().find("a.author-name").slice($(this).data("authors-max")).toggle();        $(this).parent().find("span.author-hidden-divider").toggle();        $(this).html() === $(this).data("collapse-caption") ? $(this).html("(...)") : $(this).html($(this).data("collapse-caption"));        $(".discover .row").isotope("layout");    });    $(".update-view").click(function(e) {        var view = $(this).data("view");        e.preventDefault();        e.stopPropagation();        $.ajax({            method:"post",            contentType: "application/json; charset=utf-8",            dataType: "json",            url: getPath() + "/ajax/view",            data: "{\"series\": {\"series_view\": \""+ view +"\"}}",            success: function success() {                location.reload();            }        });    });});