szurubooru/public_html/js/Util/Misc.js

249 lines
6.5 KiB
JavaScript
Raw Normal View History

2014-09-02 09:36:42 +02:00
var App = App || {};
App.Util = App.Util || {};
2014-09-02 09:36:42 +02:00
App.Util.Misc = function(_, jQuery, marked, promise) {
2014-09-02 09:36:42 +02:00
2014-09-16 17:29:11 +02:00
var exitConfirmationEnabled = false;
2014-09-02 09:36:42 +02:00
function transparentPixel() {
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
function enableExitConfirmation() {
2014-09-16 17:29:11 +02:00
exitConfirmationEnabled = true;
jQuery(window).bind('beforeunload', function(e) {
return 'There are unsaved changes.';
});
}
function disableExitConfirmation() {
2014-09-16 17:29:11 +02:00
exitConfirmationEnabled = false;
jQuery(window).unbind('beforeunload');
}
2014-09-16 17:29:11 +02:00
function isExitConfirmationEnabled() {
return exitConfirmationEnabled;
}
2014-10-05 11:05:34 +02:00
function loadImagesNicely($img) {
if (!$img.get(0).complete) {
$img.addClass('loading');
$img.css({opacity: 0});
var $div = jQuery('<div>Loading ' + $img.attr('alt') + '&hellip;</div>');
var width = $img.width();
var height = $img.height();
if (width > 50 && height > 50) {
$div.css({
position: 'absolute',
width: width + 'px',
height: height + 'px',
color: 'rgba(0, 0, 0, 0.15)',
zIndex: -1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center'});
$div.insertBefore($img);
$div.offset($img.offset());
}
$img.bind('load', function() {
$img.animate({opacity: 1}, 'fast');
$img.removeClass('loading');
$div.fadeOut($div.remove);
});
}
2014-10-05 11:05:34 +02:00
}
2014-09-04 18:06:25 +02:00
function promiseTemplate(templateName) {
2014-10-05 10:41:12 +02:00
return promiseTemplateFromDOM(templateName) ||
2014-09-08 22:02:28 +02:00
promiseTemplateWithAJAX(templateName);
2014-09-02 09:36:42 +02:00
}
2014-09-04 18:06:25 +02:00
function promiseTemplateFromDOM(templateName) {
2014-09-02 09:36:42 +02:00
var $template = jQuery('#' + templateName + '-template');
if ($template.length) {
2014-09-04 18:06:25 +02:00
return promise.make(function(resolve, reject) {
2014-10-05 10:41:12 +02:00
resolve(_.template($template.html()));
2014-09-02 09:36:42 +02:00
});
}
return null;
}
2014-09-04 18:06:25 +02:00
function promiseTemplateWithAJAX(templateName) {
return promise.make(function(resolve, reject) {
2014-09-02 09:36:42 +02:00
var templatesDir = '/templates';
var templateUrl = templatesDir + '/' + templateName + '.tpl';
2014-09-08 22:02:28 +02:00
jQuery.ajax({
2014-09-02 09:36:42 +02:00
url: templateUrl,
method: 'GET',
success: function(data, textStatus, xhr) {
2014-10-05 10:41:12 +02:00
resolve(_.template(data));
2014-09-02 09:36:42 +02:00
},
error: function(xhr, textStatus, errorThrown) {
2014-09-08 22:02:28 +02:00
console.log(new Error('Error while loading template ' + templateName + ': ' + errorThrown));
2014-09-02 09:36:42 +02:00
reject();
},
});
});
}
2014-09-07 09:57:01 +02:00
function formatRelativeTime(timeString) {
2014-09-08 22:02:28 +02:00
if (!timeString) {
2014-09-07 09:57:01 +02:00
return 'never';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
2014-09-08 22:02:28 +02:00
var then = Date.parse(timeString);
2014-09-07 09:57:01 +02:00
var now = Date.now();
2014-09-08 22:02:28 +02:00
var difference = Math.abs(now - then);
var future = now < then;
2014-09-07 09:57:01 +02:00
var text = (function(difference) {
var mul = 1000;
var prevMul;
mul *= 60;
2014-09-08 22:02:28 +02:00
if (difference < mul) {
2014-09-07 09:57:01 +02:00
return 'a few seconds';
2014-09-08 22:02:28 +02:00
} else if (difference < mul * 2) {
2014-09-07 09:57:01 +02:00
return 'a minute';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
prevMul = mul; mul *= 60;
2014-09-08 22:02:28 +02:00
if (difference < mul) {
2014-09-07 09:57:01 +02:00
return Math.round(difference / prevMul) + ' minutes';
2014-09-08 22:02:28 +02:00
} else if (difference < mul * 2) {
2014-09-07 09:57:01 +02:00
return 'an hour';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
prevMul = mul; mul *= 24;
2014-09-08 22:02:28 +02:00
if (difference < mul) {
2014-09-07 09:57:01 +02:00
return Math.round(difference / prevMul) + ' hours';
2014-09-08 22:02:28 +02:00
} else if (difference < mul * 2) {
2014-09-07 09:57:01 +02:00
return 'a day';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
prevMul = mul; mul *= 30.42;
2014-09-08 22:02:28 +02:00
if (difference < mul) {
2014-09-07 09:57:01 +02:00
return Math.round(difference / prevMul) + ' days';
2014-09-08 22:02:28 +02:00
} else if (difference < mul * 2) {
2014-09-07 09:57:01 +02:00
return 'a month';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
prevMul = mul; mul *= 12;
2014-09-08 22:02:28 +02:00
if (difference < mul) {
2014-09-07 09:57:01 +02:00
return Math.round(difference / prevMul) + ' months';
2014-09-08 22:02:28 +02:00
} else if (difference < mul * 2) {
2014-09-07 09:57:01 +02:00
return 'a year';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
return Math.round(difference / mul) + ' years';
})(difference);
2014-09-08 22:02:28 +02:00
if (text === 'a day') {
2014-09-07 09:57:01 +02:00
return future ? 'tomorrow' : 'yesterday';
2014-09-08 22:02:28 +02:00
}
2014-09-07 09:57:01 +02:00
return future ? 'in ' + text : text + ' ago';
}
2014-09-23 19:00:40 +02:00
function formatUnits(number, base, suffixes, callback) {
if (!number && number !== 0) {
2014-09-23 19:00:40 +02:00
return NaN;
}
number *= 1.0;
var suffix = suffixes.shift();
while (number >= base && suffixes.length > 0) {
suffix = suffixes.shift();
number /= base;
}
if (typeof(callback) === 'undefined') {
callback = function(number, suffix) {
return suffix ? number.toFixed(1) + suffix : number;
};
}
return callback(number, suffix);
}
function formatFileSize(fileSize) {
return formatUnits(
fileSize,
1024,
['B', 'K', 'M', 'G'],
function(number, suffix) {
var decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
return number.toFixed(decimalPlaces) + suffix;
});
}
2014-10-04 14:06:44 +02:00
function formatMarkdown(text) {
2014-10-05 20:22:45 +02:00
var renderer = new marked.Renderer();
var options = {
renderer: renderer,
breaks: true,
sanitize: true,
smartypants: true,
};
var preDecorator = function(text) {
//prevent ^#... from being treated as headers, due to tag permalinks
2014-11-10 22:28:52 +01:00
text = text.replace(/^#/g, '%%%#');
2014-11-09 10:44:02 +01:00
//fix \ before ~ being stripped away
2014-11-10 22:28:52 +01:00
text = text.replace(/\\~/g, '%%%T');
2014-10-05 20:22:45 +02:00
return text;
};
var postDecorator = function(text) {
2014-11-10 22:28:52 +01:00
//restore fixes
text = text.replace(/%%%T/g, '\\~');
text = text.replace(/%%%#/g, '#');
2014-10-05 20:22:45 +02:00
//search permalinks
text = text.replace(/\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, '<a href="#/posts/query=$1"><code>$1</code></a>');
//spoilers
text = text.replace(/\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, '<span class="spoiler">$1</span>');
//strike-through
2014-11-09 10:44:02 +01:00
text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
2014-11-10 22:28:52 +01:00
text = text.replace(/\\~/g, '~');
2014-10-05 20:22:45 +02:00
//post premalinks
text = text.replace(/(^|[\s<>\(\)\[\]])@(\d+)/g, '$1<a href="#/post/$2"><code>@$2</code></a>');
//user permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\+([a-zA-Z0-9_-]+)/g, '$1<a href="#/user/$2"><code>+$2</code></a>');
//tag permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\#([^\s<>/\\]+)/g, '$1<a href="#/posts/query=$2"><code>#$2</code></a>');
return text;
};
return postDecorator(marked(preDecorator(text), options));
2014-10-04 14:06:44 +02:00
}
function appendComplexRouteParam(baseUri, params) {
var result = baseUri + '/';
_.each(params, function(v, k) {
if (typeof(v) !== 'undefined') {
result += k + '=' + v + ';';
}
});
return result.slice(0, -1);
}
2014-09-02 09:36:42 +02:00
return {
2014-09-04 18:06:25 +02:00
promiseTemplate: promiseTemplate,
2014-09-07 09:57:01 +02:00
formatRelativeTime: formatRelativeTime,
2014-09-23 19:00:40 +02:00
formatFileSize: formatFileSize,
2014-10-04 14:06:44 +02:00
formatMarkdown: formatMarkdown,
enableExitConfirmation: enableExitConfirmation,
disableExitConfirmation: disableExitConfirmation,
2014-09-16 17:29:11 +02:00
isExitConfirmationEnabled: isExitConfirmationEnabled,
transparentPixel: transparentPixel,
2014-10-05 11:05:34 +02:00
loadImagesNicely: loadImagesNicely,
appendComplexRouteParam: appendComplexRouteParam,
2014-09-02 09:36:42 +02:00
};
2014-09-08 22:02:28 +02:00
};
2014-09-02 09:36:42 +02:00
App.DI.registerSingleton('util', ['_', 'jQuery', 'marked', 'promise'], App.Util.Misc);