Merge branch 'v3'

Conflicts:
	CHANGELOG.md
	LICENSE
	builds/appchan-x.user.js
	builds/crx/manifest.json
	builds/crx/script.js
	builds/updates.xml
	latest.js
	package.json
This commit is contained in:
Zixaphir 2014-04-04 16:12:31 -07:00
commit 8536ae3d37
13 changed files with 195 additions and 87 deletions

View File

@ -1,5 +1,8 @@
**ccd0**:
- Support expansion of .webm videos.
- Support hover for .webm videos.
- Add .webm to supported posting types.
- Add option to enable/disable sound.
- Update archives with data from MayhemYDG fork.
### v2.9.11

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.5.0
// @version 1.5.1
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

View File

@ -172,7 +172,7 @@
},
'Images and Videos': {
'Image Expansion': [true, 'Expand images / videos.'],
'Image Hover': [true, 'Show full image on mouseover.'],
'Image Hover': [true, 'Show full image / video on mouseover.'],
'Image Hover in Catalog': [false, 'Show a floating expanded image on hover in the catalog.'],
'Gallery': [true, 'Adds a simple and cute image gallery.'],
'Sauce': [true, 'Add sauce links to images.'],
@ -184,7 +184,8 @@
'Fappe Tyme': [false, 'Hide posts without images when toggled. *hint* *hint*'],
'Werk Tyme': [false, 'Hide all post images when toggled.'],
'Autoplay': [true, 'Videos begin playing immediately when opened inline.'],
'Show Controls': [true, 'Show native seek and volume controls on videos. Contract videos when dragged to the left.']
'Show Controls': [true, 'Show native seek and volume controls on videos. Contract videos when dragged to the left.'],
'Allow Sound': [true, 'Allow sound in inline videos.']
},
'Menu': {
'Menu': [true, 'Add a drop-down menu to posts.'],
@ -6684,7 +6685,9 @@
if (e.type === 'keydown' && e.keyCode !== 13 || e.target.nodeName === "TEXTAREA") {
return;
}
$.rm(this.el);
if (this.el.parentNode === Header.hover) {
$.rm(this.el);
}
$.off(this.root, this.endEvents, this.hoverend);
$.off(d, 'keydown', this.hoverend);
$.off(this.root, 'mousemove', this.hover);
@ -8597,7 +8600,7 @@
};
QR = {
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', ''],
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', 'video/webm', ''],
init: function() {
var con, sc;
this.db = new DataBoard('yourPosts');
@ -9030,21 +9033,25 @@
},
checkDimensions: function(file, isSingle, max) {
var img;
img = new Image();
img.onload = (function(_this) {
return function() {
var height, width;
height = img.height, width = img.width;
if (height > QR.max_heigth || width > QR.max_heigth) {
return QR.error("" + file.name + ": Image too large (image: " + img.height + "x" + img.width + "px, max: " + QR.max_heigth + "x" + QR.max_width + "px)");
}
if (height < QR.min_heigth || width < QR.min_heigth) {
return QR.error("" + file.name + ": Image too small (image: " + img.height + "x" + img.width + "px, min: " + QR.min_heigth + "x" + QR.min_width + "px)");
}
return QR.handleFile(file, isSingle, max);
};
})(this);
return img.src = URL.createObjectURL(file);
if (/^image\//.test(file.type)) {
img = new Image();
img.onload = (function(_this) {
return function() {
var height, width;
height = img.height, width = img.width;
if (height > QR.max_heigth || width > QR.max_heigth) {
return QR.error("" + file.name + ": Image too large (image: " + img.height + "x" + img.width + "px, max: " + QR.max_heigth + "x" + QR.max_width + "px)");
}
if (height < QR.min_heigth || width < QR.min_heigth) {
return QR.error("" + file.name + ": Image too small (image: " + img.height + "x" + img.width + "px, min: " + QR.min_heigth + "x" + QR.min_width + "px)");
}
return QR.handleFile(file, isSingle, max);
};
})(this);
return img.src = URL.createObjectURL(file);
} else {
return QR.handleFile(file, isSingle, max);
}
},
handleFile: function(file, isSingle, max) {
var post, _ref;
@ -10046,7 +10053,7 @@
return;
}
this.file.newName = this.filename.replace(/[/\\]/g, '-');
if (!/\.(jpe?g|png|gif|pdf|swf)$/i.test(this.filename)) {
if (!/\.(jpe?g|png|gif|pdf|swf|webm)$/i.test(this.filename)) {
this.file.newName += '.jpg';
}
return this.updateFilename();
@ -10765,9 +10772,12 @@
}
$.addClass(thumb, 'expanding');
naturalHeight = isVideo ? 'videoHeight' : 'naturalHeight';
if (post.file.fullImage) {
if (img = post.file.fullImage) {
$.rmClass(img, 'ihover');
$.addClass(img, 'full-image');
img.controls = img.parentNode !== thumb.parentNode;
$.asap((function() {
return post.file.fullImage[naturalHeight];
return img[naturalHeight];
}), function() {
return ImageExpand.completeExpand(post);
});
@ -10819,7 +10829,7 @@
file = post.file;
video = file.fullImage;
file.videoControls = [];
video.muted = true;
video.muted = !Conf['Allow Sound'];
if (video.controls) {
contract = $.el('a', {
textContent: 'contract',
@ -10972,8 +10982,8 @@
}
},
node: function() {
var _ref;
if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
var _ref, _ref1;
if (!(((_ref = this.file) != null ? _ref.isImage : void 0) || ((_ref1 = this.file) != null ? _ref1.isVideo : void 0))) {
return;
}
return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
@ -10986,21 +10996,46 @@
return $.on(this.nodes.thumb, 'mouseover', ImageHover.mouseover);
},
mouseover: function(e) {
var el, post;
var el, isVideo, naturalHeight, post, thumb;
post = $.hasClass(this, 'thumb') ? g.posts[this.parentNode.dataset.fullID] : Get.postFromNode(this);
el = $.el('img', {
id: 'ihover',
src: post.file.URL
});
isVideo = post.file.isVideo;
if (post.file.fullImage) {
el = post.file.fullImage;
$.rmClass(el, 'full-image');
$.addClass(el, 'ihover');
} else {
el = $.el((isVideo ? 'video' : 'img'), {
className: 'ihover',
src: post.file.URL
});
post.file.fullImage = el;
thumb = post.file.thumb;
$.after((isVideo && Conf['Show Controls'] ? thumb.parentNode : thumb), el);
}
el.dataset.fullID = post.fullID;
$.add(Header.hover, el);
if (isVideo) {
el.loop = true;
el.controls = false;
el.muted = !Conf['Allow Sound'];
if (Conf['Autoplay']) {
el.play();
}
}
naturalHeight = post.file.isVideo ? 'videoHeight' : 'naturalHeight';
UI.hover({
root: this,
el: el,
latestEvent: e,
endEvents: 'mouseout click',
asapTest: function() {
return el.naturalHeight;
return el[naturalHeight];
},
cb: function() {
if (isVideo) {
el.pause();
}
$.rmClass(el, 'ihover');
return $.addClass(el, 'full-image');
}
});
return $.on(el, 'error', ImageHover.error);

Binary file not shown.

View File

@ -147,7 +147,7 @@
},
'Images and Videos': {
'Image Expansion': [true, 'Expand images / videos.'],
'Image Hover': [true, 'Show full image on mouseover.'],
'Image Hover': [true, 'Show full image / video on mouseover.'],
'Image Hover in Catalog': [false, 'Show a floating expanded image on hover in the catalog.'],
'Gallery': [true, 'Adds a simple and cute image gallery.'],
'Sauce': [true, 'Add sauce links to images.'],
@ -159,7 +159,8 @@
'Fappe Tyme': [false, 'Hide posts without images when toggled. *hint* *hint*'],
'Werk Tyme': [false, 'Hide all post images when toggled.'],
'Autoplay': [true, 'Videos begin playing immediately when opened inline.'],
'Show Controls': [true, 'Show native seek and volume controls on videos. Contract videos when dragged to the left.']
'Show Controls': [true, 'Show native seek and volume controls on videos. Contract videos when dragged to the left.'],
'Allow Sound': [true, 'Allow sound in inline videos.']
},
'Menu': {
'Menu': [true, 'Add a drop-down menu to posts.'],
@ -6738,7 +6739,9 @@
if (e.type === 'keydown' && e.keyCode !== 13 || e.target.nodeName === "TEXTAREA") {
return;
}
$.rm(this.el);
if (this.el.parentNode === Header.hover) {
$.rm(this.el);
}
$.off(this.root, this.endEvents, this.hoverend);
$.off(d, 'keydown', this.hoverend);
$.off(this.root, 'mousemove', this.hover);
@ -8650,7 +8653,7 @@
};
QR = {
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', ''],
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', 'video/webm', ''],
init: function() {
var con, sc;
this.db = new DataBoard('yourPosts');
@ -9085,21 +9088,25 @@
},
checkDimensions: function(file, isSingle, max) {
var img;
img = new Image();
img.onload = (function(_this) {
return function() {
var height, width;
height = img.height, width = img.width;
if (height > QR.max_heigth || width > QR.max_heigth) {
return QR.error("" + file.name + ": Image too large (image: " + img.height + "x" + img.width + "px, max: " + QR.max_heigth + "x" + QR.max_width + "px)");
}
if (height < QR.min_heigth || width < QR.min_heigth) {
return QR.error("" + file.name + ": Image too small (image: " + img.height + "x" + img.width + "px, min: " + QR.min_heigth + "x" + QR.min_width + "px)");
}
return QR.handleFile(file, isSingle, max);
};
})(this);
return img.src = URL.createObjectURL(file);
if (/^image\//.test(file.type)) {
img = new Image();
img.onload = (function(_this) {
return function() {
var height, width;
height = img.height, width = img.width;
if (height > QR.max_heigth || width > QR.max_heigth) {
return QR.error("" + file.name + ": Image too large (image: " + img.height + "x" + img.width + "px, max: " + QR.max_heigth + "x" + QR.max_width + "px)");
}
if (height < QR.min_heigth || width < QR.min_heigth) {
return QR.error("" + file.name + ": Image too small (image: " + img.height + "x" + img.width + "px, min: " + QR.min_heigth + "x" + QR.min_width + "px)");
}
return QR.handleFile(file, isSingle, max);
};
})(this);
return img.src = URL.createObjectURL(file);
} else {
return QR.handleFile(file, isSingle, max);
}
},
handleFile: function(file, isSingle, max) {
var post, _ref;
@ -10084,7 +10091,7 @@
return;
}
this.file.newName = this.filename.replace(/[/\\]/g, '-');
if (!/\.(jpe?g|png|gif|pdf|swf)$/i.test(this.filename)) {
if (!/\.(jpe?g|png|gif|pdf|swf|webm)$/i.test(this.filename)) {
this.file.newName += '.jpg';
}
return this.updateFilename();
@ -10803,9 +10810,12 @@
}
$.addClass(thumb, 'expanding');
naturalHeight = isVideo ? 'videoHeight' : 'naturalHeight';
if (post.file.fullImage) {
if (img = post.file.fullImage) {
$.rmClass(img, 'ihover');
$.addClass(img, 'full-image');
img.controls = img.parentNode !== thumb.parentNode;
$.asap((function() {
return post.file.fullImage[naturalHeight];
return img[naturalHeight];
}), function() {
return ImageExpand.completeExpand(post);
});
@ -10857,7 +10867,7 @@
file = post.file;
video = file.fullImage;
file.videoControls = [];
video.muted = true;
video.muted = !Conf['Allow Sound'];
if (video.controls) {
contract = $.el('a', {
textContent: 'contract',
@ -10999,8 +11009,8 @@
}
},
node: function() {
var _ref;
if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
var _ref, _ref1;
if (!(((_ref = this.file) != null ? _ref.isImage : void 0) || ((_ref1 = this.file) != null ? _ref1.isVideo : void 0))) {
return;
}
return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
@ -11013,21 +11023,46 @@
return $.on(this.nodes.thumb, 'mouseover', ImageHover.mouseover);
},
mouseover: function(e) {
var el, post;
var el, isVideo, naturalHeight, post, thumb;
post = $.hasClass(this, 'thumb') ? g.posts[this.parentNode.dataset.fullID] : Get.postFromNode(this);
el = $.el('img', {
id: 'ihover',
src: post.file.URL
});
isVideo = post.file.isVideo;
if (post.file.fullImage) {
el = post.file.fullImage;
$.rmClass(el, 'full-image');
$.addClass(el, 'ihover');
} else {
el = $.el((isVideo ? 'video' : 'img'), {
className: 'ihover',
src: post.file.URL
});
post.file.fullImage = el;
thumb = post.file.thumb;
$.after((isVideo && Conf['Show Controls'] ? thumb.parentNode : thumb), el);
}
el.dataset.fullID = post.fullID;
$.add(Header.hover, el);
if (isVideo) {
el.loop = true;
el.controls = false;
el.muted = !Conf['Allow Sound'];
if (Conf['Autoplay']) {
el.play();
}
}
naturalHeight = post.file.isVideo ? 'videoHeight' : 'naturalHeight';
UI.hover({
root: this,
el: el,
latestEvent: e,
endEvents: 'mouseout click',
asapTest: function() {
return el.naturalHeight;
return el[naturalHeight];
},
cb: function() {
if (isVideo) {
el.pause();
}
$.rmClass(el, 'ihover');
return $.addClass(el, 'full-image');
}
});
return $.on(el, 'error', ImageHover.error);

7
builds/updates.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.5.1' />
</app>
</gupdate>

View File

@ -121,7 +121,7 @@ Config =
]
'Image Hover': [
true
'Show full image on mouseover.'
'Show full image / video on mouseover.'
]
'Image Hover in Catalog': [
false
@ -171,6 +171,10 @@ Config =
true
'Show native seek and volume controls on videos. Contract videos when dragged to the left.'
]
'Allow Sound': [
true
'Allow sound in inline videos.'
]
'Menu':
'Menu': [

View File

@ -366,7 +366,7 @@ UI = do ->
hoverend = (e) ->
return if e.type is 'keydown' and e.keyCode isnt 13 or e.target.nodeName is "TEXTAREA"
$.rm @el
$.rm @el if @el.parentNode is Header.hover
$.off @root, @endEvents, @hoverend
$.off d, 'keydown', @hoverend
$.off @root, 'mousemove', @hover

View File

@ -108,7 +108,7 @@ div.center:not(.ad-cnt) {
/* fixed, z-index */
#overlay,
#fourchanx-settings,
#qp, #ihover,
#qp, .ihover,
#navlinks, .fixed #header-bar,
:root.float #updater,
:root.float #thread-stats,
@ -124,7 +124,7 @@ div.center:not(.ad-cnt) {
#notifications {
z-index: 70;
}
#qp, #ihover {
#qp, .ihover {
z-index: 60;
}
#menu {
@ -840,7 +840,7 @@ span.hide-announcement {
:root.gecko.fit-width .full-image {
width: 100%;
}
#ihover {
.ihover {
-moz-box-sizing: border-box;
box-sizing: border-box;
max-height: 100%;

View File

@ -103,9 +103,12 @@ ImageExpand =
return if post.isHidden or post.file.isExpanded or $.hasClass thumb, 'expanding'
$.addClass thumb, 'expanding'
naturalHeight = if isVideo then 'videoHeight' else 'naturalHeight'
if post.file.fullImage
if img = post.file.fullImage
# Expand already-loaded/ing picture.
$.asap (-> post.file.fullImage[naturalHeight]), ->
$.rmClass img, 'ihover'
$.addClass img, 'full-image'
img.controls = (img.parentNode isnt thumb.parentNode)
$.asap (-> img[naturalHeight]), ->
ImageExpand.completeExpand post
return
post.file.fullImage = img = $.el (if isVideo then 'video' else 'img'),
@ -141,7 +144,7 @@ ImageExpand =
{file} = post
video = file.fullImage
file.videoControls = []
video.muted = true
video.muted = not Conf['Allow Sound']
if video.controls
# contract link in file info
contract = $.el 'a',

View File

@ -9,7 +9,7 @@ ImageHover =
name: 'Image Hover'
cb: @catalogNode
node: ->
return unless @file?.isImage
return unless @file?.isImage or @file?.isVideo
$.on @file.thumb, 'mouseover', ImageHover.mouseover
catalogNode: ->
return unless @thread.OP.file?.isImage
@ -19,17 +19,35 @@ ImageHover =
g.posts[@parentNode.dataset.fullID]
else
Get.postFromNode @
el = $.el 'img',
id: 'ihover'
src: post.file.URL
{isVideo} = post.file
if post.file.fullImage
el = post.file.fullImage
$.rmClass el, 'full-image'
$.addClass el, 'ihover'
else
el = $.el (if isVideo then 'video' else 'img'),
className: 'ihover'
src: post.file.URL
post.file.fullImage = el
{thumb} = post.file
$.after (if isVideo and Conf['Show Controls'] then thumb.parentNode else thumb), el
el.dataset.fullID = post.fullID
$.add Header.hover, el
if isVideo
el.loop = true
el.controls = false
el.muted = not Conf['Allow Sound']
el.play() if Conf['Autoplay']
naturalHeight = if post.file.isVideo then 'videoHeight' else 'naturalHeight'
UI.hover
root: @
el: el
latestEvent: e
endEvents: 'mouseout click'
asapTest: -> el.naturalHeight
asapTest: -> el[naturalHeight]
cb: ->
el.pause() if isVideo
$.rmClass el, 'ihover'
$.addClass el, 'full-image'
$.on el, 'error', ImageHover.error
error: ->
return unless doc.contains @

View File

@ -1,6 +1,6 @@
QR =
# Add empty mimeType to avoid errors with URLs selected in Window's file dialog.
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', '']
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', 'video/webm', '']
init: ->
@db = new DataBoard 'yourPosts'
@ -371,13 +371,16 @@ QR =
$.addClass QR.nodes.el, 'dump' unless isSingle
checkDimensions: (file, isSingle, max) ->
img = new Image()
img.onload = =>
{height, width} = img
return QR.error "#{file.name}: Image too large (image: #{img.height}x#{img.width}px, max: #{QR.max_heigth}x#{QR.max_width}px)" if height > QR.max_heigth or width > QR.max_heigth
return QR.error "#{file.name}: Image too small (image: #{img.height}x#{img.width}px, min: #{QR.min_heigth}x#{QR.min_width}px)" if height < QR.min_heigth or width < QR.min_heigth
if /^image\//.test file.type
img = new Image()
img.onload = =>
{height, width} = img
return QR.error "#{file.name}: Image too large (image: #{img.height}x#{img.width}px, max: #{QR.max_heigth}x#{QR.max_width}px)" if height > QR.max_heigth or width > QR.max_heigth
return QR.error "#{file.name}: Image too small (image: #{img.height}x#{img.width}px, min: #{QR.min_heigth}x#{QR.min_width}px)" if height < QR.min_heigth or width < QR.min_heigth
QR.handleFile file, isSingle, max
img.src = URL.createObjectURL file
else
QR.handleFile file, isSingle, max
img.src = URL.createObjectURL file
handleFile: (file, isSingle, max) ->
if file.size > max

View File

@ -146,7 +146,7 @@ QR.post = class
when 'filename'
return unless @file
@file.newName = @filename.replace /[/\\]/g, '-'
unless /\.(jpe?g|png|gif|pdf|swf)$/i.test @filename
unless /\.(jpe?g|png|gif|pdf|swf|webm)$/i.test @filename
# 4chan will truncate the filename if it has no extension,
# but it will always replace the extension by the correct one,
# so we suffix it with '.jpg' when needed.