diff --git a/4chan_x.user.js b/4chan_x.user.js
index fdd4a29fe..a2e94cf3c 100644
--- a/4chan_x.user.js
+++ b/4chan_x.user.js
@@ -74,7 +74,7 @@
*/
(function() {
- var $, $$, Board, Build, Clone, Conf, Config, Get, Main, Post, QuoteBacklink, QuoteInline, QuotePreview, Quotify, Redirect, Thread, Time, UI, d, g,
+ var $, $$, Board, Build, Clone, Conf, Config, FileInfo, Get, Main, Post, QuoteBacklink, QuoteInline, QuotePreview, Quotify, Redirect, Thread, Time, UI, d, g,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@@ -971,6 +971,13 @@
$.log(err, 'Time Formatting');
}
}
+ if (Conf['File Info Formatting']) {
+ try {
+ FileInfo.init();
+ } catch (err) {
+ $.log(err, 'File Info Formatting');
+ }
+ }
return $.ready(Main.initFeaturesReady);
},
initFeaturesReady: function() {
@@ -1036,7 +1043,7 @@
return $.on(d, 'DOMNodeInserted', Main.addStyle);
}
},
- css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n z-index: 1;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* quote related */\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n position: fixed;\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n outline: 2px solid rgba(216, 94, 49, .7);\n}"
+ css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n z-index: 1;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* quote */\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n position: fixed;\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n outline: 2px solid rgba(216, 94, 49, .7);\n}\n\n/* file */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull {\n display: none;\n}"
};
Redirect = {
@@ -1836,7 +1843,7 @@
Time = {
init: function() {
- this.funk = this.createFunc();
+ this.funk = this.createFunc(Conf['time']);
return Post.prototype.callbacks.push({
name: 'Time Formatting',
cb: this.node
@@ -1848,9 +1855,9 @@
}
return this.nodes.date.textContent = Time.funk(Time, this.info.date);
},
- createFunc: function() {
+ createFunc: function(format) {
var code;
- code = Conf['time'].replace(/%([A-Za-z])/g, function(s, c) {
+ code = format.replace(/%([A-Za-z])/g, function(s, c) {
if (c in Time.formatters) {
return "' + Time.formatters." + c + ".call(date) + '";
} else {
@@ -1928,6 +1935,97 @@
}
};
+ FileInfo = {
+ init: function() {
+ this.funk = this.createFunc(Conf['fileInfo']);
+ return Post.prototype.callbacks.push({
+ name: 'File Info Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (!this.file || this.isClone) {
+ return;
+ }
+ return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
+ },
+ createFunc: function(format) {
+ var code;
+ code = format.replace(/%([BKlLMnNprs])/g, function(s, c) {
+ if (c in FileInfo.formatters) {
+ return "' + FileInfo.formatters." + c + ".call(post) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('FileInfo', 'post', "return '" + code + "'");
+ },
+ convertUnit: function(size, unit) {
+ var i;
+ if (unit === 'B') {
+ return "" + (size.toFixed()) + " Bytes";
+ }
+ i = 1 + ['KB', 'MB'].indexOf(unit);
+ while (i--) {
+ size /= 1024;
+ }
+ size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
+ return "" + size + " " + unit;
+ },
+ escape: function(name) {
+ return name.replace(/<|>/g, function(c) {
+ return c === '<' && '<' || '>';
+ });
+ },
+ formatters: {
+ l: function() {
+ return "" + (FileInfo.formatters.n.call(this)) + "";
+ },
+ L: function() {
+ return "" + (FileInfo.formatters.N.call(this)) + "";
+ },
+ n: function() {
+ var fullname, shortname;
+ fullname = this.file.name;
+ shortname = Build.shortFilename(this.file.name, this.isReply);
+ if (fullname === shortname) {
+ return FileInfo.escape(fullname);
+ } else {
+ return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
+ }
+ },
+ N: function() {
+ return FileInfo.escape(this.file.name);
+ },
+ p: function() {
+ if (this.file.isSpoiler) {
+ return 'Spoiler';
+ } else {
+ return '';
+ }
+ },
+ s: function() {
+ return $.bytesToString(this.file.size);
+ },
+ B: function() {
+ return FileInfo.convertUnit(this.file.size, 'B');
+ },
+ K: function() {
+ return FileInfo.convertUnit(this.file.size, 'KB');
+ },
+ M: function() {
+ return FileInfo.convertUnit(this.file.size, 'MB');
+ },
+ r: function() {
+ if (this.file.isImage) {
+ return this.file.dimensions;
+ } else {
+ return 'PDF';
+ }
+ }
+ }
+ };
+
Main.init();
}).call(this);
diff --git a/script.coffee b/script.coffee
index c41866511..8b46f22a2 100644
--- a/script.coffee
+++ b/script.coffee
@@ -771,6 +771,13 @@ Main =
# XXX handle error
$.log err, 'Time Formatting'
+ if Conf['File Info Formatting']
+ try
+ FileInfo.init()
+ catch err
+ # XXX handle error
+ $.log err, 'File Info Formatting'
+
$.ready Main.initFeaturesReady
initFeaturesReady: ->
if d.title is '4chan - 404 Not Found'
@@ -880,7 +887,7 @@ body.fourchan_x {
float: right;
}
-/* quote related */
+/* quote */
.inlined {
opacity: .5;
}
@@ -919,6 +926,12 @@ body.fourchan_x {
.qphl {
outline: 2px solid rgba(216, 94, 49, .7);
}
+
+/* file */
+.fileText:hover .fntrunc,
+.fileText:not(:hover) .fnfull {
+ display: none;
+}
"""
@@ -1604,15 +1617,15 @@ QuoteBacklink =
Time =
init: ->
- @funk = @createFunc()
+ @funk = @createFunc Conf['time']
Post::callbacks.push
name: 'Time Formatting'
cb: @node
node: ->
return if @isClone
@nodes.date.textContent = Time.funk Time, @info.date
- createFunc: ->
- code = Conf['time'].replace /%([A-Za-z])/g, (s, c) ->
+ createFunc: (format) ->
+ code = format.replace /%([A-Za-z])/g, (s, c) ->
if c of Time.formatters
"' + Time.formatters.#{c}.call(date) + '"
else
@@ -1660,6 +1673,54 @@ Time =
S: -> Time.zeroPad @getSeconds()
y: -> @getFullYear() - 2000
+FileInfo =
+ init: ->
+ @funk = @createFunc Conf['fileInfo']
+ Post::callbacks.push
+ name: 'File Info Formatting'
+ cb: @node
+ node: ->
+ return if !@file or @isClone
+ @file.text.innerHTML = FileInfo.funk FileInfo, @
+ createFunc: (format) ->
+ code = format.replace /%([BKlLMnNprs])/g, (s, c) ->
+ if c of FileInfo.formatters
+ "' + FileInfo.formatters.#{c}.call(post) + '"
+ else
+ s
+ Function 'FileInfo', 'post', "return '#{code}'"
+ convertUnit: (size, unit) ->
+ if unit is 'B'
+ return "#{size.toFixed()} Bytes"
+ i = 1 + ['KB', 'MB'].indexOf unit
+ size /= 1024 while i--
+ size =
+ if unit is 'MB'
+ Math.round(size * 100) / 100
+ else
+ size.toFixed()
+ "#{size} #{unit}"
+ escape: (name) ->
+ name.replace /<|>/g, (c) ->
+ c is '<' and '<' or '>'
+ formatters:
+ l: -> "#{FileInfo.formatters.n.call @}"
+ L: -> "#{FileInfo.formatters.N.call @}"
+ n: ->
+ fullname = @file.name
+ shortname = Build.shortFilename @file.name, @isReply
+ if fullname is shortname
+ FileInfo.escape fullname
+ else
+ "#{FileInfo.escape shortname}#{FileInfo.escape fullname}"
+ N: -> FileInfo.escape @file.name
+ p: -> if @file.isSpoiler then 'Spoiler' else ''
+ s: -> $.bytesToString @file.size
+ B: -> FileInfo.convertUnit @file.size, 'B'
+ K: -> FileInfo.convertUnit @file.size, 'KB'
+ M: -> FileInfo.convertUnit @file.size, 'MB'
+ r: -> if @file.isImage then @file.dimensions else 'PDF'
+
Main.init()