chevereto-free/app/lib/chevereto.js

6179 lines
225 KiB
JavaScript

/* --------------------------------------------------------------------
This file is part of Chevereto Free.
https://chevereto.com/free
(c) Rodolfo Berrios <rodolfo@chevereto.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
--------------------------------------------------------------------- */
$(function () {
// Window listeners
$(window).on("resize", function () {
CHV.fn.uploader.boxSizer();
if (typeof user_background_full_fix == "function") {
user_background_full_fix();
}
CHV.fn.bindSelectableItems();
CHV.fn.listingViewer.placeholderSizing();
});
if (window.opener) {
$(window).on("load", function (e) {
window.opener.postMessage(
{
id: window.name,
requestAction: "postSettings",
},
"*"
);
});
$(window).on("message", function (e) {
var data = e.originalEvent.data;
if (
typeof data.id == typeof undefined ||
typeof data.settings == typeof undefined
) {
return;
}
if (window.name !== data.id) {
return;
}
CHV.obj.opener.uploadPlugin[data.id] = data.settings;
});
}
// Landing fancy load
if ($("#home-cover, #maintenance-wrapper, #login").exists()) {
var landing_src = $("#maintenance-wrapper").exists()
? $("#maintenance-wrapper")
.css("background-image")
.slice(4, -1)
.replace(/^\"|\"$/g, "")
: $(".home-cover-img", "#home-cover-slideshow").first().attr("data-src");
function showHomeCover() {
$("body").addClass("load");
if (!$("#maintenance-wrapper").exists()) {
$(".home-cover-img", "#home-cover-slideshow")
.first()
.css("background-image", "url(" + landing_src + ")")
.addClass("animate-in--alt")
.removeAttr("data-src");
}
setTimeout(function () {
setTimeout(function () {
$("body").addClass("loaded");
}, 400 * 3);
setTimeout(function () {
showHomeSlideshow();
}, 7000);
}, 400 * 1.5);
}
var showHomeSlideshowInterval = function () {
setTimeout(function () {
showHomeSlideshow();
}, 8000);
};
function showHomeSlideshow() {
var $image = $(
".home-cover-img[data-src]",
"#home-cover-slideshow"
).first();
var $images = $(".home-cover-img", "#home-cover-slideshow");
if ($image.length == 0) {
if ($images.length == 1) return;
$images.first().removeClass("animate-in");
$("#home-cover-slideshow").append($images.first());
setTimeout(function () {
$(".home-cover-img:last", "#home-cover-slideshow").addClass(
"animate-in"
);
}, 20);
setTimeout(function () {
$(".home-cover-img:not(:last)", "#home-cover-slideshow").removeClass(
"animate-in"
);
}, 4000);
showHomeSlideshowInterval();
} else {
var src = $image.attr("data-src");
$("<img/>")
.attr("src", src)
.on("load error", function () {
$(this).remove();
$image
.css("background-image", "url(" + src + ")")
.addClass("animate-in")
.removeAttr("data-src");
setTimeout(function () {
$(
".home-cover-img:not(:last)",
"#home-cover-slideshow"
).removeClass("animate-end animate-in--alt");
}, 2000);
showHomeSlideshowInterval();
});
}
}
if (landing_src) {
$("<img/>")
.attr("src", landing_src)
.on("load error", function () {
$(this).remove();
showHomeCover();
});
} else {
showHomeCover();
}
}
// Set the anywhere objects, just for shorter calling in $.
var anywhere_upload = CHV.fn.uploader.selectors.root,
anywhere_upload_queue = CHV.fn.uploader.selectors.queue,
$anywhere_upload = $(anywhere_upload),
$anywhere_upload_queue = $(anywhere_upload_queue);
$(document).on("click", "[data-action=top-bar-upload]", function (e) {
if ($("body").is("#upload") || $(this).data("link") == 1) return;
CHV.fn.uploader.toggle();
});
var ThemeTone = {
tones: {
light: {
html: "tone-light top-bar-white",
top: "white",
},
dark: {
html: "tone-dark top-bar-black",
top: "black",
},
},
isDark: function () {
return $("html").hasClass("tone-dark");
},
toggle: function () {
var toTone = this.isDark() ? "light" : "dark";
$("html")
.removeClass(this.tones.light.html + " " + this.tones.dark.html)
.addClass(this.tones[toTone].html);
if (!$("body#index").exists()) {
$("#top-bar")
.removeClass(this.tones.light.top + " " + this.tones.dark.top)
.addClass(this.tones[toTone].top);
}
},
save: function () {
$.ajax({
type: "POST",
data: {
action: "toggleTone",
},
cache: false,
});
ThemeTone.aux = ThemeTone.isDark();
},
timeout: {},
aux: {},
};
ThemeTone.aux = ThemeTone.isDark();
$(document).on("click", "[data-action=top-bar-tone]", function (e) {
if (e.isPropagationStopped()) {
return;
}
if ($("[data-action=top-bar-menu-full]").is(":visible")) {
PF.fn.topMenu.hide();
}
clearTimeout(ThemeTone.timeout);
ThemeTone.toggle();
ThemeTone.timeout = setTimeout(function () {
if (ThemeTone.aux !== ThemeTone.isDark()) {
ThemeTone.save();
}
}, 750);
});
// Close upload box
$("[data-action=close-upload]", $anywhere_upload).click(function () {
if ($anywhere_upload.is(":animated")) {
return;
}
$("[data-action=top-bar-upload]", "#top-bar").click();
});
// Reset upload box
$("[data-action=reset-upload]", $anywhere_upload).click(function () {
if (CHV.fn.uploader.isUploading) {
$(
"[data-action=cancel-upload-remaining], [data-action=cancel-upload]",
$anywhere_upload
).trigger("click");
}
CHV.fn.uploader.reset();
});
// Cancel remaining uploads
$(
"[data-action=cancel-upload-remaining], [data-action=cancel-upload]",
$anywhere_upload
).click(function () {
CHV.fn.uploader.isUploading = false;
$("[data-action=cancel]", $anywhere_upload_queue).click();
if (Object.size(CHV.fn.uploader.results.success) > 0) {
CHV.fn.uploader.displayResults();
return;
} else {
CHV.fn.uploader.reset();
}
});
// Toggle upload privacy
$(document).on(
"click",
"[data-action=upload-privacy]:not(disabled)",
function (e) {
if (e.isDefaultPrevented()) return;
current_privacy = $(this).data("privacy");
target_privacy = current_privacy == "public" ? "private" : "public";
this_lock = $(".icon", this).data("lock");
this_unlock = $(".icon", this).data("unlock");
$(".icon", this)
.removeClass(this_lock + " " + this_unlock)
.addClass(current_privacy == "public" ? this_lock : this_unlock);
$(this).data("privacy", target_privacy);
$("[data-action=upload-privacy-copy]").html(
$("[data-action=upload-privacy]").html()
);
$upload_button = $("[data-action=upload]", $anywhere_upload);
$upload_button.text($upload_button.data(target_privacy));
$(this).tipTip("hide");
}
);
// Do the thing when the fileupload changes
$(CHV.fn.uploader.selectors.file + ", " + CHV.fn.uploader.selectors.camera)
.on("change", function (e) {
if (!$(CHV.fn.uploader.selectors.root).data("shown")) {
CHV.fn.uploader.toggle(
{
callback: function (e) {
CHV.fn.uploader.add(e);
},
},
e
);
} else {
CHV.fn.uploader.add(e);
}
})
.on("click", function (e) {
if ($(this).data("login-needed") && !PF.fn.is_user_logged()) {
return;
}
});
function isFileTransfer(e) {
var e = e.originalEvent,
isFileTransfer = false;
if (e.dataTransfer.types) {
for (var i = 0; i < e.dataTransfer.types.length; i++) {
if (e.dataTransfer.types[i] == "Files") {
isFileTransfer = true;
break;
}
}
}
return isFileTransfer;
}
// Enable uploader events
if ($(CHV.fn.uploader.selectors.root).exists()) {
$("body").on({
dragenter: function (e) {
e.preventDefault();
if (!isFileTransfer(e)) {
return false;
}
if (!$(CHV.fn.uploader.selectors.dropzone).exists()) {
$("body").append(
$(
'<div id="' +
CHV.fn.uploader.selectors.dropzone.replace("#", "") +
'"/>'
).css({
width: "100%",
height: "100%",
position: "fixed",
/* opacity: 0.5, background: "red",*/
zIndex: 1000,
left: 0,
top: 0,
})
);
}
},
});
$(document).on(
{
dragover: function (e) {
e.preventDefault();
if (!isFileTransfer(e)) {
return false;
}
if (!$(CHV.fn.uploader.selectors.root).data("shown")) {
CHV.fn.uploader.toggle({
reset: false,
});
}
},
dragleave: function (e) {
$(CHV.fn.uploader.selectors.dropzone).remove();
if ($.isEmptyObject(CHV.fn.uploader.files)) {
CHV.fn.uploader.toggle();
}
},
drop: function (e) {
e.preventDefault();
CHV.fn.uploader.add(e);
$(CHV.fn.uploader.selectors.dropzone).remove();
},
},
CHV.fn.uploader.selectors.dropzone
);
}
//
$(document).on("keyup change", "[data-action=resize-combo-input]", function (
e
) {
var $parent = $(this).closest("[data-action=resize-combo-input]");
var $input_width = $("[name=form-width]", $parent);
var $input_height = $("[name=form-height]", $parent);
var ratio = $input_width.data("initial") / $input_height.data("initial");
var image = {
width: Math.round($input_width.prop("value") / ratio),
height: Math.round($input_height.prop("value") * ratio),
};
if ($(e.target).is($input_width)) {
$input_height.prop("value", Math.round(image.width));
} else {
$input_width.prop("value", Math.round(image.height));
}
});
// Edit item from queue
$(document).on(
"click",
anywhere_upload_queue + " [data-action=edit]",
function () {
var $item = $(this).closest("li"),
$queue = $item.closest("ul"),
id = $item.data("id"),
file = CHV.fn.uploader.files[id];
var modal = PF.obj.modal.selectors.root;
var queueObject = $.extend({}, file.formValues || file.parsedMeta);
// Inject global upload options if needed
var injectKeys = ["album_id", "category_id", "nsfw"];
for (var i = 0; i < injectKeys.length; i++) {
var key = injectKeys[i];
if (typeof queueObject[key] == typeof undefined) {
var $object = $(
"[name=upload-" + key.replace("_", "-") + "]",
CHV.fn.uploader.selectors.root
);
var value = $object.prop(
$object.is(":checkbox") ? "checked" : "value"
);
queueObject[key] = $object.is(":checkbox")
? value
? "1"
: null
: value;
}
}
// Resize before upload
PF.fn.modal.call({
type: "html",
template: $("#anywhere-upload-edit-item").html(),
callback: function () {
var imageMaxCfg = {
width:
CHV.obj.config.image.max_width != 0
? CHV.obj.config.image.max_width
: queueObject.width,
height:
CHV.obj.config.image.max_height != 0
? CHV.obj.config.image.max_height
: queueObject.height,
};
var imageMax = $.extend({}, imageMaxCfg);
var ratio = queueObject.width / queueObject.height;
imageMax.width = Math.round(imageMaxCfg.height * ratio);
imageMax.height = Math.round(imageMaxCfg.width / ratio);
if (imageMax.height > imageMaxCfg.height) {
imageMax.height = imageMaxCfg.height;
imageMax.width = Math.round(imageMax.height * ratio);
}
if (imageMax.width > imageMaxCfg.width) {
imageMax.width = imageMaxCfg.width;
imageMax.height = Math.round(imageMax.width / ratio);
}
$.each(queueObject, function (i, v) {
var name = "[name=form-" + i.replace(/_/g, "-") + "]";
var $input = $(name, modal);
if (!$input.exists()) return true;
// Input handler
if ($input.is(":checkbox")) {
$input.prop("checked", $input.attr("value") == v);
} else if ($input.is("select")) {
var $option = $input.find("[value=" + v + "]");
if (!$option.exists()) {
$option = $input.find("option:first");
}
$option.prop("selected", true);
} else {
$input.prop("value", v);
}
if (i == "width" || i == "height") {
var max = imageMax[i];
var value = file.parsedMeta[i] > max ? max : file.parsedMeta[i];
$input
.prop("max", value)
.data("initial", file.parsedMeta[i])
.prop("value", value);
}
});
// Warning on GIF images
if (file.parsedMeta.mimetype !== "image/gif") {
$("[ data-content=animated-gif-warning]", modal).remove();
}
// Canvas image preview
$(".image-preview", modal).append(
$("<canvas/>", {
class: "canvas",
})
);
var source_canvas = $(
".queue-item[data-id=" + id + "] .preview .canvas"
)[0];
var target_canvas = $(".image-preview .canvas", modal)[0];
target_canvas.width = source_canvas.width;
target_canvas.height = source_canvas.height;
var target_canvas_ctx = target_canvas.getContext("2d");
target_canvas_ctx.drawImage(source_canvas, 0, 0);
},
confirm: function () {
if (!PF.fn.form_modal_has_changed()) {
PF.fn.modal.close();
return;
}
// Validations (just in case)
var errors = false;
$.each(["width", "height"], function (i, v) {
var $input = $("[name=form-" + v + "]", modal);
var input_val = parseInt($input.val());
var min_val = parseInt($input.attr("min"));
var max_val = parseInt($input.attr("max"));
if (input_val > max_val || input_val < min_val) {
$input.highlight();
errors = true;
return true;
}
});
if (errors) {
PF.fn.growl.expirable(
PF.fn._s("Check the errors in the form to continue.")
);
return false;
}
if (typeof file.formValues == typeof undefined) {
// Stock formvalues object
file.formValues = {
title: null,
category_id: null,
width: null,
height: null,
nsfw: null,
expiration: null,
description: null,
album_id: null,
};
}
$(":input[name]", modal).each(function (i, v) {
var key = $(this)
.attr("name")
.replace("form-", "")
.replace(/-/g, "_");
if (typeof file.formValues[key] == typeof undefined) return true;
file.formValues[key] = $(this).is(":checkbox")
? $(this).is(":checked")
? $(this).prop("value")
: null
: $(this).prop("value");
});
CHV.fn.uploader.files[id].formValues = file.formValues;
return true;
},
});
}
);
// Remove item from queue
$(document).on(
"click",
anywhere_upload_queue + " [data-action=cancel]",
function () {
var $item = $(this).closest("li"),
$queue = $item.closest("ul"),
id = $item.data("id"),
queue_height = $queue.height(),
item_xhr_cancel = false;
if ($item.hasClass("completed") || $item.hasClass("failed")) {
return;
}
$("#tiptip_holder").hide();
$item.tipTip("destroy").remove();
if (queue_height !== $queue.height()) {
CHV.fn.uploader.boxSizer();
}
if (!$("li", $anywhere_upload_queue).exists()) {
$(
"[data-group=upload-queue-ready], [data-group=upload-queue], [data-group=upload-queue-ready]",
$anywhere_upload
).css("display", "");
}
if (
CHV.fn.uploader.files[id] &&
typeof CHV.fn.uploader.files[id].xhr !== "undefined"
) {
CHV.fn.uploader.files[id].xhr.abort();
item_xhr_cancel = true;
}
if (
typeof CHV.fn.uploader.files[id] !== typeof undefined &&
typeof CHV.fn.uploader.files[id].fromClipboard !== typeof undefined
) {
var c_md5 = CHV.fn.uploader.files[id].md5;
var c_index = CHV.fn.uploader.clipboardImages.indexOf(c_md5);
if (c_index > -1) {
CHV.fn.uploader.clipboardImages.splice(c_index, 1);
}
}
delete CHV.fn.uploader.files[id];
CHV.fn.uploader.queueSize();
if (Object.size(CHV.fn.uploader.files) == 0) {
// No queue left
// Null result ?
if (
!("success" in CHV.fn.uploader) ||
!("results" in CHV.fn.uploader) ||
(Object.size(CHV.fn.uploader.results.success) == 0 &&
Object.size(CHV.fn.uploader.results.error) == 0)
) {
CHV.fn.uploader.reset();
}
} else {
// Do we need to process the next item?
if (item_xhr_cancel && $("li.waiting", $queue).first().length !== 0) {
CHV.fn.uploader.upload($("li.waiting", $queue).first());
}
}
}
);
// Uploader
$(document).on("click", "[data-action=upload]", function () {
$(
"[data-group=upload], [data-group=upload-queue-ready]",
$anywhere_upload
).hide();
$anywhere_upload
.removeClass("queueReady")
.addClass("queueUploading")
.find("[data-group=uploading]")
.show();
CHV.fn.uploader.queueSize();
CHV.fn.uploader.canAdd = false;
$queue_items = $("li", $anywhere_upload_queue);
$queue_items.addClass("uploading waiting");
CHV.fn.uploader.timestamp = new Date().getTime();
CHV.fn.uploader.upload($queue_items.first("li"));
});
/*CHV.obj.image_viewer.$container.swipe({
swipe: function(event, direction, distance, duration, fingerCount) {
// right prev, left next
if(direction == "left" || direction == "right") {
var go = direction == "left" ? "next" : "prev",
$link = $("[data-action="+go+"]", ".image-viewer-navigation");
if($link.exists()) {
window.location = $link.attr("href");
return;
}
}
},
threshold: 100,
excludedElements: ".noSwipe",
allowPageScroll: "vertical"
});*/
// User page
if ($("body#user").exists()) {
if (PF.obj.listing.query_string.page > 1) {
var State = History.getState();
if (State.data && typeof State.data.scrollTop !== "undefined") {
if ($(window).scrollTop() !== State.data.scrollTop) {
$(window).scrollTop(State.data.scrollTop);
}
} else {
//var scrollTop = $(".follow-scroll").offset().top - $(".follow-scroll").height();
var scrollTop = $("#background-cover").height() - 160;
$("html, body").animate(
{
scrollTop: scrollTop,
},
0
);
}
}
}
if ($("#top-bar-shade").exists() && $("#top-bar-shade").css("opacity")) {
$("#top-bar-shade").data(
"initial-opacity",
Number($("#top-bar-shade").css("opacity"))
);
}
if (PF.fn.isDevice("phone")) {
// $("#top-bar-shade").css("opacity", 1);
}
$(window).on("scroll resize", function () {
// if (PF.fn.isDevice('phone')) {
// $("#background-cover-src").css("transform", "");
// $("#top-bar-shade").css("opacity", 1);
// return;
// }
var Y = $(window).scrollTop();
if (Y < 0) return;
var $top_bar = $("#top-bar");
var rate = Number(
Y /
($("#background-cover, [data-content=follow-scroll-opacity]").height() -
$top_bar.height())
);
if (rate > 1) rate = 1;
if ($("#top-bar-shade").data("initial-opacity")) {
rate += $("#top-bar-shade").data("initial-opacity");
}
$("#top-bar-shade").css({
opacity: rate,
});
// if (rate == 1) return;
$("#background-cover-src").css({
transform: "translate(0, " + Y * 0.8 + "px" + ")",
});
});
// Selectable list items
CHV.fn.bindSelectableItems();
// Image viewer page
if ($("body#image").exists()) {
// Data load detected
if ($(CHV.obj.image_viewer.selector + " [data-load=full]").length > 0) {
$(document).on("click", CHV.obj.image_viewer.loader, function (e) {
CHV.fn.viewerLoadImage();
});
if (
$(CHV.obj.image_viewer.loader).data("size") >
CHV.obj.config.image.load_max_filesize.getBytes()
) {
$(CHV.obj.image_viewer.loader).css("display", "block");
} else {
CHV.fn.viewerLoadImage();
}
// Fix viewer width when height changes and boom! a wild scrollbar appears
$(document).bind("DOMSubtreeModified", function () {
if (
$("html").height() > $(window).innerHeight() &&
!$("html").hasClass("scrollbar-y")
) {
$("html").addClass("scrollbar-y");
$(document).data({
width: $(this).width(),
height: $(this).height(),
});
CHV.fn.image_viewer_full_fix();
}
});
$(window).on("resize", function () {
CHV.fn.image_viewer_full_fix();
});
// Viewer navigation
$(document).on("keyup", function (e) {
var $this = $(e.target),
key = e.charCode || e.keyCode;
if ($this.is(":input")) {
return;
} else {
// Next 39, Prev 37
if (
CHV.obj.image_viewer.$navigation.exists() &&
(key == 37 || key == 39)
) {
var navigation_jump_url = $(
"[data-action=" + (key == 37 ? "prev" : "next") + "]",
CHV.obj.image_viewer.$navigation
).attr("href");
if (
typeof navigation_jump_url !== "undefined" &&
navigation_jump_url !== ""
) {
window.location = $(
"[data-action=" + (key == 37 ? "prev" : "next") + "]",
CHV.obj.image_viewer.$navigation
).attr("href");
}
}
}
});
} else {
CHV.fn.viewerImageZoomClass();
}
}
$(document)
.on("click", CHV.obj.image_viewer.container, function (e) {
if (
!(
$(this).hasClass("cursor-zoom-in") ||
$(this).hasClass("cursor-zoom-out")
)
)
return;
var zoom_in = $(this).hasClass("cursor-zoom-in");
$(this).removeClass("cursor-zoom-in cursor-zoom-out");
if (zoom_in) {
var width = $(this)[0].getBoundingClientRect().width,
height = $(this)[0].getBoundingClientRect().height,
ratio = $("img", this).attr("width") / $("img", this).attr("height"),
new_width;
if (typeof $(this).data("dimentions") == typeof undefined) {
$(this).data({
dimentions: {
width: width,
height: height,
},
ratio: ratio,
});
}
if ($("img", this).attr("width") > $(window).width()) {
$(this).css({
width: "100%",
});
new_width = $(this).width();
$(this).css({
width: width,
});
} else {
new_width = $("img", this).attr("width");
}
$(this)
.addClass("cursor-zoom-out")
.css({
width: new_width,
height: new_width / ratio + "px",
});
} else {
$(this).addClass("cursor-zoom-in").css($(this).data("dimentions"));
}
e.preventDefault();
})
.on("contextmenu", CHV.obj.image_viewer.container, function (e) {
if (!CHV.obj.config.image.right_click) {
e.preventDefault();
return false;
}
});
$(document).on(
"contextmenu",
"html.device-mobile a.image-container",
function (e) {
e.preventDefault();
return false;
}
);
$(document).on("keyup", "input[data-dashboard-tool]", function (e) {
if (e.keyCode == 13) {
var $button = $("[data-action=" + $(this).data("dashboard-tool") + "]");
$button.click();
}
});
$(document).on("click", "[data-action=dashboardTool]", function (e) {
e.preventDefault();
var tool = $(this).data("tool");
var dataSet = $(this).data("data");
var data = $.extend({}, dataSet);
var inputs = {};
for (var key in data) {
var val = $(data[key]).val();
if ($(data[key]).prop("disabled") || !val) {
return;
}
inputs[key] = $(data[key]);
data[key] = val;
}
data.action = tool;
var ajaxObj = {
type: "GET", // !
cache: false,
};
ajaxObj.data = data;
var $parent = $(this).closest(".input-label");
var validate = true;
var message;
if (validate == false) {
PF.fn.growl.expirable(message);
return;
}
for (var key in inputs) {
// inputs[key].prop("disabled", true);
}
PF.fn.loading.inline($(".loading", $parent), {
size: "small",
valign: "middle",
});
$parent.find(".btn .text").hide();
$.ajax(ajaxObj).complete(function (XHR) {
var response = XHR.responseJSON;
// inputs[key].prop("disabled", false);
$(".loading", $parent).empty();
$parent.find(".btn .text").show();
if (
response.status_code == 200 &&
typeof response.success.redirURL !== typeof undefined
) {
window.location.href = response.success.redirURL;
return;
}
PF.fn.growl.call(
response[response.status_code == 200 ? "success" : "error"].message
);
});
});
// Third-party plugin, magic comes in 3...
$(document).on("click", "[data-action=openerPostMessage]", function (e) {
if (!window.opener) return;
e.preventDefault();
var target_attr = "data-action-target";
var $target = $(
$(this).is("[" + target_attr + "]") ? $(this).attr(target_attr) : this
);
var val = $target[$target.is(":input") ? "val" : "html"]();
window.opener.postMessage(
{
id: window.name,
message: val,
},
"*"
);
});
/*
// Input copy
$(document).on("mouseenter mouseleave", ".input-copy", function(e){
if(navigator.userAgent.match(/(iPad|iPhone|iPod)/i)) {
return;
}
$(".btn-copy", this)[e.type == "mouseenter" ? "show" : "hide"]();
});
$(document).on("click", ".input-copy .btn-copy", function(){
var $input = $(this).closest(".input-copy").find("input");
$(this).hide();
$input.highlight();
});
*/
/**
* USER SIDE LISTING EDITOR
* -------------------------------------------------------------------------------------------------
*/
$(document).on("click", "[data-action=list-tools] [data-action]", function (
e
) {
var $this = $(e.target),
$list_item = $this.closest("[data-id]");
if (
$list_item &&
$list_item.find("[data-action=select]").exists() &&
(e.ctrlKey || e.metaKey) &&
e.altKey
) {
CHV.fn.list_editor.toggleSelectItem(
$list_item,
!$list_item.hasClass("selected")
);
e.preventDefault();
e.stopPropagation();
}
});
// On listing ajax, clear the "Clear selection" toggle
PF.fn.listing.ajax.callback = function (XHR) {
if (XHR.status !== 200) return;
CHV.fn.list_editor.listMassActionSet("select");
};
// Select all
$(document).on("click", "[data-action=list-select-all]", function () {
CHV.fn.list_editor.selectItem($(".list-item:visible:not(.selected)"));
CHV.fn.list_editor.listMassActionSet("clear");
});
// Clear all
$(document).on("click", "[data-action=list-clear-all]", function () {
PF.fn.close_pops();
CHV.fn.list_editor.clearSelection();
});
// List item tools action (single)
$(document).on("click", "[data-action=list-tools] [data-action]", function (
e
) {
if (e.isPropagationStopped()) return false;
var $list_item = $(this).closest(
PF.obj.listing.selectors.list_item + ", .viewer"
);
var id = $list_item.data("id");
if (typeof $list_item.data("type") !== "undefined") {
dealing_with = $list_item.data("type");
} else {
console.log("Error: data-type not defined");
return;
}
var $targets = $("[data-type=" + dealing_with + "][data-id=" + id + "]");
var $this_icon,
this_add_class,
this_remove_class,
this_label_text,
dealing_with;
switch ($(this).data("action")) {
case "select":
CHV.fn.list_editor.toggleSelectItem(
$list_item,
!$list_item.hasClass("selected")
);
break;
case "edit":
var modal_source = "[data-modal=form-edit-single]";
// Populate the modal before casting it
switch (dealing_with) {
case "image":
$("[name=form-image-title]", modal_source).attr(
"value",
$list_item.attr("data-title")
);
$("[name=form-image-description]", modal_source).html(
PF.fn.htmlEncode($list_item.data("description"))
);
$("[name=form-album-id]", modal_source)
.find("option")
.removeAttr("selected");
$("[name=form-album-id]", modal_source)
.find(
"[value=" +
$list_item.data(dealing_with == "image" ? "album-id" : "id") +
"]"
)
.attr("selected", true);
$("[name=form-category-id]", modal_source)
.find("option")
.removeAttr("selected");
$("[name=form-category-id]", modal_source)
.find("[value=" + $list_item.data("category-id") + "]")
.attr("selected", true);
$("[name=form-nsfw]", modal_source).attr(
"checked",
$list_item.data("flag") == "unsafe"
);
// Just in case...
$("[name=form-album-name]", modal_source).attr("value", "");
$("[name=form-album-description]", modal_source).html("");
$("[name=form-privacy]", modal_source)
.find("option")
.removeAttr("selected");
break;
case "album":
$("[data-action=album-switch]", modal_source).remove();
$("[name=form-album-name]", modal_source).attr(
"value",
$list_item.data("name")
);
$("[name=form-album-description]", modal_source).html(
PF.fn.htmlEncode($list_item.data("description"))
);
$("[name=form-privacy]", modal_source)
.find("option")
.removeAttr("selected");
$("[name=form-privacy]", modal_source)
.find("[value=" + $list_item.data("privacy") + "]")
.attr("selected", true);
if ($list_item.data("privacy") == "password") {
$("[data-combo-value=password]").show();
$("[name=form-album-password]", modal_source).attr(
"value",
$list_item.data("password")
);
} else {
$("[data-combo-value=password]").hide();
$("[name=form-album-password]", modal_source).attr("value", "");
}
break;
}
PF.fn.modal.call({
type: "html",
template: $(modal_source).html(),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
CHV.fn.list_editor.updateItem(
"[data-type=" + dealing_with + "][data-id=" + id + "]",
XHR.responseJSON[dealing_with],
"edit"
);
},
},
},
confirm: function () {
var $modal = $(PF.obj.modal.selectors.root);
if (
(dealing_with == "image" || dealing_with == "album") &&
$("[data-content=form-new-album]", $modal).is(":visible") &&
$("[name=form-album-name]", $modal).val() == ""
) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
if (!PF.fn.form_modal_has_changed()) {
PF.fn.modal.close();
return;
}
PF.obj.modal.form_data = {
action: "edit", // use the same method applied in viewer
edit: $list_item.data("type"),
single: true,
owner: CHV.obj.resource.user.id,
editing: {
id: id,
description: $(
"[name=form-" + dealing_with + "-description]",
$modal
).val(),
},
};
switch (dealing_with) {
case "image":
PF.obj.modal.form_data.editing.title = $(
"[name=form-image-title]",
$modal
).val();
PF.obj.modal.form_data.editing.category_id =
$("[name=form-category-id]", $modal).val() || null;
PF.obj.modal.form_data.editing.nsfw = $(
"[name=form-nsfw]",
$modal
).prop("checked")
? 1
: 0;
break;
case "album":
PF.obj.modal.form_data.editing.name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.editing.privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.editing.privacy == "password") {
PF.obj.modal.form_data.editing.password = $(
"[name=form-album-password]",
$modal
).val();
}
break;
}
PF.obj.modal.form_data.editing.new_album = $(
"[data-content=form-new-album]",
$modal
).is(":visible");
if (PF.obj.modal.form_data.editing.new_album) {
PF.obj.modal.form_data.editing.album_name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.editing.album_privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.editing.album_privacy == "password") {
PF.obj.modal.form_data.editing.album_password = $(
"[name=form-album-password]",
$modal
).val();
}
PF.obj.modal.form_data.editing.album_description = $(
"[name=form-album-description]",
$modal
).val();
} else {
PF.obj.modal.form_data.editing.album_id = $(
"[name=form-album-id]",
$modal
).val();
}
return true;
},
});
break;
case "move": // Move or create album
var modal_source = "[data-modal=form-move-single]";
// Fool the selected album
$("[name=form-album-id]", modal_source)
.find("option")
.removeAttr("selected");
$("[name=form-album-id]", modal_source)
.find(
"[value=" +
$list_item.data(dealing_with == "image" ? "album-id" : "id") +
"]"
)
.attr("selected", true);
// Just in case...
$("[name=form-album-name]", modal_source).attr("value", "");
$("[name=form-album-description]", modal_source).html("");
$("[name=form-privacy]", modal_source)
.find("option")
.removeAttr("selected");
PF.fn.modal.call({
type: "html",
template: $(modal_source).html(),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
CHV.fn.list_editor.updateMoveItemLists(
XHR.responseJSON,
dealing_with,
$targets
);
},
},
},
load: function () {
//$("[name=form-album-id]", PF.obj.modal.selectors.root).focus();
},
confirm: function () {
var $modal = $(PF.obj.modal.selectors.root);
if (
$("[data-content=form-new-album]", $modal).is(":visible") &&
$("[name=form-album-name]", $modal).val() == ""
) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
if (!PF.fn.form_modal_has_changed()) {
PF.fn.modal.close();
return;
}
PF.obj.modal.form_data = {
action: "edit", // use the same method applied in viewer
edit: $list_item.data("type"),
single: true,
owner: CHV.obj.resource.user.id,
editing: {
id: id,
},
};
PF.obj.modal.form_data.editing.new_album = $(
"[data-content=form-new-album]",
$modal
).is(":visible");
if (PF.obj.modal.form_data.editing.new_album) {
PF.obj.modal.form_data.editing.album_name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.editing.album_privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.editing.album_privacy == "password") {
PF.obj.modal.form_data.editing.album_password = $(
"[name=form-album-password]",
$modal
).val();
}
PF.obj.modal.form_data.editing.album_description = $(
"[name=form-album-description]",
$modal
).val();
} else {
PF.obj.modal.form_data.editing.album_id = $(
"[name=form-album-id]",
$modal
).val();
}
return true;
},
});
break;
case "approve":
PF.fn.modal.call({
type: "html",
template: $("[data-modal=form-approve-single]").html(),
button_submit: PF.fn._s("Confirm"),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
CHV.fn.list_editor.removeFromList(
$list_item,
PF.fn._s("The content has been approved.")
);
},
},
},
confirm: function () {
PF.obj.modal.form_data = {
action: "approve",
single: true,
approve: $list_item.data("type"),
approving: {
id: id,
},
};
return true;
},
});
break;
case "delete":
PF.fn.modal.call({
type: "html",
template: $("[data-modal=form-delete-single]").html(),
button_submit: PF.fn._s("Confirm"),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
if (dealing_with == "album") {
$("[name=form-album-id]", "[data-modal]")
.find("[value=" + id + "]")
.remove();
CHV.fn.list_editor.updateUserCounters(
"image",
XHR.responseJSON.success.affected,
"-"
);
}
CHV.fn.list_editor.deleteFromList($list_item);
CHV.fn.queuePixel();
},
},
},
confirm: function () {
PF.obj.modal.form_data = {
action: "delete",
single: true,
delete: $list_item.data("type"),
deleting: {
id: id,
},
};
return true;
},
});
break;
case "flag":
$.ajax({
type: "POST",
data: {
action: "edit",
edit: "image",
single: true,
editing: {
id: id,
nsfw: $list_item.data("flag") == "unsafe" ? 0 : 1,
},
},
}).complete(function (XHR) {
var response = XHR.responseJSON;
if (response.status_code == 200) {
var flag = response.image.nsfw == 1 ? "unsafe" : "safe";
$targets.attr("data-flag", flag).data("flag", flag);
} else {
PF.fn.growl.call(response.error.message);
}
CHV.fn.list_editor.selectionCount();
});
break;
}
});
// Item action (multiple)
$(".pop-box-menu a", "[data-content=list-selection]").click(function (e) {
var $content_listing = $(PF.obj.listing.selectors.content_listing_visible);
if (typeof $content_listing.data("list") !== "undefined") {
dealing_with = $content_listing.data("list");
} else {
console.log("Error: data-list not defined");
return;
}
var $targets = $(
PF.obj.listing.selectors.list_item + ".selected",
$content_listing
),
ids = $.map($targets, function (e, i) {
return $(e).data("id");
});
$(this).closest(".pop-btn").click();
switch ($(this).data("action")) {
case "get-embed-codes":
// Prepare the HTML
var template = "[data-modal=form-embed-codes]";
var objects = [];
$("textarea", template).html("");
// Build the object
$targets.each(function () {
var aux = {
image: $.parseJSON(decodeURIComponent($(this).data("object"))),
};
if ("url" in aux.image) {
objects.push(aux);
}
});
CHV.fn.fillEmbedCodes(objects, template, "html");
PF.fn.modal.call({
type: "html",
template: $(template).html(),
buttons: false,
});
break;
case "clear":
CHV.fn.list_editor.clearSelection();
e.stopPropagation();
break;
case "move":
case "create-album":
var template =
$(this).data("action") == "move"
? "form-move-multiple"
: "form-create-album",
modal_source = "[data-modal=" + template + "]",
dealing_id_data = /image/.test(dealing_with) ? "album-id" : "id";
$("[name=form-album-id]", modal_source).find("[value=null]").remove();
// Fool the album selection
$("[name=form-album-id]", modal_source)
.find("option")
.removeAttr("selected");
// Just in case...
$("[name=form-album-name]", modal_source).attr("value", "");
$("[name=form-album-description]", modal_source).html("");
$("[name=form-privacy]", modal_source)
.find("option")
.removeAttr("selected");
// This is an extra step...
var album_id = $targets.first().data(dealing_id_data),
same_album = true;
$targets.each(function () {
if ($(this).data(dealing_id_data) !== album_id) {
same_album = false;
return false;
}
});
if (!same_album) {
$("[name=form-album-id]", modal_source).prepend(
'<option value="null">' +
PF.fn._s("Select existing album") +
"</option>"
);
}
$("[name=form-album-id]", modal_source)
.find(
"[value=" +
(same_album ? $targets.first().data(dealing_id_data) : "null") +
"]"
)
.attr("selected", true);
PF.fn.modal.call({
type: "html",
template: $(modal_source).html(),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
CHV.fn.list_editor.updateMoveItemLists(
XHR.responseJSON,
dealing_with,
$targets
);
},
},
},
load: function () {
if (template == "form-move-multiple") {
//$("[name=form-album-id]", PF.obj.modal.selectors.root).focus();
}
},
confirm: function () {
var $modal = $(PF.obj.modal.selectors.root),
new_album = false;
if (
$("[data-content=form-new-album]", $modal).is(":visible") &&
$("[name=form-album-name]", $modal).val() == ""
) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
if ($("[data-content=form-new-album]", $modal).is(":visible")) {
new_album = true;
}
if (!PF.fn.form_modal_has_changed()) {
PF.fn.modal.close();
return;
}
var album_object = new_album ? "creating" : "moving";
PF.obj.modal.form_data = {
action: new_album ? "create-album" : "move",
type: dealing_with,
owner: CHV.obj.resource.user.id,
multiple: true,
album: {
ids: ids,
new: new_album,
},
};
if (new_album) {
PF.obj.modal.form_data.album.name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.album.privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.album.privacy == "password") {
PF.obj.modal.form_data.album.password = $(
"[name=form-album-password]",
$modal
).val();
}
PF.obj.modal.form_data.album.description = $(
"[name=form-album-description]",
$modal
).val();
} else {
PF.obj.modal.form_data.album.id = $(
"[name=form-album-id]",
$modal
).val();
}
return true;
},
});
break;
case "approve":
PF.fn.modal.call({
template: $("[data-modal=form-approve-multiple]").html(),
button_submit: PF.fn._s("Confirm"),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
CHV.fn.list_editor.removeFromList(
$targets,
PF.fn._s("The content has been approved.")
);
},
},
},
confirm: function () {
PF.obj.modal.form_data = {
action: "approve",
from: "list",
approve: dealing_with,
multiple: true,
approving: {
ids: ids,
},
};
return true;
},
});
break;
case "delete":
PF.fn.modal.call({
template: $("[data-modal=form-delete-multiple]").html(),
button_submit: PF.fn._s("Confirm"),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
// unificar
if (dealing_with == "albums") {
$targets.each(function () {
$("[name=form-album-id]", "[data-modal]")
.find("[value=" + $(this).data("id") + "]")
.remove();
});
CHV.fn.list_editor.updateUserCounters(
"image",
XHR.responseJSON.success.affected,
"-"
);
}
CHV.fn.list_editor.deleteFromList($targets);
CHV.fn.queuePixel();
},
},
},
confirm: function () {
PF.obj.modal.form_data = {
action: "delete",
from: "list",
delete: dealing_with,
multiple: true,
deleting: {
ids: ids,
},
};
return true;
},
});
break;
case "assign-category":
var category_id = $targets.first().data("category-id"),
same_category = true;
$targets.each(function () {
if ($(this).data("category-id") !== category_id) {
same_category = false;
return false;
}
});
PF.fn.modal.call({
type: "html",
template: $("[data-modal=form-assign-category]").html(),
forced: true,
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
$targets.each(function () {
var response = XHR.responseJSON;
$(this).data("category-id", response.category_id);
});
CHV.fn.list_editor.clearSelection();
},
},
},
confirm: function () {
var $modal = $(PF.obj.modal.selectors.root),
form_category =
$("[name=form-category-id]", $modal).val() || null;
if (same_category && category_id == form_category) {
PF.fn.modal.close(function () {
CHV.fn.list_editor.clearSelection();
});
return false;
}
PF.obj.modal.form_data = {
action: "edit-category",
from: "list",
multiple: true,
editing: {
ids: ids,
category_id: form_category,
},
};
return true;
},
});
break;
case "flag-safe":
case "flag-unsafe":
var action = $(this).data("action"),
flag = action == "flag-safe" ? "safe" : "unsafe";
PF.fn.modal.call({
template: $("[data-modal=form-" + action + "]").html(),
button_submit: PF.fn._s("Confirm"),
ajax: {
url: PF.obj.config.json_api,
deferred: {
success: function (XHR) {
$targets.each(function () {
$(this)
.removeClass("safe unsafe")
.addClass(flag)
.removeAttr("data-flag")
.attr("data-flag", flag)
.data("flag", flag);
});
CHV.fn.list_editor.clearSelection();
},
},
},
confirm: function () {
PF.obj.modal.form_data = {
action: action,
from: "list",
multiple: true,
editing: {
ids: ids,
nsfw: action == "flag-safe" ? 0 : 1,
},
};
return true;
},
});
break;
}
if (PF.fn.isDevice(["phone", "phablet"])) {
return false;
}
});
// Image page
if ($("body#image").exists()) {
$(window).scroll(function () {
CHV.obj.topBar.transparencyScrollToggle();
});
}
$(document).on("click", "[data-action=disconnect]", function () {
var $this = $(this),
connection = $this.data("connection");
PF.fn.modal.confirm({
message: $this.data("confirm-message"),
ajax: {
data: {
action: "disconnect",
disconnect: connection,
user_id: CHV.obj.resource.user.id,
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
$("[data-connection=" + connection + "]").fadeOut(function () {
$($("[data-connect=" + connection + "]")).fadeIn();
$(this).remove();
if ($("[data-connection]").length == 0) {
$("[data-content=empty-message]").show();
}
PF.fn.growl.expirable(response.success.message);
});
},
error: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(response.error.message);
},
},
},
});
});
$(document).on("click", "[data-action=delete-avatar]", function () {
var $parent = $(".user-settings-avatar"),
$loading = $(".loading-placeholder", $parent),
$top = $("#top-bar");
$loading.removeClass("hidden");
PF.fn.loading.inline($loading, {
center: true,
});
$.ajax({
type: "POST",
data: {
action: "delete",
delete: "avatar",
owner: CHV.obj.resource.user.id,
},
}).complete(function (XHR) {
$loading.addClass("hidden").empty();
if (XHR.status == 200) {
if (CHV.obj.logged_user.id == CHV.obj.resource.user.id) {
$("img.user-image", $top).hide();
$(".default-user-image", $top).removeClass("hidden");
}
$(".default-user-image", $parent).removeClass("hidden").css({
opacity: 0,
});
$(".btn-alt", $parent).closest("div").hide();
$("img.user-image", $parent).fadeOut(function () {
$(".default-user-image", $parent).animate({
opacity: 1,
});
});
} else {
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
}
});
});
$(document).on("change", "[data-content=user-avatar-upload-input]", function (
e
) {
e.preventDefault();
e.stopPropagation();
var $this = $(this),
$parent = $(".user-settings-avatar"),
$loading = $(".loading-placeholder", ".user-settings-avatar"),
$top = $("#top-bar"),
user_avatar_file = $(this)[0].files[0];
if ($this.data("uploading")) {
return;
}
if (/^image\/.*$/.test(user_avatar_file.type) == false) {
PF.fn.growl.call(PF.fn._s("Please select a valid image file type."));
return;
}
if (
user_avatar_file.size > CHV.obj.config.user.avatar_max_filesize.getBytes()
) {
PF.fn.growl.call(
PF.fn._s(
"Please select a picture of at most %s size.",
CHV.obj.config.user.avatar_max_filesize
)
);
return;
}
$loading.removeClass("hidden");
PF.fn.loading.inline($loading, {
center: true,
});
$this.data("uploading", true);
// HTML5 method
var user_avatar_fd = new FormData();
user_avatar_fd.append("source", user_avatar_file);
user_avatar_fd.append("action", "upload");
user_avatar_fd.append("type", "file");
user_avatar_fd.append("what", "avatar");
user_avatar_fd.append("owner", CHV.obj.resource.user.id);
user_avatar_fd.append("auth_token", PF.obj.config.auth_token);
avatarXHR = new XMLHttpRequest();
avatarXHR.open("POST", PF.obj.config.json_api, true);
avatarXHR.send(user_avatar_fd);
avatarXHR.onreadystatechange = function () {
if (this.readyState == 4) {
var response =
this.responseType !== "json"
? JSON.parse(this.response)
: this.response,
image = response.success.image;
$loading.addClass("hidden").empty();
if (this.status == 200) {
change_avatar = function (parent) {
$("img.user-image", parent)
.attr("src", image.url)
.removeClass("hidden")
.show();
};
hide_default = function (parent) {
$(".default-user-image", parent).addClass("hidden");
};
// Form
hide_default($parent);
$(".btn-alt", $parent).closest("div").show();
change_avatar($parent);
// Top
if (CHV.obj.logged_user.id == CHV.obj.resource.user.id) {
change_avatar($top);
hide_default($top);
}
PF.fn.growl.expirable(PF.fn._s("Profile image updated."));
} else {
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
}
$this.data("uploading", false);
}
};
});
$(document).on(
"change",
"[data-content=user-background-upload-input]",
function (e) {
e.preventDefault();
e.stopPropagation();
var $this = $(this),
$parent = $("[data-content=user-background-cover]"),
$src = $("[data-content=user-background-cover-src]"),
$loading = $(".loading-placeholder", $parent),
$top = $("#top-bar"),
user_file = $(this)[0].files[0];
if ($this.data("uploading")) {
return;
}
if (/^image\/.*$/.test(user_file.type) == false) {
PF.fn.growl.call(PF.fn._s("Please select a valid image file type."));
return;
}
if (
user_file.size > CHV.obj.config.user.background_max_filesize.getBytes()
) {
PF.fn.growl.call(
PF.fn._s(
"Please select a picture of at most %s size.",
CHV.obj.config.user.background_max_filesize
)
);
return;
}
$loading.removeClass("hidden");
PF.fn.loading.inline($loading, {
center: true,
size: "big",
color: "#FFF",
});
$this.data("uploading", true);
// HTML5 method
var user_picture_fd = new FormData();
user_picture_fd.append("source", user_file);
user_picture_fd.append("action", "upload");
user_picture_fd.append("type", "file");
user_picture_fd.append("what", "background");
user_picture_fd.append("owner", CHV.obj.resource.user.id);
user_picture_fd.append("auth_token", PF.obj.config.auth_token);
avatarXHR = new XMLHttpRequest();
avatarXHR.open("POST", PF.obj.config.json_api, true);
avatarXHR.send(user_picture_fd);
avatarXHR.onreadystatechange = function () {
if (this.readyState == 4) {
var response =
this.responseType !== "json"
? JSON.parse(this.response)
: this.response,
image = response.success.image;
if (this.status == 200) {
var $img = $("<img/>");
$img.attr("src", image.url).imagesLoaded(function () {
$loading.addClass("hidden").empty();
$src
.css("background-image", "url(" + image.url + ")")
.hide()
.fadeIn();
$("[data-content=user-change-background]", $parent).removeClass(
"hidden"
);
$parent.removeClass("no-background");
$("[data-content=user-upload-background]").hide();
$("[data-content=user-change-background]").show();
PF.fn.growl.expirable(
PF.fn._s("Profile background image updated.")
);
$img.remove();
if (typeof user_background_full_fix == "function") {
user_background_full_fix();
//PF.fn.follow_scroll_update();
}
});
} else {
$loading.addClass("hidden").empty();
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
}
$this.data("uploading", false);
}
};
}
);
CHV.fn.user_background = {
delete: {
submit: function () {
PF.obj.modal.form_data = {
action: "delete",
delete: "background",
owner: CHV.obj.resource.user.id,
};
return true;
},
deferred: {
success: {
before: function (XHR) {
$("[data-content=user-background-cover-src]").css(
"background-image",
"none"
);
$("[data-content=user-background-cover]")
.addClass("no-background")
.height("");
$("[data-content=user-upload-background]")
.removeClass("hidden")
.show();
$("[data-content=user-change-background]").hide();
$("#top-bar-shade").remove();
},
done: function (XHR) {
PF.fn.modal.close(function () {
PF.fn.growl.expirable(
PF.fn._s("Profile background image deleted.")
);
});
},
},
error: function (XHR) {
PF.fn.growl.expirable(
PF.fn._s("Error deleting profile background image.")
);
},
},
},
};
// Form things
CHV.str.mainform = "[data-content=main-form]";
CHV.obj.timezone = {
selector: "[data-content=timezone]",
input: "#timezone-region",
};
// Detect form changes
$(document).on("keyup change", CHV.str.mainform + " :input", function () {
if ($(this).is("[name=username]")) {
$("[data-text=username]").text($(this).val());
}
});
// Timezone handler
$(document).on("change", CHV.obj.timezone.input, function () {
var value = $(this).val(),
$timezone_combo = $("#timezone-combo-" + value);
$timezone_combo.find("option:first").prop("selected", true);
$(CHV.obj.timezone.selector).val($timezone_combo.val()).change();
});
$(document).on("change", "[id^=timezone-combo-]", function () {
var value = $(this).val();
$(CHV.obj.timezone.selector).val(value).change();
});
// Password match
$(document).on("keyup change blur", "[name^=new-password]", function () {
var $new_password = $("[name=new-password]"),
$new_password_confirm = $("[name=new-password-confirm]"),
hide = $new_password.val() == $new_password_confirm.val(),
$warning = $new_password_confirm
.closest(".input-password")
.find(".input-warning");
if ($warning.exists() == false) {
$warning = $("[data-message=new-password-confirm]");
}
if ($(this).is($new_password_confirm)) {
$new_password_confirm.data("touched", true);
}
if ($new_password_confirm.data("touched")) {
$warning
.text(!hide ? $warning.data("text") : "")
[!hide ? "removeClass" : "addClass"]("hidden-visibility");
}
});
// Submit form
$(document).on("submit", CHV.obj.mainform, function () {
switch ($(this).data("type")) {
case "password":
var $p1 = $("[name=new-password]", this),
$p2 = $("[name=new-password-confirm]", this);
if ($p1.val() !== "" || $p2.val() !== "") {
if ($p1.val() !== $p2.val()) {
$p1.highlight();
$p2.highlight();
PF.fn.growl.expirable(PF.fn._s("Passwords don't match"));
return false;
}
}
break;
}
});
$(document).on("click", "[data-action=check-for-updates]", function () {
PF.fn.loading.fullscreen();
CHV.fn.system.checkUpdates(function (XHR) {
PF.fn.loading.destroy("fullscreen");
if (XHR.status !== 200) {
PF.fn.growl.call(
PF.fn._s("An error occurred. Please try again later.")
);
return;
}
var data = XHR.responseJSON.software;
if (
PF.fn.versionCompare(
CHV.obj.system_info.version,
data.current_version
) == -1
) {
PF.fn.modal.simple({
title: PF.fn._s("Update available v%s", data.current_version),
message:
"<p>" +
PF.fn._s(
"There is an update available for your system. You can automatic download and install this update or go to %s to proceed to download the file.",
'<a href="' +
CHEVERETO.source.url +
'" target="_blank">' +
CHEVERETO.source.label +
"</a>"
) +
"<p>" +
PF.fn._s("The release notes for this update are:") +
"</p>" +
'<textarea class="r4 resize-vertical">' +
data.release_notes +
"</textarea>" +
'<div class="btn-container margin-bottom-0"><a href="' +
PF.obj.config.base_url +
"/update/" +
"?auth_token=" +
PF.obj.config.auth_token +
'" class="btn btn-input default">' +
PF.fn._s("Update now") +
'</a> <span class="btn-alt">' +
PF.fn._s("or") +
' <a data-action="cancel">' +
PF.fn._s("cancel") +
"</a></span></div>",
html: true,
});
} else {
PF.fn.growl.call(
PF.fn._s(
"This website is running latest %s version",
CHEVERETO.edition
)
);
}
});
});
if (typeof PF.fn.get_url_var("checkUpdates") !== typeof undefined) {
$("[data-action=check-for-updates]").click();
}
// Topbar native js thing
if ($("body#image").exists() && window.scrollY > 0) {
$("#top-bar").removeClass("transparent");
}
// Storage form
$(document).on("click", "[data-action=toggle-storage-https]", function () {
CHV.fn.storage.toggleHttps(
$(this).closest("[data-content=storage]").data("storage-id")
);
});
$(document).on("click", "[data-action=toggle-storage-active]", function () {
CHV.fn.storage.toggleActive(
$(this).closest("[data-content=storage]").data("storage-id")
);
});
// Detect paste image event
if ($(CHV.fn.uploader.selectors.root).exists()) {
CHV.fn.uploader.$pasteCatcher = $("<div />", {
contenteditable: "true",
id: CHV.fn.uploader.selectors.paste.replace(/#/, ""),
});
$("body").append(CHV.fn.uploader.$pasteCatcher);
// Hack Ctrl/Cmd+V to focus pasteCatcher
$(document).keydown(function (e) {
var key = e.keyCode;
var ctrlDown = e.ctrlKey || e.metaKey; // Mac support
if (ctrlDown && key == 86 && !$(e.target).is(":input")) {
// Paste detected on "body"
CHV.fn.uploader.$pasteCatcher.focus(e);
}
});
// Add the paste event listener
window.addEventListener("paste", CHV.fn.uploader.pasteImageHandler);
}
/* LIKE BUTTON */
$(document).on("click", "[data-action=like]", function () {
if (!PF.fn.is_user_logged()) {
window.location.href = CHV.obj.vars.urls.login;
return;
}
var $this = $(this);
// Block ajax while this thing is still working...
if ($this.data("XHR")) return;
$this.data("XHR", true);
var $object = $(this).is("[data-liked]")
? $(this)
: $(this).closest("[data-liked]");
var isSingle =
!$object.closest("[data-list], .viewer").exists() &&
typeof CHV.obj.resource !== typeof undefined;
var liked = $object.is("[data-liked=1]");
var action = !liked ? "like" : "dislike";
var content = {
id: isSingle
? CHV.obj.resource.id
: $(this).closest("[data-id]").attr("data-id"),
type: isSingle
? CHV.obj.resource.type
: $(this).closest("[data-type]").attr("data-type"),
};
var $targets = isSingle
? $this
: $("[data-type=" + content.type + "][data-id=" + content.id + "]");
var ajax = {
type: "POST",
data: {
action: action,
},
cache: false,
};
ajax.data[action] = {
object: content.type,
id: content.id,
};
$.ajax(ajax).complete(function (XHR) {
var response = XHR.responseJSON;
$this.data("XHR", false);
if (response.status_code !== 200) {
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
return;
}
if (isSingle && typeof response.content !== typeof undefined) {
$("[data-text=likes-count]").html(response.content.likes);
}
$targets.attr("data-liked", liked ? 0 : 1); // Toggle indicator
});
});
/* FOLLOW BUTTON */
$(document).on("click", "[data-action=follow]", function () {
if (!PF.fn.is_user_logged()) {
PF.fn.modal.call({
type: "login",
});
return;
}
var $this = $(this);
// Block ajax while this thing is still working...
if ($this.data("XHR")) return;
$this.data("XHR", true);
var $object = $(this).is("[data-followed]")
? $(this)
: $(this).closest("[data-followed]");
var isSingle = typeof CHV.obj.resource !== typeof undefined;
var followed = $object.is("[data-followed=1]");
var action = !followed ? "follow" : "unfollow";
var content = {
id: isSingle
? CHV.obj.resource.id
: $(this).closest("[data-id]").data("id"),
type: isSingle
? CHV.obj.resource.type
: $(this).closest("[data-type]").data("type"),
};
var ajax = {
type: "POST",
data: {
action: action,
},
cache: false,
};
ajax.data[action] = {
object: content.type,
id: content.id,
};
$.ajax(ajax).complete(function (XHR) {
var response = XHR.responseJSON;
$this.data("XHR", false);
if (response.status_code !== 200) {
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
return;
}
if (isSingle) {
if (typeof response.user_followed !== typeof undefined) {
var $followersLabel = $("[data-text=followers-label]");
var label = {
single: $followersLabel.data("label-single"),
plural: $followersLabel.data("label-plural"),
};
$("[data-text=followers-count]").html(
response.user_followed.followers
);
$followersLabel.html(
PF.fn._n(
label.single,
label.plural,
response.user_followed.followers
)
);
}
}
$object.attr("data-followed", followed ? 0 : 1); // Toggle indicator
});
});
// Notifications antiscroll. Must be called on visible elements.
function notifications_scroll() {
if (PF.fn.isDevice(["phone", "phablet"])) return;
var $visible_list = $(".top-bar-notifications-list ul", ".top-bar:visible");
var height;
var height_auto;
$visible_list.css("height", ""); // Reset any change
height = $visible_list.height();
$visible_list.data("height", height).css("height", "auto");
height_auto = $visible_list.height();
if (height_auto > height) {
$visible_list.height(height);
$visible_list.closest(".antiscroll-wrap").antiscroll();
}
}
// Notifications list
$(document).on("click", "[data-action=top-bar-notifications]", function (e) {
var _this = this;
var $this = $(this);
var $container = $(".top-bar-notifications-container", $this);
var $list = $(".top-bar-notifications-list", $this);
var $ul = $("ul", $list);
var $loading = $(".loading", $container);
if ($this.data("XHR")) {
return;
} else {
$loading.removeClass("hidden");
PF.fn.loading.inline($loading, {
size: "small",
message: PF.fn._s("loading"),
});
}
$.ajax({
type: "POST",
data: {
action: "notifications",
},
cache: false,
}).complete(function (XHR) {
var response = XHR.responseJSON;
if (response.status_code !== 200) {
PF.fn.growl.expirable(
PF.fn._s("An error occurred. Please try again later.")
);
$this.data("XHR", false);
$loading.addClass("hidden").html("");
return;
}
$this.data("XHR", true);
$loading.remove();
if (!response.html) {
$(".empty", $container).removeClass("hidden");
return;
}
$list.removeClass("hidden");
$ul.html(response.html);
notifications_scroll();
var $li = $("li.new", $ul);
$li.addClass("transition");
setTimeout(function () {
$li.removeClass("new");
$("[data-content=notifications-counter]", _this)
.removeClass("on")
.html("0");
setTimeout(function () {
$li.removeClass("transition");
}, 150);
}, 1500);
});
});
// Invoke reCaptcha
if (
$("#g-recaptcha").is(":empty") &&
CHV.obj.config.recaptcha.enabled &&
CHV.obj.config.recaptcha.sitekey
) {
reCaptchaCallback = function () {
if ($("#g-recaptcha").is(":empty") == false) {
return;
}
grecaptcha.render("g-recaptcha", {
sitekey: CHV.obj.config.recaptcha.sitekey,
});
};
$.getScript(
"https://www.google.com/recaptcha/api.js?onload=reCaptchaCallback&render=explicit"
);
}
$(document).on("click", ".list-item a.image-container", function (e) {
var $parent = $(this).closest(".list-item");
var $loadBtn = $parent.find("[data-action=load-image]");
if ($loadBtn.length > 0) {
loadImageListing($loadBtn);
e.preventDefault();
}
return;
});
// Load image from listing
$(document).on("click", ".list-item [data-action=load-image]", function (e) {
loadImageListing($(this));
e.preventDefault();
e.stopPropagation();
return;
});
function loadImageListing($this) {
$this.addClass("list-item-play-gif--loading");
var $parent = $this.closest(".list-item");
var $imageContainer = $(".image-container", $parent);
var $image = $("img", $imageContainer);
var imageSrc = $image.attr("src");
var md = ".md";
var mdIndex = imageSrc.lastIndexOf(md);
if (mdIndex == -1) {
var md = ".th";
var mdIndex = imageSrc.lastIndexOf(md);
}
var loadSrc =
imageSrc.substr(0, mdIndex) +
imageSrc.substr(mdIndex + md.length, imageSrc.length);
$imageContainer.append($imageContainer.html());
$load = $parent
.find(".image-container img")
.eq(1)
.attr("src", loadSrc)
.addClass("hidden");
$load.imagesLoaded(function () {
$this.remove();
$image.remove();
$(this.elements).removeClass("hidden");
});
}
$(document).on("click", "#album [data-tab=tab-codes]", function () {
var $loading = $(".content-listing-loading", "#tab-codes");
if (!$loading.exists()) {
return;
}
var $embed_codes = $("#embed-codes");
$.ajax({
type: "POST",
data: {
action: "get-album-contents",
albumid: CHV.obj.resource.id,
},
cache: false,
}).always(function (XHR) {
PF.fn.loading.destroy($loading);
if (XHR.status_code == 200) {
CHV.fn.fillEmbedCodes(XHR.contents, "#tab-codes");
$embed_codes.removeClass("soft-hidden");
}
});
});
if ($("body").is("#upload")) {
CHV.fn.uploader.toggle({
show: true,
});
}
$(document).on("keyup", function (e) {
if (
$(PF.obj.modal.selectors.root).exists() ||
!($(".viewer").exists() && e.which in CHV.fn.listingViewer.keys)
) {
return;
}
var direct = [88, 37, 39]; // X <- ->
var action = CHV.fn.listingViewer.keys[e.which];
if (direct.indexOf(e.which) == -1) {
$(
"[data-action=" + action + "]",
CHV.fn.listingViewer.selectors.root
).click();
} else {
if (action in CHV.fn.listingViewer) {
CHV.fn.listingViewer[action]();
}
}
});
$(document).on(
"click",
CHV.fn.listingViewer.selectors.root + " [data-action^=viewer-]",
function () {
var action = $(this).data("action").substring("viewer-".length);
if (action in CHV.fn.listingViewer) {
CHV.fn.listingViewer[action]();
}
}
);
$(document).on(
"click",
"a[data-href]:not([rel=popup-link]):not(.popup-link)",
function () {
var data = $(this).attr("data-href");
var href = $(this).attr("href");
if (!data && !href) return;
location.href = href ? href : data;
}
);
if (
typeof CHV.obj.config !== typeof undefined &&
CHV.obj.config.listing.viewer
) {
$(document).on(
"click",
PF.obj.listing.selectors.list_item +
"[data-type=image] a.image-container",
function (e) {
e.preventDefault();
e.stopPropagation();
var $item = $(this).closest(PF.obj.listing.selectors.list_item);
if (!$item.exists()) return;
CHV.fn.listingViewer.open($item);
}
);
}
$(document).on("contextmenu", CHV.fn.listingViewer.selectors.src, function (
e
) {
e.preventDefault();
return false;
});
var UrlParams = PF.fn.deparam(window.location.search);
if (UrlParams && "viewer" in UrlParams) {
var $parent = $(PF.obj.listing.selectors.content_listing_visible);
if ($parent.data("list") == "images") {
var $item = $(PF.obj.listing.selectors.list_item, $parent)[
UrlParams.viewer == "next" ? "first" : "last"
]();
CHV.fn.listingViewer.open($item);
}
}
});
if (typeof CHV == "undefined") {
CHV = {
obj: {},
fn: {},
str: {},
};
}
if (window.opener) {
CHV.obj.opener = {
uploadPlugin: {},
};
}
CHV.fn.listingViewer = {
selectors: {
bodyShown: ".--viewer-shown",
template: "#viewer-template",
root: ".viewer",
rootShow: ".viewer--show",
rootHide: ".viewer--hide",
rootZero: ".viewer--zero",
rootNavPrev: ".viewer--nav-prev",
rootNavNext: ".viewer--nav-next",
src: ".viewer-src",
tools: ".viewer-tools",
loader: ".viewer-loader",
owner: ".viewer-owner",
ownerGuest: ".viewer-owner--guest",
ownerUser: ".viewer-owner--user",
inputMap: ".viewer-kb-input",
},
keys: {
83: "select",
76: "like",
70: "flag",
69: "edit",
65: "move",
75: "approve",
46: "delete",
88: "close",
37: "prev",
39: "next",
},
keymap: {
select: ["S", PF.fn._s("Toggle select")],
like: ["L", PF.fn._s("Like")],
flag: ["F", PF.fn._s("Toggle flag")],
edit: ["E", PF.fn._s("Edit")],
move: ["A", PF.fn._s("Album")],
approve: ["K", PF.fn._s("Approve")],
delete: ["Del", PF.fn._s("Delete")],
close: ["X", PF.fn._s("Close")],
prev: ["◀", PF.fn._s("Previous")],
next: ["▶", PF.fn._s("Next")],
},
loading: null,
idleTimer: 0,
$item: null,
show: function () {
this.getEl("root")
.removeClass(this.selectors.rootHide.substring(1))
.addClass(this.selectors.rootShow.substring(1));
$("body").addClass(this.selectors.bodyShown.substring(1));
var hammertime = new Hammer($(CHV.fn.listingViewer.selectors.root).get(0), {
direction: Hammer.DIRECTION_VERTICAL,
});
hammertime.on("swipeleft swiperight", function (e) {
// left -> next, right -> prev
var swipe = e.type.substring("swipe".length) == "left" ? "next" : "prev";
CHV.fn.listingViewer[swipe]();
});
// if ($("html").hasClass("device-mobile")) {
// this.fullscreen();
// }
},
getItem: function () {
return this.$item;
},
getEl: function (sel) {
var context =
sel.startsWith("template") || sel.startsWith("root")
? false
: this.selectors.root;
return context ? $(this.selectors[sel], context) : $(this.selectors[sel]);
},
getObject: function (fresh) {
if (fresh || typeof this.object == typeof undefined) {
var json = decodeURIComponent(this.getItem().attr("data-object"));
this.object = (JSON && JSON.parse(json)) || $.parseJSON(json);
}
return this.object;
},
placeholderSizing: function () {
if (!this.getEl("root").exists()) return;
var vW = Math.max(
document.documentElement.clientWidth,
window.innerWidth || 0
);
var vH = Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
);
var vR = vW / vH;
var eSrc = this.getEl("src")[0];
var eW = eSrc.getAttribute("width");
var eH = eSrc.getAttribute("height");
var eR = eW / eH;
var c = vR < eR;
eSrc.classList.remove("--width-auto", "--height-auto");
eSrc.classList.add("--" + (c ? "height" : "width") + "-auto");
},
filler: function (isOpened) {
var _this = this;
var $viewer = this.getEl("root");
if (isOpened) {
var $parsed = $(this.getParsedTemplate());
$viewer.html($parsed.html());
}
$viewer[(this.getItem().hasClass("selected") ? "add" : "remove") + "Class"](
"selected"
);
var navActions = ["prev", "next"];
$.each(navActions, function (i, v) {
var navSelector =
_this.selectors[
"rootNav" + (v.charAt(0).toUpperCase() + v.slice(1).toLowerCase())
];
var action =
$(PF.obj.listing.selectors.content_listing_pagination + ":visible")
.length > 0
? "add"
: _this.getItem()[v]().exists()
? "add"
: "remove";
$viewer[action + "Class"](navSelector.substring(1));
});
$.each(this.getItem().get(0).attributes, function (i, attr) {
if (!attr.name.startsWith("data-")) return true;
$viewer.attr(attr.name, attr.value);
});
var handle = typeof this.object.user == typeof undefined ? "user" : "guest";
handle =
"owner" +
(handle.charAt(0).toUpperCase() + handle.slice(1).toLowerCase());
this.getEl(handle).remove();
if (typeof this.object.user !== typeof undefined) {
$(
this.object.user.avatar ? ".default-user-image" : "img.user-image",
this.getEl("ownerUser")
).remove();
}
var $tools = this.getItem().find(".list-item-image-tools");
this.getEl("tools").append($tools.html());
$.each($tools.find("[data-action]"), function (i, v) {
var action = $(this).attr("data-action");
var keymap = _this.keymap[action];
$(
'<div class="viewer-kb-key" data-key="' + keymap[0] + '"><kbd>' +
keymap[0] +
"</kbd><span>" +
PF.fn._s(keymap[1]) +
"</span></div>"
).appendTo(_this.getEl("inputMap"));
});
this.placeholderSizing();
this.trickyLoad();
},
remove: function () {
this.getEl("root").remove();
},
getParsedTemplate: function () {
var object = this.getObject(true);
var template = this.getEl("template").html();
var matches = template.match(/%(\S+)%/g);
if (matches) {
$.each(matches, function (i, v) {
var handle = v.slice(1, -1).split(".");
var value;
handle.map(function (k) {
var aux = !value ? object : value;
if (k in aux) {
value = aux[k];
}
});
var regex = new RegExp(v, "g");
template = template.replace(regex, value);
});
}
return template;
},
insertEl: function () {
var html = this.getParsedTemplate();
this.getEl("rootZero").remove();
$(html).appendTo("body");
},
toggleIdle: function (idle, refresh) {
var _this = this;
var refresh = typeof refresh == typeof undefined ? true : refresh;
$("html")[(idle ? "add" : "remove") + "Class"]("--idle");
if (!idle) {
clearTimeout(_this.idleTimer);
if (refresh) {
_this.idleTimer = setTimeout(function () {
var $fs = $(".fullscreen");
var $el = _this.getEl("root");
_this.toggleIdle($el.length > 0 && $fs.length == 0);
}, 5000);
}
}
},
open: function ($item) {
this.setItem($item);
this.insertEl();
this.filler();
this.show();
this.toggleIdle(false); // init idler
var _this = this;
this.getEl("root").on("mousemove mouseout", function () {
_this.toggleIdle(false);
});
},
setItem: function ($item) {
this.$item = $item;
},
trickyLoad: function () {
var $loader = this.getEl("loader");
if (this.object.image.url == this.object.display_url) {
$loader.remove();
return;
}
var srcHtml = this.getEl("src").parent().html();
var $src = $(srcHtml).attr("src", this.object.image.url);
$src.insertBefore(this.getEl("src"));
PF.fn.loading.inline($loader, {
color: "white",
size: "small",
center: true,
valign: true,
});
$loader.hide().fadeIn("slow");
$src.imagesLoaded(function () {
$src.next().remove();
PF.fn.loading.destroy($loader);
});
},
close: function () {
var _this = this;
$(this.selectors.root)
.removeClass(this.selectors.rootShow.substring(1))
.addClass(this.selectors.rootHide.substring(1));
$("body").removeClass(this.selectors.bodyShown.substring(1));
this.toggleIdle(false, false);
setTimeout(function () {
_this.remove();
}, 200);
},
browse: function (direction) {
var $item = this.getItem()[direction]();
if (!$item.exists()) {
var $pagination = $(
"[data-pagination=" + direction + "]",
PF.obj.listing.selectors.content_listing_pagination + ":visible"
);
var href = $pagination.attr("href");
if (!href) return;
var UrlParams = PF.fn.deparam(window.location.search);
window.location.href = href + "&viewer=" + direction;
return;
}
this.setItem($item);
this.filler(true);
var $loadMore = $(PF.obj.listing.selectors.content_listing_visible).find(
"[data-action=load-more]"
);
var padding = $item[direction + "All"]().length;
if (
$loadMore.length > 0 &&
padding <= 5 &&
!PF.obj.listing.calling &&
direction == "next"
) {
$("[data-action=load-more]").click();
}
},
prev: function () {
this.browse("prev");
},
next: function () {
this.browse("next");
},
};
CHV.obj.image_viewer = {
selector: "#image-viewer",
container: "#image-viewer-container",
navigation: ".image-viewer-navigation",
loading: "#image-viewer-loading",
loader: "#image-viewer-loader",
};
CHV.obj.image_viewer.$container = $(CHV.obj.image_viewer.container);
CHV.obj.image_viewer.$navigation = $(CHV.obj.image_viewer.navigation);
CHV.obj.image_viewer.$loading = $(CHV.obj.image_viewer.loading);
CHV.fn.system = {
checkUpdates: function (callback) {
$.ajax({
url: CHEVERETO.api.get.info + "/",
data: { id: CHEVERETO.id },
cache: false,
}).always(function (data, status, XHR) {
if (typeof callback == "function") {
callback(XHR);
}
});
},
};
CHV.fn.bindSelectableItems = function () {
var el = "content-listing-wrapper";
var sel = "#" + el;
if (!$(sel).exists()) {
$("[data-content=list-selection]")
.closest(".content-width")
.wrap("<div id='" + el + "' />");
} else if ($(sel).hasClass("ui-selectable")) {
$(sel).selectable("destroy");
}
if (!$("[data-content=list-selection]").exists()) {
return;
}
$("html.device-nonmobile " + sel).selectable({
delay: 150,
filter: PF.obj.listing.selectors.list_item,
cancel:
".content-empty, .header, #tab-share, #tab-full-info, .viewer-title, .header-link, .top-bar, .content-listing-pagination *, #fullscreen-modal, #top-user, #background-cover, .list-item-desc, .list-item-image-tools, [data-action=load-image], #tab-codes",
selecting: function (event, ui) {
var $this = $(ui.selecting);
var unselect = $this.hasClass("selected");
CHV.fn.list_editor[(unselect ? "unselect" : "select") + "Item"]($this);
},
unselecting: function (event, ui) {
CHV.fn.list_editor.unselectItem($(ui.unselecting));
},
});
};
CHV.fn.isCachedImage = function (src) {
var image = new Image();
image.src = src;
return image.complete || image.width + image.height > 0;
};
CHV.fn.viewerImageZoomClass = function () {
if (CHV.obj.image_viewer.$container.hasClass("jscursor-zoom-in")) {
CHV.obj.image_viewer.$container
.addClass("cursor-zoom-in")
.removeClass("jscursor-zoom-in");
}
};
CHV.fn.viewerLoadImage = function () {
if (CHV.obj.image_viewer.$loading.exists()) {
CHV.obj.image_viewer.$loading.removeClass("soft-hidden").css({
zIndex: 2,
});
PF.fn.loading.inline(CHV.obj.image_viewer.$loading, {
color: "white",
size: "small",
center: true,
valign: true,
});
CHV.obj.image_viewer.$loading.hide().fadeIn("slow");
}
$(CHV.obj.image_viewer.loader).remove();
CHV.obj.image_viewer.image.html = CHV.obj.image_viewer.$container.html();
CHV.obj.image_viewer.$container.prepend(
$(CHV.obj.image_viewer.image.html).css({
top: 0,
zIndex: 0,
})
);
CHV.obj.image_viewer.$container.find("img").eq(0).css("zIndex", 1);
CHV.obj.image_viewer.$container
.find("img")
.eq(1)
.attr("src", CHV.obj.image_viewer.image.url)
.css({
width: "100%",
height: "auto",
});
CHV.obj.image_viewer.$container
.find("img")
.eq(1)
.imagesLoaded(function () {
CHV.obj.image_viewer.$container.find("img").eq(1).css({
width: "",
height: "",
});
CHV.obj.image_viewer.$container.find("img").eq(0).remove();
PF.fn.loading.destroy(CHV.obj.image_viewer.$loading);
});
};
CHV.obj.embed_tpl = {};
CHV.obj.topBar = {
transparencyScrollToggle: function () {
var Y = $(window).scrollTop();
$("#top-bar")[(Y > 0 ? "remove" : "add") + "Class"]("transparent");
},
};
CHV.obj.uploaderReset = {
isUploading: false,
canAdd: true,
queueStatus: "ready",
uploadThreads: 0,
uploadParsedIds: [],
uploadProcessedIds: [],
files: {},
results: {
success: {},
error: {},
},
toggleWorking: 0,
filesAddId: 0,
clipboardImages: [],
};
CHV.fn.uploader = {
selectors: {
root: "#anywhere-upload",
show: ".upload-box--show",
queue: "#anywhere-upload-queue",
queue_complete: ".queue-complete",
queue_item: ".queue-item",
close_cancel: "[data-button=close-cancel]",
file: "#anywhere-upload-input",
camera: "#anywhere-upload-input-camera",
upload_item_template: "#anywhere-upload-item-template",
item_progress_bar: "[data-content=progress-bar]",
item_progress_percent: "[data-text=progress-percent]",
failed_result: "[data-content=failed-upload-result]",
fullscreen_mask: "#fullscreen-uploader-mask",
dropzone: "#uploader-dropzone",
paste: "#anywhere-upload-paste",
input: "[data-action=anywhere-upload-input]",
},
toggle: function (options, args) {
this.queueSize();
var $switch = $("[data-action=top-bar-upload]", ".top-bar");
var show = !$(CHV.fn.uploader.selectors.root).data("shown");
var options = $.extend(
{
callback: null,
reset: true,
},
options
);
if (typeof options.show !== typeof undefined && options.show) {
show = true;
}
PF.fn.growl.close(true);
PF.fn.close_pops();
if (
this.toggleWorking == 1 ||
$(CHV.fn.uploader.selectors.root).is(":animated") ||
CHV.fn.uploader.isUploading ||
($switch.data("login-needed") && !PF.fn.is_user_logged())
)
return;
this.toggleWorking = 1;
var animation = {
time: 500,
easing: null,
};
var callbacks = function () {
if (!show && options.reset) {
CHV.fn.uploader.reset();
}
if (PF.obj.follow_scroll.$node.exists()) {
PF.obj.follow_scroll.$node.removeClass("fixed");
PF.obj.follow_scroll.set();
}
PF.fn.topMenu.hide();
if (typeof options.callback == "function") {
options.callback(args);
}
CHV.fn.uploader.boxSizer();
CHV.fn.uploader.toggleWorking = 0;
};
$(CHV.fn.uploader.selectors.root)[(show ? "add" : "remove") + "Class"](
this.selectors.show.substring(1)
);
if (show) {
if (!$("body").is("#upload") && PF.fn.isDevice(["phone", "phablet"])) {
$("html").addClass("overflow-hidden");
}
$("html")
.data({
"followed-scroll": $("html").hasClass("followed-scroll"),
"top-bar-box-shadow-prevent": true,
})
.removeClass("followed-scroll")
.addClass("top-bar-box-shadow-none");
$("#top-bar").data({
stock_classes: $("#top-bar").attr("class"),
});
$(".current[data-nav]", ".top-bar").each(function () {
if ($(this).is("[data-action=top-bar-menu-full]")) return;
$(this).removeClass("current").attr("data-current", 1);
});
if (PF.fn.isDevice("mobile")) {
var $upload_heading = $(
".upload-box-heading",
$(CHV.fn.uploader.selectors.root)
);
$upload_heading.css({
position: "relative",
top: 0.5 * ($(window).height() - $upload_heading.height()) + "px",
});
}
CHV.fn.uploader.focus(function () {
setTimeout(function () {
callbacks();
}, animation.time);
});
} else {
// hide
$("[data-nav][data-current=1]", ".top-bar").each(function () {
$(this).addClass("current");
});
$(CHV.fn.uploader.selectors.fullscreen_mask).css({
opacity: 0,
});
setTimeout(function () {
$(CHV.fn.uploader.selectors.fullscreen_mask).remove();
if ($("html").data("followed-scroll")) {
$("html").addClass("followed-scroll");
}
}, 250);
var _uploadBoxHeight = $(CHV.fn.uploader.selectors.root).outerHeight();
var _uploadBoxPush =
_uploadBoxHeight -
parseInt($(CHV.fn.uploader.selectors.root).data("initial-height")) +
"px";
$(CHV.fn.uploader.selectors.root).css({
transform: "translate(0,-" + _uploadBoxPush + ")",
});
setTimeout(function () {
$("#top-bar").attr("class", $("#top-bar").data("stock_classes"));
$("html").removeClass(
$(".follow-scroll-wrapper.position-fixed").exists()
? ""
: "top-bar-box-shadow-none"
);
}, (animation.time * 1) / 3);
setTimeout(function () {
$(CHV.fn.uploader.selectors.root).css({
top: "",
});
if ($("body#image").exists()) {
CHV.obj.topBar.transparencyScrollToggle();
}
callbacks();
$("html,body").removeClass("overflow-hidden").data({
"top-bar-box-shadow-prevent": false,
});
}, animation.time);
}
$(CHV.fn.uploader.selectors.root).data("shown", show);
$switch.toggleClass("current").removeClass("opened");
},
reset: function () {
$.extend(this, $.extend(true, {}, CHV.obj.uploaderReset));
$("li", this.selectors.queue).remove();
$(this.selectors.root).height("").css({
"overflow-y": "",
"overflow-x": "",
});
$(this.selectors.queue)
.addClass("queueEmpty")
.removeClass(this.selectors.queue_complete.substring(1));
$(this.selectors.input, this.selectors.root).each(function () {
$(this).prop("value", null);
});
$("[data-group=upload-result] textarea", this.selectors.root).prop(
"value",
""
);
$.each(
[
"upload-queue-ready",
"uploading",
"upload-result",
"upload-queue-ready",
"upload-queue",
],
function (i, v) {
$("[data-group=" + v + "]").hide();
}
);
$("[data-group=upload]", this.selectors.root).show();
// Force HTML album selection (used for upload to current album)
$("[name=upload-album-id]", this.selectors.root).prop("value", function () {
var $selected = $("option[selected]", this);
if ($selected.exists()) {
return $selected.attr("value");
}
});
$(this.selectors.root)
.removeClass("queueCompleted queueReady queueHasResults")
.addClass("queueEmpty")
.attr("data-queue-size", 0);
// Always ask for category
$("[name=upload-category-id]", this.selectors.root).prop("value", "");
$("[name=upload-nsfw]", this.selectors.root).prop(
"checked",
this.defaultChecked
);
this.boxSizer(true);
},
focus: function (callback) {
if ($(this.selectors.fullscreen_mask).exists()) return;
if (!$("body").is("#upload")) {
$("body").append(
$("<div/>", {
id: this.selectors.fullscreen_mask.replace("#", ""),
class: "fullscreen soft-black",
}).css({
top: PF.fn.isDevice("phone")
? 0
: $(CHV.fn.uploader.selectors.root).data("top"),
})
);
}
setTimeout(function () {
if (!$("body").is("#upload")) {
$(CHV.fn.uploader.selectors.fullscreen_mask).css({
opacity: 1,
});
}
setTimeout(
function () {
if (typeof callback == "function") {
callback();
}
},
PF.fn.isDevice(["phone", "phablet"]) ? 0 : 250
);
}, 1);
},
boxSizer: function (forced) {
var shown = $(this.selectors.root).is(this.selectors.show);
var doit = shown || forced;
if (shown && !$("body").is("#upload")) {
$("html")[
(PF.fn.isDevice(["phone", "phablet"]) ? "add" : "remove") + "Class"
]("overflow-hidden");
}
if (!doit) return;
$(this.selectors.root).height("");
if (
!$("body").is("#upload") &&
$(this.selectors.root).height() > $(window).height()
) {
$(this.selectors.root).height($(window).height()).css({
"overflow-y": "scroll",
"overflow-x": "auto",
});
$("body").addClass("overflow-hidden");
} else {
$(this.selectors.root).css("overflow-y", "");
$("body").removeClass("overflow-hidden");
}
},
pasteURL: function () {
var urlvalues = $("[name=urls]", "#fullscreen-modal").val();
if (urlvalues) {
CHV.fn.uploader.toggle({ show: true });
CHV.fn.uploader.add({}, urlvalues);
}
},
pasteImageHandler: function (e) {
// Leave the inputs alone
if ($(e.target).is(":input")) {
return;
}
// Get the items from the clipboard
if (typeof e.clipboardData !== typeof undefined && e.clipboardData.items) {
var items = e.clipboardData.items;
} else {
// Get the items from the contenteditable catcher
setTimeout(function () {
// Hack to get the items after paste
e.clipboardData = {};
e.clipboardData.items = [];
$.each($("img", CHV.fn.uploader.$pasteCatcher), function (i, v) {
e.clipboardData.items.push(PF.fn.dataURItoBlob($(this).attr("src")));
});
$(CHV.fn.uploader.selectors.paste).html("");
return CHV.fn.uploader.pasteImageHandler(e);
}, 1);
}
if (items) {
// Loop through all items, looking for any kind of image
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
var file = items[i] instanceof Blob ? items[i] : items[i].getAsFile();
var reader = new FileReader();
reader.onload = function (evt) {
var uploaderIsVisible = $(CHV.fn.uploader.selectors.root).data(
"shown"
);
// Give a name to this clipboard image
file.name = PF.fn._s("Clipboard image") + " " + PF.fn.getDateTime();
// Mimic file select event
var file_evt = {
originalEvent: {
dataTransfer: {
files: [file],
},
preventDefault: function () { },
stopPropagation: function () { },
clipboard: true,
dataURL: evt.target.result,
name: file.name,
},
};
if (!uploaderIsVisible) {
CHV.fn.uploader.toggle({
callback: function () {
CHV.fn.uploader.add(file_evt);
},
});
} else {
CHV.fn.uploader.add(file_evt);
}
};
reader.readAsDataURL(file);
}
}
}
},
add: function (e, urls) {
var md5;
// Prevent add items ?
if (!this.canAdd) {
var e = e.originalEvent;
e.preventDefault();
e.stopPropagation();
return false;
}
$fileinput = $(this.selectors.file);
$fileinput.replaceWith(($fileinput = $fileinput.clone(true)));
var item_queue_template = $(this.selectors.upload_item_template).html();
var files = [];
if (typeof urls == typeof undefined) {
// Local files
var e = e.originalEvent;
e.preventDefault();
e.stopPropagation();
files = e.dataTransfer || e.target;
files = $.makeArray(files.files);
// Keep a map for the clipboard images
if (e.clipboard) {
md5 = PF.fn.md5(e.dataURL);
if ($.inArray(md5, this.clipboardImages) != -1) {
return null;
}
this.clipboardImages.push(md5);
}
// Filter non-images
var failed_files = [];
for (var i = 0; i < files.length; i++) {
var file = files[i];
var image_type_str;
if (typeof file.type == "undefined" || file.type == "") {
// Some browsers (Android) don't set the correct file.type
image_type_str = file.name
.substr(file.name.lastIndexOf(".") + 1)
.toLowerCase();
} else {
image_type_str = file.type.replace("image/", "");
}
// Size filter
if (file.size > CHV.obj.config.image.max_filesize.getBytes()) {
failed_files.push({
uid: i,
name:
file.name.truncate_middle() + " - " + PF.fn._s("File too big."),
});
continue;
}
// Android can output something like image:10 as the full file name so ignore this filter
if (
CHV.obj.config.upload.image_types.indexOf(image_type_str) == -1 &&
/android/i.test(navigator.userAgent) == false
) {
failed_files.push({
uid: i,
name:
file.name.truncate_middle() +
" - " +
PF.fn._s("Invalid or unsupported file format."),
});
continue;
}
if (md5) {
file.md5 = md5;
}
file.fromClipboard = e.clipboard == true;
file.uid = i;
}
for (var i = 0; i < failed_files.length; i++) {
var failed_file = failed_files[i];
files.splice(failed_file.id, 1);
}
if (failed_files.length > 0 && files.length == 0) {
var failed_message = "";
for (var i = 0; i < failed_files.length; i++) {
failed_message +=
"<li>" + PF.fn.htmlEncode(failed_files[i].name) + "</li>";
}
PF.fn.modal.simple({
title: PF.fn._s("Some files couldn't be added"),
message: "<ul>" + "<li>" + failed_message + "</ul>",
});
return;
}
if (files.length == 0) {
return;
}
} else {
// Remote files
// Strip HTML + BBCode
urls = urls.replace(/(<([^>]+)>)/g, "").replace(/(\[([^\]]+)\])/g, "");
files = urls.match_urls();
if (!files) return;
files = files.array_unique();
files = $.map(files, function (file, i) {
return {
uid: i,
name: file,
url: file,
};
});
}
// Empty current files object?
if ($.isEmptyObject(this.files)) {
for (var i = 0; i < files.length; i++) {
this.files[files[i].uid] = files[i];
this.filesAddId++;
}
} else {
/**
* Check duplicates by file name (local and remote)
* This is basic but is the quickest way to do it
* Note: it doesn't work on iOS for local files http://stackoverflow.com/questions/18412774/get-real-file-name-in-ios-6-x-filereader
*/
var currentfiles = [];
for (var key in this.files) {
if (
typeof this.files[key] == "undefined" ||
typeof this.files[key] == "function"
)
continue;
currentfiles.push(encodeURI(this.files[key].name));
}
files = $.map(files, function (file, i) {
if ($.inArray(encodeURI(file.name), currentfiles) != -1) {
return null;
}
file.uid = CHV.fn.uploader.filesAddId;
CHV.fn.uploader.filesAddId++;
return file;
});
for (var i = 0; i < files.length; i++) {
this.files[files[i].uid] = files[i];
}
}
$(this.selectors.queue, this.selectors.root).append(
item_queue_template.repeat(files.length)
);
$(
this.selectors.queue +
" " +
this.selectors.queue_item +
":not([data-id])",
this.selectors.root
).hide(); // hide the stock items
var failed_before = failed_files,
failed_files = [],
j = 0,
default_options = {
canvas: true,
maxWidth: 590,
};
function CHVLoadImage(i) {
if (typeof i == typeof undefined) {
var i = 0;
}
if (!(i in files)) {
PF.fn.loading.destroy("fullscreen");
return;
}
var file = files[i];
$(
CHV.fn.uploader.selectors.queue_item + ":not([data-id]) .load-url",
CHV.fn.uploader.selectors.queue
)[typeof file.url !== "undefined" ? "show" : "remove"]();
loadImage.parseMetaData(file.url ? file.url : file, function (data) {
// Set the queue item placeholder ids
$(
CHV.fn.uploader.selectors.queue_item +
":not([data-id]) .preview:empty",
CHV.fn.uploader.selectors.queue
)
.first()
.closest("li")
.attr("data-id", file.uid);
// Load the image (async)
loadImage(
file.url ? file.url : file,
function (img) {
++j;
var $queue_item = $(
CHV.fn.uploader.selectors.queue_item +
"[data-id=" +
file.uid +
"]",
CHV.fn.uploader.selectors.queue
);
if (
img.type ===
"error" /* || typeof data.imageHead == typeof undefined*/
) {
// image parse error (png always return undefined data)
failed_files.push({
uid: file.uid,
name: file.name.truncate_middle(),
});
} else {
if (
!$(
"[data-group=upload-queue]",
CHV.fn.uploader.selectors.root
).is(":visible")
) {
$(
"[data-group=upload-queue]",
CHV.fn.uploader.selectors.root
).css("display", "block");
}
// Detect true mimetype
var mimetype = "image/jpeg"; // Default unknown mimetype
if (typeof data.buffer !== typeof undefined) {
var buffer = new Uint8Array(data.buffer).subarray(0, 4);
var header = "";
for (var i = 0; i < buffer.length; i++) {
header += buffer[i].toString(16);
}
var header_to_mime = {
"89504e47": "image/png",
"47494638": "image/gif",
ffd8ffe0: "image/jpeg",
};
$.each(["ffd8ffe1", "ffd8ffe2"], function (i, v) {
header_to_mime[v] = header_to_mime["ffd8ffe0"];
});
if (typeof header_to_mime[header] !== typeof undefined) {
mimetype = header_to_mime[header];
}
}
var title = null;
if (typeof file.name !== typeof undefined) {
var basename = PF.fn.baseName(file.name);
title = $.trim(
basename
.substring(0, 100)
.capitalizeFirstLetter() /*.replace(/\.[^/.]+$/g, "").replace(/[\W_]+/g, " ")*/
);
}
// Set source image data
CHV.fn.uploader.files[file.uid].parsedMeta = {
title: title,
width: img.originalWidth,
height: img.originalHeight,
mimetype: mimetype,
};
$queue_item.show();
$(CHV.fn.uploader.selectors.root)
.addClass("queueReady")
.removeClass("queueEmpty");
$(
"[data-group=upload-queue-ready]",
CHV.fn.uploader.selectors.root
).show();
$("[data-group=upload]", CHV.fn.uploader.selectors.root).hide();
$queue_item.find(".load-url").remove();
$queue_item
.find(".preview")
.removeClass("soft-hidden")
.show()
.append(img);
$img = $queue_item.find(".preview").find("img,canvas");
$img.attr("class", "canvas");
queue_item_h = $queue_item.height();
queue_item_w = $queue_item.width();
var img_w = parseInt($img.attr("width")) || $img.width();
var img_h = parseInt($img.attr("height")) || $img.height();
var img_r = img_w / img_h;
$img.hide();
if (img_w > img_h || img_w == img_h) {
// Landscape
var queue_img_h = img_h < queue_item_h ? img_h : queue_item_h;
if (img_w > img_h) {
$img.height(queue_img_h).width(queue_img_h * img_r);
}
}
if (img_w < img_h || img_w == img_h) {
// Portrait
var queue_img_w = img_w < queue_item_w ? img_w : queue_item_w;
if (img_w < img_h) {
$img.width(queue_img_w).height(queue_img_w / img_r);
}
}
if (img_w == img_h) {
$img.height(queue_img_h).width(queue_img_w);
}
$img
.css({
marginTop: -$img.height() / 2,
marginLeft: -$img.width() / 2,
})
.show();
CHV.fn.uploader.boxSizer();
}
// Last one
if (j == files.length) {
if (typeof failed_before !== "undefined") {
failed_files = failed_files.concat(failed_before);
}
PF.fn.loading.destroy("fullscreen");
if (failed_files.length > 0) {
var failed_message = "";
for (var i = 0; i < failed_files.length; i++) {
failed_message +=
"<li>" + PF.fn.htmlEncode(failed_files[i].name) + "</li>";
delete CHV.fn.uploader.files[failed_files[i].uid];
$(
"li[data-id=" + failed_files[i].uid + "]",
CHV.fn.uploader.selectors.queue
)
.find("[data-action=cancel]")
.click();
}
PF.fn.modal.simple({
title: PF.fn._s("Some files couldn't be added"),
message: "<ul>" + failed_message + "</ul>",
});
} else {
CHV.fn.uploader.focus();
}
CHV.fn.uploader.boxSizer();
}
},
$.extend({}, default_options, {
orientation: data.exif ? data.exif.get("Orientation") : 1,
})
);
// Next one
setTimeout(function () {
CHVLoadImage(i + 1);
}, 25); // Spare some time...
});
}
PF.fn.loading.fullscreen();
// Load all the target images starting from zero (null in this case, yeah I like to fuck around just because reasons)
CHVLoadImage();
this.queueSize();
},
queueSize: function () {
$(this.selectors.root).attr("data-queue-size", Object.size(this.files));
$("[data-text=queue-objects]", this.selectors.root).text(
PF.fn._n("image", "images", Object.size(this.files))
);
$("[data-text=queue-size]", this.selectors.root).text(
Object.size(this.files)
);
},
queueProgress: function (e, id) {
var queue_size = Object.size(this.files);
this.files[id].progress = e.loaded / e.total;
var progress = 0;
for (var i = 0; i < queue_size; i++) {
if (
typeof this.files[i] == typeof undefined ||
!("progress" in this.files[i])
)
continue;
progress += this.files[i].progress;
}
$("[data-text=queue-progress]", this.selectors.root).text(
parseInt((100 * progress) / queue_size)
);
},
upload: function ($queue_item) {
var id = $queue_item.data("id");
var nextId = $queue_item.next().exists()
? $queue_item.next().data("id")
: false;
// Already working on this?
if ($.inArray(id, this.uploadParsedIds) !== -1) {
if ($queue_item.next().exists()) {
this.upload($queue_item.next());
}
return;
}
var self = this;
this.uploadParsedIds.push(id);
var f = this.files[id];
if (typeof f == typeof undefined) {
return;
}
var queue_is_url = typeof f.url !== typeof undefined;
var source = queue_is_url ? f.url : f;
var hasForm = typeof f.formValues !== typeof undefined;
if (typeof f == typeof undefined) {
if ($queue_item.next().exists()) {
this.upload($queue_item.next());
}
return;
}
this.uploadThreads += 1;
if (this.uploadThreads < CHV.obj.config.upload.threads && nextId) {
this.upload($queue_item.next());
}
this.isUploading = true;
// HTML5 form
var form = new FormData();
var formData = {
source: null,
type: queue_is_url ? "url" : "file",
action: "upload",
privacy: $("[data-privacy]", this.selectors.root).first().data("privacy"),
timestamp: this.timestamp,
auth_token: PF.obj.config.auth_token,
category_id:
$("[name=upload-category-id]", this.selectors.root).val() || null,
nsfw: $("[name=upload-nsfw]", this.selectors.root).prop("checked")
? 1
: 0,
album_id: $("[name=upload-album-id]", this.selectors.root).val() || null,
};
// Append URL BLOB source
if (queue_is_url) {
formData.source = source;
} else {
form.append("source", source, f.name); // Stupid 3rd argument for file
}
if (hasForm) {
// Merge with each queue item form data
$.each(f.formValues, function (i, v) {
formData[i.replace(/image_/g, "")] = v;
});
}
$.each(formData, function (i, v) {
if (v === null) return true;
form.append(i, v);
});
this.files[id].xhr = new XMLHttpRequest();
$queue_item.removeClass("waiting");
$(".block.edit, .queue-item-button.edit", $queue_item).remove();
if (!queue_is_url) {
this.files[id].xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
CHV.fn.uploader.queueProgress(e, id);
percentComplete = parseInt((e.loaded / e.total) * 100);
$(CHV.fn.uploader.selectors.item_progress_percent, $queue_item).text(
percentComplete
);
$(CHV.fn.uploader.selectors.item_progress_bar, $queue_item).width(
100 - percentComplete + "%"
);
if (percentComplete == 100) {
$(
CHV.fn.uploader.selectors.item_progress_percent,
$queue_item
).text("");
CHV.fn.uploader.itemLoading($queue_item);
}
}
};
} else {
this.queueSize();
this.queueProgress(
{
loaded: 1,
total: 1,
},
id
);
this.itemLoading($queue_item);
}
this.files[id].xhr.onreadystatechange = function () {
var is_error = false;
if (
this.readyState == 4 &&
typeof CHV.fn.uploader.files[id].xhr !== "undefined" &&
CHV.fn.uploader.files[id].xhr.status !== 0
) {
self.uploadProcessedIds.push(id);
self.uploadThreads -= 1;
$(".loading-indicator", $queue_item).remove();
$queue_item.removeClass("waiting uploading");
try {
// Parse the json response
var JSONresponse =
this.responseType !== "json"
? JSON.parse(this.response)
: this.response;
if (typeof JSONresponse !== "undefined" && this.status == 200) {
$("[data-group=image-link]", $queue_item).attr(
"href",
JSONresponse.image.url_viewer
);
} else {
if (JSONresponse.error.context == "PDOException") {
JSONresponse.error.message = "Database error";
}
JSONresponse.error.message =
CHV.fn.uploader.files[id].name.truncate_middle() +
" - " +
JSONresponse.error.message;
}
// Save the server response (keeping indexing for results)
CHV.fn.uploader.results[this.status == 200 ? "success" : "error"][
id
] = JSONresponse;
if (this.status !== 200) is_error = true;
} catch (err) {
is_error = true;
var err_handle;
if (typeof JSONresponse == typeof undefined) {
// Server epic error
err_handle = {
status: 500,
statusText: "Internal server error",
};
} else {
err_handle = {
status: 400,
statusText: JSONresponse.error.message,
};
}
JSONresponse = {
status_code: err_handle.status,
error: {
message:
CHV.fn.uploader.files[id].name.truncate_middle() +
" - Server error (" +
err_handle.statusText +
")",
code: err_handle.status,
context: "XMLHttpRequest",
},
status_txt: err_handle.statusText,
};
var error_key = Object.size(CHV.fn.uploader.results.error) + 1;
CHV.fn.uploader.results.error[error_key] = JSONresponse;
}
$queue_item.addClass(!is_error ? "completed" : "failed");
if (
typeof JSONresponse.error !== "undefined" &&
typeof JSONresponse.error.message !== "undefined"
) {
$queue_item
.attr("rel", "tooltip")
.data("tiptip", "top")
.attr("title", JSONresponse.error.message);
PF.fn.bindtipTip($queue_item);
}
if (self.uploadThreads < CHV.obj.config.upload.threads && nextId) {
CHV.fn.uploader.upload($queue_item.next());
$(CHV.fn.uploader.selectors.root).addClass("queueHasResults");
}
if (self.uploadProcessedIds.length == Object.size(self.files)) {
CHV.fn.uploader.displayResults();
}
$(".done", $queue_item).fadeOut();
}
};
this.files[id].xhr.open("POST", PF.obj.config.json_api, true);
this.files[id].xhr.setRequestHeader("Accept", "application/json");
this.files[id].xhr.send(form);
},
itemLoading: function ($queue_item) {
PF.fn.loading.inline($(".progress", $queue_item), {
color: "#FFF",
size: "normal",
center: true,
position: "absolute",
shadow: true,
});
$("[data-action=cancel], [data-action=edit]", $queue_item).hide();
},
displayResults: function () {
CHV.fn.uploader.isUploading = false;
var group_result = "[data-group=upload-result][data-result=%RESULT%]",
result_types = ["error", "mixed", "success"],
results = {};
for (var i = 0; i < result_types.length; i++) {
results[result_types[i]] = group_result.replace(
"%RESULT%",
result_types[i]
);
}
if (Object.size(this.results.error) > 0) {
var error_files = [];
for (var i in this.results.error) {
if (typeof this.results.error[i] !== "object") continue;
error_files[i] = this.results.error[i].error.message;
}
if (error_files.length > 0) {
$(this.selectors.failed_result).html(
"<li>" + error_files.join("</li><li>") + "</li>"
);
}
} else {
$(results.error, this.selectors.root).hide();
}
if (
!window.opener &&
CHV.obj.config.upload.moderation == 0 &&
CHV.obj.config.upload.redirect_single_upload &&
Object.size(this.results.success) == 1 &&
Object.size(this.results.error) == 0
) {
window.location.href = this.results.success[0].image.url_viewer;
return false;
}
$("[data-text=queue-progress]", this.selectors.root).text(100);
$("[data-group=uploading]", this.selectors.root).hide();
$(this.selectors.root)
.removeClass("queueUploading queueHasResults")
.addClass("queueCompleted");
$(this.selectors.queue).addClass(
this.selectors.queue_complete.substring(1)
);
// Append the embed codes
if (
Object.size(this.results.success) > 0 &&
$("[data-group=upload-result] textarea", this.selectors.root).exists()
) {
CHV.fn.fillEmbedCodes(
this.results.success,
CHV.fn.uploader.selectors.root,
"val"
);
}
if (
Object.size(this.results.success) > 0 &&
Object.size(this.results.error) > 0
) {
$(results.mixed + ", " + results.success, this.selectors.root).show();
} else if (Object.size(this.results.success) > 0) {
$(results.success, this.selectors.root).show();
} else if (Object.size(this.results.error) > 0) {
$(results.error, this.selectors.root).show();
}
if ($(results.success, this.selectors.root).is(":visible")) {
$(results.success, this.selectors.root)
.find("[data-group^=user], [data-group=guest]")
.hide();
$(results.success, this.selectors.root)
.find(
"[data-group=" + (PF.fn.is_user_logged() ? "user" : "guest") + "]"
)
.show();
var firstKey = Object.keys(this.results.success)[0];
if (typeof this.results.success[firstKey].image.album !== "undefined") {
var albums = [];
for (var key in this.results.success) {
var image = this.results.success[key].image;
if (
image.album &&
!!image.album.id_encoded &&
albums.indexOf(image.album.id_encoded) == -1
) {
albums.push(image.album.id_encoded);
}
}
var targetAlbum = {
link: null,
text: null,
};
if (albums.length <= 1) {
targetAlbum.link = this.results.success[firstKey].image.album.url;
targetAlbum.text = this.results.success[firstKey].image.album.name;
} else {
targetAlbum.link = this.results.success[
firstKey
].image.user.url_albums;
targetAlbum.text = PF.fn._s(
"%s's Albums",
this.results.success[firstKey].image.user.name_short_html
);
}
$("[data-text=upload-target]", this.selectors.root).text(
targetAlbum.text
);
$("[data-link=upload-target]", this.selectors.root).attr(
"href",
targetAlbum.link
);
if (PF.fn.is_user_logged()) {
var show_user_stuff = albums.length > 0 ? "album" : "stream";
$(
"[data-group=user-" + show_user_stuff + "]",
this.selectors.root
).show();
}
}
}
this.boxSizer();
this.queueStatus = "done";
// Detect plugin stuff
if (
window.opener &&
typeof CHV.obj.opener.uploadPlugin[window.name] !== typeof undefined
) {
$('[data-action="copy"]', this.selectors.root).remove();
if (
CHV.obj.opener.uploadPlugin[window.name].hasOwnProperty("autoInsert") &&
CHV.obj.opener.uploadPlugin[window.name].autoInsert
) {
var $target = $(
':input[name="' +
CHV.obj.opener.uploadPlugin[window.name].autoInsert +
'"]',
CHV.fn.uploader.selectors.root
);
var value = $target.val();
if (value) {
window.opener.postMessage(
{
id: window.name,
message: value,
},
"*"
);
window.close();
return;
}
}
} else {
$('[data-action="openerPostMessage"]', this.selectors.root).remove();
}
},
};
$.extend(CHV.fn.uploader, $.extend(true, {}, CHV.obj.uploaderReset));
CHV.fn.fillEmbedCodes = function (elements, parent, fn) {
if (typeof fn == "undefined") {
fn = "val";
}
$.each(elements, function (key, value) {
if (typeof value == typeof undefined) return;
var image = "id_encoded" in value ? value : value.image;
if (!image.medium) {
// Medium doesn't exists
image.medium = {};
var imageProp = [
"filename",
"name",
"width",
"height",
"extension",
"size",
"size_formatted",
"url",
];
for (var i = 0; i < imageProp.length; i++) {
image.medium[imageProp[i]] = image[imageProp[i]];
}
}
var flatten_image = Object.flatten(image);
$.each(CHV.obj.embed_tpl, function (key, value) {
$.each(value.options, function (k, v) {
var embed = v,
$embed = $("textarea[name=" + k + "]", parent),
template = embed.template;
for (var i in flatten_image) {
if (!flatten_image.hasOwnProperty(i)) {
continue;
}
template = template.replace(
new RegExp("%" + i.toUpperCase() + "%", "g"),
flatten_image[i]
);
}
$embed[fn](
$embed.val() +
template +
($embed.data("size") == "thumb" ? " " : "\n")
);
});
});
});
// Remove any extra \n
$.each(CHV.obj.embed_tpl, function (key, value) {
$.each(value.options, function (k, v) {
var $embed = $("textarea[name=" + k + "]", parent);
$embed[fn]($.trim($embed.val()));
});
});
};
CHV.fn.resource_privacy_toggle = function (privacy) {
if (!privacy) privacy = "public";
$("[data-content=privacy-private]").hide();
if (privacy !== "public") {
$("[data-content=privacy-private]").show();
}
};
// Album stuff
CHV.fn.submit_create_album = function () {
var $modal = $(PF.obj.modal.selectors.root);
if ($("[name=form-album-name]", $modal).val() == "") {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
PF.obj.modal.form_data = {
action: "create-album",
type: "album",
album: {
name: $("[name=form-album-name]", $modal).val(),
description: $("[name=form-album-description]", $modal).val(),
privacy: $("[name=form-privacy]", $modal).val(),
password:
$("[name=form-privacy]", $modal).val() == "password"
? $("[name=form-album-password]", $modal).val()
: null,
new: true,
},
};
return true;
};
CHV.fn.complete_create_album = {
success: function (XHR) {
var response = XHR.responseJSON.album;
window.location = response.url;
},
error: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(PF.fn._s(response.error.message));
},
};
// Upload edit (move to album or create new)
CHV.fn.submit_upload_edit = function () {
var $modal = $(PF.obj.modal.selectors.root),
new_album = false;
if (
$("[data-content=form-new-album]", $modal).is(":visible") &&
$("[name=form-album-name]", $modal).val() == ""
) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
if ($("[data-content=form-new-album]", $modal).is(":visible")) {
new_album = true;
}
PF.obj.modal.form_data = {
action: new_album ? "create-album" : "move",
type: "images",
album: {
ids: $.map(CHV.fn.uploader.results.success, function (v) {
return v.image.id_encoded;
}),
new: new_album,
},
};
if (new_album) {
PF.obj.modal.form_data.album.name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.album.description = $(
"[name=form-album-description]",
$modal
).val();
PF.obj.modal.form_data.album.privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.album.privacy == "password") {
PF.obj.modal.form_data.album.password = $(
"[name=form-album-password]",
$modal
).val();
}
} else {
PF.obj.modal.form_data.album.id = $("[name=form-album-id]", $modal).val();
}
return true;
};
CHV.fn.complete_upload_edit = {
success: function (XHR) {
var response = XHR.responseJSON.album;
window.location = response.url;
},
error: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(PF.fn._s(response.error.message));
},
};
// Image edit
CHV.fn.before_image_edit = function () {
var $modal = $("[data-ajax-deferred='CHV.fn.complete_image_edit']");
$("[data-content=form-new-album]", $modal).hide();
$("#move-existing-album", $modal).show();
};
CHV.fn.submit_image_edit = function () {
var $modal = $(PF.obj.modal.selectors.root),
new_album = false;
if (
$("[data-content=form-new-album]", $modal).is(":visible") &&
$("[name=form-album-name]", $modal).val() == ""
) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
if ($("[data-content=form-new-album]", $modal).is(":visible")) {
new_album = true;
}
PF.obj.modal.form_data = {
action: "edit",
edit: "image",
editing: {
id: CHV.obj.resource.id,
category_id: $("[name=form-category-id]", $modal).val() || null,
title: $("[name=form-image-title]", $modal).val() || null,
description: $("[name=form-image-description]", $modal).val() || null,
nsfw: $("[name=form-nsfw]", $modal).prop("checked") ? 1 : 0,
new_album: new_album,
},
};
if (new_album) {
PF.obj.modal.form_data.editing.album_privacy = $(
"[name=form-privacy]",
$modal
).val();
if (PF.obj.modal.form_data.editing.album_privacy == "password") {
PF.obj.modal.form_data.editing.album_password = $(
"[name=form-album-password]",
$modal
).val();
}
PF.obj.modal.form_data.editing.album_name = $(
"[name=form-album-name]",
$modal
).val();
PF.obj.modal.form_data.editing.album_description = $(
"[name=form-album-description]",
$modal
).val();
} else {
PF.obj.modal.form_data.editing.album_id = $(
"[name=form-album-id]",
$modal
).val();
}
return true;
};
CHV.fn.complete_image_edit = {
success: function (XHR) {
var response = XHR.responseJSON.image;
if (!response.album.id_encoded) response.album.id_encoded = "";
// Detect album change
if (CHV.obj.image_viewer.album.id_encoded !== response.album.id_encoded) {
CHV.obj.image_viewer.album.id_encoded = response.album.id_encoded;
var slice = {
html:
response.album.slice && response.album.slice.html
? response.album.slice.html
: null,
prev:
response.album.slice && response.album.slice.prev
? response.album.slice.prev
: null,
next:
response.album.slice && response.album.slice.next
? response.album.slice.next
: null,
};
$("[data-content=album-slice]").html(slice.html);
$("[data-content=album-panel-title]")[slice.html ? "show" : "hide"]();
$("a[data-action=prev]").attr("href", slice.prev);
$("a[data-action=next]").attr("href", slice.next);
$("a[data-action]", ".image-viewer-navigation").each(function () {
$(this)[
typeof $(this).attr("href") == "undefined"
? "addClass"
: "removeClass"
]("hidden");
});
}
CHV.fn.resource_privacy_toggle(response.album.privacy);
$.each(["description", "title"], function (i, v) {
var $obj = $("[data-text=image-" + v + "]");
$obj.html(PF.fn.nl2br(PF.fn.htmlEncode(response[v])));
if ($obj.html() !== "") {
$obj.show();
}
});
CHV.fn.common.updateDoctitle(response.title);
PF.fn.growl.expirable(PF.fn._s("Image edited successfully."));
// Add album to modals
CHV.fn.list_editor.addAlbumtoModals(response.album);
// Reset modal
var $modal = $("[data-submit-fn='CHV.fn.submit_image_edit']");
$.each(["description", "name", "password"], function (i, v) {
var $input = $("[name=form-album-" + v + "]", $modal);
if ($input.is("textarea")) {
$input.val("").html("");
} else {
$input.val("").attr("value", "");
}
});
$("[name=form-privacy] option", $modal).each(function () {
$(this).removeAttr("selected");
});
$("[data-combo-value=password]", $modal).hide();
// Select the album
$("[name=form-album-id]", $modal).find("option").removeAttr("selected");
$("[name=form-album-id]", $modal)
.find("[value=" + response.album.id_encoded + "]")
.attr("selected", true);
},
};
// Album edit
CHV.fn.before_album_edit = function (e) {
var modal_source = "[data-before-fn='CHV.fn.before_album_edit']";
$("[data-action=album-switch]", modal_source).remove();
};
CHV.fn.submit_album_edit = function () {
var $modal = $(PF.obj.modal.selectors.root);
if (!$("[name=form-album-name]", $modal).val()) {
PF.fn.growl.call(PF.fn._s("You must enter the album name."));
$("[name=form-album-name]", $modal).highlight();
return false;
}
PF.obj.modal.form_data = {
action: "edit",
edit: "album",
editing: {
id: CHV.obj.resource.id,
name: $("[name=form-album-name]", $modal).val(),
privacy: $("[name=form-privacy]", $modal).val(),
description: $("[name=form-album-description]", $modal).val(),
},
};
if (PF.obj.modal.form_data.editing.privacy == "password") {
PF.obj.modal.form_data.editing.password = $(
"[name=form-album-password]",
$modal
).val();
}
return true;
};
CHV.fn.complete_album_edit = {
success: function (XHR) {
var album = XHR.responseJSON.album;
$("[data-text=album-name]").html(PF.fn.htmlEncode(album.name));
$("[data-text=album-description]").html(
PF.fn.htmlEncode(album.description)
);
CHV.fn.resource_privacy_toggle(album.privacy);
var stock = CHV.obj.resource.type;
CHV.obj.resource.type = null;
CHV.fn.list_editor.updateItem($(".list-item"), XHR.responseJSON);
CHV.obj.resource.type = stock;
$("[data-modal]").each(function () {
$("option[value=" + album.id_encoded + "]", this).text(
album.name +
(album.privacy !== "public" ? " (" + PF.fn._s("private") + ")" : "")
);
});
CHV.fn.common.updateDoctitle(album.name);
PF.fn.growl.expirable(PF.fn._s("Album edited successfully."));
},
};
// Category edit
CHV.fn.category = {
formFields: ["id", "name", "url_key", "description"],
validateForm: function (id) {
var modal = PF.obj.modal.selectors.root,
submit = true,
used_url_key = false;
if (!CHV.fn.common.validateForm(modal)) {
return false;
}
if (
/^[-\w]+$/.test($("[name=form-category-url_key]", modal).val()) === false
) {
PF.fn.growl.call(PF.fn._s("Invalid URL key."));
$("[name=form-category-url_key]", modal).highlight();
return false;
}
if (Object.size(CHV.obj.categories) > 0) {
$.each(CHV.obj.categories, function (i, v) {
if (typeof id !== "undefined" && v.id == id) return true;
if (v.url_key == $("[name=form-category-url_key]", modal).val()) {
used_url_key = true;
return false;
}
});
}
if (used_url_key) {
PF.fn.growl.call(PF.fn._s("Category URL key already being used."));
$("[name=form-category-url_key]", modal).highlight();
return false;
}
return true;
},
edit: {
before: function (e) {
var $this = $(e.target),
id = $this.data("category-id"),
category = CHV.obj.categories[id],
modal_source = "[data-modal=" + $this.data("target") + "]";
$.each(CHV.fn.category.formFields, function (i, v) {
var i = "form-category-" + v,
v = category[v],
$input = $("[name=" + i + "]", modal_source);
if ($input.is("textarea")) {
$input.html(PF.fn.htmlEncode(v));
} else {
$input.attr("value", v);
}
});
},
submit: function () {
var modal = PF.obj.modal.selectors.root,
id = $("[name=form-category-id]", modal).val();
if (!CHV.fn.category.validateForm(id)) {
return false;
}
PF.obj.modal.form_data = {
action: "edit",
edit: "category",
editing: {},
};
$.each(CHV.fn.category.formFields, function (i, v) {
PF.obj.modal.form_data.editing[v] = $(
"[name=form-category-" + v + "]",
modal
).val();
});
return true;
},
complete: {
success: function (XHR) {
var category = XHR.responseJSON.category,
parent =
"[data-content=category][data-category-id=" + category.id + "]";
$.each(category, function (i, v) {
$("[data-content=category-" + i + "]", parent).html(
PF.fn.htmlEncode(v)
);
});
$("[data-link=category-url]").attr("href", category.url);
CHV.obj.categories[category.id] = category;
},
},
},
delete: {
before: function (e) {
var $this = $(e.target),
id = $this.data("category-id"),
category = CHV.obj.categories[id];
$this.attr(
"data-confirm",
$this.attr("data-confirm").replace("%s", '"' + category.name + '"')
);
},
submit: function (id) {
PF.obj.modal.form_data = {
action: "delete",
delete: "category",
deleting: {
id: id,
},
};
return true;
},
complete: {
success: function (XHR) {
PF.fn.growl.expirable(PF.fn._s("Category successfully deleted."));
var id = XHR.responseJSON.request.deleting.id;
$("[data-content=category][data-category-id=" + id + "]").remove();
delete CHV.obj.categories[id];
},
},
},
add: {
submit: function () {
var modal = PF.obj.modal.selectors.root;
if (!CHV.fn.category.validateForm()) {
return false;
}
PF.obj.modal.form_data = {
action: "add-category",
category: {},
};
$.each(CHV.fn.category.formFields, function (i, v) {
if (v == "id") return;
PF.obj.modal.form_data.category[v] = $(
"[name=form-category-" + v + "]",
modal
).val();
});
return true;
},
complete: {
success: function (XHR) {
var category = XHR.responseJSON.category,
list = "[data-content=dashboard-categories-list]",
html = $("[data-content=category-dashboard-template]").html(),
replaces = {};
$.each(category, function (i, v) {
html = html.replace(
new RegExp("%" + i.toUpperCase() + "%", "g"),
v ? v : ""
);
});
$(list).append(html);
if (Object.size(CHV.obj.categories) == 0) {
CHV.obj.categories = {};
}
CHV.obj.categories[category.id] = category;
PF.fn.growl.call(
PF.fn._s("Category %s added.", '"' + category.name + '"')
);
},
},
},
};
// IP ban edit
CHV.fn.ip_ban = {
formFields: ["id", "ip", "expires", "message"],
validateForm: function (id) {
var modal = PF.obj.modal.selectors.root,
submit = true,
already_banned = false,
ip = $("[name=form-ip_ban-ip]", modal).val();
if (!CHV.fn.common.validateForm(modal)) {
return false;
}
if (
$("[name=form-ip_ban-expires]", modal).val() !== "" &&
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(
$("[name=form-ip_ban-expires]", modal).val()
) == false
) {
PF.fn.growl.call(PF.fn._s("Invalid expiration date."));
$("[name=form-ip_ban-expires]", modal).highlight();
return false;
}
if (Object.size(CHV.obj.ip_bans) > 0) {
$.each(CHV.obj.ip_bans, function (i, v) {
if (typeof id !== "undefined" && v.id == id) return true;
if (v.ip == ip) {
already_banned = true;
return false;
}
});
}
if (already_banned) {
PF.fn.growl.call(PF.fn._s("IP %s already banned.", ip));
$("[name=form-ip_ban-ip]", modal).highlight();
return false;
}
return true;
},
add: {
submit: function () {
var modal = PF.obj.modal.selectors.root;
if (!CHV.fn.ip_ban.validateForm()) {
return false;
}
PF.obj.modal.form_data = {
action: "add-ip_ban",
ip_ban: {},
};
$.each(CHV.fn.ip_ban.formFields, function (i, v) {
if (v == "id") return;
PF.obj.modal.form_data.ip_ban[v] = $(
"[name=form-ip_ban-" + v + "]",
modal
).val();
});
return true;
},
complete: {
success: function (XHR) {
var ip_ban = XHR.responseJSON.ip_ban,
list = "[data-content=dashboard-ip_bans-list]",
html = $("[data-content=ip_ban-dashboard-template]").html(),
replaces = {};
if (typeof html !== "undefined") {
$.each(ip_ban, function (i, v) {
html = html.replace(
new RegExp("%" + i.toUpperCase() + "%", "g"),
v ? v : ""
);
});
$(list).append(html);
}
if (Object.size(CHV.obj.ip_bans) == 0) {
CHV.obj.ip_bans = {};
}
CHV.obj.ip_bans[ip_ban.id] = ip_ban;
$("[data-content=ban_ip]").hide();
$("[data-content=banned_ip]").show();
PF.fn.growl.call(PF.fn._s("IP %s banned.", ip_ban.ip));
},
error: function (XHR) {
// experimental
var error = XHR.responseJSON.error;
PF.fn.growl.call(PF.fn._s(error.message));
},
},
},
edit: {
before: function (e) {
var $this = $(e.target),
id = $this.data("ip_ban-id"),
target = CHV.obj.ip_bans[id],
modal_source = "[data-modal=" + $this.data("target") + "]";
$.each(CHV.fn.ip_ban.formFields, function (i, v) {
var i = "form-ip_ban-" + v,
v = target[v],
$input = $("[name=" + i + "]", modal_source);
if ($input.is("textarea")) {
$input.html(PF.fn.htmlEncode(v));
} else {
$input.attr("value", v);
}
});
},
submit: function () {
var modal = PF.obj.modal.selectors.root,
id = $("[name=form-ip_ban-id]", modal).val();
if (!CHV.fn.ip_ban.validateForm(id)) {
return false;
}
PF.obj.modal.form_data = {
action: "edit",
edit: "ip_ban",
editing: {},
};
$.each(CHV.fn.ip_ban.formFields, function (i, v) {
PF.obj.modal.form_data.editing[v] = $(
"[name=form-ip_ban-" + v + "]",
modal
).val();
});
return true;
},
complete: {
success: function (XHR) {
var ip_ban = XHR.responseJSON.ip_ban,
parent = "[data-content=ip_ban][data-ip_ban-id=" + ip_ban.id + "]";
$.each(ip_ban, function (i, v) {
$("[data-content=ip_ban-" + i + "]", parent).html(
PF.fn.htmlEncode(v)
);
});
CHV.obj.ip_bans[ip_ban.id] = ip_ban;
},
error: function (XHR) {
var error = XHR.responseJSON.error;
PF.fn.growl.call(PF.fn._s(error.message));
},
},
},
delete: {
before: function (e) {
var $this = $(e.target),
id = $this.data("ip_ban-id"),
ip_ban = CHV.obj.ip_bans[id];
$this.attr(
"data-confirm",
$this.attr("data-confirm").replace("%s", ip_ban.ip)
);
},
submit: function (id) {
PF.obj.modal.form_data = {
action: "delete",
delete: "ip_ban",
deleting: {
id: id,
},
};
return true;
},
complete: {
success: function (XHR) {
PF.fn.growl.expirable(PF.fn._s("IP ban successfully deleted."));
var id = XHR.responseJSON.request.deleting.id;
$("[data-content=ip_ban][data-ip_ban-id=" + id + "]").remove();
delete CHV.obj.ip_bans[id];
},
},
},
};
// Storage edit
CHV.fn.storage = {
formFields: [
"id",
"name",
"api_id",
"bucket",
"server",
"service",
"capacity",
"region",
"key",
"secret",
"url",
"account_id",
"account_name",
],
calling: false,
validateForm: function () {
var modal = PF.obj.modal.selectors.root,
id = $("[name=form-storage-id]", modal).val(),
submit = true;
$.each($(":input", modal), function (i, v) {
if ($(this).is(":hidden")) {
if ($(this).attr("required")) {
$(this).removeAttr("required").attr("data-required", 1);
}
} else {
if ($(this).attr("data-required") == 1) {
$(this).attr("required", "required");
}
}
if (
$(this).is(":visible") &&
$(this).val() == "" &&
$(this).attr("required")
) {
$(this).highlight();
submit = false;
}
});
if (!submit) {
PF.fn.growl.call(PF.fn._s("Please fill all the required fields."));
return false;
}
// Validate storage capacity
var $storage_capacity = $("[name=form-storage-capacity]", modal),
storage_capacity = $storage_capacity.val(),
capacity_error_msg;
if (storage_capacity !== "") {
if (
/^[\d\.]+\s*[A-Za-z]{2}$/.test(storage_capacity) == false ||
typeof storage_capacity.getBytes() == "undefined"
) {
capacity_error_msg = PF.fn._s(
"Invalid storage capacity value. Make sure to use a valid format."
);
} else if (
typeof CHV.obj.storages[id] !== "undefined" &&
storage_capacity.getBytes() < CHV.obj.storages[id].space_used
) {
capacity_error_msg = PF.fn._s(
"Storage capacity can't be lower than its current usage (%s).",
CHV.obj.storages[id].space_used.formatBytes()
);
}
if (capacity_error_msg) {
PF.fn.growl.call(capacity_error_msg);
$storage_capacity.highlight();
return false;
}
}
if (
/^https?:\/\/.+$/.test($("[name=form-storage-url]", modal).val()) == false
) {
PF.fn.growl.call(PF.fn._s("Invalid URL."));
$("[name=form-storage-url]", modal).highlight();
return false;
}
return true;
},
toggleHttps: function (id) {
this.toggleBool(id, "https");
},
toggleActive: function (id) {
this.toggleBool(id, "active");
},
toggleBool: function (id, string) {
if (this.calling) return;
this.calling = true;
var $root = $("[data-storage-id=" + id + "]"),
$parent = $("[data-content=storage-" + string + "]", $root),
$el = $("[data-checkbox]", $parent),
checked = CHV.obj.storages[id]["is_" + string],
toggle = checked == 0 ? 1 : 0,
data = {
action: "edit",
edit: "storage",
editing: {
id: id,
},
};
data.editing["is_" + string] = toggle;
if (string == "https") {
data.editing.url = CHV.obj.storages[id].url;
}
PF.fn.loading.fullscreen();
$.ajax({
type: "POST",
data: data,
}).always(function (data, status, XHR) {
CHV.fn.storage.calling = false;
PF.fn.loading.destroy("fullscreen");
if (typeof data.storage == "undefined") {
PF.fn.growl.call(data.responseJSON.error.message);
return;
}
var storage = data.storage;
CHV.obj.storages[storage.id] = storage;
PF.fn.growl.expirable(PF.fn._s("Storage successfully edited."));
switch (string) {
case "https":
$("[data-content=storage-url]", $root).html(storage.url);
break;
}
CHV.fn.storage.toggleBoolDisplay($el, toggle);
CHV.fn.queuePixel(); // For the lulz
});
},
edit: {
before: function (e) {
var $this = $(e.target),
id = $this.data("storage-id"),
storage = CHV.obj.storages[id],
modal_source = "[data-modal=" + $this.data("target") + "]",
combo = "[data-combo-value~=" + storage["api_id"] + "]";
$.each(CHV.fn.storage.formFields, function (i, v) {
var i = "form-storage-" + v,
v = storage[v],
$combo_input = $(combo + " [name=" + i + "]", modal_source),
$global_input = $("[name=" + i + "]", modal_source),
$input = $combo_input.exists() ? $combo_input : $global_input;
if ($input.is("textarea")) {
$input.html(PF.fn.htmlEncode(v));
} else if ($input.is("select")) {
$("option", $input).removeAttr("selected");
$("option", $input).each(function () {
if ($(this).attr("value") == v) {
$(this).attr("selected", "selected");
return false;
}
});
} else {
if (
$input.is("[name=form-storage-capacity]") &&
typeof v !== "undefined" &&
v > 0
) {
v = v.formatBytes(2);
}
$input.attr("value", v);
}
});
// Co-combo breaker
$("[data-combo-value]").addClass("soft-hidden");
$(combo).removeClass("soft-hidden");
},
submit: function () {
var modal = PF.obj.modal.selectors.root,
id = $("[name=form-storage-id]", modal).val(),
used_url_key = false;
if (!CHV.fn.storage.validateForm()) {
return false;
}
PF.obj.modal.form_data = {
action: "edit",
edit: "storage",
editing: {},
};
$.each(CHV.fn.storage.formFields, function (i, v) {
var sel;
sel = "[name=form-storage-" + v + "]";
if ($(sel, modal).attr("type") !== "hidden") {
sel += ":visible";
}
PF.obj.modal.form_data.editing[v] = $(sel, modal).val();
});
return true;
},
complete: {
success: function (XHR) {
var storage = XHR.responseJSON.storage,
parent = "[data-content=storage][data-storage-id=" + storage.id + "]",
$el = $("[data-action=toggle-storage-https]", parent);
$.each(storage, function (i, v) {
$("[data-content=storage-" + i + "]", parent).html(
PF.fn.htmlEncode(v)
);
});
CHV.obj.storages[storage.id] = storage;
CHV.fn.storage.toggleBoolDisplay($el, storage["is_https"] == 1);
CHV.fn.queuePixel(); // For the lulz
},
error: function (XHR) {
var response = XHR.responseJSON,
message = response.error.message;
PF.fn.growl.call(message);
},
},
},
add: {
submit: function () {
if (!CHV.fn.storage.validateForm()) {
return false;
}
var modal = PF.obj.modal.selectors.root;
PF.obj.modal.form_data = {
action: "add-storage",
storage: {},
};
$.each(CHV.fn.storage.formFields, function (i, v) {
if (v == "id") return;
var sel;
sel = "[name=form-storage-" + v + "]";
if ($(sel, modal).attr("type") !== "hidden") {
sel += ":visible";
}
PF.obj.modal.form_data.storage[v] = $(sel, modal).val();
});
return true;
},
complete: {
success: function (XHR) {
var storage = XHR.responseJSON.storage,
list = "[data-content=dashboard-storages-list]",
html = $("[data-content=storage-dashboard-template]").html(),
replaces = {};
$.each(storage, function (i, v) {
var upper = i.toUpperCase();
if (i == "is_https" || i == "is_active") {
var v = CHV.obj.storageTemplate.icon
.replace("%TITLE%", CHV.obj.storageTemplate.messages[i])
.replace("%ICON%", CHV.obj.storageTemplate.checkboxes[v])
.replace("%PROP%", i.replace("is_", ""));
}
html = html.replace(new RegExp("%" + upper + "%", "g"), v ? v : "");
});
$(list).append(html);
PF.fn.bindtipTip($("[data-storage-id=" + storage.id + "]"));
if (CHV.obj.storages.length == 0) {
CHV.obj.storages = {};
}
CHV.obj.storages[storage.id] = storage;
CHV.fn.queuePixel(); // For the lulz
},
error: function (XHR) {
var response = XHR.responseJSON,
message = response.error.message;
PF.fn.growl.call(message);
},
},
},
toggleBoolDisplay: function ($el, toggle) {
var icons = {
0: $el.data("unchecked-icon"),
1: $el.data("checked-icon"),
};
$el.removeClass(icons[0] + " " + icons[1]).addClass(icons[toggle ? 1 : 0]);
},
};
CHV.fn.common = {
validateForm: function (modal) {
if (typeof modal == "undefined") {
var modal = PF.obj.modal.selectors.root;
}
var submit = true;
$.each($(":input:visible", modal), function (i, v) {
if ($(this).val() == "" && $(this).attr("required")) {
$(this).highlight();
submit = false;
}
});
if (!submit) {
PF.fn.growl.call(PF.fn._s("Please fill all the required fields."));
return false;
}
return true;
},
updateDoctitle: function (pre_doctitle) {
if (typeof CHV.obj.page_info !== typeof undefined) {
CHV.obj.page_info.pre_doctitle = pre_doctitle;
CHV.obj.page_info.doctitle =
CHV.obj.page_info.pre_doctitle + CHV.obj.page_info.pos_doctitle;
document.title = CHV.obj.page_info.doctitle;
}
},
};
CHV.fn.user = {
add: {
submit: function () {
var $modal = $(PF.obj.modal.selectors.root),
submit = true;
$.each($(":input", $modal), function (i, v) {
if ($(this).val() == "" && $(this).attr("required")) {
$(this).highlight();
submit = false;
}
});
if (!submit) {
PF.fn.growl.call(PF.fn._s("Please fill all the required fields."));
return false;
}
PF.obj.modal.form_data = {
action: "add-user",
user: {
username: $("[name=form-username]", $modal).val(),
email: $("[name=form-email]", $modal).val(),
password: $("[name=form-password]", $modal).val(),
role: $("[name=form-role]", $modal).val(),
},
};
return true;
},
complete: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.expirable(PF.fn._s("User added successfully."));
},
error: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(PF.fn._s(response.error.message));
},
},
},
delete: {
submit: function () {
PF.obj.modal.form_data = {
action: "delete",
delete: "user",
owner: CHV.obj.resource.user.id,
deleting: CHV.obj.resource.user,
};
return true;
},
},
};
CHV.fn.submit_resource_approve = function () {
PF.obj.modal.form_data = {
action: "approve",
approve: CHV.obj.resource.type,
from: "resource",
owner:
typeof CHV.obj.resource.user !== "undefined"
? CHV.obj.resource.user.id
: null,
approving: CHV.obj.resource,
};
return true;
};
CHV.fn.complete_resource_approve = {
success: function (XHR) {
var response = XHR.responseJSON;
$("body").fadeOut("normal", function () {
redir = CHV.obj.resource.url;
window.location = redir;
});
},
};
CHV.fn.submit_resource_delete = function () {
PF.obj.modal.form_data = {
action: "delete",
delete: CHV.obj.resource.type,
from: "resource",
owner:
typeof CHV.obj.resource.user !== "undefined"
? CHV.obj.resource.user.id
: null,
deleting: CHV.obj.resource,
};
return true;
};
CHV.fn.complete_resource_delete = {
success: function (XHR) {
var response = XHR.responseJSON;
$("body").fadeOut("normal", function () {
var redir;
if (
CHV.obj.resource.type == "album" ||
CHV.obj.resource.type == "image"
) {
redir = CHV.obj.resource.parent_url;
} else {
redir = CHV.obj.resource.user
? CHV.obj.resource.user.url
: CHV.obj.resource.url;
}
if (typeof redir !== "undefined") {
window.location = redir + "?deleted";
}
});
},
};
CHV.fn.list_editor = {
// viewerPropagate: function($item, fn, obj) {
// if(fn == ) {
//
// }
// },
// Update all the selection counts
selectionCount: function () {
var $content_listing = $(PF.obj.listing.selectors.content_listing);
$content_listing.each(function () {
var $listing_options = $(
"[data-content=pop-selection]",
"[data-content=list-selection][data-tab=" + $(this).attr("id") + "]"
),
selection_count = $(
PF.obj.listing.selectors.list_item + ".selected",
this
).length;
all_count = $(PF.obj.listing.selectors.list_item, this).length;
$listing_options[selection_count > 0 ? "removeClass" : "addClass"](
"disabled"
);
$("[data-text=selection-count]", $listing_options).text(
selection_count > 0 ? selection_count : ""
);
// Sensitive display
if ($content_listing.data("list") == "images" && selection_count > 0) {
var has_sfw =
$(
PF.obj.listing.selectors.list_item + ".selected[data-flag=safe]",
this
).length > 0,
has_nsfw =
$(
PF.obj.listing.selectors.list_item +
".selected[data-flag=unsafe]",
this
).length > 0;
$("[data-action=flag-safe]", $listing_options)[
(has_nsfw ? "remove" : "add") + "Class"
]("hidden");
$("[data-action=flag-unsafe]", $listing_options)[
(has_sfw ? "remove" : "add") + "Class"
]("hidden");
}
if ($(this).is(":visible")) {
CHV.fn.list_editor.listMassActionSet(
all_count == selection_count ? "clear" : "select"
);
}
});
},
// Remove (delete or move) items from list
removeFromList: function ($target, msg) {
if (typeof $target == "undefined") return;
var $target = $target instanceof jQuery == false ? $($target) : $target,
$content_listing = $(PF.obj.listing.selectors.content_listing_visible),
target_size = $target.length;
$target.fadeOut("fast"); // Promise
// Update counts
var type = $target.first().data("type"),
new_count =
parseInt($("[data-text=" + type + "-count]").text()) - target_size;
CHV.fn.list_editor.updateUserCounters(
$target.first().data("type"),
target_size,
"-"
);
$target.promise().done(function () {
$(document).removeClass(
CHV.fn.listingViewer.selectors.bodyShown.substr(1)
);
// Get count related to each list
var affected_content_lists = {};
$target.each(function () {
$("[data-id=" + $(this).data("id") + "]").each(function () {
var list_id = $(this)
.closest(PF.obj.listing.selectors.content_listing)
.attr("id");
if (!affected_content_lists[list_id]) {
affected_content_lists[list_id] = 0;
}
affected_content_lists[list_id] += 1;
});
});
if (target_size == 1) {
$("[data-id=" + $(this).data("id") + "]").remove();
} else {
$target.each(function () {
$("[data-id=" + $(this).data("id") + "]").remove();
});
}
PF.fn.listing.columnizerQueue();
PF.fn.listing.refresh();
CHV.fn.list_editor.selectionCount();
if (typeof msg !== "undefined" && typeof msg == "string") {
PF.fn.growl.expirable(msg);
}
// Update offset list (+stock)
// for (var k in affected_content_lists) {
// var $list = $("#" + k),
// stock_offset = $list.data("offset"),
// offset = -affected_content_lists[k];
// stock_offset = (typeof stock_offset == "undefined") ? 0 : parseInt(stock_offset);
// $list.data("offset", stock_offset + offset);
// }
if (
!$(
PF.obj.listing.selectors.content_listing_pagination,
$content_listing
).exists() &&
$(".list-item", $content_listing).length == 0
) {
new_count = 0;
}
// On zero add the empty template
if (new_count == 0) {
$content_listing.html(PF.obj.listing.template.empty);
// Reset ajaxed status of all
$(
PF.obj.listing.selectors.content_listing +
":not(" +
PF.obj.listing.selectors.content_listing_visible +
")"
).data({
empty: null,
load: "ajax",
});
$(
"[data-content=list-selection][data-tab=" +
$content_listing.attr("id") +
"]"
).addClass("disabled");
} else {
// Count isn't zero.. But the view?
if (
$(PF.obj.listing.selectors.list_item, $content_listing).length == 0
) {
$(PF.obj.listing.selectors.pad_content).height(0);
if ($("[data-action=load-more]", $content_listing).exists()) {
$(PF.obj.listing.selectors.content_listing_visible).data("page", 0);
$("[data-action=load-more]", $content_listing).click();
PF.obj.listing.recolumnize = true;
return;
}
var $pagNext = $("[data-pagination=next]", $content_listing);
if ($pagNext.exists()) {
var hrefNext = $pagNext.attr("href");
var params = PF.fn.deparam(hrefNext);
if ("page" in params && params.page > 1) {
hrefNext = hrefNext.changeURLParameterValue(
"page",
params.page - 1
);
}
window.location = hrefNext;
return;
}
}
}
});
},
deleteFromList: function ($target) {
if (typeof growl == "undefined") {
var growl = true;
}
var $target = $target instanceof jQuery == false ? $($target) : $target;
this.removeFromList(
$target,
growl ? PF.fn._s("The content has been deleted.") : null
);
},
moveFromList: function ($target, growl) {
if (typeof growl == "undefined") {
var growl = true;
}
var $target = $target instanceof jQuery == false ? $($target) : $target;
this.removeFromList(
$target,
growl ? PF.fn._s("The content has been moved.") : null
);
},
toggleSelectItem: function ($list_item, select) {
if (typeof select !== "boolean") {
var select = true;
}
var $target = $(".viewer").is(":visible")
? $("[data-type=image][data-id=" + $list_item.attr("data-id") + "]")
: $list_item;
var $icon = $("[data-action=select] .btn-icon", $target);
var add_class, remove_class, label_text;
if (!select) {
$target.removeClass("selected");
add_class = $icon.data("icon-unselected");
remove_class = $icon.data("icon-selected");
label_text = PF.fn._s("Select");
} else {
$target.addClass("selected");
add_class = $icon.data("icon-selected");
remove_class = $icon.data("icon-unselected");
label_text = PF.fn._s("Unselect");
}
$icon.removeClass(remove_class).addClass(add_class);
$("[data-action=select] .label", $target).text(label_text);
CHV.fn.list_editor.selectionCount();
},
selectItem: function ($list_item) {
this.toggleSelectItem($list_item, true);
},
unselectItem: function ($list_item) {
this.toggleSelectItem($list_item, false);
},
clearSelection: function (all) {
var $targets = $(
PF.obj.listing.selectors.list_item + ".selected",
PF.obj.listing.selectors[
all ? "content_listing" : "content_listing_visible"
]
);
this.unselectItem($targets);
this.listMassActionSet("select");
},
listMassActionSet: function (action) {
var current = action == "select" ? "clear" : "select";
var $target = $("[data-action=list-" + current + "-all]:visible");
var text = $target.data("text-" + action + "-all");
$target.text(text).attr("data-action", "list-" + action + "-all");
},
updateItem: function ($target, response, action, growl) {
if ($target instanceof jQuery == false) {
var $target = $($target);
}
var dealing_with = $target.data("type"),
album = dealing_with == "image" ? response.album : response;
console.log($target, album, dealing_with);
this.addAlbumtoModals(album);
$("option[value=" + album.id_encoded + "]", "[name=form-album-id]").html(
PF.fn.htmlEncode(album.name_with_privacy_readable_html)
);
if (typeof action == "undefined") {
var action = "edit";
}
if (action == "edit" || action == "move") {
if (action == "move" && CHV.obj.resource.type == "album") {
CHV.fn.list_editor.moveFromList($target, growl);
return;
}
$target.attr("data-description", response.description);
if (dealing_with == "image") {
if (typeof response.title !== typeof undefined) {
$target.attr("data-title", response.title);
$target.find("[title]").attr("title", response.title);
$("[data-text=image-title]", $target).html(
PF.fn.htmlEncode(response.title)
);
}
if (typeof response.title_truncated !== typeof undefined) {
$("[data-text=image-title-truncated]", $target).html(
PF.fn.htmlEncode(response.title_truncated)
);
}
if (typeof response.category_id !== typeof undefined) {
$target.attr("data-category-id", response.category_id);
}
$target.attr({
"data-album-id": album.id_encoded,
"data-flag": response.nsfw == 1 ? "unsafe" : "safe",
});
$("[data-content=album-link]", $target).attr("href", album.url);
} else {
$target.attr({
"data-privacy": album.privacy,
"data-password": album.password,
"data-name": album.name,
});
}
$target.attr("data-privacy", album.privacy);
$("[data-text=album-name]", $target).html(PF.fn.htmlEncode(album.name));
PF.fn.growl.expirable(
action == "edit"
? PF.fn._s("The content has been edited.")
: PF.fn._s("The content has been moved.")
);
}
},
addAlbumtoModals: function (album) {
var added = false;
$("[name=form-album-id]", "[data-modal]").each(function () {
if (
album.id_encoded &&
!$("option[value=" + album.id_encoded + "]", this).exists()
) {
$(this).append(
'<option value="' +
album.id_encoded +
'">' +
album.name_with_privacy_readable_html +
"</option>"
);
added = true;
}
});
if (added) {
CHV.fn.list_editor.updateUserCounters("album", 1, "+");
}
},
updateAlbum: function (album) {
$("[data-id=" + album.id_encoded + "]").each(function () {
if (album.html !== "") {
$(this).after(album.html);
$(this).remove();
}
});
},
updateUserCounters: function (counter, number, operation) {
if (typeof operation == "undefined") {
var operation = "+";
}
// Current resource counter
var $count = $("[data-text=" + counter + "-count]"),
$count_label = $("[data-text=" + counter + "-label]"),
number = parseInt(number),
old_count = parseInt($count.html()),
new_count,
delta;
switch (operation) {
case "+":
new_count = old_count + number;
break;
case "-":
new_count = old_count - number;
break;
case "=":
new_count = number;
break;
}
delta = new_count - old_count;
// Total counter
var $total_count = $("[data-text=total-" + $count.data("text") + "]"),
$total_count_label = $(
"[data-text=" + $total_count.data("text") + "-label]"
),
old_total_count = parseInt($total_count.html()),
new_total_count = old_total_count + delta;
$count.text(new_count);
$total_count.text(new_total_count);
$count_label.text(
$count_label.data(new_count == 1 ? "label-single" : "label-plural")
);
$total_count_label.text(
$count_label.data(new_total_count == 1 ? "label-single" : "label-plural")
);
},
updateMoveItemLists: function (response, dealing_with, $targets) {
CHV.fn.list_editor.clearSelection();
if (/image/.test(dealing_with)) {
if (dealing_with == "image") {
// single
CHV.fn.list_editor.updateItem(
"[data-type=image][data-id=" + $targets.data("id") + "]",
response.image,
"move"
);
} else {
$targets.each(function () {
CHV.fn.list_editor.updateItem(
"[data-type=image][data-id=" + $(this).data("id") + "]",
response,
"move",
false
);
});
PF.fn.growl.expirable(PF.fn._s("The content has been moved."));
}
} else {
// /album?
if (CHV.obj.resource.type == "album") {
CHV.fn.list_editor.moveFromList($targets);
} else {
PF.fn.growl.expirable(PF.fn._s("The content has been moved."));
}
if (typeof response.albums_old !== "undefined") {
for (var i = 0; i < response.albums_old.length; i++) {
CHV.fn.list_editor.updateAlbum(response.albums_old[i]);
}
} else {
CHV.fn.list_editor.updateAlbum(response.old_album);
}
if (response.album) {
// New album
if (
typeof response.albums_old !== "undefined"
? response.request.album.new == "true"
: response.request.editing.new_album == "true"
) {
// Add option select to modals
CHV.fn.list_editor.addAlbumtoModals(response.album);
var old_count = parseInt($("[data-text=album-count]").text()) - 1;
$(PF.obj.listing.selectors.pad_content).each(function () {
var list_count = $(this).find(PF.obj.listing.selectors.list_item)
.length;
if (list_count == 0) {
return;
}
var params = PF.fn.deparam(
$(this)
.closest(PF.obj.listing.selectors.content_listing)
.data("params")
);
if (params.sort == "date_desc" || old_count == list_count) {
$(this)[params.sort == "date_desc" ? "prepend" : "append"](
response.album.html
);
}
});
} else {
CHV.fn.list_editor.updateAlbum(response.album);
}
}
PF.fn.listing.columnizerQueue();
PF.fn.listing.refresh(0);
}
},
};
// Queuezier!
CHV.fn.queuePixel = function () {
var img =
'<img data-content="queue-pixel" src="' +
PF.obj.config.base_url +
"/?queue&r=" +
PF.fn.generate_random_string(32) +
'" width="1" height="1" alt="" style="display: none;">';
$("body").append(img);
};
CHV.fn.import = {
errorHandler: function (response) {
PF.fn.growl.call(response.error.message);
},
reset: function (id) {
var id = parseInt(id);
CHV.obj.import.working[id].stats = $.ajax({
type: "POST",
data: {
action: "importReset",
id: id,
},
});
CHV.obj.import.working[id].stats.complete(function (XHR) {
var response = XHR.responseJSON;
if (response) {
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
if (response.import.status != "working") {
clearInterval(CHV.obj.import.working[id].interval);
}
}
});
},
updateStats: function (id) {
var id = parseInt(id);
if (
"readyState" in CHV.obj.import.working[id].stats &&
CHV.obj.import.working[id].stats.readyState != 4
) {
console.log(
"Aborting stats timeout call (previous call is still not ready)"
);
return;
}
CHV.obj.import.working[id].stats = $.ajax({
type: "POST",
data: {
action: "importStats",
id: id,
},
});
CHV.obj.import.working[id].stats.complete(function (XHR) {
var response = XHR.responseJSON;
if (response) {
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
if (response.import.status != "working") {
clearInterval(CHV.obj.import.working[id].interval);
}
}
});
},
add: {
submit: function () {
var modal = PF.obj.modal.selectors.root;
PF.obj.modal.form_data = {
action: "importAdd",
path: $("[name=form-path]", modal).val(),
options: {
root: $("[name=form-structure]", PF.obj.modal.selectors.root).val(),
},
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.expirable(
PF.fn._s(
"Import job ID %s added successfully, you can process the import now",
response.import.id
)
);
var $html = CHV.fn.import.parseTemplate(response.import);
$html.insertAfter(CHV.obj.import.sel.header, CHV.obj.import.sel.root);
$(CHV.obj.import.sel.root).removeClass("hidden");
},
error: function (XHR) {
CHV.fn.import.errorHandler(XHR.responseJSON);
},
},
},
process: {
abortAll: function (id) {
var id = parseInt(id);
if (id in CHV.obj.import.working) {
CHV.obj.import.aborted.push(id);
for (var key in CHV.obj.import.working[id].threads) {
CHV.obj.import.working[id].threads[key].abort();
}
PF.fn.growl.expirable(
"Aborted all threads for import job ID " +
id +
", changing status now"
);
if ("interval" in CHV.obj.import.working[id]) {
clearInterval(CHV.obj.import.working[id].interval);
if ("abort" in CHV.obj.import.working[id].stats) {
CHV.obj.import.working[id].stats.abort();
}
}
}
},
xhr: function (id, thread) {
var id = parseInt(id);
console.log("New XHR for thread #" + thread + " for import job ID");
if (id in CHV.obj.import.working == false) {
CHV.obj.import.working[id] = {
threads: {},
interval: {},
stats: {},
};
}
CHV.obj.import.working[id].threads[thread] = $.ajax({
type: "POST",
data: {
action: "importProcess",
id: id,
thread: thread,
},
});
CHV.obj.import.working[id].threads[thread].complete(function (XHR) {
if (XHR.status == 400) {
CHV.fn.import.errorHandler(XHR.responseJSON);
return;
}
var status = $("[data-id=" + id + "]", CHV.obj.import.sel.root).data(
"status"
);
if ($.inArray(id, CHV.obj.import.aborted) == -1) {
CHV.fn.import.process.xhr(id, thread);
}
});
},
load: function () {
$("html").data("modal-form-values", "");
return true;
},
submit: function (id) {
var modal = PF.obj.modal.selectors.root;
var threads = $("[name=form-threads]", modal).val();
if (threads == 0) {
PF.fn.growl.expirable(PF.fn._s("Select number of threads"));
return false;
}
PF.obj.modal.form_data = {
action: "importEdit",
id: id,
threads: threads,
values: {
status: "working",
},
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.expirable(
PF.fn._s(
"Import job ID %s is being processed now",
response.import.id
)
);
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
// Once the row has been edited, start the actual jobs
var threads = parseInt(response.request.threads);
for (var i = 1; i <= threads; i++) {
CHV.fn.import.process.xhr(response.import.id, i);
}
CHV.obj.import.working[response.import.id].interval = setInterval(
function () {
CHV.fn.import.updateStats(response.import.id);
},
5000
);
},
error: function (XHR) {
var response = XHR.responseJSON;
if (response.error.code == 900) {
console.log("Aborting current working process (status changed)");
CHV.fn.import.process.abortAll(response.id);
} else {
CHV.fn.import.errorHandler();
}
},
},
},
delete: {
submit: function (id) {
PF.obj.modal.form_data = {
action: "importDelete",
id: id,
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(PF.fn._s("Import ID %s removed", response.import.id));
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).remove();
if ($("li", CHV.obj.import.sel.root).size() == 1) {
$(CHV.obj.import.sel.root).addClass("hidden");
}
},
error: function (XHR) {
CHV.fn.import.errorHandler(XHR.responseJSON);
},
},
},
parseTemplate: function (dataset, $el) {
var tpl = CHV.obj.import.rowTpl;
for (var key in CHV.obj.import.importTr) {
if (typeof dataset[key] != typeof undefined) {
tpl = tpl.replaceAll("%" + key + "%", dataset[key]);
}
}
tpl = tpl.replaceAll("%parse%", dataset.options.root);
tpl = tpl.replaceAll("%shortParse%", dataset.options.root.charAt(0));
tpl = tpl.replaceAll(
"%displayStatus%",
CHV.obj.import.statusesDisplay[dataset.status]
);
var $html = $($.parseHTML(tpl)).attr(
"data-object",
JSON.stringify(dataset)
);
return $html;
},
};