Merge branch 'master' of git.xpub.nl:/var/www/git.xpub.nl/repos/xpub-lib

master
Jocavdh 7 years ago
commit a0558a6115

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored

@ -3,6 +3,7 @@ __pycache__/
*~ *~
app/uploads/** app/uploads/**
!app/uploads/cover !app/uploads/cover
/cover/**
app/mydatabase.db app/mydatabase.db
pyrqlite/ pyrqlite/
whoosh/ whoosh/

@ -15,7 +15,7 @@ registry.register("rqlite.pyrqlite", "sqlalchemy_rqlite.pyrqlite", "dialect")
basedir = os.path.abspath(os.path.dirname(__file__)) basedir = os.path.abspath(os.path.dirname(__file__))
UPLOAD_FOLDER = os.path.join(basedir, 'uploads') UPLOAD_FOLDER = os.path.join(basedir, 'uploads')
UPLOAD_FOLDER_COVER = os.path.join(basedir, 'uploads/cover') UPLOAD_FOLDER_COVER = os.path.join(basedir, 'cover')
#ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) #ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
load_dotenv(find_dotenv()) load_dotenv(find_dotenv())
app = Flask(__name__) app = Flask(__name__)
@ -29,7 +29,7 @@ app.config['PORT'] = 80
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'mydatabase.db') #app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'mydatabase.db')
db = SQLAlchemy(app) db = SQLAlchemy(app)
light = not os.path.isdir(UPLOAD_FOLDER)
DOMAIN = environ.get('DOMAIN') DOMAIN = environ.get('DOMAIN')
socketio = SocketIO(app) socketio = SocketIO(app)

@ -37,8 +37,8 @@ def get_cover(file_path, filename):
# Convert each page to a png image. # Convert each page to a png image.
for page in pages: for page in pages:
big_filename = "app/uploads/cover/"+page["filename"] + "_cover.png" big_filename = "app/cover/"+page["filename"] + "_cover.png"
small_filename = "app/uploads/cover/"+page["filename"] + "cover_small" + ".png" small_filename = "app/cover/"+page["filename"] + "cover_small" + ".png"
img = pdf_page_to_png(src_pdf, pagenum = page["pagenum"], resolution = 200) img = pdf_page_to_png(src_pdf, pagenum = page["pagenum"], resolution = 200)
img.save(filename = big_filename) img.save(filename = big_filename)

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -25,7 +25,6 @@ class UploadForm(FlaskForm):
sameness = DecimalRangeField('sameness', default=0) sameness = DecimalRangeField('sameness', default=0)
diversity = DecimalRangeField('diversity', default=0) diversity = DecimalRangeField('diversity', default=0)
gender = DecimalRangeField('gender', default=50) gender = DecimalRangeField('gender', default=50)
time = StringField('time', [validators.Length(max=5)],default=None)
choices = [('Student', 'Student'), choices = [('Student', 'Student'),
('Librarian', 'Librarian'), ('Librarian', 'Librarian'),
('Pirate', 'Pirate'), ('Pirate', 'Pirate'),
@ -43,6 +42,17 @@ class EditForm(FlaskForm):
year_published = StringField('year published', [validators.Length(max=4)],default=None) year_published = StringField('year published', [validators.Length(max=4)],default=None)
file = FileField() file = FileField()
message = StringField('message') message = StringField('message')
sameness = DecimalRangeField('sameness', default=0)
diversity = DecimalRangeField('diversity', default=0)
gender = DecimalRangeField('gender', default=50)
choices = [('Student', 'Student'),
('Librarian', 'Librarian'),
('Pirate', 'Pirate'),
('Teacher', 'Teacher'),
('Institution', 'Institution'),
('All of the above', 'All of the above'),
('None of the above', 'None of the above')]
who = SelectField('', choices=choices, default='Student')
class ChatForm(FlaskForm): class ChatForm(FlaskForm):
message = StringField('message', validators=[InputRequired()]) message = StringField('message', validators=[InputRequired()])
@ -66,7 +76,8 @@ class SearchForm(FlaskForm):
('Title', 'Title'), ('Title', 'Title'),
('Author', 'Author'), ('Author', 'Author'),
('Category', 'Category'), ('Category', 'Category'),
('Stack', 'Stack')] ('Stack', 'Stack'),
('Outliers', 'Outliers')]
select = SelectField('', choices=choices, default='All') select = SelectField('', choices=choices, default='All')
search = StringField('', validators=[InputRequired()]) search = StringField('', validators=[InputRequired()])
grid = SubmitField('Grid') grid = SubmitField('Grid')

@ -46,10 +46,9 @@ class Book(db.Model):
diversity = db.Column(db.Numeric()) diversity = db.Column(db.Numeric())
gender = db.Column(db.Numeric()) gender = db.Column(db.Numeric())
who = db.Column(db.String(255)) who = db.Column(db.String(255))
time = db.Column(db.Numeric())
def __init__(self, title, file, cover, fileformat, category, year_published, message, sameness, diversity, gender, who, time): def __init__(self, title, file, cover, fileformat, category, year_published, message, sameness, diversity, gender, who):
self.title = title self.title = title
self.file = file self.file = file
self.cover = cover self.cover = cover
@ -64,7 +63,6 @@ class Book(db.Model):
self.diversity = diversity self.diversity = diversity
self.gender = gender self.gender = gender
self.who = who self.who = who
self.time = time
def __repr__(self): def __repr__(self):

@ -5,14 +5,14 @@ font-family: "Archivo Narrow";
} }
p{ p{
font-size: 18px; font-size: 20px;
} }
a{ a{
text-decoration: none; text-decoration: underline;
color: black; color: black;
} }
a:hover{ a:hover{
@ -68,7 +68,7 @@ padding: 0px 10px;
} }
.about{ .about{
font-size: 16px; font-size: 18px;
} }
.library_table{ .library_table{
@ -106,7 +106,7 @@ background-color: #E8E8E8!important;
} }
.library_table .author_col{ .library_table .author_col{
font-size: 15px; font-size: 18px;
} }
.library_table li{ .library_table li{
@ -121,6 +121,10 @@ display: inline-block;
font-size: 10px; font-size: 10px;
} }
#ascii {
text-align: center;
}
.library_table tr:nth-child(even){ .library_table tr:nth-child(even){
background-color: #fafafa; background-color: #fafafa;
@ -129,7 +133,6 @@ background-color: #fafafa;
#title_xppl{ #title_xppl{
font-size: 46px; font-size: 46px;
cursor: pointer; cursor: pointer;
} }
.header input{ .header input{
@ -142,7 +145,7 @@ font-weight: bold;
.author input{ .author input{
height:20px; height:20px;
width: 500px; width: 500px;
font-size: 16px; font-size: 18px;
} }
.search input{ .search input{
@ -242,7 +245,7 @@ div.marquee > div.marquee-text {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
right: 0; right: 0;
width: 30%; width: 25%;
height: 100%; height: 100%;
} }
@ -254,7 +257,7 @@ div.marquee > div.marquee-text {
padding: 10px; padding: 10px;
margin: 0px; margin: 0px;
height: 100%; height: 100%;
background-color: #b4b9be; /*background-color: #b4b9be;*/
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
color: white; color: white;
@ -265,6 +268,43 @@ div.marquee > div.marquee-text {
z-index: -100000; z-index: -100000;
} }
.messageback1{
position: absolute;
bottom: 40px;
display: block;
width:100%;
padding: 0px;
margin: 0px;
height: 100%;
background-color: #b4b9be;
overflow-y: scroll;
overflow-x: hidden;
color: white;
word-wrap:break-word;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
z-index: -100000;}
.messageback2{
position: absolute;
bottom: 40px;
display: block;
width:100%;
padding: 0px;
margin: 0px;
height: 100%;
background-color: #b4b9be;
overflow-y: scroll;
overflow-x: hidden;
color: white;
word-wrap:break-word;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
z-index: -100000;}
.new-message { .new-message {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@ -273,6 +313,7 @@ width:100%;
margin:0; margin:0;
padding:0; padding:0;
z-index: 100000; z-index: 100000;
opacity: 1!important;
} }
.control{ .control{
display: block; display: block;
@ -353,7 +394,7 @@ box-sizing: border-box;
justify-items: center; justify-items: center;
} }
@media screen and (max-width: 900px) { @media screen and (max-width: 1000px) {
.grid{ .grid{
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr;
@ -362,11 +403,13 @@ box-sizing: border-box;
justify-items: center; justify-items: center;
} }
} }
@media screen and (max-width: 400px) {
@media screen and (max-width: 600px) {
.grid{ .grid{
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr 1fr 1fr;
align-items: center; grid-gap: 2px;
align-items: top;
justify-items: center; justify-items: center;
} }
} }
@ -377,6 +420,7 @@ box-sizing: border-box;
align-items: center; align-items: center;
justify-items: center; justify-items: center;
} }
.gridbox:hover{ .gridbox:hover{
opacity: 0.5; opacity: 0.5;
} }

