Commit 6d99b9bc authored by Ethan Lin's avatar Ethan Lin Committed by GitHub

Merge pull request #1 from janeczku/master

update from janeczku/calibre-web
parents 9f65eae0 e5d881ed
......@@ -53,10 +53,9 @@ DB_ROOT = check_setting_str(CFG, 'General', 'DB_ROOT', "")
APP_DB_ROOT = check_setting_str(CFG, 'General', 'APP_DB_ROOT', os.getcwd())
MAIN_DIR = check_setting_str(CFG, 'General', 'MAIN_DIR', os.getcwd())
LOG_DIR = check_setting_str(CFG, 'General', 'LOG_DIR', os.getcwd())
PORT = check_setting_int(CFG, 'General', 'PORT', 8083)
PORT = check_setting_int(CFG, 'General', 'PORT', 8083)
NEWEST_BOOKS = check_setting_str(CFG, 'General', 'NEWEST_BOOKS', 60)
RANDOM_BOOKS = check_setting_int(CFG, 'General', 'RANDOM_BOOKS', 4)
DEFAULT_LANG = check_setting_str(CFG, 'General', 'DEFAULT_LANG', "")
CheckSection('Advanced')
TITLE_REGEX = check_setting_str(CFG, 'Advanced', 'TITLE_REGEX', '^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
......@@ -73,7 +72,7 @@ if DB_ROOT == "":
configval = {"DB_ROOT": DB_ROOT, "APP_DB_ROOT": APP_DB_ROOT, "MAIN_DIR": MAIN_DIR, "LOG_DIR": LOG_DIR, "PORT": PORT,
"NEWEST_BOOKS": NEWEST_BOOKS, "DEVELOPMENT": DEVELOPMENT, "TITLE_REGEX": TITLE_REGEX,
"PUBLIC_REG": PUBLIC_REG, "UPLOADING": UPLOADING, "ANON_BROWSE": ANON_BROWSE, "DEFAULT_LANG": DEFAULT_LANG}
"PUBLIC_REG": PUBLIC_REG, "UPLOADING": UPLOADING, "ANON_BROWSE": ANON_BROWSE}
def save_config(configval):
......@@ -86,7 +85,6 @@ def save_config(configval):
new_config['General']['LOG_DIR'] = configval["LOG_DIR"]
new_config['General']['PORT'] = configval["PORT"]
new_config['General']['NEWEST_BOOKS'] = configval["NEWEST_BOOKS"]
new_config['General']['DEFAULT_LANG'] = configval["DEFAULT_LANG"]
new_config['Advanced'] = {}
new_config['Advanced']['TITLE_REGEX'] = configval["TITLE_REGEX"]
new_config['Advanced']['DEVELOPMENT'] = int(configval["DEVELOPMENT"])
......
.annotator-adder {
width: 80px;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
@font-face {
font-family: 'Libre Baskerville';
font-style: normal;
font-weight: 400;
src: local('Libre Baskerville'), local('LibreBaskerville-Regular'), url("../fonts/LibreBaskerville-Regular.ttf") format('truetype');
}
@font-face {
font-family: 'Libre Baskerville';
font-style: normal;
font-weight: 700;
src: local('Libre Baskerville Bold'), local('LibreBaskerville-Bold'), url("../fonts/LibreBaskerville-Bold") format('truetype');
}
body{
color: #444;
line-height: 21px;
font-size: 14px;
}
h1, h2, h3, h4, h5, h6{
font-family: 'Libre Baskerville';
color: #45b29d !important;
font-size: 20px !important;
}
This diff is collapsed.
@font-face{font-family:Lato;font-style:normal;font-weight:100;src:local('Lato Hairline'),local('Lato-Hairline'),url(../fonts/Lato-Hairline.ttf) format('truetype')}@font-face{font-family:Lato;font-style:normal;font-weight:300;src:local('Lato Light'),local('Lato-Light'),url(../fonts/Lato-Light.ttf) format('truetype')}@font-face{font-family:Lato;font-style:normal;font-weight:400;src:local('Lato Regular'),local('Lato-Regular'),url(../fonts/Lato-Regular.ttf) format('truetype')}@font-face{font-family:Lato;font-style:normal;font-weight:700;src:local('Lato Bold'),local('Lato-Bold'),url(../fonts/Lato-Bold.ttf) format('truetype')}@font-face{font-family:Montserrat;font-style:normal;font-weight:400;src:local('Montserrat-Regular'),url(../fonts/Montserrat-Regular.ttf) format('truetype')}@font-face{font-family:Montserrat;font-style:normal;font-weight:700;src:local('Montserrat-Bold'),url(../fonts/Montserrat-Bold.ttf) format('truetype')}@font-face{font-family:Lobster;font-style:normal;font-weight:400;src:local('Lobster'),local('Lobster-Regular'),url(../fonts/Lobster.ttf) format('truetype')}
@font-face{font-family:'Gotham-Light';src:url('../fonts/itc/Gotham-Light.eot');src:url('../fonts/itc/Gotham-Light.woff') format('woff'),url('../fonts/itc/Gotham-Light.svg#Gotham-Light') format('svg')}@font-face{font-family:'Gotham-Medium';src:url('../fonts/itc/Gotham-Medium.eot');src:url('../fonts/itc/Gotham-Medium.woff') format('woff'),url('../fonts/itc/Gotham-Medium.svg#Gotham-Medium') format('svg')}@font-face{font-family:'Gotham-Book';src:url('../fonts/itc/Gotham-Book.eot');src:url('../fonts/itc/Gotham-Book.woff') format('woff'),url('../fonts/itc/Gotham-Book.svg#Gotham-Book') format('svg')}
.fraction-slider{
position:relative;
width:100%; height:100%;
overflow:visible;
}
.fraction-slider .slide{
display:none; width:100%; height:100%;
position:absolute;
z-index:5000;
}
.fraction-slider .active-slide{
z-index:9999;
}
.fraction-slider .fs_obj{
display:block; display:none;
position:absolute;
top:0px; left:100%;
z-index:7000;
}
.fraction-slider .fs_fixed_obj{
z-index:6000;
left:0;
}
.fraction-slider .fs_obj *{
display:inline-block;
position:relative;
top:0px; left:0px;
}
.fs_loader{
width:100%; height:400px;
background:url(images/fs.spinner.gif) center center no-repeat transparent;
}
/** CONTROLS **/
.fraction-slider .prev,
.fraction-slider .next{
display:none;
position:absolute;
width:45px; height:45px;
z-index:9999;
}
.fraction-slider .prev{
left:10px; top:48%;
background:url(images/fs.prevnext.png) 0px 0px no-repeat transparent;
}
.fraction-slider .prev:hover{
background:url(images/fs.prevnext.png) 0px -45px no-repeat transparent;
}
.fraction-slider .next{
right:10px; top:48%;
background:url(images/fs.prevnext.png) -45px 0px no-repeat transparent;
}
.fraction-slider .next:hover{
background:url(images/fs.prevnext.png) -45px -45px no-repeat transparent;
}
.fraction-slider:hover .prev,
.fraction-slider:hover .next{
display:block;
}
/** PAGER **/
.fs-pager-wrapper{
position:absolute;
left:10px; bottom:10px;
z-index:9999;
}
.fs-pager-wrapper a,
.fs-custom-pager-wrapper a{
display:inline-block;
width:14px; height:14px;
margin:0 5px 0 0;
background:url(images/fs.pager.png) 0px -14px no-repeat transparent;
}
.fs-pager-wrapper .active,
.fs-custom-pager-wrapper .active{
background:url(images/fs.pager.png) 0px 0px no-repeat transparent;
}
\ No newline at end of file
.vegas-loading {
border-radius: 10px;
background: #000;
background: rgba(0,0,0,0.7);
background: url(images/loading.gif) no-repeat center center; /* Loading Gif by http://preloaders.net/ */
height: 32px;
left: 20px;
position: fixed;
top: 20px;
width: 32px;
z-index: 0;
}
.vegas-overlay {
background: transparent url(overlays/01.png);
opacity: 0.5;
z-index: -1;
}
.vegas-background {
-ms-interpolation-mode: bicubic;
image-rendering: optimizeQuality;
max-width: none !important; /* counteracts global img modification by twitter bootstrap library */
z-index: -2;
}
.vegas-overlay,
.vegas-background {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
\ No newline at end of file
/* Magnific Popup CSS */
.mfp-bg {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1042;
overflow: hidden;
position: fixed;
background: #0b0b0b;
opacity: 0.8;
filter: alpha(opacity=80); }
.mfp-wrap {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1043;
position: fixed;
outline: none !important;
-webkit-backface-visibility: hidden; }
.mfp-container {
text-align: center;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
padding: 0 8px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
.mfp-container:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle; }
.mfp-align-top .mfp-container:before {
display: none; }
.mfp-content {
position: relative;
display: inline-block;
vertical-align: middle;
margin: 0 auto;
text-align: left;
z-index: 1045; }
.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content {
width: 100%;
cursor: auto; }
.mfp-ajax-cur {
cursor: progress; }
.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close {
cursor: -moz-zoom-out;
cursor: -webkit-zoom-out;
cursor: zoom-out; }
.mfp-zoom {
cursor: pointer;
cursor: -webkit-zoom-in;
cursor: -moz-zoom-in;
cursor: zoom-in; }
.mfp-auto-cursor .mfp-content {
cursor: auto; }
.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none; }
.mfp-loading.mfp-figure {
display: none; }
.mfp-hide {
display: none !important; }
.mfp-preloader {
color: #cccccc;
position: absolute;
top: 50%;
width: auto;
text-align: center;
margin-top: -0.8em;
left: 8px;
right: 8px;
z-index: 1044; }
.mfp-preloader a {
color: #cccccc; }
.mfp-preloader a:hover {
color: white; }
.mfp-s-ready .mfp-preloader {
display: none; }
.mfp-s-error .mfp-content {
display: none; }
button.mfp-close, button.mfp-arrow {
overflow: visible;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
display: block;
outline: none;
padding: 0;
z-index: 1046;
-webkit-box-shadow: none;
box-shadow: none; }
button::-moz-focus-inner {
padding: 0;
border: 0; }
.mfp-close {
width: 44px;
height: 44px;
line-height: 44px;
position: absolute;
right: 0;
top: 0;
text-decoration: none;
text-align: center;
opacity: 0.65;
padding: 0 0 18px 10px;
color: white;
font-style: normal;
font-size: 28px;
font-family: Arial, Baskerville, monospace; }
.mfp-close:hover, .mfp-close:focus {
opacity: 1; }
.mfp-close:active {
top: 1px; }
.mfp-close-btn-in .mfp-close {
color: #333333; }
.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close {
color: white;
right: -6px;
text-align: right;
padding-right: 6px;
width: 100%; }
.mfp-counter {
position: absolute;
top: 0;
right: 0;
color: #cccccc;
font-size: 12px;
line-height: 18px; }
.mfp-arrow {
position: absolute;
opacity: 0.65;
margin: 0;
top: 50%;
margin-top: -55px;
padding: 0;
width: 90px;
height: 110px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
.mfp-arrow:active {
margin-top: -54px; }
.mfp-arrow:hover, .mfp-arrow:focus {
opacity: 1; }
.mfp-arrow:before, .mfp-arrow:after, .mfp-arrow .mfp-b, .mfp-arrow .mfp-a {
content: '';
display: block;
width: 0;
height: 0;
position: absolute;
left: 0;
top: 0;
margin-top: 35px;
margin-left: 35px;
border: medium inset transparent; }
.mfp-arrow:after, .mfp-arrow .mfp-a {
border-top-width: 13px;
border-bottom-width: 13px;
top: 8px; }
.mfp-arrow:before, .mfp-arrow .mfp-b {
border-top-width: 21px;
border-bottom-width: 21px; }
.mfp-arrow-left {
left: 0; }
.mfp-arrow-left:after, .mfp-arrow-left .mfp-a {
border-right: 17px solid white;
margin-left: 31px; }
.mfp-arrow-left:before, .mfp-arrow-left .mfp-b {
margin-left: 25px;
border-right: 27px solid #3f3f3f; }
.mfp-arrow-right {
right: 0; }
.mfp-arrow-right:after, .mfp-arrow-right .mfp-a {
border-left: 17px solid white;
margin-left: 39px; }
.mfp-arrow-right:before, .mfp-arrow-right .mfp-b {
border-left: 27px solid #3f3f3f; }
.mfp-iframe-holder {
padding-top: 40px;
padding-bottom: 40px; }
.mfp-iframe-holder .mfp-content {
line-height: 0;
width: 100%;
max-width: 900px; }
.mfp-iframe-holder .mfp-close {
top: -40px; }
.mfp-iframe-scaler {
width: 100%;
height: 0;
overflow: hidden;
padding-top: 56.25%; }
.mfp-iframe-scaler iframe {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
background: black; }
/* Main image in popup */
img.mfp-img {
width: auto;
max-width: 100%;
height: auto;
display: block;
line-height: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 40px 0 40px;
margin: 0 auto; }
/* The shadow behind the image */
.mfp-figure {
line-height: 0; }
.mfp-figure:after {
content: '';
position: absolute;
left: 0;
top: 40px;
bottom: 40px;
display: block;
right: 0;
width: auto;
height: auto;
z-index: -1;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
background: #444444; }
.mfp-figure small {
color: #bdbdbd;
display: block;
font-size: 12px;
line-height: 14px; }
.mfp-bottom-bar {
margin-top: -36px;
position: absolute;
top: 100%;
left: 0;
width: 100%;
cursor: auto; }
.mfp-title {
text-align: left;
line-height: 18px;
color: #f3f3f3;
word-wrap: break-word;
padding-right: 36px; }
.mfp-image-holder .mfp-content {
max-width: 100%; }
.mfp-gallery .mfp-image-holder .mfp-figure {
cursor: pointer; }
@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) {
/**
* Remove all paddings around the image on small screen
*/
.mfp-img-mobile .mfp-image-holder {
padding-left: 0;
padding-right: 0; }
.mfp-img-mobile img.mfp-img {
padding: 0; }
.mfp-img-mobile .mfp-figure {
/* The shadow behind the image */ }
.mfp-img-mobile .mfp-figure:after {
top: 0;
bottom: 0; }
.mfp-img-mobile .mfp-figure small {
display: inline;
margin-left: 5px; }
.mfp-img-mobile .mfp-bottom-bar {
background: rgba(0, 0, 0, 0.6);
bottom: 0;
margin: 0;
top: auto;
padding: 3px 5px;
position: fixed;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
.mfp-img-mobile .mfp-bottom-bar:empty {
padding: 0; }
.mfp-img-mobile .mfp-counter {
right: 5px;
top: 3px; }
.mfp-img-mobile .mfp-close {
top: 0;
right: 0;
width: 35px;
height: 35px;
line-height: 35px;
background: rgba(0, 0, 0, 0.6);
position: fixed;
text-align: center;
padding: 0; } }
@media all and (max-width: 900px) {
.mfp-arrow {
-webkit-transform: scale(0.75);
transform: scale(0.75); }
.mfp-arrow-left {
-webkit-transform-origin: 0;
transform-origin: 0; }
.mfp-arrow-right {
-webkit-transform-origin: 100%;
transform-origin: 100%; }
.mfp-container {
padding-left: 6px;
padding-right: 6px; } }
.mfp-ie7 .mfp-img {
padding: 0; }
.mfp-ie7 .mfp-bottom-bar {
width: 600px;
left: 50%;
margin-left: -300px;
margin-top: 5px;
padding-bottom: 5px; }
.mfp-ie7 .mfp-container {
padding: 0; }
.mfp-ie7 .mfp-content {
padding-top: 44px; }
.mfp-ie7 .mfp-close {
top: 0;
right: 0;
padding-top: 0; }
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" > <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs >
<font id="entypo-social" horiz-adv-x="555" ><font-face
font-family="Entypo Social"
units-per-em="1000"
panose-1="0 0 0 0 0 0 0 0 0 0"
ascent="750"
descent="-250"
alphabetic="0" />
<missing-glyph horiz-adv-x="500" />
</font>
</defs>
</svg>
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" > <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs >
<font id="entypo" horiz-adv-x="508" ><font-face
font-family="Entypo"
units-per-em="1000"
panose-1="0 0 0 0 0 0 0 0 0 0"
ascent="750"
descent="-250"
alphabetic="0" />
<missing-glyph horiz-adv-x="500" />
</font>
</defs>
</svg>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*! intention.js v0.9.7.3
* http://intentionjs.com/
*
* context.js
*
* Copyright 2011, 2013 Dowjones and other contributors
* Released under the MIT license
*
*/
!function(){"use strict";var a=function(a,b){function c(a,b){var c=new Date,d=null;return function(e){var f=new Date;if(b>f-c){d&&window.clearTimeout(d);var g=function(b){return function(){a(b)}};return d=window.setTimeout(g(e),b),!1}a(e),c=f}}var d,e,f=new b;return f.responsive([{name:"base"}]).respond("base"),d=f.responsive({ID:"width",contexts:[{name:"standard",min:840},{name:"tablet",min:510},{name:"mobile",min:0}],matcher:function(a,b){return"string"==typeof a?a===b.name:a>=b.min},measure:function(b){return"string"==typeof b?b:a(window).width()}}),e=f.responsive({ID:"orientation",contexts:[{name:"portrait",rotation:0},{name:"landscape",rotation:90}],matcher:function(a,b){return a===b.rotation},measure:function(){var a=Math.abs(window.orientation);return a>0&&(a=180-a),a}}),f.responsive({ID:"touch",contexts:[{name:"touch"}],matcher:function(){return"ontouchstart"in window}}).respond(),f.responsive({ID:"highres",contexts:[{name:"highres"}],matcher:function(){return window.devicePixelRatio>1}}).respond(),a(window).on("resize",c(d.respond,100)).on("orientationchange",d.respond).on("orientationchange",e.respond),d.respond(),e.respond(),a(function(){f.elements(document)}),f};!function(a,b){"function"==typeof define&&define.amd?define("context",["jquery","intention"],b):a.intent=b(a.jQuery,a.Intention)}(this,function(b,c){return a(b,c)})}.call(this);
\ No newline at end of file
EPUBJS.Hooks.register("beforeChapterDisplay").highlight = function(callback, renderer){
// EPUBJS.core.addScript("js/libs/jquery.highlight.js", null, renderer.doc.head);
var s = document.createElement("style");
s.innerHTML =".highlight { background: yellow; font-weight: normal; }";
renderer.render.document.head.appendChild(s);
if(callback) callback();
}
This diff is collapsed.
/*! intention.js v0.9.7.3
* http://intentionjs.com/
*
* intention.js
*
* Copyright 2011, 2013 Dowjones and other contributors
* Released under the MIT license
*
*/
!function(a,b){"use strict";"function"==typeof define&&define.amd?define("intention",["jquery","underscore"],b):a.Intention=b(a.jQuery,a._)}(this,function(a,b){"use strict";var c=function(c){var d=b.extend(this,c,{_listeners:{},contexts:[],elms:a(),axes:{},priority:[]});return d};return c.prototype={responsive:function d(a,c){var e,f="abcdefghijklmnopqrstuvwxyz0123456789",g="";for(e=0;5>e;e++)g+=f[Math.floor(Math.random()*f.length)];var h={matcher:function(a,b){return a===b.name},measure:b.identity,ID:g};if(b.isObject(c)===!1&&(c={}),b.isArray(a)&&b.isArray(a[0].contexts))return b.each(a,function(a){d.apply(this,a)},this),void 0;b.isArray(a)===!1&&b.isObject(a)?c=a:c.contexts=a,c=b.extend({},h,c),this.on("_"+c.ID+":",b.bind(function(a){this.axes=this._contextualize(c.ID,a.context,this.axes),this._respond(this.axes,this.elms)},this));var i={ID:c.ID,current:null,contexts:c.contexts,respond:b.bind(this._responder(c.ID,c.contexts,c.matcher,c.measure),this)};return this.axes[c.ID]=i,this.axes.__keys__=this.priority,this.priority.unshift(c.ID),i},elements:function(c){return c||(c=document),a("[data-intent],[intent],[data-in],[in]",c).each(b.bind(function(b,c){this.add(a(c))},this)),this},add:function(c,d){var e;return d||(d={}),c.each(b.bind(function(c,f){var g=!1;this.elms.each(function(a,b){return f===b?(g=!0,!1):!0}),g===!1&&(e=this._fillSpec(b.extend(d,this._attrsToSpec(f.attributes,this.axes))),this._makeChanges(a(f),e,this.axes),this.elms.push({elm:f,spec:e}))},this)),this},remove:function(a){var b=this.elms;return a.each(function(a,c){b.each(function(a,d){return c===d.elm?(b.splice(a,1),!1):!0})}),this},is:function(a){var c=this.axes;return b.some(c.__keys__,function(b){return a===c[b].current})},current:function(a){return this.axes.hasOwnProperty(a)?this.axes[a].current:!1},on:function(a,b){var c=a.split(" "),d=0;for(d;d<c.length;d++)void 0===this._listeners[c[d]]&&(this._listeners[c[d]]=[]),this._listeners[c[d]].push(b);return this},off:function(a,c){if(b.isArray(this._listeners[a])){var d,e=this._listeners[a];for(d=0;e.length;d++)if(e[d]===c){e.splice(d,1);break}}return this},_responder:function(a,c,d,e){var f;return function(){var g=e.apply(this,arguments);return b.every(c,function(c){return d(g,c)?void 0===f||c.name!==f.name?(f=c,this._emitter({_type:"_"+a+":",context:f.name},f,this)._emitter({_type:a+":",context:f.name},f,this)._emitter(b.extend({},{_type:a+":"+f.name},f),f,this)._emitter(b.extend({},{_type:f.name},f),f,this),!1):!1:!0},this),this}},_emitter:function(a){if("string"==typeof a&&(a={_type:a}),a.target||(a.target=this),!a._type)throw new Error(a._type+" is not a supported event.");if(b.isArray(this._listeners[a._type])){var c,d=this._listeners[a._type];for(c=0;c<d.length;c++)d[c].apply(this,arguments)}return this},_fillSpec:function(a){var c=function(c){b.each(a,function(a,d){b.each(a,function(a,b){c(a,b,d)})})},d={};return c(function(a){b.isObject(a)&&b.each(a,function(a,b){d[b]=""})}),c(function(c,e,f){b.isObject(c)&&(a[f][e]=b.extend({},d,c))}),a},_assocAxis:function(a,c){var d=!1;return b.every(c.__keys__,function(e){return d===!1?(b.every(c[e].contexts,function(b){return b.name===a?(d=e,!1):!0}),!0):!1}),d},_makeSpec:function(a,b,c,d,e){var f;return void 0!==e[a]?(f=e[a],void 0===f[b]&&(f[b]={})):(f={},f[b]={},e[a]=f),f[b][c]=d,e},_attrsToSpec:function(a,c){var d={},e=new RegExp("^(data-)?(in|intent)-(([a-zA-Z0-9][a-zA-Z0-9]*:)?([a-zA-Z0-9]*))-([A-Za-z:-]+)"),f=new RegExp("^(data-)?(in|intent)-([a-zA-Z0-9][_a-zA-Z0-9]*):$");return b.each(a,function(a){var g,h=a.name.match(e);if(null!==h){if(h=h.slice(-3),g=h[0],void 0===h[0]){if(h[0]=this._assocAxis(h[1],c),h[0]===!1)return}else h[0]=h[0].replace(/:$/,"");h.push(a.value),h.push(d),d=this._makeSpec.apply(this,h)}else f.test(a.name)&&(g=a.name.match(f)[3],b.each(c[g].contexts,function(b){this._makeSpec(g,b.name,"class",b.name+" "+a.value,d)},this))},this),d},_contextSpec:function(a,b){return b.hasOwnProperty(a.axis)&&b[a.axis].hasOwnProperty(a.ctx)?b[a.axis][a.ctx]:{}},_resolveSpecs:function(c,d){var e={},f=["append","prepend","before","after"];return b.each(c,function(c){b.each(this._contextSpec(c,d),function(c,d){"class"===d?(e[d]||(e[d]=[]),e[d]=b.union(e[d],c.split(" "))):void 0!==e.move&&""!==e.move.value||-1===a.inArray(d,f)?(void 0===e[d]||""===e[d])&&(e[d]=c):e.move={value:c,placement:d}},this)},this),e},_currentContexts:function(a){var c=[];return b.each(a.__keys__,function(b){return null!==a[b].current?(c.push({ctx:a[b].current,axis:b}),void 0):void 0}),c},_removeClasses:function(a,c){var d=[];return b.each(c.__keys__,function(e){var f=c[e];b.each(f.contexts,function(c){if(c.name!==f.current){var e,g=this._contextSpec({axis:f.ID,ctx:c.name},a);void 0!==g&&void 0!==g["class"]&&(e=g["class"].split(" "),void 0!==e&&(d=b.union(d,e)))}},this)},this),d},_contextConfig:function(a,b){return this._resolveSpecs(this._currentContexts(b),a,b)},_makeChanges:function(c,d,e){if(b.isEmpty(e)===!1){var f=this._contextConfig(d,e);b.each(f,function(f,g){if("move"===g)(d.__placement__!==f.placement||d.__move__!==f.value)&&(a(f.value)[f.placement](c),d.__placement__=f.placement,d.__move__=f.value);else if("class"===g){var h=c.attr("class")||"";h=b.union(f,b.difference(h.split(" "),this._removeClasses(d,e))),c.attr("class",h.join(" "))}else c.attr(g,f)},this)}return c},_respond:function(c,d){d.each(b.bind(function(b,d){var e=a(d.elm);this._makeChanges(e,d.spec,c),e.trigger("intent",this)},this))},_contextualize:function(a,b,c){return c[a].current=b,c},_axis_test_pattern:new RegExp("^_[a-zA-Z0-9]"),_axis_match_pattern:new RegExp("^_([a-zA-Z0-9][_a-zA-Z0-9]*)"),_trim_pattern:new RegExp("^s+|s+$","g")},c});
\ No newline at end of file
This diff is collapsed.
// ----------------------------------------------------------------------------
// Vegas – Fullscreen Backgrounds and Slideshows with jQuery.
// v1.3.3 - released 2013-09-03 13:27
// Licensed under the MIT license.
// http://vegas.jaysalvat.com/
// ----------------------------------------------------------------------------
// Copyright (C) 2010-2013 Jay Salvat
// http://jaysalvat.com/
// ----------------------------------------------------------------------------
(function(e){function t(a,n){var r={align:"center",valign:"center"};if(e.extend(r,n),0===a.height())return a.load(function(){t(e(this),n)}),void 0;var i,s,g,d=o(),l=d.width,u=d.height,v=a.width(),c=a.height(),p=u/l,f=c/v;p>f?(i=u/f,s=u):(i=l,s=l*f),g={width:i+"px",height:s+"px",top:"auto",bottom:"auto",left:"auto",right:"auto"},isNaN(parseInt(r.valign,10))?"top"==r.valign?g.top=0:"bottom"==r.valign?g.bottom=0:g.top=(u-s)/2:g.top=0-(s-u)/100*parseInt(r.valign,10)+"px",isNaN(parseInt(r.align,10))?"left"==r.align?g.left=0:"right"==r.align?g.right=0:g.left=(l-i)/2:g.left=0-(i-l)/100*parseInt(r.align,10)+"px",a.css(g)}function a(){d.prependTo("body").fadeIn()}function n(){d.fadeOut("fast",function(){e(this).remove()})}function r(){return e("body").css("backgroundImage")?e("body").css("backgroundImage").replace(/url\("?(.*?)"?\)/i,"$1"):void 0}function o(){var e=window,t="inner";return"innerWidth"in window||(e=document.documentElement||document.body,t="client"),{width:e[t+"Width"],height:e[t+"Height"]}}var i,s=e("<img />").addClass("vegas-background"),g=e("<div />").addClass("vegas-overlay"),d=e("<div />").addClass("vegas-loading"),l=e(),u=null,v=[],c=0,p=5e3,f=function(){},h={init:function(o){var i={src:r(),align:"center",valign:"center",fade:0,loading:!0,load:function(){},complete:function(){}};e.extend(i,e.vegas.defaults.background,o),i.loading&&a();var g=s.clone();return g.css({position:"fixed",left:"0px",top:"0px"}).bind("load",function(){g!=l&&(e(window).bind("load resize.vegas",function(){t(g,i)}),l.is("img")?(l.stop(),g.hide().insertAfter(l).fadeIn(i.fade,function(){e(".vegas-background").not(this).remove(),e("body").trigger("vegascomplete",[this,c-1]),i.complete.apply(g,[c-1])})):g.hide().prependTo("body").fadeIn(i.fade,function(){e("body").trigger("vegascomplete",[this,c-1]),i.complete.apply(this,[c-1])}),l=g,t(l,i),i.loading&&n(),e("body").trigger("vegasload",[l.get(0),c-1]),i.load.apply(l.get(0),[c-1]),c&&(e("body").trigger("vegaswalk",[l.get(0),c-1]),i.walk.apply(l.get(0),[c-1])))}).attr("src",i.src),e.vegas},destroy:function(t){return t&&"background"!=t||(e(".vegas-background, .vegas-loading").remove(),e(window).unbind("*.vegas"),l=e()),t&&"overlay"!=t||e(".vegas-overlay").remove(),clearInterval(i),e.vegas},overlay:function(t){var a={src:null,opacity:null};return e.extend(a,e.vegas.defaults.overlay,t),g.remove(),g.css({margin:"0",padding:"0",position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),a.src&&g.css("backgroundImage","url("+a.src+")"),a.opacity&&g.css("opacity",a.opacity),g.prependTo("body"),e.vegas},slideshow:function(t,a){var n={step:c,delay:p,preload:!1,backgrounds:v,walk:f};if(e.extend(n,e.vegas.defaults.slideshow,t),n.backgrounds!=v&&(t.step||(n.step=0),t.walk||(n.walk=function(){}),n.preload&&e.vegas("preload",n.backgrounds)),v=n.backgrounds,p=n.delay,c=n.step,f=n.walk,clearInterval(i),!v.length)return e.vegas;var r=function(){0>c&&(c=v.length-1),(c>=v.length||!v[c-1])&&(c=0);var t=v[c++];t.walk=n.walk,t.fade===void 0&&(t.fade=n.fade),t.fade>n.delay&&(t.fade=n.delay),e.vegas(t)};return r(),a||(u=!1,e("body").trigger("vegasstart",[l.get(0),c-1])),u||(i=setInterval(r,n.delay)),e.vegas},next:function(){var t=c;return c&&(e.vegas("slideshow",{step:c},!0),e("body").trigger("vegasnext",[l.get(0),c-1,t-1])),e.vegas},previous:function(){var t=c;return c&&(e.vegas("slideshow",{step:c-2},!0),e("body").trigger("vegasprevious",[l.get(0),c-1,t-1])),e.vegas},jump:function(t){var a=c;return c&&(e.vegas("slideshow",{step:t},!0),e("body").trigger("vegasjump",[l.get(0),c-1,a-1])),e.vegas},stop:function(){var t=c;return c=0,u=null,clearInterval(i),e("body").trigger("vegasstop",[l.get(0),t-1]),e.vegas},pause:function(){return u=!0,clearInterval(i),e("body").trigger("vegaspause",[l.get(0),c-1]),e.vegas},get:function(e){return null===e||"background"==e?l.get(0):"overlay"==e?g.get(0):"step"==e?c-1:"paused"==e?u:void 0},preload:function(t){var a=[];for(var n in t)if(t[n].src){var r=document.createElement("img");r.src=t[n].src,a.push(r)}return e.vegas}};e.vegas=function(t){return h[t]?h[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?(e.error("Method "+t+" does not exist"),void 0):h.init.apply(this,arguments)},e.vegas.defaults={background:{},slideshow:{},overlay:{}}})(jQuery);
\ No newline at end of file
/*!
* screenfull
* v2.0.0 - 2014-12-22
* (c) Sindre Sorhus; MIT License
*/
(function () {
'use strict';
var isCommonjs = typeof module !== 'undefined' && module.exports;
var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;
var fn = (function () {
var val;
var valLength;
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];
var i = 0;
var l = fnMap.length;
var ret = {};
for (; i < l; i++) {
val = fnMap[i];
if (val && val[1] in document) {
for (i = 0, valLength = val.length; i < valLength; i++) {
ret[fnMap[0][i]] = val[i];
}
return ret;
}
}
return false;
})();
var screenfull = {
request: function (elem) {
var request = fn.requestFullscreen;
elem = elem || document.documentElement;
// Work around Safari 5.1 bug: reports support for
// keyboard in fullscreen even though it doesn't.
// Browser sniffing, since the alternative with
// setTimeout is even worse.
if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
elem[request]();
} else {
elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
}
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
if (this.isFullscreen) {
this.exit();
} else {
this.request(elem);
}
},
raw: fn
};
if (!fn) {
if (isCommonjs) {
module.exports = false;
} else {
window.screenfull = false;
}
return;
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: function () {
return !!document[fn.fullscreenElement];
}
},
element: {
enumerable: true,
get: function () {
return document[fn.fullscreenElement];
}
},
enabled: {
enumerable: true,
get: function () {
// Coerce to boolean in case of old WebKit
return !!document[fn.fullscreenEnabled];
}
}
});
if (isCommonjs) {
module.exports = screenfull;
} else {
window.screenfull = screenfull;
}
})();
/*!
* screenfull
* v1.1.0 - 2013-09-06
* https://github.com/sindresorhus/screenfull.js
* (c) Sindre Sorhus; MIT License
*/
!function(a,b){"use strict";var c="undefined"!=typeof Element&&"ALLOW_KEYBOARD_INPUT"in Element,d=function(){for(var a,c,d=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenchange","MSFullscreenerror"]],e=0,f=d.length,g={};f>e;e++)if(a=d[e],a&&a[1]in b){for(e=0,c=a.length;c>e;e++)g[d[0][e]]=a[e];return g}return!1}(),e={request:function(a){var e=d.requestFullscreen;a=a||b.documentElement,/5\.1[\.\d]* Safari/.test(navigator.userAgent)?a[e]():a[e](c&&Element.ALLOW_KEYBOARD_INPUT)},exit:function(){b[d.exitFullscreen]()},toggle:function(a){this.isFullscreen?this.exit():this.request(a)},onchange:function(){},onerror:function(){},raw:d};return d?(Object.defineProperties(e,{isFullscreen:{get:function(){return!!b[d.fullscreenElement]}},element:{enumerable:!0,get:function(){return b[d.fullscreenElement]}},enabled:{enumerable:!0,get:function(){return!!b[d.fullscreenEnabled]}}}),b.addEventListener(d.fullscreenchange,function(a){e.onchange.call(e,a)}),b.addEventListener(d.fullscreenerror,function(a){e.onerror.call(e,a)}),a.screenfull=e,void 0):(a.screenfull=!1,void 0)}(window,document);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
// Hypothesis Customized embedding
// This hypothesis config function returns a new constructor which modifies
// annotator for a better integration. Below we create our own EpubAnnotationSidebar
// Constructor, customizing the show and hide function to take acount for the reader UI.
window.hypothesisConfig = function() {
var Annotator = window.Annotator;
var $main = $("#main");
function EpubAnnotationSidebar(elem, options) {
options = {
server: true,
origin: true,
showHighlights: true,
Toolbar: {container: '#annotation-controls'}
}
Annotator.Host.call(this, elem, options);
}
EpubAnnotationSidebar.prototype = Object.create(Annotator.Host.prototype);
EpubAnnotationSidebar.prototype.show = function() {
this.frame.css({
'margin-left': (-1 * this.frame.width()) + "px"
});
this.frame.removeClass('annotator-collapsed');
if (!$main.hasClass('single')) {
$main.addClass("single");
this.toolbar.find('[name=sidebar-toggle]').removeClass('h-icon-chevron-left').addClass('h-icon-chevron-right');
this.setVisibleHighlights(true);
}
};
EpubAnnotationSidebar.prototype.hide = function() {
this.frame.css({
'margin-left': ''
});
this.frame.addClass('annotator-collapsed');
if ($main.hasClass('single')) {
$main.removeClass("single");
this.toolbar.find('[name=sidebar-toggle]').removeClass('h-icon-chevron-right').addClass('h-icon-chevron-left');
this.setVisibleHighlights(false);
}
};
return {
constructor: EpubAnnotationSidebar,
}
};
// This is the Epub.js plugin. Annotations are updated on location change.
EPUBJS.reader.plugins.HypothesisController = function (Book) {
var reader = this;
var $main = $("#main");
var updateAnnotations = function () {
var annotator = Book.renderer.render.window.annotator;
if (annotator && annotator.constructor.$) {
var annotations = getVisibleAnnotations(annotator.constructor.$);
annotator.showAnnotations(annotations)
}
};
var getVisibleAnnotations = function ($) {
var width = Book.renderer.render.iframe.clientWidth;
return $('.annotator-hl').map(function() {
var $this = $(this),
left = this.getBoundingClientRect().left;
if (left >= 0 && left <= width) {
return $this.data('annotation');
}
}).get();
};
Book.on("renderer:locationChanged", updateAnnotations);
return {}
};
EPUBJS.reader.search = {};
// Search Server -- https://github.com/futurepress/epubjs-search
EPUBJS.reader.search.SERVER = "";
EPUBJS.reader.search.request = function(q, callback) {
var fetch = $.ajax({
dataType: "json",
url: EPUBJS.reader.search.SERVER + "/search?q=" + encodeURIComponent(q)
});
fetch.fail(function(err) {
console.error(err);
});
fetch.done(function(results) {
callback(results);
});
};
EPUBJS.reader.plugins.SearchController = function(Book) {
var reader = this;
var $searchBox = $("#searchBox"),
$searchResults = $("#searchResults"),
$searchView = $("#searchView"),
iframeDoc;
var searchShown = false;
var onShow = function() {
query();
searchShown = true;
$searchView.addClass("shown");
};
var onHide = function() {
searchShown = false;
$searchView.removeClass("shown");
};
var query = function() {
var q = $searchBox.val();
if(q == '') {
return;
}
$searchResults.empty();
$searchResults.append("<li><p>Searching...</p></li>");
EPUBJS.reader.search.request(q, function(data) {
var results = data.results;
$searchResults.empty();
if(iframeDoc) {
$(iframeDoc).find('body').unhighlight();
}
if(results.length == 0) {
$searchResults.append("<li><p>No Results Found</p></li>");
return;
}
iframeDoc = $("#viewer iframe")[0].contentDocument;
$(iframeDoc).find('body').highlight(q, { element: 'span' });
results.forEach(function(result) {
var $li = $("<li></li>");
var $item = $("<a href='"+result.href+"' data-cfi='"+result.cfi+"'><span>"+result.title+"</span><p>"+result.highlight+"</p></a>");
$item.on("click", function(e) {
var $this = $(this),
cfi = $this.data("cfi");
e.preventDefault();
Book.gotoCfi(cfi+"/1:0");
Book.on("renderer:chapterDisplayed", function() {
iframeDoc = $("#viewer iframe")[0].contentDocument;
$(iframeDoc).find('body').highlight(q, { element: 'span' });
})
});
$li.append($item);
$searchResults.append($li);
});
});
};
$searchBox.on("search", function(e) {
var q = $searchBox.val();
//-- SearchBox is empty or cleared
if(q == '') {
$searchResults.empty();
if(reader.SidebarController.getActivePanel() == "Search") {
reader.SidebarController.changePanelTo("Toc");
}
$(iframeDoc).find('body').unhighlight();
iframeDoc = false;
return;
}
reader.SidebarController.changePanelTo("Search");
e.preventDefault();
});
return {
"show" : onShow,
"hide" : onHide
};
};
document.ontouchmove = function(e){
return true;
};
Sortable.create(sortTrue, {
group: "sorting",
sort: true
});
function sendData(path){
var elements;
var counter;
var maxElements;
var tmp=[];
elements=Sortable.utils.find(sortTrue,"div");
maxElements=elements.length;
var form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", path);
for(counter=0;counter<maxElements;counter++){
tmp[counter]=elements[counter].getAttribute("id");
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", elements[counter].getAttribute("id"));
hiddenField.setAttribute("value", counter+1);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -13,9 +13,9 @@
<th>{{_('Upload')}}</th>
<th>{{_('Edit')}}</th>
<th>{{_('Passwd')}}</th>
</tr>
{% for user in content %}
{% if not user.role_anonymous() or config.ANON_BROWSE %}
<tr>
<td><a href="{{url_for('edit_user', user_id=user.id)}}">{{user.nickname}}</a></td>
<td>{{user.email}}</td>
......@@ -26,7 +26,8 @@
<td>{% if user.role_upload() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_edit() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_passwd() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<div class="btn btn-default"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
......
......@@ -104,11 +104,11 @@
{{entry.comments[0].text|safe}}
{% endif %}
{% if g.user.is_authenticated %}
<div class="more-stuff">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Download, send to Kindle, reading">
{% if g.user.role_download() %}
<div class="btn-group" role="group">
<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')}}
......@@ -120,6 +120,9 @@
{%endfor%}
</ul>
</div>
{% endif %}
{% if g.user.is_authenticated %}
{% if g.user.kindle_mail %}
<a href="{{url_for('send_to_kindle', book_id=entry.id)}}" id="sendbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{_('Send to Kindle')}}</a>
{% endif %}
......@@ -136,10 +139,11 @@
{%endfor%}
</ul>
</div>
{% endif %}
</div>
</div>
</br>
{% if g.user.is_authenticated %}
{% if g.user.shelf.all() or g.public_shelfes %}
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Add to shelves">
......@@ -180,7 +184,7 @@
</div>
</div>
{% endif %}
{% endif %}
{% if g.user.role_edit() %}
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Edit/Delete book">
......@@ -189,7 +193,7 @@
</div>
{% endif %}
{% endif %}
</div>
</div>
</div>
......
......@@ -30,7 +30,6 @@
{% endif %}
</div>
</div>
<!-- <p><a href="{{ url_for('edit_book', book_id=entry.id) }}">{{entry.authors[0].name}}: {{entry.title}}</a></p> -->
{% endfor %}
</div>
</div>
......
......@@ -12,8 +12,8 @@
<input type="text" class="form-control" name="mail_port" id="mail_port" value="{{content.mail_port}}">
</div>
<div class="form-group">
<label for="mail_use_ssl">{{_('Server uses SSL (StartTLS)')}}</label>
<input type="checkbox" name="mail_use_ssl" id="mail_use_ssl" {% if content.mail_use_ssl %}checked{% endif %}>
<label for="mail_use_ssl">{{_('Server uses SSL (StartTLS)')}}</label>
</div>
<div class="form-group">
<label for="mail_login">{{_('SMTP login')}}</label>
......
......@@ -2,18 +2,30 @@
<feed xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:2853dacf-ed79-42f5-8e8a-a7bb3d1ae6a2</id>
<link rel="self"
href="{{url_for('feed_index')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
href="{{request.script_root + request.full_path}}"
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<link rel="start"
href="{{url_for('feed_index')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<link rel="up"
href="{{url_for('feed_index')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
{% if pagination.has_prev %}
<link rel="first"
href="{{request.script_root + request.path}}"
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
{% endif %}
{% if pagination.has_next %}
<link rel="next"
title="{{_('Next')}}"
href="{{ next_url }}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
href="{{ request.script_root + request.path }}?offset={{ pagination.next_offset }}"
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
{% endif %}
{% if pagination.has_prev %}
<link rel="previous"
href="{{request.script_root + request.path}}?offset={{ pagination.previous_offset }}"
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
{% endif %}
<link rel="search"
href="{{url_for('feed_osd')}}"
type="application/opensearchdescription+xml"/>
......@@ -30,7 +42,6 @@
<updated>{{entry.timestamp}}</updated>
<author>
<name>{{entry.authors[0].name}}</name>
<uri>{{entry.authors[0].name}}</uri>
</author>
<language>{{entry.language}}</language>
{% for tag in entry.tags %}
......@@ -38,45 +49,39 @@
term="{{tag.name}}"
label="{{tag.name}}"/>
{% endfor %}
<summary>{% if entry.comments[0] %}{{entry.comments[0].text|striptags}}{% endif %}</summary>
{% if entry.comments[0] %}<summary>{{entry.comments[0].text|striptags}}</summary>{% endif %}
{% if entry.has_cover %}
<link rel="http://opds-spec.org/image" href="{{ url_for('feed_get_cover', cover_path=entry.path) }}" type="image/jpg"/>
<link rel="http://opds-spec.org/cover" href="{{ url_for('feed_get_cover', cover_path=entry.path) }}" type="image/jpg"/>
<link rel="http://opds-spec.org/image/thumbnail" href="{{ url_for('feed_get_cover', cover_path=entry.path) }}" type="image/jpg"/>
<link type="image/jpeg" href="{{url_for('feed_get_cover', book_id=entry.id)}}" rel="http://opds-spec.org/image"/>
<link type="image/jpeg" href="{{url_for('feed_get_cover', book_id=entry.id)}}" rel="http://opds-spec.org/image/thumbnail"/>
{% endif %}
{% for format in entry.data %}
<link rel="http://opds-spec.org/acquisition" href="{{ url_for('get_opds_download_link', book_id=entry.id, format=format.format|lower)}}"
length="{{format.uncompressed_size}}" mtime="{{entry.timestamp}}"
{% if format.format|lower == "epub" %}
type="application/epub+zip"/>
{% else %}
type="application/x-mobipocket-ebook"/>
{% endif %}
length="{{format.uncompressed_size}}" mtime="{{entry.timestamp}}" type="{{format.format|lower|mimetype}}"/>
{% endfor %}
</entry>
{% endfor %}
{% for author in authors %}
<entry>
<title>{{author.name}}</title>
<id>{{ url_for('feed_author', name=author.name) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_author', name=author.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_author', name=author.name)}}" rel="subsection"/>
<id>{{ url_for('feed_author', id=author.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_author', id=author.id)}}"/>
<link type="application/atom+xml" href="{{url_for('feed_author', id=author.id)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in categorys %}
<entry>
<title>{{entry.name}}</title>
<id>{{ url_for('feed_category', name=entry.name) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_category', name=entry.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_category', name=entry.name)}}" rel="subsection"/>
<id>{{ url_for('feed_category', id=entry.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_category', id=entry.id)}}"/>
<link type="application/atom+xml" href="{{url_for('feed_category', id=entry.id)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in series %}
<entry>
<title>{{entry.name}}</title>
<id>{{ url_for('feed_series', name=entry.name) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_series', name=entry.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_series', name=entry.name)}}" rel="subsection"/>
<id>{{ url_for('feed_series', id=entry.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_series', id=entry.id)}}" />
<link type="application/atom+xml" href="{{url_for('feed_series', id=entry.id)}}" rel="subsection"/>
</entry>
{% endfor %}
</feed>
......@@ -27,28 +27,28 @@
</entry>
<entry>
<title>{{_('Random Books')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_discover')}}" />
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_discover')}}"/>
<link rel="http://opds-spec.org/featured" href="{{url_for('feed_discover')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition"/>
<id>{{url_for('feed_discover')}}</id>
<content type="text">{{_('Show Random Books')}}</content>
</entry>
<entry>
<title>{{_('Authors')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_authorindex')}}" />
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_authorindex')}}"/>
<link rel="subsection" href="{{url_for('feed_authorindex')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_authorindex')}}</id>
<content type="text">{{_('Books ordered by Author')}}</content>
</entry>
<entry>
<title>{{_('Category list')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_categoryindex')}}" />
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_categoryindex')}}"/>
<link rel="subsection" href="{{url_for('feed_categoryindex')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_categoryindex')}}</id>
<content type="text">{{_('Books ordered by category')}}</content>
</entry>
<entry>
<title>{{_('Series list')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_seriesindex')}}" />
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_seriesindex')}}"/>
<link rel="subsection" href="{{url_for('feed_seriesindex')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_seriesindex')}}</id>
<content type="text">{{_('Books ordered by series')}}</content>
......
{
"pubdate": "{{entry.pubdate}}",
"title": "{{entry.title}}",
"format_metadata": {
{% for format in entry.data %}
"{{format.format}}": {
"mtime": "{{entry.last_modified}}",
"size": {{format.uncompressed_size}},
"path": ""
}{% if not loop.last %},{% endif %}
{% endfor %}
},
"formats": [
{% for format in entry.data %}
"{{format.format}}"{% if not loop.last %},{% endif %}
{% endfor %}
],
"series": null,
"cover": "/opds/cover/{{entry.id}}",
"languages": [
{% for lang in entry.languages %}
"{{lang.lang_code}}"{% if not loop.last %},{% endif %}
{% endfor %}
],
"comments": "{% if entry.comments|length > 0 %}{{entry.comments[0].text.replace('"', '\\"')|safe}}{% endif %}",
"tags": [
{% for tag in entry.tags %}
"{{tag.name}}"{% if not loop.last %},{% endif %}
{% endfor %}
],
"application_id": {{entry.id}},
"series_index": {% if entry.series|length > 0 %}"{{entry.series_index}}"{% else %}null{% endif %},
"last_modified": "{{entry.last_modified}}",
"author_sort": "{{entry.author_sort}}",
"uuid": "{{entry.uuid}}",
"timestamp": "{{entry.timestamp}}",
"thumbnail": "/opds/cover/{{entry.id}}",
"main_format": {
"{{entry.data[0].format|lower}}": "/download/{{entry.id}}/{{entry.data[0].format|lower}}"
},
"rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %},
"authors": [
{% for author in entry.authors %}
"{{author.name}}"{% if not loop.last %},{% endif %}
{% endfor %}
],
"other_formats": {
{% if entry.data.__len__() > 1 %}
{% for format in entry.data[1:] %}
"{{format.format|lower}}": "/download/{{entry.id}}/{{format.format|lower}}"{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %} },
"title_sort": "{{entry.sort}}"
}
\ No newline at end of file
......@@ -24,7 +24,7 @@
<script src="{{ url_for('static', filename='js/libs/jquery.min.js') }}"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/underscore.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/underscore-min.js') }}"></script>
<script src="{{ url_for('static', filename='js/intention.js') }}"></script>
<script src="{{ url_for('static', filename='js/context.js') }}"></script>
<script src="{{ url_for('static', filename='js/plugins.js') }}"></script>
......@@ -146,10 +146,11 @@
<li><a href="{{url_for('show_shelf', shelf_id=shelf.id)}}"><span class="glyphicon glyphicon-list"></span> {{shelf.name}}</a></li>
{% endfor %}
{% if not g.user.is_anonymous() %}
<li class="create-shelf"><a href="{{url_for('create_shelf')}}">{{_('Create a Shelf')}}</a></li>
<li id="nav_createshelf" class="create-shelf"><a href="{{url_for('create_shelf')}}">{{_('Create a Shelf')}}</a></li>
<li id="nav_about"><a href="{{url_for('stats')}}"><span class="glyphicon glyphicon-info-sign"></span> {{_('About')}}</a></li>
{% endif %}
{% endif %}
<li><a href="{{url_for('stats')}}"><span class="glyphicon glyphicon-info-sign"></span> {{_('About')}}</a></li>
</ul>
</nav>
</div>
......
......@@ -13,7 +13,7 @@
<label for="email">{{_('Email address')}}</label>
<input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" autocomplete="off" required>
</div>
{% if g.user and g.user.role_passwd() or g.user.role_admin()%}
{% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %}
<div class="form-group">
<label for="password">{{_('Password')}}</label>
<input type="password" class="form-control" name="password" id="password" value="" autocomplete="off">
......@@ -27,7 +27,7 @@
<label for="locale">{{_('Language')}}</label>
<select name="locale" id="locale" class="form-control">
{% for translation in translations %}
<option value="{{translation.language}}" {% if translation.language == content.locale %}selected{% endif %}>{{ translation.display_name }}</option>
<option value="{{translation}}" {% if translation|string == content.locale %}selected{% endif %}>{{ translation.display_name }}</option>
{% endfor %}
</select>
</div>
......@@ -62,11 +62,12 @@
</div>
{% if g.user and g.user.role_admin() and not profile %}
{% if not content.role_anonymous() %}
<div class="form-group">
<input type="checkbox" name="admin_role" id="admin_role" {% if content.role_admin() %}checked{% endif %}>
<label for="admin_role">{{_('Admin user')}}</label>
</div>
{% endif %}
<div class="form-group">
<input type="checkbox" name="download_role" id="download_role" {% if content.role_download() %}checked{% endif %}>
<label for="download_role">{{_('Allow Downloads')}}</label>
......@@ -79,19 +80,21 @@
<input type="checkbox" name="edit_role" id="edit_role" {% if content.role_edit() %}checked{% endif %}>
<label for="edit_role">{{_('Allow Edit')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
</div>
{% if not content.role_anonymous() %}
<div class="form-group">
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
</div>
{% endif %}
{% endif %}
{% if g.user and g.user.role_admin() and not profile and not new_user %}
<div class="checkbox">
<label>
<input type="checkbox" name="delete"> {{_('Delete this user')}}
</label>
</div>
{% if g.user and g.user.role_admin() and not profile and not new_user and not content.role_anonymous() %}
<div class="checkbox">
<label>
<input type="checkbox" name="delete"> {{_('Delete this user')}}
</label>
</div>
{% endif %}
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not profile %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
{% endif %}
......
......@@ -5,9 +5,12 @@ from sqlalchemy import *
from sqlalchemy import exc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
from flask_login import AnonymousUserMixin
import os
import config
import traceback
from werkzeug.security import generate_password_hash
from flask_babel import gettext as _
dbpath = os.path.join(config.APP_DB_ROOT, "app.db")
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
......@@ -19,28 +22,11 @@ ROLE_DOWNLOAD = 2
ROLE_UPLOAD = 4
ROLE_EDIT = 8
ROLE_PASSWD = 16
ROLE_ANONYMOUS = 32
DEFAULT_PASS = "admin123"
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
nickname = Column(String(64), unique=True)
email = Column(String(120), unique=True, default="")
role = Column(SmallInteger, default=ROLE_USER)
password = Column(String)
kindle_mail = Column(String(120), default="")
shelf = relationship('Shelf', backref='user', lazy='dynamic')
downloads = relationship('Downloads', backref='user', lazy='dynamic')
locale = Column(String(2), default="en")
random_books = Column(Integer, default=1)
language_books = Column(Integer, default=1)
series_books = Column(Integer, default=1)
category_books = Column(Integer, default=1)
hot_books = Column(Integer, default=1)
default_language = Column(String(3), default="all")
class UserBase():
def is_authenticated(self):
return True
......@@ -74,6 +60,12 @@ class User(Base):
else:
return False
def role_anonymous(self):
if self.role is not None:
return True if self.role & ROLE_ANONYMOUS == ROLE_ANONYMOUS else False
else:
return False
def is_active(self):
return True
......@@ -105,6 +97,53 @@ class User(Base):
return '<User %r>' % self.nickname
class User(UserBase,Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
nickname = Column(String(64), unique=True)
email = Column(String(120), unique=True, default="")
role = Column(SmallInteger, default=ROLE_USER)
password = Column(String)
kindle_mail = Column(String(120), default="")
shelf = relationship('Shelf', backref='user', lazy='dynamic')
downloads = relationship('Downloads', backref='user', lazy='dynamic')
locale = Column(String(2), default="en")
random_books = Column(Integer, default=1)
language_books = Column(Integer, default=1)
series_books = Column(Integer, default=1)
category_books = Column(Integer, default=1)
hot_books = Column(Integer, default=1)
default_language = Column(String(3), default="all")
class Anonymous(AnonymousUserMixin,UserBase):
def __init__(self):
self.loadSettings()
def loadSettings(self):
data=session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first()
self.nickname = data.nickname
self.role = data.role
self.random_books = data.random_books
self.default_language = data.default_language
self.language_books = data.language_books
self.series_books = data.series_books
self.category_books = data.category_books
self.hot_books = data.hot_books
self.default_language = data.default_language
self.locale = data.locale
def role_admin(self):
return False
def is_active(self):
return False
def is_anonymous(self):
return config.ANON_BROWSE
class Shelf(Base):
__tablename__ = 'shelf'
......@@ -155,6 +194,8 @@ class Settings(Base):
def migrate_Database():
if session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first() is None:
create_anonymous_user()
try:
session.query(exists().where(User.random_books)).scalar()
session.commit()
......@@ -213,6 +254,20 @@ def get_mail_settings():
return data
def create_anonymous_user():
user = User()
user.nickname = _("Guest")
user.email='no@email'
user.role = ROLE_ANONYMOUS
user.password = generate_password_hash('1')
session.add(user)
try:
session.commit()
except:
session.rollback()
pass
def create_admin_user():
user = User()
......@@ -236,6 +291,7 @@ if not os.path.exists(dbpath):
Base.metadata.create_all(engine)
create_default_config()
create_admin_user()
create_anonymous_user()
except Exception:
pass
else:
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment