Gallery.coffee and ImageCommon.coffee
This commit is contained in:
parent
28f694591d
commit
bc67db84af
@ -115,7 +115,7 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, Callbacks, CatalogLinks, CatalogThread, Clone, Color, Conf, Config, CrossOrigin, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, E, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Flash, Fourchan, Gallery, Get, GlobalMessage, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, JSColor, Keybinds, Labels, Linkify, Main, MarkNewIPs, MascotTools, Mascots, Menu, Nav, Navigate, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteInline, QuoteMarkers, QuotePreview, QuoteStrikeThrough, QuoteThreading, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, SimpleDict, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadStats, ThreadUpdater, ThreadWatcher, Time, TrashQueue, UI, Unread, Video, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, Callbacks, CatalogLinks, CatalogThread, Clone, Color, Conf, Config, CrossOrigin, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, E, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Flash, Fourchan, Gallery, Get, GlobalMessage, Header, IDColor, ImageCommon, ImageExpand, ImageHover, ImageLoader, Index, JSColor, Keybinds, Labels, Linkify, Main, MarkNewIPs, MascotTools, Mascots, Menu, Nav, Navigate, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteInline, QuoteMarkers, QuotePreview, QuoteStrikeThrough, QuoteThreading, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, SimpleDict, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadStats, ThreadUpdater, ThreadWatcher, Time, TrashQueue, UI, Unread, Video, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
__slice = [].slice,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
@ -10337,8 +10337,8 @@
|
||||
|
||||
Gallery = {
|
||||
init: function() {
|
||||
var el;
|
||||
if (g.BOARD === 'f' || !Conf['Gallery']) {
|
||||
var el, _ref;
|
||||
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Gallery']) || g.BOARD === 'f') {
|
||||
return;
|
||||
}
|
||||
el = $.el('a', {
|
||||
@ -10360,7 +10360,7 @@
|
||||
return;
|
||||
}
|
||||
if (Gallery.nodes) {
|
||||
Gallery.generateThumb($('.file', this.nodes.root));
|
||||
Gallery.generateThumb(this);
|
||||
Gallery.nodes.total.textContent = Gallery.images.length;
|
||||
}
|
||||
if (!Conf['Image Expansion']) {
|
||||
@ -10368,14 +10368,30 @@
|
||||
}
|
||||
},
|
||||
build: function(image) {
|
||||
var cb, createSubEntry, dialog, el, file, i, key, menuButton, name, nodes, value, _i, _len, _ref, _ref1;
|
||||
var candidate, cb, dialog, entry, file, key, menuButton, nodes, post, thumb, value, _i, _j, _len, _len1, _ref, _ref1, _ref2;
|
||||
if (Conf['Fullscreen Gallery']) {
|
||||
$.one(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', function() {
|
||||
return $.on(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close);
|
||||
});
|
||||
if (typeof doc.mozRequestFullScreen === "function") {
|
||||
doc.mozRequestFullScreen();
|
||||
}
|
||||
if (typeof doc.webkitRequestFullScreen === "function") {
|
||||
doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
}
|
||||
Gallery.images = [];
|
||||
nodes = Gallery.nodes = {};
|
||||
Gallery.fullIDs = {};
|
||||
Gallery.slideshow = false;
|
||||
nodes.el = dialog = $.el('div', {
|
||||
id: 'a-gallery',
|
||||
innerHTML: "<div class=gal-viewport>\n <span class=gal-buttons>\n <a class=\"menu-button\" href=\"javascript:;\"><i></i></a>\n <a href=javascript:; class=gal-close>×</a>\n </span>\n <a class=gal-name target=\"_blank\"></a>\n <span class=gal-count>\n <span class='count'></span> / <span class='total'></span>\n </span>\n <div class=gal-prev></div>\n <div class=gal-image>\n <a href=javascript:;><img></a>\n </div>\n <div class=gal-next></div>\n</div>\n<div class=gal-thumbnails></div>"
|
||||
id: 'a-gallery'
|
||||
});
|
||||
$.extend(dialog, {
|
||||
innerHTML: "<div class=\"gal-viewport\">\r<span class=\"gal-buttons\">\r<a href=\"javascript:;\" class=\"gal-start\" title=\"Start slideshow (S to toggle)\"><i></i></a>\r<a href=\"javascript:;\" class=\"gal-stop\" title=\"Stop slideshow (S to toggle)\"><i></i></a>\r<a href=\"javascript:;\" class=\"menu-button\"><i></i></a>\r<a href=\"javascript:;\" class=\"gal-close\">×</a>\r</span>\r<a class=\"gal-name\" target=\"_blank\"></a>\r<span class=\"gal-count\">\r<span class=\"count\"></span> / <span class=\"total\"></span>\r</span>\r<div class=\"gal-prev\"></div>\r<div class=\"gal-image\">\r<a href=\"javascript:;\"><img></a>\r</div>\r<div class=\"gal-next\"></div>\r</div>\r<div class=\"gal-thumbnails\"></div>"
|
||||
});
|
||||
_ref = {
|
||||
buttons: '.gal-buttons',
|
||||
frame: '.gal-image',
|
||||
name: '.gal-name',
|
||||
count: '.count',
|
||||
@ -10389,58 +10405,71 @@
|
||||
nodes[key] = $(value, dialog);
|
||||
}
|
||||
menuButton = $('.menu-button', dialog);
|
||||
nodes.menu = new UI.Menu();
|
||||
nodes.menu = new UI.Menu('gallery');
|
||||
cb = Gallery.cb;
|
||||
$.on(nodes.frame, 'click', cb.blank);
|
||||
$.on(nodes.next, 'click', cb.advance);
|
||||
$.on(nodes.next, 'click', cb.click);
|
||||
$.on($('.gal-prev', dialog), 'click', cb.prev);
|
||||
$.on($('.gal-next', dialog), 'click', cb.next);
|
||||
$.on($('.gal-start', dialog), 'click', cb.start);
|
||||
$.on($('.gal-stop', dialog), 'click', cb.stop);
|
||||
$.on($('.gal-close', dialog), 'click', cb.close);
|
||||
$.on(menuButton, 'click', function(e) {
|
||||
return nodes.menu.toggle(e, this, g);
|
||||
});
|
||||
createSubEntry = Gallery.menu.createSubEntry;
|
||||
for (name in Config.gallery) {
|
||||
el = createSubEntry(name).el;
|
||||
nodes.menu.addEntry({
|
||||
el: el,
|
||||
order: 0
|
||||
});
|
||||
_ref1 = Gallery.menu.createSubEntries();
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
entry = _ref1[_i];
|
||||
entry.order = 0;
|
||||
nodes.menu.addEntry(entry);
|
||||
}
|
||||
$.on(d, 'keydown', cb.keybinds);
|
||||
$.off(d, 'keydown', Keybinds.keydown);
|
||||
_ref1 = $$('.post .file');
|
||||
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
|
||||
file = _ref1[i];
|
||||
if (!$('.fileDeletedRes, .fileDeleted', file)) {
|
||||
Gallery.generateThumb(file);
|
||||
if (Conf['Keybinds']) {
|
||||
$.off(d, 'keydown', Keybinds.keydown);
|
||||
}
|
||||
_ref2 = $$('.post .file');
|
||||
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
|
||||
file = _ref2[_j];
|
||||
post = Get.postFromNode(file);
|
||||
if (post.file.isDead) {
|
||||
continue;
|
||||
}
|
||||
Gallery.generateThumb(post);
|
||||
if (!image && Gallery.fullIDs[post.fullID]) {
|
||||
candidate = post.file.thumb.parentNode;
|
||||
if (Header.getTopOf(candidate) + candidate.getBoundingClientRect().height >= 0) {
|
||||
image = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
$.addClass(doc, 'gallery-open');
|
||||
$.add(d.body, dialog);
|
||||
nodes.thumbs.scrollTop = 0;
|
||||
nodes.current.parentElement.scrollTop = 0;
|
||||
Gallery.cb.open.call(image ? $("[href*='" + image.pathname + "']", nodes.thumbs) : Gallery.images[0]);
|
||||
d.body.style.overflow = 'hidden';
|
||||
return nodes.total.textContent = i;
|
||||
if (image) {
|
||||
thumb = $("[href='" + image.href + "']", nodes.thumbs);
|
||||
}
|
||||
thumb || (thumb = Gallery.images[Gallery.images.length - 1]);
|
||||
if (thumb) {
|
||||
Gallery.open(thumb);
|
||||
}
|
||||
doc.style.overflow = 'hidden';
|
||||
return nodes.total.textContent = Gallery.images.length;
|
||||
},
|
||||
generateThumb: function(file) {
|
||||
var post, thumb, thumbImg, title;
|
||||
post = Get.postFromNode(file);
|
||||
if (!(post.file && (post.file.isImage || post.file.isVideo || Conf['PDF in Gallery']))) {
|
||||
generateThumb: function(post) {
|
||||
var thumb, thumbImg, _ref, _ref1;
|
||||
if (post.isClone || post.isHidden && !(((_ref = post.file) != null ? _ref.isImage : void 0) || ((_ref1 = post.file) != null ? _ref1.isVideo : void 0) || Conf['PDF in Gallery'])) {
|
||||
return;
|
||||
}
|
||||
title = ($('.fileText a', file)).textContent;
|
||||
Gallery.fullIDs[post.fullID] = true;
|
||||
thumb = $.el('a', {
|
||||
className: 'gal-thumb',
|
||||
href: post.file.URL,
|
||||
target: '_blank',
|
||||
title: title
|
||||
title: post.file.name
|
||||
});
|
||||
thumb.dataset.id = Gallery.images.length;
|
||||
thumb.dataset.post = post.fullID;
|
||||
if (post.file.isVideo) {
|
||||
thumb.dataset.isVideo = true;
|
||||
}
|
||||
thumbImg = post.file.thumb.cloneNode(false);
|
||||
thumbImg.style.cssText = '';
|
||||
$.add(thumb, thumbImg);
|
||||
@ -10448,6 +10477,110 @@
|
||||
Gallery.images.push(thumb);
|
||||
return $.add(Gallery.nodes.thumbs, thumb);
|
||||
},
|
||||
open: function(thumb) {
|
||||
var el, elType, file, name, newID, nodes, oldID, post, slideshow, _base, _ref;
|
||||
nodes = Gallery.nodes;
|
||||
name = nodes.name;
|
||||
oldID = +nodes.current.dataset.id;
|
||||
newID = +thumb.dataset.id;
|
||||
slideshow = Gallery.slideshow && (newID > oldID || (oldID === Gallery.images.length - 1 && newID === 0));
|
||||
if (el = $('.gal-highlight', nodes.thumbs)) {
|
||||
$.rmClass(el, 'gal-highlight');
|
||||
}
|
||||
$.addClass(thumb, 'gal-highlight');
|
||||
elType = /\.webm$/.test(thumb.href) ? 'video' : /\.pdf$/.test(thumb.href) ? 'iframe' : 'image';
|
||||
$[elType === 'iframe' ? 'addClass' : 'rmClass'](doc, 'gal-pdf');
|
||||
file = $.el(elType, {
|
||||
title: name.download = name.textContent = thumb.title
|
||||
});
|
||||
$.on(file, 'error', (function(_this) {
|
||||
return function() {
|
||||
return Gallery.error(file, thumb);
|
||||
};
|
||||
})(this));
|
||||
file.src = name.href = thumb.href;
|
||||
$.extend(file.dataset, thumb.dataset);
|
||||
if (!nodes.current.error) {
|
||||
if (typeof (_base = nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
}
|
||||
$.replace(nodes.current, file);
|
||||
if (elType === 'video') {
|
||||
file.loop = true;
|
||||
if (Conf['Autoplay']) {
|
||||
file.play();
|
||||
}
|
||||
if (Conf['Show Controls']) {
|
||||
ImageCommon.addControls(file);
|
||||
}
|
||||
}
|
||||
nodes.count.textContent = +thumb.dataset.id + 1;
|
||||
nodes.current = file;
|
||||
nodes.frame.scrollTop = 0;
|
||||
nodes.next.focus();
|
||||
if (slideshow) {
|
||||
Gallery.setupTimer();
|
||||
} else {
|
||||
Gallery.cb.stop();
|
||||
}
|
||||
if (Conf['Scroll to Post'] && (post = (_ref = (post = g.posts[file.dataset.post])) != null ? _ref.nodes.root : void 0)) {
|
||||
Header.scrollTo(post);
|
||||
}
|
||||
return nodes.thumbs.scrollTop = thumb.offsetTop + thumb.offsetHeight / 2 - nodes.thumbs.clientHeight / 2;
|
||||
},
|
||||
error: function(file, thumb) {
|
||||
var _ref;
|
||||
if (((_ref = file.error) != null ? _ref.code : void 0) === MediaError.MEDIA_ERR_DECODE) {
|
||||
return new Notice('error', 'Corrupt or unplayable video', 30);
|
||||
}
|
||||
if (file.src.split('/')[2] !== 'i.4cdn.org') {
|
||||
return;
|
||||
}
|
||||
return ImageCommon.error(file, g.posts[file.dataset.post], null, function(URL) {
|
||||
if (!URL) {
|
||||
return;
|
||||
}
|
||||
thumb.href = URL;
|
||||
if (Gallery.nodes.current === file) {
|
||||
return file.src = URL;
|
||||
}
|
||||
});
|
||||
},
|
||||
cleanupTimer: function() {
|
||||
var current;
|
||||
clearTimeout(Gallery.timeoutID);
|
||||
current = Gallery.nodes.current;
|
||||
$.off(current, 'canplaythrough load', Gallery.startTimer);
|
||||
return $.off(current, 'ended', Gallery.cb.next);
|
||||
},
|
||||
startTimer: function() {
|
||||
return Gallery.timeoutID = setTimeout(Gallery.checkTimer, Gallery.delay * $.SECOND);
|
||||
},
|
||||
setupTimer: function() {
|
||||
var current, isVideo;
|
||||
Gallery.cleanupTimer();
|
||||
current = Gallery.nodes.current;
|
||||
isVideo = current.nodeName === 'VIDEO';
|
||||
if (isVideo) {
|
||||
current.play();
|
||||
}
|
||||
if ((isVideo ? current.readyState >= 4 : current.complete) || current.nodeName === 'IFRAME') {
|
||||
return Gallery.startTimer();
|
||||
} else {
|
||||
return $.on(current, (isVideo ? 'canplaythrough' : 'load'), Gallery.startTimer);
|
||||
}
|
||||
},
|
||||
checkTimer: function() {
|
||||
var current;
|
||||
current = Gallery.nodes.current;
|
||||
if (current.nodeName === 'VIDEO' && !current.paused) {
|
||||
$.on(current, 'ended', Gallery.cb.next);
|
||||
return current.loop = false;
|
||||
} else {
|
||||
return Gallery.cb.next();
|
||||
}
|
||||
},
|
||||
cb: {
|
||||
keybinds: function(e) {
|
||||
var cb, key;
|
||||
@ -10456,7 +10589,7 @@
|
||||
}
|
||||
cb = (function() {
|
||||
switch (key) {
|
||||
case 'Esc':
|
||||
case Conf['Close']:
|
||||
case Conf['Open Gallery']:
|
||||
return Gallery.cb.close;
|
||||
case 'Right':
|
||||
@ -10466,6 +10599,10 @@
|
||||
case 'Left':
|
||||
case '':
|
||||
return Gallery.cb.prev;
|
||||
case Conf['Pause']:
|
||||
return Gallery.cb.pause;
|
||||
case Conf['Slideshow']:
|
||||
return Gallery.cb.toggleSlideshow;
|
||||
}
|
||||
})();
|
||||
if (!cb) {
|
||||
@ -10476,110 +10613,34 @@
|
||||
return cb();
|
||||
},
|
||||
open: function(e) {
|
||||
var el, elType, file, name, nodes, post, rect, top, _base, _ref;
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (!this) {
|
||||
return;
|
||||
if (this) {
|
||||
return Gallery.open(this);
|
||||
}
|
||||
nodes = Gallery.nodes;
|
||||
name = nodes.name;
|
||||
if (el = $('.gal-highlight', nodes.thumbs)) {
|
||||
$.rmClass(el, 'gal-highlight');
|
||||
}
|
||||
$.addClass(this, 'gal-highlight');
|
||||
elType = this.dataset.isVideo ? 'video' : /\.pdf$/.test(this.href) ? 'iframe' : 'img';
|
||||
$[elType === 'iframe' ? 'addClass' : 'rmClass'](nodes.el, 'gal-pdf');
|
||||
file = $.el(elType, {
|
||||
src: name.href = this.href,
|
||||
title: name.download = name.textContent = this.title
|
||||
});
|
||||
$.extend(file.dataset, this.dataset);
|
||||
if (typeof (_base = nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
$.replace(nodes.current, file);
|
||||
if (this.dataset.isVideo) {
|
||||
Video.configure(file);
|
||||
}
|
||||
nodes.count.textContent = +this.dataset.id + 1;
|
||||
nodes.current = file;
|
||||
nodes.frame.scrollTop = 0;
|
||||
nodes.next.focus();
|
||||
if (Conf['Scroll to Post'] && (post = (_ref = (post = g.posts[file.dataset.post])) != null ? _ref.nodes.root : void 0)) {
|
||||
Header.scrollTo(post);
|
||||
}
|
||||
$.on(file, 'error', function() {
|
||||
return Gallery.cb.error(file, thumb);
|
||||
});
|
||||
rect = this.getBoundingClientRect();
|
||||
top = rect.top;
|
||||
if (top > 0) {
|
||||
top += rect.height - doc.clientHeight;
|
||||
if (top < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return nodes.thumbs.scrollTop += top;
|
||||
},
|
||||
image: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return Gallery.build(this);
|
||||
},
|
||||
error: function(img, thumb) {
|
||||
var URL, post, src;
|
||||
post = Get.postFromLink($.el('a', {
|
||||
href: img.dataset.post
|
||||
}));
|
||||
delete post.file.fullImage;
|
||||
src = this.src.split('/');
|
||||
if (src[2] === 'i.4cdn.org') {
|
||||
URL = Redirect.to('file', {
|
||||
boardID: src[3],
|
||||
filename: src[src.length - 1]
|
||||
});
|
||||
if (URL) {
|
||||
thumb.href = URL;
|
||||
if (Gallery.nodes.current !== img) {
|
||||
return;
|
||||
}
|
||||
img.src = URL;
|
||||
return;
|
||||
}
|
||||
if (g.DEAD || post.isDead || post.file.isDead) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return $.ajax("//a.4cdn.org/" + post.board + "/thread/" + post.thread + ".json", {
|
||||
onload: function() {
|
||||
var i, postObj, posts;
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
i = 0;
|
||||
posts = this.response.posts;
|
||||
while (postObj = posts[i++]) {
|
||||
if (postObj.no === post.ID) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!postObj.no) {
|
||||
return post.kill();
|
||||
}
|
||||
if (postObj.filedeleted) {
|
||||
return post.kill(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
prev: function() {
|
||||
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id - 1] || Gallery.images[Gallery.images.length - 1]);
|
||||
},
|
||||
next: function() {
|
||||
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id + 1] || Gallery.images[0]);
|
||||
},
|
||||
enterKey: function() {
|
||||
if (Gallery.nodes.current.paused) {
|
||||
return Gallery.nodes.current.play();
|
||||
} else {
|
||||
return Gallery.cb.next();
|
||||
}
|
||||
},
|
||||
click: function() {
|
||||
return Gallery.cb[Gallery.nodes.current.controls ? 'stop' : 'enterKey']();
|
||||
},
|
||||
toggle: function() {
|
||||
return (Gallery.nodes ? Gallery.cb.close : Gallery.build)();
|
||||
},
|
||||
@ -10588,41 +10649,66 @@
|
||||
return Gallery.cb.close();
|
||||
}
|
||||
},
|
||||
advance: function() {
|
||||
if (Gallery.nodes.current.controls) {
|
||||
return;
|
||||
}
|
||||
if (Gallery.nodes.current.paused) {
|
||||
return Gallery.nodes.current.play();
|
||||
}
|
||||
return Gallery.cb.next();
|
||||
},
|
||||
pause: function() {
|
||||
var current;
|
||||
Gallery.cb.stop();
|
||||
current = Gallery.nodes.current;
|
||||
if (current.nodeType === 'VIDEO') {
|
||||
if (current.nodeName === 'VIDEO') {
|
||||
return current[current.paused ? 'play' : 'pause']();
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
$.addClass(Gallery.nodes.buttons, 'gal-playing');
|
||||
Gallery.slideshow = true;
|
||||
return Gallery.setupTimer();
|
||||
},
|
||||
stop: function() {
|
||||
var current;
|
||||
if (!Gallery.slideshow) {
|
||||
return;
|
||||
}
|
||||
Gallery.cleanupTimer();
|
||||
current = Gallery.nodes.current;
|
||||
current.loop = current.nodeName === 'VIDEO';
|
||||
$.rmClass(Gallery.nodes.buttons, 'gal-playing');
|
||||
return Gallery.slideshow = false;
|
||||
},
|
||||
close: function() {
|
||||
var _base;
|
||||
if (typeof (_base = Gallery.nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
$.rm(Gallery.nodes.el);
|
||||
$.rmClass(doc, 'gallery-open');
|
||||
if (Conf['Fullscreen Gallery']) {
|
||||
$.off(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close);
|
||||
if (typeof d.mozCancelFullScreen === "function") {
|
||||
d.mozCancelFullScreen();
|
||||
}
|
||||
if (typeof d.webkitExitFullscreen === "function") {
|
||||
d.webkitExitFullscreen();
|
||||
}
|
||||
}
|
||||
delete Gallery.nodes;
|
||||
d.body.style.overflow = '';
|
||||
delete Gallery.fullIDs;
|
||||
doc.style.overflow = '';
|
||||
$.off(d, 'keydown', Gallery.cb.keybinds);
|
||||
return $.on(d, 'keydown', Keybinds.keydown);
|
||||
if (Conf['Keybinds']) {
|
||||
$.on(d, 'keydown', Keybinds.keydown);
|
||||
}
|
||||
return clearTimeout(Gallery.timeoutID);
|
||||
},
|
||||
setFitness: function() {
|
||||
return (this.checked ? $.addClass : $.rmClass)(doc, "gal-" + (this.name.toLowerCase().replace(/\s+/g, '-')));
|
||||
},
|
||||
setDelay: function() {
|
||||
return Gallery.delay = +this.value;
|
||||
}
|
||||
},
|
||||
menu: {
|
||||
init: function() {
|
||||
var createSubEntry, el, name, subEntries;
|
||||
if (!Conf['Gallery']) {
|
||||
var createSubEntry, el, name, subEntries, _ref;
|
||||
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Gallery'])) {
|
||||
return;
|
||||
}
|
||||
el = $.el('span', {
|
||||
@ -10655,10 +10741,149 @@
|
||||
return {
|
||||
el: label
|
||||
};
|
||||
},
|
||||
createSubEntries: function() {
|
||||
var delayInput, delayLabel, item, subEntries;
|
||||
subEntries = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'];
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
item = _ref[_i];
|
||||
_results.push(Gallery.menu.createSubEntry(item));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
delayLabel = $.el('label', {
|
||||
innerHTML: "Slide Delay: <input type=\"number\" name=\"Slide Delay\" min=\"0\" step=\"any\" class=\"field\">"
|
||||
});
|
||||
delayInput = delayLabel.firstElementChild;
|
||||
delayInput.value = Gallery.delay;
|
||||
$.on(delayInput, 'change', Gallery.cb.setDelay);
|
||||
$.on(delayInput, 'change', $.cb.value);
|
||||
subEntries.push({
|
||||
el: delayLabel
|
||||
});
|
||||
return subEntries;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ImageCommon = {
|
||||
rewind: function(el) {
|
||||
if (el.nodeName === 'VIDEO') {
|
||||
if (el.readyState >= el.HAVE_METADATA) {
|
||||
return el.currentTime = 0;
|
||||
}
|
||||
} else if (/\.gif$/.test(el.src)) {
|
||||
return $.queueTask(function() {
|
||||
return el.src = el.src;
|
||||
});
|
||||
}
|
||||
},
|
||||
pushCache: function(el) {
|
||||
ImageCommon.cache = el;
|
||||
return $.on(el, 'error', ImageCommon.cacheError);
|
||||
},
|
||||
popCache: function() {
|
||||
var el;
|
||||
el = ImageCommon.cache;
|
||||
$.off(el, 'error', ImageCommon.cacheError);
|
||||
delete ImageCommon.cache;
|
||||
return el;
|
||||
},
|
||||
cacheError: function() {
|
||||
if (ImageCommon.cache === this) {
|
||||
return delete ImageCommon.cache;
|
||||
}
|
||||
},
|
||||
decodeError: function(file, post) {
|
||||
var message, _ref;
|
||||
if (((_ref = file.error) != null ? _ref.code : void 0) !== MediaError.MEDIA_ERR_DECODE) {
|
||||
return false;
|
||||
}
|
||||
if (!(message = $('.warning', post.file.thumb.parentNode))) {
|
||||
message = $.el('div', {
|
||||
className: 'warning'
|
||||
});
|
||||
$.after(post.file.thumb, message);
|
||||
}
|
||||
message.textContent = 'Error: Corrupt or unplayable video';
|
||||
return true;
|
||||
},
|
||||
error: function(file, post, delay, cb) {
|
||||
var URL, redirect, src, timeoutID;
|
||||
src = post.file.URL.split('/');
|
||||
URL = Redirect.to('file', {
|
||||
boardID: post.board.ID,
|
||||
filename: src[src.length - 1]
|
||||
});
|
||||
if (!(Conf['404 Redirect'] && URL && Redirect.securityCheck(URL))) {
|
||||
URL = null;
|
||||
}
|
||||
if ((post.isDead || post.file.isDead) && file.src.split('/')[2] === 'i.4cdn.org') {
|
||||
return cb(URL);
|
||||
}
|
||||
if (delay != null) {
|
||||
timeoutID = setTimeout((function() {
|
||||
return cb(URL);
|
||||
}), delay);
|
||||
}
|
||||
if (post.isDead || post.file.isDead) {
|
||||
return;
|
||||
}
|
||||
redirect = function() {
|
||||
if (file.src.split('/')[2] === 'i.4cdn.org') {
|
||||
if (delay != null) {
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
return cb(URL);
|
||||
}
|
||||
};
|
||||
return $.ajax("//a.4cdn.org/" + post.board + "/thread/" + post.thread + ".json", {
|
||||
onload: function() {
|
||||
var postObj, _i, _len, _ref;
|
||||
if (this.status === 404) {
|
||||
post.kill();
|
||||
}
|
||||
if (this.status !== 200) {
|
||||
return redirect();
|
||||
}
|
||||
_ref = this.response.posts;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
postObj = _ref[_i];
|
||||
if (postObj.no === post.ID) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (postObj.no !== post.ID) {
|
||||
post.kill();
|
||||
return redirect();
|
||||
} else if (postObj.filedeleted) {
|
||||
post.kill(true);
|
||||
return redirect();
|
||||
} else {
|
||||
return URL = post.file.URL;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
addControls: function(video) {
|
||||
var handler;
|
||||
handler = function() {
|
||||
var t;
|
||||
$.off(video, 'mouseover', handler);
|
||||
t = new Date().getTime();
|
||||
return $.asap((function() {
|
||||
return (typeof chrome !== "undefined" && chrome !== null) || (video.readyState >= 3 && video.currentTime <= Math.max(0.1, video.duration - 0.5)) || new Date().getTime() >= t + 1000;
|
||||
}), function() {
|
||||
return video.controls = true;
|
||||
});
|
||||
};
|
||||
return $.on(video, 'mouseover', handler);
|
||||
}
|
||||
};
|
||||
|
||||
ImageExpand = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, Callbacks, CatalogLinks, CatalogThread, Clone, Color, Conf, Config, CrossOrigin, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, E, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Flash, Fourchan, Gallery, Get, GlobalMessage, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, JSColor, Keybinds, Labels, Linkify, Main, MarkNewIPs, MascotTools, Mascots, Menu, Nav, Navigate, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteInline, QuoteMarkers, QuotePreview, QuoteStrikeThrough, QuoteThreading, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, SimpleDict, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadStats, ThreadUpdater, ThreadWatcher, Time, TrashQueue, UI, Unread, Video, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, Callbacks, CatalogLinks, CatalogThread, Clone, Color, Conf, Config, CrossOrigin, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, E, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Flash, Fourchan, Gallery, Get, GlobalMessage, Header, IDColor, ImageCommon, ImageExpand, ImageHover, ImageLoader, Index, JSColor, Keybinds, Labels, Linkify, Main, MarkNewIPs, MascotTools, Mascots, Menu, Nav, Navigate, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteInline, QuoteMarkers, QuotePreview, QuoteStrikeThrough, QuoteThreading, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, SimpleDict, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadStats, ThreadUpdater, ThreadWatcher, Time, TrashQueue, UI, Unread, Video, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
__slice = [].slice,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
@ -10372,8 +10372,8 @@
|
||||
|
||||
Gallery = {
|
||||
init: function() {
|
||||
var el;
|
||||
if (g.BOARD === 'f' || !Conf['Gallery']) {
|
||||
var el, _ref;
|
||||
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Gallery']) || g.BOARD === 'f') {
|
||||
return;
|
||||
}
|
||||
el = $.el('a', {
|
||||
@ -10395,7 +10395,7 @@
|
||||
return;
|
||||
}
|
||||
if (Gallery.nodes) {
|
||||
Gallery.generateThumb($('.file', this.nodes.root));
|
||||
Gallery.generateThumb(this);
|
||||
Gallery.nodes.total.textContent = Gallery.images.length;
|
||||
}
|
||||
if (!Conf['Image Expansion']) {
|
||||
@ -10403,14 +10403,30 @@
|
||||
}
|
||||
},
|
||||
build: function(image) {
|
||||
var cb, createSubEntry, dialog, el, file, i, key, menuButton, name, nodes, value, _i, _len, _ref, _ref1;
|
||||
var candidate, cb, dialog, entry, file, key, menuButton, nodes, post, thumb, value, _i, _j, _len, _len1, _ref, _ref1, _ref2;
|
||||
if (Conf['Fullscreen Gallery']) {
|
||||
$.one(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', function() {
|
||||
return $.on(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close);
|
||||
});
|
||||
if (typeof doc.mozRequestFullScreen === "function") {
|
||||
doc.mozRequestFullScreen();
|
||||
}
|
||||
if (typeof doc.webkitRequestFullScreen === "function") {
|
||||
doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
}
|
||||
Gallery.images = [];
|
||||
nodes = Gallery.nodes = {};
|
||||
Gallery.fullIDs = {};
|
||||
Gallery.slideshow = false;
|
||||
nodes.el = dialog = $.el('div', {
|
||||
id: 'a-gallery',
|
||||
innerHTML: "<div class=gal-viewport>\n <span class=gal-buttons>\n <a class=\"menu-button\" href=\"javascript:;\"><i></i></a>\n <a href=javascript:; class=gal-close>×</a>\n </span>\n <a class=gal-name target=\"_blank\"></a>\n <span class=gal-count>\n <span class='count'></span> / <span class='total'></span>\n </span>\n <div class=gal-prev></div>\n <div class=gal-image>\n <a href=javascript:;><img></a>\n </div>\n <div class=gal-next></div>\n</div>\n<div class=gal-thumbnails></div>"
|
||||
id: 'a-gallery'
|
||||
});
|
||||
$.extend(dialog, {
|
||||
innerHTML: "<div class=\"gal-viewport\">\r<span class=\"gal-buttons\">\r<a href=\"javascript:;\" class=\"gal-start\" title=\"Start slideshow (S to toggle)\"><i></i></a>\r<a href=\"javascript:;\" class=\"gal-stop\" title=\"Stop slideshow (S to toggle)\"><i></i></a>\r<a href=\"javascript:;\" class=\"menu-button\"><i></i></a>\r<a href=\"javascript:;\" class=\"gal-close\">×</a>\r</span>\r<a class=\"gal-name\" target=\"_blank\"></a>\r<span class=\"gal-count\">\r<span class=\"count\"></span> / <span class=\"total\"></span>\r</span>\r<div class=\"gal-prev\"></div>\r<div class=\"gal-image\">\r<a href=\"javascript:;\"><img></a>\r</div>\r<div class=\"gal-next\"></div>\r</div>\r<div class=\"gal-thumbnails\"></div>"
|
||||
});
|
||||
_ref = {
|
||||
buttons: '.gal-buttons',
|
||||
frame: '.gal-image',
|
||||
name: '.gal-name',
|
||||
count: '.count',
|
||||
@ -10424,58 +10440,71 @@
|
||||
nodes[key] = $(value, dialog);
|
||||
}
|
||||
menuButton = $('.menu-button', dialog);
|
||||
nodes.menu = new UI.Menu();
|
||||
nodes.menu = new UI.Menu('gallery');
|
||||
cb = Gallery.cb;
|
||||
$.on(nodes.frame, 'click', cb.blank);
|
||||
$.on(nodes.next, 'click', cb.advance);
|
||||
$.on(nodes.next, 'click', cb.click);
|
||||
$.on($('.gal-prev', dialog), 'click', cb.prev);
|
||||
$.on($('.gal-next', dialog), 'click', cb.next);
|
||||
$.on($('.gal-start', dialog), 'click', cb.start);
|
||||
$.on($('.gal-stop', dialog), 'click', cb.stop);
|
||||
$.on($('.gal-close', dialog), 'click', cb.close);
|
||||
$.on(menuButton, 'click', function(e) {
|
||||
return nodes.menu.toggle(e, this, g);
|
||||
});
|
||||
createSubEntry = Gallery.menu.createSubEntry;
|
||||
for (name in Config.gallery) {
|
||||
el = createSubEntry(name).el;
|
||||
nodes.menu.addEntry({
|
||||
el: el,
|
||||
order: 0
|
||||
});
|
||||
_ref1 = Gallery.menu.createSubEntries();
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
entry = _ref1[_i];
|
||||
entry.order = 0;
|
||||
nodes.menu.addEntry(entry);
|
||||
}
|
||||
$.on(d, 'keydown', cb.keybinds);
|
||||
$.off(d, 'keydown', Keybinds.keydown);
|
||||
_ref1 = $$('.post .file');
|
||||
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
|
||||
file = _ref1[i];
|
||||
if (!$('.fileDeletedRes, .fileDeleted', file)) {
|
||||
Gallery.generateThumb(file);
|
||||
if (Conf['Keybinds']) {
|
||||
$.off(d, 'keydown', Keybinds.keydown);
|
||||
}
|
||||
_ref2 = $$('.post .file');
|
||||
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
|
||||
file = _ref2[_j];
|
||||
post = Get.postFromNode(file);
|
||||
if (post.file.isDead) {
|
||||
continue;
|
||||
}
|
||||
Gallery.generateThumb(post);
|
||||
if (!image && Gallery.fullIDs[post.fullID]) {
|
||||
candidate = post.file.thumb.parentNode;
|
||||
if (Header.getTopOf(candidate) + candidate.getBoundingClientRect().height >= 0) {
|
||||
image = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
$.addClass(doc, 'gallery-open');
|
||||
$.add(d.body, dialog);
|
||||
nodes.thumbs.scrollTop = 0;
|
||||
nodes.current.parentElement.scrollTop = 0;
|
||||
Gallery.cb.open.call(image ? $("[href*='" + image.pathname + "']", nodes.thumbs) : Gallery.images[0]);
|
||||
d.body.style.overflow = 'hidden';
|
||||
return nodes.total.textContent = i;
|
||||
if (image) {
|
||||
thumb = $("[href='" + image.href + "']", nodes.thumbs);
|
||||
}
|
||||
thumb || (thumb = Gallery.images[Gallery.images.length - 1]);
|
||||
if (thumb) {
|
||||
Gallery.open(thumb);
|
||||
}
|
||||
doc.style.overflow = 'hidden';
|
||||
return nodes.total.textContent = Gallery.images.length;
|
||||
},
|
||||
generateThumb: function(file) {
|
||||
var post, thumb, thumbImg, title;
|
||||
post = Get.postFromNode(file);
|
||||
if (!(post.file && (post.file.isImage || post.file.isVideo || Conf['PDF in Gallery']))) {
|
||||
generateThumb: function(post) {
|
||||
var thumb, thumbImg, _ref, _ref1;
|
||||
if (post.isClone || post.isHidden && !(((_ref = post.file) != null ? _ref.isImage : void 0) || ((_ref1 = post.file) != null ? _ref1.isVideo : void 0) || Conf['PDF in Gallery'])) {
|
||||
return;
|
||||
}
|
||||
title = ($('.fileText a', file)).textContent;
|
||||
Gallery.fullIDs[post.fullID] = true;
|
||||
thumb = $.el('a', {
|
||||
className: 'gal-thumb',
|
||||
href: post.file.URL,
|
||||
target: '_blank',
|
||||
title: title
|
||||
title: post.file.name
|
||||
});
|
||||
thumb.dataset.id = Gallery.images.length;
|
||||
thumb.dataset.post = post.fullID;
|
||||
if (post.file.isVideo) {
|
||||
thumb.dataset.isVideo = true;
|
||||
}
|
||||
thumbImg = post.file.thumb.cloneNode(false);
|
||||
thumbImg.style.cssText = '';
|
||||
$.add(thumb, thumbImg);
|
||||
@ -10483,6 +10512,110 @@
|
||||
Gallery.images.push(thumb);
|
||||
return $.add(Gallery.nodes.thumbs, thumb);
|
||||
},
|
||||
open: function(thumb) {
|
||||
var el, elType, file, name, newID, nodes, oldID, post, slideshow, _base, _ref;
|
||||
nodes = Gallery.nodes;
|
||||
name = nodes.name;
|
||||
oldID = +nodes.current.dataset.id;
|
||||
newID = +thumb.dataset.id;
|
||||
slideshow = Gallery.slideshow && (newID > oldID || (oldID === Gallery.images.length - 1 && newID === 0));
|
||||
if (el = $('.gal-highlight', nodes.thumbs)) {
|
||||
$.rmClass(el, 'gal-highlight');
|
||||
}
|
||||
$.addClass(thumb, 'gal-highlight');
|
||||
elType = /\.webm$/.test(thumb.href) ? 'video' : /\.pdf$/.test(thumb.href) ? 'iframe' : 'image';
|
||||
$[elType === 'iframe' ? 'addClass' : 'rmClass'](doc, 'gal-pdf');
|
||||
file = $.el(elType, {
|
||||
title: name.download = name.textContent = thumb.title
|
||||
});
|
||||
$.on(file, 'error', (function(_this) {
|
||||
return function() {
|
||||
return Gallery.error(file, thumb);
|
||||
};
|
||||
})(this));
|
||||
file.src = name.href = thumb.href;
|
||||
$.extend(file.dataset, thumb.dataset);
|
||||
if (!nodes.current.error) {
|
||||
if (typeof (_base = nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
}
|
||||
$.replace(nodes.current, file);
|
||||
if (elType === 'video') {
|
||||
file.loop = true;
|
||||
if (Conf['Autoplay']) {
|
||||
file.play();
|
||||
}
|
||||
if (Conf['Show Controls']) {
|
||||
ImageCommon.addControls(file);
|
||||
}
|
||||
}
|
||||
nodes.count.textContent = +thumb.dataset.id + 1;
|
||||
nodes.current = file;
|
||||
nodes.frame.scrollTop = 0;
|
||||
nodes.next.focus();
|
||||
if (slideshow) {
|
||||
Gallery.setupTimer();
|
||||
} else {
|
||||
Gallery.cb.stop();
|
||||
}
|
||||
if (Conf['Scroll to Post'] && (post = (_ref = (post = g.posts[file.dataset.post])) != null ? _ref.nodes.root : void 0)) {
|
||||
Header.scrollTo(post);
|
||||
}
|
||||
return nodes.thumbs.scrollTop = thumb.offsetTop + thumb.offsetHeight / 2 - nodes.thumbs.clientHeight / 2;
|
||||
},
|
||||
error: function(file, thumb) {
|
||||
var _ref;
|
||||
if (((_ref = file.error) != null ? _ref.code : void 0) === MediaError.MEDIA_ERR_DECODE) {
|
||||
return new Notice('error', 'Corrupt or unplayable video', 30);
|
||||
}
|
||||
if (file.src.split('/')[2] !== 'i.4cdn.org') {
|
||||
return;
|
||||
}
|
||||
return ImageCommon.error(file, g.posts[file.dataset.post], null, function(URL) {
|
||||
if (!URL) {
|
||||
return;
|
||||
}
|
||||
thumb.href = URL;
|
||||
if (Gallery.nodes.current === file) {
|
||||
return file.src = URL;
|
||||
}
|
||||
});
|
||||
},
|
||||
cleanupTimer: function() {
|
||||
var current;
|
||||
clearTimeout(Gallery.timeoutID);
|
||||
current = Gallery.nodes.current;
|
||||
$.off(current, 'canplaythrough load', Gallery.startTimer);
|
||||
return $.off(current, 'ended', Gallery.cb.next);
|
||||
},
|
||||
startTimer: function() {
|
||||
return Gallery.timeoutID = setTimeout(Gallery.checkTimer, Gallery.delay * $.SECOND);
|
||||
},
|
||||
setupTimer: function() {
|
||||
var current, isVideo;
|
||||
Gallery.cleanupTimer();
|
||||
current = Gallery.nodes.current;
|
||||
isVideo = current.nodeName === 'VIDEO';
|
||||
if (isVideo) {
|
||||
current.play();
|
||||
}
|
||||
if ((isVideo ? current.readyState >= 4 : current.complete) || current.nodeName === 'IFRAME') {
|
||||
return Gallery.startTimer();
|
||||
} else {
|
||||
return $.on(current, (isVideo ? 'canplaythrough' : 'load'), Gallery.startTimer);
|
||||
}
|
||||
},
|
||||
checkTimer: function() {
|
||||
var current;
|
||||
current = Gallery.nodes.current;
|
||||
if (current.nodeName === 'VIDEO' && !current.paused) {
|
||||
$.on(current, 'ended', Gallery.cb.next);
|
||||
return current.loop = false;
|
||||
} else {
|
||||
return Gallery.cb.next();
|
||||
}
|
||||
},
|
||||
cb: {
|
||||
keybinds: function(e) {
|
||||
var cb, key;
|
||||
@ -10491,7 +10624,7 @@
|
||||
}
|
||||
cb = (function() {
|
||||
switch (key) {
|
||||
case 'Esc':
|
||||
case Conf['Close']:
|
||||
case Conf['Open Gallery']:
|
||||
return Gallery.cb.close;
|
||||
case 'Right':
|
||||
@ -10501,6 +10634,10 @@
|
||||
case 'Left':
|
||||
case '':
|
||||
return Gallery.cb.prev;
|
||||
case Conf['Pause']:
|
||||
return Gallery.cb.pause;
|
||||
case Conf['Slideshow']:
|
||||
return Gallery.cb.toggleSlideshow;
|
||||
}
|
||||
})();
|
||||
if (!cb) {
|
||||
@ -10511,110 +10648,34 @@
|
||||
return cb();
|
||||
},
|
||||
open: function(e) {
|
||||
var el, elType, file, name, nodes, post, rect, top, _base, _ref;
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (!this) {
|
||||
return;
|
||||
if (this) {
|
||||
return Gallery.open(this);
|
||||
}
|
||||
nodes = Gallery.nodes;
|
||||
name = nodes.name;
|
||||
if (el = $('.gal-highlight', nodes.thumbs)) {
|
||||
$.rmClass(el, 'gal-highlight');
|
||||
}
|
||||
$.addClass(this, 'gal-highlight');
|
||||
elType = this.dataset.isVideo ? 'video' : /\.pdf$/.test(this.href) ? 'iframe' : 'img';
|
||||
$[elType === 'iframe' ? 'addClass' : 'rmClass'](nodes.el, 'gal-pdf');
|
||||
file = $.el(elType, {
|
||||
src: name.href = this.href,
|
||||
title: name.download = name.textContent = this.title
|
||||
});
|
||||
$.extend(file.dataset, this.dataset);
|
||||
if (typeof (_base = nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
$.replace(nodes.current, file);
|
||||
if (this.dataset.isVideo) {
|
||||
Video.configure(file);
|
||||
}
|
||||
nodes.count.textContent = +this.dataset.id + 1;
|
||||
nodes.current = file;
|
||||
nodes.frame.scrollTop = 0;
|
||||
nodes.next.focus();
|
||||
if (Conf['Scroll to Post'] && (post = (_ref = (post = g.posts[file.dataset.post])) != null ? _ref.nodes.root : void 0)) {
|
||||
Header.scrollTo(post);
|
||||
}
|
||||
$.on(file, 'error', function() {
|
||||
return Gallery.cb.error(file, thumb);
|
||||
});
|
||||
rect = this.getBoundingClientRect();
|
||||
top = rect.top;
|
||||
if (top > 0) {
|
||||
top += rect.height - doc.clientHeight;
|
||||
if (top < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return nodes.thumbs.scrollTop += top;
|
||||
},
|
||||
image: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return Gallery.build(this);
|
||||
},
|
||||
error: function(img, thumb) {
|
||||
var URL, post, src;
|
||||
post = Get.postFromLink($.el('a', {
|
||||
href: img.dataset.post
|
||||
}));
|
||||
delete post.file.fullImage;
|
||||
src = this.src.split('/');
|
||||
if (src[2] === 'i.4cdn.org') {
|
||||
URL = Redirect.to('file', {
|
||||
boardID: src[3],
|
||||
filename: src[src.length - 1]
|
||||
});
|
||||
if (URL) {
|
||||
thumb.href = URL;
|
||||
if (Gallery.nodes.current !== img) {
|
||||
return;
|
||||
}
|
||||
img.src = URL;
|
||||
return;
|
||||
}
|
||||
if (g.DEAD || post.isDead || post.file.isDead) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return $.ajax("//a.4cdn.org/" + post.board + "/thread/" + post.thread + ".json", {
|
||||
onload: function() {
|
||||
var i, postObj, posts;
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
i = 0;
|
||||
posts = this.response.posts;
|
||||
while (postObj = posts[i++]) {
|
||||
if (postObj.no === post.ID) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!postObj.no) {
|
||||
return post.kill();
|
||||
}
|
||||
if (postObj.filedeleted) {
|
||||
return post.kill(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
prev: function() {
|
||||
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id - 1] || Gallery.images[Gallery.images.length - 1]);
|
||||
},
|
||||
next: function() {
|
||||
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id + 1] || Gallery.images[0]);
|
||||
},
|
||||
enterKey: function() {
|
||||
if (Gallery.nodes.current.paused) {
|
||||
return Gallery.nodes.current.play();
|
||||
} else {
|
||||
return Gallery.cb.next();
|
||||
}
|
||||
},
|
||||
click: function() {
|
||||
return Gallery.cb[Gallery.nodes.current.controls ? 'stop' : 'enterKey']();
|
||||
},
|
||||
toggle: function() {
|
||||
return (Gallery.nodes ? Gallery.cb.close : Gallery.build)();
|
||||
},
|
||||
@ -10623,41 +10684,66 @@
|
||||
return Gallery.cb.close();
|
||||
}
|
||||
},
|
||||
advance: function() {
|
||||
if (Gallery.nodes.current.controls) {
|
||||
return;
|
||||
}
|
||||
if (Gallery.nodes.current.paused) {
|
||||
return Gallery.nodes.current.play();
|
||||
}
|
||||
return Gallery.cb.next();
|
||||
},
|
||||
pause: function() {
|
||||
var current;
|
||||
Gallery.cb.stop();
|
||||
current = Gallery.nodes.current;
|
||||
if (current.nodeType === 'VIDEO') {
|
||||
if (current.nodeName === 'VIDEO') {
|
||||
return current[current.paused ? 'play' : 'pause']();
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
$.addClass(Gallery.nodes.buttons, 'gal-playing');
|
||||
Gallery.slideshow = true;
|
||||
return Gallery.setupTimer();
|
||||
},
|
||||
stop: function() {
|
||||
var current;
|
||||
if (!Gallery.slideshow) {
|
||||
return;
|
||||
}
|
||||
Gallery.cleanupTimer();
|
||||
current = Gallery.nodes.current;
|
||||
current.loop = current.nodeName === 'VIDEO';
|
||||
$.rmClass(Gallery.nodes.buttons, 'gal-playing');
|
||||
return Gallery.slideshow = false;
|
||||
},
|
||||
close: function() {
|
||||
var _base;
|
||||
if (typeof (_base = Gallery.nodes.current).pause === "function") {
|
||||
_base.pause();
|
||||
}
|
||||
$.rm(Gallery.nodes.el);
|
||||
$.rmClass(doc, 'gallery-open');
|
||||
if (Conf['Fullscreen Gallery']) {
|
||||
$.off(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close);
|
||||
if (typeof d.mozCancelFullScreen === "function") {
|
||||
d.mozCancelFullScreen();
|
||||
}
|
||||
if (typeof d.webkitExitFullscreen === "function") {
|
||||
d.webkitExitFullscreen();
|
||||
}
|
||||
}
|
||||
delete Gallery.nodes;
|
||||
d.body.style.overflow = '';
|
||||
delete Gallery.fullIDs;
|
||||
doc.style.overflow = '';
|
||||
$.off(d, 'keydown', Gallery.cb.keybinds);
|
||||
return $.on(d, 'keydown', Keybinds.keydown);
|
||||
if (Conf['Keybinds']) {
|
||||
$.on(d, 'keydown', Keybinds.keydown);
|
||||
}
|
||||
return clearTimeout(Gallery.timeoutID);
|
||||
},
|
||||
setFitness: function() {
|
||||
return (this.checked ? $.addClass : $.rmClass)(doc, "gal-" + (this.name.toLowerCase().replace(/\s+/g, '-')));
|
||||
},
|
||||
setDelay: function() {
|
||||
return Gallery.delay = +this.value;
|
||||
}
|
||||
},
|
||||
menu: {
|
||||
init: function() {
|
||||
var createSubEntry, el, name, subEntries;
|
||||
if (!Conf['Gallery']) {
|
||||
var createSubEntry, el, name, subEntries, _ref;
|
||||
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Gallery'])) {
|
||||
return;
|
||||
}
|
||||
el = $.el('span', {
|
||||
@ -10690,10 +10776,136 @@
|
||||
return {
|
||||
el: label
|
||||
};
|
||||
},
|
||||
createSubEntries: function() {
|
||||
var delayInput, delayLabel, item, subEntries;
|
||||
subEntries = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'];
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
item = _ref[_i];
|
||||
_results.push(Gallery.menu.createSubEntry(item));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
delayLabel = $.el('label', {
|
||||
innerHTML: "Slide Delay: <input type=\"number\" name=\"Slide Delay\" min=\"0\" step=\"any\" class=\"field\">"
|
||||
});
|
||||
delayInput = delayLabel.firstElementChild;
|
||||
delayInput.value = Gallery.delay;
|
||||
$.on(delayInput, 'change', Gallery.cb.setDelay);
|
||||
$.on(delayInput, 'change', $.cb.value);
|
||||
subEntries.push({
|
||||
el: delayLabel
|
||||
});
|
||||
return subEntries;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ImageCommon = {
|
||||
rewind: function(el) {
|
||||
if (el.nodeName === 'VIDEO') {
|
||||
if (el.readyState >= el.HAVE_METADATA) {
|
||||
return el.currentTime = 0;
|
||||
}
|
||||
} else if (/\.gif$/.test(el.src)) {
|
||||
return $.queueTask(function() {
|
||||
return el.src = el.src;
|
||||
});
|
||||
}
|
||||
},
|
||||
pushCache: function(el) {
|
||||
ImageCommon.cache = el;
|
||||
return $.on(el, 'error', ImageCommon.cacheError);
|
||||
},
|
||||
popCache: function() {
|
||||
var el;
|
||||
el = ImageCommon.cache;
|
||||
$.off(el, 'error', ImageCommon.cacheError);
|
||||
delete ImageCommon.cache;
|
||||
return el;
|
||||
},
|
||||
cacheError: function() {
|
||||
if (ImageCommon.cache === this) {
|
||||
return delete ImageCommon.cache;
|
||||
}
|
||||
},
|
||||
decodeError: function(file, post) {
|
||||
var message, _ref;
|
||||
if (((_ref = file.error) != null ? _ref.code : void 0) !== MediaError.MEDIA_ERR_DECODE) {
|
||||
return false;
|
||||
}
|
||||
if (!(message = $('.warning', post.file.thumb.parentNode))) {
|
||||
message = $.el('div', {
|
||||
className: 'warning'
|
||||
});
|
||||
$.after(post.file.thumb, message);
|
||||
}
|
||||
message.textContent = 'Error: Corrupt or unplayable video';
|
||||
return true;
|
||||
},
|
||||
error: function(file, post, delay, cb) {
|
||||
var URL, redirect, src, timeoutID;
|
||||
src = post.file.URL.split('/');
|
||||
URL = Redirect.to('file', {
|
||||
boardID: post.board.ID,
|
||||
filename: src[src.length - 1]
|
||||
});
|
||||
if (!(Conf['404 Redirect'] && URL && Redirect.securityCheck(URL))) {
|
||||
URL = null;
|
||||
}
|
||||
if ((post.isDead || post.file.isDead) && file.src.split('/')[2] === 'i.4cdn.org') {
|
||||
return cb(URL);
|
||||
}
|
||||
if (delay != null) {
|
||||
timeoutID = setTimeout((function() {
|
||||
return cb(URL);
|
||||
}), delay);
|
||||
}
|
||||
if (post.isDead || post.file.isDead) {
|
||||
return;
|
||||
}
|
||||
redirect = function() {
|
||||
if (file.src.split('/')[2] === 'i.4cdn.org') {
|
||||
if (delay != null) {
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
return cb(URL);
|
||||
}
|
||||
};
|
||||
return $.ajax(post.file.URL, {
|
||||
onloadend: function() {
|
||||
if (this.status === 200) {
|
||||
return URL = post.file.URL;
|
||||
} else {
|
||||
if (this.status === 404) {
|
||||
post.kill(true);
|
||||
}
|
||||
return redirect();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
type: 'head'
|
||||
});
|
||||
},
|
||||
addControls: function(video) {
|
||||
var handler;
|
||||
handler = function() {
|
||||
var t;
|
||||
$.off(video, 'mouseover', handler);
|
||||
t = new Date().getTime();
|
||||
return $.asap((function() {
|
||||
return (typeof chrome !== "undefined" && chrome !== null) || (video.readyState >= 3 && video.currentTime <= Math.max(0.1, video.duration - 0.5)) || new Date().getTime() >= t + 1000;
|
||||
}), function() {
|
||||
return video.controls = true;
|
||||
});
|
||||
};
|
||||
return $.on(video, 'mouseover', handler);
|
||||
}
|
||||
};
|
||||
|
||||
ImageExpand = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
|
||||
|
||||
18
src/General/html/Features/Gallery.html
Normal file
18
src/General/html/Features/Gallery.html
Normal file
@ -0,0 +1,18 @@
|
||||
<div class="gal-viewport">
|
||||
<span class="gal-buttons">
|
||||
<a href="javascript:;" class="gal-start" title="Start slideshow (S to toggle)"><i></i></a>
|
||||
<a href="javascript:;" class="gal-stop" title="Stop slideshow (S to toggle)"><i></i></a>
|
||||
<a href="javascript:;" class="menu-button"><i></i></a>
|
||||
<a href="javascript:;" class="gal-close">×</a>
|
||||
</span>
|
||||
<a class="gal-name" target="_blank"></a>
|
||||
<span class="gal-count">
|
||||
<span class="count"></span> / <span class="total"></span>
|
||||
</span>
|
||||
<div class="gal-prev"></div>
|
||||
<div class="gal-image">
|
||||
<a href="javascript:;"><img></a>
|
||||
</div>
|
||||
<div class="gal-next"></div>
|
||||
</div>
|
||||
<div class="gal-thumbnails"></div>
|
||||
@ -1,6 +1,6 @@
|
||||
Gallery =
|
||||
init: ->
|
||||
return if g.BOARD is 'f' or !Conf['Gallery']
|
||||
return if not (g.VIEW in ['index', 'thread'] and Conf['Gallery']) or g.BOARD is 'f'
|
||||
|
||||
el = $.el 'a',
|
||||
href: 'javascript:;'
|
||||
@ -20,38 +20,30 @@ Gallery =
|
||||
node: ->
|
||||
return unless @file
|
||||
if Gallery.nodes
|
||||
Gallery.generateThumb $ '.file', @nodes.root
|
||||
Gallery.generateThumb @
|
||||
Gallery.nodes.total.textContent = Gallery.images.length
|
||||
|
||||
unless Conf['Image Expansion']
|
||||
$.on @file.thumb.parentNode, 'click', Gallery.cb.image
|
||||
|
||||
build: (image) ->
|
||||
if Conf['Fullscreen Gallery']
|
||||
$.one d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', ->
|
||||
$.on d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close
|
||||
doc.mozRequestFullScreen?()
|
||||
doc.webkitRequestFullScreen?(Element.ALLOW_KEYBOARD_INPUT)
|
||||
|
||||
Gallery.images = []
|
||||
nodes = Gallery.nodes = {}
|
||||
Gallery.fullIDs = {}
|
||||
Gallery.slideshow = false
|
||||
|
||||
nodes.el = dialog = $.el 'div',
|
||||
id: 'a-gallery'
|
||||
innerHTML: """
|
||||
<div class=gal-viewport>
|
||||
<span class=gal-buttons>
|
||||
<a class="menu-button" href="javascript:;"><i></i></a>
|
||||
<a href=javascript:; class=gal-close>×</a>
|
||||
</span>
|
||||
<a class=gal-name target="_blank"></a>
|
||||
<span class=gal-count>
|
||||
<span class='count'></span> / <span class='total'></span>
|
||||
</span>
|
||||
<div class=gal-prev></div>
|
||||
<div class=gal-image>
|
||||
<a href=javascript:;><img></a>
|
||||
</div>
|
||||
<div class=gal-next></div>
|
||||
</div>
|
||||
<div class=gal-thumbnails></div>
|
||||
"""
|
||||
$.extend dialog, <%= importHTML('Features/Gallery') %>
|
||||
|
||||
nodes[key] = $ value, dialog for key, value of {
|
||||
buttons: '.gal-buttons'
|
||||
frame: '.gal-image'
|
||||
name: '.gal-name'
|
||||
count: '.count'
|
||||
@ -62,56 +54,64 @@ Gallery =
|
||||
}
|
||||
|
||||
menuButton = $ '.menu-button', dialog
|
||||
nodes.menu = new UI.Menu()
|
||||
nodes.menu = new UI.Menu 'gallery'
|
||||
|
||||
{cb} = Gallery
|
||||
$.on nodes.frame, 'click', cb.blank
|
||||
$.on nodes.next, 'click', cb.advance
|
||||
$.on nodes.next, 'click', cb.click
|
||||
$.on $('.gal-prev', dialog), 'click', cb.prev
|
||||
$.on $('.gal-next', dialog), 'click', cb.next
|
||||
$.on $('.gal-start', dialog), 'click', cb.start
|
||||
$.on $('.gal-stop', dialog), 'click', cb.stop
|
||||
$.on $('.gal-close', dialog), 'click', cb.close
|
||||
|
||||
$.on menuButton, 'click', (e) ->
|
||||
nodes.menu.toggle e, @, g
|
||||
|
||||
{createSubEntry} = Gallery.menu
|
||||
for name of Config.gallery
|
||||
{el} = createSubEntry name
|
||||
|
||||
nodes.menu.addEntry
|
||||
el: el
|
||||
order: 0
|
||||
for entry in Gallery.menu.createSubEntries()
|
||||
entry.order = 0
|
||||
nodes.menu.addEntry entry
|
||||
|
||||
$.on d, 'keydown', cb.keybinds
|
||||
$.off d, 'keydown', Keybinds.keydown
|
||||
Gallery.generateThumb file for file, i in $$ '.post .file' when !$ '.fileDeletedRes, .fileDeleted', file
|
||||
$.off d, 'keydown', Keybinds.keydown if Conf['Keybinds']
|
||||
|
||||
for file in $$ '.post .file'
|
||||
post = Get.postFromNode file
|
||||
continue if post.file.isDead
|
||||
Gallery.generateThumb post
|
||||
# If no image to open is given, pick image we have scrolled to.
|
||||
if !image and Gallery.fullIDs[post.fullID]
|
||||
candidate = post.file.thumb.parentNode
|
||||
if Header.getTopOf(candidate) + candidate.getBoundingClientRect().height >= 0
|
||||
image = candidate
|
||||
$.addClass doc, 'gallery-open'
|
||||
|
||||
$.add d.body, dialog
|
||||
|
||||
nodes.thumbs.scrollTop = 0
|
||||
nodes.current.parentElement.scrollTop = 0
|
||||
|
||||
Gallery.cb.open.call if image
|
||||
$ "[href*='#{image.pathname}']", nodes.thumbs
|
||||
else
|
||||
Gallery.images[0]
|
||||
thumb = $ "[href='#{image.href}']", nodes.thumbs if image
|
||||
thumb or= Gallery.images[Gallery.images.length-1]
|
||||
Gallery.open thumb if thumb
|
||||
|
||||
d.body.style.overflow = 'hidden'
|
||||
nodes.total.textContent = i
|
||||
doc.style.overflow = 'hidden'
|
||||
nodes.total.textContent = Gallery.images.length
|
||||
|
||||
generateThumb: (file) ->
|
||||
post = Get.postFromNode file
|
||||
return unless post.file and (post.file.isImage or post.file.isVideo or Conf['PDF in Gallery'])
|
||||
title = ($ '.fileText a', file).textContent
|
||||
generateThumb: (post) ->
|
||||
return if post.isClone or post.isHidden and
|
||||
not (post.file?.isImage or post.file?.isVideo or Conf['PDF in Gallery'])
|
||||
|
||||
Gallery.fullIDs[post.fullID] = true
|
||||
|
||||
thumb = $.el 'a',
|
||||
className: 'gal-thumb'
|
||||
href: post.file.URL
|
||||
target: '_blank'
|
||||
title: title
|
||||
title: post.file.name
|
||||
|
||||
thumb.dataset.id = Gallery.images.length
|
||||
thumb.dataset.post = post.fullID
|
||||
thumb.dataset.isVideo = true if post.file.isVideo
|
||||
thumb.dataset.id = Gallery.images.length
|
||||
thumb.dataset.post = post.fullID
|
||||
|
||||
thumbImg = post.file.thumb.cloneNode false
|
||||
thumbImg.style.cssText = ''
|
||||
@ -122,12 +122,95 @@ Gallery =
|
||||
Gallery.images.push thumb
|
||||
$.add Gallery.nodes.thumbs, thumb
|
||||
|
||||
open: (thumb) ->
|
||||
{nodes} = Gallery
|
||||
{name} = nodes
|
||||
oldID = +nodes.current.dataset.id
|
||||
newID = +thumb.dataset.id
|
||||
slideshow = Gallery.slideshow and (newID > oldID or (oldID is Gallery.images.length-1 and newID is 0))
|
||||
|
||||
$.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', nodes.thumbs
|
||||
$.addClass thumb, 'gal-highlight'
|
||||
|
||||
elType = if /\.webm$/.test(thumb.href)
|
||||
'video'
|
||||
else if /\.pdf$/.test(thumb.href)
|
||||
'iframe'
|
||||
else
|
||||
'image'
|
||||
|
||||
$[if elType is 'iframe' then 'addClass' else 'rmClass'] doc, 'gal-pdf'
|
||||
file = $.el elType,
|
||||
title: name.download = name.textContent = thumb.title
|
||||
$.on file, 'error', =>
|
||||
Gallery.error file, thumb
|
||||
file.src = name.href = thumb.href
|
||||
|
||||
$.extend file.dataset, thumb.dataset
|
||||
nodes.current.pause?() unless nodes.current.error
|
||||
$.replace nodes.current, file
|
||||
if elType is 'video'
|
||||
file.loop = true
|
||||
file.play() if Conf['Autoplay']
|
||||
ImageCommon.addControls file if Conf['Show Controls']
|
||||
nodes.count.textContent = +thumb.dataset.id + 1
|
||||
nodes.current = file
|
||||
nodes.frame.scrollTop = 0
|
||||
nodes.next.focus()
|
||||
if slideshow
|
||||
Gallery.setupTimer()
|
||||
else
|
||||
Gallery.cb.stop()
|
||||
|
||||
# Scroll to post
|
||||
if Conf['Scroll to Post'] and post = (post = g.posts[file.dataset.post])?.nodes.root
|
||||
Header.scrollTo post
|
||||
|
||||
# Center selected thumbnail
|
||||
nodes.thumbs.scrollTop = thumb.offsetTop + thumb.offsetHeight/2 - nodes.thumbs.clientHeight/2
|
||||
|
||||
error: (file, thumb) ->
|
||||
if file.error?.code is MediaError.MEDIA_ERR_DECODE
|
||||
return new Notice 'error', 'Corrupt or unplayable video', 30
|
||||
return unless file.src.split('/')[2] is 'i.4cdn.org'
|
||||
ImageCommon.error file, g.posts[file.dataset.post], null, (URL) ->
|
||||
return unless URL
|
||||
thumb.href = URL
|
||||
file.src = URL if Gallery.nodes.current is file
|
||||
|
||||
cleanupTimer: ->
|
||||
clearTimeout Gallery.timeoutID
|
||||
{current} = Gallery.nodes
|
||||
$.off current, 'canplaythrough load', Gallery.startTimer
|
||||
$.off current, 'ended', Gallery.cb.next
|
||||
|
||||
startTimer: ->
|
||||
Gallery.timeoutID = setTimeout Gallery.checkTimer, Gallery.delay * $.SECOND
|
||||
|
||||
setupTimer: ->
|
||||
Gallery.cleanupTimer()
|
||||
{current} = Gallery.nodes
|
||||
isVideo = current.nodeName is 'VIDEO'
|
||||
current.play() if isVideo
|
||||
if (if isVideo then current.readyState >= 4 else current.complete) or current.nodeName is 'IFRAME'
|
||||
Gallery.startTimer()
|
||||
else
|
||||
$.on current, (if isVideo then 'canplaythrough' else 'load'), Gallery.startTimer
|
||||
|
||||
checkTimer: ->
|
||||
{current} = Gallery.nodes
|
||||
if current.nodeName is 'VIDEO' and !current.paused
|
||||
$.on current, 'ended', Gallery.cb.next
|
||||
current.loop = false
|
||||
else
|
||||
Gallery.cb.next()
|
||||
|
||||
cb:
|
||||
keybinds: (e) ->
|
||||
return unless key = Keybinds.keyCode e
|
||||
|
||||
cb = switch key
|
||||
when 'Esc', Conf['Open Gallery']
|
||||
when Conf['Close'], Conf['Open Gallery']
|
||||
Gallery.cb.close
|
||||
when 'Right'
|
||||
Gallery.cb.next
|
||||
@ -135,6 +218,10 @@ Gallery =
|
||||
Gallery.cb.advance
|
||||
when 'Left', ''
|
||||
Gallery.cb.prev
|
||||
when Conf['Pause']
|
||||
Gallery.cb.pause
|
||||
when Conf['Slideshow']
|
||||
Gallery.cb.toggleSlideshow
|
||||
|
||||
return unless cb
|
||||
e.stopPropagation()
|
||||
@ -143,80 +230,13 @@ Gallery =
|
||||
|
||||
open: (e) ->
|
||||
e.preventDefault() if e
|
||||
return unless @
|
||||
|
||||
{nodes} = Gallery
|
||||
{name} = nodes
|
||||
|
||||
$.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', nodes.thumbs
|
||||
$.addClass @, 'gal-highlight'
|
||||
|
||||
elType = if @dataset.isVideo then 'video' else if /\.pdf$/.test(@href) then 'iframe' else 'img'
|
||||
$[if elType is 'iframe' then 'addClass' else 'rmClass'] nodes.el, 'gal-pdf'
|
||||
|
||||
file = $.el elType,
|
||||
src: name.href = @href
|
||||
title: name.download = name.textContent = @title
|
||||
|
||||
$.extend file.dataset, @dataset
|
||||
nodes.current.pause?()
|
||||
$.replace nodes.current, file
|
||||
Video.configure file if @dataset.isVideo
|
||||
nodes.count.textContent = +@dataset.id + 1
|
||||
nodes.current = file
|
||||
nodes.frame.scrollTop = 0
|
||||
nodes.next.focus()
|
||||
|
||||
# Scroll to post
|
||||
if Conf['Scroll to Post'] and post = (post = g.posts[file.dataset.post])?.nodes.root
|
||||
Header.scrollTo post
|
||||
|
||||
$.on file, 'error', ->
|
||||
Gallery.cb.error file, thumb
|
||||
|
||||
# Scroll
|
||||
rect = @getBoundingClientRect()
|
||||
{top} = rect
|
||||
if top > 0
|
||||
top += rect.height - doc.clientHeight
|
||||
return if top < 0
|
||||
|
||||
nodes.thumbs.scrollTop += top
|
||||
if @ then Gallery.open @
|
||||
|
||||
image: (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
Gallery.build @
|
||||
|
||||
error: (img, thumb) ->
|
||||
post = Get.postFromLink $.el 'a', href: img.dataset.post
|
||||
delete post.file.fullImage
|
||||
|
||||
src = @src.split '/'
|
||||
if src[2] is 'i.4cdn.org'
|
||||
URL = Redirect.to 'file',
|
||||
boardID: src[3]
|
||||
filename: src[src.length - 1]
|
||||
if URL
|
||||
thumb.href = URL
|
||||
return unless Gallery.nodes.current is img
|
||||
img.src = URL
|
||||
return
|
||||
if g.DEAD or post.isDead or post.file.isDead
|
||||
return
|
||||
|
||||
# XXX CORS for i.4cdn.org WHEN?
|
||||
$.ajax "//a.4cdn.org/#{post.board}/thread/#{post.thread}.json", onload: ->
|
||||
return if @status isnt 200
|
||||
i = 0
|
||||
{posts} = @response
|
||||
while postObj = posts[i++]
|
||||
break if postObj.no is post.ID
|
||||
unless postObj.no
|
||||
return post.kill()
|
||||
if postObj.filedeleted
|
||||
post.kill true
|
||||
|
||||
prev: ->
|
||||
Gallery.cb.open.call(
|
||||
Gallery.images[+Gallery.nodes.current.dataset.id - 1] or Gallery.images[Gallery.images.length - 1]
|
||||
@ -225,33 +245,54 @@ Gallery =
|
||||
Gallery.cb.open.call(
|
||||
Gallery.images[+Gallery.nodes.current.dataset.id + 1] or Gallery.images[0]
|
||||
)
|
||||
|
||||
enterKey: -> if Gallery.nodes.current.paused then Gallery.nodes.current.play() else Gallery.cb.next()
|
||||
click: -> Gallery.cb[if Gallery.nodes.current.controls then 'stop' else 'enterKey']()
|
||||
toggle: -> (if Gallery.nodes then Gallery.cb.close else Gallery.build)()
|
||||
blank: (e) -> Gallery.cb.close() if e.target is @
|
||||
|
||||
advance: ->
|
||||
if Gallery.nodes.current.controls then return
|
||||
if Gallery.nodes.current.paused then return Gallery.nodes.current.play()
|
||||
Gallery.cb.next()
|
||||
|
||||
pause: ->
|
||||
Gallery.cb.stop()
|
||||
{current} = Gallery.nodes
|
||||
current[if current.paused then 'play' else 'pause']() if current.nodeType is 'VIDEO'
|
||||
current[if current.paused then 'play' else 'pause']() if current.nodeName is 'VIDEO'
|
||||
|
||||
start: ->
|
||||
$.addClass Gallery.nodes.buttons, 'gal-playing'
|
||||
Gallery.slideshow = true
|
||||
Gallery.setupTimer()
|
||||
|
||||
stop: ->
|
||||
return unless Gallery.slideshow
|
||||
Gallery.cleanupTimer()
|
||||
{current} = Gallery.nodes
|
||||
current.loop = current.nodeName is 'VIDEO'
|
||||
$.rmClass Gallery.nodes.buttons, 'gal-playing'
|
||||
Gallery.slideshow = false
|
||||
|
||||
close: ->
|
||||
Gallery.nodes.current.pause?()
|
||||
$.rm Gallery.nodes.el
|
||||
$.rmClass doc, 'gallery-open'
|
||||
if Conf['Fullscreen Gallery']
|
||||
$.off d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close
|
||||
d.mozCancelFullScreen?()
|
||||
d.webkitExitFullscreen?()
|
||||
delete Gallery.nodes
|
||||
d.body.style.overflow = ''
|
||||
delete Gallery.fullIDs
|
||||
doc.style.overflow = ''
|
||||
|
||||
$.off d, 'keydown', Gallery.cb.keybinds
|
||||
$.on d, 'keydown', Keybinds.keydown
|
||||
$.on d, 'keydown', Keybinds.keydown if Conf['Keybinds']
|
||||
clearTimeout Gallery.timeoutID
|
||||
|
||||
setFitness: ->
|
||||
(if @checked then $.addClass else $.rmClass) doc, "gal-#{@name.toLowerCase().replace /\s+/g, '-'}"
|
||||
|
||||
setDelay: -> Gallery.delay = +@value
|
||||
|
||||
menu:
|
||||
init: ->
|
||||
return if !Conf['Gallery']
|
||||
return unless g.VIEW in ['index', 'thread'] and Conf['Gallery']
|
||||
|
||||
el = $.el 'span',
|
||||
textContent: 'Gallery'
|
||||
@ -277,3 +318,15 @@ Gallery =
|
||||
$.event 'change', null, input
|
||||
$.on input, 'change', $.cb.checked
|
||||
el: label
|
||||
|
||||
createSubEntries: ->
|
||||
subEntries = (Gallery.menu.createSubEntry item for item in ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'])
|
||||
|
||||
delayLabel = $.el 'label', <%= html('Slide Delay: <input type="number" name="Slide Delay" min="0" step="any" class="field">') %>
|
||||
delayInput = delayLabel.firstElementChild
|
||||
delayInput.value = Gallery.delay
|
||||
$.on delayInput, 'change', Gallery.cb.setDelay
|
||||
$.on delayInput, 'change', $.cb.value
|
||||
subEntries.push el: delayLabel
|
||||
|
||||
subEntries
|
||||
81
src/Images/ImageCommon.coffee
Normal file
81
src/Images/ImageCommon.coffee
Normal file
@ -0,0 +1,81 @@
|
||||
ImageCommon =
|
||||
rewind: (el) ->
|
||||
if el.nodeName is 'VIDEO'
|
||||
el.currentTime = 0 if el.readyState >= el.HAVE_METADATA
|
||||
else if /\.gif$/.test el.src
|
||||
$.queueTask -> el.src = el.src
|
||||
|
||||
pushCache: (el) ->
|
||||
ImageCommon.cache = el
|
||||
$.on el, 'error', ImageCommon.cacheError
|
||||
|
||||
popCache: ->
|
||||
el = ImageCommon.cache
|
||||
$.off el, 'error', ImageCommon.cacheError
|
||||
delete ImageCommon.cache
|
||||
el
|
||||
|
||||
cacheError: ->
|
||||
delete ImageCommon.cache if ImageCommon.cache is @
|
||||
|
||||
decodeError: (file, post) ->
|
||||
return false unless file.error?.code is MediaError.MEDIA_ERR_DECODE
|
||||
unless message = $ '.warning', post.file.thumb.parentNode
|
||||
message = $.el 'div', className: 'warning'
|
||||
$.after post.file.thumb, message
|
||||
message.textContent = 'Error: Corrupt or unplayable video'
|
||||
return true
|
||||
|
||||
error: (file, post, delay, cb) ->
|
||||
src = post.file.URL.split '/'
|
||||
URL = Redirect.to 'file',
|
||||
boardID: post.board.ID
|
||||
filename: src[src.length - 1]
|
||||
unless Conf['404 Redirect'] and URL and Redirect.securityCheck URL
|
||||
URL = null
|
||||
|
||||
return cb URL if (post.isDead or post.file.isDead) and file.src.split('/')[2] is 'i.4cdn.org'
|
||||
|
||||
timeoutID = setTimeout (-> cb URL), delay if delay?
|
||||
return if post.isDead or post.file.isDead
|
||||
redirect = ->
|
||||
if file.src.split('/')[2] is 'i.4cdn.org'
|
||||
clearTimeout timeoutID if delay?
|
||||
cb URL
|
||||
|
||||
<% if (type === 'crx') { %>
|
||||
$.ajax post.file.URL,
|
||||
onloadend: ->
|
||||
if @status is 200
|
||||
URL = post.file.URL
|
||||
else
|
||||
post.kill true if @status is 404
|
||||
redirect()
|
||||
,
|
||||
type: 'head'
|
||||
<% } else { %>
|
||||
# XXX CORS for i.4cdn.org WHEN?
|
||||
$.ajax "//a.4cdn.org/#{post.board}/thread/#{post.thread}.json", onload: ->
|
||||
post.kill() if @status is 404
|
||||
return redirect() if @status isnt 200
|
||||
for postObj in @response.posts
|
||||
break if postObj.no is post.ID
|
||||
if postObj.no isnt post.ID
|
||||
post.kill()
|
||||
redirect()
|
||||
else if postObj.filedeleted
|
||||
post.kill true
|
||||
redirect()
|
||||
else
|
||||
URL = post.file.URL
|
||||
<% } %>
|
||||
|
||||
# Add controls, but not until the mouse is moved over the video.
|
||||
addControls: (video) ->
|
||||
handler = ->
|
||||
$.off video, 'mouseover', handler
|
||||
# Hacky workaround for Firefox forever-loading bug for very short videos
|
||||
t = new Date().getTime()
|
||||
$.asap (-> chrome? or (video.readyState >= 3 and video.currentTime <= Math.max 0.1, (video.duration - 0.5)) or new Date().getTime() >= t + 1000), ->
|
||||
video.controls = true
|
||||
$.on video, 'mouseover', handler
|
||||
Loading…
x
Reference in New Issue
Block a user