@ -63,13 +63,34 @@ function generateTitle(elem) {
} }
$(function() { $(function() {
$("#tabs").tabs().addClass("ui-tabs-vertical ui-helper-clearfix"); var index = 'ui-tabs-active';
// Define friendly data store name
var dataStore = window.sessionStorage;
var oldIndex = 0;
// Start magic!
try {
// getter: Fetch previous value
oldIndex = dataStore.getItem(index);
} catch(e) {}
$("#tabs").tabs({
active: oldIndex,
activate: function(event, ui) {
// Get future value
var newIndex = ui.newTab.parent().children().index(ui.newTab);
// Set future value
try {
dataStore.setItem( index, newIndex );
} catch(e) {}
}
});
$("#tabs").addClass("ui-tabs-vertical ui-helper-clearfix");
$("#tabs li").removeClass("ui-corner-top").addClass("ui-corner-left"); $("#tabs li").removeClass("ui-corner-top").addClass("ui-corner-left");
}); });
$(".no_cover").each(function() { $(".no_cover").each(function() {
var string = $(this).attr('id') var string = $(this).attr('id')
var randomColor = colorHash(string).rgb var randomColor = colorHash(string).rgb

File diff suppressed because one or more lines are too long

@ -0,0 +1,486 @@
/**
* jQuery.marquee - scrolling text like old marquee element
* @author Aamir Afridi - aamirafridi(at)gmail(dot)com / http://aamirafridi.com/jquery/jquery-marquee-plugin
*/;
(function($) {
$.fn.marquee = function(options) {
return this.each(function() {
// Extend the options if any provided
var o = $.extend({}, $.fn.marquee.defaults, options),
$this = $(this),
$marqueeWrapper, containerWidth, animationCss, verticalDir, elWidth,
loopCount = 3,
playState = 'animation-play-state',
css3AnimationIsSupported = false,
// Private methods
_prefixedEvent = function(element, type, callback) {
var pfx = ["webkit", "moz", "MS", "o", ""];
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p] + type, callback, false);
}
},
_objToString = function(obj) {
var tabjson = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
tabjson.push(p + ':' + obj[p]);
}
}
tabjson.push();
return '{' + tabjson.join(',') + '}';
},
_startAnimationWithDelay = function() {
$this.timer = setTimeout(animate, o.delayBeforeStart);
},
// Public methods
methods = {
pause: function() {
if (css3AnimationIsSupported && o.allowCss3Support) {
$marqueeWrapper.css(playState, 'paused');
} else {
// pause using pause plugin
if ($.fn.pause) {
$marqueeWrapper.pause();
}
}
// save the status
$this.data('runningStatus', 'paused');
// fire event
$this.trigger('paused');
},
resume: function() {
// resume using css3
if (css3AnimationIsSupported && o.allowCss3Support) {
$marqueeWrapper.css(playState, 'running');
} else {
// resume using pause plugin
if ($.fn.resume) {
$marqueeWrapper.resume();
}
}
// save the status
$this.data('runningStatus', 'resumed');
// fire event
$this.trigger('resumed');
},
toggle: function() {
methods[$this.data('runningStatus') == 'resumed' ? 'pause' : 'resume']();
},
destroy: function() {
// Clear timer
clearTimeout($this.timer);
// Unbind all events
$this.find("*").addBack().unbind();
// Just unwrap the elements that has been added using this plugin
$this.html($this.find('.js-marquee:first').html());
}
};
// Check for methods
if (typeof options === 'string') {
if ($.isFunction(methods[options])) {
// Following two IF statements to support public methods
if (!$marqueeWrapper) {
$marqueeWrapper = $this.find('.js-marquee-wrapper');
}
if ($this.data('css3AnimationIsSupported') === true) {
css3AnimationIsSupported = true;
}
methods[options]();
}
return;
}
/* Check if element has data attributes. They have top priority
For details https://twitter.com/aamirafridi/status/403848044069679104 - Can't find a better solution :/
jQuery 1.3.2 doesn't support $.data().KEY hence writting the following */
var dataAttributes = {},
attr;
$.each(o, function(key, value) {
// Check if element has this data attribute
attr = $this.attr('data-' + key);
if (typeof attr !== 'undefined') {
// Now check if value is boolean or not
switch (attr) {
case 'true':
attr = true;
break;
case 'false':
attr = false;
break;
}
o[key] = attr;
}
});
// Reintroduce speed as an option. It calculates duration as a factor of the container width
// measured in pixels per second.
if (o.speed) {
o.duration = parseInt($this.width(), 10) / o.speed * 1000;
}
// Shortcut to see if direction is upward or downward
verticalDir = o.direction == 'up' || o.direction == 'down';
// no gap if not duplicated
o.gap = o.duplicated ? parseInt(o.gap) : 0;
// wrap inner content into a div
$this.wrapInner('<div class="js-marquee"></div>');
// Make copy of the element
var $el = $this.find('.js-marquee').css({
'margin-right': o.gap,
'float': 'left'
});
if (o.duplicated) {
$el.clone(true).appendTo($this);
}
// wrap both inner elements into one div
$this.wrapInner('<div style="width:100000px" class="js-marquee-wrapper"></div>');
// Save the reference of the wrapper
$marqueeWrapper = $this.find('.js-marquee-wrapper');
// If direction is up or down, get the height of main element
if (verticalDir) {
var containerHeight = $this.height();
$marqueeWrapper.removeAttr('style');
$this.height(containerHeight);
// Change the CSS for js-marquee element
$this.find('.js-marquee').css({
'float': 'none',
'margin-bottom': o.gap,
'margin-right': 0
});
// Remove bottom margin from 2nd element if duplicated
if (o.duplicated) $this.find('.js-marquee:last').css({
'margin-bottom': 0
});
var elHeight = $this.find('.js-marquee:first').height() + o.gap;
// adjust the animation duration according to the text length
if (o.startVisible && !o.duplicated) {
// Compute the complete animation duration and save it for later reference
// formula is to: (Height of the text node + height of the main container / Height of the main container) * duration;
o._completeDuration = ((parseInt(elHeight, 10) + parseInt(containerHeight, 10)) / parseInt(containerHeight, 10)) * o.duration;
// formula is to: (Height of the text node / height of the main container) * duration
o.duration = (parseInt(elHeight, 10) / parseInt(containerHeight, 10)) * o.duration;
} else {
// formula is to: (Height of the text node + height of the main container / Height of the main container) * duration;
o.duration = ((parseInt(elHeight, 10) + parseInt(containerHeight, 10)) / parseInt(containerHeight, 10)) * o.duration;
}
} else {
// Save the width of the each element so we can use it in animation
elWidth = $this.find('.js-marquee:first').width() + o.gap;
// container width
containerWidth = $this.width();
// adjust the animation duration according to the text length
if (o.startVisible && !o.duplicated) {
// Compute the complete animation duration and save it for later reference
// formula is to: (Width of the text node + width of the main container / Width of the main container) * duration;
o._completeDuration = ((parseInt(elWidth, 10) + parseInt(containerWidth, 10)) / parseInt(containerWidth, 10)) * o.duration;
// (Width of the text node / width of the main container) * duration
o.duration = (parseInt(elWidth, 10) / parseInt(containerWidth, 10)) * o.duration;
} else {
// formula is to: (Width of the text node + width of the main container / Width of the main container) * duration;
o.duration = ((parseInt(elWidth, 10) + parseInt(containerWidth, 10)) / parseInt(containerWidth, 10)) * o.duration;
}
}
// if duplicated then reduce the duration
if (o.duplicated) {
o.duration = o.duration / 2;
}
if (o.allowCss3Support) {
var
elm = document.body || document.createElement('div'),
animationName = 'marqueeAnimation-' + Math.floor(Math.random() * 10000000),
domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
animationString = 'animation',
animationCss3Str = '',
keyframeString = '';
// Check css3 support
if (elm.style.animation !== undefined) {
keyframeString = '@keyframes ' + animationName + ' ';
css3AnimationIsSupported = true;
}
if (css3AnimationIsSupported === false) {
for (var i = 0; i < domPrefixes.length; i++) {
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
var prefix = '-' + domPrefixes[i].toLowerCase() + '-';
animationString = prefix + animationString;
playState = prefix + playState;
keyframeString = '@' + prefix + 'keyframes ' + animationName + ' ';
css3AnimationIsSupported = true;
break;
}
}
}
if (css3AnimationIsSupported) {
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's infinite ' + o.css3easing;
$this.data('css3AnimationIsSupported', true);
}
}
var _rePositionVertically = function() {
$marqueeWrapper.css('transform', 'translateY(' + (o.direction == 'up' ? containerHeight + 'px' : '-' + elHeight + 'px') + ')');
},
_rePositionHorizontally = function() {
$marqueeWrapper.css('transform', 'translateX(' + (o.direction == 'left' ? containerWidth + 'px' : '-' + elWidth + 'px') + ')');
};
// if duplicated option is set to true than position the wrapper
if (o.duplicated) {
if (verticalDir) {
if (o.startVisible) {
$marqueeWrapper.css('transform', 'translateY(0)');
} else {
$marqueeWrapper.css('transform', 'translateY(' + (o.direction == 'up' ? containerHeight + 'px' : '-' + ((elHeight * 2) - o.gap) + 'px') + ')');
}
} else {
if (o.startVisible) {
$marqueeWrapper.css('transform', 'translateX(0)');
} else {
$marqueeWrapper.css('transform', 'translateX(' + (o.direction == 'left' ? containerWidth + 'px' : '-' + ((elWidth * 2) - o.gap) + 'px') + ')');
}
}
// If the text starts out visible we can skip the two initial loops
if (!o.startVisible) {
loopCount = 1;
}
} else if (o.startVisible) {
// We only have two different loops if marquee is duplicated and starts visible
loopCount = 2;
} else {
if (verticalDir) {
_rePositionVertically();
} else {
_rePositionHorizontally();
}
}
// Animate recursive method
var animate = function() {
if (o.duplicated) {
// When duplicated, the first loop will be scroll longer so double the duration
if (loopCount === 1) {
o._originalDuration = o.duration;
if (verticalDir) {
o.duration = o.direction == 'up' ? o.duration + (containerHeight / ((elHeight) / o.duration)) : o.duration * 2;
} else {
o.duration = o.direction == 'left' ? o.duration + (containerWidth / ((elWidth) / o.duration)) : o.duration * 2;
}
// Adjust the css3 animation as well
if (animationCss3Str) {
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing;
}
loopCount++;
}
// On 2nd loop things back to normal, normal duration for the rest of animations
else if (loopCount === 2) {
o.duration = o._originalDuration;
// Adjust the css3 animation as well
if (animationCss3Str) {
animationName = animationName + '0';
keyframeString = $.trim(keyframeString) + '0 ';
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing;
}
loopCount++;
}
}
if (verticalDir) {
if (o.duplicated) {
// Adjust the starting point of animation only when first loops finishes
if (loopCount > 2) {
$marqueeWrapper.css('transform', 'translateY(' + (o.direction == 'up' ? 0 : '-' + elHeight + 'px') + ')');
}
animationCss = {
'transform': 'translateY(' + (o.direction == 'up' ? '-' + elHeight + 'px' : 0) + ')'
};
} else if (o.startVisible) {
// This loop moves the marquee out of the container
if (loopCount === 2) {
// Adjust the css3 animation as well
if (animationCss3Str) {
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing;
}
animationCss = {
'transform': 'translateY(' + (o.direction == 'up' ? '-' + elHeight + 'px' : containerHeight + 'px') + ')'
};
loopCount++;
} else if (loopCount === 3) {
// Set the duration for the animation that will run forever
o.duration = o._completeDuration;
// Adjust the css3 animation as well
if (animationCss3Str) {
animationName = animationName + '0';
keyframeString = $.trim(keyframeString) + '0 ';
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing;
}
_rePositionVertically();
}
} else {
_rePositionVertically();
animationCss = {
'transform': 'translateY(' + (o.direction == 'up' ? '-' + ($marqueeWrapper.height()) + 'px' : containerHeight + 'px') + ')'
};
}
} else {
if (o.duplicated) {
// Adjust the starting point of animation only when first loops finishes
if (loopCount > 2) {
$marqueeWrapper.css('transform', 'translateX(' + (o.direction == 'left' ? 0 : '-' + elWidth + 'px') + ')');
}
animationCss = {
'transform': 'translateX(' + (o.direction == 'left' ? '-' + elWidth + 'px' : 0) + ')'
};
} else if (o.startVisible) {
// This loop moves the marquee out of the container
if (loopCount === 2) {
// Adjust the css3 animation as well
if (animationCss3Str) {
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's ' + o.delayBeforeStart / 1000 + 's ' + o.css3easing;
}
animationCss = {
'transform': 'translateX(' + (o.direction == 'left' ? '-' + elWidth + 'px' : containerWidth + 'px') + ')'
};
loopCount++;
} else if (loopCount === 3) {
// Set the duration for the animation that will run forever
o.duration = o._completeDuration;
// Adjust the css3 animation as well
if (animationCss3Str) {
animationName = animationName + '0';
keyframeString = $.trim(keyframeString) + '0 ';
animationCss3Str = animationName + ' ' + o.duration / 1000 + 's 0s infinite ' + o.css3easing;
}
_rePositionHorizontally();
}
} else {
_rePositionHorizontally();
animationCss = {
'transform': 'translateX(' + (o.direction == 'left' ? '-' + elWidth + 'px' : containerWidth + 'px') + ')'
};
}
}
// fire event
$this.trigger('beforeStarting');
// If css3 support is available than do it with css3, otherwise use jQuery as fallback
if (css3AnimationIsSupported) {
// Add css3 animation to the element
$marqueeWrapper.css(animationString, animationCss3Str);
var keyframeCss = keyframeString + ' { 100% ' + _objToString(animationCss) + '}',
$styles = $marqueeWrapper.find('style');
// Now add the keyframe animation to the marquee element
if ($styles.length !== 0) {
// Bug fixed for jQuery 1.3.x - Instead of using .last(), use following
$styles.filter(":last").html(keyframeCss);
} else {
$('head').append('<style>' + keyframeCss + '</style>');
}
// Animation iteration event
_prefixedEvent($marqueeWrapper[0], "AnimationIteration", function() {
$this.trigger('finished');
});
// Animation stopped
_prefixedEvent($marqueeWrapper[0], "AnimationEnd", function() {
animate();
$this.trigger('finished');
});
} else {
// Start animating
$marqueeWrapper.animate(animationCss, o.duration, o.easing, function() {
// fire event
$this.trigger('finished');
// animate again
if (o.pauseOnCycle) {
_startAnimationWithDelay();
} else {
animate();
}
});
}
// save the status
$this.data('runningStatus', 'resumed');
};
// bind pause and resume events
$this.bind('pause', methods.pause);
$this.bind('resume', methods.resume);
if (o.pauseOnHover) {
$this.bind('mouseenter', methods.pause);
$this.bind('mouseleave', methods.resume);
}
// If css3 animation is supported than call animate method at once
if (css3AnimationIsSupported && o.allowCss3Support) {
animate();
} else {
// Starts the recursive method
_startAnimationWithDelay();
}
});
}; // End of Plugin
// Public: plugin defaults options
$.fn.marquee.defaults = {
// If you wish to always animate using jQuery
allowCss3Support: true,
// works when allowCss3Support is set to true - for full list see http://www.w3.org/TR/2013/WD-css3-transitions-20131119/#transition-timing-function
css3easing: 'linear',
// requires jQuery easing plugin. Default is 'linear'
easing: 'linear',
// pause time before the next animation turn in milliseconds
delayBeforeStart: 1000,
// 'left', 'right', 'up' or 'down'
direction: 'left',
// true or false - should the marquee be duplicated to show an effect of continues flow
duplicated: false,
// duration in milliseconds of the marquee in milliseconds
duration: 5000,
// gap in pixels between the tickers
gap: 20,
// on cycle pause the marquee
pauseOnCycle: false,
// on hover pause the marquee - using jQuery plugin https://github.com/tobia/Pause
pauseOnHover: false,
// the marquee is visible initially positioned next to the border towards it will be moving
startVisible: false
};
})(jQuery);

@ -0,0 +1,16 @@
/**
* jQuery.marquee - scrolling text like old marquee element
* @author Aamir Afridi - aamirafridi(at)gmail(dot)com / http://aamirafridi.com/jquery/jquery-marquee-plugin
*/
(function(f){f.fn.marquee=function(x){return this.each(function(){var a=f.extend({},f.fn.marquee.defaults,x),b=f(this),c,t,e=3,y="animation-play-state",p=!1,E=function(a,b,c){for(var e=["webkit","moz","MS","o",""],d=0;d<e.length;d++)e[d]||(b=b.toLowerCase()),a.addEventListener(e[d]+b,c,!1)},F=function(a){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(c+":"+a[c]);b.push();return"{"+b.join(",")+"}"},l={pause:function(){p&&a.allowCss3Support?c.css(y,"paused"):f.fn.pause&&c.pause();b.data("runningStatus",
"paused");b.trigger("paused")},resume:function(){p&&a.allowCss3Support?c.css(y,"running"):f.fn.resume&&c.resume();b.data("runningStatus","resumed");b.trigger("resumed")},toggle:function(){l["resumed"==b.data("runningStatus")?"pause":"resume"]()},destroy:function(){clearTimeout(b.timer);b.find("*").addBack().unbind();b.html(b.find(".js-marquee:first").html())}};if("string"===typeof x)f.isFunction(l[x])&&(c||(c=b.find(".js-marquee-wrapper")),!0===b.data("css3AnimationIsSupported")&&(p=!0),l[x]());else{var u;
f.each(a,function(c,d){u=b.attr("data-"+c);if("undefined"!==typeof u){switch(u){case "true":u=!0;break;case "false":u=!1}a[c]=u}});a.speed&&(a.duration=parseInt(b.width(),10)/a.speed*1E3);var v="up"==a.direction||"down"==a.direction;a.gap=a.duplicated?parseInt(a.gap):0;b.wrapInner('<div class="js-marquee"></div>');var h=b.find(".js-marquee").css({"margin-right":a.gap,"float":"left"});a.duplicated&&h.clone(!0).appendTo(b);b.wrapInner('<div style="width:100000px" class="js-marquee-wrapper"></div>');
c=b.find(".js-marquee-wrapper");if(v){var k=b.height();c.removeAttr("style");b.height(k);b.find(".js-marquee").css({"float":"none","margin-bottom":a.gap,"margin-right":0});a.duplicated&&b.find(".js-marquee:last").css({"margin-bottom":0});var q=b.find(".js-marquee:first").height()+a.gap;a.startVisible&&!a.duplicated?(a._completeDuration=(parseInt(q,10)+parseInt(k,10))/parseInt(k,10)*a.duration,a.duration*=parseInt(q,10)/parseInt(k,10)):a.duration*=(parseInt(q,10)+parseInt(k,10))/parseInt(k,10)}else{var m=
b.find(".js-marquee:first").width()+a.gap;var n=b.width();a.startVisible&&!a.duplicated?(a._completeDuration=(parseInt(m,10)+parseInt(n,10))/parseInt(n,10)*a.duration,a.duration*=parseInt(m,10)/parseInt(n,10)):a.duration*=(parseInt(m,10)+parseInt(n,10))/parseInt(n,10)}a.duplicated&&(a.duration/=2);if(a.allowCss3Support){h=document.body||document.createElement("div");var g="marqueeAnimation-"+Math.floor(1E7*Math.random()),A=["Webkit","Moz","O","ms","Khtml"],B="animation",d="",r="";h.style.animation&&
(r="@keyframes "+g+" ",p=!0);if(!1===p)for(var z=0;z<A.length;z++)if(void 0!==h.style[A[z]+"AnimationName"]){h="-"+A[z].toLowerCase()+"-";B=h+B;y=h+y;r="@"+h+"keyframes "+g+" ";p=!0;break}p&&(d=g+" "+a.duration/1E3+"s "+a.delayBeforeStart/1E3+"s infinite "+a.css3easing,b.data("css3AnimationIsSupported",!0))}var C=function(){c.css("transform","translateY("+("up"==a.direction?k+"px":"-"+q+"px")+")")},D=function(){c.css("transform","translateX("+("left"==a.direction?n+"px":"-"+m+"px")+")")};a.duplicated?
(v?a.startVisible?c.css("transform","translateY(0)"):c.css("transform","translateY("+("up"==a.direction?k+"px":"-"+(2*q-a.gap)+"px")+")"):a.startVisible?c.css("transform","translateX(0)"):c.css("transform","translateX("+("left"==a.direction?n+"px":"-"+(2*m-a.gap)+"px")+")"),a.startVisible||(e=1)):a.startVisible?e=2:v?C():D();var w=function(){a.duplicated&&(1===e?(a._originalDuration=a.duration,a.duration=v?"up"==a.direction?a.duration+k/(q/a.duration):2*a.duration:"left"==a.direction?a.duration+n/
(m/a.duration):2*a.duration,d&&(d=g+" "+a.duration/1E3+"s "+a.delayBeforeStart/1E3+"s "+a.css3easing),e++):2===e&&(a.duration=a._originalDuration,d&&(g+="0",r=f.trim(r)+"0 ",d=g+" "+a.duration/1E3+"s 0s infinite "+a.css3easing),e++));v?a.duplicated?(2<e&&c.css("transform","translateY("+("up"==a.direction?0:"-"+q+"px")+")"),t={transform:"translateY("+("up"==a.direction?"-"+q+"px":0)+")"}):a.startVisible?2===e?(d&&(d=g+" "+a.duration/1E3+"s "+a.delayBeforeStart/1E3+"s "+a.css3easing),t={transform:"translateY("+
("up"==a.direction?"-"+q+"px":k+"px")+")"},e++):3===e&&(a.duration=a._completeDuration,d&&(g+="0",r=f.trim(r)+"0 ",d=g+" "+a.duration/1E3+"s 0s infinite "+a.css3easing),C()):(C(),t={transform:"translateY("+("up"==a.direction?"-"+c.height()+"px":k+"px")+")"}):a.duplicated?(2<e&&c.css("transform","translateX("+("left"==a.direction?0:"-"+m+"px")+")"),t={transform:"translateX("+("left"==a.direction?"-"+m+"px":0)+")"}):a.startVisible?2===e?(d&&(d=g+" "+a.duration/1E3+"s "+a.delayBeforeStart/1E3+"s "+a.css3easing),
t={transform:"translateX("+("left"==a.direction?"-"+m+"px":n+"px")+")"},e++):3===e&&(a.duration=a._completeDuration,d&&(g+="0",r=f.trim(r)+"0 ",d=g+" "+a.duration/1E3+"s 0s infinite "+a.css3easing),D()):(D(),t={transform:"translateX("+("left"==a.direction?"-"+m+"px":n+"px")+")"});b.trigger("beforeStarting");if(p){c.css(B,d);var h=r+" { 100% "+F(t)+"}",l=c.find("style");0!==l.length?l.filter(":last").html(h):f("head").append("<style>"+h+"</style>");E(c[0],"AnimationIteration",function(){b.trigger("finished")});
E(c[0],"AnimationEnd",function(){w();b.trigger("finished")})}else c.animate(t,a.duration,a.easing,function(){b.trigger("finished");a.pauseOnCycle?b.timer=setTimeout(w,a.delayBeforeStart):w()});b.data("runningStatus","resumed")};b.bind("pause",l.pause);b.bind("resume",l.resume);a.pauseOnHover&&(b.bind("mouseenter",l.pause),b.bind("mouseleave",l.resume));p&&a.allowCss3Support?w():b.timer=setTimeout(w,a.delayBeforeStart)}})};f.fn.marquee.defaults={allowCss3Support:!0,css3easing:"linear",easing:"linear",
delayBeforeStart:1E3,direction:"left",duplicated:!1,duration:5E3,gap:20,pauseOnCycle:!1,pauseOnHover:!1,startVisible:!1}})(jQuery);

@ -2,29 +2,27 @@
{% block main %} {% block main %}
<h1 class="page-header">About</h1> <h1 class="page-header">About</h1>
<div style="width: 900px;">
<p class='about'> <p class='about'>
XPPL is a project aimed at people who are studying the field of media culture, or as we like to call them: knowledge comrades. XPPL is a project aimed at people who are studying the field of media culture, or as we like to call them: knowledge comrades.
<br> <br>
<br> <br>
This digital library gathers all the books and articles floating around on the shelves of the Piet Zwart Institute, and our hard drives and memory sticks, so that they can be shared, annotated and grouped together into stacks... This digital library gathers all the books and articles floating around on the shelves of the Piet Zwart Institute, and our hard drives and memory sticks, so that they can be shared, annotated and grouped together into stacks... Its web interface hosts a curated catalogue of books and articles, and its distributed architecture provides instances for uploading and downloading.
<br> <br>
<br> <br>
Its web interface hosts a curated catalogue of books and articles, and its distributed architecture provides instances for uploading and downloading. It starts at XPUB, but can go anywhere we want it to.
<br> <br>
<br> <br>
It starts at XPUB, but can go anywhere we want it to.</p> Are you interested in how this library works? Have a look at the source code in <a href 'https://git.xpub.nl/xpub-lib/log.html'> our git. </a>
</p>
<h2> What's the deal with the stacks? </h2> <h2> What's the deal with the stacks? </h2>
<p class='about'> <p class='about'>
A stack is a number of books that are read at a certain point in time, alternating between them. They usually have a topic in common, or follow a certain study path that can bring you to a point of knowledge. Rather than a bookshelf, where books are lined up and often forgotten, the stack on your table/nightstand/toilet consists of books prone to be opened and reopened at any time. A stack is a number of books that are read at a certain point in time, alternating between them. They usually have a topic in common, or follow a certain study path that can bring you to a point of knowledge. Rather than a bookshelf, where books are lined up and often forgotten, the stack on your table/nightstand/toilet consists of books prone to be opened and reopened at any time.
</p> </p>
<h2>Who's behind this?</h2> <h2>Who's behind this?</h2>
<p class='about'> <p class='about'>
We're Angeliki, Alex, Alice, Joca, Natasha and Zalán, helped and supported by Femke, Aymeric, Michael, Steve, Andre, Leslie and many more. We're Angeliki, Alex, Alice, Joca, Natasha and Zalán, helped and supported by Femke, Aymeric, Michael, Steve, Andre, Leslie and many more. XPUB is a study path within the Piet Zwart Institute masters program.
<br>
<br>
XPUB is a study path within the Piet Zwart Institute masters program.
</p> </p>
</div>
{% endblock %} {% endblock %}

@ -36,7 +36,7 @@ function outputUpdate3(gender) {
<div class="form-group">Title:* <br> {{ form.title (size=50, class="form-control") }}</div> <div class="form-group">Title:* <br> {{ form.title (size=50, class="form-control") }}</div>
<br> <br>
<div data-toggle="fieldset" id="phone-fieldset"> <div data-toggle="fieldset" id="phone-fieldset">
Author(s):* <button type="button" data-toggle="fieldset-add-row data-target="#phone-fieldset">+</button> Author(s):* <button type="button" data-toggle="fieldset-add-row" data-target="#phone-fieldset">+</button>
<table> <table>
<tr> <tr>
<th></th> <th></th>
@ -68,17 +68,12 @@ Check the bibliography. How diverse are the references in this book? <br>
<br><hr align="left" style="width:96%;"><br> <br><hr align="left" style="width:96%;"><br>
Check the writing. Who is speaking? Is the voice more often male or female? <br> Check the writing. Who is speaking? Is the voice more often male or female? <br>
{{ form.diversity(min=1, max=100, oninput="outputUpdate3(value)") }} &nbsp; {{ form.gender(min=1, max=100, oninput="outputUpdate3(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="diversity" id="selected-gender">{{ form.gender.data }} </output> % female</span> <span style="color: #d3d3d3;"><output for="diversity" id="selected-gender">{{ form.gender.data }} </output> % female</span>
<br><hr align="left" style="width:96%;"><br> <br><hr align="left" style="width:96%;"><br>
Who are you? {{ render_field(form.who) }} Who are you? {{ render_field(form.who) }}
<br><hr align="left" style="width:96%;"><br>
How much time have you spent with this item?
Include the time spent looking for it, and uploading it.<br>
{{ form.time (size = 50, class="form-control")}} <span style="color: #d3d3d3;">hours</span>
<br>
<br><hr align="left" style="width:96%;"><br> <br><hr align="left" style="width:96%;"><br>
<div style="width: 40%;"> <div style="width: 40%;">

@ -22,12 +22,26 @@
{{form.hidden_tag()}} {{form.hidden_tag()}}
<br> <br>
{{ render_field(form.stack_name)}} {{ render_field(form.stack_name)}}
{{ render_field(form.stack_description)}} <div style="width: 40%;">
Add a nice description: {{ form.stack_description(size=90, class="form-control") }}
</div>
{{ render_field(form.stack_author)}} {{ render_field(form.stack_author)}}
<br>
<button type="submit" class='button'>Create</button> <button type="submit" class='button'>Create</button>
</form>
<br>
<hr>
<br>
<h1> Stacks currently in the library </h1>
<ul>
{% for stack in stacks %}
<li> <a href="stacks/tab/{{ stack.id }}">
</form> {{ stack.stack_name }}
</a></td>
{% endfor %}
</ul>

@ -6,7 +6,7 @@
<div> Chosen book: <div> Chosen book:
<h1 class="header">{{ book.title }}</h1> <h1 class="header">{{ book.title }}</h1>
<img class="no_cover" id="{{ book.title }}" src="../uploads/cover/{{ book.cover }}" width="150" onerror="if (this.src != '../static/img/{{ book.cover }}') this.src = '../static/img/default_cover.gif';"> <img class="no_cover" id="{{ book.title }}" src="../cover/{{ book.cover }}" width="150" onerror="if (this.src != '../static/img/{{ book.cover }}') this.src = '../static/img/default_cover.gif';">
</div> </div>
<p>These are all the stacks that have been built so far.</p> <p>These are all the stacks that have been built so far.</p>

@ -43,15 +43,22 @@
{% block js %} {% endblock%} {% block js %} {% endblock%}
<<<<<<< HEAD
<script type="text/javascript" src="http://code.jquery.com/jquery-2.2.4.js"></script> <script type="text/javascript" src="http://code.jquery.com/jquery-2.2.4.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.12.0/jquery-ui.js"></script> <script type="text/javascript" src="http://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<script type='text/javascript' src='//cdn.jsdelivr.net/jquery.marquee/1.4.0/jquery.marquee.min.js'></script> <script type='text/javascript' src='//cdn.jsdelivr.net/jquery.marquee/1.4.0/jquery.marquee.min.js'></script>
=======
<script src="{{ url_for("static", filename="js/jquery-3.3.1.min.js") }}"></script>
<script src="{{ url_for("static", filename="js/jquery-ui-1.12.1.custom/jquery-ui.js") }}"></script>
<script src="{{ url_for("static", filename="js/jquery.marquee.min.js") }}"></script>
>>>>>>> 0f5e5606ab9152e9d27e7081e251e12a7f33824b
<script type="text/javascript" src="{{ url_for("static", filename="js/jquery.tablesorter.js") }}"></script> <script type="text/javascript" src="{{ url_for("static", filename="js/jquery.tablesorter.js") }}"></script>
<script src="{{ url_for("static", filename="js/app.js") }}"></script> <script src="{{ url_for("static", filename="js/app.js") }}"></script>
<script src="{{ url_for("static", filename="js/vendor/socket.io.slim.js") }}"></script> <script src="{{ url_for("static", filename="js/vendor/socket.io.slim.js") }}"></script>
<script src="{{ url_for("static", filename="js/vendor/vue.min.js") }}"></script> <script src="{{ url_for("static", filename="js/vendor/vue.min.js") }}"></script>
<script> <script>
function convertTime(inTime){ function convertTime(inTime){
var time = inTime; var time = inTime;
time = time.match(/(\d+)\-(\d+)\-(\d+)\s*(\d+):(\d+):(\d+)/); time = time.match(/(\d+)\-(\d+)\-(\d+)\s*(\d+):(\d+):(\d+)/);
@ -98,6 +105,28 @@ socket.on('connect', function() {
}); });
socket.on('channel-' + app.channel, function(msg) { socket.on('channel-' + app.channel, function(msg) {
console.log("new: "+msg.text)
$(".messageback1").each(function() {
var oldColor = $(this).css("background-color");
var randomColor = colorHash(msg.text).rgb;
console.log("old: "+oldColor)
console.log("new: "+randomColor)
$(this).css({
background: "-webkit-gradient(linear, left top, left bottom, from("+oldColor+"), to("+randomColor+"))",
backgroundColor: randomColor
});
$('.messageback2').animate({
opacity: 0
}, 1000, function() {
$('.messageback2').css({background: "-webkit-gradient(linear, left top, left bottom, from("+oldColor+"), to("+randomColor+"))", opacity: 1})
});
});
// Add new message to HTML // Add new message to HTML
let my_messages = app.messages; let my_messages = app.messages;
my_messages.push({ my_messages.push({

@ -1,22 +1,36 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block main %} {% block main %}
{% from "_formhelpers.html" import render_field %}
<head>
<script>
function outputUpdate(sameness) {
document.querySelector('#selected-sameness').value = sameness;
}
function outputUpdate2(diversity) {
document.querySelector('#selected-diversity').value = diversity;
}
function outputUpdate3(gender) {
document.querySelector('#selected-gender').value = gender;
}
</script>
</head>
<div class="container"> <div class="container">
<a href="{{ url_for('show_book_by_id', id=book.id )}}">back</a> <a href="{{ url_for('show_book_by_id', id=book.id )}}">back</a>
<form method="POST" action="{{ url_for('edit_book_by_id', id=book.id )}}" enctype=multipart/form-data> <form method="POST" action="{{ url_for('edit_book_by_id', id=book.id )}}" enctype=multipart/form-data>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="form-group"><h1 class="header">{{ form.title.label }} {{ form.title(size=20, class="form-control") }}</h1></div> <div class="form-group"><h1 class="header">{{ form.title.label }} {{ form.title(size=20, class="form-control") }}</h1></div>
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="150" onerror="if (this.src != '/uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"> <div style="float:right; padding-right: 300px;">
<img class="no_cover" id="{{ book.title }}" src="../uploads/cover/{{ book.cover }}" width="280px" onerror="if (this.src != '/uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></div>
<br> <br> <br>
<div data-toggle="fieldset" id="phone-fieldset"> <div data-toggle="fieldset" id="phone-fieldset">
{{ form.author.label }} <button type="button" data-toggle="fieldset-add-row" {{ form.author.label }}*: <button type="button" data-toggle="fieldset-add-row"
data-target="#phone-fieldset">+</button> data-target="#phone-fieldset">+</button>
<table> <table>
<tr> <tr>
@ -25,28 +39,45 @@
</tr> </tr>
{% for author in form.author %} {% for author in form.author %}
<tr data-toggle="fieldset-entry"> <tr data-toggle="fieldset-entry">
<td>{{ author.author_name }}</td> <td>{{ author.author_name (size=50, class="form-control") }}</td>
<td><button type="button" data-toggle="fieldset-remove-row" id="phone-{{loop.index0}}-remove">-</button></td> <td><button type="button" data-toggle="fieldset-remove-row" id="phone-{{loop.index0}}-remove">-</button></td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table><br>
</div><br> <br>
<div class="form-group" style="padding-bottom: 10px;"> Category:* <br> {{ form.category(size=50, class="form-control") }} <br><br>
Category: {{ form.category(size=20, Year published: <br> {{ form.year_published(size=8, class="form-control") }} <br><br>
class="form-control") }}
</div> How different is this item to the rest of the collection?
<div class="form-group" style="padding-bottom: 10px;"> Or is it more of the same? <br>
Year published: {{ form.year_published(size=8, class="form-control") }} {{ form.sameness(min=0, max=100, oninput="outputUpdate(value)") }} &nbsp;
</div> <span style="color: #d3d3d3;"><output for="sameness" id="selected-sameness">{{ form.sameness.data }} </output> % different</span>
<br><hr align="left" style="width:40%;"><br>
Check the bibliography. How diverse are the references in this book? <br>
{{ form.diversity(min=0, max=100, oninput="outputUpdate2(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="diversity" id="selected-diversity">{{ form.diversity.data }} </output> % diverse</span>
<br><hr align="left" style="width:40%;"><br>
Check the writing. Who is speaking? Is the voice more often male or female? <br>
{{ form.gender(min=1, max=100, oninput="outputUpdate3(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="diversity" id="selected-gender">{{ form.gender.data }} </output> % female</span>
<br><hr align="left" style="width:40%;"><br>
Who are you? {{ render_field(form.who)}}
<br><hr align="left" style="width:40%;"><br>
<div class="form-group" style="padding-bottom: 10px;"> <div class="form-group" style="padding-bottom: 10px;">
Current file: {{ book.file }} Current file: {{ book.file }} &nbsp;&nbsp;&nbsp;&nbsp; Upload new file: {{form.file}}
</div> </div>
<div class="form-group" style="padding-bottom: 10px;"> <div class="form-group" style="padding-bottom: 10px;">
Upload new file: {{form.file}}
</div> </div>
<div class="form-group" style="padding-bottom: 10px;"> <div class="form-group" style="padding-bottom: 10px;">
If uploading, write a new message: {{form.message(size=150, class="form-control") }} If uploading, write a new message: <br>{{form.message(size=135, class="form-control") }}
</div> </div>
<br> <br>

@ -3,10 +3,16 @@
<li><a href="{{ url_for('home') }}">Home</a></li> <li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('show_books') }}">Catalogue</a></li> <li><a href="{{ url_for('show_books') }}">Catalogue</a></li>
<li><a href="{{ url_for('show_stacks') }}">Stacks</a></li> <li><a href="{{ url_for('show_stacks') }}">Stacks</a></li>
{%if light%}
{%else%}
<li><a href="{{ url_for('add_book') }}">Add Book</a></li> <li><a href="{{ url_for('add_book') }}">Add Book</a></li>
<li><a href="{{ url_for ('add_stack') }}">Add Stack</a></li> <li><a href="{{ url_for ('add_stack') }}">Add Stack</a></li>
{%endif%}
<li><a href="{{ url_for('about') }}">About</a></li> <li><a href="{{ url_for('about') }}">About</a></li>
{%if light%}
{%else%}
<li><a href="{{ url_for('show_instances') }}">Instances</a></li> <li><a href="{{ url_for('show_instances') }}">Instances</a></li>
{%endif%}
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</nav> </nav>

@ -3,10 +3,10 @@
{% block main %} {% block main %}
<div id="home_content"> <div id="home_content">
<h1 class="header" id="title_xppl">XPPL</h1> <h1 class="header" id="title_xppl">XPPL</h1>
<p class="lead">This is the awesome library of Experimental Publishing. <br> <p class="lead"> Welcome to our digital library. <br>
On instance: {{server}} / From: {{client}} On instance: {{server}} / From: {{client}}
<br> <br>
This might only be one interface to this library: Feel free to browse our catalogue, interfaced in many different ways.
</p> </p>
<a href="{{url_for('scape')}}">Scape</a> <a href="{{url_for('scape')}}">Scape</a>
@ -15,6 +15,8 @@ This might only be one interface to this library:
<br><br><br> <br><br><br>
{%if light%}
{%else%}
<form method="GET" action="/export/csv"> <form method="GET" action="/export/csv">
<button type="submit">Export Catalogue (.CSV)</button> <button type="submit">Export Catalogue (.CSV)</button>
</form> </form>
@ -23,9 +25,13 @@ This might only be one interface to this library:
<button type = "button" onclick="document.getElementById('file_import_csv').click()">Import Catalogue (.CSV)</button> <button type = "button" onclick="document.getElementById('file_import_csv').click()">Import Catalogue (.CSV)</button>
</form> </form>
</div> </div>
{%endif%}
<div id="app" class="container"> <div id="app" class="container">
<div class="messageback1"></div>
<div class="messageback2"></div>
<section class="messages"> <section class="messages">
<div v-for="message in messages" class="box"> <div v-for="message in messages" class="box">
<article class="media"> <article class="media">
<div class="media-content"> <div class="media-content">
@ -38,6 +44,7 @@ This might only be one interface to this library:
</div> </div>
</article> </article>
</div> </div>
</section> </section>
<section class="new-message"> <section class="new-message">
<div class="field has-addons"> <div class="field has-addons">

@ -32,10 +32,13 @@
</div> </div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
{%if light%}
{%else%}
<div style="width: 220px; float: left; padding-right: 40px;"> <div style="width: 220px; float: left; padding-right: 40px;">
<img class="no_cover" width="220" src = '/static/img/default_cover.gif';> <img class="no_cover" width="220" src = '/static/img/default_cover.gif';>
</div> </div>
<br> <br>
<div> <div>
<h2>Add this book:</h2> <h2>Add this book:</h2>
@ -60,21 +63,19 @@
</table> </table>
</div> </div>
</div> </div>
<div style="padding-left:10px; padding-bottom: 50px;"> <div style="padding-left:10px; padding-bottom: 100px;">
<br>
Category: {{ form.category(size=27, class="form-control") }} Category: {{ form.category(size=27, class="form-control") }}
<br> <br>
<br>
Year published: {{ form.year_published(size=8, class="form-control") }}
<br>
<br> <br>
{{ form.file }} {{ form.file }}
{{ form.upload }} {{ form.upload }}
{{ form.wish }} {{ form.wish }}
</form> </form>
<br> <br>
<p><a href="{{ url_for('home') }}" style="font-size: 9pt;">go back home</a></p>
<br> <br>
</div> </div>
{%endif%}
<div class= "Container" style= "border-top: dashed; border-width: 1px;"> <div class= "Container" style= "border-top: dashed; border-width: 1px;">
<h2> More potential books </h2> <h2> More potential books </h2>
<table class="library_table" id="table" style="width:100%"> <table class="library_table" id="table" style="width:100%">
@ -86,7 +87,10 @@
<th width="100px;">Year</th> <th width="100px;">Year</th>
<th width="100px;">Category</th> <th width="100px;">Category</th>
<th width="100px;">Stack</th> <th width="100px;">Stack</th>
{%if light%}
{%else%}
<th width="100px;">Add to a stack</th> <th width="100px;">Add to a stack</th>
{%endif%}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -94,7 +98,7 @@
<tr> <tr>
<td style= "padding: 5px;"> <td style= "padding: 5px;">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="70" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="70" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';">
<!-- <object class="no_cover" data="../static/img/default_cover.png" type="image/png" width="65"> <!-- <object class="no_cover" data="../static/img/default_cover.png" type="image/png" width="65">
<p hidden="True"></p> <p hidden="True"></p>
@ -121,10 +125,13 @@
</td> </td>
{%if light%}
{%else%}
<td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}"> <td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}">
===> ===>
</a></td> </a></td>
{%endif%}
</tr> </tr>
{% endfor %} {% endfor %}

@ -14,7 +14,7 @@
</div> </div>
<br> <br>
<h3 style="line-height:0px;"">Results: "{{ query }}" included in {{ count }} out of {{ whole }} items </h3> <h3 style="line-height:0px;">Results: "{{ query }}" included in {{ count }} out of {{ whole }} items </h3>
<div style="height: 20px; background-color: yellow; line-height:4px;"> <div style="height: 20px; background-color: yellow; line-height:4px;">
<div style="background-color: black; width: {{ percentage }}%; height: 100%;"></div> <div style="background-color: black; width: {{ percentage }}%; height: 100%;"></div>
</div> </div>
@ -39,13 +39,15 @@
<th width="100px;">Year</th> <th width="100px;">Year</th>
<th width="100px;">Category</th> <th width="100px;">Category</th>
<th width="100px;">Stack</th> <th width="100px;">Stack</th>
{%if light%}
{%else%}
<th width="100px;">Add to stack</th> <th width="100px;">Add to stack</th>
{%endif%}
</tr> </tr>
{% for book in books %} {% for book in books %}
<tr> <tr>
<td style= "padding: 5px;"> <td style= "padding: 5px;">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="70" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></td> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="70" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></td>
<td><a href="{{url_for('show_book_by_id', id=book.id)}}">{{ book.title }}</a></td> <td><a href="{{url_for('show_book_by_id', id=book.id)}}">{{ book.title }}</a></td>
<td> {% for author in book.authors %} <td> {% for author in book.authors %}
@ -60,9 +62,12 @@
<li><a href="{{url_for('show_stack_by_id', id=stack.id)}}">{{ stack.stack_name }}</a> </li> <li><a href="{{url_for('show_stack_by_id', id=stack.id)}}">{{ stack.stack_name }}</a> </li>
{% endfor %} {% endfor %}
</td> </td>
{%if light%}
{%else%}
<td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}"> <td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}">
==> ==>
</a></td> </a></td>
{%endif%}
{% endfor %} {% endfor %}
</table> </table>
@ -81,12 +86,14 @@
<th width="100px;">Year</th> <th width="100px;">Year</th>
<th width="100px;">Category</th> <th width="100px;">Category</th>
<th width="100px;">Stack</th> <th width="100px;">Stack</th>
{%if light%}
{%else%}
<th width="100px;">Add to stack</th> <th width="100px;">Add to stack</th>
{%endif%}
</tr> </tr>
{% for book in books_all %} {% for book in books_all %}
<tr> <tr>
<td style= "padding: 5px;"><img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="80" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></td> <td style= "padding: 5px;"><img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="80" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></td>
<td><a href="{{url_for('show_book_by_id', id=book.id)}}">{{ book.title }}</a></td> <td><a href="{{url_for('show_book_by_id', id=book.id)}}">{{ book.title }}</a></td>
<td> {% for author in book.authors %} <td> {% for author in book.authors %}
@ -102,10 +109,12 @@
{% endfor %} {% endfor %}
</td> </td>
{%if light%}
{%else%}
<td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}"> <td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}">
==> ==>
</a></td> </a></td>
{%endif%}
{% endfor %} {% endfor %}
</table> </table>
<p> <p>

@ -14,7 +14,7 @@
</div> </div>
<br> <br>
<h3 style="line-height:0px;"">Results: "{{ query }}" included in {{ count }} out of {{ whole }} items </h3> <h3 style="line-height:0px;">Results: "{{ query }}" included in {{ count }} out of {{ whole }} items </h3>
<div style="height: 20px; background-color: yellow; line-height:4px;"> <div style="height: 20px; background-color: yellow; line-height:4px;">
<div style="background-color: black; width: {{ percentage }}%; height: 100%;"></div> <div style="background-color: black; width: {{ percentage }}%; height: 100%;"></div>
</div> </div>
@ -37,7 +37,7 @@
<div class="gridbox"> <div class="gridbox">
<a href="/books/{{ book.id }}"> <a href="/books/{{ book.id }}">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a>
<p> <p>
<tbody> <tbody>
<th> <th>
@ -61,7 +61,7 @@
<div class="gridbox"> <div class="gridbox">
<a href="books/{{ book.id }}"> <a href="books/{{ book.id }}">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a>
<p> <p>
<tbody> <tbody>
<th> <th>

@ -74,7 +74,7 @@
<div class = "drag" id = "{{ book.id }}" style="position: absolute;width:70px;height:auto; top:{{ book.scapeY }}px; left:{{ book.scapeX }}px;"> <div class = "drag" id = "{{ book.id }}" style="position: absolute;width:70px;height:auto; top:{{ book.scapeY }}px; left:{{ book.scapeX }}px;">
<img class="no_cover" id="{{ book.title }}" src="../uploads/cover/{{ book.cover }}" style="width:100%;height:auto;" onerror="if (this.src != '../static/img/default_cover.png') this.src = '../static/img/default_cover.png';"> <img class="no_cover" id="{{ book.title }}" src="../cover/{{ book.cover }}" style="width:100%;height:auto;" onerror="if (this.src != '../static/img/default_cover.gif') this.src = '../static/img/default_cover.gif';">
<p class="booktitle" style="font-size:7px;"><a href="books/{{ book.id }}">{{ book.title }}</a></p> <p class="booktitle" style="font-size:7px;"><a href="books/{{ book.id }}">{{ book.title }}</a></p>
{% set got = {} %} {% set got = {} %}
@ -104,7 +104,7 @@
</div> </div>
</div> </div>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script> <script src="{{ url_for("static", filename="js/jquery-3.3.1.min.js") }}"></script>
<script src="{{ url_for("static", filename="js/app.js") }}"></script> <script src="{{ url_for("static", filename="js/app.js") }}"></script>
<script> <script>
@ -150,8 +150,8 @@
} }
</script> </script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script src="{{ url_for("static", filename="js/jquery-ui-1.12.1.custom/jquery-ui.js") }}"></script>
<script> <script>
$( function() { $( function() {
var currentZoom = $('#scape_container').css('zoom'); var currentZoom = $('#scape_container').css('zoom');

@ -2,11 +2,12 @@
{% block main %} {% block main %}
<div class="container"> <div class="container">
<h1 class="header">{{ book.title }}</h1> <h1 class="header">{{ book.title }}</h1>
<div style="float:right; padding-right: 140px;"> <div style="float:right; padding-right: 140px;">
<img class="no_cover" id="{{ book.title }}" src="../uploads/cover/{{ book.cover }}" width="280px" onerror="if (this.src != '../uploads/cover/{{ book.cover }}') this.src = '../static/img/default_cover.gif';"></div> <img class="no_cover" id="{{ book.title }}" src="../cover/{{ book.cover }}" width="280px" onerror="if (this.src != '../cover/{{ book.cover }}') this.src = '../static/img/default_cover.gif';"></div>
<table class="library_table" id="table" style="width:50%; padding-bottom: 80px;"> <table class="library_table" id="table" style="width:50%; padding-bottom: 180px;">
<thead> <thead>
<tr id="header"> <tr id="header">
<th style="width: 150px;"></th> <th style="width: 150px;"></th>
@ -58,19 +59,10 @@
<td>Who is uploading<br></td> <td>Who is uploading<br></td>
<td>{{ book.who or '?' }} </td> <td>{{ book.who or '?' }} </td>
</tr> </tr>
<tr>
<td>How much time has been spent with this item?<br></td>
<td>{{ book.time or '?' }} </td>
</tr>
</tbody>
</table>
<a href="../uploads/{{ book.file }}">download {{ book.fileformat }}</a> <tr>
<br> <td>Instances:</td>
<br> <td>{% set got = {} %}
<p>Instances:</p>
{% set got = {} %}
{% set all = 1 %} {% set all = 1 %}
{% for instance in book.instances %} {% for instance in book.instances %}
@ -85,31 +77,39 @@
{% for instance, value in got.items() %} {% for instance, value in got.items() %}
{% set result = value/(book.instances|length) %} {% set result = value/(book.instances|length) %}
{{ instance }}: {{ (result*100)|round|int }}%<br> {{ instance }}: {{ (result*100)|round|int }}%<br>
{% endfor %} {% endfor %}</td>
<br>
</tbody>
</table>
{%if light%}
{%else%}
<br>
<a href="{{url_for('add_to_stack', id=book.id)}}">Add book to Stack ===></a> <br><br>
<br>
{% if book.file %} {% if book.file %}
<button id="myBtn" style= "width: 180px; font-size: 10pt;"><a> Download this {{ book.fileformat }}</a></button> <button id="myBtn" style= "width: 180px; font-size: 10pt;"><a> Download this {{ book.fileformat }}</a></button>
<div id="myModal" class="modal"> <div id="myModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="close">&times;</span> <span class="close">&times;</span>
<h3>A message from the uploading librarian:</h3> <h3>A message from the uploading librarian:</h3>
<span style="font-style: italic;">"{{book.message or 'Happy reading.'}}" </span><br> <span style="font-style: italic;">"{{book.message or '...'}}" </span><br>
<h4><a href="../uploads/{{ book.file }}"> >>>> Link to file <<<<</h4></a></div> <h4><a href="../uploads/{{ book.file }}"> >>>> Link to file <<<<</h4></a>
</div> </div>
{% else %} </div>
{% endif %} {% else %}
{% endif %}
<button style= "font-size: 10pt;"> <a href="{{ url_for('edit_book_by_id', id=book.id )}}">edit</a></button> <a href="{{ url_for('edit_book_by_id', id=book.id )}}"><button style= "font-size: 10pt;"> edit</button></a>
<button style= "font-size: 10pt;"> <a href="{{ url_for('remove_book_by_id', id=book.id)}}">delete</a></button> <a href="{{ url_for('remove_book_by_id', id=book.id)}}"><button style= "font-size: 10pt;"> delete</button></a>
<br><br> <br><br>
<br><br>
{%endif%}
<hr> <hr>
{% if previousbook %} {% if previousbook %}
<a href="{{ url_for('show_book_by_id', id=previousbook.id )}}" style="font-size: 9pt;"> < see the previous book added to XPPL: &nbsp;<i>{{ previousbook.title |truncate(40,True,'...') }} </i></a> {% endif %} <a href="{{ url_for('show_book_by_id', id=previousbook.id )}}" style="font-size: 10pt;"> < see the previous book added to XPPL: &nbsp;<i>{{ previousbook.title |truncate(40,True,'...') }} </i></a> {% endif %}
{% if nextbook %} {% if nextbook %}
<a href="{{ url_for('show_book_by_id', id=nextbook.id )}}" style="float:right; font-size: 9pt;"> see the next book added to XPPL: &nbsp;<i>{{ nextbook.title|truncate(40,True,'...')}} </i>> </a>{% endif %} <a href="{{ url_for('show_book_by_id', id=nextbook.id )}}" style="float:right; font-size: 10pt;"> see the next book added to XPPL: &nbsp;<i>{{ nextbook.title|truncate(40,True,'...')}} </i>> </a>{% endif %}
</div> </div>
{% endblock %} {% endblock %}

@ -36,7 +36,10 @@
<th width="100px;">Year</th> <th width="100px;">Year</th>
<th width="100px;">Category</th> <th width="100px;">Category</th>
<th width="100px;">Stack</th> <th width="100px;">Stack</th>
{%if light%}
{%else%}
<th width="100px;">Add to a stack</th> <th width="100px;">Add to a stack</th>
{%endif%}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -44,7 +47,7 @@
<tr> <tr>
<td style= "padding: 5px;"> <td style= "padding: 5px;">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="70" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="70" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';">
<!-- <object class="no_cover" data="../static/img/default_cover.png" type="image/png" width="65"> <!-- <object class="no_cover" data="../static/img/default_cover.png" type="image/png" width="65">
<p hidden="True"></p> <p hidden="True"></p>
@ -59,19 +62,29 @@
{% endfor %}</td> {% endfor %}</td>
<td id='fileformat'>{{ book.year_published or ''}}</td> <td id='fileformat'>{{ book.year_published or ''}}</td>
<td>{{ book.category}}</td> <td>{{ book.category}}</td>
<td> <td id='ascii'>
{% for stack in book.stacks %} {% for stack in book.stacks %}
<li><a href="{{url_for('show_stack_by_id', id=stack.id)}}"> {{ stack.stack_name }} </a></li> <li><a href="{{url_for('show_stack_by_id', id=stack.id)}}"> {{ stack.stack_name }} </a></li>
{% else %}
<li style='font-size:10px;'>
XXXXXXXXXX <br>
XXXXXXXXXX <br>
XXXXXXXXXX <br>
{% endfor %} {% endfor %}
</td> </td>
{%if light%}
{%else%}
<td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}"> <td id='plus'><a href="{{url_for('add_to_stack', id=book.id)}}">
===> ===>
</a></td> </a></td>{%endif%}
</tr> </tr>
{% endfor %} {% endfor %}

@ -34,7 +34,7 @@
<div class="gridbox"> <div class="gridbox">
<a href="books/{{ book.id }}"> <a href="books/{{ book.id }}">
<img class="no_cover" id="{{ book.title }}" src="/uploads/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '//uploads/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a> <img class="no_cover" id="{{ book.title }}" src="/cover/{{ book.cover }}" width="100%" onerror="if (this.src != '/cover/{{ book.cover }}') this.src = '/static/img/default_cover.gif';"></a>
<p> <p>
<tbody> <tbody>
<th> <th>

@ -13,26 +13,39 @@
{{ stack.stack_author }} {{ stack.stack_author }}
{% endif %} {% endif %}
<h2>Books in this stack:</h2> <h2>Books in this stack:</h2>
<p> <p>
{% for book in stack.books %} {% for book in stack.books %}
{% if loop.length >= 5 %}
{% if loop.index == 6 %}
<p style='color:red;'>Your stack is getting a little too big. Are these next books really relevant?</p>
<br>
<br>
{% endif %}
{% endif %}
<li> <a href="{{url_for('show_book_by_id', id=book.id)}}">{{book.title}}</a> </li> <li> <a href="{{url_for('show_book_by_id', id=book.id)}}">{{book.title}}</a> </li>
<img class="no_cover" id="{{ book.title }}" src="../uploads/cover/{{ book.cover }}" width="150" onerror="if (this.src != '../uploads/cover/{{ book.cover }}') this.src = '../static/img/default_cover.gif';"> <img class="no_cover" id="{{ book.title }}" src="../cover/{{ book.cover }}" width="150" onerror="if (this.src != '../cover/{{ book.cover }}') this.src = '../static/img/default_cover.gif';">
<div class='widget'> <div class='widget'>
{%if light%}
{%else%}
<iframe src="../uploads/{{ book.file }}" width="50%" ></iframe> <iframe src="../uploads/{{ book.file }}" width="50%" ></iframe>
{%endif%}
</div> </div>
{% endfor %}</p>
{% endfor %}</p>
<br> <br>
<br> <br>
<p> {%if light%}
<a href="{{ url_for('remove_stack_by_id', id=stack.id )}}">Remove stack</a> </p> {%else%}
<p> <p><a href="{{url_for('show_books')}}">Add some more books</a></p>
<a href="{{ url_for('edit_stack_by_id', id=stack.id )}}">Edit title and/or description</a> </p> <p><a href="{{ url_for('edit_stack_by_id', id=stack.id )}}">Edit title and/or description</a> </p>
<p><a href="{{ url_for('remove_stack_by_id', id=stack.id )}}">Remove stack</a> </p>
{%endif%}
<p><a href="{{url_for('show_stacks')}}">Go back to the other stacks</p> <p><a href="{{url_for('show_stacks')}}">Go back to the other stacks</p>
</div> </div>

@ -17,17 +17,12 @@
{{ stack.stack_author }} {{ stack.stack_author }}
{% endif %} {% endif %}
<p style='font-weight:bold;'>Books in this stack: {% for book in stack.books %} </p>
<p style='font-weight:bold;'>Books in this stack: {% for book in stack.books %}
<li style="font-size: 18px;"> <a href="{{url_for('show_book_by_id', id=book.id)}}">{{book.title}}</a> </li> <li style="font-size: 18px;"> <a href="{{url_for('show_book_by_id', id=book.id)}}">{{book.title}}</a> </li>
<p style="font-size: 10px;"><a href='{{url_for('add_to_stack', id=book.id)}}'> <p style="font-size: 10px;"><a href='{{url_for('add_to_stack', id=book.id)}}'> Add to another stack </a></p>
Add to another stack
</a></p>
{% endfor %}</p>
{% endfor %}
</div> </div>

@ -5,9 +5,10 @@ Werkzeug Documentation: http://werkzeug.pocoo.org/documentation/
This file creates your application. This file creates your application.
""" """
from app import app, db, socketio, DOMAIN from app import app, db, socketio, DOMAIN, light
from flask import Flask, Response, session, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort from flask import Flask, Response, session, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort
import json import json
from functools import wraps
from sqlalchemy.sql.expression import func, select from sqlalchemy.sql.expression import func, select
from sqlalchemy.sql import except_ from sqlalchemy.sql import except_
from app.forms import UploadForm, EditForm, SearchForm, ChatForm, StackForm, AddtoStackForm, EditStackForm from app.forms import UploadForm, EditForm, SearchForm, ChatForm, StackForm, AddtoStackForm, EditStackForm
@ -48,26 +49,34 @@ def allowed_file(filename):
# Routing for your application. # Routing for your application.
### ###
def check_light(func):
@wraps(func)
def decorated_function(*args, **kwargs):
if not light:
return func(*args, **kwargs)
else:
flash("Your account has expired. Update your billing info.")
return redirect(url_for('home'))
return decorated_function
@app.route('/', methods= ['POST','GET']) @app.route('/', methods= ['POST','GET'])
def home(): def home():
print("/////////////")
print(light)
chat_form = ChatForm() chat_form = ChatForm()
chat_messages = db.session.query(Chat).all() chat_messages = db.session.query(Chat).all()
username = 'librarian' username = 'librarian'
# if request.method == 'POST':
# if chat_form.validate_on_submit():
# message = chat_form.message.data
# msg = Chat(message)
# db.session.add(msg)
# db.session.commit()
#client = request.remote_addr
server = request.host server = request.host
if request.environ.get('HTTP_X_FORWARDED_FOR') is None: if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
client =request.environ['REMOTE_ADDR'] client =request.environ['REMOTE_ADDR']
else: else:
client = request.environ['HTTP_X_FORWARDED_FOR'] client = request.environ['HTTP_X_FORWARDED_FOR']
return render_template('home.html',domain=DOMAIN,chat=chat_messages, channel = 1, username=username, client=client, server=server) return render_template('home.html',domain=DOMAIN,chat=chat_messages, channel = 1, username=username, client=client, server=server, light=light)
@app.route('/hello/<name>') @app.route('/hello/<name>')
def hello(name): def hello(name):
@ -76,9 +85,10 @@ def hello(name):
@app.route('/about/') @app.route('/about/')
def about(): def about():
"""Render the website's about page.""" """Render the website's about page."""
return render_template('about.html', name="Mary Jane") return render_template('about.html', light=light)
@app.route('/uploads/<filename>') @app.route('/uploads/<filename>')
@check_light
def uploaded_file(filename): def uploaded_file(filename):
book = Book.query.filter_by(file=filename).first() book = Book.query.filter_by(file=filename).first()
i = Instance(request.host, "download") i = Instance(request.host, "download")
@ -90,7 +100,7 @@ def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], return send_from_directory(app.config['UPLOAD_FOLDER'],
filename) filename)
@app.route('/uploads/cover/<filename>') @app.route('/cover/<filename>')
def uploaded_file_cover(filename): def uploaded_file_cover(filename):
return send_from_directory(app.config['UPLOAD_FOLDER_COVER'], return send_from_directory(app.config['UPLOAD_FOLDER_COVER'],
filename) filename)
@ -131,7 +141,7 @@ def scape():
@app.route('/books_grid') @app.route('/books_grid')
def show_books_grid(): def show_books_grid():
books = db.session.query(Book).all() # or you could have used User.query.all() books = db.session.query(Book).all() # or you could have used User.query.all()
return render_template('show_books_grid.html', books=books) return render_template('show_books_grid.html', books=books, light=light)
@app.route('/books/<int:id>') @app.route('/books/<int:id>')
def show_book_by_id(id): def show_book_by_id(id):
@ -155,12 +165,13 @@ def show_book_by_id(id):
db.session.add(user_info) db.session.add(user_info)
db.session.commit() db.session.commit()
if not book: if not book:
return render_template('red_link.html', id=id) return render_template('red_link.html', id=id, light=light)
else: else:
return render_template('show_book_detail.html', book=book, previousbook = previousbook, nextbook = nextbook, all_instances=all_instances) return render_template('show_book_detail.html', book=book, previousbook = previousbook, nextbook = nextbook, all_instances=all_instances, light=light)
@app.route('/books/<int:id>/delete', methods=['POST', 'GET']) @app.route('/books/<int:id>/delete', methods=['POST', 'GET'])
@check_light
def remove_book_by_id(id): def remove_book_by_id(id):
book_to_edit = Book.query.filter_by(id=id).first() book_to_edit = Book.query.filter_by(id=id).first()
title = book_to_edit.title title = book_to_edit.title
@ -171,9 +182,10 @@ def remove_book_by_id(id):
return redirect(url_for('show_books')) return redirect(url_for('show_books'))
@app.route('/books/<int:id>/edit', methods=['POST', 'GET']) @app.route('/books/<int:id>/edit', methods=['POST', 'GET'])
@check_light
def edit_book_by_id(id): def edit_book_by_id(id):
book_to_edit = Book.query.filter_by(id=id).first() book_to_edit = Book.query.filter_by(id=id).first()
user_form = EditForm(title = book_to_edit.title, author =book_to_edit.authors, category = book_to_edit.category, year_published= book_to_edit.year_published, message= book_to_edit.message) user_form = EditForm(title = book_to_edit.title, author =book_to_edit.authors, category = book_to_edit.category, year_published= book_to_edit.year_published, message= book_to_edit.message, sameness=book_to_edit.sameness, gender=book_to_edit.gender, diversity=book_to_edit.diversity, who=book_to_edit.who)
if request.method == 'POST': if request.method == 'POST':
if user_form.validate_on_submit(): if user_form.validate_on_submit():
@ -183,6 +195,11 @@ def edit_book_by_id(id):
category = user_form.category.data category = user_form.category.data
year_published = user_form.year_published.data year_published = user_form.year_published.data
message = user_form.message.data message = user_form.message.data
sameness = user_form.sameness.data
gender = user_form.gender.data
diversity = user_form.diversity.data
who = user_form.who.data
if year_published=="": if year_published=="":
year_published = None year_published = None
book = Book.query.filter_by(id=id).first() book = Book.query.filter_by(id=id).first()
@ -190,6 +207,10 @@ def edit_book_by_id(id):
book.category = category book.category = category
book.year_published = year_published book.year_published = year_published
book.message = message book.message = message
book.sameness = sameness
book.gender = gender
book.diversity = diversity
book.who = who
#authors update #authors update
book.authors.clear() book.authors.clear()
@ -230,10 +251,11 @@ def edit_book_by_id(id):
flash("%s updated" % (title)) flash("%s updated" % (title))
return redirect(url_for('show_book_by_id', id=id)) return redirect(url_for('show_book_by_id', id=id))
return render_template('edit_book_detail.html', book=book_to_edit, form=user_form) return render_template('edit_book_detail.html', book=book_to_edit, form=user_form, light=light)
@app.route('/add-book', methods=['POST', 'GET']) @app.route('/add-book', methods=['POST', 'GET'])
@check_light
def add_book(): def add_book():
upload_form = UploadForm() upload_form = UploadForm()
allbooks = db.session.query(Book).all() allbooks = db.session.query(Book).all()
@ -259,7 +281,6 @@ def add_book():
sameness = upload_form.sameness.data sameness = upload_form.sameness.data
gender = upload_form.gender.data gender = upload_form.gender.data
diversity = upload_form.diversity.data diversity = upload_form.diversity.data
time = upload_form.time.data
who = upload_form.who.data who = upload_form.who.data
if year_published=="": if year_published=="":
@ -309,9 +330,8 @@ def add_book():
html_string = render_template('potential_pdf.html', pbooks = pbooks) html_string = render_template('potential_pdf.html', pbooks = pbooks)
html = HTML(string=html_string) html = HTML(string=html_string)
html.write_pdf(target='app/uploads/potential.pdf'); html.write_pdf(target='app/uploads/potential.pdf');
print ('potential_pdf')
book = Book(title, filename, cover, file_extension, category, year_published, message, sameness, diversity, gender, who, time) book = Book(title, filename, cover, file_extension, category, year_published, message, sameness, diversity, gender, who)
db.session.add(book) db.session.add(book)
for author in authors: for author in authors:
author_name = author.get("author_name") author_name = author.get("author_name")
@ -332,7 +352,7 @@ def add_book():
return redirect(url_for('show_books')) return redirect(url_for('show_books'))
flash_errors(upload_form) flash_errors(upload_form)
return render_template('add_book.html', form=upload_form, books_all=books_all, authors_all=authors_all, categories=categories, stacks_all=stacks_all, books_potential=books_potential, earliest=earliest, latest=latest) return render_template('add_book.html', form=upload_form, books_all=books_all, authors_all=authors_all, categories=categories, stacks_all=stacks_all, books_potential=books_potential, earliest=earliest, latest=latest, light=light)
# Flash errors from the form if validation fails # Flash errors from the form if validation fails
@ -352,10 +372,11 @@ def show_author_by_id(id):
if not author: if not author:
abort (404) abort (404)
else: else:
return render_template('show_author_detail.html', author=author) return render_template('show_author_detail.html', author=author, light=light)
@app.route('/authors/<int:id>/edit', methods=['POST', 'GET']) @app.route('/authors/<int:id>/edit', methods=['POST', 'GET'])
@check_light
def edit_author_by_id(id): def edit_author_by_id(id):
return "Ask the programmer." return "Ask the programmer."
@ -364,9 +385,10 @@ def edit_author_by_id(id):
@app.route('/stacks') @app.route('/stacks')
def show_stacks(): def show_stacks():
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
return render_template('show_stacks.html', stacks=stacks) return render_template('show_stacks.html', stacks=stacks, light=light)
@app.route('/stacks/add_stack', methods=['POST', 'GET']) @app.route('/stacks/add_stack', methods=['POST', 'GET'])
@check_light
def add_stack(): def add_stack():
form = StackForm() form = StackForm()
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
@ -382,7 +404,7 @@ def add_stack():
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
return redirect(url_for('show_stacks')) return redirect(url_for('show_stacks'))
flash("%s stack created" % (stack_name)) flash("%s stack created" % (stack_name))
return render_template('add_stack.html', stacks=stacks, form=form) return render_template('add_stack.html', stacks=stacks, form=form, light=light)
@app.route('/stacks/tab/<int:id>', methods=['POST', 'GET']) @app.route('/stacks/tab/<int:id>', methods=['POST', 'GET'])
def show_stack_in_tab(id): def show_stack_in_tab(id):
@ -394,20 +416,22 @@ def show_stack_by_id(id, is_tab=False):
stack = Stack.query.get(id) stack = Stack.query.get(id)
if not stack: if not stack:
abort (404) return render_template('add_stack.html', stacks=stacks, form=form, light=light)
else: else:
if is_tab == False: if is_tab == False:
return render_template('show_stack_detail.html', stack=stack) return render_template('show_stack_detail.html', stack=stack, light=light)
else: else:
return render_template('show_stack_detail_tab.html', stack=stack) return render_template('show_stack_detail_tab.html', stack=stack, light=light)
@app.route('/stacks/<int:id>/delete', methods=['POST', 'GET']) @app.route('/stacks/<int:id>/delete', methods=['POST', 'GET'])
@check_light
def remove_stack_by_id(id): def remove_stack_by_id(id):
Stack.query.filter_by(id=id).delete() Stack.query.filter_by(id=id).delete()
db.session.commit() db.session.commit()
return redirect(url_for('show_stacks')) return redirect(url_for('show_stacks'))
@app.route('/stacks/<int:id>/edit', methods=['POST', 'GET']) @app.route('/stacks/<int:id>/edit', methods=['POST', 'GET'])
@check_light
def edit_stack_by_id(id): def edit_stack_by_id(id):
stack = Stack.query.filter_by(id=id).first() stack = Stack.query.filter_by(id=id).first()
form = EditStackForm(edit_stack_name = stack.stack_name, edit_stack_description = stack.stack_description) form = EditStackForm(edit_stack_name = stack.stack_name, edit_stack_description = stack.stack_description)
@ -420,9 +444,10 @@ def edit_stack_by_id(id):
stack.stack_description = stack_description stack.stack_description = stack_description
db.session.commit() db.session.commit()
return redirect(url_for('show_stack_by_id', id=id)) return redirect(url_for('show_stack_by_id', id=id))
return render_template('edit_stack_detail.html', stack=stack, form=form) return render_template('edit_stack_detail.html', stack=stack, form=form, light=light)
@app.route('/instances', methods=['POST', 'GET']) @app.route('/instances', methods=['POST', 'GET'])
@check_light
def show_instances(): def show_instances():
all_instances = db.session.query(Instance).all() all_instances = db.session.query(Instance).all()
instances = [] instances = []
@ -451,17 +476,18 @@ def show_instances():
print(oldname) print(oldname)
print(name) print(name)
db.session.commit() db.session.commit()
return render_template('show_instances.html', instances=instances) return render_template('show_instances.html', instances=instances, light=light)
@app.route('/stacks/<int:stackid>/remove/<int:bookid>', methods=['POST', 'GET']) @app.route('/stacks/<int:stackid>/remove/<int:bookid>', methods=['POST', 'GET'])
@check_light
def remove_from_stack(bookid, stackid): def remove_from_stack(bookid, stackid):
book = Book.query.get(bookid) book = Book.query.get(bookid)
stack = Stack.query.get(stackid) stack = Stack.query.get(stackid)
if book not in stack.books: if book not in stack.books:
return render_template('show_book_detail.html', book=book) return render_template('show_book_detail.html', book=book, light=light)
stack.books.remove(book) stack.books.remove(book)
db.session.commit() db.session.commit()
return render_template('show_book_detail.html', book=book) return render_template('show_book_detail.html', book=book, light=light)
## search ## search
view = ['1'] view = ['1']
@ -476,12 +502,12 @@ def show_books():
if search.grid.data: if search.grid.data:
viewby = '2' viewby = '2'
view.append('2') view.append('2')
return render_template ('show_books_grid.html', books=books, form=search) return render_template ('show_books_grid.html', books=books, form=search, light=light)
if search.listview.data: if search.listview.data:
viewby = '1' viewby = '1'
view.append('1') view.append('1')
return render_template ('show_books.html', books=books, form=search) return render_template ('show_books.html', books=books, form=search, light=light)
if request.method == 'POST': if request.method == 'POST':
newmsg = 'searched for: ' + search.search.data newmsg = 'searched for: ' + search.search.data
@ -498,7 +524,7 @@ def show_books():
db.session.rollback() db.session.rollback()
return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data, viewby=viewby))) return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data, viewby=viewby)))
return render_template('show_books.html', books=books, form=search) return render_template('show_books.html', books=books, form=search, light=light)
@app.route('/search/<searchtype>/<viewby>/<query>', methods=['POST', 'GET']) @app.route('/search/<searchtype>/<viewby>/<query>', methods=['POST', 'GET'])
def search_results(searchtype, query, viewby): def search_results(searchtype, query, viewby):
@ -519,19 +545,21 @@ def search_results(searchtype, query, viewby):
if searchtype== 'Stack': if searchtype== 'Stack':
results=db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query)).order_by(Book.title) results=db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query)).order_by(Book.title)
if searchtype== 'Outliers':
results=Book.query.filter(Book.sameness > 50).order_by(Book.title)
if searchtype== 'All': if searchtype== 'All':
# results=Book.query.whoosh_search(query) # results=Book.query.whoosh_search(query)
results=Book.query.filter(Book.title.contains(query)) results=Book.query.filter(Book.title.contains(query))
results=results.union(Book.query.filter(Book.category.contains(query))) results=results.union(Book.query.filter(Book.category.contains(query)))
results=results.union(Book.query.filter(Book.year_published.contains(query))) results=results.union(Book.query.filter(Book.year_published.contains(query)))
results=results.union(db.session.query(Book).join(Book.authors).filter(Author.author_name.contains(query))) results=results.union(db.session.query(Book).join(Book.authors).filter(Author.author_name.contains(query)))
results=results.union(db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query))) results=results.union(db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query))).order_by(Book.title)
results=results.union(db.session.query(Book).join(Book.stacks).filter(Stack.stack_description.contains(query))).order_by(Book.title)
if results.count() == 0: if results.count() == 0:
books = Book.query.filter(Book.file.like('potential.pdf')) books = Book.query.filter(Book.file.like('potential.pdf'))
upload_form = UploadForm(title= query, author='') upload_form = UploadForm(title= query, author='')
return render_template('red_link.html', form=upload_form, title=query, books=books) return render_template('red_link.html', form=upload_form, title=query, books=books, light=light)
count = results.count() count = results.count()
whole = Book.query.count() whole = Book.query.count()
@ -541,11 +569,11 @@ def search_results(searchtype, query, viewby):
if search.listview.data: if search.listview.data:
view.append('1') view.append('1')
return render_template('results.html', books=results, form=search, query=query, books_all=books_all, searchtype=search.select.data, count = count, whole = whole, percentage = percentage) return render_template('results.html', books=results, form=search, query=query, books_all=books_all, searchtype=search.select.data, count = count, whole = whole, percentage = percentage, light=light)
if search.grid.data: if search.grid.data:
view.append('2') view.append('2')
return render_template('results_grid.html', books=results, form=search, query=query, books_all=books_all, searchtype=search.select.data, count = count, whole = whole, percentage = percentage) return render_template('results_grid.html', books=results, form=search, query=query, books_all=books_all, searchtype=search.select.data, count = count, whole = whole, percentage = percentage, light=light)
if request.method == 'POST': if request.method == 'POST':
newmsg = 'searched for: ' + search.search.data newmsg = 'searched for: ' + search.search.data
@ -570,10 +598,10 @@ def search_results(searchtype, query, viewby):
return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data, viewby=viewby))) return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data, viewby=viewby)))
if viewby == '2': if viewby == '2':
return render_template('results_grid.html', form=search, books=results, books_all=books_all, searchtype=search.select.data, query=query, count = count, whole = whole, percentage = percentage) return render_template('results_grid.html', form=search, books=results, books_all=books_all, searchtype=search.select.data, query=query, count = count, whole = whole, percentage = percentage, light=light)
else: else:
return render_template('results.html', form=search, books=results, books_all=books_all, searchtype=search.select.data, query=query, count = count, whole = whole, percentage = percentage) return render_template('results.html', form=search, books=results, books_all=books_all, searchtype=search.select.data, query=query, count = count, whole = whole, percentage = percentage, light=light)
autocomplete_suggestions = [] autocomplete_suggestions = []
autocomplete.load() autocomplete.load()
@ -599,22 +627,24 @@ def autocomplete_search():
## STACKS! ## STACKS!
@app.route('/add_to_stack/<int:id>', methods=['GET', 'POST']) @app.route('/add_to_stack/<int:id>', methods=['GET', 'POST'])
@check_light
def add_to_stack(id): def add_to_stack(id):
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
add_form = AddtoStackForm(request.form) add_form = AddtoStackForm(request.form)
add_form.select_stack.choices = [(stack.id, stack.stack_name) for stack in stacks] add_form.select_stack.choices = [(stack.id, stack.stack_name) for stack in stacks]
if request.method == 'GET': if request.method == 'GET':
book = Book.query.get(id) book = Book.query.get(id)
return render_template('add_to_stacks.html', id=id, stacks=stacks, book=book, add_form=add_form) return render_template('add_to_stacks.html', id=id, stacks=stacks, book=book, add_form=add_form, light=light)
else: else:
stack = Stack.query.get(int(add_form.select_stack.data)) stack = Stack.query.get(int(add_form.select_stack.data))
book = Book.query.get(id) book = Book.query.get(id)
stack.books.append(book) stack.books.append(book)
db.session.commit() db.session.commit()
return render_template('show_stack_detail.html', stack=stack) return render_template('show_stack_detail.html', stack=stack, light=light)
@app.route('/export/csv', methods=['GET']) @app.route('/export/csv', methods=['GET'])
@check_light
def export_csv(): def export_csv():
output = io.StringIO() output = io.StringIO()
#fieldnames = ['title', 'authors', 'file', 'fileformat', 'category', 'year_published', 'description' ] #fieldnames = ['title', 'authors', 'file', 'fileformat', 'category', 'year_published', 'description' ]
@ -650,6 +680,7 @@ def export_csv():
import codecs import codecs
@app.route('/import/csv', methods= ['POST','GET']) @app.route('/import/csv', methods= ['POST','GET'])
@check_light
def import_csv(): def import_csv():
if request.method == 'POST': if request.method == 'POST':
if 'file' not in request.files: if 'file' not in request.files:
@ -664,18 +695,34 @@ def import_csv():
print("allreadyexists") print("allreadyexists")
else: else:
cover = '' cover = ''
if row['file']: if row['file'] == '':
file = 'potential.pdf'
file_extension = '.pdf'
ptitle = row['title']
pbook = Potential(ptitle)
db.session.add(pbook)
db.session.commit()
pbooks = Potential.query.all()
template = 'app/templates/potential_pdf.html'
html_string = render_template('potential_pdf.html', pbooks = pbooks)
html = HTML(string=html_string)
html.write_pdf(target='app/uploads/potential.pdf')
else:
fullpath = os.path.join(app.config['UPLOAD_FOLDER'], row['file']) fullpath = os.path.join(app.config['UPLOAD_FOLDER'], row['file'])
name, file_extension = os.path.splitext(row['file']) name, file_extension = os.path.splitext(row['file'])
print ('get_cover', fullpath, name) print ('get_cover', fullpath, name)
cover = get_cover(fullpath, name) cover = get_cover(fullpath, name)
file = str(id) + "_" + row['file']
if row['year_published']: if row['year_published']:
year_published = int(row['year_published']) year_published = int(row['year_published'])
else: else:
year_published = None; year_published = None;
book = Book(row['title'], row['file'], cover, row['fileformat'], row['category'],year_published, None, None, None, None, None, None) book = Book(row['title'], file, cover, row['fileformat'], row['category'],year_published, None, None, None, None, None)
if row['scapeX']:
book.scapeX = float(row['scapeX']) book.scapeX = float(row['scapeX'])
if row['scapeY']:
book.scapeY = float(row['scapeY']) book.scapeY = float(row['scapeY'])
db.session.add(book) db.session.add(book)
@ -690,10 +737,11 @@ def import_csv():
db.session.add(a) db.session.add(a)
book.authors.append(a) book.authors.append(a)
db.session.commit() db.session.commit()
return render_template('import_csv.html', numberadded=numberadded) return render_template('import_csv.html', numberadded=numberadded, light=light)
@app.route('/empty_catalogue487352698237465', methods= ['POST','GET']) @app.route('/emptycataloguexpubxpubfuck', methods= ['POST','GET'])
@check_light
def empty_catalogue(): def empty_catalogue():
meta = db.metadata meta = db.metadata
for table in reversed(meta.sorted_tables): for table in reversed(meta.sorted_tables):
@ -737,12 +785,6 @@ def get_chat():
# The functions below should be applicable to all Flask apps. # The functions below should be applicable to all Flask apps.
### ###
@app.route('/<file_name>.txt')
def send_text_file(file_name):
"""Send your static text file."""
file_dot_text = file_name + '.txt'
return app.send_static_file(file_dot_text)
@app.after_request @app.after_request
def add_header(response): def add_header(response):
@ -751,14 +793,14 @@ def add_header(response):
and also to cache the rendered page for 10 minutes. and also to cache the rendered page for 10 minutes.
""" """
response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1' response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
response.headers['Cache-Control'] = 'public, max-age=600' response.headers['Cache-Control'] = 'no-cache'
return response return response
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(error): def page_not_found(error):
"""Custom 404 page.""" """Custom 404 page."""
return render_template('404.html'), 404 return render_template('404.html', light=light), 404
### SOCKET for the chat ### SOCKET for the chat

@ -20,7 +20,7 @@ with open(args.csv) as f:
print ('get_cover', fullpath, name) print ('get_cover', fullpath, name)
cover = get_cover(fullpath, name) cover = get_cover(fullpath, name)
book = Book(row['Title'], row['Filename'], cover, row['Format'], row['Category'], None, None, None, None, None, None, None) book = Book(row['Title'], row['Filename'], cover, row['Format'], row['Category'], None, None, None, None, None, None)
db.session.add(book) db.session.add(book)
authors = row['Author'].split(',') authors = row['Author'].split(',')

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
rm app/mydatabase.db #rm app/mydatabase.db
mkdir -p app/uploads/cover mkdir -p app/uploads/cover
chmod 777 app/uploads/ chmod 777 app/uploads/
chmod 777 app/uploads/cover chmod 777 app/uploads/cover

Binary file not shown.
Loading…
Cancel
Save