czaks
8 years ago
121 changed files with 4568 additions and 1143 deletions
Binary file not shown.
@ -0,0 +1,82 @@ |
|||||
|
/* |
||||
|
* catalog-search.js |
||||
|
* - Search and filters threads when on catalog view |
||||
|
* - Optional shortcuts 's' and 'esc' to open and close the search. |
||||
|
* |
||||
|
* Usage: |
||||
|
* $config['additional_javascript'][] = 'js/jquery.min.js'; |
||||
|
* $config['additional_javascript'][] = 'js/comment-toolbar.js'; |
||||
|
*/ |
||||
|
if (active_page == 'catalog') { |
||||
|
onready(function () { |
||||
|
'use strict'; |
||||
|
|
||||
|
// 'true' = enable shortcuts
|
||||
|
var useKeybinds = true; |
||||
|
|
||||
|
// trigger the search 400ms after last keystroke
|
||||
|
var delay = 400; |
||||
|
var timeoutHandle; |
||||
|
|
||||
|
//search and hide none matching threads
|
||||
|
function filter(search_term) { |
||||
|
$('.replies').each(function () { |
||||
|
var subject = $(this).children('.intro').text().toLowerCase(); |
||||
|
var comment = $(this).clone().children().remove(':lt(2)').end().text().trim().toLowerCase(); |
||||
|
search_term = search_term.toLowerCase(); |
||||
|
|
||||
|
if (subject.indexOf(search_term) == -1 && comment.indexOf(search_term) == -1) { |
||||
|
$(this).parents('div[id="Grid"]>.mix').css('display', 'none'); |
||||
|
} else { |
||||
|
$(this).parents('div[id="Grid"]>.mix').css('display', 'inline-block'); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function searchToggle() { |
||||
|
var button = $('#catalog_search_button')[0]; |
||||
|
|
||||
|
if (!button.dataset.expanded) { |
||||
|
button.dataset.expanded = '1'; |
||||
|
button.innerText = 'Close'; |
||||
|
$('.catalog_search').append(' <input id="search_field" style="border: inset 1px;">'); |
||||
|
$('#search_field').focus(); |
||||
|
} else { |
||||
|
delete button.dataset.expanded; |
||||
|
button.innerText = 'Search'; |
||||
|
$('.catalog_search').children().last().remove(); |
||||
|
$('div[id="Grid"]>.mix').each(function () { $(this).css('display', 'inline-block'); }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
$('.threads').before('<span class="catalog_search">[<a id="catalog_search_button" style="text-decoration:none; cursor:pointer;"></a>]</span>'); |
||||
|
$('#catalog_search_button').text('Search'); |
||||
|
|
||||
|
$('#catalog_search_button').on('click', searchToggle); |
||||
|
$('.catalog_search').on('keyup', 'input#search_field', function (e) { |
||||
|
window.clearTimeout(timeoutHandle); |
||||
|
timeoutHandle = window.setTimeout(filter, 400, e.target.value); |
||||
|
}); |
||||
|
|
||||
|
if (useKeybinds) { |
||||
|
// 's'
|
||||
|
$('body').on('keydown', function (e) { |
||||
|
if (e.which === 83 && e.target.tagName === 'BODY' && !(e.ctrlKey || e.altKey || e.shiftKey)) { |
||||
|
e.preventDefault(); |
||||
|
if ($('#search_field').length !== 0) { |
||||
|
$('#search_field').focus(); |
||||
|
} else { |
||||
|
searchToggle(); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
// 'esc'
|
||||
|
$('.catalog_search').on('keydown', 'input#search_field', function (e) { |
||||
|
if (e.which === 27 && !(e.ctrlKey || e.altKey || e.shiftKey)) { |
||||
|
window.clearTimeout(timeoutHandle); |
||||
|
searchToggle(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
@ -0,0 +1,191 @@ |
|||||
|
/* |
||||
|
* file-selector.js - Add support for drag and drop file selection, and paste from clipbboard on supported browsers. |
||||
|
* |
||||
|
* Usage: |
||||
|
* $config['additional_javascript'][] = 'js/jquery.min.js'; |
||||
|
* $config['additional_javascript'][] = 'js/file-selector.js'; |
||||
|
*/ |
||||
|
function init_file_selector(max_images) { |
||||
|
|
||||
|
$(document).ready(function () { |
||||
|
// add options panel item
|
||||
|
if (window.Options && Options.get_tab('general')) { |
||||
|
Options.extend_tab('general', '<label id="file-drag-drop"><input type="checkbox">' + _('Drag and drop file selection') + '</label>'); |
||||
|
|
||||
|
$('#file-drag-drop>input').on('click', function() { |
||||
|
if ($('#file-drag-drop>input').is(':checked')) { |
||||
|
localStorage.file_dragdrop = 'true'; |
||||
|
} else { |
||||
|
localStorage.file_dragdrop = 'false'; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (typeof localStorage.file_dragdrop === 'undefined') localStorage.file_dragdrop = 'true'; |
||||
|
if (localStorage.file_dragdrop === 'true') $('#file-drag-drop>input').prop('checked', true); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// disabled by user, or incompatible browser.
|
||||
|
if (localStorage.file_dragdrop == 'false' || !(window.URL.createObjectURL && window.File)) |
||||
|
return; |
||||
|
|
||||
|
// multipost not enabled
|
||||
|
if (typeof max_images == 'undefined') { |
||||
|
var max_images = 1; |
||||
|
} |
||||
|
|
||||
|
$('<div class="dropzone-wrap" style="display: none;">'+ |
||||
|
'<div class="dropzone" tabindex="0">'+ |
||||
|
'<div class="file-hint">'+_('Select/drop/paste files here')+'</div>'+ |
||||
|
'<div class="file-thumbs"></div>'+ |
||||
|
'</div>'+ |
||||
|
'</div>'+ |
||||
|
'</div>').prependTo('#upload td'); |
||||
|
|
||||
|
var files = []; |
||||
|
$('#upload_file').remove(); // remove the original file selector
|
||||
|
$('.dropzone-wrap').css('user-select', 'none').show(); // let jquery add browser specific prefix
|
||||
|
|
||||
|
function addFile(file) { |
||||
|
if (files.length == max_images) |
||||
|
return; |
||||
|
|
||||
|
files.push(file); |
||||
|
addThumb(file); |
||||
|
} |
||||
|
|
||||
|
function removeFile(file) { |
||||
|
files.splice(files.indexOf(file), 1); |
||||
|
} |
||||
|
|
||||
|
function getThumbElement(file) { |
||||
|
return $('.tmb-container').filter(function(){return($(this).data('file-ref')==file);}); |
||||
|
} |
||||
|
|
||||
|
function addThumb(file) { |
||||
|
|
||||
|
var fileName = (file.name.length < 24) ? file.name : file.name.substr(0, 22) + '…'; |
||||
|
var fileType = file.type.split('/')[0]; |
||||
|
var fileExt = file.type.split('/')[1]; |
||||
|
var $container = $('<div>') |
||||
|
.addClass('tmb-container') |
||||
|
.data('file-ref', file) |
||||
|
.append( |
||||
|
$('<div>').addClass('remove-btn').html('✖'), |
||||
|
$('<div>').addClass('file-tmb'), |
||||
|
$('<div>').addClass('tmb-filename').html(fileName) |
||||
|
) |
||||
|
.appendTo('.file-thumbs'); |
||||
|
|
||||
|
var $fileThumb = $container.find('.file-tmb'); |
||||
|
if (fileType == 'image') { |
||||
|
// if image file, generate thumbnail
|
||||
|
var objURL = window.URL.createObjectURL(file); |
||||
|
$fileThumb.css('background-image', 'url('+ objURL +')'); |
||||
|
} else { |
||||
|
$fileThumb.html('<span>' + fileExt.toUpperCase() + '</span>'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
$(document).on('ajax_before_post', function (e, formData) { |
||||
|
for (var i=0; i<max_images; i++) { |
||||
|
var key = 'file'; |
||||
|
if (i > 0) key += i + 1; |
||||
|
if (typeof files[i] === 'undefined') break; |
||||
|
formData.append(key, files[i]); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// clear file queue and UI on success
|
||||
|
$(document).on('ajax_after_post', function () { |
||||
|
files = []; |
||||
|
$('.file-thumbs').empty(); |
||||
|
}); |
||||
|
|
||||
|
var dragCounter = 0; |
||||
|
var dropHandlers = { |
||||
|
dragenter: function (e) { |
||||
|
e.stopPropagation(); |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
if (dragCounter === 0) $('.dropzone').addClass('dragover'); |
||||
|
dragCounter++; |
||||
|
}, |
||||
|
dragover: function (e) { |
||||
|
// needed for webkit to work
|
||||
|
e.stopPropagation(); |
||||
|
e.preventDefault(); |
||||
|
}, |
||||
|
dragleave: function (e) { |
||||
|
e.stopPropagation(); |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
dragCounter--; |
||||
|
if (dragCounter === 0) $('.dropzone').removeClass('dragover'); |
||||
|
}, |
||||
|
drop: function (e) { |
||||
|
e.stopPropagation(); |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
$('.dropzone').removeClass('dragover'); |
||||
|
dragCounter = 0; |
||||
|
|
||||
|
var fileList = e.originalEvent.dataTransfer.files; |
||||
|
for (var i=0; i<fileList.length; i++) { |
||||
|
addFile(fileList[i]); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// attach handlers
|
||||
|
$(document).on(dropHandlers); |
||||
|
|
||||
|
$(document).on('click', '.dropzone .remove-btn', function (e) { |
||||
|
e.stopPropagation(); |
||||
|
|
||||
|
var file = $(e.target).parent().data('file-ref'); |
||||
|
|
||||
|
getThumbElement(file).remove(); |
||||
|
removeFile(file); |
||||
|
}); |
||||
|
|
||||
|
$(document).on('keypress click', '.dropzone', function (e) { |
||||
|
e.stopPropagation(); |
||||
|
|
||||
|
// accept mouse click or Enter
|
||||
|
if ((e.which != 1 || e.target.className != 'file-hint') && |
||||
|
e.which != 13) |
||||
|
return; |
||||
|
|
||||
|
var $fileSelector = $('<input type="file" multiple>'); |
||||
|
|
||||
|
$fileSelector.on('change', function (e) { |
||||
|
if (this.files.length > 0) { |
||||
|
for (var i=0; i<this.files.length; i++) { |
||||
|
addFile(this.files[i]); |
||||
|
} |
||||
|
} |
||||
|
$(this).remove(); |
||||
|
}); |
||||
|
|
||||
|
$fileSelector.click(); |
||||
|
}); |
||||
|
|
||||
|
$(document).on('paste', function (e) { |
||||
|
var clipboard = e.originalEvent.clipboardData; |
||||
|
if (typeof clipboard.items != 'undefined' && clipboard.items.length != 0) { |
||||
|
|
||||
|
//Webkit
|
||||
|
for (var i=0; i<clipboard.items.length; i++) { |
||||
|
if (clipboard.items[i].kind != 'file') |
||||
|
continue; |
||||
|
|
||||
|
//convert blob to file
|
||||
|
var file = new File([clipboard.items[i].getAsFile()], 'ClipboardImage.png', {type: 'image/png'}); |
||||
|
addFile(file); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
} |
@ -0,0 +1,165 @@ |
|||||
|
if (active_page == 'index' || active_page == 'thread') |
||||
|
$(function(){ |
||||
|
|
||||
|
var gallery_view = false; |
||||
|
|
||||
|
$('hr:first').before('<div id="gallery-view" style="text-align:right"><a class="unimportant" href="javascript:void(0)">-</a></div>'); |
||||
|
$('#gallery-view a').html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode")).click(function() { |
||||
|
gallery_view = !gallery_view; |
||||
|
$(this).html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode")); |
||||
|
toggle_gview(document); |
||||
|
}); |
||||
|
|
||||
|
var toggle_gview = function(elem) { |
||||
|
if (gallery_view) { |
||||
|
$(elem).find('img.post-image').parent().each(function() { |
||||
|
this.oldonclick = this.onclick; |
||||
|
this.onclick = handle_click; |
||||
|
$(this).attr('data-galid', Math.random()); |
||||
|
}); |
||||
|
} |
||||
|
else { |
||||
|
$(elem).find('img.post-image').parent().each(function() { |
||||
|
if (this.onclick == handle_click) this.onclick = this.oldonclick; |
||||
|
}); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
$(document).on('new_post', toggle_gview); |
||||
|
|
||||
|
var gallery_opened = false; |
||||
|
|
||||
|
var handle_click = function(e) { |
||||
|
e.stopPropagation(); |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
if (!gallery_opened) open_gallery(); |
||||
|
|
||||
|
gallery_setimage($(this).attr('data-galid')); |
||||
|
}; |
||||
|
|
||||
|
var handler, images, active, toolbar; |
||||
|
|
||||
|
var open_gallery = function() { |
||||
|
$('body').css('overflow', 'hidden'); |
||||
|
|
||||
|
gallery_opened = true; |
||||
|
|
||||
|
handler = $("<div id='alert_handler'></div>").hide().appendTo('body').css('text-align', 'left'); |
||||
|
|
||||
|
$("<div id='alert_background'></div>").click(close_gallery).appendTo(handler); |
||||
|
|
||||
|
images = $("<div id='gallery_images'></div>").appendTo(handler); |
||||
|
toolbar = $("<div id='gallery_toolbar'></div>").appendTo(handler); |
||||
|
active = $("<div id='gallery_main'></div>").appendTo(handler); |
||||
|
|
||||
|
active.on('click', function() { |
||||
|
close_gallery(); |
||||
|
}); |
||||
|
|
||||
|
$('img.post-image').parent().each(function() { |
||||
|
var thumb = $(this).find('img').attr('src'); |
||||
|
|
||||
|
var i = $('<img>').appendTo(images); |
||||
|
i.attr('src', thumb); |
||||
|
i.attr('data-galid-th', $(this).attr('data-galid')); |
||||
|
|
||||
|
i.on('click', function(e) { |
||||
|
gallery_setimage($(this).attr('data-galid-th')); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
$("<a href='javascript:void(0)'><i class='fa fa-times'></i></div>") |
||||
|
.click(close_gallery).appendTo(toolbar); |
||||
|
|
||||
|
$('body').on('keydown.gview', function(e) { |
||||
|
if (e.which == 39 || e.which == 40) { // right or down arrow
|
||||
|
gallery_setimage(+1); |
||||
|
e.preventDefault(); |
||||
|
} |
||||
|
else if (e.which == 37 || e.which == 38) { // left or up arrow
|
||||
|
gallery_setimage(-1); |
||||
|
e.preventDefault(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
handler.fadeIn(400); |
||||
|
}; |
||||
|
|
||||
|
var gallery_setimage = function(a) { |
||||
|
if (a == +1 || a == -1) { |
||||
|
var meth = (a == -1) ? 'prev' : 'next'; |
||||
|
a = $('#gallery_images img.active')[meth]().attr('data-galid-th'); |
||||
|
if (!a) return; |
||||
|
} |
||||
|
|
||||
|
$('#gallery_images img.active').removeClass('active'); |
||||
|
|
||||
|
var thumb = $('#gallery_images [data-galid-th="'+a+'"]'); |
||||
|
var elem = $('a[data-galid="'+a+'"]'); |
||||
|
|
||||
|
thumb.addClass('active'); |
||||
|
|
||||
|
var topscroll = thumb.position().top + images.scrollTop(); |
||||
|
topscroll -= images.height() / 2; |
||||
|
topscroll += thumb.height() / 2; |
||||
|
images.animate({'scrollTop': topscroll}, 300); |
||||
|
|
||||
|
var img = elem.attr('href'); |
||||
|
|
||||
|
active.find('img, video').fadeOut(200, function() { $(this).remove(); }); |
||||
|
|
||||
|
var i; |
||||
|
if (img.match(/player\.php/)) { |
||||
|
img = img.replace(/.*player\.php\?v=|&t=.*/g, ''); |
||||
|
} |
||||
|
if (img.match(/\.webm$|\.mp4$|\.ogv$/i)) { // We are handling video nao
|
||||
|
i = $('<video>'); |
||||
|
i.attr('src', img); |
||||
|
i.attr('autoplay', true); |
||||
|
i.attr('controls', true); |
||||
|
i.appendTo(active); |
||||
|
i.hide(); |
||||
|
} |
||||
|
else { // Just a plain image
|
||||
|
i = $('<img>'); |
||||
|
i.attr('src', img); |
||||
|
i.appendTo(active); |
||||
|
i.hide(); |
||||
|
} |
||||
|
|
||||
|
// Let's actually preload the next few images
|
||||
|
var nextimg = $('#gallery_images active'); |
||||
|
for (var j = 0; j < 3; j++) { |
||||
|
nextimg = nextimg.next(); |
||||
|
var attr; |
||||
|
if (attr = nextimg.attr('data-gaild-th')) { |
||||
|
var href = $('a[data-galid="'+attr+'"]').attr('href'); |
||||
|
if (href.match(/\.webm|\.mp4|\.ogv/i)) { j--; continue; } |
||||
|
if ($('[data-galid-preload="'+attr+'"]').length) continue; |
||||
|
var img = $('<img>').attr('src', href).attr('data-galid-preload', attr).hide().appendTo('body').on('load', function() { $(this).remove(); }); |
||||
|
} |
||||
|
else break; |
||||
|
} |
||||
|
|
||||
|
i.one('load canplay', function() { |
||||
|
i.css('left', 'calc(50% - '+i.width()+'px / 2)'); |
||||
|
i.css('top', 'calc(50% - '+i.height()+'px / 2)'); |
||||
|
i.fadeIn(200); |
||||
|
}).on('click', function(e) { |
||||
|
e.stopPropagation(); |
||||
|
gallery_setimage(+1); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
var close_gallery = function() { |
||||
|
$('body').css('overflow', 'auto'); |
||||
|
|
||||
|
gallery_opened = false; |
||||
|
|
||||
|
$('body').off('keydown.gview'); |
||||
|
|
||||
|
handler.fadeOut(400, function() { handler.remove(); }); |
||||
|
}; |
||||
|
|
||||
|
}); |
@ -0,0 +1,182 @@ |
|||||
|
/* image-hover.js |
||||
|
* This script is copied almost verbatim from https://github.com/Pashe/8chanX/blob/2-0/8chan-x.user.js
|
||||
|
* All I did was remove the sprintf dependency and integrate it into 8chan's Options as opposed to Pashe's. |
||||
|
* I also changed initHover() to also bind on new_post. |
||||
|
* Thanks Pashe for using WTFPL. |
||||
|
*/ |
||||
|
|
||||
|
if (active_page === "catalog" || active_page === "thread" || active_page === "index") { |
||||
|
$(document).on('ready', function(){ |
||||
|
|
||||
|
if (window.Options && Options.get_tab('general')) { |
||||
|
Options.extend_tab("general", |
||||
|
"<fieldset><legend>Image hover</legend>" |
||||
|
+ ("<label class='image-hover' id='imageHover'><input type='checkbox' /> "+_('Image hover')+"</label>") |
||||
|
+ ("<label class='image-hover' id='catalogImageHover'><input type='checkbox' /> "+_('Image hover on catalog')+"</label>") |
||||
|
+ ("<label class='image-hover' id='imageHoverFollowCursor'><input type='checkbox' /> "+_('Image hover should follow cursor')+"</label>") |
||||
|
+ "</fieldset>"); |
||||
|
} |
||||
|
|
||||
|
$('.image-hover').on('change', function(){ |
||||
|
var setting = $(this).attr('id'); |
||||
|
|
||||
|
localStorage[setting] = $(this).children('input').is(':checked'); |
||||
|
}); |
||||
|
|
||||
|
if (!localStorage.imageHover || !localStorage.catalogImageHover || !localStorage.imageHoverFollowCursor) { |
||||
|
localStorage.imageHover = 'false'; |
||||
|
localStorage.catalogImageHover = 'false'; |
||||
|
localStorage.imageHoverFollowCursor = 'false'; |
||||
|
} |
||||
|
|
||||
|
if (getSetting('imageHover')) $('#imageHover>input').prop('checked', 'checked'); |
||||
|
if (getSetting('catalogImageHover')) $('#catalogImageHover>input').prop('checked', 'checked'); |
||||
|
if (getSetting('imageHoverFollowCursor')) $('#imageHoverFollowCursor>input').prop('checked', 'checked'); |
||||
|
|
||||
|
function getFileExtension(filename) { //Pashe, WTFPL
|
||||
|
if (filename.match(/\.([a-z0-9]+)(&loop.*)?$/i) !== null) { |
||||
|
return filename.match(/\.([a-z0-9]+)(&loop.*)?$/i)[1]; |
||||
|
} else if (filename.match(/https?:\/\/(www\.)?youtube.com/)) { |
||||
|
return 'Youtube'; |
||||
|
} else { |
||||
|
return "unknown: " + filename; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function isImage(fileExtension) { //Pashe, WTFPL
|
||||
|
return ($.inArray(fileExtension, ["jpg", "jpeg", "gif", "png"]) !== -1); |
||||
|
} |
||||
|
|
||||
|
function isVideo(fileExtension) { //Pashe, WTFPL
|
||||
|
return ($.inArray(fileExtension, ["webm", "mp4"]) !== -1); |
||||
|
} |
||||
|
|
||||
|
function isOnCatalog() { |
||||
|
return window.active_page === "catalog"; |
||||
|
} |
||||
|
|
||||
|
function isOnThread() { |
||||
|
return window.active_page === "thread"; |
||||
|
} |
||||
|
|
||||
|
function getSetting(key) { |
||||
|
return (localStorage[key] == 'true'); |
||||
|
} |
||||
|
|
||||
|
function initImageHover() { //Pashe, influenced by tux, et al, WTFPL
|
||||
|
if (!getSetting("imageHover") && !getSetting("catalogImageHover")) {return;} |
||||
|
|
||||
|
var selectors = []; |
||||
|
|
||||
|
if (getSetting("imageHover")) {selectors.push("img.post-image", "canvas.post-image");} |
||||
|
if (getSetting("catalogImageHover") && isOnCatalog()) { |
||||
|
selectors.push(".thread-image"); |
||||
|
$(".theme-catalog div.thread").css("position", "inherit"); |
||||
|
} |
||||
|
|
||||
|
function bindEvents(el) { |
||||
|
$(el).find(selectors.join(", ")).each(function () { |
||||
|
if ($(this).parent().data("expanded")) {return;} |
||||
|
|
||||
|
var $this = $(this); |
||||
|
|
||||
|
$this.on("mousemove", imageHoverStart); |
||||
|
$this.on("mouseout", imageHoverEnd); |
||||
|
$this.on("click", imageHoverEnd); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
bindEvents(document.body); |
||||
|
$(document).on('new_post', function(e, post) { |
||||
|
bindEvents(post); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function imageHoverStart(e) { //Pashe, anonish, WTFPL
|
||||
|
var hoverImage = $("#chx_hoverImage"); |
||||
|
|
||||
|
if (hoverImage.length) { |
||||
|
if (getSetting("imageHoverFollowCursor")) { |
||||
|
var scrollTop = $(window).scrollTop(); |
||||
|
var imgY = e.pageY; |
||||
|
var imgTop = imgY; |
||||
|
var windowWidth = $(window).width(); |
||||
|
var imgWidth = hoverImage.width() + e.pageX; |
||||
|
|
||||
|
if (imgY < scrollTop + 15) { |
||||
|
imgTop = scrollTop; |
||||
|
} else if (imgY > scrollTop + $(window).height() - hoverImage.height() - 15) { |
||||
|
imgTop = scrollTop + $(window).height() - hoverImage.height() - 15; |
||||
|
} |
||||
|
|
||||
|
if (imgWidth > windowWidth) { |
||||
|
hoverImage.css({ |
||||
|
'left': (e.pageX + (windowWidth - imgWidth)), |
||||
|
'top' : imgTop, |
||||
|
}); |
||||
|
} else { |
||||
|
hoverImage.css({ |
||||
|
'left': e.pageX, |
||||
|
'top' : imgTop, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
hoverImage.appendTo($("body")); |
||||
|
} |
||||
|
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var $this = $(this); |
||||
|
|
||||
|
var fullUrl; |
||||
|
if ($this.parent().attr("href").match("src")) { |
||||
|
fullUrl = $this.parent().attr("href"); |
||||
|
} else if (isOnCatalog()) { |
||||
|
fullUrl = $this.attr("data-fullimage"); |
||||
|
if (!isImage(getFileExtension(fullUrl))) {fullUrl = $this.attr("src");} |
||||
|
} |
||||
|
|
||||
|
if (isVideo(getFileExtension(fullUrl))) {return;} |
||||
|
|
||||
|
hoverImage = $('<img id="chx_hoverImage" src="'+fullUrl+'" />'); |
||||
|
|
||||
|
if (getSetting("imageHoverFollowCursor")) { |
||||
|
var size = $this.parents('.file').find('.unimportant').text().match(/\b(\d+)x(\d+)\b/), |
||||
|
maxWidth = $(window).width(), |
||||
|
maxHeight = $(window).height(); |
||||
|
|
||||
|
var scale = Math.min(1, maxWidth / size[1], maxHeight / size[2]); |
||||
|
hoverImage.css({ |
||||
|
"position" : "absolute", |
||||
|
"z-index" : 101, |
||||
|
"pointer-events": "none", |
||||
|
"width" : size[1] + "px", |
||||
|
"height" : size[2] + "px", |
||||
|
"max-width" : (size[1] * scale) + "px", |
||||
|
"max-height" : (size[2] * scale) + "px", |
||||
|
'left' : e.pageX, |
||||
|
'top' : imgTop, |
||||
|
}); |
||||
|
} else { |
||||
|
hoverImage.css({ |
||||
|
"position" : "fixed", |
||||
|
"top" : 0, |
||||
|
"right" : 0, |
||||
|
"z-index" : 101, |
||||
|
"pointer-events": "none", |
||||
|
"max-width" : "100%", |
||||
|
"max-height" : "100%", |
||||
|
}); |
||||
|
} |
||||
|
hoverImage.appendTo($("body")); |
||||
|
if (isOnThread()) {$this.css("cursor", "none");} |
||||
|
} |
||||
|
|
||||
|
function imageHoverEnd() { //Pashe, WTFPL
|
||||
|
$("#chx_hoverImage").remove(); |
||||
|
} |
||||
|
|
||||
|
initImageHover(); |
||||
|
}); |
||||
|
} |
@ -0,0 +1,116 @@ |
|||||
|
/***************************************************************** |
||||
|
* ------- WARNING! --------- * |
||||
|
***************************************************************** |
||||
|
* This script is at the current time undocumented and * |
||||
|
* unsupported. It is still a work in progress and will likely * |
||||
|
* change. You are on your own. * |
||||
|
*****************************************************************/ |
||||
|
|
||||
|
+function() { |
||||
|
|
||||
|
var uniq = function(a) { |
||||
|
var b = {}; |
||||
|
var c = []; |
||||
|
a.forEach(function(i) { |
||||
|
if (!b[i]) { |
||||
|
c.push(i); |
||||
|
b[i] = true; |
||||
|
} |
||||
|
}); |
||||
|
return c; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
if (active_page == 'thread' || active_page == 'index') { |
||||
|
var board = null; |
||||
|
|
||||
|
$(function() { |
||||
|
board = $('input[name="board"]').first().val(); |
||||
|
}); |
||||
|
|
||||
|
$(document).on('ajax_after_post', function(e, r) { |
||||
|
var threads = JSON.parse(localStorage.obthreads || '[]'); |
||||
|
|
||||
|
var thread = null; |
||||
|
if (active_page == 'index') { |
||||
|
thread = r.id|0; |
||||
|
} |
||||
|
else { |
||||
|
thread = $('[id^="thread_"]').first().attr('id').replace("thread_", "")|0; |
||||
|
} |
||||
|
|
||||
|
threads.push([board, thread]); |
||||
|
threads = uniq(threads); |
||||
|
localStorage.obthreads = JSON.stringify(threads); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
var loaded = false; |
||||
|
$(function() { |
||||
|
loaded = true; |
||||
|
}); |
||||
|
|
||||
|
var activate = function() { |
||||
|
if (document.location.hash != '#own') return false; |
||||
|
|
||||
|
if (loaded) late_activate(); |
||||
|
else $(function() { late_activate(); }); |
||||
|
|
||||
|
return true; |
||||
|
}; |
||||
|
|
||||
|
var late_activate = function() { |
||||
|
$('[id^="thread_"]').remove(); |
||||
|
|
||||
|
var threads = JSON.parse(localStorage.obthreads || '[]'); |
||||
|
|
||||
|
threads.forEach(function(v) { |
||||
|
var board = v[0]; |
||||
|
var thread = v[1]; |
||||
|
var url = "/"+board+"/res/"+thread+".html"; |
||||
|
|
||||
|
$.get(url, function(html) { |
||||
|
var s = $(html).find('[id^="thread_"]'); |
||||
|
|
||||
|
s[0].bumptime = (new Date(s.find("time").last().attr("datetime"))).getTime(); |
||||
|
|
||||
|
var added = false; |
||||
|
$('[id^="thread_"]').each(function() { |
||||
|
if (added) return; |
||||
|
if (s[0].bumptime > this.bumptime) { |
||||
|
added = true; |
||||
|
s.insertBefore(this); |
||||
|
} |
||||
|
}); |
||||
|
if (!added) { |
||||
|
s.appendTo('[name="postcontrols"]'); |
||||
|
} |
||||
|
|
||||
|
s.find('.post.reply').addClass('hidden').hide().slice(-3).removeClass('hidden').show(); |
||||
|
|
||||
|
s.find('.post.reply.hidden').next().addClass('hidden').hide(); // Hide <br> elements
|
||||
|
|
||||
|
var posts_omitted = s.find('.post.reply.hidden').length; |
||||
|
var images_omitted = s.find('.post.reply.hidden img').length; |
||||
|
|
||||
|
if (posts_omitted > 0) { |
||||
|
var omitted = $(fmt('<span class="omitted">'+_('{0} posts and {1} images omitted.')+' '+_('Click reply to view.')+'</span>', |
||||
|
[posts_omitted, images_omitted])); |
||||
|
|
||||
|
omitted.appendTo(s.find('.post.op')); |
||||
|
} |
||||
|
|
||||
|
var reply = $('<a href="'+url+'">['+_('Reply')+']</a>').appendTo(s.find('.intro').first()); |
||||
|
|
||||
|
$(document).trigger('new_post', s[0]); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
$(window).on("hashchange", function() { |
||||
|
return !activate(); |
||||
|
}); |
||||
|
activate(); |
||||
|
|
||||
|
|
||||
|
}(); |
@ -0,0 +1,116 @@ |
|||||
|
/* |
||||
|
* thread-stats.js |
||||
|
* - Adds statistics of the thread below the posts area |
||||
|
* - Shows ID post count beside each postID on hover |
||||
|
* |
||||
|
* Usage: |
||||
|
* $config['additional_javascript'][] = 'js/jquery.min.js'; |
||||
|
* $config['additional_javascript'][] = 'js/thread-stats.js'; |
||||
|
*/ |
||||
|
if (active_page == 'thread') { |
||||
|
$(document).ready(function(){ |
||||
|
//check if page uses unique ID
|
||||
|
var IDsupport = ($('.poster_id').length > 0); |
||||
|
var thread_id = (document.location.pathname + document.location.search).split('/'); |
||||
|
thread_id = thread_id[thread_id.length -1].split('+')[0].split('-')[0].split('.')[0]; |
||||
|
|
||||
|
$('.boardlist.bottom, footer') |
||||
|
.first() |
||||
|
.before('<div id="thread_stats"></div>'); |
||||
|
var el = $('#thread_stats'); |
||||
|
el.prepend(_('Page')+' <span id="thread_stats_page">?</span>'); |
||||
|
if (IDsupport){ |
||||
|
el.prepend('<span id="thread_stats_uids">0</span> UIDs | '); |
||||
|
} |
||||
|
el.prepend('<span id="thread_stats_images">0</span> '+_('images')+' | '); |
||||
|
el.prepend('<span id="thread_stats_posts">0</span> '+_('replies')+' | '); |
||||
|
delete el; |
||||
|
function update_thread_stats(){ |
||||
|
var op = $('#thread_'+ thread_id +' > div.post.op:not(.post-hover):not(.inline)').first(); |
||||
|
var replies = $('#thread_'+ thread_id +' > div.post.reply:not(.post-hover):not(.inline)'); |
||||
|
// post count
|
||||
|
$('#thread_stats_posts').text(replies.length); |
||||
|
// image count
|
||||
|
$('#thread_stats_images').text(replies.filter(function(){ |
||||
|
return $(this).find('> .files').text().trim() != false; |
||||
|
}).length); |
||||
|
// unique ID count
|
||||
|
if (IDsupport) { |
||||
|
var opID = op.find('> .intro > .poster_id').text(); |
||||
|
var ids = {}; |
||||
|
replies.each(function(){ |
||||
|
var cur = $(this).find('> .intro > .poster_id'); |
||||
|
var curID = cur.text(); |
||||
|
if (ids[curID] === undefined) { |
||||
|
ids[curID] = 0; |
||||
|
} |
||||
|
ids[curID]++; |
||||
|
}); |
||||
|
if (ids[opID] === undefined) { |
||||
|
ids[opID] = 0; |
||||
|
} |
||||
|
ids[opID]++; |
||||
|
var cur = op.find('>.intro >.poster_id'); |
||||
|
cur.find('+.posts_by_id').remove(); |
||||
|
cur.after('<span class="posts_by_id"> ('+ ids[cur.text()] +')</span>'); |
||||
|
replies.each(function(){ |
||||
|
cur = $(this).find('>.intro >.poster_id'); |
||||
|
cur.find('+.posts_by_id').remove(); |
||||
|
cur.after('<span class="posts_by_id"> ('+ ids[cur.text()] +')</span>'); |
||||
|
}); |
||||
|
var size = function(obj) { |
||||
|
var size = 0, key; |
||||
|
for (key in obj) { |
||||
|
if (obj.hasOwnProperty(key)) size++; |
||||
|
} |
||||
|
return size; |
||||
|
}; |
||||
|
$('#thread_stats_uids').text(size(ids)); |
||||
|
} |
||||
|
var board_name = $('input[name="board"]').val(); |
||||
|
$.getJSON('//'+ document.location.host +'/'+ board_name +'/threads.json').success(function(data){ |
||||
|
var found, page = '???'; |
||||
|
for (var i=0;data[i];i++){ |
||||
|
var threads = data[i].threads; |
||||
|
for (var j=0; threads[j]; j++){ |
||||
|
if (parseInt(threads[j].no) == parseInt(thread_id)) { |
||||
|
page = data[i].page +1; |
||||
|
found = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (found) break; |
||||
|
} |
||||
|
$('#thread_stats_page').text(page); |
||||
|
if (!found) $('#thread_stats_page').css('color','red'); |
||||
|
else $('#thread_stats_page').css('color',''); |
||||
|
}); |
||||
|
} |
||||
|
// load the current page the thread is on.
|
||||
|
// uses ajax call so it gets loaded on a delay (depending on network resources available)
|
||||
|
var thread_stats_page_timer = setInterval(function(){ |
||||
|
var board_name = $('input[name="board"]').val(); |
||||
|
$.getJSON('//'+ document.location.host +'/'+ board_name +'/threads.json').success(function(data){ |
||||
|
var found, page = '???'; |
||||
|
for (var i=0;data[i];i++){ |
||||
|
var threads = data[i].threads; |
||||
|
for (var j=0; threads[j]; j++){ |
||||
|
if (parseInt(threads[j].no) == parseInt(thread_id)) { |
||||
|
page = data[i].page +1; |
||||
|
found = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (found) break; |
||||
|
} |
||||
|
$('#thread_stats_page').text(page); |
||||
|
if (!found) $('#thread_stats_page').css('color','red'); |
||||
|
else $('#thread_stats_page').css('color',''); |
||||
|
}); |
||||
|
},30000); |
||||
|
$('body').append('<style>.posts_by_id{display:none;}.poster_id:hover+.posts_by_id{display:initial}</style>'); |
||||
|
update_thread_stats(); |
||||
|
$('#update_thread').click(update_thread_stats); |
||||
|
$(document).on('new_post',update_thread_stats); |
||||
|
}); |
||||
|
} |
@ -1 +1 @@ |
|||||
Subproject commit 2c272dffca0f3d7b7163bd82ba15629f54409278 |
Subproject commit f11220032e7edb8349516d3751d3aaee0fd0de68 |
@ -0,0 +1,216 @@ |
|||||
|
<?php |
||||
|
require_once("inc/functions.php"); |
||||
|
|
||||
|
if (!$config['smart_build']) { |
||||
|
die('You need to enable $config["smart_build"]'); |
||||
|
} |
||||
|
|
||||
|
$config['smart_build'] = false; // Let's disable it, so we can build the page for real |
||||
|
|
||||
|
function after_open_board() { global $config; |
||||
|
$config['smart_build'] = false; |
||||
|
}; |
||||
|
|
||||
|
function sb_board($b, $page = 1) { global $config, $build_pages; $page = (int)$page; |
||||
|
if ($page < 1) return false; |
||||
|
if (!openBoard($b)) return false; |
||||
|
if ($page > $config['max_pages']) return false; |
||||
|
$config['try_smarter'] = true; |
||||
|
$build_pages = array($page); |
||||
|
buildIndex("skip"); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_api_board($b, $page = 0) { $page = (int)$page; |
||||
|
return sb_board($b, $page + 1); |
||||
|
} |
||||
|
|
||||
|
function sb_thread($b, $thread, $slugcheck = false) { global $config; $thread = (int)$thread; |
||||
|
if ($thread < 1) return false; |
||||
|
|
||||
|
if (!preg_match('/^'.$config['board_regex'].'$/u', $b)) return false; |
||||
|
|
||||
|
if (Cache::get("thread_exists_".$b."_".$thread) == "no") return false; |
||||
|
|
||||
|
$query = prepare(sprintf("SELECT MAX(`id`) AS `max` FROM ``posts_%s``", $b)); |
||||
|
if (!$query->execute()) return false; |
||||
|
|
||||
|
$s = $query->fetch(PDO::FETCH_ASSOC); |
||||
|
$max = $s['max']; |
||||
|
|
||||
|
if ($thread > $max) return false; |
||||
|
|
||||
|
$query = prepare(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL", $b)); |
||||
|
$query->bindValue(':id', $thread); |
||||
|
|
||||
|
if (!$query->execute() || !$query->fetch(PDO::FETCH_ASSOC) ) { |
||||
|
Cache::set("thread_exists_".$b."_".$thread, "no"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if ($slugcheck && $config['slugify']) { |
||||
|
global $request; |
||||
|
|
||||
|
$link = link_for(array("id" => $thread), $slugcheck === 50, array("uri" => $b)); |
||||
|
$link = "/".$b."/".$config['dir']['res'].$link; |
||||
|
|
||||
|
if ($link != $request) { |
||||
|
header("Location: $link", true, 301); |
||||
|
die(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ($slugcheck == 50) { // Should we really generate +50 page? Maybe there are not enough posts anyway |
||||
|
global $request; |
||||
|
$r = str_replace("+50", "", $request); |
||||
|
$r = substr($r, 1); // Cut the slash |
||||
|
|
||||
|
if (file_exists($r)) return false; |
||||
|
} |
||||
|
|
||||
|
if (!openBoard($b)) return false; |
||||
|
buildThread($thread); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_thread_slugcheck($b, $thread) { |
||||
|
return sb_thread($b, $thread, true); |
||||
|
} |
||||
|
function sb_thread_slugcheck50($b, $thread) { |
||||
|
return sb_thread($b, $thread, 50); |
||||
|
} |
||||
|
|
||||
|
function sb_api($b) { global $config, $build_pages; |
||||
|
if (!openBoard($b)) return false; |
||||
|
$config['try_smarter'] = true; |
||||
|
$build_pages = array(-1); |
||||
|
buildIndex(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_ukko() { |
||||
|
rebuildTheme("ukko", "post-thread"); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_catalog($b) { |
||||
|
if (!openBoard($b)) return false; |
||||
|
|
||||
|
rebuildTheme("catalog", "post-thread", $b); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_recent() { |
||||
|
rebuildTheme("recent", "post-thread"); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function sb_sitemap() { |
||||
|
rebuildTheme("sitemap", "all"); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
$entrypoints = array(); |
||||
|
|
||||
|
$entrypoints['/%b/'] = 'sb_board'; |
||||
|
$entrypoints['/%b/'.$config['file_index']] = 'sb_board'; |
||||
|
$entrypoints['/%b/'.$config['file_page']] = 'sb_board'; |
||||
|
$entrypoints['/%b/%d.json'] = 'sb_api_board'; |
||||
|
if ($config['api']['enabled']) { |
||||
|
$entrypoints['/%b/threads.json'] = 'sb_api'; |
||||
|
$entrypoints['/%b/catalog.json'] = 'sb_api'; |
||||
|
} |
||||
|
|
||||
|
$entrypoints['/%b/'.$config['dir']['res'].$config['file_page']] = 'sb_thread_slugcheck'; |
||||
|
$entrypoints['/%b/'.$config['dir']['res'].$config['file_page50']] = 'sb_thread_slugcheck50'; |
||||
|
if ($config['slugify']) { |
||||
|
$entrypoints['/%b/'.$config['dir']['res'].$config['file_page_slug']] = 'sb_thread_slugcheck'; |
||||
|
$entrypoints['/%b/'.$config['dir']['res'].$config['file_page50_slug']] = 'sb_thread_slugcheck50'; |
||||
|
} |
||||
|
if ($config['api']['enabled']) { |
||||
|
$entrypoints['/%b/'.$config['dir']['res'].'%d.json'] = 'sb_thread'; |
||||
|
} |
||||
|
|
||||
|
$entrypoints['/*/'] = 'sb_ukko'; |
||||
|
$entrypoints['/*/index.html'] = 'sb_ukko'; |
||||
|
$entrypoints['/recent.html'] = 'sb_recent'; |
||||
|
$entrypoints['/%b/catalog.html'] = 'sb_catalog'; |
||||
|
$entrypoints['/sitemap.xml'] = 'sb_sitemap'; |
||||
|
|
||||
|
$reached = false; |
||||
|
|
||||
|
$request = $_SERVER['REQUEST_URI']; |
||||
|
list($request) = explode('?', $request); |
||||
|
|
||||
|
foreach ($entrypoints as $id => $fun) { |
||||
|
$id = '@^' . preg_quote($id, '@') . '$@u'; |
||||
|
|
||||
|
$id = str_replace('%b', '('.$config['board_regex'].')', $id); |
||||
|
$id = str_replace('%d', '([0-9]+)', $id); |
||||
|
$id = str_replace('%s', '[a-zA-Z0-9-]+', $id); |
||||
|
|
||||
|
$matches = null; |
||||
|
|
||||
|
if (preg_match ($id, $request, $matches)) { |
||||
|
array_shift($matches); |
||||
|
|
||||
|
$reached = call_user_func_array($fun, $matches); |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function die_404() { global $config; |
||||
|
if (!$config['page_404']) { |
||||
|
header("HTTP/1.1 404 Not Found"); |
||||
|
header("Status: 404 Not Found"); |
||||
|
echo "<h1>404 Not Found</h1><p>Page doesn't exist<hr><address>vichan</address>"; |
||||
|
} |
||||
|
else { |
||||
|
header("Location: ".$config['page_404']); |
||||
|
} |
||||
|
header("X-Accel-Expires: 120"); |
||||
|
die(); |
||||
|
} |
||||
|
|
||||
|
if ($reached) { |
||||
|
if ($request[strlen($request)-1] == '/') { |
||||
|
$request .= 'index.html'; |
||||
|
} |
||||
|
$request = '.'.$request; |
||||
|
|
||||
|
if (!file_exists($request)) { |
||||
|
die_404(); |
||||
|
} |
||||
|
|
||||
|
header("HTTP/1.1 200 OK"); |
||||
|
header("Status: 200 OK"); |
||||
|
if (preg_match('/\.json$/', $request)) { |
||||
|
header("Content-Type", "application/json"); |
||||
|
} |
||||
|
elseif (preg_match('/\.js$/', $request)) { |
||||
|
header("Content-Type", "text/javascript; charset=utf-8"); |
||||
|
} |
||||
|
elseif (preg_match('/\.xml$/', $request)) { |
||||
|
header("Content-Type", "application/xml"); |
||||
|
} |
||||
|
else { |
||||
|
header("Content-Type", "text/html; charset=utf-8"); |
||||
|
} |
||||
|
header("Cache-Control: public, nocache, no-cache, max-age=0, must-revalidate"); |
||||
|
header("Expires: Fri, 22 Feb 1991 06:00:00 GMT"); |
||||
|
header("Last-Modified: ".date('r', filemtime($request))); |
||||
|
|
||||
|
//if (isset ($_SERVER['HTTP_ACCEPT_ENCODING']) && preg_match('/gzip/', $_SERVER['HTTP_ACCEPT_ENCODING']) && file_exists($request.".gz")) { |
||||
|
// header("Content-Encoding: gzip"); |
||||
|
// $file = fopen($request.".gz", 'r'); |
||||
|
//} |
||||
|
//else { |
||||
|
$file = fopen($request, 'r'); |
||||
|
//} |
||||
|
fpassthru($file); |
||||
|
fclose($file); |
||||
|
} |
||||
|
else { |
||||
|
die_404(); |
||||
|
} |
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 348 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,34 @@ |
|||||
|
// Animated Icons |
||||
|
// -------------------------- |
||||
|
|
||||
|
.@{fa-css-prefix}-spin { |
||||
|
-webkit-animation: fa-spin 2s infinite linear; |
||||
|
animation: fa-spin 2s infinite linear; |
||||
|
} |
||||
|
|
||||
|
.@{fa-css-prefix}-pulse { |
||||
|
-webkit-animation: fa-spin 1s infinite steps(8); |
||||
|
animation: fa-spin 1s infinite steps(8); |
||||
|
} |
||||
|
|
||||
|
@-webkit-keyframes fa-spin { |
||||
|
0% { |
||||
|
-webkit-transform: rotate(0deg); |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
-webkit-transform: rotate(359deg); |
||||
|
transform: rotate(359deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes fa-spin { |
||||
|
0% { |
||||
|
-webkit-transform: rotate(0deg); |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
-webkit-transform: rotate(359deg); |
||||
|
transform: rotate(359deg); |
||||
|
} |
||||
|
} |
@ -1,20 +1,26 @@ |
|||||
// Mixins |
// Mixins |
||||
// -------------------------- |
// -------------------------- |
||||
|
|
||||
|
.fa-icon() { |
||||
|
display: inline-block; |
||||
|
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration |
||||
|
font-size: inherit; // can't have font-size inherit on line above, so need to override |
||||
|
text-rendering: auto; // optimizelegibility throws things off #1094 |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
|
||||
|
} |
||||
|
|
||||
.fa-icon-rotate(@degrees, @rotation) { |
.fa-icon-rotate(@degrees, @rotation) { |
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); |
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); |
||||
-webkit-transform: rotate(@degrees); |
-webkit-transform: rotate(@degrees); |
||||
-moz-transform: rotate(@degrees); |
|
||||
-ms-transform: rotate(@degrees); |
-ms-transform: rotate(@degrees); |
||||
-o-transform: rotate(@degrees); |
|
||||
transform: rotate(@degrees); |
transform: rotate(@degrees); |
||||
} |
} |
||||
|
|
||||
.fa-icon-flip(@horiz, @vert, @rotation) { |
.fa-icon-flip(@horiz, @vert, @rotation) { |
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); |
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); |
||||
-webkit-transform: scale(@horiz, @vert); |
-webkit-transform: scale(@horiz, @vert); |
||||
-moz-transform: scale(@horiz, @vert); |
|
||||
-ms-transform: scale(@horiz, @vert); |
-ms-transform: scale(@horiz, @vert); |
||||
-o-transform: scale(@horiz, @vert); |
|
||||
transform: scale(@horiz, @vert); |
transform: scale(@horiz, @vert); |
||||
} |
} |
||||
|
@ -0,0 +1,34 @@ |
|||||
|
// Spinning Icons |
||||
|
// -------------------------- |
||||
|
|
||||
|
.#{$fa-css-prefix}-spin { |
||||
|
-webkit-animation: fa-spin 2s infinite linear; |
||||
|
animation: fa-spin 2s infinite linear; |
||||
|
} |
||||
|
|
||||
|
.#{$fa-css-prefix}-pulse { |
||||
|
-webkit-animation: fa-spin 1s infinite steps(8); |
||||
|
animation: fa-spin 1s infinite steps(8); |
||||
|
} |
||||
|
|
||||
|
@-webkit-keyframes fa-spin { |
||||
|
0% { |
||||
|
-webkit-transform: rotate(0deg); |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
-webkit-transform: rotate(359deg); |
||||
|
transform: rotate(359deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes fa-spin { |
||||
|
0% { |
||||
|
-webkit-transform: rotate(0deg); |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
-webkit-transform: rotate(359deg); |
||||
|
transform: rotate(359deg); |
||||
|
} |
||||
|
} |
@ -1,20 +1,26 @@ |
|||||
// Mixins |
// Mixins |
||||
// -------------------------- |
// -------------------------- |
||||
|
|
||||
|
@mixin fa-icon() { |
||||
|
display: inline-block; |
||||
|
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration |
||||
|
font-size: inherit; // can't have font-size inherit on line above, so need to override |
||||
|
text-rendering: auto; // optimizelegibility throws things off #1094 |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
|
||||
|
} |
||||
|
|
||||
@mixin fa-icon-rotate($degrees, $rotation) { |
@mixin fa-icon-rotate($degrees, $rotation) { |
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); |
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); |
||||
-webkit-transform: rotate($degrees); |
-webkit-transform: rotate($degrees); |
||||
-moz-transform: rotate($degrees); |
|
||||
-ms-transform: rotate($degrees); |
-ms-transform: rotate($degrees); |
||||
-o-transform: rotate($degrees); |
|
||||
transform: rotate($degrees); |
transform: rotate($degrees); |
||||
} |
} |
||||
|
|
||||
@mixin fa-icon-flip($horiz, $vert, $rotation) { |
@mixin fa-icon-flip($horiz, $vert, $rotation) { |
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); |
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); |
||||
-webkit-transform: scale($horiz, $vert); |
-webkit-transform: scale($horiz, $vert); |
||||
-moz-transform: scale($horiz, $vert); |
|
||||
-ms-transform: scale($horiz, $vert); |
-ms-transform: scale($horiz, $vert); |
||||
-o-transform: scale($horiz, $vert); |
|
||||
transform: scale($horiz, $vert); |
transform: scale($horiz, $vert); |
||||
} |
} |
||||
|
@ -0,0 +1,15 @@ |
|||||
|
<table class='fileboard'> |
||||
|
<tr> |
||||
|
<th> <!-- checkbox --> |
||||
|
<th>{% trans %}No.{% endtrans %} |
||||
|
<th>{% trans %}Name{% endtrans %} |
||||
|
<th>{% trans %}File{% endtrans %} |
||||
|
<th>{% trans %}Tag{% endtrans %} |
||||
|
<th>{% trans %}Subject{% endtrans %} |
||||
|
<th>{% trans %}Size{% endtrans %} |
||||
|
<th>{% trans %}Date{% endtrans %} |
||||
|
<th>{% trans %}Replies{% endtrans %} |
||||
|
<th> <!-- reply --> |
||||
|
</tr> |
||||
|
{{ body }} |
||||
|
</table> |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue