... not sure why that didn't all go through in one commit
parent
b51c90dcb3
commit
0f759f9df4
@ -1,336 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, ajaxify, socket, app, config, utils, translator, bootbox */
|
||||
|
||||
define('forum/account/edit', ['forum/account/header', 'uploader'], function(header, uploader) {
|
||||
var AccountEdit = {},
|
||||
gravatarPicture = '',
|
||||
uploadedPicture = '',
|
||||
selectedImageType = '',
|
||||
currentEmail;
|
||||
|
||||
AccountEdit.init = function() {
|
||||
gravatarPicture = ajaxify.variables.get('gravatarpicture');
|
||||
uploadedPicture = ajaxify.variables.get('uploadedpicture');
|
||||
|
||||
header.init();
|
||||
|
||||
$('#submitBtn').on('click', updateProfile);
|
||||
|
||||
$('#inputBirthday').datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
yearRange: '1900:+0'
|
||||
});
|
||||
|
||||
currentEmail = $('#inputEmail').val();
|
||||
|
||||
handleImageChange();
|
||||
handleAccountDelete();
|
||||
handleImageUpload();
|
||||
handleEmailConfirm();
|
||||
handlePasswordChange();
|
||||
updateSignature();
|
||||
updateImages();
|
||||
};
|
||||
|
||||
function updateProfile() {
|
||||
var userData = {
|
||||
uid: $('#inputUID').val(),
|
||||
username: $('#inputUsername').val(),
|
||||
email: $('#inputEmail').val(),
|
||||
fullname: $('#inputFullname').val(),
|
||||
website: $('#inputWebsite').val(),
|
||||
birthday: $('#inputBirthday').val(),
|
||||
location: $('#inputLocation').val(),
|
||||
signature: $('#inputSignature').val()
|
||||
};
|
||||
|
||||
socket.emit('user.updateProfile', userData, function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[user:profile_update_success]]');
|
||||
|
||||
if (data.picture) {
|
||||
$('#user-current-picture').attr('src', data.picture);
|
||||
$('#user_label img').attr('src', data.picture);
|
||||
}
|
||||
|
||||
if (data.gravatarpicture) {
|
||||
$('#user-gravatar-picture').attr('src', data.gravatarpicture);
|
||||
gravatarPicture = data.gravatarpicture;
|
||||
}
|
||||
|
||||
if (data.userslug) {
|
||||
var oldslug = $('.account-username-box').attr('data-userslug');
|
||||
$('.account-username-box a').each(function(index) {
|
||||
$(this).attr('href', $(this).attr('href').replace(oldslug, data.userslug));
|
||||
});
|
||||
|
||||
$('.account-username-box').attr('data-userslug', data.userslug);
|
||||
|
||||
$('#user-profile-link').attr('href', config.relative_path + '/user/' + data.userslug);
|
||||
$('#user-header-name').text(userData.username);
|
||||
}
|
||||
|
||||
if (currentEmail !== data.email) {
|
||||
currentEmail = data.email;
|
||||
$('#confirm-email').removeClass('hide');
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleImageChange() {
|
||||
function selectImageType(type) {
|
||||
$('#gravatar-box .fa-check').toggle(type === 'gravatar');
|
||||
$('#uploaded-box .fa-check').toggle(type === 'uploaded');
|
||||
selectedImageType = type;
|
||||
}
|
||||
|
||||
$('#changePictureBtn').on('click', function() {
|
||||
selectedImageType = '';
|
||||
updateImages();
|
||||
|
||||
$('#change-picture-modal').modal('show');
|
||||
$('#change-picture-modal').removeClass('hide');
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#gravatar-box').on('click', function() {
|
||||
selectImageType('gravatar');
|
||||
});
|
||||
|
||||
$('#uploaded-box').on('click', function() {
|
||||
selectImageType('uploaded');
|
||||
});
|
||||
|
||||
$('#savePictureChangesBtn').on('click', function() {
|
||||
$('#change-picture-modal').modal('hide');
|
||||
|
||||
if (selectedImageType) {
|
||||
changeUserPicture(selectedImageType);
|
||||
|
||||
if (selectedImageType === 'gravatar') {
|
||||
$('#user-current-picture').attr('src', gravatarPicture);
|
||||
$('#user-header-picture').attr('src', gravatarPicture);
|
||||
} else if (selectedImageType === 'uploaded') {
|
||||
$('#user-current-picture').attr('src', uploadedPicture);
|
||||
$('#user-header-picture').attr('src', uploadedPicture);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleAccountDelete() {
|
||||
$('#deleteAccountBtn').on('click', function() {
|
||||
translator.translate('[[user:delete_account_confirm]]', function(translated) {
|
||||
bootbox.confirm(translated + '<p><input type="text" class="form-control" id="confirm-username" /></p>', function(confirm) {
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($('#confirm-username').val() !== app.username) {
|
||||
app.alertError('[[error:invalid-username]]');
|
||||
return false;
|
||||
} else {
|
||||
socket.emit('user.deleteAccount', {}, function(err) {
|
||||
if (!err) {
|
||||
app.logout();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleImageUpload() {
|
||||
function onUploadComplete(urlOnServer) {
|
||||
urlOnServer = urlOnServer + '?' + new Date().getTime();
|
||||
|
||||
$('#user-current-picture').attr('src', urlOnServer);
|
||||
$('#user-uploaded-picture').attr('src', urlOnServer);
|
||||
$('#user-header-picture').attr('src', urlOnServer);
|
||||
uploadedPicture = urlOnServer;
|
||||
}
|
||||
|
||||
|
||||
$('#upload-picture-modal').on('hide', function() {
|
||||
$('#userPhotoInput').val('');
|
||||
});
|
||||
|
||||
$('#uploadPictureBtn').on('click', function() {
|
||||
|
||||
$('#change-picture-modal').modal('hide');
|
||||
uploader.open(config.relative_path + '/api/user/' + ajaxify.variables.get('userslug') + '/uploadpicture', {}, config.maximumProfileImageSize, function(imageUrlOnServer) {
|
||||
onUploadComplete(imageUrlOnServer);
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#uploadFromUrlBtn').on('click', function() {
|
||||
$('#change-picture-modal').modal('hide');
|
||||
var uploadModal = $('#upload-picture-from-url-modal');
|
||||
uploadModal.modal('show').removeClass('hide');
|
||||
|
||||
uploadModal.find('.upload-btn').on('click', function() {
|
||||
var url = uploadModal.find('#uploadFromUrl').val();
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
socket.emit('user.uploadProfileImageFromUrl', url, function(err, imageUrlOnServer) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
onUploadComplete(imageUrlOnServer);
|
||||
|
||||
uploadModal.modal('hide');
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleEmailConfirm() {
|
||||
$('#confirm-email').on('click', function() {
|
||||
socket.emit('user.emailConfirm', {}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('[[notifications:email-confirm-sent]]');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handlePasswordChange() {
|
||||
var currentPassword = $('#inputCurrentPassword');
|
||||
var password_notify = $('#password-notify');
|
||||
var password_confirm_notify = $('#password-confirm-notify');
|
||||
var password = $('#inputNewPassword');
|
||||
var password_confirm = $('#inputNewPasswordAgain');
|
||||
var passwordvalid = false;
|
||||
var passwordsmatch = false;
|
||||
var successIcon = '<i class="fa fa-check"></i>';
|
||||
|
||||
function onPasswordChanged() {
|
||||
passwordvalid = utils.isPasswordValid(password.val());
|
||||
if (password.val().length < config.minimumPasswordLength) {
|
||||
showError(password_notify, '[[user:change_password_error_length]]');
|
||||
} else if (!passwordvalid) {
|
||||
showError(password_notify, '[[user:change_password_error]]');
|
||||
} else {
|
||||
showSuccess(password_notify, successIcon);
|
||||
}
|
||||
}
|
||||
|
||||
function onPasswordConfirmChanged() {
|
||||
if(password.val()) {
|
||||
if (password.val() !== password_confirm.val()) {
|
||||
showError(password_confirm_notify, '[[user:change_password_error_match]]');
|
||||
passwordsmatch = false;
|
||||
} else {
|
||||
showSuccess(password_confirm_notify, successIcon);
|
||||
passwordsmatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
password.on('blur', onPasswordChanged);
|
||||
password_confirm.on('blur', onPasswordConfirmChanged);
|
||||
|
||||
$('#changePasswordBtn').on('click', function() {
|
||||
if ((passwordvalid && passwordsmatch) || app.isAdmin) {
|
||||
socket.emit('user.changePassword', {
|
||||
'currentPassword': currentPassword.val(),
|
||||
'newPassword': password.val(),
|
||||
'uid': ajaxify.variables.get('theirid')
|
||||
}, function(err) {
|
||||
currentPassword.val('');
|
||||
password.val('');
|
||||
password_confirm.val('');
|
||||
passwordsmatch = false;
|
||||
passwordvalid = false;
|
||||
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[user:change_password_success]]');
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function changeUserPicture(type) {
|
||||
socket.emit('user.changePicture', {
|
||||
type: type,
|
||||
uid: ajaxify.variables.get('theirid')
|
||||
}, function(err) {
|
||||
if(err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateImages() {
|
||||
var currentPicture = $('#user-current-picture').attr('src');
|
||||
|
||||
if (gravatarPicture) {
|
||||
$('#user-gravatar-picture').attr('src', gravatarPicture);
|
||||
}
|
||||
|
||||
if (uploadedPicture) {
|
||||
$('#user-uploaded-picture').attr('src', uploadedPicture);
|
||||
}
|
||||
|
||||
$('#gravatar-box').toggle(!!gravatarPicture);
|
||||
$('#uploaded-box').toggle(!!uploadedPicture);
|
||||
|
||||
$('#gravatar-box .fa-check').toggle(currentPicture !== uploadedPicture);
|
||||
$('#uploaded-box .fa-check').toggle(currentPicture === uploadedPicture);
|
||||
}
|
||||
|
||||
function updateSignature() {
|
||||
function getSignatureCharsLeft() {
|
||||
return $('#inputSignature').length ? '(' + $('#inputSignature').val().length + '/' + config.maximumSignatureLength + ')' : '';
|
||||
}
|
||||
|
||||
$('#signatureCharCountLeft').html(getSignatureCharsLeft());
|
||||
|
||||
$('#inputSignature').on('keyup change', function(ev) {
|
||||
$('#signatureCharCountLeft').html(getSignatureCharsLeft());
|
||||
});
|
||||
}
|
||||
|
||||
function showError(element, msg) {
|
||||
translator.translate(msg, function(msg) {
|
||||
element.html(msg);
|
||||
element.parent()
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger');
|
||||
element.show();
|
||||
});
|
||||
}
|
||||
|
||||
function showSuccess(element, msg) {
|
||||
translator.translate(msg, function(msg) {
|
||||
element.html(msg);
|
||||
element.parent()
|
||||
.removeClass('alert-danger')
|
||||
.addClass('alert-success');
|
||||
element.show();
|
||||
});
|
||||
}
|
||||
|
||||
return AccountEdit;
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, utils */
|
||||
|
||||
define('forum/account/favourites', ['forum/account/header', 'forum/infinitescroll'], function(header, infinitescroll) {
|
||||
var Favourites = {};
|
||||
|
||||
Favourites.init = function() {
|
||||
header.init();
|
||||
|
||||
$('.user-favourite-posts img').addClass('img-responsive');
|
||||
|
||||
infinitescroll.init(loadMore);
|
||||
};
|
||||
|
||||
function loadMore(direction) {
|
||||
if (direction < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('posts.loadMoreFavourites', {
|
||||
after: $('.user-favourite-posts').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
if (data.posts && data.posts.length) {
|
||||
onPostsLoaded(data.posts, done);
|
||||
$('.user-favourite-posts').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onPostsLoaded(posts, callback) {
|
||||
infinitescroll.parseAndTranslate('account/favourites', 'posts', {posts: posts}, function(html) {
|
||||
$('.user-favourite-posts').append(html);
|
||||
html.find('img').addClass('img-responsive');
|
||||
html.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return Favourites;
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
define('forum/account/followers', ['forum/account/header'], function(header) {
|
||||
var Followers = {};
|
||||
|
||||
Followers.init = function() {
|
||||
header.init();
|
||||
|
||||
var yourid = ajaxify.variables.get('yourid'),
|
||||
theirid = ajaxify.variables.get('theirid'),
|
||||
followersCount = ajaxify.variables.get('followersCount');
|
||||
|
||||
|
||||
if (parseInt(followersCount, 10) === 0) {
|
||||
$('#no-followers-notice').removeClass('hide');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return Followers;
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
define('forum/account/following', ['forum/account/header'], function(header) {
|
||||
var Following = {};
|
||||
|
||||
Following.init = function() {
|
||||
header.init();
|
||||
|
||||
var followingCount = ajaxify.variables.get('followingCount');
|
||||
|
||||
if (parseInt(followingCount, 10) === 0) {
|
||||
$('#no-following-notice').removeClass('hide');
|
||||
}
|
||||
};
|
||||
|
||||
return Following;
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
define('forum/account/header', function() {
|
||||
var AccountHeader = {};
|
||||
|
||||
AccountHeader.init = function() {
|
||||
displayAccountMenus();
|
||||
selectActivePill();
|
||||
};
|
||||
|
||||
function displayAccountMenus() {
|
||||
var yourid = ajaxify.variables.get('yourid'),
|
||||
theirid = ajaxify.variables.get('theirid');
|
||||
|
||||
if (parseInt(yourid, 10) !== 0 && parseInt(yourid, 10) === parseInt(theirid, 10)) {
|
||||
$('#editLink, #settingsLink, #favouritesLink').removeClass('hide');
|
||||
} else {
|
||||
$('.account-sub-links .plugin-link').each(function() {
|
||||
var $this = $(this);
|
||||
$this.toggleClass('hide', $this.hasClass('private'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function selectActivePill() {
|
||||
$('.account-sub-links li').removeClass('active').each(function() {
|
||||
var href = $(this).find('a').attr('href');
|
||||
if (window.location.href.indexOf(href) !== -1) {
|
||||
$(this).addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return AccountHeader;
|
||||
});
|
@ -1,46 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket, utils */
|
||||
|
||||
define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], function(header, infinitescroll) {
|
||||
var AccountPosts = {};
|
||||
|
||||
AccountPosts.init = function() {
|
||||
header.init();
|
||||
|
||||
$('.user-favourite-posts img').addClass('img-responsive');
|
||||
|
||||
infinitescroll.init(loadMore);
|
||||
};
|
||||
|
||||
function loadMore(direction) {
|
||||
if (direction < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('posts.loadMoreUserPosts', {
|
||||
uid: $('.account-username-box').attr('data-uid'),
|
||||
after: $('.user-favourite-posts').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
if (data.posts && data.posts.length) {
|
||||
onPostsLoaded(data.posts, done);
|
||||
$('.user-favourite-posts').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onPostsLoaded(posts, callback) {
|
||||
infinitescroll.parseAndTranslate('account/posts', 'posts', {posts: posts}, function(html) {
|
||||
$('.user-favourite-posts').append(html);
|
||||
html.find('img').addClass('img-responsive');
|
||||
html.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return AccountPosts;
|
||||
});
|
@ -1,127 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, ajaxify, app, utils, socket, translator*/
|
||||
|
||||
define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll'], function(header, infinitescroll) {
|
||||
var Account = {},
|
||||
yourid,
|
||||
theirid,
|
||||
isFollowing;
|
||||
|
||||
Account.init = function() {
|
||||
header.init();
|
||||
|
||||
yourid = ajaxify.variables.get('yourid');
|
||||
theirid = ajaxify.variables.get('theirid');
|
||||
isFollowing = ajaxify.variables.get('isFollowing');
|
||||
|
||||
app.enterRoom('user/' + theirid);
|
||||
|
||||
processPage();
|
||||
|
||||
updateButtons();
|
||||
|
||||
$('#follow-btn').on('click', function() {
|
||||
return toggleFollow('follow');
|
||||
});
|
||||
|
||||
$('#unfollow-btn').on('click', function() {
|
||||
return toggleFollow('unfollow');
|
||||
});
|
||||
|
||||
$('#chat-btn').on('click', function() {
|
||||
app.openChat($('.account-username').html(), theirid);
|
||||
});
|
||||
|
||||
socket.removeListener('event:user_status_change', onUserStatusChange);
|
||||
socket.on('event:user_status_change', onUserStatusChange);
|
||||
|
||||
if (yourid !== theirid) {
|
||||
socket.emit('user.increaseViewCount', theirid);
|
||||
}
|
||||
|
||||
infinitescroll.init(loadMoreTopics);
|
||||
};
|
||||
|
||||
function processPage() {
|
||||
$('.user-recent-posts img, .post-signature img').addClass('img-responsive');
|
||||
}
|
||||
|
||||
function updateButtons() {
|
||||
var isSelfOrNotLoggedIn = yourid === theirid || parseInt(yourid, 10) === 0;
|
||||
$('#follow-btn').toggleClass('hide', isFollowing || isSelfOrNotLoggedIn);
|
||||
$('#unfollow-btn').toggleClass('hide', !isFollowing || isSelfOrNotLoggedIn);
|
||||
$('#chat-btn').toggleClass('hide', isSelfOrNotLoggedIn);
|
||||
}
|
||||
|
||||
function toggleFollow(type) {
|
||||
socket.emit('user.' + type, {
|
||||
uid: theirid
|
||||
}, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
$('#follow-btn').toggleClass('hide', type === 'follow');
|
||||
$('#unfollow-btn').toggleClass('hide', type === 'unfollow');
|
||||
app.alertSuccess('[[global:alert.' + type + ', ' + $('.account-username').html() + ']]');
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function onUserStatusChange(data) {
|
||||
var onlineStatus = $('.account-online-status');
|
||||
|
||||
if(parseInt(ajaxify.variables.get('theirid'), 10) !== parseInt(data.uid, 10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
translator.translate('[[global:' + data.status + ']]', function(translated) {
|
||||
onlineStatus.attr('class', 'account-online-status fa fa-circle status ' + data.status)
|
||||
.attr('title', translated)
|
||||
.attr('data-original-title', translated);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function loadMoreTopics(direction) {
|
||||
if(direction < 0 || !$('.user-recent-posts').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.loading-indicator').removeClass('hidden');
|
||||
|
||||
infinitescroll.loadMore('user.loadMoreRecentPosts', {
|
||||
after: $('.user-recent-posts').attr('data-nextstart'),
|
||||
uid: theirid
|
||||
}, function(data, done) {
|
||||
if (data.posts && data.posts.length) {
|
||||
onPostsLoaded(data.posts, done);
|
||||
$('.user-recent-posts').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
$('.loading-indicator').addClass('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
function onPostsLoaded(posts, callback) {
|
||||
posts = posts.filter(function(post) {
|
||||
return !$('.user-recent-posts div[data-pid=' + post.pid + ']').length;
|
||||
});
|
||||
|
||||
if (!posts.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
infinitescroll.parseAndTranslate('account/profile', 'posts', {posts: posts}, function(html) {
|
||||
|
||||
$('.user-recent-posts .loading-indicator').before(html);
|
||||
html.find('span.timeago').timeago();
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return Account;
|
||||
});
|
@ -1,71 +0,0 @@
|
||||
define('forum/account/settings', ['forum/account/header'], function(header) {
|
||||
var AccountSettings = {};
|
||||
|
||||
AccountSettings.init = function() {
|
||||
header.init();
|
||||
|
||||
$('#submitBtn').on('click', function() {
|
||||
var settings = {};
|
||||
|
||||
$('.account').find('input, textarea, select').each(function(id, input) {
|
||||
input = $(input);
|
||||
var setting = input.attr('data-property');
|
||||
if (input.is('select')) {
|
||||
settings[setting] = input.val();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input.attr('type')) {
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
settings[setting] = input.val();
|
||||
break;
|
||||
case 'checkbox':
|
||||
settings[setting] = input.is(':checked') ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
socket.emit('user.saveSettings', {uid: ajaxify.variables.get('theirid'), settings: settings}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[success:settings-saved]]');
|
||||
app.loadConfig();
|
||||
if (parseInt(app.uid, 10) === parseInt(ajaxify.variables.get('theirid'), 10)) {
|
||||
ajaxify.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
socket.emit('user.getSettings', {uid: ajaxify.variables.get('theirid')}, function(err, settings) {
|
||||
var inputs = $('.account').find('input, textarea, select');
|
||||
|
||||
inputs.each(function(index, input) {
|
||||
input = $(input);
|
||||
var setting = input.attr('data-property');
|
||||
if (setting) {
|
||||
if (input.is('select')) {
|
||||
input.val(settings[setting]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input.attr('type')) {
|
||||
case 'text' :
|
||||
case 'textarea' :
|
||||
input.val(settings[setting]);
|
||||
break;
|
||||
case 'checkbox' :
|
||||
input.prop('checked', !!settings[setting]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return AccountSettings;
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket, utils */
|
||||
|
||||
define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], function(header, infinitescroll) {
|
||||
var AccountTopics = {};
|
||||
|
||||
AccountTopics.init = function() {
|
||||
header.init();
|
||||
|
||||
infinitescroll.init(loadMore);
|
||||
};
|
||||
|
||||
function loadMore(direction) {
|
||||
if (direction < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMoreFromSet', {
|
||||
set: 'uid:' + $('.account-username-box').attr('data-uid') + ':topics',
|
||||
after: $('.user-topics').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
|
||||
if (data.topics && data.topics.length) {
|
||||
onTopicsLoaded(data.topics, done);
|
||||
$('.user-topics').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onTopicsLoaded(topics, callback) {
|
||||
infinitescroll.parseAndTranslate('account/topics', 'topics', {topics: topics}, function(html) {
|
||||
$('#topics-container').append(html);
|
||||
html.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return AccountTopics;
|
||||
});
|
@ -1,33 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, socket */
|
||||
|
||||
define('forum/admin/appearance/customise', ['forum/admin/settings'], function(Settings) {
|
||||
var Customise = {};
|
||||
|
||||
Customise.init = function() {
|
||||
Settings.prepare(function() {
|
||||
$('#customCSS').text($('#customCSS-holder').val());
|
||||
$('#customHTML').text($('#customHTML-holder').val());
|
||||
|
||||
var customCSS = ace.edit("customCSS"),
|
||||
customHTML = ace.edit("customHTML");
|
||||
|
||||
customCSS.setTheme("ace/theme/twilight");
|
||||
customCSS.getSession().setMode("ace/mode/css");
|
||||
|
||||
customCSS.on('change', function(e) {
|
||||
$('#customCSS-holder').val(customCSS.getValue());
|
||||
});
|
||||
|
||||
customHTML.setTheme("ace/theme/twilight");
|
||||
customHTML.getSession().setMode("ace/mode/html");
|
||||
|
||||
customHTML.on('change', function(e) {
|
||||
$('#customHTML-holder').val(customHTML.getValue());
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return Customise;
|
||||
});
|
||||
|
@ -1,73 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, socket */
|
||||
|
||||
define('forum/admin/appearance/skins', function() {
|
||||
var Skins = {};
|
||||
|
||||
Skins.init = function() {
|
||||
var scriptEl = $('<script />');
|
||||
scriptEl.attr('src', '//bootswatch.aws.af.cm/3/?callback=bootswatchListener');
|
||||
$('body').append(scriptEl);
|
||||
|
||||
$('#bootstrap_themes').on('click', function(e){
|
||||
var target = $(e.target),
|
||||
action = target.attr('data-action');
|
||||
|
||||
if (action && action === 'use') {
|
||||
var parentEl = target.parents('li'),
|
||||
themeType = parentEl.attr('data-type'),
|
||||
cssSrc = parentEl.attr('data-css'),
|
||||
themeId = parentEl.attr('data-theme');
|
||||
|
||||
socket.emit('admin.themes.set', {
|
||||
type: themeType,
|
||||
id: themeId,
|
||||
src: cssSrc
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
highlightSelectedTheme(themeId);
|
||||
|
||||
app.alert({
|
||||
alert_id: 'admin:theme',
|
||||
type: 'info',
|
||||
title: 'Theme Changed',
|
||||
message: 'Please restart your NodeBB to fully activate this theme',
|
||||
timeout: 5000,
|
||||
clickfn: function() {
|
||||
socket.emit('admin.restart');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Skins.render = function(bootswatch) {
|
||||
var themeContainer = $('#bootstrap_themes');
|
||||
|
||||
templates.parse('admin/partials/theme_list', {
|
||||
themes: bootswatch.themes.map(function(theme) {
|
||||
return {
|
||||
type: 'bootswatch',
|
||||
id: theme.name,
|
||||
name: theme.name,
|
||||
description: theme.description,
|
||||
screenshot_url: theme.thumbnail,
|
||||
url: theme.preview,
|
||||
css: theme.cssCdn
|
||||
};
|
||||
})
|
||||
}, function(html) {
|
||||
themeContainer.html(html);
|
||||
});
|
||||
};
|
||||
|
||||
function highlightSelectedTheme(themeId) {
|
||||
$('.themes li[data-theme]').removeClass('btn-warning');
|
||||
$('.themes li[data-theme="' + themeId + '"]').addClass('btn-warning');
|
||||
}
|
||||
|
||||
return Skins;
|
||||
});
|
@ -1,93 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, socket */
|
||||
|
||||
define('forum/admin/appearance/themes', function() {
|
||||
var Themes = {};
|
||||
|
||||
Themes.init = function() {
|
||||
$('#installed_themes').on('click', function(e){
|
||||
var target = $(e.target),
|
||||
action = target.attr('data-action');
|
||||
|
||||
if (action && action === 'use') {
|
||||
var parentEl = target.parents('li'),
|
||||
themeType = parentEl.attr('data-type'),
|
||||
cssSrc = parentEl.attr('data-css'),
|
||||
themeId = parentEl.attr('data-theme');
|
||||
|
||||
socket.emit('admin.themes.set', {
|
||||
type: themeType,
|
||||
id: themeId,
|
||||
src: cssSrc
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
highlightSelectedTheme(themeId);
|
||||
|
||||
app.alert({
|
||||
alert_id: 'admin:theme',
|
||||
type: 'info',
|
||||
title: 'Theme Changed',
|
||||
message: 'Please restart your NodeBB to fully activate this theme',
|
||||
timeout: 5000,
|
||||
clickfn: function() {
|
||||
socket.emit('admin.restart');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#revert_theme').on('click', function() {
|
||||
bootbox.confirm('Are you sure you wish to remove the custom theme and restore the NodeBB default theme?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.themes.set', {
|
||||
type: 'local',
|
||||
id: 'nodebb-theme-vanilla'
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
highlightSelectedTheme('nodebb-theme-vanilla');
|
||||
app.alert({
|
||||
alert_id: 'admin:theme',
|
||||
type: 'success',
|
||||
title: 'Theme Changed',
|
||||
message: 'You have successfully reverted your NodeBB back to it\'s default theme.',
|
||||
timeout: 3500
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Installed Themes
|
||||
socket.emit('admin.themes.getInstalled', function(err, themes) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
var instListEl = $('#installed_themes');
|
||||
|
||||
if (!themes.length) {
|
||||
instListEl.append($('<li/ >').addClass('no-themes').html('No installed themes found'));
|
||||
return;
|
||||
} else {
|
||||
templates.parse('admin/partials/theme_list', {
|
||||
themes: themes
|
||||
}, function(html) {
|
||||
instListEl.html(html);
|
||||
highlightSelectedTheme(config['theme:id']);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function highlightSelectedTheme(themeId) {
|
||||
$('.themes li[data-theme]').removeClass('btn-warning');
|
||||
$('.themes li[data-theme="' + themeId + '"]').addClass('btn-warning');
|
||||
}
|
||||
|
||||
return Themes;
|
||||
});
|
@ -1,83 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, socket */
|
||||
|
||||
define('forum/admin/extend/plugins', function() {
|
||||
var Plugins = {
|
||||
init: function() {
|
||||
var pluginsList = $('.plugins'),
|
||||
numPlugins = pluginsList[0].querySelectorAll('li').length,
|
||||
pluginID;
|
||||
|
||||
if (numPlugins > 0) {
|
||||
|
||||
pluginsList.on('click', 'button[data-action="toggleActive"]', function() {
|
||||
pluginID = $(this).parents('li').attr('data-plugin-id');
|
||||
var btn = $(this);
|
||||
socket.emit('admin.plugins.toggleActive', pluginID, function(err, status) {
|
||||
btn.html('<i class="fa fa-power-off"></i> ' + (status.active ? 'Deactivate' : 'Activate'));
|
||||
btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active);
|
||||
|
||||
app.alert({
|
||||
alert_id: 'plugin_toggled',
|
||||
title: 'Plugin ' + (status.active ? 'Enabled' : 'Disabled'),
|
||||
message: status.active ? 'Please restart your NodeBB to fully activate this plugin' : 'Plugin successfully deactivated',
|
||||
type: status.active ? 'warning' : 'success',
|
||||
timeout: 5000,
|
||||
clickfn: function() {
|
||||
socket.emit('admin.restart');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
pluginsList.on('click', 'button[data-action="toggleInstall"]', function() {
|
||||
pluginID = $(this).parents('li').attr('data-plugin-id');
|
||||
|
||||
var btn = $(this);
|
||||
var activateBtn = btn.siblings('[data-action="toggleActive"]');
|
||||
btn.html(btn.html() + 'ing')
|
||||
.attr('disabled', true)
|
||||
.find('i').attr('class', 'fa fa-refresh fa-spin');
|
||||
|
||||
socket.emit('admin.plugins.toggleInstall', pluginID, function(err, status) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (status.installed) {
|
||||
btn.html('<i class="fa fa-trash-o"></i> Uninstall');
|
||||
} else {
|
||||
btn.html('<i class="fa fa-download"></i> Install');
|
||||
|
||||
}
|
||||
activateBtn.toggleClass('hidden', !status.installed);
|
||||
|
||||
btn.toggleClass('btn-danger', status.installed).toggleClass('btn-success', !status.installed)
|
||||
.attr('disabled', false);
|
||||
|
||||
app.alert({
|
||||
alert_id: 'plugin_toggled',
|
||||
title: 'Plugin ' + (status.installed ? 'Installed' : 'Uninstalled'),
|
||||
message: status.installed ? 'Plugin successfully installed, please activate the plugin.' : 'The plugin has been successfully deactivated and uninstalled.',
|
||||
type: 'info',
|
||||
timeout: 5000
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#plugin-search').on('input propertychange', function() {
|
||||
var term = $(this).val();
|
||||
$('.plugins li').each(function() {
|
||||
var pluginId = $(this).attr('data-plugin-id');
|
||||
$(this).toggleClass('hide', pluginId && pluginId.indexOf(term) === -1);
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
pluginsList.append('<li><p><i>No plugins found.</i></p></li>');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Plugins;
|
||||
});
|
@ -1,198 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, socket */
|
||||
|
||||
define('forum/admin/extend/widgets', function() {
|
||||
var Widgets = {};
|
||||
|
||||
Widgets.init = function() {
|
||||
prepareWidgets();
|
||||
|
||||
$('#widgets .nav-pills a').on('click', function(ev) {
|
||||
var $this = $(this);
|
||||
$('#widgets .nav-pills li').removeClass('active');
|
||||
$this.parent().addClass('active');
|
||||
|
||||
$('#widgets .tab-pane').removeClass('active');
|
||||
$('#widgets .tab-pane[data-template="' + $this.attr('data-template') + '"]').addClass('active');
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function prepareWidgets() {
|
||||
$('[data-location="drafts"]').insertAfter($('[data-location="drafts"]').closest('.tab-content'));
|
||||
|
||||
$('#widgets .available-widgets .widget-panel').draggable({
|
||||
helper: function(e) {
|
||||
return $(e.target).parents('.widget-panel').clone().addClass('block').width($(e.target.parentNode).width());
|
||||
},
|
||||
distance: 10,
|
||||
connectToSortable: ".widget-area"
|
||||
});
|
||||
|
||||
$('#widgets .available-containers .containers > [data-container-html]').draggable({
|
||||
helper: function(e) {
|
||||
var target = $(e.target);
|
||||
target = target.attr('data-container-html') ? target : target.parents('[data-container-html]');
|
||||
|
||||
return target.clone().addClass('block').width(target.width()).css('opacity', '0.5');
|
||||
},
|
||||
distance: 10
|
||||
});
|
||||
|
||||
function appendToggle(el) {
|
||||
if (!el.hasClass('block')) {
|
||||
el.addClass('block')
|
||||
.droppable({
|
||||
accept: '[data-container-html]',
|
||||
drop: function(event, ui) {
|
||||
var el = $(this);
|
||||
|
||||
el.find('.panel-body .container-html').val(ui.draggable.attr('data-container-html'));
|
||||
el.find('.panel-body').removeClass('hidden');
|
||||
},
|
||||
hoverClass: "panel-info"
|
||||
})
|
||||
.children('.panel-heading')
|
||||
.append('<div class="pull-right pointer"><span class="delete-widget"><i class="fa fa-times-circle"></i></span></div><div class="pull-left pointer"><span class="toggle-widget"><i class="fa fa-chevron-circle-down"></i></span> </div>')
|
||||
.children('small').html('');
|
||||
}
|
||||
}
|
||||
|
||||
$('#widgets .widget-area').sortable({
|
||||
update: function (event, ui) {
|
||||
appendToggle(ui.item);
|
||||
},
|
||||
connectWith: "div"
|
||||
}).on('click', '.toggle-widget', function() {
|
||||
$(this).parents('.widget-panel').children('.panel-body').toggleClass('hidden');
|
||||
}).on('click', '.delete-widget', function() {
|
||||
var panel = $(this).parents('.widget-panel');
|
||||
|
||||
bootbox.confirm('Are you sure you wish to delete this widget?', function(confirm) {
|
||||
if (confirm) {
|
||||
panel.remove();
|
||||
}
|
||||
});
|
||||
}).on('dblclick', '.panel-heading', function() {
|
||||
$(this).parents('.widget-panel').children('.panel-body').toggleClass('hidden');
|
||||
});
|
||||
|
||||
$('#widgets .save').on('click', saveWidgets);
|
||||
|
||||
function saveWidgets() {
|
||||
var total = $('#widgets [data-template][data-location]').length;
|
||||
|
||||
$('#widgets [data-template][data-location]').each(function(i, el) {
|
||||
el = $(el);
|
||||
|
||||
var template = el.attr('data-template'),
|
||||
location = el.attr('data-location'),
|
||||
area = el.children('.widget-area'),
|
||||
widgets = [];
|
||||
|
||||
area.find('.widget-panel[data-widget]').each(function() {
|
||||
var widgetData = {},
|
||||
data = $(this).find('form').serializeArray();
|
||||
|
||||
for (var d in data) {
|
||||
if (data.hasOwnProperty(d)) {
|
||||
if (data[d].name) {
|
||||
widgetData[data[d].name] = data[d].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widgets.push({
|
||||
widget: $(this).attr('data-widget'),
|
||||
data: widgetData
|
||||
});
|
||||
});
|
||||
|
||||
socket.emit('admin.widgets.set', {
|
||||
template: template,
|
||||
location: location,
|
||||
widgets: widgets
|
||||
}, function(err) {
|
||||
total--;
|
||||
|
||||
if (err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (total === 0) {
|
||||
app.alert({
|
||||
alert_id: 'admin:widgets',
|
||||
type: 'success',
|
||||
title: 'Widgets Updated',
|
||||
message: 'Successfully updated widgets',
|
||||
timeout: 2500
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function populateWidget(widget, data) {
|
||||
if (data.title) {
|
||||
var title = widget.find('.panel-heading strong');
|
||||
title.text(title.text() + ' - ' + data.title);
|
||||
}
|
||||
|
||||
widget.find('input, textarea').each(function() {
|
||||
var input = $(this),
|
||||
value = data[input.attr('name')];
|
||||
|
||||
if (this.type === 'checkbox') {
|
||||
input.attr('checked', !!value);
|
||||
} else {
|
||||
input.val(value);
|
||||
}
|
||||
});
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
$.get(RELATIVE_PATH + '/api/admin/extend/widgets', function(data) {
|
||||
var areas = data.areas;
|
||||
|
||||
for(var i=0; i<areas.length; ++i) {
|
||||
var area = areas[i],
|
||||
widgetArea = $('#widgets .area[data-template="' + area.template + '"][data-location="' + area.location + '"]').find('.widget-area');
|
||||
|
||||
widgetArea.html('');
|
||||
|
||||
for (var k=0; k<area.data.length; ++k) {
|
||||
var widgetData = area.data[k],
|
||||
widgetEl = $('.available-widgets [data-widget="' + widgetData.widget + '"]').clone(true);
|
||||
|
||||
widgetArea.append(populateWidget(widgetEl, widgetData.data));
|
||||
appendToggle(widgetEl);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.color-selector').on('click', '.btn', function() {
|
||||
var btn = $(this),
|
||||
selector = btn.parents('.color-selector'),
|
||||
container = selector.parents('[data-container-html]'),
|
||||
classList = [];
|
||||
|
||||
selector.children().each(function() {
|
||||
classList.push($(this).attr('data-class'));
|
||||
});
|
||||
|
||||
container
|
||||
.removeClass(classList.join(' '))
|
||||
.addClass(btn.attr('data-class'));
|
||||
|
||||
container.attr('data-container-html', container.attr('data-container-html')
|
||||
.replace(/class="[a-zA-Z0-9-\s]+"/, 'class="' + container[0].className.replace(' pointer ui-draggable', '') + '"')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return Widgets;
|
||||
});
|
@ -1,190 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, app, socket, Hammer, RELATIVE_PATH */
|
||||
|
||||
define('forum/admin/footer', ['forum/admin/settings'], function(Settings) {
|
||||
var acpIndex;
|
||||
|
||||
$(document).ready(function() {
|
||||
if(!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
getSearchIndex();
|
||||
} else {
|
||||
activateMobile();
|
||||
}
|
||||
|
||||
$(window).on('action:ajaxify.end', function(ev, data) {
|
||||
var url = data.url;
|
||||
|
||||
selectMenuItem(data.url);
|
||||
});
|
||||
|
||||
setupMainMenu();
|
||||
});
|
||||
|
||||
function activateMobile() {
|
||||
$('.admin').addClass('mobile');
|
||||
$('#main-menu').addClass('transitioning');
|
||||
|
||||
Hammer(document.body).on('swiperight', function(e) {
|
||||
$('#main-menu').addClass('open');
|
||||
});
|
||||
|
||||
Hammer(document.body).on('swipeleft', function(e) {
|
||||
$('#main-menu').removeClass('open');
|
||||
});
|
||||
|
||||
Hammer($('#main-menu')[0]).on('swiperight', function(e) {
|
||||
$('#main-menu').addClass('open');
|
||||
});
|
||||
|
||||
Hammer($('#main-menu')[0]).on('swipeleft', function(e) {
|
||||
$('#main-menu').removeClass('open');
|
||||
});
|
||||
|
||||
$(window).on('scroll', function() {
|
||||
$('#main-menu').height($(window).height() + 20);
|
||||
});
|
||||
}
|
||||
|
||||
function setupMainMenu() {
|
||||
$('.sidebar-nav .nav-header').on('click', function() {
|
||||
$(this).parents('.sidebar-nav').toggleClass('open');
|
||||
setTimeout(function() {
|
||||
$('.nano').nanoScroller();
|
||||
}, 500); // replace with animationend event
|
||||
});
|
||||
|
||||
$('.nano').nanoScroller();
|
||||
|
||||
$('#main-menu .nav-list > li a').append('<span class="pull-right"><i class="fa fa-inverse fa-arrow-circle-right"></i> </span>');
|
||||
}
|
||||
|
||||
function selectMenuItem(url) {
|
||||
$('#main-menu .nav-list > li').removeClass('active').each(function() {
|
||||
var menu = $(this),
|
||||
category = menu.parents('.sidebar-nav'),
|
||||
href = menu.children('a').attr('href');
|
||||
|
||||
if (href && href.slice(1).indexOf(url) !== -1) {
|
||||
category.addClass('open');
|
||||
menu.addClass('active');
|
||||
modifyBreadcrumb(category.find('.nav-header').text(), menu.text());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function modifyBreadcrumb() {
|
||||
var caret = ' <i class="fa fa-angle-right"></i> ';
|
||||
|
||||
$('#breadcrumbs').html(caret + Array.prototype.slice.call(arguments).join(caret));
|
||||
}
|
||||
|
||||
function getSearchIndex() {
|
||||
$.getJSON(RELATIVE_PATH + '/templates/indexed.json', function (data) {
|
||||
acpIndex = data;
|
||||
for (var file in acpIndex) {
|
||||
if (acpIndex.hasOwnProperty(file)) {
|
||||
acpIndex[file] = acpIndex[file].replace(/<img/g, '<none'); // can't think of a better solution, see #2153
|
||||
acpIndex[file] = $('<div class="search-container">' + acpIndex[file] + '</div>');
|
||||
acpIndex[file].find('script').remove();
|
||||
|
||||
acpIndex[file] = acpIndex[file].text().toLowerCase().replace(/[ |\r|\n]+/g, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
delete acpIndex['/admin/header.tpl'];
|
||||
delete acpIndex['/admin/footer.tpl'];
|
||||
|
||||
setupACPSearch();
|
||||
});
|
||||
}
|
||||
|
||||
function setupACPSearch() {
|
||||
var menu = $('#acp-search .dropdown-menu'),
|
||||
routes = [],
|
||||
input = $('#acp-search input'),
|
||||
firstResult = null;
|
||||
|
||||
input.on('keyup', function() {
|
||||
$('#acp-search .dropdown').addClass('open');
|
||||
});
|
||||
|
||||
$('#acp-search').parents('form').on('submit', function(ev) {
|
||||
var input = $(this).find('input'),
|
||||
href = firstResult ? firstResult : RELATIVE_PATH + '/search/' + input.val();
|
||||
|
||||
ajaxify.go(href.replace(/^\//, ''));
|
||||
|
||||
setTimeout(function() {
|
||||
$('#acp-search .dropdown').removeClass('open');
|
||||
$(input).blur();
|
||||
}, 150);
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.sidebar-nav a').each(function(idx, link) {
|
||||
routes.push($(link).attr('href'));
|
||||
});
|
||||
|
||||
input.on('blur', function() {
|
||||
$(this).val('').attr('placeholder', '/');
|
||||
});
|
||||
|
||||
input.on('keyup focus', function() {
|
||||
var $input = $(this),
|
||||
value = $input.val().toLowerCase(),
|
||||
menuItems = $('#acp-search .dropdown-menu').html('');
|
||||
|
||||
function toUpperCase(txt){
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
}
|
||||
|
||||
$input.attr('placeholder', '');
|
||||
|
||||
firstResult = null;
|
||||
|
||||
if (value.length >= 3) {
|
||||
for (var file in acpIndex) {
|
||||
if (acpIndex.hasOwnProperty(file)) {
|
||||
var position = acpIndex[file].indexOf(value);
|
||||
|
||||
if (position !== -1) {
|
||||
var href = file.replace('.tpl', ''),
|
||||
title = href.replace(/^\/admin\//, '').split('/'),
|
||||
description = acpIndex[file].substring(Math.max(0, position - 25), Math.min(acpIndex[file].length - 1, position + 25))
|
||||
.replace(value, '<span class="search-match">' + value + '</span>');
|
||||
|
||||
for (var t in title) {
|
||||
if (title.hasOwnProperty(t)) {
|
||||
title[t] = title[t]
|
||||
.replace('-', ' ')
|
||||
.replace(/\w\S*/g, toUpperCase);
|
||||
}
|
||||
}
|
||||
|
||||
title = title.join(' > ');
|
||||
href = RELATIVE_PATH + href;
|
||||
firstResult = firstResult ? firstResult : href;
|
||||
|
||||
if ($.inArray(href, routes) !== -1) {
|
||||
menuItems.append('<li role="presentation"><a role="menuitem" href="' + href + '">' + title + '<br /><small><code>...' + description + '...</code></small></a></li>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (menuItems.html() !== '') {
|
||||
menuItems.append('<li role="presentation" class="divider"></li>');
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length > 0) {
|
||||
menuItems.append('<li role="presentation"><a role="menuitem" href="' + RELATIVE_PATH + '/search/' + value + '">Search the forum for <strong>' + value + '</strong></a></li>');
|
||||
} else {
|
||||
menuItems.append('<li role="presentation"><a role="menuitem" href="#">Start typing to see results...</a></li>');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,445 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, ajaxify, app, socket, RELATIVE_PATH*/
|
||||
|
||||
define('forum/admin/general/dashboard', ['semver'], function(semver) {
|
||||
var Admin = {},
|
||||
intervals = {
|
||||
rooms: false,
|
||||
graphs: false
|
||||
},
|
||||
isMobile = false;
|
||||
|
||||
|
||||
Admin.init = function() {
|
||||
app.enterRoom('admin');
|
||||
socket.emit('meta.rooms.getAll', Admin.updateRoomUsage);
|
||||
|
||||
isMobile = !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
intervals.rooms = setInterval(function() {
|
||||
if (app.isFocused && app.isConnected) {
|
||||
socket.emit('meta.rooms.getAll', Admin.updateRoomUsage);
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
clearInterval(intervals.rooms);
|
||||
clearInterval(intervals.graphs);
|
||||
|
||||
intervals.rooms = null;
|
||||
intervals.graphs = null;
|
||||
});
|
||||
|
||||
$('#logout-link').on('click', function() {
|
||||
$.post(RELATIVE_PATH + '/logout', function() {
|
||||
window.location.href = RELATIVE_PATH + '/';
|
||||
});
|
||||
});
|
||||
|
||||
$.get('https://api.github.com/repos/NodeBB/NodeBB/tags', function(releases) {
|
||||
// Re-sort the releases, as they do not follow Semver (wrt pre-releases)
|
||||
releases = releases.sort(function(a, b) {
|
||||
a = a.name.replace(/^v/, '');
|
||||
b = b.name.replace(/^v/, '');
|
||||
return semver.lt(a, b) ? 1 : -1;
|
||||
});
|
||||
|
||||
var version = $('#version').html(),
|
||||
latestVersion = releases[0].name.slice(1),
|
||||
checkEl = $('.version-check');
|
||||
checkEl.html($('.version-check').html().replace('<i class="fa fa-spinner fa-spin"></i>', 'v' + latestVersion));
|
||||
|
||||
// Alter box colour accordingly
|
||||
if (semver.eq(latestVersion, version)) {
|
||||
checkEl.removeClass('alert-info').addClass('alert-success');
|
||||
checkEl.append('<p>You are <strong>up-to-date</strong> <i class="fa fa-check"></i></p>');
|
||||
} else if (semver.gt(latestVersion, version)) {
|
||||
checkEl.removeClass('alert-info').addClass('alert-danger');
|
||||
checkEl.append('<p>A new version (v' + latestVersion + ') has been released. Consider upgrading your NodeBB.</p>');
|
||||
} else if (semver.gt(version, latestVersion)) {
|
||||
checkEl.removeClass('alert-info').addClass('alert-warning');
|
||||
checkEl.append('<p>You are running a <strong>development version</strong>! Unintended bugs may occur. <i class="fa fa-warning"></i></p>');
|
||||
}
|
||||
});
|
||||
|
||||
$('.restart').on('click', function() {
|
||||
bootbox.confirm('Are you sure you wish to restart NodeBB?', function(confirm) {
|
||||
if (confirm) {
|
||||
app.alert({
|
||||
alert_id: 'instance_restart',
|
||||
type: 'info',
|
||||
title: 'Restarting... <i class="fa fa-spin fa-refresh"></i>',
|
||||
message: 'NodeBB is restarting.',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
$(window).one('action:reconnected', function() {
|
||||
app.alert({
|
||||
alert_id: 'instance_restart',
|
||||
type: 'success',
|
||||
title: '<i class="fa fa-check"></i> Success',
|
||||
message: 'NodeBB has successfully restarted.',
|
||||
timeout: 5000
|
||||
});
|
||||
});
|
||||
|
||||
socket.emit('admin.restart');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.reload').on('click', function() {
|
||||
app.alert({
|
||||
alert_id: 'instance_reload',
|
||||
type: 'info',
|
||||
title: 'Reloading... <i class="fa fa-spin fa-refresh"></i>',
|
||||
message: 'NodeBB is reloading.',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
socket.emit('admin.reload', function(err) {
|
||||
if (!err) {
|
||||
app.alert({
|
||||
alert_id: 'instance_reload',
|
||||
type: 'success',
|
||||
title: '<i class="fa fa-check"></i> Success',
|
||||
message: 'NodeBB has successfully reloaded.',
|
||||
timeout: 5000
|
||||
});
|
||||
} else {
|
||||
app.alert({
|
||||
alert_id: 'instance_reload',
|
||||
type: 'danger',
|
||||
title: '[[global:alert.error]]',
|
||||
message: '[[error:reload-failed, ' + err.message + ']]'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setupGraphs();
|
||||
};
|
||||
|
||||
Admin.updateRoomUsage = function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
var html = '<div class="text-center pull-left">' +
|
||||
'<div>'+ data.onlineRegisteredCount +'</div>' +
|
||||
'<div>Users</div>' +
|
||||
'</div>' +
|
||||
'<div class="text-center pull-left">' +
|
||||
'<div>'+ data.onlineGuestCount +'</div>' +
|
||||
'<div>Guests</div>' +
|
||||
'</div>' +
|
||||
'<div class="text-center pull-left">' +
|
||||
'<div>'+ (data.onlineRegisteredCount + data.onlineGuestCount) +'</div>' +
|
||||
'<div>Total</div>' +
|
||||
'</div>' +
|
||||
'<div class="text-center pull-left">' +
|
||||
'<div>'+ data.socketCount +'</div>' +
|
||||
'<div>Connections</div>' +
|
||||
'</div>';
|
||||
|
||||
var idle = data.socketCount - (data.users.home + data.users.topics + data.users.category);
|
||||
|
||||
updateRegisteredGraph(data.onlineRegisteredCount, data.onlineGuestCount);
|
||||
updatePresenceGraph(data.users.home, data.users.topics, data.users.category, idle);
|
||||
updateTopicsGraph(data.topics);
|
||||
|
||||
$('#active-users').html(html);
|
||||
};
|
||||
|
||||
var graphs = {
|
||||
traffic: null,
|
||||
registered: null,
|
||||
presence: null,
|
||||
topics: null
|
||||
};
|
||||
|
||||
var topicColors = ["#bf616a","#5B90BF","#d08770","#ebcb8b","#a3be8c","#96b5b4","#8fa1b3","#b48ead","#ab7967","#46BFBD"],
|
||||
usedTopicColors = [];
|
||||
|
||||
// from chartjs.org
|
||||
function lighten(col, amt) {
|
||||
var usePound = false;
|
||||
|
||||
if (col[0] == "#") {
|
||||
col = col.slice(1);
|
||||
usePound = true;
|
||||
}
|
||||
|
||||
var num = parseInt(col,16);
|
||||
|
||||
var r = (num >> 16) + amt;
|
||||
|
||||
if (r > 255) r = 255;
|
||||
else if (r < 0) r = 0;
|
||||
|
||||
var b = ((num >> 8) & 0x00FF) + amt;
|
||||
|
||||
if (b > 255) b = 255;
|
||||
else if (b < 0) b = 0;
|
||||
|
||||
var g = (num & 0x0000FF) + amt;
|
||||
|
||||
if (g > 255) g = 255;
|
||||
else if (g < 0) g = 0;
|
||||
|
||||
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
|
||||
}
|
||||
|
||||
function getHoursArray() {
|
||||
var currentHour = new Date().getHours(),
|
||||
labels = [];
|
||||
|
||||
for (var i = currentHour, ii = currentHour - 12; i > ii; i--) {
|
||||
var hour = i < 0 ? 24 + i : i;
|
||||
labels.push(hour + ':00 ');
|
||||
}
|
||||
|
||||
return labels.reverse();
|
||||
}
|
||||
|
||||
function setupGraphs() {
|
||||
var trafficCanvas = document.getElementById('analytics-traffic'),
|
||||
registeredCanvas = document.getElementById('analytics-registered'),
|
||||
presenceCanvas = document.getElementById('analytics-presence'),
|
||||
topicsCanvas = document.getElementById('analytics-topics'),
|
||||
trafficCtx = trafficCanvas.getContext('2d'),
|
||||
registeredCtx = registeredCanvas.getContext('2d'),
|
||||
presenceCtx = presenceCanvas.getContext('2d'),
|
||||
topicsCtx = topicsCanvas.getContext('2d'),
|
||||
trafficLabels = getHoursArray();
|
||||
|
||||
if (isMobile) {
|
||||
Chart.defaults.global.showTooltips = false;
|
||||
}
|
||||
|
||||
var data = {
|
||||
labels: trafficLabels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Page Views",
|
||||
fillColor: "rgba(220,220,220,0.2)",
|
||||
strokeColor: "rgba(220,220,220,1)",
|
||||
pointColor: "rgba(220,220,220,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(220,220,220,1)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0,0]
|
||||
},
|
||||
{
|
||||
label: "Unique Visitors",
|
||||
fillColor: "rgba(151,187,205,0.2)",
|
||||
strokeColor: "rgba(151,187,205,1)",
|
||||
pointColor: "rgba(151,187,205,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0,0]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
trafficCanvas.width = $(trafficCanvas).parent().width(); // is this necessary
|
||||
graphs.traffic = new Chart(trafficCtx).Line(data, {
|
||||
responsive: true
|
||||
});
|
||||
|
||||
graphs.registered = new Chart(registeredCtx).Doughnut([{
|
||||
value: 1,
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "Registered Users"
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Anonymous Users"
|
||||
}], {
|
||||
responsive: true
|
||||
});
|
||||
|
||||
graphs.presence = new Chart(presenceCtx).Doughnut([{
|
||||
value: 1,
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "On homepage"
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Reading posts"
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
color: "#FDB45C",
|
||||
highlight: "#FFC870",
|
||||
label: "Browsing topics"
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
color: "#949FB1",
|
||||
highlight: "#A8B3C5",
|
||||
label: "Idle"
|
||||
}], {
|
||||
responsive: true
|
||||
});
|
||||
|
||||
graphs.topics = new Chart(topicsCtx).Doughnut([], {responsive: true});
|
||||
topicsCanvas.onclick = function(evt){
|
||||
var obj = graphs.topics.getSegmentsAtEvent(evt);
|
||||
window.open(RELATIVE_PATH + '/topic/' + obj[0].tid);
|
||||
};
|
||||
|
||||
intervals.graphs = setInterval(updateTrafficGraph, 15000);
|
||||
updateTrafficGraph();
|
||||
|
||||
$(window).on('resize', adjustPieCharts);
|
||||
adjustPieCharts();
|
||||
}
|
||||
|
||||
function adjustPieCharts() {
|
||||
$('.pie-chart.legend-up').each(function() {
|
||||
var $this = $(this);
|
||||
|
||||
if ($this.width() < 320) {
|
||||
$this.addClass('compact');
|
||||
} else {
|
||||
$this.removeClass('compact');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTrafficGraph() {
|
||||
if (!app.isFocused || !app.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('admin.analytics.get', {graph: "traffic"}, function (err, data) {
|
||||
for (var i = 0, ii = data.pageviews.length; i < ii; i++) {
|
||||
graphs.traffic.datasets[0].points[i].value = data.pageviews[i];
|
||||
graphs.traffic.datasets[1].points[i].value = data.uniqueVisitors[i];
|
||||
}
|
||||
|
||||
var currentHour = new Date().getHours();
|
||||
|
||||
graphs.traffic.scale.xLabels = getHoursArray();
|
||||
graphs.traffic.update();
|
||||
});
|
||||
}
|
||||
|
||||
function updateRegisteredGraph(registered, anonymous) {
|
||||
graphs.registered.segments[0].value = registered;
|
||||
graphs.registered.segments[1].value = anonymous;
|
||||
graphs.registered.update();
|
||||
}
|
||||
|
||||
function updatePresenceGraph(homepage, posts, topics, idle) {
|
||||
graphs.presence.segments[0].value = homepage;
|
||||
graphs.presence.segments[1].value = posts;
|
||||
graphs.presence.segments[2].value = topics;
|
||||
graphs.presence.segments[3].value = idle;
|
||||
graphs.presence.update();
|
||||
}
|
||||
|
||||
function updateTopicsGraph(topics) {
|
||||
if (!Object.keys(topics).length) {
|
||||
topics = {"0": {
|
||||
title: "No users browsing",
|
||||
value: 1
|
||||
}};
|
||||
}
|
||||
|
||||
var tids = Object.keys(topics),
|
||||
segments = graphs.topics.segments;
|
||||
|
||||
function reassignExistingTopics() {
|
||||
for (var i = 0, ii = segments.length; i < ii; i++ ) {
|
||||
if (!segments[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tid = segments[i].tid;
|
||||
|
||||
if ($.inArray(tid, tids) === -1) {
|
||||
usedTopicColors.splice($.inArray(segments[i].color, usedTopicColors), 1);
|
||||
graphs.topics.removeData(i);
|
||||
} else {
|
||||
graphs.topics.segments[i].value = topics[tid].value;
|
||||
delete topics[tid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assignNewTopics() {
|
||||
while (segments.length < 10 && tids.length > 0) {
|
||||
var tid = tids.pop(),
|
||||
data = topics[tid],
|
||||
color = null;
|
||||
|
||||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tid === '0') {
|
||||
color = '#4D5360';
|
||||
} else {
|
||||
do {
|
||||
for (var i = 0, ii = topicColors.length; i < ii; i++) {
|
||||
var chosenColor = topicColors[i];
|
||||
|
||||
if ($.inArray(chosenColor, usedTopicColors) === -1) {
|
||||
color = chosenColor;
|
||||
usedTopicColors.push(color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (color === null && usedTopicColors.length < topicColors.length);
|
||||
}
|
||||
|
||||
if (color) {
|
||||
graphs.topics.addData({
|
||||
value: data.value,
|
||||
color: color,
|
||||
highlight: lighten(color, 10),
|
||||
label: data.title
|
||||
});
|
||||
|
||||
segments[segments.length - 1].tid = tid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildTopicsLegend() {
|
||||
var legend = $('#topics-legend').html('');
|
||||
|
||||
for (var i = 0, ii = segments.length; i < ii; i++) {
|
||||
var topic = segments[i],
|
||||
label = topic.tid === '0' ? topic.label : '<a title="' + topic.label + '"href="' + RELATIVE_PATH + '/topic/' + topic.tid + '" target="_blank"> ' + topic.label + '</a>';
|
||||
|
||||
legend.append(
|
||||
'<li>' +
|
||||
'<div style="background-color: ' + topic.highlightColor + '; border-color: ' + topic.strokeColor + '"></div>' +
|
||||
'<span>' + label + '</span>' +
|
||||
'</li>');
|
||||
}
|
||||
}
|
||||
|
||||
reassignExistingTopics();
|
||||
assignNewTopics();
|
||||
buildTopicsLegend();
|
||||
|
||||
graphs.topics.update();
|
||||
}
|
||||
|
||||
function buildTopicsLegend() {
|
||||
|
||||
}
|
||||
|
||||
return Admin;
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
"use strict";
|
||||
/*global define*/
|
||||
|
||||
define('forum/admin/general/languages', ['forum/admin/settings'], function(Settings) {
|
||||
$(function() {
|
||||
Settings.prepare();
|
||||
});
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, socket */
|
||||
|
||||
define('forum/admin/general/sounds', ['sounds', 'settings'], function(Sounds, Settings) {
|
||||
var SoundsAdmin = {};
|
||||
|
||||
SoundsAdmin.init = function() {
|
||||
// Sounds tab
|
||||
$('.sounds').find('button[data-action="play"]').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var fileName = $(this).parent().parent().find('select').val();
|
||||
Sounds.playFile(fileName);
|
||||
});
|
||||
|
||||
// Load Form Values
|
||||
Settings.load('sounds', $('.sounds form'));
|
||||
|
||||
// Saving of Form Values
|
||||
var saveEl = $('#save');
|
||||
saveEl.on('click', function() {
|
||||
Settings.save('sounds', $('.sounds form'), function() {
|
||||
socket.emit('admin.fireEvent', {
|
||||
name: 'event:sounds.reloadMapping'
|
||||
});
|
||||
app.alertSuccess('Settings Saved');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return SoundsAdmin;
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* globals define, bootbox */
|
||||
|
||||
define(function() {
|
||||
var iconSelect = {};
|
||||
|
||||
iconSelect.init = function(el, onModified) {
|
||||
onModified = onModified || function() {};
|
||||
var selected = el.attr('class').replace('fa-2x', '').replace('fa', '').replace(/\s+/g, '');
|
||||
$('#icons .selected').removeClass('selected');
|
||||
|
||||
if (selected === '') {
|
||||
selected = 'fa-doesnt-exist';
|
||||
}
|
||||
if (selected) {
|
||||
$('#icons .fa-icons .fa.' + selected).parent().addClass('selected');
|
||||
}
|
||||
|
||||
bootbox.confirm('<h2>Select an icon.</h2>' + $('#icons').html(), function(confirm) {
|
||||
if (confirm) {
|
||||
var iconClass = $('.bootbox .selected').attr('class');
|
||||
var categoryIconClass = $('<div/>').addClass(iconClass).removeClass('fa').removeClass('selected').attr('class');
|
||||
if (categoryIconClass === 'fa-doesnt-exist') {
|
||||
categoryIconClass = '';
|
||||
}
|
||||
|
||||
el.attr('class', 'fa fa-2x ' + categoryIconClass);
|
||||
el.val(categoryIconClass);
|
||||
el.attr('value', categoryIconClass);
|
||||
|
||||
onModified(el);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function() { //bootbox was rewritten for BS3 and I had to add this timeout for the previous code to work. TODO: to look into
|
||||
$('.bootbox .fa-icons i').on('click', function() {
|
||||
$('.bootbox .selected').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
return iconSelect;
|
||||
});
|
||||
|
@ -1,391 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, socket, app, bootbox, templates, ajaxify, RELATIVE_PATH*/
|
||||
|
||||
define('forum/admin/manage/categories', ['uploader', 'forum/admin/iconSelect'], function(uploader, iconSelect) {
|
||||
var Categories = {};
|
||||
|
||||
Categories.init = function() {
|
||||
var modified_categories = {};
|
||||
|
||||
function modified(el) {
|
||||
var cid = $(el).parents('li').attr('data-cid');
|
||||
if(cid) {
|
||||
modified_categories[cid] = modified_categories[cid] || {};
|
||||
modified_categories[cid][$(el).attr('data-name')] = $(el).val();
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
if(Object.keys(modified_categories).length) {
|
||||
socket.emit('admin.categories.update', modified_categories, function(err, result) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (result && result.length) {
|
||||
app.alert({
|
||||
title: 'Updated Categories',
|
||||
message: 'Category IDs ' + result.join(', ') + ' was successfully updated.',
|
||||
type: 'success',
|
||||
timeout: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
modified_categories = {};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function update_blockclass(el) {
|
||||
el.parentNode.parentNode.className = 'entry-row ' + el.value;
|
||||
}
|
||||
|
||||
function updateCategoryOrders() {
|
||||
var categories = $('.admin-categories #entry-container').children();
|
||||
for(var i = 0; i<categories.length; ++i) {
|
||||
var input = $(categories[i]).find('input[data-name="order"]');
|
||||
|
||||
input.val(i+1).attr('data-value', i+1);
|
||||
modified(input);
|
||||
}
|
||||
}
|
||||
|
||||
$('#entry-container').sortable({
|
||||
stop: function(event, ui) {
|
||||
updateCategoryOrders();
|
||||
},
|
||||
distance: 10
|
||||
});
|
||||
|
||||
$('.blockclass, .admin-categories form select').each(function() {
|
||||
var $this = $(this);
|
||||
$this.val($this.attr('data-value'));
|
||||
});
|
||||
|
||||
function showCreateCategoryModal() {
|
||||
$('#new-category-modal').modal();
|
||||
}
|
||||
|
||||
function createNewCategory() {
|
||||
var category = {
|
||||
name: $('#inputName').val(),
|
||||
description: $('#inputDescription').val(),
|
||||
icon: $('#new-category-modal i').attr('value'),
|
||||
bgColor: '#0059b2',
|
||||
color: '#fff',
|
||||
order: $('.admin-categories #entry-container').children().length + 1
|
||||
};
|
||||
|
||||
socket.emit('admin.categories.create', category, function(err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alert({
|
||||
alert_id: 'category_created',
|
||||
title: 'Created',
|
||||
message: 'Category successfully created!',
|
||||
type: 'success',
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
$('#new-category-modal').modal('hide');
|
||||
ajaxify.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
function enableColorPicker(idx, inputEl) {
|
||||
var $inputEl = $(inputEl),
|
||||
previewEl = $inputEl.parents('[data-cid]').find('.preview-box');
|
||||
|
||||
admin.enableColorPicker($inputEl, function(hsb, hex) {
|
||||
if ($inputEl.attr('data-name') === 'bgColor') {
|
||||
previewEl.css('background', '#' + hex);
|
||||
} else if ($inputEl.attr('data-name') === 'color') {
|
||||
previewEl.css('color', '#' + hex);
|
||||
}
|
||||
|
||||
modified($inputEl[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function setupEditTargets() {
|
||||
$('[data-edit-target]').on('click', function() {
|
||||
var $this = $(this),
|
||||
target = $($this.attr('data-edit-target'));
|
||||
|
||||
$this.addClass('hide');
|
||||
target.removeClass('hide').on('blur', function() {
|
||||
$this.removeClass('hide').children('span').html(this.value);
|
||||
$(this).addClass('hide');
|
||||
}).val($this.children('span').html());
|
||||
|
||||
target.focus();
|
||||
});
|
||||
}
|
||||
|
||||
$(function() {
|
||||
var url = window.location.href,
|
||||
parts = url.split('/'),
|
||||
active = parts[parts.length - 1];
|
||||
|
||||
$('.nav-pills li').removeClass('active');
|
||||
$('.nav-pills li a').each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.attr('href').match(active)) {
|
||||
$this.parent().addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#addNew').on('click', showCreateCategoryModal);
|
||||
$('#create-category-btn').on('click', createNewCategory);
|
||||
|
||||
$('#entry-container, #new-category-modal').on('click', '.icon', function(ev) {
|
||||
iconSelect.init($(this).find('i'), modified);
|
||||
});
|
||||
|
||||
$('.admin-categories form input, .admin-categories form select').on('change', function(ev) {
|
||||
modified(ev.target);
|
||||
});
|
||||
|
||||
$('.dropdown').on('click', '[data-disabled]', function(ev) {
|
||||
var btn = $(this),
|
||||
categoryRow = btn.parents('li'),
|
||||
cid = categoryRow.attr('data-cid'),
|
||||
disabled = btn.attr('data-disabled') === 'false' ? '1' : '0';
|
||||
|
||||
categoryRow.remove();
|
||||
modified_categories[cid] = modified_categories[cid] || {};
|
||||
modified_categories[cid].disabled = disabled;
|
||||
|
||||
save();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Colour Picker
|
||||
$('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker);
|
||||
|
||||
$('.admin-categories').on('click', '.save', save);
|
||||
$('.admin-categories').on('click', '.purge', function() {
|
||||
var categoryRow = $(this).parents('li[data-cid]');
|
||||
var cid = categoryRow.attr('data-cid');
|
||||
|
||||
bootbox.confirm('Do you really want to purge this category "' + categoryRow.find('#cid-' + cid + '-name').val() + '"?<br/><strong class="text-danger">Warning!</strong> All topics and posts in this category will be purged!', function(confirm) {
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
socket.emit('admin.categories.purge', cid, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('Category purged!');
|
||||
categoryRow.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('.admin-categories').on('click', '.permissions', function() {
|
||||
var cid = $(this).parents('li[data-cid]').attr('data-cid');
|
||||
Categories.launchPermissionsModal(cid);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
$('.admin-categories').on('click', '.upload-button', function() {
|
||||
var inputEl = $(this),
|
||||
cid = inputEl.parents('li[data-cid]').attr('data-cid');
|
||||
|
||||
uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) {
|
||||
inputEl.val(imageUrlOnServer);
|
||||
var previewBox = inputEl.parents('li[data-cid]').find('.preview-box');
|
||||
previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')')
|
||||
.css('background-size', 'cover');
|
||||
modified(inputEl[0]);
|
||||
});
|
||||
});
|
||||
|
||||
$('.admin-categories').on('click', '.delete-image', function() {
|
||||
var parent = $(this).parents('li[data-cid]'),
|
||||
inputEl = parent.find('.upload-button'),
|
||||
preview = parent.find('.preview-box'),
|
||||
bgColor = parent.find('.category_bgColor').val();
|
||||
|
||||
inputEl.val('');
|
||||
modified(inputEl[0]);
|
||||
|
||||
preview.css('background', bgColor);
|
||||
|
||||
$(this).addClass('hide').hide();
|
||||
});
|
||||
|
||||
$('#revertChanges').on('click', function() {
|
||||
ajaxify.refresh();
|
||||
});
|
||||
|
||||
setupEditTargets();
|
||||
|
||||
$('button[data-action="setParent"]').on('click', function() {
|
||||
var cid = $(this).parents('[data-cid]').attr('data-cid'),
|
||||
modal = $('#setParent');
|
||||
|
||||
modal.find('select').val($(this).attr('data-parentCid'));
|
||||
modal.attr('data-cid', cid).modal();
|
||||
});
|
||||
|
||||
$('button[data-action="removeParent"]').on('click', function() {
|
||||
var cid = $(this).parents('[data-cid]').attr('data-cid');
|
||||
var payload= {};
|
||||
payload[cid] = {
|
||||
parentCid: 0
|
||||
};
|
||||
socket.emit('admin.categories.update', payload, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
ajaxify.go('admin/manage/categories/active');
|
||||
});
|
||||
});
|
||||
|
||||
$('#setParent [data-cid]').on('click', function() {
|
||||
var modalEl = $('#setParent'),
|
||||
parentCid = $(this).attr('data-cid'),
|
||||
payload = {};
|
||||
|
||||
payload[modalEl.attr('data-cid')] = {
|
||||
parentCid: parentCid
|
||||
};
|
||||
|
||||
socket.emit('admin.categories.update', payload, function(err) {
|
||||
modalEl.one('hidden.bs.modal', function() {
|
||||
ajaxify.go('admin/manage/categories/active');
|
||||
});
|
||||
modalEl.modal('hide');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Categories.launchPermissionsModal = function(cid) {
|
||||
var modal = $('#category-permissions-modal'),
|
||||
searchEl = modal.find('#permission-search'),
|
||||
resultsEl = modal.find('.search-results.users'),
|
||||
groupsResultsEl = modal.find('.search-results.groups'),
|
||||
searchDelay;
|
||||
|
||||
// Clear the search field and results
|
||||
searchEl.val('');
|
||||
resultsEl.html('');
|
||||
|
||||
searchEl.off().on('keyup', function() {
|
||||
var searchEl = this,
|
||||
liEl;
|
||||
|
||||
clearTimeout(searchDelay);
|
||||
|
||||
searchDelay = setTimeout(function() {
|
||||
socket.emit('admin.categories.search', {
|
||||
username: searchEl.value,
|
||||
cid: cid
|
||||
}, function(err, results) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
templates.parse('admin/partials/categories/users', {
|
||||
users: results
|
||||
}, function(html) {
|
||||
resultsEl.html(html);
|
||||
});
|
||||
});
|
||||
}, 250);
|
||||
});
|
||||
|
||||
Categories.refreshPrivilegeList(cid);
|
||||
|
||||
resultsEl.off().on('click', '[data-priv]', function(e) {
|
||||
var anchorEl = $(this),
|
||||
uid = anchorEl.parents('li[data-uid]').attr('data-uid'),
|
||||
privilege = anchorEl.attr('data-priv');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
socket.emit('admin.categories.setPrivilege', {
|
||||
cid: cid,
|
||||
uid: uid,
|
||||
privilege: privilege,
|
||||
set: !anchorEl.hasClass('active')
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
anchorEl.toggleClass('active', !anchorEl.hasClass('active'));
|
||||
Categories.refreshPrivilegeList(cid);
|
||||
});
|
||||
});
|
||||
|
||||
modal.off().on('click', '.members li > img', function() {
|
||||
searchEl.val($(this).attr('title'));
|
||||
searchEl.keyup();
|
||||
});
|
||||
|
||||
// User Groups and privileges
|
||||
socket.emit('admin.categories.groupsList', cid, function(err, results) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
templates.parse('admin/partials/categories/groups', {
|
||||
groups: results
|
||||
}, function(html) {
|
||||
groupsResultsEl.html(html);
|
||||
});
|
||||
});
|
||||
|
||||
groupsResultsEl.off().on('click', '[data-priv]', function(e) {
|
||||
var anchorEl = $(this),
|
||||
name = anchorEl.parents('li[data-name]').attr('data-name'),
|
||||
privilege = anchorEl.attr('data-priv');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
socket.emit('admin.categories.setGroupPrivilege', {
|
||||
cid: cid,
|
||||
name: name,
|
||||
privilege: privilege,
|
||||
set: !anchorEl.hasClass('active')
|
||||
}, function(err) {
|
||||
if (!err) {
|
||||
anchorEl.toggleClass('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
modal.modal();
|
||||
};
|
||||
|
||||
Categories.refreshPrivilegeList = function (cid) {
|
||||
var modalEl = $('#category-permissions-modal'),
|
||||
memberList = $('.members');
|
||||
|
||||
socket.emit('admin.categories.getPrivilegeSettings', cid, function(err, privilegeList) {
|
||||
var membersLength = privilegeList.length,
|
||||
liEl, x, userObj;
|
||||
|
||||
memberList.html('');
|
||||
if (membersLength > 0) {
|
||||
for(x = 0; x < membersLength; x++) {
|
||||
userObj = privilegeList[x];
|
||||
liEl = $('<li/>').attr('data-uid', userObj.uid).html('<img src="' + userObj.picture + '" title="' + userObj.username + '" />');
|
||||
memberList.append(liEl);
|
||||
}
|
||||
} else {
|
||||
liEl = $('<li/>').addClass('empty').html('None.');
|
||||
memberList.append(liEl);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Categories;
|
||||
});
|
@ -1,68 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, socket, app, admin, utils, bootbox, RELATIVE_PATH*/
|
||||
|
||||
define('forum/admin/manage/flags', ['forum/infinitescroll', 'admin/selectable'], function(infinitescroll, selectable) {
|
||||
var Flags = {};
|
||||
|
||||
Flags.init = function() {
|
||||
handleDismiss();
|
||||
handleDelete();
|
||||
handleInfiniteScroll();
|
||||
};
|
||||
|
||||
function handleDismiss() {
|
||||
$('.flags').on('click', '.dismiss', function() {
|
||||
var btn = $(this);
|
||||
var pid = btn.siblings('[data-pid]').attr('data-pid');
|
||||
|
||||
socket.emit('admin.dismissFlag', pid, function(err) {
|
||||
done(err, btn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete() {
|
||||
$('.flags').on('click', '.delete', function() {
|
||||
var btn = $(this);
|
||||
var pid = btn.siblings('[data-pid]').attr('data-pid');
|
||||
var tid = btn.siblings('[data-pid]').attr('data-tid');
|
||||
socket.emit('posts.delete', {pid: pid, tid: tid}, function(err) {
|
||||
done(err, btn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function done(err, btn) {
|
||||
if (err) {
|
||||
return app.alertError(err.messaage);
|
||||
}
|
||||
btn.parent().fadeOut(function() {
|
||||
btn.remove();
|
||||
});
|
||||
if (!$('.flags [data-pid]').length) {
|
||||
$('.post-container').text('No flagged posts!');
|
||||
}
|
||||
}
|
||||
|
||||
function handleInfiniteScroll() {
|
||||
infinitescroll.init(function(direction) {
|
||||
if (direction < 0 && !$('.flags').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('admin.getMoreFlags', $('[data-next]').attr('data-next'), function(data, done) {
|
||||
if (data.posts && data.posts.length) {
|
||||
infinitescroll.parseAndTranslate('admin/manage/flags', 'posts', {posts: data.posts}, function(html) {
|
||||
$('[data-next]').attr('data-next', data.next);
|
||||
$('.post-container').append(html);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return Flags;
|
||||
});
|
@ -1,263 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, templates, socket, ajaxify, app, bootbox*/
|
||||
|
||||
define('forum/admin/manage/groups', ['forum/admin/iconSelect'], function(iconSelect) {
|
||||
var Groups = {};
|
||||
|
||||
Groups.init = function() {
|
||||
var yourid = ajaxify.variables.get('yourid'),
|
||||
createModal = $('#create-modal'),
|
||||
createGroupName = $('#create-group-name'),
|
||||
create = $('#create'),
|
||||
createModalGo = $('#create-modal-go'),
|
||||
createGroupDesc = $('#create-group-desc'),
|
||||
createModalError = $('#create-modal-error'),
|
||||
groupDetailsModal = $('#group-details-modal'),
|
||||
groupDetailsSearch = $('#group-details-search'),
|
||||
groupDetailsSearchResults = $('#group-details-search-results'),
|
||||
groupMembersEl = $('ul.current_members'),
|
||||
formEl = groupDetailsModal.find('form'),
|
||||
detailsModalSave = $('#details-modal-save'),
|
||||
groupsList = $('#groups-list'),
|
||||
groupIcon = $('#group-icon'),
|
||||
changeGroupIcon = $('#change-group-icon'),
|
||||
changeGroupName = $('#change-group-name'),
|
||||
changeGroupDesc = $('#change-group-desc'),
|
||||
changeGroupUserTitle = $('#change-group-user-title'),
|
||||
changeGroupLabelColor = $('#change-group-label-color'),
|
||||
groupIcon = $('#group-icon'),
|
||||
groupLabelPreview = $('#group-label-preview'),
|
||||
searchDelay;
|
||||
|
||||
// Tooltips
|
||||
$('#groups-list .members li').tooltip();
|
||||
|
||||
createModal.on('keypress', function(e) {
|
||||
switch(e.keyCode) {
|
||||
case 13:
|
||||
createModalGo.click();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
create.on('click', function() {
|
||||
createModal.modal('show');
|
||||
setTimeout(function() {
|
||||
createGroupName.focus();
|
||||
}, 250);
|
||||
});
|
||||
|
||||
createModalGo.on('click', function() {
|
||||
var submitObj = {
|
||||
name: createGroupName.val(),
|
||||
description: createGroupDesc.val()
|
||||
},
|
||||
errorText;
|
||||
|
||||
socket.emit('admin.groups.create', submitObj, function(err, data) {
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case 'group-exists':
|
||||
errorText = '<strong>Please choose another name</strong><p>There seems to be a group with this name already.</p>';
|
||||
break;
|
||||
case 'name-too-short':
|
||||
errorText = '<strong>Please specify a group name</strong><p>A group name is required for administrative purposes.</p>';
|
||||
break;
|
||||
default:
|
||||
errorText = '<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>';
|
||||
break;
|
||||
}
|
||||
|
||||
createModalError.html(errorText).removeClass('hide');
|
||||
} else {
|
||||
createModalError.addClass('hide');
|
||||
createGroupName.val('');
|
||||
createModal.on('hidden.bs.modal', function() {
|
||||
ajaxify.go('admin/groups');
|
||||
});
|
||||
createModal.modal('hide');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
formEl.keypress(function(e) {
|
||||
switch(e.keyCode) {
|
||||
case 13:
|
||||
detailsModalSave.click();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
changeGroupUserTitle.keydown(function() {
|
||||
setTimeout(function() {
|
||||
groupLabelPreview.text(changeGroupUserTitle.val());
|
||||
}, 0);
|
||||
});
|
||||
|
||||
changeGroupLabelColor.keydown(function() {
|
||||
setTimeout(function() {
|
||||
groupLabelPreview.css('background', changeGroupLabelColor.val() || '#000000');
|
||||
}, 0);
|
||||
});
|
||||
|
||||
groupsList.on('click', 'button[data-action]', function() {
|
||||
var el = $(this),
|
||||
action = el.attr('data-action'),
|
||||
groupName = el.parents('li[data-groupname]').attr('data-groupname');
|
||||
|
||||
switch (action) {
|
||||
case 'delete':
|
||||
bootbox.confirm('Are you sure you wish to delete this group?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.groups.delete', groupName, function(err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
ajaxify.go('admin/groups');
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'members':
|
||||
socket.emit('admin.groups.get', groupName, function(err, groupObj) {
|
||||
|
||||
changeGroupName.val(groupObj.name).prop('readonly', groupObj.system);
|
||||
changeGroupDesc.val(groupObj.description);
|
||||
changeGroupUserTitle.val(groupObj.userTitle);
|
||||
groupIcon.attr('class', 'fa fa-2x ' + groupObj.icon).attr('value', groupObj.icon);
|
||||
changeGroupLabelColor.val(groupObj.labelColor);
|
||||
groupLabelPreview.css('background', groupObj.labelColor || '#000000').text(groupObj.userTitle);
|
||||
groupMembersEl.empty();
|
||||
|
||||
if (groupObj.members.length > 0) {
|
||||
for (var x = 0; x < groupObj.members.length; x++) {
|
||||
var memberIcon = $('<li />')
|
||||
.attr('data-uid', groupObj.members[x].uid)
|
||||
.append($('<img />').attr('src', groupObj.members[x].picture))
|
||||
.append($('<span />').html(groupObj.members[x].username));
|
||||
groupMembersEl.append(memberIcon);
|
||||
}
|
||||
}
|
||||
|
||||
groupDetailsModal.attr('data-groupname', groupObj.name);
|
||||
groupDetailsModal.modal('show');
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
groupDetailsSearch.on('keyup', function() {
|
||||
|
||||
if (searchDelay) {
|
||||
clearTimeout(searchDelay);
|
||||
}
|
||||
|
||||
searchDelay = setTimeout(function() {
|
||||
var searchText = groupDetailsSearch.val(),
|
||||
foundUser;
|
||||
|
||||
socket.emit('admin.user.search', searchText, function(err, results) {
|
||||
if (!err && results && results.users.length > 0) {
|
||||
var numResults = results.users.length, x;
|
||||
if (numResults > 4) {
|
||||
numResults = 4;
|
||||
}
|
||||
|
||||
groupDetailsSearchResults.empty();
|
||||
for (x = 0; x < numResults; x++) {
|
||||
foundUser = $('<li />');
|
||||
foundUser
|
||||
.attr({title: results.users[x].username, 'data-uid': results.users[x].uid})
|
||||
.append($('<img />').attr('src', results.users[x].picture))
|
||||
.append($('<span />').html(results.users[x].username));
|
||||
|
||||
groupDetailsSearchResults.append(foundUser);
|
||||
}
|
||||
} else {
|
||||
groupDetailsSearchResults.html('<li>No Users Found</li>');
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
|
||||
groupDetailsSearchResults.on('click', 'li[data-uid]', function() {
|
||||
var userLabel = $(this),
|
||||
uid = parseInt(userLabel.attr('data-uid'), 10),
|
||||
groupName = groupDetailsModal.attr('data-groupname'),
|
||||
members = [];
|
||||
|
||||
groupMembersEl.find('li[data-uid]').each(function() {
|
||||
members.push(parseInt($(this).attr('data-uid'), 10));
|
||||
});
|
||||
|
||||
if (members.indexOf(uid) === -1) {
|
||||
socket.emit('admin.groups.join', {
|
||||
groupName: groupName,
|
||||
uid: uid
|
||||
}, function(err, data) {
|
||||
if (!err) {
|
||||
groupMembersEl.append(userLabel.clone(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
groupMembersEl.on('click', 'li[data-uid]', function() {
|
||||
var uid = $(this).attr('data-uid'),
|
||||
groupName = groupDetailsModal.attr('data-groupname');
|
||||
|
||||
socket.emit('admin.groups.get', groupName, function(err, groupObj){
|
||||
if (!err){
|
||||
bootbox.confirm('Are you sure you want to remove this user?', function(confirm) {
|
||||
if (confirm){
|
||||
socket.emit('admin.groups.leave', {
|
||||
groupName: groupName,
|
||||
uid: uid
|
||||
}, function(err, data) {
|
||||
if (!err) {
|
||||
groupMembersEl.find('li[data-uid="' + uid + '"]').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
changeGroupIcon.on('click', function() {
|
||||
iconSelect.init(groupIcon);
|
||||
});
|
||||
|
||||
admin.enableColorPicker(changeGroupLabelColor, function(hsb, hex) {
|
||||
groupLabelPreview.css('background-color', '#' + hex);
|
||||
});
|
||||
|
||||
detailsModalSave.on('click', function() {
|
||||
socket.emit('admin.groups.update', {
|
||||
groupName: groupDetailsModal.attr('data-groupname'),
|
||||
values: {
|
||||
name: changeGroupName.val(),
|
||||
userTitle: changeGroupUserTitle.val(),
|
||||
description: changeGroupDesc.val(),
|
||||
icon: groupIcon.attr('value'),
|
||||
labelColor: changeGroupLabelColor.val()
|
||||
}
|
||||
}, function(err) {
|
||||
if (!err) {
|
||||
groupDetailsModal.on('hidden.bs.modal', function() {
|
||||
ajaxify.go('admin/groups');
|
||||
});
|
||||
groupDetailsModal.modal('hide');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return Groups;
|
||||
});
|
@ -1,110 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, socket, app, admin, utils, bootbox, RELATIVE_PATH*/
|
||||
|
||||
define('forum/admin/manage/tags', ['forum/infinitescroll', 'admin/selectable'], function(infinitescroll, selectable) {
|
||||
var Tags = {},
|
||||
timeoutId = 0;
|
||||
|
||||
Tags.init = function() {
|
||||
handleColorPickers();
|
||||
selectable.enable('.tag-management', '.tag-row');
|
||||
|
||||
$('#tag-search').on('input propertychange', function() {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(function() {
|
||||
socket.emit('topics.searchAndLoadTags', {query: $('#tag-search').val()}, function(err, tags) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
infinitescroll.parseAndTranslate('admin/manage/tags', 'tags', {tags: tags}, function(html) {
|
||||
$('.tag-list').html(html);
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
timeoutId = 0;
|
||||
|
||||
selectable.enable('.tag-management', '.tag-row');
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
|
||||
$('#modify').on('click', function(ev) {
|
||||
var tagsToModify = $('.tag-row.selected');
|
||||
if (!tagsToModify.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var firstTag = $(tagsToModify[0]),
|
||||
title = tagsToModify.length > 1 ? 'Editing multiple tags' : 'Editing ' + firstTag.find('.tag-item').text() + ' tag';
|
||||
|
||||
bootbox.dialog({
|
||||
title: title,
|
||||
message: firstTag.find('.tag-modal').html(),
|
||||
buttons: {
|
||||
success: {
|
||||
label: "Save",
|
||||
className: "btn-primary save",
|
||||
callback: function() {
|
||||
var modal = $('.bootbox'),
|
||||
bgColor = modal.find('[data-name="bgColor"]').val(),
|
||||
color = modal.find('[data-name="color"]').val();
|
||||
|
||||
tagsToModify.each(function(idx, tag) {
|
||||
tag = $(tag);
|
||||
|
||||
tag.find('[data-name="bgColor"]').val(bgColor);
|
||||
tag.find('[data-name="color"]').val(color);
|
||||
tag.find('.tag-item').css('background-color', bgColor).css('color', color);
|
||||
|
||||
save(tag);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
handleColorPickers();
|
||||
}, 500); // bootbox made me do it.
|
||||
});
|
||||
};
|
||||
|
||||
function handleColorPickers() {
|
||||
function enableColorPicker(idx, inputEl) {
|
||||
var $inputEl = $(inputEl),
|
||||
previewEl = $inputEl.parents('.tag-row').find('.tag-item');
|
||||
|
||||
admin.enableColorPicker($inputEl, function(hsb, hex) {
|
||||
if ($inputEl.attr('data-name') === 'bgColor') {
|
||||
previewEl.css('background-color', '#' + hex);
|
||||
} else if ($inputEl.attr('data-name') === 'color') {
|
||||
previewEl.css('color', '#' + hex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker);
|
||||
}
|
||||
|
||||
function save(tag) {
|
||||
var data = {
|
||||
tag: tag.attr('data-tag'),
|
||||
bgColor : tag.find('[data-name="bgColor"]').val(),
|
||||
color : tag.find('[data-name="color"]').val()
|
||||
};
|
||||
|
||||
socket.emit('admin.tags.update', data, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('Tag Updated!');
|
||||
});
|
||||
}
|
||||
|
||||
return Tags;
|
||||
});
|
@ -1,289 +0,0 @@
|
||||
"use strict";
|
||||
/* global socket, define, templates, bootbox, app, ajaxify, */
|
||||
define('forum/admin/manage/users', ['admin/selectable'], function(selectable) {
|
||||
var Users = {};
|
||||
|
||||
Users.init = function() {
|
||||
var yourid = ajaxify.variables.get('yourid');
|
||||
|
||||
selectable.enable('#users-container', '.user-selectable');
|
||||
|
||||
function getSelectedUids() {
|
||||
var uids = [];
|
||||
$('#users-container .users-box .selected').each(function() {
|
||||
uids.push($(this).parents('[data-uid]').attr('data-uid'));
|
||||
});
|
||||
|
||||
return uids;
|
||||
}
|
||||
|
||||
function update(className, state) {
|
||||
$('#users-container .users-box .selected').siblings('.labels').find(className).each(function() {
|
||||
$(this).toggleClass('hide', !state);
|
||||
});
|
||||
}
|
||||
|
||||
function unselectAll() {
|
||||
$('#users-container .users-box .selected').removeClass('selected');
|
||||
}
|
||||
|
||||
function removeSelected() {
|
||||
$('#users-container .users-box .selected').remove();
|
||||
}
|
||||
|
||||
function done(successMessage, className, flag) {
|
||||
return function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess(successMessage);
|
||||
if (className) {
|
||||
update(className, flag);
|
||||
}
|
||||
unselectAll();
|
||||
};
|
||||
}
|
||||
|
||||
$('.ban-user').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bootbox.confirm('Do you really want to ban?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.user.banUsers', uids, done('User(s) banned!', '.ban', true));
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.unban-user').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('admin.user.unbanUsers', uids, done('User(s) unbanned!', '.ban', false));
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.reset-lockout').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('admin.user.resetLockouts', uids, done('Lockout(s) reset!'));
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.admin-user').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uids.indexOf(yourid) !== -1) {
|
||||
app.alertError('You can\'t remove yourself as Administrator!');
|
||||
} else {
|
||||
socket.emit('admin.user.makeAdmins', uids, done('User(s) are now administrators.', '.administrator', true));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.remove-admin-user').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uids.indexOf(yourid.toString()) !== -1) {
|
||||
app.alertError('You can\'t remove yourself as Administrator!');
|
||||
} else {
|
||||
bootbox.confirm('Do you really want to remove admins?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.user.removeAdmins', uids, done('User(s) are no longer administrators.', '.administrator', false));
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.validate-email').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
bootbox.confirm('Do you want to validate email(s) of these user(s)?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.user.validateEmail', uids, done('Emails validated', '.notvalidated', false));
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.delete-user').on('click', function() {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
bootbox.confirm('<b>Warning!</b><br/>Do you really want to delete user(s)?<br/> This action is not reversable, all user data and content will be erased!', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.user.deleteUsers', uids, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('User(s) Deleted!');
|
||||
removeSelected();
|
||||
unselectAll();
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
function handleUserCreate() {
|
||||
var errorEl = $('#create-modal-error');
|
||||
$('#createUser').on('click', function() {
|
||||
$('#create-modal').modal('show');
|
||||
$('#create-modal form')[0].reset();
|
||||
errorEl.addClass('hide');
|
||||
});
|
||||
|
||||
$('#create-modal-go').on('click', function() {
|
||||
var username = $('#create-user-name').val(),
|
||||
email = $('#create-user-email').val(),
|
||||
password = $('#create-user-password').val(),
|
||||
passwordAgain = $('#create-user-password-again').val();
|
||||
|
||||
|
||||
if(password !== passwordAgain) {
|
||||
return errorEl.html('<strong>Error</strong><p>Passwords must match!</p>').removeClass('hide');
|
||||
}
|
||||
|
||||
var user = {
|
||||
username: username,
|
||||
email: email,
|
||||
password: password
|
||||
};
|
||||
|
||||
socket.emit('admin.user.createUser', user, function(err) {
|
||||
if(err) {
|
||||
return errorEl.html('<strong>Error</strong><p>' + err.message + '</p>').removeClass('hide');
|
||||
}
|
||||
$('#create-modal').modal('hide');
|
||||
$('#create-modal').on('hidden.bs.modal', function() {
|
||||
ajaxify.go('admin/users');
|
||||
});
|
||||
app.alertSuccess('User created!');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var timeoutId = 0,
|
||||
loadingMoreUsers = false;
|
||||
|
||||
var url = window.location.href,
|
||||
parts = url.split('/'),
|
||||
active = parts[parts.length - 1];
|
||||
|
||||
$('.nav-pills li').removeClass('active');
|
||||
$('.nav-pills li a').each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.attr('href').match(active)) {
|
||||
$this.parent().addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#search-user').on('keyup', function() {
|
||||
if (timeoutId !== 0) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(function() {
|
||||
var username = $('#search-user').val();
|
||||
|
||||
$('.fa-spinner').removeClass('hidden');
|
||||
|
||||
socket.emit('admin.user.search', username, function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
templates.parse('admin/manage/users', 'users', data, function(html) {
|
||||
$('#users-container').html(html);
|
||||
|
||||
$('.fa-spinner').addClass('hidden');
|
||||
|
||||
if (data && data.users.length === 0) {
|
||||
$('#user-notfound-notify').html('User not found!')
|
||||
.show()
|
||||
.addClass('label-danger')
|
||||
.removeClass('label-success');
|
||||
} else {
|
||||
$('#user-notfound-notify').html(data.users.length + ' user' + (data.users.length > 1 ? 's' : '') + ' found! Search took ' + data.timing + ' ms.')
|
||||
.show()
|
||||
.addClass('label-success')
|
||||
.removeClass('label-danger');
|
||||
}
|
||||
|
||||
selectable.enable('#users-container', '.user-selectable');
|
||||
});
|
||||
});
|
||||
}, 250);
|
||||
});
|
||||
|
||||
handleUserCreate();
|
||||
|
||||
function onUsersLoaded(users) {
|
||||
templates.parse('admin/manage/users', 'users', {users: users}, function(html) {
|
||||
$('#users-container').append($(html));
|
||||
});
|
||||
}
|
||||
|
||||
function loadMoreUsers() {
|
||||
var set = '';
|
||||
if (active === 'latest') {
|
||||
set = 'users:joindate';
|
||||
} else if (active === 'sort-posts') {
|
||||
set = 'users:postcount';
|
||||
} else if (active === 'sort-reputation') {
|
||||
set = 'users:reputation';
|
||||
}
|
||||
|
||||
if (set) {
|
||||
loadingMoreUsers = true;
|
||||
socket.emit('user.loadMore', {
|
||||
set: set,
|
||||
after: $('#users-container').children().length
|
||||
}, function(err, data) {
|
||||
if (data && data.users.length) {
|
||||
onUsersLoaded(data.users);
|
||||
}
|
||||
loadingMoreUsers = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('#load-more-users-btn').on('click', loadMoreUsers);
|
||||
|
||||
$(window).off('scroll').on('scroll', function() {
|
||||
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||
|
||||
if ($(window).scrollTop() > bottom && !loadingMoreUsers) {
|
||||
loadMoreUsers();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
return Users;
|
||||
});
|
@ -1,169 +0,0 @@
|
||||
"use strict";
|
||||
/*global define, app, socket, ajaxify, RELATIVE_PATH */
|
||||
|
||||
define('forum/admin/settings', ['uploader', 'sounds'], function(uploader, sounds) {
|
||||
var Settings = {};
|
||||
|
||||
Settings.init = function() {
|
||||
Settings.prepare();
|
||||
};
|
||||
|
||||
Settings.prepare = function(callback) {
|
||||
// Come back in 125ms if the config isn't ready yet
|
||||
if (!app.config) {
|
||||
setTimeout(function() {
|
||||
Settings.prepare(callback);
|
||||
}, 125);
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate the fields on the page from the config
|
||||
var fields = $('#content [data-field]'),
|
||||
numFields = fields.length,
|
||||
saveBtn = $('#save'),
|
||||
revertBtn = $('#revert'),
|
||||
x, key, inputType, field;
|
||||
|
||||
for (x = 0; x < numFields; x++) {
|
||||
field = fields.eq(x);
|
||||
key = field.attr('data-field');
|
||||
inputType = field.attr('type');
|
||||
if (field.is('input')) {
|
||||
if (app.config[key]) {
|
||||
switch (inputType) {
|
||||
case 'text':
|
||||
case 'hidden':
|
||||
case 'password':
|
||||
case 'textarea':
|
||||
case 'number':
|
||||
field.val(app.config[key]);
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
field.prop('checked', parseInt(app.config[key], 10) === 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (field.is('textarea')) {
|
||||
if (app.config[key]) {
|
||||
field.val(app.config[key]);
|
||||
}
|
||||
} else if (field.is('select')) {
|
||||
if (app.config[key]) {
|
||||
field.val(app.config[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
revertBtn.off('click').on('click', function(e) {
|
||||
ajaxify.refresh();
|
||||
});
|
||||
|
||||
saveBtn.off('click').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
saveFields(fields, function onFieldsSaved(err) {
|
||||
if (err) {
|
||||
return app.alert({
|
||||
alert_id: 'config_status',
|
||||
timeout: 2500,
|
||||
title: 'Changes Not Saved',
|
||||
message: 'NodeBB encountered a problem saving your changes',
|
||||
type: 'danger'
|
||||
});
|
||||
}
|
||||
app.alert({
|
||||
alert_id: 'config_status',
|
||||
timeout: 2500,
|
||||
title: 'Changes Saved',
|
||||
message: 'Your changes to the NodeBB configuration have been saved.',
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
handleUploads();
|
||||
|
||||
$('button[data-action="email.test"]').off('click').on('click', function() {
|
||||
socket.emit('admin.email.test', function(err) {
|
||||
app.alert({
|
||||
alert_id: 'test_email_sent',
|
||||
type: !err ? 'info' : 'danger',
|
||||
title: 'Test Email Sent',
|
||||
message: err ? err.message : '',
|
||||
timeout: 2500
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
function handleUploads() {
|
||||
$('#content input[data-action="upload"]').each(function() {
|
||||
var uploadBtn = $(this);
|
||||
uploadBtn.on('click', function() {
|
||||
uploader.open(uploadBtn.attr('data-route'), {}, 0, function(image) {
|
||||
$('#' + uploadBtn.attr('data-target')).val(image);
|
||||
});
|
||||
|
||||
uploader.hideAlerts();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Settings.remove = function(key) {
|
||||
socket.emit('admin.config.remove', key);
|
||||
};
|
||||
|
||||
function saveFields(fields, callback) {
|
||||
var data = {};
|
||||
|
||||
fields.each(function() {
|
||||
var field = $(this);
|
||||
var key = field.attr('data-field'),
|
||||
value, inputType;
|
||||
|
||||
if (field.is('input')) {
|
||||
inputType = field.attr('type');
|
||||
switch (inputType) {
|
||||
case 'text':
|
||||
case 'password':
|
||||
case 'hidden':
|
||||
case 'textarea':
|
||||
case 'number':
|
||||
value = field.val();
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
value = field.prop('checked') ? '1' : '0';
|
||||
break;
|
||||
}
|
||||
} else if (field.is('textarea') || field.is('select')) {
|
||||
value = field.val();
|
||||
}
|
||||
|
||||
data[key] = value;
|
||||
});
|
||||
|
||||
socket.emit('admin.config.setMultiple', data, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (app.config) {
|
||||
for(var field in data) {
|
||||
if (data.hasOwnProperty(field)) {
|
||||
app.config[field] = data[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return Settings;
|
||||
});
|
@ -1,351 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, config, templates, app, utils, ajaxify, socket, translator */
|
||||
|
||||
define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll', 'share', 'navigator', 'forum/categoryTools'], function(composer, pagination, infinitescroll, share, navigator, categoryTools) {
|
||||
var Category = {};
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
if(data && data.url.indexOf('category') !== 0) {
|
||||
navigator.hide();
|
||||
|
||||
removeListeners();
|
||||
}
|
||||
});
|
||||
|
||||
function removeListeners() {
|
||||
socket.removeListener('event:new_topic', Category.onNewTopic);
|
||||
categoryTools.removeListeners();
|
||||
}
|
||||
|
||||
Category.init = function() {
|
||||
var cid = ajaxify.variables.get('category_id');
|
||||
|
||||
app.enterRoom('category_' + cid);
|
||||
|
||||
share.addShareHandlers(ajaxify.variables.get('category_name'));
|
||||
|
||||
$('#new_post').on('click', function () {
|
||||
composer.newTopic(cid);
|
||||
});
|
||||
|
||||
socket.on('event:new_topic', Category.onNewTopic);
|
||||
|
||||
categoryTools.init(cid);
|
||||
|
||||
enableInfiniteLoadingOrPagination();
|
||||
|
||||
if (!config.usePagination) {
|
||||
navigator.init('#topics-container > .category-item', ajaxify.variables.get('topic_count'), Category.toTop, Category.toBottom, Category.navigatorCallback);
|
||||
}
|
||||
|
||||
$('#topics-container').on('click', '.topic-title', function() {
|
||||
var clickedTid = $(this).parents('li.category-item[data-tid]').attr('data-tid');
|
||||
$('#topics-container li.category-item').each(function(index, el) {
|
||||
if($(el).offset().top - $(window).scrollTop() > 0) {
|
||||
localStorage.setItem('category:' + cid + ':bookmark', $(el).attr('data-tid'));
|
||||
localStorage.setItem('category:' + cid + ':bookmark:clicked', clickedTid);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
handleIgnoreWatch(cid);
|
||||
};
|
||||
|
||||
function handleIgnoreWatch(cid) {
|
||||
$('.watch, .ignore').on('click', function() {
|
||||
var $this = $(this);
|
||||
var command = $this.hasClass('watch') ? 'watch' : 'ignore';
|
||||
|
||||
socket.emit('categories.' + command, cid, function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
$('.watch').toggleClass('hidden', command === 'watch');
|
||||
$('.ignore').toggleClass('hidden', command === 'ignore');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Category.toTop = function() {
|
||||
navigator.scrollTop(0);
|
||||
};
|
||||
|
||||
Category.toBottom = function() {
|
||||
socket.emit('categories.lastTopicIndex', ajaxify.variables.get('category_id'), function(err, index) {
|
||||
navigator.scrollBottom(index);
|
||||
});
|
||||
};
|
||||
|
||||
Category.navigatorCallback = function(element, elementCount) {
|
||||
return parseInt(element.attr('data-index'), 10) + 1;
|
||||
};
|
||||
|
||||
$(window).on('action:popstate', function(ev, data) {
|
||||
if(data.url.indexOf('category/') === 0) {
|
||||
var cid = data.url.match(/^category\/(\d+)/);
|
||||
if (cid && cid[1]) {
|
||||
cid = cid[1];
|
||||
}
|
||||
if (!cid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bookmark = localStorage.getItem('category:' + cid + ':bookmark');
|
||||
var clicked = localStorage.getItem('category:' + cid + ':bookmark:clicked');
|
||||
|
||||
if (!bookmark) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(config.usePagination) {
|
||||
socket.emit('topics.getTidPage', bookmark, function(err, page) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
if(parseInt(page, 10) !== pagination.currentPage) {
|
||||
pagination.loadPage(page);
|
||||
} else {
|
||||
Category.scrollToTopic(bookmark, clicked, 400);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
socket.emit('topics.getTidIndex', bookmark, function(err, index) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
Category.highlightTopic(clicked);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
$('#topics-container').empty();
|
||||
|
||||
loadTopicsAfter(index, function() {
|
||||
Category.scrollToTopic(bookmark, clicked, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Category.highlightTopic = function(tid) {
|
||||
var highlight = $('#topics-container li.category-item[data-tid="' + tid + '"]');
|
||||
if(highlight.length && !highlight.hasClass('highlight')) {
|
||||
highlight.addClass('highlight');
|
||||
setTimeout(function() {
|
||||
highlight.removeClass('highlight');
|
||||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
Category.scrollToTopic = function(tid, clickedTid, duration, offset) {
|
||||
if(!tid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!offset) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if($('#topics-container li.category-item[data-tid="' + tid + '"]').length) {
|
||||
var cid = ajaxify.variables.get('category_id');
|
||||
var scrollTo = $('#topics-container li.category-item[data-tid="' + tid + '"]');
|
||||
|
||||
if (cid && scrollTo.length) {
|
||||
$('html, body').animate({
|
||||
scrollTop: (scrollTo.offset().top - $('#header-menu').height() - offset) + 'px'
|
||||
}, duration !== undefined ? duration : 400, function() {
|
||||
Category.highlightTopic(clickedTid);
|
||||
navigator.update();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function enableInfiniteLoadingOrPagination() {
|
||||
if (!config.usePagination) {
|
||||
infinitescroll.init(Category.loadMoreTopics);
|
||||
} else {
|
||||
navigator.hide();
|
||||
pagination.init(ajaxify.variables.get('currentPage'), ajaxify.variables.get('pageCount'));
|
||||
}
|
||||
}
|
||||
|
||||
Category.onNewTopic = function(topic) {
|
||||
$(window).trigger('filter:categories.new_topic', topic);
|
||||
|
||||
ajaxify.loadTemplate('category', function(categoryTemplate) {
|
||||
var html = templates.parse(templates.getBlock(categoryTemplate, 'topics'), {
|
||||
privileges: {editable: !!$('.thread-tools').length},
|
||||
topics: [topic]
|
||||
});
|
||||
|
||||
translator.translate(html, function(translatedHTML) {
|
||||
var topic = $(translatedHTML),
|
||||
container = $('#topics-container'),
|
||||
topics = $('#topics-container').children('.category-item'),
|
||||
numTopics = topics.length;
|
||||
|
||||
$('#topics-container, .category-sidebar').removeClass('hidden');
|
||||
|
||||
var noTopicsWarning = $('#category-no-topics');
|
||||
if (noTopicsWarning.length) {
|
||||
noTopicsWarning.remove();
|
||||
ajaxify.widgets.render('category', window.location.pathname.slice(1));
|
||||
}
|
||||
|
||||
if (numTopics > 0) {
|
||||
for (var x = 0; x < numTopics; x++) {
|
||||
var pinned = $(topics[x]).hasClass('pinned');
|
||||
if (pinned) {
|
||||
if(x === numTopics - 1) {
|
||||
topic.insertAfter(topics[x]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
topic.insertBefore(topics[x]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
container.append(topic);
|
||||
}
|
||||
|
||||
topic.hide().fadeIn('slow');
|
||||
|
||||
socket.emit('categories.getPageCount', ajaxify.variables.get('category_id'), function(err, newPageCount) {
|
||||
pagination.recreatePaginationLinks(newPageCount);
|
||||
});
|
||||
|
||||
topic.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
updateTopicCount();
|
||||
|
||||
$(window).trigger('action:categories.new_topic.loaded');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function updateTopicCount() {
|
||||
socket.emit('categories.getTopicCount', ajaxify.variables.get('category_id'), function(err, topicCount) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
navigator.setCount(topicCount);
|
||||
});
|
||||
}
|
||||
|
||||
Category.onTopicsLoaded = function(data, callback) {
|
||||
if(!data || !data.topics.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
function removeAlreadyAddedTopics(topics) {
|
||||
return topics.filter(function(topic) {
|
||||
return $('#topics-container li[data-tid="' + topic.tid +'"]').length === 0;
|
||||
});
|
||||
}
|
||||
|
||||
var after = null,
|
||||
before = null;
|
||||
|
||||
function findInsertionPoint() {
|
||||
if (!$('#topics-container .category-item[data-tid]').length) {
|
||||
return;
|
||||
}
|
||||
var last = $('#topics-container .category-item[data-tid]').last();
|
||||
var lastIndex = last.attr('data-index');
|
||||
var firstIndex = data.topics[data.topics.length - 1].index;
|
||||
if (firstIndex > lastIndex) {
|
||||
after = last;
|
||||
} else {
|
||||
before = $('#topics-container .category-item[data-tid]').first();
|
||||
}
|
||||
}
|
||||
|
||||
data.topics = removeAlreadyAddedTopics(data.topics);
|
||||
if(!data.topics.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
findInsertionPoint();
|
||||
|
||||
ajaxify.loadTemplate('category', function(categoryTemplate) {
|
||||
var html = templates.parse(templates.getBlock(categoryTemplate, 'topics'), data);
|
||||
|
||||
translator.translate(html, function(translatedHTML) {
|
||||
var container = $('#topics-container'),
|
||||
html = $(translatedHTML);
|
||||
|
||||
$('#topics-container, .category-sidebar').removeClass('hidden');
|
||||
$('#category-no-topics').remove();
|
||||
|
||||
if(config.usePagination) {
|
||||
container.empty().append(html);
|
||||
} else {
|
||||
if(after) {
|
||||
html.insertAfter(after);
|
||||
} else if(before) {
|
||||
html.insertBefore(before);
|
||||
} else {
|
||||
container.append(html);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
html.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Category.loadMoreTopics = function(direction) {
|
||||
if (!$('#topics-container').length || !$('#topics-container').children().length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.calculateAfter(direction, '#topics-container .category-item[data-tid]', config.topicsPerPage, false, function(after, offset, el) {
|
||||
loadTopicsAfter(after, function() {
|
||||
if (direction < 0 && el) {
|
||||
Category.scrollToTopic(el.attr('data-tid'), null, 0, offset);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function loadTopicsAfter(after, callback) {
|
||||
if(!utils.isNumber(after) || (after === 0 && $('#topics-container li.category-item[data-index="0"]').length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(window).trigger('action:categories.loading');
|
||||
infinitescroll.loadMore('categories.loadMore', {
|
||||
cid: ajaxify.variables.get('category_id'),
|
||||
after: after
|
||||
}, function (data, done) {
|
||||
|
||||
if (data.topics && data.topics.length) {
|
||||
Category.onTopicsLoaded(data, function() {
|
||||
done();
|
||||
callback();
|
||||
});
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
|
||||
$(window).trigger('action:categories.loaded');
|
||||
});
|
||||
}
|
||||
|
||||
return Category;
|
||||
});
|
@ -1,205 +0,0 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, translator, socket, bootbox, ajaxify */
|
||||
|
||||
|
||||
define('forum/categoryTools', ['forum/topic/move', 'topicSelect'], function(move, topicSelect) {
|
||||
|
||||
var CategoryTools = {};
|
||||
|
||||
CategoryTools.init = function(cid) {
|
||||
CategoryTools.cid = cid;
|
||||
|
||||
topicSelect.init(onTopicSelect);
|
||||
|
||||
$('.delete_thread').on('click', function(e) {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
categoryCommand(isAny(isTopicDeleted, tids) ? 'restore' : 'delete', tids);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.purge_thread').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
categoryCommand('purge', tids);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.lock_thread').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
if (tids.length) {
|
||||
socket.emit(isAny(isTopicLocked, tids) ? 'topics.unlock' : 'topics.lock', {tids: tids, cid: CategoryTools.cid}, onCommandComplete);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.pin_thread').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
if (tids.length) {
|
||||
socket.emit(isAny(isTopicPinned, tids) ? 'topics.unpin' : 'topics.pin', {tids: tids, cid: CategoryTools.cid}, onCommandComplete);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.markAsUnreadForAll').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
if (tids.length) {
|
||||
socket.emit('topics.markAsUnreadForAll', tids, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('[[topic:markAsUnreadForAll.success]]');
|
||||
|
||||
onCommandComplete();
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.move_thread').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
|
||||
if (tids.length) {
|
||||
move.init(tids, cid, onCommandComplete);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.move_all_threads').on('click', function() {
|
||||
move.init(null, cid, function(err) {
|
||||
ajaxify.refresh();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
socket.on('event:topic_deleted', setDeleteState);
|
||||
socket.on('event:topic_restored', setDeleteState);
|
||||
socket.on('event:topic_purged', onTopicPurged);
|
||||
socket.on('event:topic_locked', setLockedState);
|
||||
socket.on('event:topic_unlocked', setLockedState);
|
||||
socket.on('event:topic_pinned', setPinnedState);
|
||||
socket.on('event:topic_unpinned', setPinnedState);
|
||||
socket.on('event:topic_moved', onTopicMoved);
|
||||
};
|
||||
|
||||
function categoryCommand(command, tids) {
|
||||
if (!tids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function(msg) {
|
||||
bootbox.confirm(msg, function(confirm) {
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('topics.' + command, {tids: tids, cid: CategoryTools.cid}, onCommandComplete);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CategoryTools.removeListeners = function() {
|
||||
socket.removeListener('event:topic_deleted', setDeleteState);
|
||||
socket.removeListener('event:topic_restored', setDeleteState);
|
||||
socket.removeListener('event:topic_purged', onTopicPurged);
|
||||
socket.removeListener('event:topic_locked', setLockedState);
|
||||
socket.removeListener('event:topic_unlocked', setLockedState);
|
||||
socket.removeListener('event:topic_pinned', setPinnedState);
|
||||
socket.removeListener('event:topic_unpinned', setPinnedState);
|
||||
socket.removeListener('event:topic_moved', onTopicMoved);
|
||||
};
|
||||
|
||||
function closeDropDown() {
|
||||
$('.thread-tools.open').find('.dropdown-toggle').trigger('click');
|
||||
}
|
||||
|
||||
function onCommandComplete(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
closeDropDown();
|
||||
topicSelect.unselectAll();
|
||||
}
|
||||
|
||||
function onTopicSelect() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
var isAnyDeleted = isAny(isTopicDeleted, tids);
|
||||
var areAllDeleted = areAll(isTopicDeleted, tids);
|
||||
var isAnyPinned = isAny(isTopicPinned, tids);
|
||||
var isAnyLocked = isAny(isTopicLocked, tids);
|
||||
|
||||
$('.delete_thread span').translateHtml('<i class="fa fa-fw ' + (isAnyDeleted ? 'fa-history' : 'fa-trash-o') + '"></i> [[topic:thread_tools.' + (isAnyDeleted ? 'restore' : 'delete') + ']]');
|
||||
$('.pin_thread').translateHtml('<i class="fa fa-fw fa-thumb-tack"></i> [[topic:thread_tools.' + (isAnyPinned ? 'unpin' : 'pin') + ']]');
|
||||
$('.lock_thread').translateHtml('<i class="fa fa-fw fa-' + (isAnyLocked ? 'un': '') + 'lock"></i> [[topic:thread_tools.' + (isAnyLocked ? 'un': '') + 'lock]]');
|
||||
$('.purge_thread').toggleClass('hidden', !areAllDeleted);
|
||||
}
|
||||
|
||||
function isAny(method, tids) {
|
||||
for(var i=0; i<tids.length; ++i) {
|
||||
if(method(tids[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function areAll(method, tids) {
|
||||
for(var i=0; i<tids.length; ++i) {
|
||||
if(!method(tids[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isTopicDeleted(tid) {
|
||||
return getTopicEl(tid).hasClass('deleted');
|
||||
}
|
||||
|
||||
function isTopicLocked(tid) {
|
||||
return getTopicEl(tid).hasClass('locked');
|
||||
}
|
||||
|
||||
function isTopicPinned(tid) {
|
||||
return getTopicEl(tid).hasClass('pinned');
|
||||
}
|
||||
|
||||
function getTopicEl(tid) {
|
||||
return $('#topics-container li[data-tid="' + tid + '"]');
|
||||
}
|
||||
|
||||
function setDeleteState(data) {
|
||||
var topic = getTopicEl(data.tid);
|
||||
topic.toggleClass('deleted', data.isDeleted);
|
||||
topic.find('.fa-lock').toggleClass('hide', !data.isDeleted);
|
||||
}
|
||||
|
||||
function setPinnedState(data) {
|
||||
var topic = getTopicEl(data.tid);
|
||||
topic.toggleClass('pinned', data.isPinned);
|
||||
topic.find('.fa-thumb-tack').toggleClass('hide', !data.isPinned);
|
||||
ajaxify.refresh();
|
||||
}
|
||||
|
||||
function setLockedState(data) {
|
||||
var topic = getTopicEl(data.tid);
|
||||
topic.toggleClass('locked', data.isLocked);
|
||||
topic.find('.fa-lock').toggleClass('hide', !data.isLocked);
|
||||
}
|
||||
|
||||
function onTopicMoved(data) {
|
||||
getTopicEl(data.tid).remove();
|
||||
}
|
||||
|
||||
function onTopicPurged(tids) {
|
||||
if (!tids) {
|
||||
return;
|
||||
}
|
||||
for(var i=0; i<tids.length; ++i) {
|
||||
getTopicEl(tids[i]).remove();
|
||||
}
|
||||
}
|
||||
|
||||
return CategoryTools;
|
||||
});
|
@ -1,275 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, ajaxify, utils, socket, templates */
|
||||
|
||||
define('forum/chats', ['string', 'sounds', 'forum/infinitescroll'], function(S, sounds, infinitescroll) {
|
||||
var Chats = {
|
||||
initialised: false
|
||||
};
|
||||
|
||||
var newMessage = false;
|
||||
|
||||
Chats.init = function() {
|
||||
var containerEl = $('.expanded-chat ul');
|
||||
|
||||
if (!Chats.initialised) {
|
||||
Chats.addSocketListeners();
|
||||
Chats.addGlobalEventListeners();
|
||||
}
|
||||
|
||||
Chats.addEventListeners();
|
||||
Chats.resizeMainWindow();
|
||||
Chats.scrollToBottom(containerEl);
|
||||
Chats.setActive();
|
||||
|
||||
Chats.initialised = true;
|
||||
};
|
||||
|
||||
Chats.getRecipientUid = function() {
|
||||
return parseInt($('.expanded-chat').attr('data-uid'), 10);
|
||||
};
|
||||
|
||||
Chats.isCurrentChat = function(uid) {
|
||||
return Chats.getRecipientUid() === parseInt(uid, 10);
|
||||
};
|
||||
|
||||
Chats.addEventListeners = function() {
|
||||
var inputEl = $('.chat-input'),
|
||||
sendEl = $('.expanded-chat button[data-action="send"]'),
|
||||
popoutEl = $('[data-action="pop-out"]');
|
||||
|
||||
$('.chats-list').on('click', 'li', function(e) {
|
||||
ajaxify.go('chats/' + utils.slugify($(this).attr('data-username')));
|
||||
});
|
||||
|
||||
inputEl.on('keypress', function(e) {
|
||||
if(e.which === 13) {
|
||||
Chats.sendMessage(Chats.getRecipientUid(), inputEl);
|
||||
}
|
||||
});
|
||||
|
||||
inputEl.on('keyup', function() {
|
||||
var val = !!$(this).val();
|
||||
if ((val && $(this).attr('data-typing') === 'true') || (!val && $(this).attr('data-typing') === 'false')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Chats.notifyTyping(Chats.getRecipientUid(), val);
|
||||
$(this).attr('data-typing', val);
|
||||
});
|
||||
|
||||
sendEl.on('click', function(e) {
|
||||
Chats.sendMessage(Chats.getRecipientUid(), inputEl);
|
||||
return false;
|
||||
});
|
||||
|
||||
popoutEl.on('click', function() {
|
||||
var username = $('.expanded-chat').attr('data-username'),
|
||||
uid = Chats.getRecipientUid();
|
||||
|
||||
if (app.previousUrl && app.previousUrl.match(/chats/)) {
|
||||
ajaxify.go('chats', function() {
|
||||
app.openChat(username, uid);
|
||||
}, true);
|
||||
} else {
|
||||
window.history.go(-1);
|
||||
}
|
||||
});
|
||||
|
||||
$('.recent-chats').on('scroll', function() {
|
||||
var $this = $(this);
|
||||
var bottom = ($this[0].scrollHeight - $this.height()) * 0.9;
|
||||
if ($this.scrollTop() > bottom) {
|
||||
loadMoreRecentChats();
|
||||
}
|
||||
});
|
||||
|
||||
$('.expanded-chat [data-since]').on('click', function() {
|
||||
var since = $(this).attr('data-since');
|
||||
$('.expanded-chat [data-since]').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
loadChatSince(since);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function loadChatSince(since) {
|
||||
var uid = Chats.getRecipientUid();
|
||||
if (!uid) {
|
||||
return;
|
||||
}
|
||||
socket.emit('modules.chats.get', {touid: uid, since: since}, function(err, messages) {
|
||||
var chatContent = $('.expanded-chat .chat-content');
|
||||
chatContent.find('.chat-message').remove();
|
||||
Chats.parseMessage(messages, onMessagesParsed);
|
||||
});
|
||||
}
|
||||
|
||||
Chats.addGlobalEventListeners = function() {
|
||||
$(window).on('resize', Chats.resizeMainWindow);
|
||||
$(window).on('mousemove keypress click', function() {
|
||||
if (newMessage) {
|
||||
var recipientUid = Chats.getRecipientUid();
|
||||
if (recipientUid) {
|
||||
socket.emit('modules.chats.markRead', recipientUid);
|
||||
newMessage = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function onMessagesParsed(html) {
|
||||
var newMessage = $(html);
|
||||
newMessage.insertBefore($('.user-typing'));
|
||||
newMessage.find('span.timeago').timeago();
|
||||
newMessage.find('img:not(".chat-user-image")').addClass('img-responsive');
|
||||
Chats.scrollToBottom($('.expanded-chat .chat-content'));
|
||||
}
|
||||
|
||||
Chats.addSocketListeners = function() {
|
||||
socket.on('event:chats.receive', function(data) {
|
||||
var typingNotifEl = $('.user-typing'),
|
||||
containerEl = $('.expanded-chat ul');
|
||||
|
||||
if (Chats.isCurrentChat(data.withUid)) {
|
||||
newMessage = data.self === 0;
|
||||
data.message.self = data.self;
|
||||
Chats.parseMessage(data.message, onMessagesParsed);
|
||||
} else {
|
||||
$('.chats-list li[data-uid="' + data.withUid + '"]').addClass('unread');
|
||||
app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + data.message.fromUser.username + ']]');
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('event:chats.userStartTyping', function(withUid) {
|
||||
var typingNotifEl = $('.user-typing');
|
||||
|
||||
if (Chats.isCurrentChat(withUid)) {
|
||||
typingNotifEl.removeClass('hide');
|
||||
}
|
||||
|
||||
$('.chats-list li[data-uid="' + withUid + '"]').addClass('typing');
|
||||
});
|
||||
|
||||
socket.on('event:chats.userStopTyping', function(withUid) {
|
||||
var typingNotifEl = $('.user-typing');
|
||||
|
||||
if (Chats.isCurrentChat(withUid)) {
|
||||
typingNotifEl.addClass('hide');
|
||||
}
|
||||
|
||||
$('.chats-list li[data-uid="' + withUid + '"]').removeClass('typing');
|
||||
});
|
||||
|
||||
socket.on('event:user_status_change', function(data) {
|
||||
var userEl = $('.chats-list li[data-uid="' + data.uid +'"]');
|
||||
|
||||
if (userEl.length) {
|
||||
var statusEl = userEl.find('.status');
|
||||
translator.translate('[[global:' + data.status + ']]', function(translated) {
|
||||
statusEl.attr('class', 'fa fa-circle status ' + data.status)
|
||||
.attr('title', translated)
|
||||
.attr('data-original-title', translated);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Chats.resizeMainWindow = function() {
|
||||
var messagesList = $('.expanded-chat ul');
|
||||
|
||||
if (messagesList.length) {
|
||||
var margin = $('.expanded-chat ul').outerHeight(true) - $('.expanded-chat ul').height(),
|
||||
inputHeight = $('.chat-input').outerHeight(true),
|
||||
fromTop = messagesList.offset().top;
|
||||
|
||||
messagesList.height($(window).height() - (fromTop + inputHeight + (margin * 4)));
|
||||
}
|
||||
};
|
||||
|
||||
Chats.notifyTyping = function(toUid, typing) {
|
||||
socket.emit('modules.chats.user' + (typing ? 'Start' : 'Stop') + 'Typing', {
|
||||
touid: toUid,
|
||||
fromUid: app.uid
|
||||
});
|
||||
};
|
||||
|
||||
Chats.sendMessage = function(toUid, inputEl) {
|
||||
var msg = S(inputEl.val()).stripTags().s;
|
||||
if (msg.length) {
|
||||
msg = msg +'\n';
|
||||
socket.emit('modules.chats.send', {
|
||||
touid:toUid,
|
||||
message:msg
|
||||
});
|
||||
inputEl.val('');
|
||||
sounds.play('chat-outgoing');
|
||||
Chats.notifyTyping(toUid, false);
|
||||
}
|
||||
};
|
||||
|
||||
Chats.scrollToBottom = function(containerEl) {
|
||||
if (containerEl.length) {
|
||||
containerEl.scrollTop(
|
||||
containerEl[0].scrollHeight - containerEl.height()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Chats.setActive = function() {
|
||||
var recipientUid = Chats.getRecipientUid();
|
||||
if (recipientUid) {
|
||||
socket.emit('modules.chats.markRead', recipientUid);
|
||||
$('.expanded-chat input').focus();
|
||||
}
|
||||
$('.chats-list li').removeClass('bg-primary');
|
||||
$('.chats-list li[data-uid="' + recipientUid + '"]').addClass('bg-primary');
|
||||
};
|
||||
|
||||
Chats.parseMessage = function(data, callback) {
|
||||
templates.parse('partials/chat_message' + (Array.isArray(data) ? 's' : ''), {
|
||||
messages: data
|
||||
}, callback);
|
||||
};
|
||||
|
||||
function loadMoreRecentChats() {
|
||||
var recentChats = $('.recent-chats');
|
||||
if (recentChats.attr('loading')) {
|
||||
return;
|
||||
}
|
||||
recentChats.attr('loading', 1);
|
||||
socket.emit('modules.chats.getRecentChats', {
|
||||
after: recentChats.attr('data-nextstart')
|
||||
}, function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (data && data.users.length) {
|
||||
onRecentChatsLoaded(data.users, function() {
|
||||
recentChats.removeAttr('loading');
|
||||
recentChats.attr('data-nextstart', data.nextStart);
|
||||
});
|
||||
} else {
|
||||
recentChats.removeAttr('loading');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onRecentChatsLoaded(users, callback) {
|
||||
users = users.filter(function(user) {
|
||||
return !$('.recent-chats li[data-uid=' + user.uid + ']').length;
|
||||
});
|
||||
|
||||
if (!users.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
infinitescroll.parseAndTranslate('chats', 'chats', {chats: users}, function(html) {
|
||||
$('.recent-chats').append(html);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return Chats;
|
||||
});
|
@ -1,69 +0,0 @@
|
||||
define('forum/footer', ['notifications', 'chat'], function(Notifications, Chat) {
|
||||
|
||||
Notifications.prepareDOM();
|
||||
Chat.prepareDOM();
|
||||
translator.prepareDOM();
|
||||
|
||||
function updateUnreadTopicCount(err, count) {
|
||||
if (err) {
|
||||
return console.warn('Error updating unread count', err);
|
||||
}
|
||||
|
||||
$('#unread-count')
|
||||
.toggleClass('unread-count', count > 0)
|
||||
.attr('data-content', count > 20 ? '20+' : count);
|
||||
}
|
||||
|
||||
function updateUnreadChatCount(err, count) {
|
||||
if (err) {
|
||||
return console.warn('Error updating unread count', err);
|
||||
}
|
||||
|
||||
$('#chat-count')
|
||||
.toggleClass('unread-count', count > 0)
|
||||
.attr('data-content', count > 20 ? '20+' : count);
|
||||
}
|
||||
|
||||
function initUnreadTopics() {
|
||||
var unreadTopics = {};
|
||||
|
||||
function onNewPost(data) {
|
||||
if (data && data.posts && data.posts.length) {
|
||||
var post = data.posts[0];
|
||||
|
||||
if (parseInt(post.uid, 10) !== parseInt(app.uid, 10) && !unreadTopics[post.topic.tid]) {
|
||||
increaseUnreadCount();
|
||||
markTopicsUnread(post.topic.tid);
|
||||
unreadTopics[post.topic.tid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function increaseUnreadCount() {
|
||||
var count = parseInt($('#unread-count').attr('data-content'), 10) + 1;
|
||||
updateUnreadTopicCount(null, count);
|
||||
}
|
||||
|
||||
function markTopicsUnread(tid) {
|
||||
$('[data-tid="' + tid + '"]').addClass('unread');
|
||||
}
|
||||
|
||||
$(window).on('action:ajaxify.end', function(ev, data) {
|
||||
var tid = data.url.match(/^topic\/(\d+)/);
|
||||
|
||||
if (tid && tid[1]) {
|
||||
delete unreadTopics[tid[1]];
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('event:new_post', onNewPost);
|
||||
}
|
||||
|
||||
socket.on('event:unread.updateCount', updateUnreadTopicCount);
|
||||
socket.emit('user.getUnreadCount', updateUnreadTopicCount);
|
||||
|
||||
socket.on('event:unread.updateChatCount', updateUnreadChatCount);
|
||||
socket.emit('user.getUnreadChatCount', updateUnreadChatCount);
|
||||
|
||||
initUnreadTopics();
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
define('forum/groups/details', function() {
|
||||
var Details = {};
|
||||
|
||||
Details.init = function() {
|
||||
var memberListEl = $('.groups.details .members');
|
||||
|
||||
memberListEl.on('click', '[data-slug]', function() {
|
||||
var slug = this.getAttribute('data-slug');
|
||||
ajaxify.go('user/' + slug);
|
||||
});
|
||||
};
|
||||
|
||||
return Details;
|
||||
});
|
@ -1,77 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, socket, app, templates, translator, ajaxify*/
|
||||
|
||||
define('forum/home', function() {
|
||||
var home = {};
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
if (data.url !== '') {
|
||||
socket.removeListener('event:new_post', home.onNewPost);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
home.init = function() {
|
||||
app.enterRoom('home');
|
||||
|
||||
socket.removeListener('event:new_post', home.onNewPost);
|
||||
socket.on('event:new_post', home.onNewPost);
|
||||
|
||||
$('.home .category-header').tooltip({
|
||||
placement: 'bottom'
|
||||
});
|
||||
};
|
||||
|
||||
home.onNewPost = function(data) {
|
||||
if (data && data.posts && data.posts.length && data.posts[0].topic) {
|
||||
renderNewPost(data.posts[0].topic.cid, data.posts[0]);
|
||||
}
|
||||
};
|
||||
|
||||
function renderNewPost(cid, post) {
|
||||
var category = $('.home .category-item[data-cid="' + cid + '"]');
|
||||
var categoryBox = category.find('.category-box');
|
||||
var numRecentReplies = category.attr('data-numRecentReplies');
|
||||
if (!numRecentReplies || !parseInt(numRecentReplies, 10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var recentPosts = categoryBox.find('.post-preview');
|
||||
var insertBefore = recentPosts.first();
|
||||
|
||||
parseAndTranslate([post], function(html) {
|
||||
html.hide();
|
||||
if(recentPosts.length === 0) {
|
||||
html.appendTo(categoryBox);
|
||||
} else {
|
||||
html.insertBefore(recentPosts.first());
|
||||
}
|
||||
|
||||
html.fadeIn();
|
||||
|
||||
app.createUserTooltips();
|
||||
|
||||
if (categoryBox.find('.post-preview').length > parseInt(numRecentReplies, 10)) {
|
||||
recentPosts.last().remove();
|
||||
}
|
||||
|
||||
$(window).trigger('action:posts.loaded');
|
||||
});
|
||||
}
|
||||
|
||||
function parseAndTranslate(posts, callback) {
|
||||
ajaxify.loadTemplate('home', function(homeTemplate) {
|
||||
var html = templates.parse(templates.getBlock(homeTemplate, 'posts'), {categories: {posts: posts}});
|
||||
|
||||
translator.translate(html, function(translatedHTML) {
|
||||
translatedHTML = $(translatedHTML);
|
||||
translatedHTML.find('img').addClass('img-responsive');
|
||||
translatedHTML.find('span.timeago').timeago();
|
||||
callback(translatedHTML);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return home;
|
||||
});
|
@ -1,92 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, socket, ajaxify, translator, templates, app */
|
||||
|
||||
define('forum/infinitescroll', function() {
|
||||
|
||||
var scroll = {};
|
||||
var callback;
|
||||
var previousScrollTop = 0;
|
||||
var loadingMore = false;
|
||||
var topOffset = 0;
|
||||
|
||||
scroll.init = function(cb, _topOffest) {
|
||||
callback = cb;
|
||||
topOffset = _topOffest || 0;
|
||||
$(window).off('scroll', onScroll).on('scroll', onScroll);
|
||||
|
||||
// if ($(document).height() === $(window).height()) {
|
||||
// callback(1);
|
||||
// }
|
||||
};
|
||||
|
||||
function onScroll() {
|
||||
var originalPostEl = $('li[data-index="0"]'),
|
||||
top = $(window).height() * 0.15 + topOffset + (originalPostEl ? originalPostEl.outerHeight() : 0),
|
||||
bottom = ($(document).height() - $(window).height()) * 0.85,
|
||||
currentScrollTop = $(window).scrollTop();
|
||||
|
||||
if(currentScrollTop < top && currentScrollTop < previousScrollTop) {
|
||||
callback(-1);
|
||||
} else if (currentScrollTop > bottom && currentScrollTop > previousScrollTop) {
|
||||
callback(1);
|
||||
}
|
||||
previousScrollTop = currentScrollTop;
|
||||
}
|
||||
|
||||
scroll.loadMore = function(method, data, callback) {
|
||||
if (loadingMore) {
|
||||
return;
|
||||
}
|
||||
loadingMore = true;
|
||||
socket.emit(method, data, function(err, data) {
|
||||
if (err) {
|
||||
loadingMore = false;
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
callback(data, function() {
|
||||
loadingMore = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
scroll.parseAndTranslate = function(template, blockName, data, callback) {
|
||||
ajaxify.loadTemplate(template, function(templateHtml) {
|
||||
var html = templates.parse(templates.getBlock(templateHtml, blockName), data);
|
||||
|
||||
translator.translate(html, function(translatedHTML) {
|
||||
callback($(translatedHTML));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
scroll.calculateAfter = function(direction, selector, count, reverse, callback) {
|
||||
var after = 0,
|
||||
offset = 0,
|
||||
el = direction > 0 ? $(selector).last() : $(selector).first(),
|
||||
increment;
|
||||
|
||||
count = reverse ? -count : count;
|
||||
increment = reverse ? -1 : 1;
|
||||
|
||||
if (direction > 0) {
|
||||
after = parseInt(el.attr('data-index'), 10) + increment;
|
||||
} else {
|
||||
after = parseInt(el.attr('data-index'), 10);
|
||||
if (isNaN(after)) {
|
||||
after = 0;
|
||||
}
|
||||
after -= count;
|
||||
if (after < 0) {
|
||||
after = 0;
|
||||
}
|
||||
if (el && el.offset()) {
|
||||
offset = el.offset().top - $('#header-menu').offset().top + $('#header-menu').height();
|
||||
}
|
||||
}
|
||||
|
||||
callback(after, offset, el);
|
||||
};
|
||||
|
||||
return scroll;
|
||||
});
|
@ -1,39 +0,0 @@
|
||||
"use strict";
|
||||
/* global define, app, RELATIVE_PATH */
|
||||
|
||||
define('forum/login', function() {
|
||||
var Login = {};
|
||||
|
||||
Login.init = function() {
|
||||
var errorEl = $('#login-error-notify'),
|
||||
submitEl = $('#login'),
|
||||
formEl = $('#login-form');
|
||||
|
||||
submitEl.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!$('#username').val() || !$('#password').val()) {
|
||||
translator.translate('[[error:invalid-username-or-password]]', function(translated) {
|
||||
errorEl.find('p').text(translated)
|
||||
errorEl.show();
|
||||
});
|
||||
} else {
|
||||
errorEl.hide();
|
||||
|
||||
if (!submitEl.hasClass('disabled')) {
|
||||
submitEl.addClass('disabled');
|
||||
formEl.submit();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#login-error-notify button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
errorEl.hide();
|
||||
});
|
||||
|
||||
$('#content #username').focus();
|
||||
};
|
||||
|
||||
return Login;
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
define('forum/notifications', function() {
|
||||
var Notifications = {};
|
||||
|
||||
Notifications.init = function() {
|
||||
var listEl = $('.notifications-list');
|
||||
|
||||
$('span.timeago').timeago();
|
||||
|
||||
// Allow the user to click anywhere in the LI
|
||||
listEl.on('click', 'li', function(e) {
|
||||
this.querySelector('a').click();
|
||||
});
|
||||
}
|
||||
|
||||
return Notifications;
|
||||
});
|
@ -1,108 +0,0 @@
|
||||
'use strict';
|
||||
/*global define, utils, ajaxify, bootbox*/
|
||||
|
||||
define('forum/pagination', function() {
|
||||
var pagination = {};
|
||||
|
||||
pagination.currentPage = 0;
|
||||
pagination.pageCount = 0;
|
||||
|
||||
pagination.init = function(currentPage, pageCount) {
|
||||
pagination.currentPage = parseInt(currentPage, 10);
|
||||
pagination.pageCount = parseInt(pageCount, 10);
|
||||
|
||||
pagination.recreatePaginationLinks(pageCount);
|
||||
|
||||
$('.pagination')
|
||||
.on('click', '.previous', function() {
|
||||
return pagination.loadPage(pagination.currentPage - 1);
|
||||
}).on('click', '.next', function() {
|
||||
return pagination.loadPage(pagination.currentPage + 1);
|
||||
}).on('click', '.select_page', function(e) {
|
||||
e.preventDefault();
|
||||
bootbox.prompt('Enter page number:', function(pageNum) {
|
||||
pagination.loadPage(pageNum);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
pagination.recreatePaginationLinks = function(newPageCount) {
|
||||
pagination.pageCount = parseInt(newPageCount, 10);
|
||||
|
||||
var pagesToShow = determinePagesToShow();
|
||||
|
||||
var html = '';
|
||||
for(var i=0; i<pagesToShow.length; ++i) {
|
||||
if(i > 0) {
|
||||
if (pagesToShow[i] - 1 !== pagesToShow[i-1]) {
|
||||
html += '<li><a class="select_page" href="#">|</a></li>';
|
||||
}
|
||||
}
|
||||
html += '<li class="page" data-page="' + pagesToShow[i] + '"><a href="#">' + pagesToShow[i] + '</a></li>';
|
||||
}
|
||||
|
||||
$('.pagination li.page').remove();
|
||||
$('.pagination li .select_page').parent().remove();
|
||||
$(html).insertAfter($('.pagination li.previous'));
|
||||
|
||||
updatePageLinks();
|
||||
};
|
||||
|
||||
function determinePagesToShow() {
|
||||
var pagesToShow = [1];
|
||||
if(pagination.pageCount !== 1) {
|
||||
pagesToShow.push(pagination.pageCount);
|
||||
}
|
||||
|
||||
var previous = pagination.currentPage - 1;
|
||||
var next = pagination.currentPage + 1;
|
||||
|
||||
if(previous > 1 && pagesToShow.indexOf(previous) === -1) {
|
||||
pagesToShow.push(previous);
|
||||
}
|
||||
|
||||
if(next < pagination.pageCount && pagesToShow.indexOf(next) === -1) {
|
||||
pagesToShow.push(next);
|
||||
}
|
||||
|
||||
if(pagesToShow.indexOf(pagination.currentPage) === -1) {
|
||||
pagesToShow.push(pagination.currentPage);
|
||||
}
|
||||
|
||||
pagesToShow.sort(function(a, b) {
|
||||
return parseInt(a, 10) - parseInt(b, 10);
|
||||
});
|
||||
return pagesToShow;
|
||||
}
|
||||
|
||||
pagination.loadPage = function(page, callback) {
|
||||
page = parseInt(page, 10);
|
||||
if(!utils.isNumber(page) || page < 1 || page > pagination.pageCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ajaxify.go(window.location.pathname.slice(1) + '?page=' + page, function() {
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
function updatePageLinks() {
|
||||
$('.pagination').toggleClass('hide', pagination.pageCount === 0 || pagination.pageCount === 1);
|
||||
|
||||
$('.pagination .next').toggleClass('disabled', pagination.currentPage === pagination.pageCount);
|
||||
$('.pagination .previous').toggleClass('disabled', pagination.currentPage === 1);
|
||||
|
||||
$('.pagination .page').removeClass('active');
|
||||
$('.pagination .page[data-page="' + pagination.currentPage + '"]').addClass('active');
|
||||
$('.pagination .page').each(function(index, element) {
|
||||
var li = $(this);
|
||||
var page = li.attr('data-page');
|
||||
li.find('a').attr('href', window.location.pathname + '?page=' + page);
|
||||
});
|
||||
}
|
||||
|
||||
return pagination;
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket*/
|
||||
|
||||
define('forum/popular', ['forum/recent', 'forum/infinitescroll'], function(recent, infinitescroll) {
|
||||
var Popular = {};
|
||||
|
||||
Popular.init = function() {
|
||||
app.enterRoom('recent_posts');
|
||||
|
||||
$('#new-topics-alert').on('click', function() {
|
||||
$(this).addClass('hide');
|
||||
});
|
||||
|
||||
recent.selectActivePill();
|
||||
};
|
||||
|
||||
return Popular;
|
||||
});
|
@ -1,140 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket, utils */
|
||||
|
||||
define('forum/recent', ['forum/infinitescroll'], function(infinitescroll) {
|
||||
var Recent = {};
|
||||
|
||||
var newTopicCount = 0,
|
||||
newPostCount = 0;
|
||||
|
||||
var active = '';
|
||||
|
||||
function getActiveSection() {
|
||||
var url = window.location.href,
|
||||
parts = url.split('/'),
|
||||
active = parts[parts.length - 1];
|
||||
return active;
|
||||
}
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
if(data.url.indexOf('recent') !== 0) {
|
||||
Recent.removeListeners();
|
||||
}
|
||||
});
|
||||
|
||||
Recent.init = function() {
|
||||
app.enterRoom('recent_posts');
|
||||
|
||||
Recent.watchForNewPosts();
|
||||
|
||||
active = Recent.selectActivePill();
|
||||
|
||||
$('#new-topics-alert').on('click', function() {
|
||||
$(this).addClass('hide');
|
||||
});
|
||||
|
||||
|
||||
infinitescroll.init(Recent.loadMoreTopics);
|
||||
};
|
||||
|
||||
Recent.selectActivePill = function() {
|
||||
var active = getActiveSection();
|
||||
|
||||
$('.nav-pills li').removeClass('active');
|
||||
$('.nav-pills li a').each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.attr('href').match(active)) {
|
||||
$this.parent().addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return active;
|
||||
};
|
||||
|
||||
Recent.watchForNewPosts = function () {
|
||||
newPostCount = 0;
|
||||
newTopicCount = 0;
|
||||
Recent.removeListeners();
|
||||
socket.on('event:new_topic', onNewTopic);
|
||||
socket.on('event:new_post', onNewPost);
|
||||
};
|
||||
|
||||
function onNewTopic(data) {
|
||||
++newTopicCount;
|
||||
Recent.updateAlertText();
|
||||
}
|
||||
|
||||
function onNewPost(data) {
|
||||
++newPostCount;
|
||||
Recent.updateAlertText();
|
||||
}
|
||||
|
||||
Recent.removeListeners = function() {
|
||||
socket.removeListener('event:new_topic', onNewTopic);
|
||||
socket.removeListener('event:new_post', onNewPost);
|
||||
};
|
||||
|
||||
Recent.updateAlertText = function() {
|
||||
var text = 'There';
|
||||
|
||||
if (newTopicCount > 1) {
|
||||
text += ' are ' + newTopicCount + ' new topics';
|
||||
} else if (newTopicCount === 1) {
|
||||
text += ' is a new topic';
|
||||
}
|
||||
|
||||
if (newPostCount > 1) {
|
||||
text += (newTopicCount?' and ':' are ') + newPostCount + ' new posts';
|
||||
} else if(newPostCount === 1) {
|
||||
text += (newTopicCount?' and ':' is ') + ' a new post';
|
||||
}
|
||||
|
||||
text += '. Click here to reload.';
|
||||
|
||||
$('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow');
|
||||
$('#category-no-topics').addClass('hide');
|
||||
};
|
||||
|
||||
Recent.loadMoreTopics = function(direction) {
|
||||
if(direction < 0 || !$('#topics-container').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMoreRecentTopics', {
|
||||
after: $('#topics-container').attr('data-nextstart'),
|
||||
term: active
|
||||
}, function(data, done) {
|
||||
if (data.topics && data.topics.length) {
|
||||
Recent.onTopicsLoaded('recent', data.topics, false, done);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Recent.onTopicsLoaded = function(templateName, topics, showSelect, callback) {
|
||||
|
||||
topics = topics.filter(function(topic) {
|
||||
return !$('#topics-container li[data-tid=' + topic.tid + ']').length;
|
||||
});
|
||||
|
||||
if (!topics.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
infinitescroll.parseAndTranslate(templateName, 'topics', {topics: topics, showSelect: showSelect}, function(html) {
|
||||
$('#category-no-topics').remove();
|
||||
|
||||
$('#topics-container').append(html);
|
||||
html.find('span.timeago').timeago();
|
||||
app.createUserTooltips();
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
return Recent;
|
||||
});
|
@ -1,198 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, utils, socket, config */
|
||||
|
||||
|
||||
define('forum/register', function() {
|
||||
var Register = {},
|
||||
validationError = false,
|
||||
successIcon = '<i class="fa fa-check"></i>';
|
||||
|
||||
function showError(element, msg) {
|
||||
translator.translate(msg, function(msg) {
|
||||
element.html(msg);
|
||||
element.parent()
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger');
|
||||
element.show();
|
||||
});
|
||||
validationError = true;
|
||||
}
|
||||
|
||||
function showSuccess(element, msg) {
|
||||
translator.translate(msg, function(msg) {
|
||||
element.html(msg);
|
||||
element.parent()
|
||||
.removeClass('alert-danger')
|
||||
.addClass('alert-success');
|
||||
element.show();
|
||||
});
|
||||
}
|
||||
|
||||
function validateEmail(email, callback) {
|
||||
callback = callback || function() {};
|
||||
var email_notify = $('#email-notify');
|
||||
|
||||
if (!email) {
|
||||
validationError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils.isEmailValid(email)) {
|
||||
showError(email_notify, '[[error:invalid-email]]');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('user.emailExists', {
|
||||
email: email
|
||||
}, function(err, exists) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
showError(email_notify, '[[error:email-taken]]');
|
||||
} else {
|
||||
showSuccess(email_notify, successIcon);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function validateUsername(username, callback) {
|
||||
callback = callback || function() {};
|
||||
|
||||
var username_notify = $('#username-notify');
|
||||
|
||||
if (!username) {
|
||||
validationError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (username.length < config.minimumUsernameLength) {
|
||||
showError(username_notify, '[[error:username-too-short]]');
|
||||
} else if (username.length > config.maximumUsernameLength) {
|
||||
showError(username_notify, '[[error:username-too-long]]');
|
||||
} else if (!utils.isUserNameValid(username) || !utils.slugify(username)) {
|
||||
showError(username_notify, '[[error:invalid-username]]');
|
||||
} else {
|
||||
socket.emit('user.exists', {
|
||||
username: username
|
||||
}, function(err, exists) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
showError(username_notify, '[[error:username-taken]]');
|
||||
} else {
|
||||
showSuccess(username_notify, successIcon);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function validatePassword(password, password_confirm) {
|
||||
if (!password) {
|
||||
validationError = true;
|
||||
return;
|
||||
}
|
||||
var password_notify = $('#password-notify'),
|
||||
password_confirm_notify = $('#password-confirm-notify');
|
||||
|
||||
if (password.length < config.minimumPasswordLength) {
|
||||
showError(password_notify, '[[user:change_password_error_length]]');
|
||||
} else if (!utils.isPasswordValid(password)) {
|
||||
showError(password_notify, '[[user:change_password_error]]');
|
||||
} else {
|
||||
showSuccess(password_notify, successIcon);
|
||||
}
|
||||
|
||||
if (password !== password_confirm && password_confirm !== '') {
|
||||
showError(password_confirm_notify, '[[user:change_password_error_match]]');
|
||||
}
|
||||
}
|
||||
|
||||
function validatePasswordConfirm(password, password_confirm) {
|
||||
var password_notify = $('#password-notify'),
|
||||
password_confirm_notify = $('#password-confirm-notify');
|
||||
|
||||
if (!password || password_notify.hasClass('alert-error')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (password !== password_confirm) {
|
||||
showError(password_confirm_notify, '[[user:change_password_error_match]]');
|
||||
} else {
|
||||
showSuccess(password_confirm_notify, successIcon);
|
||||
}
|
||||
}
|
||||
|
||||
Register.init = function() {
|
||||
var email = $('#email'),
|
||||
username = $('#username'),
|
||||
password = $('#password'),
|
||||
password_confirm = $('#password-confirm'),
|
||||
register = $('#register'),
|
||||
agreeTerms = $('#agree-terms');
|
||||
|
||||
$('#referrer').val(app.previousUrl);
|
||||
|
||||
email.on('blur', function() {
|
||||
validateEmail(email.val());
|
||||
});
|
||||
|
||||
username.on('keyup', function() {
|
||||
$('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
|
||||
});
|
||||
|
||||
username.on('blur', function() {
|
||||
validateUsername(username.val());
|
||||
});
|
||||
|
||||
password.on('blur', function() {
|
||||
validatePassword(password.val(), password_confirm.val());
|
||||
});
|
||||
|
||||
password_confirm.on('blur', function() {
|
||||
validatePasswordConfirm(password.val(), password_confirm.val());
|
||||
});
|
||||
|
||||
function validateForm(callback) {
|
||||
validationError = false;
|
||||
validatePassword(password.val(), password_confirm.val());
|
||||
validatePasswordConfirm(password.val(), password_confirm.val());
|
||||
|
||||
validateEmail(email.val(), function() {
|
||||
validateUsername(username.val(), callback);
|
||||
});
|
||||
}
|
||||
|
||||
register.on('click', function(e) {
|
||||
var registerBtn = $(this);
|
||||
e.preventDefault();
|
||||
validateForm(function() {
|
||||
if (!validationError) {
|
||||
registerBtn.parents('form').trigger('submit');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if(agreeTerms.length) {
|
||||
agreeTerms.on('click', function() {
|
||||
if ($(this).prop('checked')) {
|
||||
register.removeAttr('disabled');
|
||||
} else {
|
||||
register.attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
|
||||
register.attr('disabled', 'disabled');
|
||||
}
|
||||
};
|
||||
|
||||
return Register;
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
define('forum/reset', function() {
|
||||
var ResetPassword = {};
|
||||
|
||||
ResetPassword.init = function() {
|
||||
var inputEl = $('#email'),
|
||||
errorEl = $('#error'),
|
||||
successEl = $('#success');
|
||||
|
||||
$('#reset').on('click', function() {
|
||||
if (inputEl.val() && inputEl.val().indexOf('@') !== -1) {
|
||||
socket.emit('user.reset.send', inputEl.val(), function(err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
errorEl.addClass('hide').hide();
|
||||
successEl.removeClass('hide').show();
|
||||
inputEl.val('');
|
||||
});
|
||||
} else {
|
||||
successEl.addClass('hide').hide();
|
||||
errorEl.removeClass('hide').show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return ResetPassword;
|
||||
});
|
@ -1,55 +0,0 @@
|
||||
define('forum/reset_code', function() {
|
||||
var ResetCode = {};
|
||||
|
||||
ResetCode.init = function() {
|
||||
var reset_code = ajaxify.variables.get('reset_code');
|
||||
|
||||
var resetEl = $('#reset'),
|
||||
password = $('#password'),
|
||||
repeat = $('#repeat'),
|
||||
noticeEl = $('#notice');
|
||||
|
||||
resetEl.on('click', function() {
|
||||
if (password.val().length < 6) {
|
||||
$('#error').addClass('hide').hide();
|
||||
noticeEl.find('strong').html('Invalid Password');
|
||||
noticeEl.find('p').html('The password entered is too short, please pick a different password.');
|
||||
noticeEl.removeClass('hide').css({display: 'block'});
|
||||
} else if (password.value !== repeat.value) {
|
||||
$('#error').hide();
|
||||
noticeEl.find('strong').html('Invalid Password');
|
||||
noticeEl.find('p').html('The two passwords you\'ve entered do not match.');
|
||||
noticeEl.removeClass('hide').css({display: 'block'});
|
||||
} else {
|
||||
socket.emit('user.reset.commit', {
|
||||
code: reset_code,
|
||||
password: password.val()
|
||||
}, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
$('#error').addClass('hide').hide();
|
||||
$('#notice').addClass('hide').hide();
|
||||
$('#success').removeClass('hide').addClass('show').show();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.emit('user.reset.valid', reset_code, function(err, valid) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
resetEl.prop('disabled', false);
|
||||
} else {
|
||||
var formEl = $('#reset-form');
|
||||
// Show error message
|
||||
$('#error').show();
|
||||
formEl.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return ResetCode;
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
define('forum/search', ['search'], function(searchModule) {
|
||||
var Search = {};
|
||||
|
||||
Search.init = function() {
|
||||
var searchQuery = $('#post-results').attr('data-search-query');
|
||||
var regexes = [];
|
||||
var searchTerms = searchQuery.split(' ');
|
||||
for (var i=0; i<searchTerms.length; ++i) {
|
||||
var regex = new RegExp(searchTerms[i], 'gi');
|
||||
regexes.push({regex: regex, term: searchTerms[i]});
|
||||
}
|
||||
|
||||
$('.search-result-text').each(function() {
|
||||
var result = $(this);
|
||||
var text = result.html();
|
||||
for(var i=0; i<regexes.length; ++i) {
|
||||
text = text.replace(regexes[i].regex, '<strong>' + regexes[i].term + '</strong>');
|
||||
}
|
||||
result.html(text).find('img').addClass('img-responsive');
|
||||
});
|
||||
|
||||
$('#search-form input').val(searchQuery);
|
||||
|
||||
$('#mobile-search-form').off('submit').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var input = $(this).find('input');
|
||||
|
||||
searchModule.query(input.val(), function() {
|
||||
input.val('');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return Search;
|
||||
});
|
@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket */
|
||||
|
||||
define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function(recent, infinitescroll) {
|
||||
var Tag = {};
|
||||
|
||||
Tag.init = function() {
|
||||
app.enterRoom('tags');
|
||||
|
||||
if ($('body').height() <= $(window).height() && $('#topics-container').children().length >= 20) {
|
||||
$('#load-more-btn').show();
|
||||
}
|
||||
|
||||
$('#load-more-btn').on('click', function() {
|
||||
loadMoreTopics();
|
||||
});
|
||||
|
||||
infinitescroll.init(loadMoreTopics);
|
||||
|
||||
function loadMoreTopics(direction) {
|
||||
if(direction < 0 || !$('#topics-container').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMoreFromSet', {
|
||||
set: 'tag:' + ajaxify.variables.get('tag') + ':topics',
|
||||
after: $('#topics-container').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
if (data.topics && data.topics.length) {
|
||||
recent.onTopicsLoaded('tag', data.topics, false, done);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
$('#load-more-btn').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Tag;
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, utils, socket */
|
||||
|
||||
define('forum/tags', ['forum/infinitescroll'], function(infinitescroll) {
|
||||
var Tags = {};
|
||||
var timeoutId = 0;
|
||||
|
||||
Tags.init = function() {
|
||||
app.enterRoom('tags');
|
||||
|
||||
$('#tag-search').on('input propertychange', function() {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
timeoutId = setTimeout(function() {
|
||||
socket.emit('topics.searchAndLoadTags', {query: $('#tag-search').val()}, function(err, results) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
onTagsLoaded(results, true, function() {
|
||||
timeoutId = 0;
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
|
||||
infinitescroll.init(Tags.loadMoreTags);
|
||||
};
|
||||
|
||||
Tags.loadMoreTags = function(direction) {
|
||||
if(direction < 0 || !$('.tag-list').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMoreTags', {
|
||||
after: $('.tag-list').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
if (data && data.tags && data.tags.length) {
|
||||
onTagsLoaded(data.tags, false, done);
|
||||
$('.tag-list').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function onTagsLoaded(tags, replace, callback) {
|
||||
callback = callback || function() {};
|
||||
infinitescroll.parseAndTranslate('tags', 'tags', {tags: tags}, function(html) {
|
||||
$('.tag-list')[replace ? 'html' : 'append'](html);
|
||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
return Tags;
|
||||
});
|
@ -1,452 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
/* globals define, app, templates, translator, socket, bootbox, config, ajaxify, RELATIVE_PATH, utils */
|
||||
|
||||
var dependencies = [
|
||||
'forum/pagination',
|
||||
'forum/infinitescroll',
|
||||
'forum/topic/threadTools',
|
||||
'forum/topic/postTools',
|
||||
'forum/topic/events',
|
||||
'forum/topic/browsing',
|
||||
'navigator'
|
||||
];
|
||||
|
||||
define('forum/topic', dependencies, function(pagination, infinitescroll, threadTools, postTools, events, browsing, navigator) {
|
||||
var Topic = {},
|
||||
currentUrl = '';
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
if(data.url.indexOf('topic') !== 0) {
|
||||
navigator.hide();
|
||||
$('.header-topic-title').find('span').text('').hide();
|
||||
app.removeAlert('bookmark');
|
||||
|
||||
events.removeListeners();
|
||||
|
||||
socket.removeListener('event:new_post', onNewPost);
|
||||
socket.removeListener('event:new_notification', onNewNotification);
|
||||
}
|
||||
});
|
||||
|
||||
Topic.init = function() {
|
||||
var tid = ajaxify.variables.get('topic_id'),
|
||||
thread_state = {
|
||||
locked: ajaxify.variables.get('locked'),
|
||||
deleted: ajaxify.variables.get('deleted'),
|
||||
pinned: ajaxify.variables.get('pinned')
|
||||
},
|
||||
postCount = ajaxify.variables.get('postcount');
|
||||
|
||||
$(window).trigger('action:topic.loading');
|
||||
|
||||
app.enterRoom('topic_' + tid);
|
||||
|
||||
processPage($('.topic'));
|
||||
|
||||
showBottomPostBar();
|
||||
|
||||
postTools.init(tid, thread_state);
|
||||
threadTools.init(tid, thread_state);
|
||||
events.init();
|
||||
|
||||
handleSorting();
|
||||
|
||||
hidePostToolsForDeletedPosts();
|
||||
|
||||
enableInfiniteLoadingOrPagination();
|
||||
|
||||
addBlockQuoteHandler();
|
||||
|
||||
addBlockquoteEllipses($('.topic .post-content > blockquote'));
|
||||
|
||||
handleBookmark(tid);
|
||||
|
||||
navigator.init('.posts > .post-row', postCount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex);
|
||||
|
||||
socket.on('event:new_post', onNewPost);
|
||||
socket.on('event:new_notification', onNewNotification);
|
||||
|
||||
$(window).on('scroll', updateTopicTitle);
|
||||
|
||||
$(window).trigger('action:topic.loaded');
|
||||
|
||||
socket.emit('topics.enter', tid);
|
||||
};
|
||||
|
||||
Topic.toTop = function() {
|
||||
navigator.scrollTop(0);
|
||||
};
|
||||
|
||||
Topic.toBottom = function() {
|
||||
socket.emit('topics.postcount', ajaxify.variables.get('topic_id'), function(err, postCount) {
|
||||
if (config.topicPostSort !== 'oldest_to_newest') {
|
||||
postCount = 1;
|
||||
}
|
||||
navigator.scrollBottom(postCount - 1);
|
||||
});
|
||||
};
|
||||
|
||||
function handleBookmark(tid) {
|
||||
var bookmark = localStorage.getItem('topic:' + tid + ':bookmark');
|
||||
var postIndex = getPostIndex();
|
||||
if (postIndex) {
|
||||
navigator.scrollToPost(postIndex - 1, true);
|
||||
} else if (bookmark && (!config.usePagination || (config.usePagination && pagination.currentPage === 1)) && ajaxify.variables.get('postcount') > 1) {
|
||||
app.alert({
|
||||
alert_id: 'bookmark',
|
||||
message: '[[topic:bookmark_instructions]]',
|
||||
timeout: 0,
|
||||
type: 'info',
|
||||
clickfn : function() {
|
||||
navigator.scrollToPost(parseInt(bookmark, 10), true);
|
||||
},
|
||||
closefn : function() {
|
||||
localStorage.removeItem('topic:' + tid + ':bookmark');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getPostIndex() {
|
||||
var parts = window.location.pathname.split('/');
|
||||
return parts[4] ? parseInt(parts[4], 10) : 0;
|
||||
}
|
||||
|
||||
function handleSorting() {
|
||||
var threadSort = $('.thread-sort');
|
||||
threadSort.find('i').removeClass('fa-check');
|
||||
var currentSetting = threadSort.find('a[data-sort="' + config.topicPostSort + '"]');
|
||||
currentSetting.find('i').addClass('fa-check');
|
||||
|
||||
$('.thread-sort').on('click', 'a', function() {
|
||||
var newSetting = $(this).attr('data-sort');
|
||||
socket.emit('user.setTopicSort', newSetting, function(err) {
|
||||
config.topicPostSort = newSetting;
|
||||
ajaxify.go('topic/' + ajaxify.variables.get('topic_slug'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showBottomPostBar() {
|
||||
if($('#post-container .post-row').length > 1 || !$('#post-container li[data-index="0"]').length) {
|
||||
$('.bottom-post-bar').removeClass('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function onNewPost(data) {
|
||||
var tid = ajaxify.variables.get('topic_id');
|
||||
if(data && data.posts && data.posts.length && data.posts[0].tid !== tid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(config.usePagination) {
|
||||
return onNewPostPagination(data);
|
||||
}
|
||||
|
||||
for (var i=0; i<data.posts.length; ++i) {
|
||||
var postcount = $('.user_postcount_' + data.posts[i].uid);
|
||||
postcount.html(parseInt(postcount.html(), 10) + 1);
|
||||
}
|
||||
socket.emit('topics.markAsRead', [tid]);
|
||||
createNewPosts(data);
|
||||
}
|
||||
|
||||
function onNewNotification(data) {
|
||||
var tid = ajaxify.variables.get('topic_id');
|
||||
if (data && data.tid && parseInt(data.tid, 10) === parseInt(tid, 10)) {
|
||||
socket.emit('topics.markTopicNotificationsRead', tid);
|
||||
}
|
||||
}
|
||||
|
||||
function addBlockQuoteHandler() {
|
||||
$('#post-container').on('click', 'blockquote .toggle', function() {
|
||||
var blockQuote = $(this).parent('blockquote');
|
||||
var toggle = $(this);
|
||||
blockQuote.toggleClass('uncollapsed');
|
||||
var collapsed = !blockQuote.hasClass('uncollapsed');
|
||||
toggle.toggleClass('fa-angle-down', collapsed).toggleClass('fa-angle-up', !collapsed);
|
||||
});
|
||||
}
|
||||
|
||||
function addBlockquoteEllipses(blockquotes) {
|
||||
blockquotes.each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.find(':hidden:not(br)').length && !$this.find('.toggle').length) {
|
||||
$this.append('<i class="fa fa-angle-down pointer toggle"></i>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function enableInfiniteLoadingOrPagination() {
|
||||
if(!config.usePagination) {
|
||||
infinitescroll.init(loadMorePosts, $('#post-container .post-row[data-index="0"]').height());
|
||||
} else {
|
||||
navigator.hide();
|
||||
|
||||
pagination.init(parseInt(ajaxify.variables.get('currentPage'), 10), parseInt(ajaxify.variables.get('pageCount'), 10));
|
||||
}
|
||||
}
|
||||
|
||||
function hidePostToolsForDeletedPosts() {
|
||||
$('#post-container li.deleted').each(function() {
|
||||
postTools.toggle($(this).attr('data-pid'), true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function updateTopicTitle() {
|
||||
if($(window).scrollTop() > 50) {
|
||||
$('.header-topic-title').find('span').text(ajaxify.variables.get('topic_name')).show();
|
||||
} else {
|
||||
$('.header-topic-title').find('span').text('').hide();
|
||||
}
|
||||
}
|
||||
|
||||
Topic.calculateIndex = function(index, elementCount) {
|
||||
if (index !== 1 && config.topicPostSort !== 'oldest_to_newest') {
|
||||
return elementCount - index + 2;
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
Topic.navigatorCallback = function(element, elementCount) {
|
||||
var path = ajaxify.removeRelativePath(window.location.pathname.slice(1));
|
||||
if (!path.startsWith('topic')) {
|
||||
return 1;
|
||||
}
|
||||
var postIndex = parseInt(element.attr('data-index'), 10);
|
||||
var index = postIndex + 1;
|
||||
if (config.topicPostSort !== 'oldest_to_newest') {
|
||||
if (postIndex === 0) {
|
||||
index = 1;
|
||||
} else {
|
||||
index = Math.max(elementCount - postIndex + 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
var currentBookmark = localStorage.getItem('topic:' + ajaxify.variables.get('topic_id') + ':bookmark');
|
||||
|
||||
if (!currentBookmark || parseInt(postIndex, 10) >= parseInt(currentBookmark, 10)) {
|
||||
localStorage.setItem('topic:' + ajaxify.variables.get('topic_id') + ':bookmark', postIndex);
|
||||
app.removeAlert('bookmark');
|
||||
}
|
||||
|
||||
if (!navigator.scrollActive) {
|
||||
var parts = ajaxify.removeRelativePath(window.location.pathname.slice(1)).split('/');
|
||||
var topicId = parts[1],
|
||||
slug = parts[2];
|
||||
var newUrl = 'topic/' + topicId + '/' + (slug ? slug : '');
|
||||
if (postIndex > 0) {
|
||||
newUrl += '/' + (postIndex + 1);
|
||||
}
|
||||
|
||||
if (newUrl !== currentUrl) {
|
||||
if (history.replaceState) {
|
||||
var search = (window.location.search ? window.location.search : '');
|
||||
history.replaceState({
|
||||
url: newUrl + search
|
||||
}, null, window.location.protocol + '//' + window.location.host + RELATIVE_PATH + '/' + newUrl + search);
|
||||
}
|
||||
currentUrl = newUrl;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
function onNewPostPagination(data) {
|
||||
var posts = data.posts;
|
||||
socket.emit('topics.getPageCount', ajaxify.variables.get('topic_id'), function(err, newPageCount) {
|
||||
|
||||
pagination.recreatePaginationLinks(newPageCount);
|
||||
|
||||
if (pagination.currentPage === pagination.pageCount) {
|
||||
createNewPosts(data);
|
||||
} else if(data.posts && data.posts.length && parseInt(data.posts[0].uid, 10) === parseInt(app.uid, 10)) {
|
||||
pagination.loadPage(pagination.pageCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createNewPosts(data, callback) {
|
||||
callback = callback || function() {};
|
||||
if(!data || (data.posts && !data.posts.length)) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
function removeAlreadyAddedPosts() {
|
||||
data.posts = data.posts.filter(function(post) {
|
||||
return $('#post-container li[data-pid="' + post.pid +'"]').length === 0;
|
||||
});
|
||||
}
|
||||
|
||||
var after = null,
|
||||
before = null;
|
||||
|
||||
function findInsertionPoint() {
|
||||
var firstPostTimestamp = parseInt(data.posts[0].timestamp, 10);
|
||||
var firstPostVotes = parseInt(data.posts[0].votes, 10);
|
||||
var firstPostPid = data.posts[0].pid;
|
||||
|
||||
var firstReply = $('#post-container li.post-row[data-index!="0"]').first();
|
||||
var lastReply = $('#post-container li.post-row[data-index!="0"]').last();
|
||||
|
||||
if (config.topicPostSort === 'oldest_to_newest') {
|
||||
if (firstPostTimestamp < parseInt(firstReply.attr('data-timestamp'), 10)) {
|
||||
before = firstReply;
|
||||
} else if(firstPostTimestamp >= parseInt(lastReply.attr('data-timestamp'), 10)) {
|
||||
after = lastReply;
|
||||
}
|
||||
} else if(config.topicPostSort === 'newest_to_oldest') {
|
||||
if (firstPostTimestamp > parseInt(firstReply.attr('data-timestamp'), 10)) {
|
||||
before = firstReply;
|
||||
} else if(firstPostTimestamp <= parseInt(lastReply.attr('data-timestamp'), 10)) {
|
||||
after = lastReply;
|
||||
}
|
||||
} else if(config.topicPostSort === 'most_votes') {
|
||||
if (firstPostVotes > parseInt(firstReply.attr('data-votes'), 10)) {
|
||||
before = firstReply;
|
||||
} else if(firstPostVotes < parseInt(firstReply.attr('data-votes'), 10)) {
|
||||
after = lastReply;
|
||||
} else {
|
||||
if (firstPostPid > firstReply.attr('data-pid')) {
|
||||
before = firstReply;
|
||||
} else if(firstPostPid <= firstReply.attr('data-pid')) {
|
||||
after = lastReply;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeAlreadyAddedPosts();
|
||||
if(!data.posts.length) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
findInsertionPoint();
|
||||
|
||||
data.title = $('<div></div>').text(ajaxify.variables.get('topic_name')).html();
|
||||
data.viewcount = ajaxify.variables.get('viewcount');
|
||||
|
||||
infinitescroll.parseAndTranslate('topic', 'posts', data, function(html) {
|
||||
if(after) {
|
||||
html.insertAfter(after);
|
||||
} else if(before) {
|
||||
// Save document height and position for future reference (about 5 lines down)
|
||||
var height = $(document).height(),
|
||||
scrollTop = $(document).scrollTop(),
|
||||
originalPostEl = $('li[data-index="0"]');
|
||||
|
||||
// Insert the new post
|
||||
html.insertBefore(before);
|
||||
|
||||
// If the user is not at the top of the page... (or reasonably so...)
|
||||
if (scrollTop > originalPostEl.offset().top) {
|
||||
// Now restore the relative position the user was on prior to new post insertion
|
||||
$(document).scrollTop(scrollTop + ($(document).height() - height));
|
||||
}
|
||||
} else {
|
||||
$('#post-container').append(html);
|
||||
}
|
||||
|
||||
html.hide().fadeIn('slow');
|
||||
|
||||
addBlockquoteEllipses(html.find('.post-content > blockquote'));
|
||||
|
||||
$(window).trigger('action:posts.loaded');
|
||||
onNewPostsLoaded(html, data.posts);
|
||||
callback(true);
|
||||
});
|
||||
}
|
||||
|
||||
function onNewPostsLoaded(html, posts) {
|
||||
|
||||
var pids = [];
|
||||
for(var i=0; i<posts.length; ++i) {
|
||||
pids.push(posts[i].pid);
|
||||
}
|
||||
|
||||
socket.emit('posts.getPrivileges', pids, function(err, privileges) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
for(i=0; i<pids.length; ++i) {
|
||||
toggleModTools(pids[i], privileges[i]);
|
||||
}
|
||||
});
|
||||
|
||||
processPage(html);
|
||||
}
|
||||
|
||||
function processPage(element) {
|
||||
app.createUserTooltips();
|
||||
app.replaceSelfLinks(element.find('a'));
|
||||
utils.addCommasToNumbers(element.find('.formatted-number'));
|
||||
utils.makeNumbersHumanReadable(element.find('.human-readable-number'));
|
||||
element.find('span.timeago').timeago();
|
||||
element.find('.post-content img:not(.emoji)').addClass('img-responsive').each(function() {
|
||||
var $this = $(this);
|
||||
if (!$this.parent().is('a')) {
|
||||
$this.wrap('<a href="' + $this.attr('src') + '" target="_blank">');
|
||||
}
|
||||
});
|
||||
postTools.updatePostCount();
|
||||
showBottomPostBar();
|
||||
}
|
||||
|
||||
function toggleModTools(pid, privileges) {
|
||||
var postEl = $('.post-row[data-pid="' + pid + '"]');
|
||||
|
||||
postEl.find('.edit, .delete').toggleClass('hidden', !privileges.editable);
|
||||
postEl.find('.move').toggleClass('hidden', !privileges.move);
|
||||
postEl.find('.reply, .quote').toggleClass('hidden', !$('.post_reply').length);
|
||||
var isSelfPost = parseInt(postEl.attr('data-uid'), 10) === parseInt(app.uid, 10);
|
||||
postEl.find('.chat, .flag').toggleClass('hidden', isSelfPost || !app.uid);
|
||||
}
|
||||
|
||||
function loadMorePosts(direction) {
|
||||
if (!$('#post-container').length || navigator.scrollActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
var reverse = config.topicPostSort === 'newest_to_oldest' || config.topicPostSort === 'most_votes';
|
||||
|
||||
infinitescroll.calculateAfter(direction, '#post-container .post-row[data-index!="0"]', config.postsPerPage, reverse, function(after, offset, el) {
|
||||
loadPostsAfter(after);
|
||||
});
|
||||
}
|
||||
|
||||
function loadPostsAfter(after) {
|
||||
var tid = ajaxify.variables.get('topic_id');
|
||||
if (!utils.isNumber(tid) || !utils.isNumber(after) || (after === 0 && $('#post-container li.post-row[data-index="1"]').length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var indicatorEl = $('.loading-indicator');
|
||||
if (!indicatorEl.is(':animated')) {
|
||||
indicatorEl.fadeIn();
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMore', {
|
||||
tid: tid,
|
||||
after: after
|
||||
}, function (data, done) {
|
||||
|
||||
indicatorEl.fadeOut();
|
||||
|
||||
if (data && data.posts && data.posts.length) {
|
||||
createNewPosts(data, function(postsCreated) {
|
||||
done();
|
||||
});
|
||||
hidePostToolsForDeletedPosts();
|
||||
} else {
|
||||
navigator.update();
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Topic;
|
||||
});
|
@ -1,95 +0,0 @@
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, translator, config, socket, ajaxify */
|
||||
|
||||
define('forum/topic/browsing', function() {
|
||||
|
||||
var Browsing = {};
|
||||
|
||||
Browsing.onUpdateUsersInRoom = function(data) {
|
||||
if(data && data.room.indexOf('topic_' + ajaxify.variables.get('topic_id')) !== -1) {
|
||||
for(var i=0; i<data.users.length; ++i) {
|
||||
addUserIcon(data.users[i]);
|
||||
}
|
||||
getReplyingUsers();
|
||||
}
|
||||
};
|
||||
|
||||
Browsing.onUserEnter = function(data) {
|
||||
var activeEl = $('.thread_active_users');
|
||||
var user = activeEl.find('a[data-uid="' + data.uid + '"]');
|
||||
if (!user.length && activeEl.children().length < 10) {
|
||||
addUserIcon(data);
|
||||
} else {
|
||||
user.attr('data-count', parseInt(user.attr('data-count'), 10) + 1);
|
||||
}
|
||||
};
|
||||
|
||||
Browsing.onUserLeave = function(uid) {
|
||||
var activeEl = $('.thread_active_users');
|
||||
var user = activeEl.find('a[data-uid="' + uid + '"]');
|
||||
if (user.length) {
|
||||
var count = Math.max(0, parseInt(user.attr('data-count'), 10) - 1);
|
||||
user.attr('data-count', count);
|
||||
if (count <= 0) {
|
||||
user.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Browsing.onUserStatusChange = function(data) {
|
||||
updateOnlineIcon($('.username-field[data-uid="' + data.uid + '"]'), data.status);
|
||||
|
||||
updateBrowsingUsers(data);
|
||||
};
|
||||
|
||||
function updateOnlineIcon(el, status) {
|
||||
translator.translate('[[global:' + status + ']]', function(translated) {
|
||||
el.siblings('i')
|
||||
.attr('class', 'fa fa-circle status ' + status)
|
||||
.attr('title', translated)
|
||||
.attr('data-original-title', translated);
|
||||
});
|
||||
}
|
||||
|
||||
function updateBrowsingUsers(data) {
|
||||
var activeEl = $('.thread_active_users');
|
||||
var user = activeEl.find('a[data-uid="'+ data.uid + '"]');
|
||||
if (user.length && data.status === 'offline') {
|
||||
user.parent().remove();
|
||||
}
|
||||
}
|
||||
|
||||
function addUserIcon(user) {
|
||||
if (!user.userslug) {
|
||||
return;
|
||||
}
|
||||
var activeEl = $('.thread_active_users');
|
||||
var userEl = createUserIcon(user.uid, user.picture, user.userslug, user.username);
|
||||
activeEl.append(userEl);
|
||||
activeEl.find('a[data-uid] img').tooltip({
|
||||
placement: 'top'
|
||||
});
|
||||
}
|
||||
|
||||
function createUserIcon(uid, picture, userslug, username) {
|
||||
if(!$('.thread_active_users').find('[data-uid="' + uid + '"]').length) {
|
||||
return $('<div class="inline-block"><a data-uid="' + uid + '" data-count="1" href="' + config.relative_path + '/user/' + userslug + '"><img title="' + username + '" src="'+ picture +'"/></a></div>');
|
||||
}
|
||||
}
|
||||
|
||||
function getReplyingUsers() {
|
||||
var activeEl = $('.thread_active_users');
|
||||
socket.emit('modules.composer.getUsersByTid', ajaxify.variables.get('topic_id'), function(err, uids) {
|
||||
if (uids && uids.length) {
|
||||
for(var x=0;x<uids.length;x++) {
|
||||
activeEl.find('[data-uid="' + uids[x] + '"]').addClass('replying');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Browsing;
|
||||
});
|
@ -1,180 +0,0 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* globals app, ajaxify, define, socket, translator, templates */
|
||||
|
||||
define('forum/topic/events', ['forum/topic/browsing', 'forum/topic/postTools', 'forum/topic/threadTools'], function(browsing, postTools, threadTools) {
|
||||
|
||||
var Events = {};
|
||||
|
||||
var events = {
|
||||
'event:update_users_in_room': browsing.onUpdateUsersInRoom,
|
||||
'event:user_enter': browsing.onUserEnter,
|
||||
'event:user_leave': browsing.onUserLeave,
|
||||
'event:user_status_change': browsing.onUserStatusChange,
|
||||
'event:voted': updatePostVotesAndUserReputation,
|
||||
'event:favourited': updateFavouriteCount,
|
||||
|
||||
'event:topic_deleted': toggleTopicDeleteState,
|
||||
'event:topic_restored': toggleTopicDeleteState,
|
||||
'event:topic_purged': onTopicPurged,
|
||||
|
||||
'event:topic_locked': threadTools.setLockedState,
|
||||
'event:topic_unlocked': threadTools.setLockedState,
|
||||
|
||||
'event:topic_pinned': threadTools.setPinnedState,
|
||||
'event:topic_unpinned': threadTools.setPinnedState,
|
||||
|
||||
'event:topic_moved': onTopicMoved,
|
||||
|
||||
'event:post_edited': onPostEdited,
|
||||
'event:post_purged': onPostPurged,
|
||||
|
||||
'event:post_deleted': togglePostDeleteState,
|
||||
'event:post_restored': togglePostDeleteState,
|
||||
|
||||
'posts.favourite': togglePostFavourite,
|
||||
'posts.unfavourite': togglePostFavourite,
|
||||
|
||||
'posts.upvote': togglePostVote,
|
||||
'posts.downvote': togglePostVote,
|
||||
'posts.unvote': togglePostVote,
|
||||
|
||||
'event:topic.toggleReply': toggleReply,
|
||||
};
|
||||
|
||||
Events.init = function() {
|
||||
Events.removeListeners();
|
||||
for(var eventName in events) {
|
||||
if (events.hasOwnProperty(eventName)) {
|
||||
socket.on(eventName, events[eventName]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Events.removeListeners = function() {
|
||||
for(var eventName in events) {
|
||||
if (events.hasOwnProperty(eventName)) {
|
||||
socket.removeListener(eventName, events[eventName]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function updatePostVotesAndUserReputation(data) {
|
||||
var votes = $('li[data-pid="' + data.post.pid + '"] .votes'),
|
||||
reputationElements = $('.reputation[data-uid="' + data.post.uid + '"]');
|
||||
|
||||
votes.html(data.post.votes).attr('data-votes', data.post.votes);
|
||||
reputationElements.html(data.user.reputation).attr('data-reputation', data.user.reputation);
|
||||
}
|
||||
|
||||
function updateFavouriteCount(data) {
|
||||
$('li[data-pid="' + data.post.pid + '"] .favouriteCount').html(data.post.reputation).attr('data-favourites', data.post.reputation);
|
||||
}
|
||||
|
||||
function toggleTopicDeleteState(data) {
|
||||
threadTools.setLockedState(data);
|
||||
threadTools.setDeleteState(data);
|
||||
}
|
||||
|
||||
function onTopicPurged(tid) {
|
||||
ajaxify.go('category/' + ajaxify.variables.get('category_id'));
|
||||
}
|
||||
|
||||
function onTopicMoved(data) {
|
||||
if (data && data.tid > 0) {
|
||||
ajaxify.go('topic/' + data.tid);
|
||||
}
|
||||
}
|
||||
|
||||
function onPostEdited(data) {
|
||||
var editedPostEl = $('#content_' + data.pid),
|
||||
editedPostTitle = $('#topic_title_' + data.pid);
|
||||
|
||||
if (editedPostTitle.length) {
|
||||
editedPostTitle.fadeOut(250, function() {
|
||||
editedPostTitle.html(data.title).fadeIn(250);
|
||||
});
|
||||
}
|
||||
|
||||
editedPostEl.fadeOut(250, function() {
|
||||
editedPostEl.html(data.content);
|
||||
editedPostEl.find('img').addClass('img-responsive');
|
||||
app.replaceSelfLinks(editedPostEl.find('a'));
|
||||
editedPostEl.fadeIn(250);
|
||||
|
||||
$(window).trigger('action:posts.edited');
|
||||
});
|
||||
|
||||
if (data.tags && data.tags.length !== $('.tags').first().children().length) {
|
||||
ajaxify.loadTemplate('partials/post_bar', function(postBarTemplate) {
|
||||
var html = templates.parse(templates.getBlock(postBarTemplate, 'tags'), {
|
||||
tags: data.tags
|
||||
});
|
||||
var tags = $('.tags');
|
||||
tags.fadeOut(250, function() {
|
||||
tags.html(html).fadeIn(250);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onPostPurged(pid) {
|
||||
$('#post-container li[data-pid="' + pid + '"]').fadeOut(500, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
function togglePostDeleteState(data) {
|
||||
var postEl = $('#post-container li[data-pid="' + data.pid + '"]');
|
||||
|
||||
if (!postEl.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
postEl.toggleClass('deleted');
|
||||
var isDeleted = postEl.hasClass('deleted');
|
||||
postTools.toggle(data.pid, isDeleted);
|
||||
|
||||
if (!app.isAdmin && parseInt(data.uid, 10) !== parseInt(app.uid, 10)) {
|
||||
if (isDeleted) {
|
||||
postEl.find('.post-content').translateHtml('[[topic:post_is_deleted]]');
|
||||
} else {
|
||||
postEl.find('.post-content').html(data.content);
|
||||
}
|
||||
}
|
||||
|
||||
postTools.updatePostCount();
|
||||
}
|
||||
|
||||
function togglePostFavourite(data) {
|
||||
var favBtn = $('li[data-pid="' + data.post.pid + '"] .favourite');
|
||||
if (!favBtn.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
favBtn.addClass('btn-warning')
|
||||
.attr('data-favourited', data.isFavourited);
|
||||
|
||||
var icon = favBtn.find('i');
|
||||
var className = icon.attr('class');
|
||||
|
||||
if (data.isFavourited ? className.indexOf('-o') !== -1 : className.indexOf('-o') === -1) {
|
||||
icon.attr('class', data.isFavourited ? className.replace('-o', '') : className + '-o');
|
||||
}
|
||||
}
|
||||
|
||||
function togglePostVote(data) {
|
||||
var post = $('li[data-pid="' + data.post.pid + '"]');
|
||||
|
||||
post.find('.upvote').toggleClass('btn-primary upvoted', data.upvote);
|
||||
post.find('.downvote').toggleClass('btn-primary downvoted', data.downvote);
|
||||
}
|
||||
|
||||
function toggleReply(data) {
|
||||
$('.thread_active_users [data-uid="' + data.uid + '"]').toggleClass('replying', data.isReplying);
|
||||
}
|
||||
|
||||
return Events;
|
||||
|
||||
});
|
@ -1,136 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, translator, socket */
|
||||
|
||||
define('forum/topic/fork', function() {
|
||||
|
||||
var Fork = {},
|
||||
forkModal,
|
||||
forkCommit,
|
||||
pids = [];
|
||||
|
||||
Fork.init = function() {
|
||||
$('.fork_thread').on('click', onForkThreadClicked);
|
||||
};
|
||||
|
||||
function disableClicks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function disableClicksOnPosts() {
|
||||
$('.post-row').on('click', 'button,a', disableClicks);
|
||||
}
|
||||
|
||||
function enableClicksOnPosts() {
|
||||
$('.post-row').off('click', 'button,a', disableClicks);
|
||||
}
|
||||
|
||||
function onForkThreadClicked() {
|
||||
forkModal = $('#fork-thread-modal');
|
||||
forkCommit = forkModal.find('#fork_thread_commit');
|
||||
pids.length = 0;
|
||||
|
||||
showForkModal();
|
||||
showNoPostsSelected();
|
||||
|
||||
forkModal.find('.close,#fork_thread_cancel').on('click', closeForkModal);
|
||||
forkModal.find('#fork-title').on('change', checkForkButtonEnable);
|
||||
$('#post-container').on('click', 'li[data-pid]', function() {
|
||||
togglePostSelection($(this));
|
||||
});
|
||||
|
||||
disableClicksOnPosts();
|
||||
|
||||
forkCommit.on('click', createTopicFromPosts);
|
||||
}
|
||||
|
||||
function showForkModal() {
|
||||
forkModal.removeClass('hide')
|
||||
.css('position', 'fixed')
|
||||
.css('left', Math.max(0, (($(window).width() - $(forkModal).outerWidth()) / 2) + $(window).scrollLeft()) + 'px')
|
||||
.css('top', '0px')
|
||||
.css('z-index', '2000');
|
||||
}
|
||||
|
||||
function createTopicFromPosts() {
|
||||
socket.emit('topics.createTopicFromPosts', {
|
||||
title: forkModal.find('#fork-title').val(),
|
||||
pids: pids
|
||||
}, function(err, newTopic) {
|
||||
function fadeOutAndRemove(pid) {
|
||||
$('#post-container li[data-pid="' + pid + '"]').fadeOut(500, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alert({
|
||||
timeout: 5000,
|
||||
title: '[[global:alert.success]]',
|
||||
message: '[[topic:fork_success]]',
|
||||
type: 'success',
|
||||
clickfn: function() {
|
||||
ajaxify.go('topic/' + newTopic.slug);
|
||||
}
|
||||
});
|
||||
|
||||
for(var i=0; i<pids.length; ++i) {
|
||||
fadeOutAndRemove(pids[i]);
|
||||
}
|
||||
closeForkModal();
|
||||
});
|
||||
}
|
||||
|
||||
function togglePostSelection(post) {
|
||||
var newPid = post.attr('data-pid');
|
||||
|
||||
if(parseInt(post.attr('data-index'), 10) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(newPid) {
|
||||
var index = pids.indexOf(newPid);
|
||||
if(index === -1) {
|
||||
pids.push(newPid);
|
||||
post.css('opacity', '0.5');
|
||||
} else {
|
||||
pids.splice(index, 1);
|
||||
post.css('opacity', '1.0');
|
||||
}
|
||||
|
||||
if(pids.length) {
|
||||
pids.sort();
|
||||
forkModal.find('#fork-pids').html(pids.toString());
|
||||
} else {
|
||||
showNoPostsSelected();
|
||||
}
|
||||
checkForkButtonEnable();
|
||||
}
|
||||
}
|
||||
|
||||
function showNoPostsSelected() {
|
||||
forkModal.find('#fork-pids').translateHtml('[[topic:fork_no_pids]]');
|
||||
}
|
||||
|
||||
function checkForkButtonEnable() {
|
||||
if(forkModal.find('#fork-title').length && pids.length) {
|
||||
forkCommit.removeAttr('disabled');
|
||||
} else {
|
||||
forkCommit.attr('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
function closeForkModal() {
|
||||
for(var i=0; i<pids.length; ++i) {
|
||||
$('#post-container li[data-pid="' + pids[i] + '"]').css('opacity', 1);
|
||||
}
|
||||
forkModal.addClass('hide');
|
||||
$('#post-container').off('click', 'li[data-pid]');
|
||||
enableClicksOnPosts();
|
||||
}
|
||||
|
||||
return Fork;
|
||||
});
|
@ -1,100 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket */
|
||||
|
||||
define('forum/topic/move', function() {
|
||||
|
||||
var Move = {},
|
||||
modal,
|
||||
targetCid,
|
||||
targetCategoryLabel;
|
||||
|
||||
Move.init = function(tids, currentCid, onComplete) {
|
||||
modal = $('#move_thread_modal');
|
||||
|
||||
Move.tids = tids;
|
||||
Move.currentCid = currentCid;
|
||||
Move.onComplete = onComplete;
|
||||
Move.moveAll = tids ? false : true;
|
||||
|
||||
modal.on('shown.bs.modal', onMoveModalShown);
|
||||
$('#move-confirm').hide();
|
||||
|
||||
if (Move.moveAll || (tids && tids.length > 1)) {
|
||||
modal.find('.modal-header h3').translateText('[[topic:move_topics]]');
|
||||
}
|
||||
|
||||
modal.modal('show');
|
||||
};
|
||||
|
||||
function onMoveModalShown() {
|
||||
var loadingEl = $('#categories-loading');
|
||||
if (!loadingEl.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('categories.get', onCategoriesLoaded);
|
||||
}
|
||||
|
||||
function onCategoriesLoaded(err, categories) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
renderCategories(categories);
|
||||
|
||||
modal.on('click', '.category-list li[data-cid]', function(e) {
|
||||
selectCategory($(this));
|
||||
});
|
||||
|
||||
$('#move_thread_commit').on('click', onCommitClicked);
|
||||
}
|
||||
|
||||
function selectCategory(category) {
|
||||
modal.find('#confirm-category-name').html(category.html());
|
||||
$('#move-confirm').show();
|
||||
|
||||
targetCid = category.attr('data-cid');
|
||||
targetCategoryLabel = category.html();
|
||||
$('#move_thread_commit').prop('disabled', false);
|
||||
}
|
||||
|
||||
function onCommitClicked() {
|
||||
var commitEl = $('#move_thread_commit');
|
||||
|
||||
if (!commitEl.prop('disabled') && targetCid) {
|
||||
commitEl.prop('disabled', true);
|
||||
|
||||
moveTopics();
|
||||
}
|
||||
}
|
||||
|
||||
function moveTopics() {
|
||||
socket.emit(Move.moveAll ? 'topics.moveAll' : 'topics.move', {
|
||||
tids: Move.tids,
|
||||
cid: targetCid,
|
||||
currentCid: Move.currentCid
|
||||
}, function(err) {
|
||||
modal.modal('hide');
|
||||
$('#move_thread_commit').prop('disabled', false);
|
||||
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[topic:topic_move_success, ' + targetCategoryLabel + ']]');
|
||||
if (typeof Move.onComplete === 'function') {
|
||||
Move.onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderCategories(categories) {
|
||||
templates.parse('partials/category_list', {categories: categories}, function(html) {
|
||||
modal.find('.modal-body').prepend(html);
|
||||
$('#categories-loading').remove();
|
||||
});
|
||||
}
|
||||
|
||||
return Move;
|
||||
});
|
@ -1,322 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, translator, ajaxify, socket, bootbox */
|
||||
|
||||
define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(composer, share, navigator) {
|
||||
|
||||
var PostTools = {},
|
||||
topicName;
|
||||
|
||||
PostTools.init = function(tid, threadState) {
|
||||
topicName = ajaxify.variables.get('topic_name');
|
||||
|
||||
addPostHandlers(tid, threadState);
|
||||
|
||||
share.addShareHandlers(topicName);
|
||||
|
||||
addVoteHandler();
|
||||
};
|
||||
|
||||
PostTools.toggle = function(pid, isDeleted) {
|
||||
var postEl = $('#post-container li[data-pid="' + pid + '"]');
|
||||
|
||||
postEl.find('.quote, .favourite, .post_reply, .chat').toggleClass('hidden', isDeleted);
|
||||
postEl.find('.purge').toggleClass('hidden', !isDeleted);
|
||||
postEl.find('.delete .i').toggleClass('fa-trash-o', !isDeleted).toggleClass('fa-history', isDeleted);
|
||||
postEl.find('.delete span').translateHtml(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]');
|
||||
};
|
||||
|
||||
PostTools.updatePostCount = function() {
|
||||
socket.emit('topics.postcount', ajaxify.variables.get('topic_id'), function(err, postCount) {
|
||||
if (!err) {
|
||||
$('.topic-post-count').html(postCount);
|
||||
navigator.setCount(postCount);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function addVoteHandler() {
|
||||
$('#post-container').on('mouseenter', '.post-row .votes', function() {
|
||||
loadDataAndCreateTooltip($(this), 'posts.getUpvoters');
|
||||
});
|
||||
}
|
||||
|
||||
function loadDataAndCreateTooltip(el, method) {
|
||||
var pid = el.parents('.post-row').attr('data-pid');
|
||||
socket.emit(method, pid, function(err, data) {
|
||||
if (!err) {
|
||||
createTooltip(el, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createTooltip(el, data) {
|
||||
var usernames = data.usernames;
|
||||
if (!usernames.length) {
|
||||
return;
|
||||
}
|
||||
if (usernames.length + data.otherCount > 6) {
|
||||
usernames = usernames.join(', ').replace(/,/g, '|');
|
||||
translator.translate('[[topic:users_and_others, ' + usernames + ', ' + data.otherCount + ']]', function(translated) {
|
||||
translated = translated.replace(/\|/g, ',');
|
||||
el.attr('title', translated).tooltip('destroy').tooltip('show');
|
||||
});
|
||||
} else {
|
||||
usernames = usernames.join(', ');
|
||||
el.attr('title', usernames).tooltip('destroy').tooltip('show');
|
||||
}
|
||||
}
|
||||
|
||||
function addPostHandlers(tid, threadState) {
|
||||
$('.topic').on('click', '.post_reply', function() {
|
||||
if (!threadState.locked) {
|
||||
onReplyClicked($(this), tid, topicName);
|
||||
}
|
||||
});
|
||||
|
||||
var postContainer = $('#post-container');
|
||||
|
||||
postContainer.on('click', '.quote', function() {
|
||||
if (!threadState.locked) {
|
||||
onQuoteClicked($(this), tid, topicName);
|
||||
}
|
||||
});
|
||||
|
||||
postContainer.on('click', '.favourite', function() {
|
||||
favouritePost($(this), getData($(this), 'data-pid'));
|
||||
});
|
||||
|
||||
postContainer.on('click', '.upvote', function() {
|
||||
return toggleVote($(this), '.upvoted', 'posts.upvote');
|
||||
});
|
||||
|
||||
postContainer.on('click', '.downvote', function() {
|
||||
return toggleVote($(this), '.downvoted', 'posts.downvote');
|
||||
});
|
||||
|
||||
postContainer.on('click', '.flag', function() {
|
||||
flagPost(getData($(this), 'data-pid'));
|
||||
});
|
||||
|
||||
postContainer.on('click', '.edit', function(e) {
|
||||
composer.editPost(getData($(this), 'data-pid'));
|
||||
});
|
||||
|
||||
postContainer.on('click', '.delete', function(e) {
|
||||
deletePost($(this), tid);
|
||||
});
|
||||
|
||||
postContainer.on('click', '.purge', function(e) {
|
||||
purgePost($(this), tid);
|
||||
});
|
||||
|
||||
postContainer.on('click', '.move', function(e) {
|
||||
openMovePostModal($(this));
|
||||
});
|
||||
|
||||
postContainer.on('click', '.chat', function(e) {
|
||||
openChat($(this));
|
||||
});
|
||||
}
|
||||
|
||||
function onReplyClicked(button, tid, topicName) {
|
||||
var selectionText = '',
|
||||
selection = window.getSelection ? window.getSelection() : document.selection.createRange();
|
||||
|
||||
if ($(selection.baseNode).parents('.post-content').length > 0) {
|
||||
var snippet = selection.toString();
|
||||
if (snippet.length) {
|
||||
selectionText = '> ' + snippet.replace(/\n/g, '\n> ') + '\n\n';
|
||||
}
|
||||
}
|
||||
|
||||
var username = getUserName(selectionText ? $(selection.baseNode) : button);
|
||||
if (getData(button, 'data-uid') === '0') {
|
||||
username = '';
|
||||
}
|
||||
if (selectionText.length) {
|
||||
composer.addQuote(tid, ajaxify.variables.get('topic_slug'), getData(button, 'data-index'), getData(button, 'data-pid'), topicName, username, selectionText);
|
||||
} else {
|
||||
composer.newReply(tid, getData(button, 'data-pid'), topicName, username ? username + ' ' : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onQuoteClicked(button, tid, topicName) {
|
||||
var username = getUserName(button),
|
||||
pid = getData(button, 'data-pid');
|
||||
|
||||
socket.emit('posts.getRawPost', pid, function(err, post) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
var quoted = '';
|
||||
if(post) {
|
||||
quoted = '> ' + post.replace(/\n/g, '\n> ') + '\n\n';
|
||||
}
|
||||
|
||||
if($('.composer').length) {
|
||||
composer.addQuote(tid, ajaxify.variables.get('topic_slug'), getData(button, 'data-index'), pid, topicName, username, quoted);
|
||||
} else {
|
||||
composer.newReply(tid, pid, topicName, '[[modules:composer.user_said, ' + username + ']]\n' + quoted);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function favouritePost(button, pid) {
|
||||
var method = button.attr('data-favourited') === 'false' ? 'posts.favourite' : 'posts.unfavourite';
|
||||
|
||||
socket.emit(method, {
|
||||
pid: pid,
|
||||
room_id: app.currentRoom
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function toggleVote(button, className, method) {
|
||||
var post = button.parents('.post-row'),
|
||||
currentState = post.find(className).length;
|
||||
|
||||
socket.emit(currentState ? 'posts.unvote' : method , {
|
||||
pid: post.attr('data-pid'),
|
||||
room_id: app.currentRoom
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getData(button, data) {
|
||||
return button.parents('.post-row').attr(data);
|
||||
}
|
||||
|
||||
function getUserName(button) {
|
||||
var username = '',
|
||||
post = button.parents('li[data-pid]');
|
||||
|
||||
if (post.length) {
|
||||
username = post.attr('data-username').replace(/\s/g, '-');
|
||||
}
|
||||
if (post.length && post.attr('data-uid') !== '0') {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
function deletePost(button, tid) {
|
||||
var pid = getData(button, 'data-pid'),
|
||||
postEl = $('#post-container li[data-pid="' + pid + '"]'),
|
||||
action = !postEl.hasClass('deleted') ? 'delete' : 'restore';
|
||||
|
||||
postAction(action, pid, tid);
|
||||
}
|
||||
|
||||
function purgePost(button, tid) {
|
||||
postAction('purge', getData(button, 'data-pid'), tid);
|
||||
}
|
||||
|
||||
function postAction(action, pid, tid) {
|
||||
translator.translate('[[topic:post_' + action + '_confirm]]', function(msg) {
|
||||
bootbox.confirm(msg, function(confirm) {
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('posts.' + action, {
|
||||
pid: pid,
|
||||
tid: tid
|
||||
}, function(err) {
|
||||
if(err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openMovePostModal(button) {
|
||||
var moveModal = $('#move-post-modal'),
|
||||
moveBtn = moveModal.find('#move_post_commit'),
|
||||
topicId = moveModal.find('#topicId');
|
||||
|
||||
showMoveModal();
|
||||
|
||||
moveModal.find('.close,#move_post_cancel').on('click', function() {
|
||||
moveModal.addClass('hide');
|
||||
});
|
||||
|
||||
topicId.on('change', function() {
|
||||
if(topicId.val().length) {
|
||||
moveBtn.removeAttr('disabled');
|
||||
} else {
|
||||
moveBtn.attr('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
moveBtn.on('click', function() {
|
||||
movePost(button.parents('.post-row'), getData(button, 'data-pid'), topicId.val());
|
||||
});
|
||||
}
|
||||
|
||||
function showMoveModal() {
|
||||
$('#move-post-modal').removeClass('hide')
|
||||
.css("position", "fixed")
|
||||
.css("left", Math.max(0, (($(window).width() - $($('#move-post-modal')).outerWidth()) / 2) + $(window).scrollLeft()) + "px")
|
||||
.css("top", "0px")
|
||||
.css("z-index", "2000");
|
||||
}
|
||||
|
||||
function movePost(post, pid, tid) {
|
||||
socket.emit('topics.movePost', {pid: pid, tid: tid}, function(err) {
|
||||
$('#move-post-modal').addClass('hide');
|
||||
|
||||
if(err) {
|
||||
$('#topicId').val('');
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
post.fadeOut(500, function() {
|
||||
post.remove();
|
||||
});
|
||||
|
||||
$('#topicId').val('');
|
||||
|
||||
app.alertSuccess('[[topic:post_moved]]');
|
||||
});
|
||||
}
|
||||
|
||||
function flagPost(pid) {
|
||||
translator.translate('[[topic:flag_confirm]]', function(message) {
|
||||
bootbox.confirm(message, function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('posts.flag', pid, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[topic:flag_success]]');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openChat(button) {
|
||||
var post = button.parents('li.post-row');
|
||||
|
||||
app.openChat(post.attr('data-username'), post.attr('data-uid'));
|
||||
button.parents('.btn-group').find('.dropdown-toggle').click();
|
||||
return false;
|
||||
}
|
||||
|
||||
return PostTools;
|
||||
});
|
@ -1,169 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, translator, ajaxify, socket, bootbox */
|
||||
|
||||
define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], function(fork, move) {
|
||||
|
||||
var ThreadTools = {};
|
||||
|
||||
ThreadTools.init = function(tid, threadState) {
|
||||
ThreadTools.threadState = threadState;
|
||||
|
||||
if (threadState.locked) {
|
||||
ThreadTools.setLockedState({tid: tid, isLocked: true});
|
||||
}
|
||||
|
||||
if (threadState.deleted) {
|
||||
ThreadTools.setDeleteState({tid: tid, isDelete: true});
|
||||
}
|
||||
|
||||
if (threadState.pinned) {
|
||||
ThreadTools.setPinnedState({tid: tid, isPinned: true});
|
||||
}
|
||||
|
||||
$('.delete_thread').on('click', function() {
|
||||
topicCommand(threadState.deleted ? 'restore' : 'delete', tid);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.purge_thread').on('click', function() {
|
||||
topicCommand('purge', tid);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.lock_thread').on('click', function() {
|
||||
socket.emit(threadState.locked ? 'topics.unlock' : 'topics.lock', {tids: [tid], cid: ajaxify.variables.get('category_id')});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.pin_thread').on('click', function() {
|
||||
socket.emit(threadState.pinned ? 'topics.unpin' : 'topics.pin', {tids: [tid], cid: ajaxify.variables.get('category_id')});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.markAsUnreadForAll').on('click', function() {
|
||||
var btn = $(this);
|
||||
socket.emit('topics.markAsUnreadForAll', [tid], function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.alertSuccess('[[topic:markAsUnreadForAll.success]]');
|
||||
btn.parents('.thread-tools.open').find('.dropdown-toggle').trigger('click');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.move_thread').on('click', function(e) {
|
||||
move.init([tid], ajaxify.variables.get('category_id'));
|
||||
return false;
|
||||
});
|
||||
|
||||
fork.init();
|
||||
|
||||
$('.posts').on('click', '.follow', function() {
|
||||
socket.emit('topics.follow', tid, function(err, state) {
|
||||
if(err) {
|
||||
return app.alert({
|
||||
type: 'danger',
|
||||
alert_id: 'topic_follow',
|
||||
title: '[[global:please_log_in]]',
|
||||
message: '[[topic:login_to_subscribe]]',
|
||||
timeout: 5000
|
||||
});
|
||||
}
|
||||
|
||||
setFollowState(state);
|
||||
|
||||
app.alert({
|
||||
alert_id: 'follow_thread',
|
||||
message: state ? '[[topic:following_topic.message]]' : '[[topic:not_following_topic.message]]',
|
||||
type: 'success',
|
||||
timeout: 5000
|
||||
});
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function topicCommand(command, tid) {
|
||||
translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function(msg) {
|
||||
bootbox.confirm(msg, function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('topics.' + command, {tids: [tid], cid: ajaxify.variables.get('category_id')});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ThreadTools.setLockedState = function(data) {
|
||||
var threadEl = $('#post-container');
|
||||
if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) {
|
||||
var isLocked = data.isLocked && !app.isAdmin;
|
||||
|
||||
$('.lock_thread').translateHtml('<i class="fa fa-fw fa-' + (data.isLocked ? 'un': '') + 'lock"></i> [[topic:thread_tools.' + (data.isLocked ? 'un': '') + 'lock]]');
|
||||
|
||||
translator.translate(isLocked ? '[[topic:locked]]' : '[[topic:reply]]', function(translated) {
|
||||
var className = isLocked ? 'fa-lock' : 'fa-reply';
|
||||
threadEl.find('.post_reply').html('<i class="fa ' + className + '"></i> ' + translated);
|
||||
$('.topic-main-buttons .post_reply').attr('disabled', isLocked).html(isLocked ? '<i class="fa fa-lock"></i> ' + translated : translated);
|
||||
});
|
||||
|
||||
threadEl.find('.quote, .edit, .delete').toggleClass('hidden', isLocked);
|
||||
$('.topic-title i.fa-lock').toggleClass('hide', !data.isLocked);
|
||||
ThreadTools.threadState.locked = data.isLocked;
|
||||
}
|
||||
};
|
||||
|
||||
ThreadTools.setDeleteState = function(data) {
|
||||
var threadEl = $('#post-container');
|
||||
if (parseInt(data.tid, 10) !== parseInt(threadEl.attr('data-tid'), 10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.delete_thread span').translateHtml('<i class="fa fa-fw ' + (data.isDelete ? 'fa-history' : 'fa-trash-o') + '"></i> [[topic:thread_tools.' + (data.isDelete ? 'restore' : 'delete') + ']]');
|
||||
|
||||
threadEl.toggleClass('deleted', data.isDelete);
|
||||
ThreadTools.threadState.deleted = data.isDelete;
|
||||
$('.purge_thread').toggleClass('hidden', !data.isDelete);
|
||||
|
||||
if (data.isDelete) {
|
||||
translator.translate('[[topic:deleted_message]]', function(translated) {
|
||||
$('<div id="thread-deleted" class="alert alert-warning">' + translated + '</div>').insertBefore(threadEl);
|
||||
});
|
||||
} else {
|
||||
$('#thread-deleted').remove();
|
||||
}
|
||||
};
|
||||
|
||||
ThreadTools.setPinnedState = function(data) {
|
||||
var threadEl = $('#post-container');
|
||||
if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) {
|
||||
translator.translate('<i class="fa fa-fw fa-thumb-tack"></i> [[topic:thread_tools.' + (data.isPinned ? 'unpin' : 'pin') + ']]', function(translated) {
|
||||
$('.pin_thread').html(translated);
|
||||
ThreadTools.threadState.pinned = data.isPinned;
|
||||
});
|
||||
$('.topic-title i.fa-thumb-tack').toggleClass('hide', !data.isPinned);
|
||||
}
|
||||
};
|
||||
|
||||
function setFollowState(state) {
|
||||
var title = state ? '[[topic:unwatch.title]]' : '[[topic:watch.title]]';
|
||||
var iconClass = state ? 'fa fa-eye-slash' : 'fa fa-eye';
|
||||
var text = state ? '[[topic:unwatch]]' : '[[topic:watch]]';
|
||||
|
||||
var followEl = $('.posts .follow');
|
||||
|
||||
translator.translate(title, function(titleTranslated) {
|
||||
followEl.attr('title', titleTranslated).find('i').attr('class', iconClass);
|
||||
followEl.find('span').text(text);
|
||||
|
||||
translator.translate(followEl.html(), function(translated) {
|
||||
followEl.html(translated);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return ThreadTools;
|
||||
});
|
@ -1,151 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, app, socket */
|
||||
|
||||
define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], function(recent, topicSelect, infinitescroll) {
|
||||
var Unread = {};
|
||||
|
||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||
if(data.url.indexOf('unread') !== 0) {
|
||||
recent.removeListeners();
|
||||
}
|
||||
});
|
||||
|
||||
Unread.init = function() {
|
||||
app.enterRoom('recent_posts');
|
||||
|
||||
$('#new-topics-alert').on('click', function() {
|
||||
$(this).addClass('hide');
|
||||
});
|
||||
|
||||
recent.watchForNewPosts();
|
||||
|
||||
$('#markSelectedRead').on('click', function() {
|
||||
var tids = topicSelect.getSelectedTids();
|
||||
if(!tids.length) {
|
||||
return;
|
||||
}
|
||||
socket.emit('topics.markAsRead', tids, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
doneRemovingTids(tids);
|
||||
});
|
||||
});
|
||||
|
||||
$('#markAllRead').on('click', function() {
|
||||
socket.emit('topics.markAllRead', function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
app.alertSuccess('[[unread:topics_marked_as_read.success]]');
|
||||
|
||||
$('#topics-container').empty();
|
||||
$('#category-no-topics').removeClass('hidden');
|
||||
$('.markread').addClass('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
$('.markread').on('click', '.category', function() {
|
||||
function getCategoryTids(cid) {
|
||||
var tids = [];
|
||||
$('#topics-container .category-item[data-cid="' + cid + '"]').each(function() {
|
||||
tids.push($(this).attr('data-tid'));
|
||||
});
|
||||
return tids;
|
||||
}
|
||||
var cid = $(this).attr('data-cid');
|
||||
var tids = getCategoryTids(cid);
|
||||
|
||||
socket.emit('topics.markCategoryTopicsRead', cid, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
doneRemovingTids(tids);
|
||||
});
|
||||
});
|
||||
|
||||
socket.emit('categories.get', onCategoriesLoaded);
|
||||
|
||||
topicSelect.init();
|
||||
|
||||
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) {
|
||||
$('#load-more-btn').show();
|
||||
}
|
||||
|
||||
$('#load-more-btn').on('click', function() {
|
||||
loadMoreTopics();
|
||||
});
|
||||
|
||||
infinitescroll.init(loadMoreTopics);
|
||||
|
||||
function loadMoreTopics(direction) {
|
||||
if(direction < 0 || !$('#topics-container').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('topics.loadMoreUnreadTopics', {
|
||||
after: $('#topics-container').attr('data-nextstart')
|
||||
}, function(data, done) {
|
||||
if (data.topics && data.topics.length) {
|
||||
recent.onTopicsLoaded('unread', data.topics, true, done);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
done();
|
||||
$('#load-more-btn').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function doneRemovingTids(tids) {
|
||||
removeTids(tids);
|
||||
|
||||
app.alertSuccess('[[unread:topics_marked_as_read.success]]');
|
||||
|
||||
if (!$('#topics-container').children().length) {
|
||||
$('#category-no-topics').removeClass('hidden');
|
||||
$('.markread').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function removeTids(tids) {
|
||||
for(var i=0; i<tids.length; ++i) {
|
||||
$('#topics-container .category-item[data-tid="' + tids[i] + '"]').remove();
|
||||
}
|
||||
}
|
||||
|
||||
function onCategoriesLoaded(err, categories) {
|
||||
createCategoryLinks(categories);
|
||||
}
|
||||
|
||||
function createCategoryLinks(categories) {
|
||||
categories = categories.filter(function(category) {
|
||||
return !category.disabled;
|
||||
});
|
||||
|
||||
for(var i=0; i<categories.length; ++i) {
|
||||
createCategoryLink(categories[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function createCategoryLink(category) {
|
||||
|
||||
var link = $('<a role="menuitem" href="#"></a>');
|
||||
if (category.icon) {
|
||||
link.append('<i class="fa fa-fw ' + category.icon + '"></i> ' + category.name);
|
||||
} else {
|
||||
link.append(category.name);
|
||||
}
|
||||
|
||||
|
||||
$('<li role="presentation" class="category" data-cid="' + category.cid + '"></li>')
|
||||
.append(link)
|
||||
.appendTo($('.markread .dropdown-menu'));
|
||||
}
|
||||
|
||||
return Unread;
|
||||
});
|
@ -1,186 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals define, socket, app, ajaxify, templates, translator*/
|
||||
|
||||
define('forum/users', function() {
|
||||
var Users = {};
|
||||
|
||||
var loadingMoreUsers = false;
|
||||
|
||||
Users.init = function() {
|
||||
|
||||
var active = getActiveSection();
|
||||
|
||||
$('.nav-pills li').removeClass('active');
|
||||
$('.nav-pills li a').each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.attr('href').match(active)) {
|
||||
$this.parent().addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
handleSearch();
|
||||
|
||||
socket.removeListener('event:user_status_change', onUserStatusChange);
|
||||
socket.on('event:user_status_change', onUserStatusChange);
|
||||
|
||||
$('#load-more-users-btn').on('click', loadMoreUsers);
|
||||
|
||||
$(window).off('scroll').on('scroll', function() {
|
||||
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||
|
||||
if ($(window).scrollTop() > bottom && !loadingMoreUsers) {
|
||||
loadMoreUsers();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function loadMoreUsers() {
|
||||
var set = '';
|
||||
var activeSection = getActiveSection();
|
||||
if (activeSection === 'latest') {
|
||||
set = 'users:joindate';
|
||||
} else if (activeSection === 'sort-posts') {
|
||||
set = 'users:postcount';
|
||||
} else if (activeSection === 'sort-reputation') {
|
||||
set = 'users:reputation';
|
||||
} else if (activeSection === 'online' || activeSection === 'users') {
|
||||
set = 'users:online';
|
||||
}
|
||||
|
||||
if (set) {
|
||||
startLoading(set, $('#users-container').children('.registered-user').length);
|
||||
}
|
||||
}
|
||||
|
||||
function startLoading(set, after) {
|
||||
loadingMoreUsers = true;
|
||||
|
||||
socket.emit('user.loadMore', {
|
||||
set: set,
|
||||
after: after
|
||||
}, function(err, data) {
|
||||
if (data && data.users.length) {
|
||||
onUsersLoaded(data.users);
|
||||
$('#load-more-users-btn').removeClass('disabled');
|
||||
} else {
|
||||
$('#load-more-users-btn').addClass('disabled');
|
||||
}
|
||||
loadingMoreUsers = false;
|
||||
});
|
||||
}
|
||||
|
||||
function onUsersLoaded(users) {
|
||||
users = users.filter(function(user) {
|
||||
return !$('.users-box[data-uid="' + user.uid + '"]').length;
|
||||
});
|
||||
|
||||
ajaxify.loadTemplate('users', function(usersTemplate) {
|
||||
var html = templates.parse(templates.getBlock(usersTemplate, 'users'), {users: users});
|
||||
|
||||
translator.translate(html, function(translated) {
|
||||
$('#users-container').append(translated);
|
||||
$('#users-container .anon-user').appendTo($('#users-container'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
var timeoutId = 0;
|
||||
var lastSearch = null;
|
||||
|
||||
$('#search-user').on('keyup', function() {
|
||||
if (timeoutId !== 0) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = 0;
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(function() {
|
||||
function reset() {
|
||||
notify.html('<i class="fa fa-search"></i>');
|
||||
notify.parent().removeClass('btn-warning label-warning btn-success label-success');
|
||||
}
|
||||
var username = $('#search-user').val();
|
||||
var notify = $('#user-notfound-notify');
|
||||
|
||||
if (username === '') {
|
||||
notify.html('<i class="fa fa-circle-o"></i>');
|
||||
notify.parent().removeClass('btn-warning label-warning btn-success label-success');
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastSearch === username) {
|
||||
return;
|
||||
}
|
||||
lastSearch = username;
|
||||
|
||||
notify.html('<i class="fa fa-spinner fa-spin"></i>');
|
||||
|
||||
socket.emit('user.search', username, function(err, data) {
|
||||
if (err) {
|
||||
reset();
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
ajaxify.loadTemplate('users', function(usersTemplate) {
|
||||
var html = templates.parse(templates.getBlock(usersTemplate, 'users'), data);
|
||||
|
||||
translator.translate(html, function(translated) {
|
||||
$('#users-container').html(translated);
|
||||
if (!data.users.length) {
|
||||
translator.translate('[[error:no-user]]', function(translated) {
|
||||
notify.html(translated);
|
||||
notify.parent().addClass('btn-warning label-warning');
|
||||
});
|
||||
} else {
|
||||
translator.translate('[[users:users-found-search-took, ' + data.users.length + ', ' + data.timing + ']]', function(translated) {
|
||||
notify.html(translated);
|
||||
notify.parent().addClass('btn-success label-success');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
|
||||
function onUserStatusChange(data) {
|
||||
var section = getActiveSection();
|
||||
if((section.indexOf('online') === 0 || section.indexOf('users') === 0)) {
|
||||
updateUser(data);
|
||||
}
|
||||
}
|
||||
|
||||
function updateUser(data) {
|
||||
if (data.status === 'offline') {
|
||||
return;
|
||||
}
|
||||
var usersContainer = $('#users-container');
|
||||
var userEl = usersContainer.find('li[data-uid="' + data.uid +'"]');
|
||||
|
||||
if (userEl.length) {
|
||||
var statusEl = userEl.find('.status');
|
||||
translator.translate('[[global:' + data.status + ']]', function(translated) {
|
||||
statusEl.attr('class', 'fa fa-circle status ' + data.status)
|
||||
.attr('title', translated)
|
||||
.attr('data-original-title', translated);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getActiveSection() {
|
||||
var url = window.location.href,
|
||||
parts = url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
return Users;
|
||||
});
|
Loading…
Reference in New Issue