commit
93720c9fdf
@ -1,4 +1,4 @@
|
||||
helper.py ident export-subst
|
||||
updater.py ident export-subst
|
||||
/test export-ignore
|
||||
cps/static/css/libs/* linguist-vendored
|
||||
cps/static/js/libs/* linguist-vendored
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@
|
||||
@media (min-device-width: 768px) {
|
||||
.upload-modal-dialog {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
}
|
||||
}
|
@ -0,0 +1,708 @@
|
||||
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||
* Copyright (C) 2018-2019 hexeth
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
// Move advanced search to side-menu
|
||||
$( 'a[href*="advanced"]' ).parent().insertAfter( '#nav_new' );
|
||||
$( 'body' ).addClass('blur');
|
||||
$( 'body.stat' ).addClass( 'stats' );
|
||||
$( 'body.config' ).addClass( 'admin');
|
||||
$( 'body.uiconfig' ).addClass( 'admin');
|
||||
$( 'body.advsearch' ).addClass( 'advanced_search' );
|
||||
$( 'body.newuser' ).addClass( 'admin' );
|
||||
$( 'body.mailset' ).addClass( 'admin' );
|
||||
|
||||
// Back button
|
||||
curHref = window.location.href.split('/');
|
||||
prevHref = document.referrer.split('/');
|
||||
$( '.navbar-form.navbar-left' )
|
||||
.before( '<div class="plexBack"><a href="' + document.referrer + '"></a></div>' );
|
||||
if ( history.length === 1 ||
|
||||
curHref[0] +
|
||||
curHref[1] +
|
||||
curHref[2] !=
|
||||
prevHref[0] +
|
||||
prevHref[1] +
|
||||
prevHref[2] ||
|
||||
$( 'body.root' )>length > 0 ) {
|
||||
$( '.plexBack' ).addClass( 'noBack' );
|
||||
}
|
||||
|
||||
//Weird missing a after pressing back from edit.
|
||||
setTimeout(function() {
|
||||
if ( $( '.plexBack a').length < 1 ) {
|
||||
$( '.plexBack' ).append('<a href="' + document.referrer + '"></a>');
|
||||
}
|
||||
},10);
|
||||
|
||||
// Home button
|
||||
$( '.plexBack' ).before( '<div class="home-btn"></div>' );
|
||||
$( 'a.navbar-brand' ).clone().appendTo( '.home-btn' ).empty().removeClass('navbar-brand');
|
||||
/////////////////////////////////
|
||||
// Start of Book Details Work //
|
||||
///////////////////////////////
|
||||
|
||||
// Wrap book description in div container
|
||||
if ( $( 'body.book' ).length > 0 ) {
|
||||
|
||||
description = $( '.comments' );
|
||||
bookInfo = $( '.author' ).nextUntil( 'h3:contains("Description")');
|
||||
$( 'h3:contains("Description")' ).detach();
|
||||
$( '.comments' ).detach();
|
||||
$( bookInfo ).wrapAll( '<div class="bookinfo"></div>' );
|
||||
// $( 'h3:contains("Description:")' ).after( '<div class="description"></div>' );
|
||||
$( '.languages' ).appendTo( '.bookinfo' );
|
||||
$('.hr').detach();
|
||||
if ( $( '.identifiers ').length > 0 ) {
|
||||
console.log(".identifiers length " + $( '.identifiers ').length );
|
||||
$( '.identifiers' ).before( '<div class="hr"></div>' );
|
||||
} else {
|
||||
if ( $( '.bookinfo > p:first-child' ).length > 0 ) {
|
||||
console.log(".bookinfo > p:first-child length " + $( '.bookinfo > p' ).length );
|
||||
$( '.bookinfo > p:first-child' ).first().after( '<div class="hr"></div>' );
|
||||
} else{
|
||||
if ( $( '.bookinfo a[href*="/series/"]' ).length > 0 ) {
|
||||
console.log( 'series text found; placing hr below series' );
|
||||
$( '.bookinfo a[href*="/series/"]' ).parent().after( '<div class="hr"></div>' );
|
||||
} else {
|
||||
console.log("prepending hr div to top of .bookinfo");
|
||||
$( '.bookinfo' ).prepend( '<div class="hr"></div>' );
|
||||
}
|
||||
}
|
||||
}
|
||||
$( '.rating' ).insertBefore( '.hr' );
|
||||
$( '#remove-from-shelves' ).insertAfter( '.hr' );
|
||||
$( description ).appendTo('.bookinfo')
|
||||
/* if book description is not in html format, Remove extra line breaks
|
||||
Remove blank lines/unnecessary spaces, split by line break to array
|
||||
Push array into .description div. If there is still a wall of text,
|
||||
find sentences and split wall into groups of three sentence paragraphs.
|
||||
If the book format is in html format, Keep html, but strip away inline
|
||||
styles and empty elements */
|
||||
|
||||
// If text is sitting in div as text node
|
||||
if ( $('.comments:has(p)' ).length === 0 ) {
|
||||
newdesc = description.text()
|
||||
.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split(/\n/);
|
||||
$('.comments' ).empty();
|
||||
$.each(newdesc, function(i, val) {
|
||||
$( 'div.comments' ).append( '<p>' + newdesc[i] + '</p>' );
|
||||
});
|
||||
$( '.comments' ).fadeIn(100);
|
||||
} //If still a wall of text create 3 sentence paragraphs.
|
||||
if( $( '.comments p' ).length === 1 ) {
|
||||
if ( description.context != undefined ) {
|
||||
newdesc = description.text()
|
||||
.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split(/\n/);
|
||||
}
|
||||
else {
|
||||
newdesc = description.text();
|
||||
}
|
||||
doc = nlp ( newdesc.toString() );
|
||||
sentences = doc.map((m)=> m.out( 'text' ));
|
||||
sentences[0] = sentences[0].replace(",","");
|
||||
$( '.comments p' ).remove();
|
||||
let size = 3; let sentenceChunks = [];
|
||||
for (var i=0; i<sentences.length; i+=size) {
|
||||
sentenceChunks.push(sentences.slice(i,i+size));
|
||||
}
|
||||
let output = '';
|
||||
$.each(sentenceChunks, function(i, val) {
|
||||
let preOutput = '';
|
||||
$.each(val, function(i, val) {
|
||||
preOutput += val;
|
||||
});
|
||||
output += '<p>' + preOutput + '</p>';
|
||||
});
|
||||
$( 'div.comments' ).append( output );
|
||||
}
|
||||
else {
|
||||
$.each(description, function(i, val) {
|
||||
// $( description[i].outerHTML ).appendTo( '.comments' );
|
||||
$( 'div.comments :empty' ).remove();
|
||||
$( 'div.comments ').attr( 'style', '' );
|
||||
});
|
||||
$( 'div.comments' ).fadeIn( 100 );
|
||||
}
|
||||
|
||||
// Sexy blurred backgrounds
|
||||
cover = $( '.cover img' ).attr( 'src' );
|
||||
$( '#loader + .container-fluid' )
|
||||
.prepend( '<div class="blur-wrapper"></div' );
|
||||
$( '.blur-wrapper' )
|
||||
.prepend( '<div><img class="bg-blur" src="' + cover + '"></div>' );
|
||||
|
||||
// Fix-up book detail headings
|
||||
publisher = $( '.publishers p span' ).text().split( ':' );
|
||||
$( '.publishers p span' ).remove();
|
||||
$.each(publisher, function(i, val) {
|
||||
$( '.publishers' ).append( '<span>' + publisher[i] + '</span>' );
|
||||
});
|
||||
$( '.publishers span:nth-child(3)' ).text(function() {
|
||||
return $(this).text().replace(/^\s+|^\t+|\t+|\s+$/g, "");
|
||||
});
|
||||
|
||||
published = $( '.publishing-date p' )
|
||||
.text().split(': ');
|
||||
$( '.publishing-date p' ).remove();
|
||||
$.each(published, function(i, val) {
|
||||
$( '.publishing-date' ).append( '<span>' + published[i] + '</span>' );
|
||||
});
|
||||
|
||||
languages = $( '.languages p span' ).text().split( ': ' );
|
||||
$( '.languages p span' ).remove();
|
||||
$.each(languages, function(i, val) {
|
||||
$( '.languages' ).append( '<span>' + languages[i] + '</span>' );
|
||||
});
|
||||
|
||||
$( '.book-meta h2:first' ).clone()
|
||||
.prependTo( '.book-meta > .btn-toolbar:first' );
|
||||
|
||||
// If only one download type exists still put the items into a drop-drown list.
|
||||
downloads = $( 'a[id^=btnGroupDrop]' ).get();
|
||||
if ( $( downloads ).length === 1 ) {
|
||||
$( '<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-download"></span>Download :<span class="caret"></span></button><ul class="dropdown-menu leramslist aria-labelledby="btnGroupDrop1"></ul>' ).insertBefore( downloads[downloads.length-1] );
|
||||
$( downloads ).detach();
|
||||
$.each(downloads, function(i, val) {
|
||||
$( '<li>' + downloads[i].outerHTML + '</li>' ).appendTo( '.leramslist' );
|
||||
});
|
||||
$( '.leramslist' ).find( 'span' ).remove();
|
||||
$( '.leramslist a' ).removeClass( 'btn btn-primary' ).removeAttr( 'role' );
|
||||
}
|
||||
|
||||
// Add classes to buttons
|
||||
$( '#sendbtn' ).parent().addClass( 'sendBtn' );
|
||||
$( '[id*=btnGroupDrop]' ).parent().addClass( 'downloadBtn' );
|
||||
$( 'read-in-browser' ).parent().addClass( 'readBtn' );
|
||||
$( '.downloadBtn button:first' ).addClass( 'download-text' );
|
||||
|
||||
// Move all options in book details page to the same group
|
||||
$( '[aria-label*="Delete book"]' )
|
||||
.prependTo( '[aria-label^="Download, send"]' )
|
||||
.children().removeClass( 'btn-sm' );
|
||||
$( '.custom_columns' )
|
||||
.addClass(' btn-group' )
|
||||
.attr('role', 'group' )
|
||||
.removeClass( 'custom_columns' )
|
||||
.prependTo( '[aria-label^="Download, send"]' );
|
||||
$( '#have_read_cb' )
|
||||
.after( '<label class="block-label readLbl" for="#have_read_cb"></label>' );
|
||||
$( '#shelf-actions' ).prependTo( '[aria-label^="Download, send"]' );
|
||||
|
||||
|
||||
// Move dropdown lists higher in dom, replace bootstrap toggle with own toggle.
|
||||
$( 'ul[aria-labelledby="read-in-browser"]' ).insertBefore( '.blur-wrapper' ).addClass('readinbrowser-drop');
|
||||
$( 'ul[aria-labelledby="send-to-kindle"]' ).insertBefore( '.blur-wrapper' ).addClass('sendtokindle-drop');
|
||||
$( '.leramslist' ).insertBefore( '.blur-wrapper' );
|
||||
$( 'ul[aria-labelledby="btnGroupDrop1"]' ).insertBefore( '.blur-wrapper' ).addClass('leramslist');
|
||||
$( '#add-to-shelves' ).insertBefore( '.blur-wrapper' );
|
||||
|
||||
$( '#read-in-browser' ).click( function() {
|
||||
$( '.readinbrowser-drop' ).toggle();
|
||||
});
|
||||
|
||||
$('.downloadBtn' ).click( function() {
|
||||
$( '.leramslist' ).toggle();
|
||||
});
|
||||
|
||||
$('#sendbtn2' ).click( function() {
|
||||
$( '.sendtokindle-drop' ).toggle();
|
||||
});
|
||||
|
||||
|
||||
$('div[aria-label="Add to shelves"]' ).click( function() {
|
||||
$( '#add-to-shelves' ).toggle();
|
||||
});
|
||||
|
||||
// Fix formatting error on book detail languages
|
||||
if ( !$( '.book-meta > .bookinfo > .languages > span:last-of-type' ).text().startsWith(" ") ) {
|
||||
$( '.book-meta > .bookinfo > .languages > span:last-of-type' ).prepend(" ");
|
||||
}
|
||||
|
||||
//Work to reposition dropdowns. Does not currently solve for
|
||||
//screen resizing
|
||||
function dropdownToggle() {
|
||||
|
||||
topPos = $( '.book-meta > .btn-toolbar:first' ).offset().top
|
||||
|
||||
if ( $( '#read-in-browser' ).length > 0 ) {
|
||||
position = $( '#read-in-browser' ).offset().left
|
||||
if ( position + $( '.readinbrowser-drop' ).width() > $( window ).width() ) {
|
||||
positionOff = position + $( '.readinbrowser-drop' ).width() - $( window ).width();
|
||||
ribPosition = position - positionOff - 5
|
||||
$( '.readinbrowser-drop' ).attr("style", "left: " + ribPosition + "px !important; right: auto; top: " + topPos + "px");
|
||||
} else {
|
||||
$( '.readinbrowser-drop' ).attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $( '#sendbtn2' ).length > 0 ) {
|
||||
position = $( '#sendbtn2' ).offset().left
|
||||
if ( position + $( '.sendtokindle-drop' ).width() > $( window ).width() ) {
|
||||
positionOff = position + $( '.sendtokindle-drop' ).width() - $( window ).width();
|
||||
ribPosition = position - positionOff - 5
|
||||
$( '.sendtokindle-drop' ).attr("style", "left: " + ribPosition + "px !important; right: auto; top: " + topPos + "px");
|
||||
} else {
|
||||
$( '.sendtokindle-drop' ).attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $( '.downloadBtn' ).length > 0 ) {
|
||||
|
||||
position = $( '#btnGroupDrop1' ).offset().left
|
||||
|
||||
if ( position + $( '.leramslist' ).width() > $( window ).width() ) {
|
||||
positionOff = position + $( '.leramslist' ).width() - $( window ).width();
|
||||
dlPosition = position - positionOff - 5
|
||||
$( '.leramslist' ).attr("style", "left: " + dlPosition + "px !important; right: auto; top: " + topPos + "px");
|
||||
} else {
|
||||
$( '.leramslist' ).attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $( 'div[aria-label="Add to shelves"]' ).length > 0 ) {
|
||||
|
||||
position = $( 'div[aria-label="Add to shelves"]' ).offset().left
|
||||
|
||||
if ( position + $( '#add-to-shelves' ).width() > $( window ).width() ) {
|
||||
positionOff = position + $( '#add-to-shelves' ).width() - $( window ).width();
|
||||
adsPosition = position - positionOff - 5
|
||||
$( '#add-to-shelves' ).attr("style", "left: " + adsPosition + "px !important; right: auto; top: " + topPos + "px");
|
||||
} else {
|
||||
$( '#add-to-shelves' ).attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px");
|
||||
}
|
||||
}
|
||||
}
|
||||
dropdownToggle();
|
||||
|
||||
$( window ).on( 'resize', function() {
|
||||
dropdownToggle();
|
||||
});
|
||||
|
||||
// Clone book rating for mobile view.
|
||||
$( '.book-meta > .bookinfo > .rating' ).clone().insertBefore( '.book-meta > .description' ).addClass('rating-mobile');
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// End of Book Details Work //
|
||||
/////////////////////////////
|
||||
|
||||
/////////////////////////////////
|
||||
// Start of Global Work //
|
||||
///////////////////////////////
|
||||
|
||||
// Hide dropdown and collapse menus on click-off
|
||||
$(document).mouseup(function (e) {
|
||||
var container = new Array();
|
||||
container.push($('ul[aria-labelledby="read-in-browser"]'));
|
||||
container.push($('.sendtokindle-drop'));
|
||||
container.push($('.leramslist'));
|
||||
container.push($('#add-to-shelves'));
|
||||
container.push($('.navbar-collapse.collapse.in'));
|
||||
|
||||
$.each(container, function(key, value) {
|
||||
if (!$(value).is(e.target) // if the target of the click isn't the container...
|
||||
&& $(value).has(e.target).length === 0) // ... nor a descendant of the container
|
||||
{
|
||||
if ( $(value).hasClass('dropdown-menu') )
|
||||
{
|
||||
$(value).hide();
|
||||
} else
|
||||
{
|
||||
if ( $(value).hasClass('collapse') )
|
||||
{
|
||||
$(value).collapse('toggle');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Split path name to array and remove blanks
|
||||
url = window.location.pathname
|
||||
|
||||
// Move create shelf
|
||||
$( '#nav_createshelf' ).prependTo( '.your-shelves' );
|
||||
|
||||
// Create drop-down for profile and move elements to it
|
||||
$( '#main-nav' )
|
||||
.prepend( '<li class="dropdown"><a href="#" class="dropdown-toggle profileDrop" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-user"></span></a><ul class="dropdown-menu profileDropli"></ul></li>' );
|
||||
$( '#top_user' ).parent().addClass( 'dropdown' ).appendTo( '.profileDropli' );
|
||||
$( '#nav_about' ).addClass( 'dropdown' ).appendTo( '.profileDropli' );
|
||||
$( '#register' ).parent().addClass( 'dropdown' ).appendTo( '.profileDropli' );
|
||||
$( '#logout' ).parent().addClass( 'dropdown' ).appendTo( '.profileDropli' );
|
||||
|
||||
// Remove the modals except from some areas where they are needed
|
||||
bodyClass = $( 'body' ).attr( 'class' ).split(' ');
|
||||
modalWanted = ['admin', 'editbook', 'config', 'uiconfig'];
|
||||
|
||||
if ( $.inArray( bodyClass[0], modalWanted) != -1 ) {
|
||||
} else {
|
||||
$(' a:not(.dropdown-toggle) ')
|
||||
.removeAttr( 'data-toggle', 'data-target', 'data-remote' );
|
||||
}
|
||||
|
||||
|
||||
// Add classes to global buttons
|
||||
$( '#top_tasks' ).parent().addClass( 'top_tasks' );
|
||||
$( '#top_admin' ).parent().addClass( 'top_admin' );
|
||||
$( '#form-upload' ).parent().addClass( 'form-upload' );
|
||||
|
||||
// Search button work
|
||||
$( 'input#query' ).focus(function() {
|
||||
$( 'form[role="search"]' ).addClass( 'search-focus' );
|
||||
});
|
||||
$( 'input#query' ).focusout(function() {
|
||||
setTimeout(function() {
|
||||
$( 'form[role="search"]' ).removeClass( 'search-focus' );
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Check if dropdown goes out of viewport and add class
|
||||
|
||||
$(document).on('click','.dropdown-toggle',function() {
|
||||
// Add .offscreen if part of container not visible
|
||||
$('.dropdown-menu:visible').filter(function(){
|
||||
return $(this).visible() === false;
|
||||
}).each(function(){
|
||||
$(this).addClass('offscreen');
|
||||
});
|
||||
});
|
||||
|
||||
// Fade out content on page unload
|
||||
// delegate all clicks on "a" tag (links)
|
||||
/*$(document).on("click", "a:not(.btn-toolbar a, a[href*='shelf/remove'], .identifiers a, .bookinfo , .btn-group > a, #add-to-shelves a, #book-list a, .stat.blur a )", function () {
|
||||
|
||||
// get the href attribute
|
||||
var newUrl = $(this).attr("href");
|
||||
|
||||
// veryfy if the new url exists or is a hash
|
||||
if (!newUrl || newUrl[0] === "#") {
|
||||
// set that hash
|
||||
location.hash = newUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
now, fadeout the html (whole page)
|
||||
$( '.blur-wrapper' ).fadeOut(250);
|
||||
$(".row-fluid .col-sm-10").fadeOut(500,function () {
|
||||
// when the animation is complete, set the new location
|
||||
location = newUrl;
|
||||
});
|
||||
|
||||
// prevent the default browser behavior.
|
||||
return false;
|
||||
});*/
|
||||
|
||||
// Collapse long text into read-more
|
||||
$( 'div.comments' ).readmore( {
|
||||
collapsedHeight: 134,
|
||||
heightMargin: 45,
|
||||
speed: 300,
|
||||
moreLink: '<a href="#">READ MORE</a>', // ToDo: make translateable
|
||||
lessLink: '<a href="#">READ LESS</a>', // ToDo: make translateable
|
||||
});
|
||||
/////////////////////////////////
|
||||
// End of Global Work //
|
||||
///////////////////////////////
|
||||
|
||||
// Author Page Background Blur
|
||||
if ( $( 'body.author' ).length >0 ) {
|
||||
cover = $( '.author-bio img' ).attr( 'src' );
|
||||
$( '#loader + .container-fluid' )
|
||||
.prepend( '<div class="blur-wrapper"></div>' );
|
||||
$( '.blur-wrapper' ).prepend( '<img class="bg-blur" src="' + cover + '">' );
|
||||
// Place undefined cover images inside container
|
||||
if ( $( '.bg-blur[src="undefined"]' ).length > 0 ) {
|
||||
$( '.bg-blur' ).before( '<div class="bg-blur undefined-img"></div>' );
|
||||
$( 'img.bg-blur' ).appendTo( '.undefined-img' );
|
||||
}
|
||||
}
|
||||
|
||||
// Ereader Page - add class to iframe body on ereader page after it loads.
|
||||
backurl = '../../book/' + url[2]
|
||||
$( 'body.epub #title-controls' )
|
||||
.append('<div class="epub-back"><input action="action" onclick="location.href=backurl; return false;" type="button" value="Back" /></div>')
|
||||
|
||||
$( 'body.stat .col-sm-10 p:first' ).insertAfter( '#libs' );
|
||||
|
||||
// Check if link is external and force _blank attribute
|
||||
$(function(){ // document ready
|
||||
$( 'a' ).filter(function () {
|
||||
return this.hostname && this.hostname !== location.hostname;
|
||||
}).each(function () {
|
||||
$(this).addClass("external").attr( 'target', '_blank' );
|
||||
});
|
||||
});
|
||||
|
||||
// Check if lists are empty and add class to buttons
|
||||
if ( $.trim( $('#add-to-shelves').html() ).length === 0 ) {
|
||||
$( '#add-to-shelf' ).addClass( 'empty-ul' );
|
||||
}
|
||||
|
||||
shelfLength = $('#add-to-shelves li').length
|
||||
emptyLength = 0
|
||||
|
||||
$('#add-to-shelves').on('click','li a',function(){
|
||||
console.log('#remove-from-shelves change registered' );
|
||||
emptyLength++
|
||||
|
||||
setTimeout(function() {
|
||||
if ( emptyLength >= shelfLength ) {
|
||||
console.log('list is empty; adding empty-ul class' );
|
||||
$( '#add-to-shelf' ).addClass( 'empty-ul' );
|
||||
} else {
|
||||
console.log('list is not empty; removing empty-ul class' );
|
||||
$( '#add-to-shelf' ).removeClass( 'empty-ul' );
|
||||
}
|
||||
},100);
|
||||
});
|
||||
|
||||
if ( $.trim( $( 'ul[aria-labelledby="read-in-browser"] li' ).html() ).length === 0 ) {
|
||||
$('#read-in-browser').addClass('empty-ul');
|
||||
}
|
||||
|
||||
// Shelf Buttons and Tooltips
|
||||
if ( $( 'body.shelf' ).length > 0 ) {
|
||||
$( 'div[data-target="#DeleteShelfDialog"]' )
|
||||
.before( '<div class=".btn-group shelf-btn-group"></div>' )
|
||||
.appendTo( '.shelf-btn-group' )
|
||||
.addClass( 'delete-shelf-btn' );
|
||||
|
||||
$( 'a[href*="edit"]' )
|
||||
.appendTo( '.shelf-btn-group' )
|
||||
.addClass( 'edit-shelf-btn' );
|
||||
|
||||
$( 'a[href*="order"]' )
|
||||
.appendTo( '.shelf-btn-group' )
|
||||
.addClass( 'order-shelf-btn' );
|
||||
$( '.delete-shelf-btn' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '.delete-shelf-btn' ).text(), // 'Delete Shelf'
|
||||
'data-placement': 'bottom' })
|
||||
.addClass('delete-btn-tooltip');
|
||||
|
||||
$( '.edit-shelf-btn' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '.edit-shelf-btn' ).text(), // 'Edit Shelf'
|
||||
'data-placement': 'bottom' })
|
||||
.addClass('edit-btn-tooltip');
|
||||
|
||||
$( '.order-shelf-btn' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '.order-shelf-btn' ).text(), //'Reorder Shelf'
|
||||
'data-placement': 'bottom' })
|
||||
.addClass('order-btn-tooltip');
|
||||
}
|
||||
|
||||
// Rest of Tooltips
|
||||
$( '.home-btn > a' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $(document.body).attr('data-text'), // Home
|
||||
'data-placement': 'bottom' })
|
||||
.addClass('home-btn-tooltip');
|
||||
|
||||
$( '.plexBack > a' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $(document.body).attr('data-textback'), // Back
|
||||
'data-placement': 'bottom' })
|
||||
.addClass('back-btn-tooltip');
|
||||
|
||||
$( '#top_tasks' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#top_tasks' ).text(), // 'Tasks'
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '#main-nav' })
|
||||
.addClass('tasks-btn-tooltip');
|
||||
|
||||
$( '#top_admin' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#top_admin' ).attr('data-text'), // Settings
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '#main-nav' })
|
||||
.addClass('admin-btn-tooltip');
|
||||
|
||||
$( '.profileDrop' ).attr({
|
||||
'title': $( '#top_user' ).attr('data-text'), //Account
|
||||
'data-placement': 'bottom',
|
||||
'data-toggle-two': 'tooltip',
|
||||
'data-viewport': '#main-nav' })
|
||||
.addClass('send-btn-tooltip dropdown');
|
||||
|
||||
$( '#btn-upload' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#btn-upload' ).parent().text() , // 'Upload'
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '#main-nav' })
|
||||
.addClass('upload-btn-tooltip');
|
||||
|
||||
$( '#add-to-shelf' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '#add-to-shelf' ).text() , // 'Add to Shelf'
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('addtoshelf-btn-tooltip');
|
||||
|
||||
$( '#have_read_cb' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#have_read_cb').attr('data-unchecked'),
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('readunread-btn-tooltip');
|
||||
|
||||
$( '#have_read_cb:checked' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#have_read_cb').attr('data-checked'),
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('readunread-btn-tooltip');
|
||||
|
||||
$( 'button#delete' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( 'button#delete' ).text(), //'Delete'
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('delete-book-btn-tooltip');
|
||||
|
||||
$( '#have_read_cb' ).click(function() {
|
||||
if ( $( '#have_read_cb:checked' ).length > 0 ) {
|
||||
$( this ).attr('data-original-title', $('#have_read_cb').attr('data-checked'));
|
||||
} else {
|
||||
$( this).attr('data-original-title', $('#have_read_cb').attr('data-unchecked'));
|
||||
}
|
||||
});
|
||||
|
||||
$( '.btn-group[aria-label="Edit/Delete book"] a' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#edit_book' ).text(), // 'Edit'
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('edit-btn-tooltip');
|
||||
|
||||
$( '#sendbtn' ).attr({
|
||||
'data-toggle': 'tooltip',
|
||||
'title': $( '#sendbtn' ).attr('data-text'),
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('send-btn-tooltip');
|
||||
|
||||
$( '#sendbtn2' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '#sendbtn2' ).text(), // 'Send to Kindle',
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' })
|
||||
.addClass('send-btn-tooltip');
|
||||
|
||||
$( '#read-in-browser' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '#read-in-browser' ).text(),
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar'})
|
||||
.addClass('send-btn-tooltip');
|
||||
|
||||
$( '#btnGroupDrop1' ).attr({
|
||||
'data-toggle-two': 'tooltip',
|
||||
'title': $( '#btnGroupDrop1' ).text(),
|
||||
'data-placement': 'bottom',
|
||||
'data-viewport': '.btn-toolbar' });
|
||||
|
||||
if ( $( 'body.epub').length === 0 ) {
|
||||
$(document).ready(function(){
|
||||
$('[data-toggle="tooltip"]').tooltip({container: 'body', trigger: 'hover'});
|
||||
$('[data-toggle-two="tooltip"]').tooltip({container: 'body', trigger: 'hover'});
|
||||
$( '#btn-upload' ).attr('title', " ");
|
||||
});
|
||||
|
||||
|
||||
$( '[data-toggle-two="tooltip"]' ).click(function(){
|
||||
$('[data-toggle-two="tooltip"]').tooltip('hide');
|
||||
});
|
||||
|
||||
$( '[data-toggle="tooltip"]' ).click(function(){
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
});
|
||||
}
|
||||
|
||||
$( '#read-in-browser a' ).attr('target',"");
|
||||
|
||||
if ( $( '.edit-shelf-btn').length > 1 ) {
|
||||
$( '.edit-shelf-btn:first').remove();
|
||||
}
|
||||
if ( $( '.order-shelf-btn').length > 1 ) {
|
||||
$( '.order-shelf-btn:first').remove();
|
||||
}
|
||||
|
||||
$( '#top_user > span.hidden-sm' ).clone().insertBefore( '.profileDropli' );
|
||||
$( '.navbar-collapse.collapse.in').before('<div class="sidebar-backdrop"></div>');
|
||||
|
||||
// Get rid of leading white space
|
||||
recentlyAdded = $( '#nav_new a:contains("Recently")' ).text().trim();
|
||||
$('#nav_new a:contains("Recently")').contents().filter(function() {
|
||||
return this.nodeType == 3
|
||||
}).each(function(){
|
||||
this.textContent = this.textContent.replace(' Recently Added',recentlyAdded);
|
||||
});
|
||||
|
||||
// Change shelf textValue
|
||||
shelfText = $( '.shelf .discover h2:first' ).text().replace(':',' —').replace(/\'/g,'');
|
||||
$( '.shelf .discover h2:first' ).text(shelfText);
|
||||
|
||||
shelfText = $( '.shelforder .col-sm-10 .col-sm-6.col-lg-6.col-xs-6 h2:first' ).text().replace(':',' —').replace(/\'/g,'');
|
||||
$( '.shelforder .col-sm-10 .col-sm-6.col-lg-6.col-xs-6 h2:first' ).text(shelfText);
|
||||
|
||||
|
||||
function mobileSupport() {
|
||||
if ( $( window ).width() <= 768 ) {
|
||||
//Move menu to collapse
|
||||
$( '.row-fluid > .col-sm-2:first' ).appendTo( '.navbar-collapse.collapse:first');
|
||||
if ( $( '.sidebar-backdrop' ).length < 1 ) {
|
||||
$( '.navbar-collapse.collapse:first' ).after( '<div class="sidebar-backdrop"></div>' );
|
||||
}
|
||||
} else {
|
||||
//Move menu out of collapse
|
||||
$( '.col-sm-2:first' ).insertBefore( '.col-sm-10:first');
|
||||
$( '.sidebar-backdrop' ).remove();
|
||||
}
|
||||
}
|
||||
|
||||
// LayerCake plug
|
||||
if ( $(' body.stat p').length > 0 ) {
|
||||
$(' body.stat p').append(" and <a href='https://github.com/leram84/layer.Cake/tree/master/caliBlur' target='_blank'>layer.Cake</a>");
|
||||
str = $(' body.stat p').html().replace("</a>.","</a>");
|
||||
$(' body.stat p').html(str);
|
||||
}
|
||||
// Collect delete buttons in editbook to single dropdown
|
||||
$( '.editbook .text-center.more-stuff' ).prepend( '<button id="deleteButton" type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-remove"></span>Delete Format<span class="caret"></span></button><ul class="dropdown-menu delete-dropdown"></ul>' );
|
||||
|
||||
deleteButtons = $( '.editbook .text-center.more-stuff a' ).removeClass('btn btn-danger' ).attr( 'type', '').get();
|
||||
|
||||
$( deleteButtons ).detach();
|
||||
$( '.editbook .text-center.more-stuff h4' ).remove();
|
||||
$.each(deleteButtons, function(i, val) {
|
||||
$( '<li>' + deleteButtons[i].outerHTML + '</li>' ).appendTo( '.delete-dropdown' );
|
||||
});
|
||||
|
||||
// Turn off bootstrap animations
|
||||
$(function() { $.support.transition = false; })
|
||||
|
||||
mobileSupport();
|
||||
|
||||
// Only call function once resize is complete
|
||||
//var id;
|
||||
$( window ).on('resize',function() {
|
||||
// clearTimeout(id);
|
||||
// id = setTimeout(mobileSupport, 500);
|
||||
mobileSupport();
|
||||
});
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
!function(a){a.fn.datepicker.dates.ja={days:["日曜","月曜","火曜","水曜","木曜","金曜","土曜"],daysShort:["日","月","火","水","木","金","土"],daysMin:["日","月","火","水","木","金","土"],months:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今日",format:"yyyy/mm/dd",titleFormat:"yyyy年mm月",clear:"クリア"}}(jQuery);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
!function(t){var i=t(window);t.fn.visible=function(t,e,o){if(!(this.length<1)){var r=this.length>1?this.eq(0):this,n=r.get(0),f=i.width(),h=i.height(),o=o?o:"both",l=e===!0?n.offsetWidth*n.offsetHeight:!0;if("function"==typeof n.getBoundingClientRect){var g=n.getBoundingClientRect(),u=g.top>=0&&g.top<h,s=g.bottom>0&&g.bottom<=h,c=g.left>=0&&g.left<f,a=g.right>0&&g.right<=f,v=t?u||s:u&&s,b=t?c||a:c&&a;if("both"===o)return l&&v&&b;if("vertical"===o)return l&&v;if("horizontal"===o)return l&&b}else{var d=i.scrollTop(),p=d+h,w=i.scrollLeft(),m=w+f,y=r.offset(),z=y.top,B=z+r.height(),C=y.left,R=C+r.width(),j=t===!0?B:z,q=t===!0?z:B,H=t===!0?R:C,L=t===!0?C:R;if("both"===o)return!!l&&p>=q&&j>=d&&m>=L&&H>=w;if("vertical"===o)return!!l&&p>=q&&j>=d;if("horizontal"===o)return!!l&&m>=L&&H>=w}}}}(jQuery);
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* @preserve
|
||||
*
|
||||
* Readmore.js jQuery plugin
|
||||
* Author: @jed_foster
|
||||
* Project home: http://jedfoster.github.io/Readmore.js
|
||||
* Licensed under the MIT license
|
||||
*
|
||||
* Debounce function from http://davidwalsh.name/javascript-debounce-function
|
||||
*/
|
||||
!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){"use strict";function e(t,e,i){var o;return function(){var n=this,a=arguments,s=function(){o=null,i||t.apply(n,a)},r=i&&!o;clearTimeout(o),o=setTimeout(s,e),r&&t.apply(n,a)}}function i(t){var e=++h;return String(null==t?"rmjs-":t)+e}function o(t){var e=t.clone().css({height:"auto",width:t.width(),maxHeight:"none",overflow:"hidden"}).insertAfter(t),i=e.outerHeight(),o=parseInt(e.css({maxHeight:""}).css("max-height").replace(/[^-\d\.]/g,""),10),n=t.data("defaultHeight");e.remove();var a=o||t.data("collapsedHeight")||n;t.data({expandedHeight:i,maxHeight:o,collapsedHeight:a}).css({maxHeight:"none"})}function n(t){if(!d[t.selector]){var e=" ";t.embedCSS&&""!==t.blockCSS&&(e+=t.selector+" + [data-readmore-toggle], "+t.selector+"[data-readmore]{"+t.blockCSS+"}"),e+=t.selector+"[data-readmore]{transition: height "+t.speed+"ms;overflow: hidden;}",function(t,e){var i=t.createElement("style");i.type="text/css",i.styleSheet?i.styleSheet.cssText=e:i.appendChild(t.createTextNode(e)),t.getElementsByTagName("head")[0].appendChild(i)}(document,e),d[t.selector]=!0}}function a(e,i){this.element=e,this.options=t.extend({},r,i),n(this.options),this._defaults=r,this._name=s,this.init(),window.addEventListener?(window.addEventListener("load",c),window.addEventListener("resize",c)):(window.attachEvent("load",c),window.attachEvent("resize",c))}var s="readmore",r={speed:100,collapsedHeight:200,heightMargin:16,moreLink:'<a href="#">Read More</a>',lessLink:'<a href="#">Close</a>',embedCSS:!0,blockCSS:"display: block; width: 100%;",startOpen:!1,blockProcessed:function(){},beforeToggle:function(){},afterToggle:function(){}},d={},h=0,c=e(function(){t("[data-readmore]").each(function(){var e=t(this),i="true"===e.attr("aria-expanded");o(e),e.css({height:e.data(i?"expandedHeight":"collapsedHeight")})})},100);a.prototype={init:function(){var e=t(this.element);e.data({defaultHeight:this.options.collapsedHeight,heightMargin:this.options.heightMargin}),o(e);var n=e.data("collapsedHeight"),a=e.data("heightMargin");if(e.outerHeight(!0)<=n+a)return this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!1),!0;var s=e.attr("id")||i(),r=this.options.startOpen?this.options.lessLink:this.options.moreLink;e.attr({"data-readmore":"","aria-expanded":this.options.startOpen,id:s}),e.after(t(r).on("click",function(t){return function(i){t.toggle(this,e[0],i)}}(this)).attr({"data-readmore-toggle":s,"aria-controls":s})),this.options.startOpen||e.css({height:n}),this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!0)},toggle:function(e,i,o){o&&o.preventDefault(),e||(e=t('[aria-controls="'+this.element.id+'"]')[0]),i||(i=this.element);var n=t(i),a="",s="",r=!1,d=n.data("collapsedHeight");n.height()<=d?(a=n.data("expandedHeight")+"px",s="lessLink",r=!0):(a=d,s="moreLink"),this.options.beforeToggle&&"function"==typeof this.options.beforeToggle&&this.options.beforeToggle(e,n,!r),n.css({height:a}),n.on("transitionend",function(i){return function(){i.options.afterToggle&&"function"==typeof i.options.afterToggle&&i.options.afterToggle(e,n,r),t(this).attr({"aria-expanded":r}).off("transitionend")}}(this)),t(e).replaceWith(t(this.options[s]).on("click",function(t){return function(e){t.toggle(this,i,e)}}(this)).attr({"data-readmore-toggle":n.attr("id"),"aria-controls":n.attr("id")}))},destroy:function(){t(this.element).each(function(){var e=t(this);e.attr({"data-readmore":null,"aria-expanded":null}).css({maxHeight:"",height:""}).next("[data-readmore-toggle]").remove(),e.removeData()})}},t.fn.readmore=function(e){var i=arguments,o=this.selector;return e=e||{},"object"==typeof e?this.each(function(){if(t.data(this,"plugin_"+s)){var i=t.data(this,"plugin_"+s);i.destroy.apply(i)}e.selector=o,t.data(this,"plugin_"+s,new a(this,e))}):"string"==typeof e&&"_"!==e[0]&&"init"!==e?this.each(function(){var o=t.data(this,"plugin_"+s);o instanceof a&&"function"==typeof o[e]&&o[e].apply(o,Array.prototype.slice.call(i,1))}):void 0}});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* bootstrap-uploadprogress
|
||||
* github: https://github.com/jakobadam/bootstrap-uploadprogress
|
||||
*
|
||||
* Copyright (c) 2015 Jakob Aarøe Dam
|
||||
* Version 1.0.0
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
"use strict";
|
||||
|
||||
$.support.xhrFileUpload = !!(window.FileReader && window.ProgressEvent);
|
||||
$.support.xhrFormData = !!window.FormData;
|
||||
|
||||
if (!$.support.xhrFileUpload || !$.support.xhrFormData) {
|
||||
// skip decorating form
|
||||
return;
|
||||
}
|
||||
|
||||
var template = "<div class=\"modal fade\" id=\"file-progress-modal\">" +
|
||||
"<div class=\"modal-dialog upload-modal-dialog\">" +
|
||||
" <div class=\"modal-content\">" +
|
||||
" <div class=\"modal-header\">" +
|
||||
" <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>" +
|
||||
" <h4 class=\"modal-title\">Uploading</h4>" +
|
||||
" </div>" +
|
||||
" <div class=\"modal-body\">" +
|
||||
" <div class=\"modal-message\"></div>" +
|
||||
" <div class=\"progress\">" +
|
||||
" <div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"0\" aria-valuemin=\"0\"" +
|
||||
" aria-valuemax=\"100\" style=\"width: 0%;min-width: 2em;\">" +
|
||||
" 0%" +
|
||||
" </div>" +
|
||||
" </div>" +
|
||||
" </div>" +
|
||||
" <div class=\"modal-footer\" style=\"display:none\">" +
|
||||
" <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Close</button>" +
|
||||
" </div>" +
|
||||
" </div>" +
|
||||
" </div>" +
|
||||
"</div>";
|
||||
|
||||
var UploadProgress = function(element, options) {
|
||||
this.options = options;
|
||||
this.$element = $(element);
|
||||
};
|
||||
|
||||
UploadProgress.prototype = {
|
||||
|
||||
constructor: function() {
|
||||
this.$form = this.$element;
|
||||
this.$form.on("submit", $.proxy(this.submit, this));
|
||||
this.$modal = $(this.options.template);
|
||||
this.$modalTitle = this.$modal.find(".modal-title");
|
||||
this.$modalFooter = this.$modal.find(".modal-footer");
|
||||
this.$modalBar = this.$modal.find(".progress-bar");
|
||||
|
||||
// Translate texts
|
||||
this.$modalTitle.text(this.options.modalTitle)
|
||||
this.$modalFooter.children("button").text(this.options.modalFooter);
|
||||
|
||||
this.$modal.on("hidden.bs.modal", $.proxy(this.reset, this));
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.$modalTitle.text(this.options.modalTitle);
|
||||
this.$modalFooter.hide();
|
||||
this.$modalBar.addClass("progress-bar-success");
|
||||
this.$modalBar.removeClass("progress-bar-danger");
|
||||
if (this.xhr) {
|
||||
this.xhr.abort();
|
||||
}
|
||||
},
|
||||
|
||||
submit: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
this.$modal.modal({
|
||||
backdrop: "static",
|
||||
keyboard: false
|
||||
});
|
||||
|
||||
// We need the native XMLHttpRequest for the progress event
|
||||
var xhr = new XMLHttpRequest();
|
||||
this.xhr = xhr;
|
||||
|
||||
xhr.addEventListener("load", $.proxy(this.success, this, xhr));
|
||||
xhr.addEventListener("error", $.proxy(this.error, this, xhr));
|
||||
|
||||
xhr.upload.addEventListener("progress", $.proxy(this.progress, this));
|
||||
|
||||
var form = this.$form;
|
||||
|
||||
xhr.open(form.attr("method"), form.attr("action"));
|
||||
xhr.setRequestHeader("X-REQUESTED-WITH", "XMLHttpRequest");
|
||||
|
||||
var data = new FormData(form.get(0));
|
||||
xhr.send(data);
|
||||
},
|
||||
|
||||
success: function(xhr) {
|
||||
if (xhr.status === 0 || xhr.status >= 400) {
|
||||
// HTTP 500 ends up here!?!
|
||||
return this.error(xhr);
|
||||
}
|
||||
this.setProgress(100);
|
||||
var url;
|
||||
var contentType = xhr.getResponseHeader("Content-Type");
|
||||
|
||||
// make it possible to return the redirect URL in
|
||||
// a JSON response
|
||||
if (contentType.indexOf("application/json") !== -1) {
|
||||
var response = $.parseJSON(xhr.responseText);
|
||||
url = response.location;
|
||||
}
|
||||
else{
|
||||
url = this.options.redirect_url;
|
||||
}
|
||||
window.location.href = url;
|
||||
},
|
||||
|
||||
// handle form error
|
||||
// we replace the form with the returned one
|
||||
error: function(xhr) {
|
||||
this.$modalTitle.text(this.options.modalTitleFailed);
|
||||
|
||||
this.$modalBar.removeClass("progress-bar-success");
|
||||
this.$modalBar.addClass("progress-bar-danger");
|
||||
this.$modalFooter.show();
|
||||
|
||||
var contentType = xhr.getResponseHeader("Content-Type");
|
||||
// Write the error response to the document.
|
||||
if (contentType || xhr.status === 422) {
|
||||
var responseText = xhr.responseText;
|
||||
if (contentType.indexOf("text/plain") !== -1) {
|
||||
responseText = "<pre>" + responseText + "</pre>";
|
||||
document.write(responseText);
|
||||
}
|
||||
else {
|
||||
this.$modalBar.text(responseText);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.$modalBar.text(this.options.modalTitleFailed);
|
||||
}
|
||||
},
|
||||
|
||||
setProgress: function(percent) {
|
||||
var txt = percent + "%";
|
||||
if (percent === 100) {
|
||||
txt = this.options.uploadedMsg;
|
||||
}
|
||||
this.$modalBar.attr("aria-valuenow", percent);
|
||||
this.$modalBar.text(txt);
|
||||
this.$modalBar.css("width", percent + "%");
|
||||
},
|
||||
|
||||
progress: function(/*ProgressEvent*/e) {
|
||||
var percent = Math.round((e.loaded / e.total) * 100);
|
||||
this.setProgress(percent);
|
||||
},
|
||||
|
||||
// replaceForm replaces the contents of the current form
|
||||
// with the form in the html argument.
|
||||
// We use the id of the current form to find the new form in the html
|
||||
replaceForm: function(html) {
|
||||
var newForm;
|
||||
var formId = this.$form.attr("id");
|
||||
if ( typeof formId !== "undefined") {
|
||||
newForm = $(html).find("#" + formId);
|
||||
} else {
|
||||
newForm = $(html).find("form");
|
||||
}
|
||||
// add the filestyle again
|
||||
newForm.find(":file").filestyle({buttonBefore: true});
|
||||
this.$form.html(newForm.children());
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.uploadprogress = function(options) {
|
||||
return this.each(function() {
|
||||
var _options = $.extend({}, $.fn.uploadprogress.defaults, options);
|
||||
var fileProgress = new UploadProgress(this, _options);
|
||||
fileProgress.constructor();
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.uploadprogress.defaults = {
|
||||
template: template,
|
||||
uploadedMsg: "Upload done, processing, please wait...",
|
||||
modalTitle: "Uploading",
|
||||
modalFooter: "Close",
|
||||
modalTitleFailed: "Upload failed"
|
||||
//redirect_url: ...
|
||||
// need to customize stuff? Add here, and change code accordingly.
|
||||
};
|
||||
|
||||
})(window.jQuery);
|
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="http-error" lang="{{ g.user.locale }}">
|
||||
<head>
|
||||
<title>{{ instance }} | HTTP Error ({{ error_code }})</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="apple-touch-icon" sizes="140x140" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
||||
{% if g.current_theme == 1 %}
|
||||
<link href="{{ url_for('static', filename='css/caliBlur.min.css') }}" rel="stylesheet" media="screen">
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container text-center">
|
||||
<h1>{{ error_code }}</h1>
|
||||
<h3>{{ error_name }}</h3>
|
||||
<a href="{{url_for('index')}}" title="{{ _('Back to home') }}">{{_('Back to home')}}</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,514 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||
# Copyright (C) 2018-2019 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/>.
|
||||
|
||||
import threading
|
||||
import zipfile
|
||||
import requests
|
||||
import re
|
||||
import logging
|
||||
import server
|
||||
import time
|
||||
from io import BytesIO
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
from ub import config, UPDATE_STABLE
|
||||
from tempfile import gettempdir
|
||||
import datetime
|
||||
import json
|
||||
from flask_babel import gettext as _
|
||||
from babel.dates import format_datetime
|
||||
import web
|
||||
|
||||
|
||||
def is_sha1(sha1):
|
||||
if len(sha1) != 40:
|
||||
return False
|
||||
try:
|
||||
int(sha1, 16)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class Updater(threading.Thread):
|
||||
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
self.status = -1
|
||||
self.updateIndex = None
|
||||
|
||||
def get_current_version_info(self):
|
||||
if config.get_update_channel == UPDATE_STABLE:
|
||||
return self._stable_version_info()
|
||||
else:
|
||||
return self._nightly_version_info()
|
||||
|
||||
def get_available_updates(self, request_method):
|
||||
if config.get_update_channel == UPDATE_STABLE:
|
||||
return self._stable_available_updates(request_method)
|
||||
else:
|
||||
return self._nightly_available_updates(request_method)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.status = 1
|
||||
r = requests.get(self._get_request_path(), stream=True)
|
||||
r.raise_for_status()
|
||||
|
||||
self.status = 2
|
||||
z = zipfile.ZipFile(BytesIO(r.content))
|
||||
self.status = 3
|
||||
tmp_dir = gettempdir()
|
||||
z.extractall(tmp_dir)
|
||||
foldername = os.path.join(tmp_dir, z.namelist()[0])[:-1]
|
||||
if not os.path.isdir(foldername):
|
||||
self.status = 11
|
||||
logging.getLogger('cps.web').info(u'Extracted contents of zipfile not found in temp folder')
|
||||
return
|
||||
self.status = 4
|
||||
self.update_source(foldername, config.get_main_dir)
|
||||
self.status = 6
|
||||
time.sleep(2)
|
||||
server.Server.setRestartTyp(True)
|
||||
server.Server.stopServer()
|
||||
self.status = 7
|
||||
time.sleep(2)
|
||||
except requests.exceptions.HTTPError as ex:
|
||||
logging.getLogger('cps.web').info( u'HTTP Error' + ' ' + str(ex))
|
||||
self.status = 8
|
||||
except requests.exceptions.ConnectionError:
|
||||
logging.getLogger('cps.web').info(u'Connection error')
|
||||
self.status = 9
|
||||
except requests.exceptions.Timeout:
|
||||
logging.getLogger('cps.web').info(u'Timeout while establishing connection')
|
||||
self.status = 10
|
||||
except requests.exceptions.RequestException:
|
||||
self.status = 11
|
||||
logging.getLogger('cps.web').info(u'General error')
|
||||
|
||||
def get_update_status(self):
|
||||
return self.status
|
||||
|
||||
@classmethod
|
||||
def file_to_list(self, filelist):
|
||||
return [x.strip() for x in open(filelist, 'r') if not x.startswith('#EXT')]
|
||||
|
||||
@classmethod
|
||||
def one_minus_two(self, one, two):
|
||||
return [x for x in one if x not in set(two)]
|
||||
|
||||
@classmethod
|
||||
def reduce_dirs(self, delete_files, new_list):
|
||||
new_delete = []
|
||||
for filename in delete_files:
|
||||
parts = filename.split(os.sep)
|
||||
sub = ''
|
||||
for part in parts:
|
||||
sub = os.path.join(sub, part)
|
||||
if sub == '':
|
||||
sub = os.sep
|
||||
count = 0
|
||||
for song in new_list:
|
||||
if song.startswith(sub):
|
||||
count += 1
|
||||
break
|
||||
if count == 0:
|
||||
if sub != '\\':
|
||||
new_delete.append(sub)
|
||||
break
|
||||
return list(set(new_delete))
|
||||
|
||||
@classmethod
|
||||
def reduce_files(self, remove_items, exclude_items):
|
||||
rf = []
|
||||
for item in remove_items:
|
||||
if not item.startswith(exclude_items):
|
||||
rf.append(item)
|
||||
return rf
|
||||
|
||||
@classmethod
|
||||
def moveallfiles(self, root_src_dir, root_dst_dir):
|
||||
change_permissions = True
|
||||
if sys.platform == "win32" or sys.platform == "darwin":
|
||||
change_permissions = False
|
||||
else:
|
||||
logging.getLogger('cps.web').debug('Update on OS-System : ' + sys.platform)
|
||||
new_permissions = os.stat(root_dst_dir)
|
||||
# print new_permissions
|
||||
for src_dir, __, files in os.walk(root_src_dir):
|
||||
dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
|
||||
if not os.path.exists(dst_dir):
|
||||
os.makedirs(dst_dir)
|
||||
logging.getLogger('cps.web').debug('Create-Dir: '+dst_dir)
|
||||
if change_permissions:
|
||||
# print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid))
|
||||
os.chown(dst_dir, new_permissions.st_uid, new_permissions.st_gid)
|
||||
for file_ in files:
|
||||
src_file = os.path.join(src_dir, file_)
|
||||
dst_file = os.path.join(dst_dir, file_)
|
||||
if os.path.exists(dst_file):
|
||||
if change_permissions:
|
||||
permission = os.stat(dst_file)
|
||||
logging.getLogger('cps.web').debug('Remove file before copy: '+dst_file)
|
||||
os.remove(dst_file)
|
||||
else:
|
||||
if change_permissions:
|
||||
permission = new_permissions
|
||||
shutil.move(src_file, dst_dir)
|
||||
logging.getLogger('cps.web').debug('Move File '+src_file+' to '+dst_dir)
|
||||
if change_permissions:
|
||||
try:
|
||||
os.chown(dst_file, permission.st_uid, permission.st_gid)
|
||||
except (Exception) as e:
|
||||
# ex = sys.exc_info()
|
||||
old_permissions = os.stat(dst_file)
|
||||
logging.getLogger('cps.web').debug('Fail change permissions of ' + str(dst_file) + '. Before: '
|
||||
+ str(old_permissions.st_uid) + ':' + str(old_permissions.st_gid) + ' After: '
|
||||
+ str(permission.st_uid) + ':' + str(permission.st_gid) + ' error: '+str(e))
|
||||
return
|
||||
|
||||
def update_source(self, source, destination):
|
||||
# destination files
|
||||
old_list = list()
|
||||
exclude = (
|
||||
os.sep + 'app.db', os.sep + 'calibre-web.log1', os.sep + 'calibre-web.log2', os.sep + 'gdrive.db',
|
||||
os.sep + 'vendor', os.sep + 'calibre-web.log', os.sep + '.git', os.sep +'client_secrets.json',
|
||||
os.sep + 'gdrive_credentials', os.sep + 'settings.yaml')
|
||||
for root, dirs, files in os.walk(destination, topdown=True):
|
||||
for name in files:
|
||||
old_list.append(os.path.join(root, name).replace(destination, ''))
|
||||
for name in dirs:
|
||||
old_list.append(os.path.join(root, name).replace(destination, ''))
|
||||
# source files
|
||||
new_list = list()
|
||||
for root, dirs, files in os.walk(source, topdown=True):
|
||||
for name in files:
|
||||
new_list.append(os.path.join(root, name).replace(source, ''))
|
||||
for name in dirs:
|
||||
new_list.append(os.path.join(root, name).replace(source, ''))
|
||||
|
||||
delete_files = self.one_minus_two(old_list, new_list)
|
||||
|
||||
rf = self.reduce_files(delete_files, exclude)
|
||||
|
||||
remove_items = self.reduce_dirs(rf, new_list)
|
||||
|
||||
self.moveallfiles(source, destination)
|
||||
|
||||
for item in remove_items:
|
||||
item_path = os.path.join(destination, item[1:])
|
||||
if os.path.isdir(item_path):
|
||||
logging.getLogger('cps.web').debug("Delete dir " + item_path)
|
||||
shutil.rmtree(item_path, ignore_errors=True)
|
||||
else:
|
||||
try:
|
||||
logging.getLogger('cps.web').debug("Delete file " + item_path)
|
||||
# log_from_thread("Delete file " + item_path)
|
||||
os.remove(item_path)
|
||||
except Exception:
|
||||
logging.getLogger('cps.web').debug("Could not remove:" + item_path)
|
||||
shutil.rmtree(source, ignore_errors=True)
|
||||
|
||||
def _nightly_version_info(self):
|
||||
content = {}
|
||||
content[0] = '$Format:%H$'
|
||||
content[1] = '$Format:%cI$'
|
||||
# content[0] = 'bb7d2c6273ae4560e83950d36d64533343623a57'
|
||||
# content[1] = '2018-09-09T10:13:08+02:00'
|
||||
if is_sha1(content[0]) and len(content[1]) > 0:
|
||||
return {'version': content[0], 'datetime': content[1]}
|
||||
return False
|
||||
|
||||
def _stable_version_info(self):
|
||||
return {'version': '0.6.1'} # Current version
|
||||
|
||||
def _nightly_available_updates(self, request_method):
|
||||
tz = datetime.timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone)
|
||||
if request_method == "GET":
|
||||
repository_url = 'https://api.github.com/repos/janeczku/calibre-web'
|
||||
status, commit = self._load_remote_data(repository_url +'/git/refs/heads/master')
|
||||
parents = []
|
||||
if status['message'] != '':
|
||||
return json.dumps(status)
|
||||
if 'object' not in commit:
|
||||
status['message'] = _(u'Unexpected data while reading update information')
|
||||
return json.dumps(status)
|
||||
|
||||
if commit['object']['sha'] == status['current_commit_hash']:
|
||||
status.update({
|
||||
'update': False,
|
||||
'success': True,
|
||||
'message': _(u'No update available. You already have the latest version installed')
|
||||
})
|
||||
return json.dumps(status)
|
||||
|
||||
# a new update is available
|
||||
status['update'] = True
|
||||
|
||||
try:
|
||||
r = requests.get(repository_url + '/git/commits/' + commit['object']['sha'])
|
||||
r.raise_for_status()
|
||||
update_data = r.json()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
status['error'] = _(u'HTTP Error') + ' ' + str(e)
|
||||
except requests.exceptions.ConnectionError:
|
||||
status['error'] = _(u'Connection error')
|
||||
except requests.exceptions.Timeout:
|
||||
status['error'] = _(u'Timeout while establishing connection')
|
||||
except requests.exceptions.RequestException:
|
||||
status['error'] = _(u'General error')
|
||||
|
||||
if status['message'] != '':
|
||||
return json.dumps(status)
|
||||
|
||||
if 'committer' in update_data and 'message' in update_data:
|
||||
status['success'] = True
|
||||
status['message'] = _(
|
||||
u'A new update is available. Click on the button below to update to the latest version.')
|
||||
|
||||
new_commit_date = datetime.datetime.strptime(
|
||||
update_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
|
||||
parents.append(
|
||||
[
|
||||
format_datetime(new_commit_date, format='short', locale=web.get_locale()),
|
||||
update_data['message'],
|
||||
update_data['sha']
|
||||
]
|
||||
)
|
||||
|
||||
# it only makes sense to analyze the parents if we know the current commit hash
|
||||
if status['current_commit_hash'] != '':
|
||||
try:
|
||||
parent_commit = update_data['parents'][0]
|
||||
# limit the maximum search depth
|
||||
remaining_parents_cnt = 10
|
||||
except IndexError:
|
||||
remaining_parents_cnt = None
|
||||
|
||||
if remaining_parents_cnt is not None:
|
||||
while True:
|
||||
if remaining_parents_cnt == 0:
|
||||
break
|
||||
|
||||
# check if we are more than one update behind if so, go up the tree
|
||||
if parent_commit['sha'] != status['current_commit_hash']:
|
||||
try:
|
||||
r = requests.get(parent_commit['url'])
|
||||
r.raise_for_status()
|
||||
parent_data = r.json()
|
||||
|
||||
parent_commit_date = datetime.datetime.strptime(
|
||||
parent_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
|
||||
parent_commit_date = format_datetime(
|
||||
parent_commit_date, format='short', locale=web.get_locale())
|
||||
|
||||
parents.append([parent_commit_date,
|
||||
parent_data['message'].replace('\r\n','<p>').replace('\n','<p>')])
|
||||
parent_commit = parent_data['parents'][0]
|
||||
remaining_parents_cnt -= 1
|
||||
except Exception:
|
||||
# it isn't crucial if we can't get information about the parent
|
||||
break
|
||||
else:
|
||||
# parent is our current version
|
||||
break
|
||||
|
||||
else:
|
||||
status['success'] = False
|
||||
status['message'] = _(u'Could not fetch update information')
|
||||
|
||||
# a new update is available
|
||||
status['update'] = True
|
||||
if 'body' in commit:
|
||||
status['success'] = True
|
||||
status['message'] = _(
|
||||
u'A new update is available. Click on the button below to update to the latest version.')
|
||||
|
||||
new_commit_date = datetime.datetime.strptime(
|
||||
commit['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
|
||||
parents.append(
|
||||
[
|
||||
format_datetime(new_commit_date, format='short', locale=web.get_locale()),
|
||||
commit['message'],
|
||||
commit['sha']
|
||||
]
|
||||
)
|
||||
|
||||
# it only makes sense to analyze the parents if we know the current commit hash
|
||||
if status['current_commit_hash'] != '':
|
||||
try:
|
||||
parent_commit = commit['parents'][0]
|
||||
# limit the maximum search depth
|
||||
remaining_parents_cnt = 10
|
||||
except IndexError:
|
||||
remaining_parents_cnt = None
|
||||
|
||||
if remaining_parents_cnt is not None:
|
||||
while True:
|
||||
if remaining_parents_cnt == 0:
|
||||
break
|
||||
|
||||
# check if we are more than one update behind if so, go up the tree
|
||||
if commit['sha'] != status['current_commit_hash']:
|
||||
try:
|
||||
r = requests.get(parent_commit['url'])
|
||||
r.raise_for_status()
|
||||
parent_data = r.json()
|
||||
|
||||
parent_commit_date = datetime.datetime.strptime(
|
||||
parent_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
|
||||
parent_commit_date = format_datetime(
|
||||
parent_commit_date, format='short', locale=web.get_locale())
|
||||
|
||||
parents.append([parent_commit_date, parent_data['message'], parent_data['sha']])
|
||||
parent_commit = parent_data['parents'][0]
|
||||
remaining_parents_cnt -= 1
|
||||
except Exception:
|
||||
# it isn't crucial if we can't get information about the parent
|
||||
break
|
||||
else:
|
||||
# parent is our current version
|
||||
break
|
||||
status['history'] = parents[::-1]
|
||||
return json.dumps(status)
|
||||
return ''
|
||||
|
||||
def _stable_available_updates(self, request_method):
|
||||
if request_method == "GET":
|
||||
parents = []
|
||||
# repository_url = 'https://api.github.com/repos/flatpak/flatpak/releases' # test URL
|
||||
repository_url = 'https://api.github.com/repos/janeczku/calibre-web/releases'
|
||||
status, commit = self._load_remote_data(repository_url)
|
||||
if status['message'] != '':
|
||||
return json.dumps(status)
|
||||
if not commit:
|
||||
status['success'] = True
|
||||
status['message'] = _(u'No release information available')
|
||||
return json.dumps(status)
|
||||
version = status['current_commit_hash']
|
||||
current_version = status['current_commit_hash'].split('.')
|
||||
|
||||
# we are already on newest version, no update available
|
||||
if 'tag_name' not in commit[0]:
|
||||
status['message'] = _(u'Unexpected data while reading update information')
|
||||
return json.dumps(status)
|
||||
if commit[0]['tag_name'] == version:
|
||||
status.update({
|
||||
'update': False,
|
||||
'success': True,
|
||||
'message': _(u'No update available. You already have the latest version installed')
|
||||
})
|
||||
return json.dumps(status)
|
||||
|
||||
i = len(commit) - 1
|
||||
while i >= 0:
|
||||
if 'tag_name' not in commit[i] or 'body' not in commit[i]:
|
||||
status['message'] = _(u'Unexpected data while reading update information')
|
||||
return json.dumps(status)
|
||||
major_version_update = int(commit[i]['tag_name'].split('.')[0])
|
||||
minor_version_update = int(commit[i]['tag_name'].split('.')[1])
|
||||
patch_version_update = int(commit[i]['tag_name'].split('.')[2])
|
||||
|
||||
# Check if major versions are identical search for newest nonenqual commit and update to this one
|
||||
if major_version_update == int(current_version[0]):
|
||||
if (minor_version_update == int(current_version[1]) and
|
||||
patch_version_update > int(current_version[2])) or \
|
||||
minor_version_update > int(current_version[1]):
|
||||
parents.append([commit[i]['tag_name'],commit[i]['body'].replace('\r\n', '<p>')])
|
||||
i -= 1
|
||||
continue
|
||||
if major_version_update < int(current_version[0]):
|
||||
i -= 1
|
||||
continue
|
||||
if major_version_update > int(current_version[0]):
|
||||
# found update update to last version before major update, unless current version is on last version
|
||||
# before major update
|
||||
if commit[i+1]['tag_name'].split('.')[1] == current_version[1]:
|
||||
parents.append([commit[i]['tag_name'],
|
||||
commit[i]['body'].replace('\r\n', '<p>').replace('\n', '<p>')])
|
||||
status.update({
|
||||
'update': True,
|
||||
'success': True,
|
||||
'message': _(u'A new update is available. Click on the button below to '
|
||||
u'update to version: %(version)s', version=commit[i]['tag_name']),
|
||||
'history': parents
|
||||
})
|
||||
self.updateFile = commit[i]['zipball_url']
|
||||
else:
|
||||
status.update({
|
||||
'update': True,
|
||||
'success': True,
|
||||
'message': _(u'A new update is available. Click on the button below to '
|
||||
u'update to version: %(version)s', version=commit[i]['tag_name']),
|
||||
'history': parents
|
||||
})
|
||||
self.updateFile = commit[i +1]['zipball_url']
|
||||
break
|
||||
if i == -1:
|
||||
status.update({
|
||||
'update': True,
|
||||
'success': True,
|
||||
'message': _(
|
||||
u'A new update is available. Click on the button below to update to the latest version.'),
|
||||
'history': parents
|
||||
})
|
||||
self.updateFile = commit[0]['zipball_url']
|
||||
return json.dumps(status)
|
||||
|
||||
def _get_request_path(self):
|
||||
if config.get_update_channel == UPDATE_STABLE:
|
||||
return self.updateFile
|
||||
else:
|
||||
return 'https://api.github.com/repos/janeczku/calibre-web/zipball/master'
|
||||
|
||||
def _load_remote_data(self, repository_url):
|
||||
status = {
|
||||
'update': False,
|
||||
'success': False,
|
||||
'message': '',
|
||||
'current_commit_hash': ''
|
||||
}
|
||||
commit = None
|
||||
version = self.get_current_version_info()
|
||||
if version is False:
|
||||
status['current_commit_hash'] = _(u'Unknown')
|
||||
else:
|
||||
status['current_commit_hash'] = version['version']
|
||||
try:
|
||||
r = requests.get(repository_url)
|
||||
commit = r.json()
|
||||
r.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if commit:
|
||||
if 'message' in commit:
|
||||
status['message'] = _(u'HTTP Error') + ': ' + commit['message']
|
||||
else:
|
||||
status['message'] = _(u'HTTP Error') + ': ' + str(e)
|
||||
except requests.exceptions.ConnectionError:
|
||||
status['message'] = _(u'Connection error')
|
||||
except requests.exceptions.Timeout:
|
||||
status['message'] = _(u'Timeout while establishing connection')
|
||||
except requests.exceptions.RequestException:
|
||||
status['message'] = _(u'General error')
|
||||
|
||||
return status, commit
|
||||
|
||||
|
||||
updater_thread = Updater()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue