Merge branch 'master' of github.com:ipetepete/NodeBB

v1.18.x
Peter Peterson 12 years ago
commit 3968877b1e

@ -76,6 +76,9 @@ var ajaxify = {};
templates.flush(); templates.flush();
templates.load_template(function () { templates.load_template(function () {
exec_body_scripts(content); exec_body_scripts(content);
require(['forum/' + tpl_url], function(script) {
if (script && script.init) script.init();
});
if (callback) { if (callback) {
callback(); callback();

@ -1,85 +1,92 @@
(function() { define(['forum/accountheader'], function(header) {
var yourid = templates.get('yourid'), var Account = {};
theirid = templates.get('theirid'),
isFollowing = templates.get('isFollowing');
$(document).ready(function() { Account.init = function() {
var username = $('.account-username a').html(); header.init();
app.enter_room('user/' + theirid);
app.addCommasToNumbers(); var yourid = templates.get('yourid'),
theirid = templates.get('theirid'),
isFollowing = templates.get('isFollowing');
var followBtn = $('#follow-btn'); $(document).ready(function() {
var unfollowBtn = $('#unfollow-btn'); var username = $('.account-username a').html();
app.enter_room('user/' + theirid);
if (yourid !== theirid) { app.addCommasToNumbers();
if (isFollowing) {
followBtn.hide();
unfollowBtn.show();
} else {
followBtn.show();
unfollowBtn.hide();
}
} else {
followBtn.hide();
unfollowBtn.hide();
}
followBtn.on('click', function() { var followBtn = $('#follow-btn');
socket.emit('api:user.follow', { var unfollowBtn = $('#unfollow-btn');
uid: theirid
}, function(success) { if (yourid !== theirid) {
if (success) { if (isFollowing) {
followBtn.hide(); followBtn.hide();
unfollowBtn.show(); unfollowBtn.show();
app.alertSuccess('You are now following ' + username + '!');
} else { } else {
app.alertError('There was an error following' + username + '!');
}
});
return false;
});
unfollowBtn.on('click', function() {
socket.emit('api:user.unfollow', {
uid: theirid
}, function(success) {
if (success) {
followBtn.show(); followBtn.show();
unfollowBtn.hide(); unfollowBtn.hide();
app.alertSuccess('You are no longer following ' + username + '!');
} else {
app.alertError('There was an error unfollowing ' + username + '!');
} }
} else {
followBtn.hide();
unfollowBtn.hide();
}
followBtn.on('click', function() {
socket.emit('api:user.follow', {
uid: theirid
}, function(success) {
if (success) {
followBtn.hide();
unfollowBtn.show();
app.alertSuccess('You are now following ' + username + '!');
} else {
app.alertError('There was an error following' + username + '!');
}
});
return false;
}); });
return false;
});
$('.user-recent-posts .topic-row').on('click', function() { unfollowBtn.on('click', function() {
ajaxify.go($(this).attr('topic-url')); socket.emit('api:user.unfollow', {
}); uid: theirid
}, function(success) {
if (success) {
followBtn.show();
unfollowBtn.hide();
app.alertSuccess('You are no longer following ' + username + '!');
} else {
app.alertError('There was an error unfollowing ' + username + '!');
}
});
return false;
});
var onlineStatus = $('.account-online-status'); $('.user-recent-posts .topic-row').on('click', function() {
ajaxify.go($(this).attr('topic-url'));
});
function handleUserOnline(data) { socket.on('api:user.isOnline', Account.handleUserOnline);
if (data.online) {
onlineStatus.find('span span').text('online');
onlineStatus.find('i').attr('class', 'icon-circle');
} else {
onlineStatus.find('span span').text('offline');
onlineStatus.find('i').attr('class', 'icon-circle-blank');
}
}
socket.on('api:user.isOnline', handleUserOnline); socket.emit('api:user.isOnline', theirid, Account.handleUserOnline);
socket.emit('api:user.isOnline', theirid, handleUserOnline); socket.on('event:new_post', function(data) {
var html = templates.prepare(templates['account'].blocks['posts']).parse(data);
$('.user-recent-posts').prepend(html);
});
socket.on('event:new_post', function(data) {
var html = templates.prepare(templates['account'].blocks['posts']).parse(data);
$('.user-recent-posts').prepend(html);
}); });
};
}); Account.handleUserOnline = function(data) {
var onlineStatus = $('.account-online-status');
if (data.online) {
onlineStatus.find('span span').text('online');
onlineStatus.find('i').attr('class', 'icon-circle');
} else {
onlineStatus.find('span span').text('offline');
onlineStatus.find('i').attr('class', 'icon-circle-blank');
}
};
}()); return Account;
});

@ -1,88 +1,258 @@
var gravatarPicture = templates.get('gravatarpicture'); define(['forum/accountheader'], function(header) {
var uploadedPicture = templates.get('uploadedpicture'); var AccountEdit = {};
$(document).ready(function() { AccountEdit.init = function() {
header.init();
var gravatarPicture = templates.get('gravatarpicture');
var uploadedPicture = templates.get('uploadedpicture');
$('#uploadForm').submit(function() {
AccountEdit.status('uploading the file ...');
$('#uploadForm').submit(function() { $('#upload-progress-bar').css('width', '0%');
status('uploading the file ...'); $('#upload-progress-box').show();
$('#upload-progress-box').removeClass('hide');
$('#upload-progress-bar').css('width', '0%'); if (!$('#userPhotoInput').val()) {
$('#upload-progress-box').show(); AccountEdit.error('select an image to upload!');
$('#upload-progress-box').removeClass('hide'); return false;
}
$(this).find('#imageUploadCsrf').val($('#csrf_token').val());
if (!$('#userPhotoInput').val()) {
error('select an image to upload!');
return false;
}
$(this).find('#imageUploadCsrf').val($('#csrf_token').val()); $(this).ajaxSubmit({
error: function(xhr) {
AccountEdit.error('Error: ' + xhr.status);
},
$(this).ajaxSubmit({ uploadProgress: function(event, position, total, percent) {
console.log(percent);
$('#upload-progress-bar').css('width', percent + '%');
},
error: function(xhr) {
error('Error: ' + xhr.status);
},
uploadProgress: function(event, position, total, percent) { success: function(response) {
console.log(percent); if (response.error) {
$('#upload-progress-bar').css('width', percent + '%'); AccountEdit.error(response.error);
}, return;
}
var imageUrlOnServer = response.path;
success: function(response) { $('#user-current-picture').attr('src', imageUrlOnServer);
if (response.error) { $('#user-uploaded-picture').attr('src', imageUrlOnServer);
error(response.error);
return; uploadedPicture = imageUrlOnServer;
setTimeout(function() {
AccountEdit.hideAlerts();
$('#upload-picture-modal').modal('hide');
}, 750);
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']
});
AccountEdit.success('File uploaded successfully!');
} }
});
var imageUrlOnServer = response.path; return false;
});
$('#user-current-picture').attr('src', imageUrlOnServer); var selectedImageType = '';
$('#user-uploaded-picture').attr('src', imageUrlOnServer);
$('#submitBtn').on('click', function() {
var userData = {
uid: $('#inputUID').val(),
email: $('#inputEmail').val(),
fullname: $('#inputFullname').val(),
website: $('#inputWebsite').val(),
birthday: $('#inputBirthday').val(),
location: $('#inputLocation').val(),
signature: $('#inputSignature').val()
};
socket.emit('api:user.updateProfile', userData, function(err, data) {
if (data.success) {
app.alertSuccess('Your profile has been updated successfully!');
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;
}
} else {
app.alertError('There was an error updating your profile! ' + err.error);
}
});
return false;
});
$('#changePictureBtn').on('click', function() {
selectedImageType = '';
AccountEdit.updateImages();
uploadedPicture = imageUrlOnServer; $('#change-picture-modal').modal('show');
$('#change-picture-modal').removeClass('hide');
setTimeout(function() { return false;
hideAlerts(); });
$('#upload-picture-modal').modal('hide');
}, 750); $('#gravatar-box').on('click', function() {
$('#gravatar-box .icon-ok').show();
$('#uploaded-box .icon-ok').hide();
selectedImageType = 'gravatar';
});
socket.emit('api:updateHeader', { $('#uploaded-box').on('click', function() {
fields: ['username', 'picture', 'userslug'] $('#gravatar-box .icon-ok').hide();
}); $('#uploaded-box .icon-ok').show();
success('File uploaded successfully!'); selectedImageType = 'uploaded';
});
$('#savePictureChangesBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
if (selectedImageType) {
AccountEdit.changeUserPicture(selectedImageType);
if (selectedImageType == 'gravatar')
$('#user-current-picture').attr('src', gravatarPicture);
else if (selectedImageType == 'uploaded')
$('#user-current-picture').attr('src', uploadedPicture);
} }
});
$('#upload-picture-modal').on('hide', function() {
$('#userPhotoInput').val('');
});
$('#uploadPictureBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
$('#upload-picture-modal').modal('show');
$('#upload-picture-modal').removeClass('hide');
AccountEdit.hideAlerts();
return false;
});
$('#pictureUploadSubmitBtn').on('click', function() {
$('#uploadForm').submit();
}); });
return false; (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;
function onPasswordChanged() {
passwordvalid = utils.isPasswordValid(password.val());
if (password.val().length < config.minimumPasswordLength) {
password_notify.html('Password too short');
password_notify.attr('class', 'alert alert-danger');
password_notify.removeClass('hide');
} else if (!passwordvalid) {
password_notify.html('Invalid password');
password_notify.attr('class', 'alert alert-danger');
password_notify.removeClass('hide');
} else {
password_notify.html('OK!');
password_notify.attr('class', 'alert alert-success');
password_notify.removeClass('hide');
}
onPasswordConfirmChanged();
}
function onPasswordConfirmChanged() {
if (password_notify.hasClass('alert-danger') || !password_confirm.val()) {
password_confirm_notify.addClass('hide');
return;
}
if (password.val() !== password_confirm.val()) {
password_confirm_notify.html('Passwords must match!');
password_confirm_notify.attr('class', 'alert alert-danger');
password_confirm_notify.removeClass('hide');
passwordsmatch = false;
} else {
password_confirm_notify.html('OK!');
password_confirm_notify.attr('class', 'alert alert-success');
password_confirm_notify.removeClass('hide');
passwordsmatch = true;
}
}
password.on('blur', onPasswordChanged);
password_confirm.on('blur', onPasswordConfirmChanged);
function hideAlerts() { $('#changePasswordBtn').on('click', function() {
if (passwordvalid && passwordsmatch && currentPassword.val()) {
socket.emit('api:user.changePassword', {
'currentPassword': currentPassword.val(),
'newPassword': password.val()
}, function(err) {
currentPassword.val('');
password.val('');
password_confirm.val('');
password_notify.addClass('hide');
password_confirm_notify.addClass('hide');
passwordsmatch = false;
passwordvalid = false;
if (err) {
app.alertError(err.error);
return;
}
app.alertSuccess('Your password is updated!');
});
}
return false;
});
}());
};
AccountEdit.hideAlerts = function() {
$('#alert-status').addClass('hide'); $('#alert-status').addClass('hide');
$('#alert-success').addClass('hide'); $('#alert-success').addClass('hide');
$('#alert-error').addClass('hide'); $('#alert-error').addClass('hide');
$('#upload-progress-box').addClass('hide'); $('#upload-progress-box').addClass('hide');
} }
function status(message) { AccountEdit.status = function(message) {
hideAlerts(); AccountEdit.hideAlerts();
$('#alert-status').text(message).removeClass('hide'); $('#alert-status').text(message).removeClass('hide');
} }
function success(message) { AccountEdit.success = function(message) {
hideAlerts(); AccountEdit.hideAlerts();
$('#alert-success').text(message).removeClass('hide'); $('#alert-success').text(message).removeClass('hide');
} }
function error(message) { AccountEdit.error = function(message) {
hideAlerts(); AccountEdit.hideAlerts();
$('#alert-error').text(message).removeClass('hide'); $('#alert-error').text(message).removeClass('hide');
} }
function changeUserPicture(type) { AccountEdit.changeUserPicture = function(type) {
var userData = { var userData = {
type: type type: type
}; };
@ -94,40 +264,10 @@ $(document).ready(function() {
}); });
} }
var selectedImageType = ''; AccountEdit.updateImages = function() {
$('#submitBtn').on('click', function() {
var userData = {
uid: $('#inputUID').val(),
email: $('#inputEmail').val(),
fullname: $('#inputFullname').val(),
website: $('#inputWebsite').val(),
birthday: $('#inputBirthday').val(),
location: $('#inputLocation').val(),
signature: $('#inputSignature').val()
};
socket.emit('api:user.updateProfile', userData, function(err, data) {
if (data.success) {
app.alertSuccess('Your profile has been updated successfully!');
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;
}
} else {
app.alertError('There was an error updating your profile! ' + err.error);
}
});
return false;
});
function updateImages() {
var currentPicture = $('#user-current-picture').attr('src'); var currentPicture = $('#user-current-picture').attr('src');
var gravatarPicture = templates.get('gravatarpicture');
var uploadedPicture = templates.get('uploadedpicture');
if (gravatarPicture) { if (gravatarPicture) {
$('#user-gravatar-picture').attr('src', gravatarPicture); $('#user-gravatar-picture').attr('src', gravatarPicture);
@ -153,139 +293,5 @@ $(document).ready(function() {
$('#uploaded-box .icon-ok').hide(); $('#uploaded-box .icon-ok').hide();
} }
return AccountEdit;
$('#changePictureBtn').on('click', function() {
selectedImageType = '';
updateImages();
$('#change-picture-modal').modal('show');
$('#change-picture-modal').removeClass('hide');
return false;
});
$('#gravatar-box').on('click', function() {
$('#gravatar-box .icon-ok').show();
$('#uploaded-box .icon-ok').hide();
selectedImageType = 'gravatar';
});
$('#uploaded-box').on('click', function() {
$('#gravatar-box .icon-ok').hide();
$('#uploaded-box .icon-ok').show();
selectedImageType = 'uploaded';
});
$('#savePictureChangesBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
if (selectedImageType) {
changeUserPicture(selectedImageType);
if (selectedImageType == 'gravatar')
$('#user-current-picture').attr('src', gravatarPicture);
else if (selectedImageType == 'uploaded')
$('#user-current-picture').attr('src', uploadedPicture);
}
});
$('#upload-picture-modal').on('hide', function() {
$('#userPhotoInput').val('');
});
$('#uploadPictureBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
$('#upload-picture-modal').modal('show');
$('#upload-picture-modal').removeClass('hide');
hideAlerts();
return false;
});
$('#pictureUploadSubmitBtn').on('click', function() {
$('#uploadForm').submit();
});
(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;
function onPasswordChanged() {
passwordvalid = utils.isPasswordValid(password.val());
if (password.val().length < config.minimumPasswordLength) {
password_notify.html('Password too short');
password_notify.attr('class', 'alert alert-danger');
password_notify.removeClass('hide');
} else if (!passwordvalid) {
password_notify.html('Invalid password');
password_notify.attr('class', 'alert alert-danger');
password_notify.removeClass('hide');
} else {
password_notify.html('OK!');
password_notify.attr('class', 'alert alert-success');
password_notify.removeClass('hide');
}
onPasswordConfirmChanged();
}
function onPasswordConfirmChanged() {
if (password_notify.hasClass('alert-danger') || !password_confirm.val()) {
password_confirm_notify.addClass('hide');
return;
}
if (password.val() !== password_confirm.val()) {
password_confirm_notify.html('Passwords must match!');
password_confirm_notify.attr('class', 'alert alert-danger');
password_confirm_notify.removeClass('hide');
passwordsmatch = false;
} else {
password_confirm_notify.html('OK!');
password_confirm_notify.attr('class', 'alert alert-success');
password_confirm_notify.removeClass('hide');
passwordsmatch = true;
}
}
password.on('blur', onPasswordChanged);
password_confirm.on('blur', onPasswordConfirmChanged);
$('#changePasswordBtn').on('click', function() {
if (passwordvalid && passwordsmatch && currentPassword.val()) {
socket.emit('api:user.changePassword', {
'currentPassword': currentPassword.val(),
'newPassword': password.val()
}, function(err) {
currentPassword.val('');
password.val('');
password_confirm.val('');
password_notify.addClass('hide');
password_confirm_notify.addClass('hide');
passwordsmatch = false;
passwordvalid = false;
if (err) {
app.alertError(err.error);
return;
}
app.alertSuccess('Your password is updated!');
});
}
return false;
});
}());
}); });

@ -1,24 +1,11 @@
(function() { define(function() {
var yourid = templates.get('yourid'), var AccountHeader = {};
theirid = templates.get('theirid');
AccountHeader.init = function() {
var yourid = templates.get('yourid'),
theirid = templates.get('theirid');
function createMenu() { AccountHeader.createMenu();
var userslug = $('.account-username-box').attr('data-userslug');
var links = $('<div class="account-sub-links inline-block pull-right">\
<span id="settingsLink" class="pull-right"><a href="/user/' + userslug + '/settings">settings</a></span>\
<span id="favouritesLink" class="pull-right"><a href="/user/' + userslug + '/favourites">favourites</a></span>\
<span class="pull-right"><a href="/user/' + userslug + '/followers">followers</a></span>\
<span class="pull-right"><a href="/user/' + userslug + '/following">following</a></span>\
<span id="editLink" class="pull-right"><a href="/user/' + userslug + '/edit">edit</a></span>\
</div>');
$('.account-username-box').append(links);
}
$(document).ready(function() {
createMenu();
var editLink = $('#editLink'); var editLink = $('#editLink');
var settingsLink = $('#settingsLink'); var settingsLink = $('#settingsLink');
@ -37,6 +24,20 @@
return false; return false;
} }
}); });
}); }
AccountHeader.createMenu = function() {
var userslug = $('.account-username-box').attr('data-userslug');
var links = $('<div class="account-sub-links inline-block pull-right">\
<span id="settingsLink" class="pull-right"><a href="/user/' + userslug + '/settings">settings</a></span>\
<span id="favouritesLink" class="pull-right"><a href="/user/' + userslug + '/favourites">favourites</a></span>\
<span class="pull-right"><a href="/user/' + userslug + '/followers">followers</a></span>\
<span class="pull-right"><a href="/user/' + userslug + '/following">following</a></span>\
<span id="editLink" class="pull-right"><a href="/user/' + userslug + '/edit">edit</a></span>\
</div>');
$('.account-username-box').append(links);
}
}()); return AccountHeader;
});

@ -1,19 +1,25 @@
$(document).ready(function() { define(['forum/accountheader'], function(header) {
var AccountSettings = {};
$('#submitBtn').on('click', function() { AccountSettings.init = function() {
header.init();
var settings = { $('#submitBtn').on('click', function() {
showemail: $('#showemailCheckBox').is(':checked') ? 1 : 0
};
socket.emit('api:user.saveSettings', settings, function(success) { var settings = {
if (success) { showemail: $('#showemailCheckBox').is(':checked') ? 1 : 0
app.alertSuccess('Settings saved!'); };
} else {
app.alertError('There was an error saving settings!'); socket.emit('api:user.saveSettings', settings, function(success) {
} if (success) {
app.alertSuccess('Settings saved!');
} else {
app.alertError('There was an error saving settings!');
}
});
return false;
}); });
return false; };
});
return AccountSettings;
}); });

@ -1,139 +1,144 @@
var modified_categories = {}; define(function() {
var Categories = {};
function modified(el) { Categories.init = function() {
var cid = $(el).parents('li').attr('data-cid'); var modified_categories = {};
modified_categories[cid] = modified_categories[cid] || {}; function modified(el) {
modified_categories[cid][$(el).attr('data-name')] = $(el).val(); var cid = $(el).parents('li').attr('data-cid');
}
function save() { modified_categories[cid] = modified_categories[cid] || {};
socket.emit('api:admin.categories.update', modified_categories); modified_categories[cid][$(el).attr('data-name')] = $(el).val();
modified_categories = {};
}
function select_icon(el) {
var selected = el.attr('class').replace(' icon-2x', '');
jQuery('#icons .selected').removeClass('selected');
if (selected)
jQuery('#icons .' + selected).parent().addClass('selected');
bootbox.confirm('<h2>Select an icon.</h2>' + document.getElementById('icons').innerHTML, function(confirm) {
if (confirm) {
var iconClass = jQuery('.bootbox .selected').children(':first').attr('class');
el.attr('class', iconClass + ' icon-2x');
el.val(iconClass);
modified(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
jQuery('.bootbox .col-md-3').on('click', function() {
jQuery('.bootbox .selected').removeClass('selected');
jQuery(this).addClass('selected');
});
}, 500);
}
function save() {
socket.emit('api:admin.categories.update', modified_categories);
modified_categories = {};
}
function update_blockclass(el) { function select_icon(el) {
el.parentNode.parentNode.className = 'entry-row ' + el.value; var selected = el.attr('class').replace(' icon-2x', '');
} jQuery('#icons .selected').removeClass('selected');
if (selected)
jQuery('#icons .' + selected).parent().addClass('selected');
jQuery('#entry-container').sortable();
jQuery('.blockclass').each(function() {
jQuery(this).val(this.getAttribute('data-value'));
});
bootbox.confirm('<h2>Select an icon.</h2>' + document.getElementById('icons').innerHTML, function(confirm) {
if (confirm) {
var iconClass = jQuery('.bootbox .selected').children(':first').attr('class');
el.attr('class', iconClass + ' icon-2x');
el.val(iconClass);
//DRY Failure. this needs to go into an ajaxify onready style fn. Currently is copy pasted into every single function so after ACP is off the ground fix asap modified(el);
(function() { }
function showCreateCategoryModal() { });
$('#new-category-modal').modal();
}
function createNewCategory() {
var category = {
name: $('#inputName').val(),
description: $('#inputDescription').val(),
icon: $('#new-category-modal i').attr('value'),
blockclass: $('#inputBlockclass').val()
};
socket.emit('api:admin.categories.create', category, function(err, data) {
if (!err) {
app.alert({
alert_id: 'category_created',
title: 'Created',
message: 'Category successfully created!',
type: 'success',
timeout: 2000
});
var html = templates.prepare(templates['admin/categories'].blocks['categories']).parse({ setTimeout(function() { //bootbox was rewritten for BS3 and I had to add this timeout for the previous code to work. TODO: to look into
categories: [data] jQuery('.bootbox .col-md-3').on('click', function() {
jQuery('.bootbox .selected').removeClass('selected');
jQuery(this).addClass('selected');
}); });
$('#entry-container').append(html); }, 500);
}
$('#new-category-modal').modal('hide');
}
});
}
jQuery('document').ready(function() {
var url = window.location.href,
parts = url.split('/'),
active = parts[parts.length - 1];
jQuery('.nav-pills li').removeClass('active');
jQuery('.nav-pills li a').each(function() {
if (this.getAttribute('href').match(active)) {
jQuery(this.parentNode).addClass('active');
return false;
}
});
jQuery('#save').on('click', save);
jQuery('#addNew').on('click', showCreateCategoryModal);
jQuery('#create-category-btn').on('click', createNewCategory);
jQuery('#entry-container').on('click', '.icon', function(ev) { function update_blockclass(el) {
select_icon($(this).find('i')); el.parentNode.parentNode.className = 'entry-row ' + el.value;
}); }
jQuery('.blockclass').on('change', function(ev) {
update_blockclass(ev.target);
});
jQuery('.category_name, .category_description, .blockclass').on('change', function(ev) { jQuery('#entry-container').sortable();
modified(ev.target); jQuery('.blockclass').each(function() {
jQuery(this).val(this.getAttribute('data-value'));
}); });
jQuery('.entry-row button').each(function(index, element) {
var disabled = $(element).attr('data-disabled');
if (disabled == "0" || disabled == "")
$(element).html('Disable');
else
$(element).html('Enable');
}); //DRY Failure. this needs to go into an ajaxify onready style fn. Currently is copy pasted into every single function so after ACP is off the ground fix asap
function showCreateCategoryModal() {
$('#new-category-modal').modal();
}
jQuery('.entry-row button').on('click', function(ev) { function createNewCategory() {
var btn = jQuery(this); var category = {
var categoryRow = btn.parents('li'); name: $('#inputName').val(),
var cid = categoryRow.attr('data-cid'); description: $('#inputDescription').val(),
icon: $('#new-category-modal i').attr('value'),
blockclass: $('#inputBlockclass').val()
};
socket.emit('api:admin.categories.create', category, function(err, data) {
if (!err) {
app.alert({
alert_id: 'category_created',
title: 'Created',
message: 'Category successfully created!',
type: 'success',
timeout: 2000
});
var html = templates.prepare(templates['admin/categories'].blocks['categories']).parse({
categories: [data]
});
$('#entry-container').append(html);
$('#new-category-modal').modal('hide');
}
});
}
var disabled = btn.html() == "Disable" ? "1" : "0"; jQuery('document').ready(function() {
categoryRow.remove(); var url = window.location.href,
modified_categories[cid] = modified_categories[cid] || {}; parts = url.split('/'),
modified_categories[cid]['disabled'] = disabled; active = parts[parts.length - 1];
jQuery('.nav-pills li').removeClass('active');
jQuery('.nav-pills li a').each(function() {
if (this.getAttribute('href').match(active)) {
jQuery(this.parentNode).addClass('active');
return false;
}
});
jQuery('#save').on('click', save);
jQuery('#addNew').on('click', showCreateCategoryModal);
jQuery('#create-category-btn').on('click', createNewCategory);
jQuery('#entry-container').on('click', '.icon', function(ev) {
select_icon($(this).find('i'));
});
jQuery('.blockclass').on('change', function(ev) {
update_blockclass(ev.target);
});
jQuery('.category_name, .category_description, .blockclass').on('change', function(ev) {
modified(ev.target);
});
jQuery('.entry-row button').each(function(index, element) {
var disabled = $(element).attr('data-disabled');
if (disabled == "0" || disabled == "")
$(element).html('Disable');
else
$(element).html('Enable');
});
jQuery('.entry-row button').on('click', function(ev) {
var btn = jQuery(this);
var categoryRow = btn.parents('li');
var cid = categoryRow.attr('data-cid');
var disabled = btn.html() == "Disable" ? "1" : "0";
categoryRow.remove();
modified_categories[cid] = modified_categories[cid] || {};
modified_categories[cid]['disabled'] = disabled;
save();
return false;
});
save();
return false;
}); });
};
}); return Categories;
});
}());

@ -1,121 +1,44 @@
var nodebb_admin = (function(nodebb_admin) { jQuery('document').ready(function() {
// On menu click, change "active" state
nodebb_admin.config = undefined; var menuEl = document.querySelector('.sidebar-nav'),
liEls = menuEl.querySelectorAll('li')
nodebb_admin.prepare = function() { parentEl = null;
// Come back in 500ms if the config isn't ready yet
if (nodebb_admin.config === undefined) { menuEl.addEventListener('click', function(e) {
setTimeout(function() { parentEl = e.target.parentNode;
nodebb_admin.prepare(); if (parentEl.nodeName === 'LI') {
}, 500); for (var x = 0, numLis = liEls.length; x < numLis; x++) {
return; if (liEls[x] !== parentEl) jQuery(liEls[x]).removeClass('active');
} else jQuery(parentEl).addClass('active');
// Populate the fields on the page from the config
var fields = document.querySelectorAll('#content [data-field]'),
numFields = fields.length,
saveBtn = document.getElementById('save'),
x, key, inputType;
for (x = 0; x < numFields; x++) {
key = fields[x].getAttribute('data-field');
inputType = fields[x].getAttribute('type');
if (fields[x].nodeName === 'INPUT') {
if (nodebb_admin.config[key]) {
switch (inputType) {
case 'text':
case 'textarea':
case 'number':
fields[x].value = nodebb_admin.config[key];
break;
case 'checkbox':
fields[x].checked = nodebb_admin.config[key] === '1' ? true : false;
break;
}
}
} else if (fields[x].nodeName === 'TEXTAREA') {
if (nodebb_admin.config[key]) fields[x].value = nodebb_admin.config[key];
} }
} }
}, false);
});
saveBtn.addEventListener('click', function(e) { socket.once('api:config.get', function(config) {
var key, value; require(['forum/admin/settings'], function(Settings) {
e.preventDefault(); Settings.config = config;
});
for (x = 0; x < numFields; x++) { });
key = fields[x].getAttribute('data-field');
if (fields[x].nodeName === 'INPUT') { socket.emit('api:config.get');
inputType = fields[x].getAttribute('type');
switch (inputType) { socket.on('api:config.set', function(data) {
case 'text': if (data.status === 'ok') {
case 'number': app.alert({
value = fields[x].value; alert_id: 'config_status',
break; timeout: 2500,
title: 'Changes Saved',
case 'checkbox': message: 'Your changes to the NodeBB configuration have been saved.',
value = fields[x].checked ? '1' : '0'; type: 'success'
break; });
} } else {
} else if (fields[x].nodeName === 'TEXTAREA') { app.alert({
value = fields[x].value; alert_id: 'config_status',
} timeout: 2500,
title: 'Changes Not Saved',
socket.emit('api:config.set', { message: 'NodeBB encountered a problem saving your changes',
key: key, type: 'danger'
value: value
});
}
}); });
} }
});
nodebb_admin.remove = function(key) {
socket.emit('api:config.remove', key);
}
jQuery('document').ready(function() {
// On menu click, change "active" state
var menuEl = document.querySelector('.sidebar-nav'),
liEls = menuEl.querySelectorAll('li')
parentEl = null;
menuEl.addEventListener('click', function(e) {
parentEl = e.target.parentNode;
if (parentEl.nodeName === 'LI') {
for (var x = 0, numLis = liEls.length; x < numLis; x++) {
if (liEls[x] !== parentEl) jQuery(liEls[x]).removeClass('active');
else jQuery(parentEl).addClass('active');
}
}
}, false);
});
socket.once('api:config.get', function(config) {
nodebb_admin.config = config;
});
socket.emit('api:config.get');
socket.on('api:config.set', function(data) {
if (data.status === 'ok') {
app.alert({
alert_id: 'config_status',
timeout: 2500,
title: 'Changes Saved',
message: 'Your changes to the NodeBB configuration have been saved.',
type: 'success'
});
} else {
app.alert({
alert_id: 'config_status',
timeout: 2500,
title: 'Changes Not Saved',
message: 'NodeBB encountered a problem saving your changes',
type: 'danger'
});
}
});
return nodebb_admin;
}(nodebb_admin || {}));

@ -1,194 +1,200 @@
$(document).ready(function() { define(function() {
var createEl = document.getElementById('create'), var Groups = {};
createModal = $('#create-modal'),
createSubmitBtn = document.getElementById('create-modal-go'), Groups.init = function() {
createNameEl = $('#create-group-name'), var createEl = document.getElementById('create'),
detailsModal = $('#group-details-modal'), createModal = $('#create-modal'),
detailsSearch = detailsModal.find('#group-details-search'), createSubmitBtn = document.getElementById('create-modal-go'),
searchResults = detailsModal.find('#group-details-search-results'), createNameEl = $('#create-group-name'),
groupMembersEl = detailsModal.find('ul.current_members'), detailsModal = $('#group-details-modal'),
detailsModalSave = detailsModal.find('.btn-primary'), detailsSearch = detailsModal.find('#group-details-search'),
searchDelay = undefined, searchResults = detailsModal.find('#group-details-search-results'),
listEl = $('#groups-list'); groupMembersEl = detailsModal.find('ul.current_members'),
detailsModalSave = detailsModal.find('.btn-primary'),
createEl.addEventListener('click', function() { searchDelay = undefined,
createModal.modal('show'); listEl = $('#groups-list');
setTimeout(function() {
createNameEl.focus(); createEl.addEventListener('click', function() {
}, 250); createModal.modal('show');
}, false); setTimeout(function() {
createNameEl.focus();
createSubmitBtn.addEventListener('click', function() { }, 250);
var submitObj = { }, false);
name: createNameEl.val(),
description: $('#create-group-desc').val() createSubmitBtn.addEventListener('click', function() {
}, var submitObj = {
errorEl = $('#create-modal-error'), name: createNameEl.val(),
errorText; description: $('#create-group-desc').val()
},
socket.emit('api:groups.create', submitObj, function(err, data) { errorEl = $('#create-modal-error'),
if (err) { errorText;
switch (err) {
case 'group-exists': socket.emit('api:groups.create', submitObj, function(err, data) {
errorText = '<strong>Please choose another name</strong><p>There seems to be a group with this name already.</p>'; if (err) {
break; switch (err) {
case 'name-too-short': case 'group-exists':
errorText = '<strong>Please specify a grou name</strong><p>A group name is required for administrative purposes.</p>'; errorText = '<strong>Please choose another name</strong><p>There seems to be a group with this name already.</p>';
break; break;
default: case 'name-too-short':
errorText = '<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>'; errorText = '<strong>Please specify a grou name</strong><p>A group name is required for administrative purposes.</p>';
break; break;
default:
errorText = '<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>';
break;
}
errorEl.html(errorText).removeClass('hide');
} else {
createModal.modal('hide');
errorEl.addClass('hide');
createNameEl.val('');
ajaxify.go('admin/groups');
} }
});
});
errorEl.html(errorText).removeClass('hide'); listEl.on('click', 'button[data-action]', function() {
} else { var action = this.getAttribute('data-action'),
createModal.modal('hide'); gid = $(this).parents('li[data-gid]').attr('data-gid');
errorEl.addClass('hide');
createNameEl.val(''); switch (action) {
ajaxify.go('admin/groups'); case 'delete':
bootbox.confirm('Are you sure you wish to delete this group?', function(confirm) {
if (confirm) {
socket.emit('api:groups.delete', gid, function(err, data) {
if (data === 'OK') ajaxify.go('admin/groups');
});
}
});
break;
case 'members':
socket.emit('api:groups.get', gid, function(err, groupObj) {
var formEl = detailsModal.find('form'),
nameEl = formEl.find('#change-group-name'),
descEl = formEl.find('#change-group-desc'),
memberIcon = document.createElement('li'),
numMembers = groupObj.members.length,
membersFrag = document.createDocumentFragment(),
memberIconImg, x;
nameEl.val(groupObj.name);
descEl.val(groupObj.description);
// Member list
memberIcon.innerHTML = '<img /><span></span>';
memberIconImg = memberIcon.querySelector('img');
memberIconLabel = memberIcon.querySelector('span');
if (numMembers > 0) {
for (x = 0; x < numMembers; x++) {
memberIconImg.src = groupObj.members[x].picture;
memberIconLabel.innerHTML = groupObj.members[x].username;
memberIcon.setAttribute('data-uid', groupObj.members[x].uid);
membersFrag.appendChild(memberIcon.cloneNode(true));
}
groupMembersEl.html('');
groupMembersEl[0].appendChild(membersFrag);
}
detailsModal.attr('data-gid', groupObj.gid);
detailsModal.modal('show');
});
break;
} }
}); });
});
detailsSearch.on('keyup', function() {
listEl.on('click', 'button[data-action]', function() { var searchEl = this;
var action = this.getAttribute('data-action'),
gid = $(this).parents('li[data-gid]').attr('data-gid'); if (searchDelay) clearTimeout(searchDelay);
switch (action) { searchDelay = setTimeout(function() {
case 'delete': var searchText = searchEl.value,
bootbox.confirm('Are you sure you wish to delete this group?', function(confirm) { resultsEl = document.getElementById('group-details-search-results'),
if (confirm) { foundUser = document.createElement('li'),
socket.emit('api:groups.delete', gid, function(err, data) { foundUserImg, foundUserLabel;
if (data === 'OK') ajaxify.go('admin/groups');
}); foundUser.innerHTML = '<img /><span></span>';
} foundUserImg = foundUser.getElementsByTagName('img')[0];
}); foundUserLabel = foundUser.getElementsByTagName('span')[0];
break;
case 'members': socket.emit('api:admin.user.search', searchText, function(err, results) {
socket.emit('api:groups.get', gid, function(err, groupObj) { if (!err && results && results.length > 0) {
var formEl = detailsModal.find('form'), var numResults = results.length,
nameEl = formEl.find('#change-group-name'), resultsSlug = document.createDocumentFragment(),
descEl = formEl.find('#change-group-desc'), x;
memberIcon = document.createElement('li'), if (numResults > 4) numResults = 4;
numMembers = groupObj.members.length, for (x = 0; x < numResults; x++) {
membersFrag = document.createDocumentFragment(), foundUserImg.src = results[x].picture;
memberIconImg, x; foundUserLabel.innerHTML = results[x].username;
foundUser.setAttribute('title', results[x].username);
foundUser.setAttribute('data-uid', results[x].uid);
nameEl.val(groupObj.name); resultsSlug.appendChild(foundUser.cloneNode(true));
descEl.val(groupObj.description);
// Member list
memberIcon.innerHTML = '<img /><span></span>';
memberIconImg = memberIcon.querySelector('img');
memberIconLabel = memberIcon.querySelector('span');
if (numMembers > 0) {
for (x = 0; x < numMembers; x++) {
memberIconImg.src = groupObj.members[x].picture;
memberIconLabel.innerHTML = groupObj.members[x].username;
memberIcon.setAttribute('data-uid', groupObj.members[x].uid);
membersFrag.appendChild(memberIcon.cloneNode(true));
} }
groupMembersEl.html('');
groupMembersEl[0].appendChild(membersFrag);
}
detailsModal.attr('data-gid', groupObj.gid); resultsEl.innerHTML = '';
detailsModal.modal('show'); resultsEl.appendChild(resultsSlug);
} else resultsEl.innerHTML = '<li>No Users Found</li>';
}); });
break; }, 200);
} });
});
detailsSearch.on('keyup', function() {
var searchEl = this;
if (searchDelay) clearTimeout(searchDelay);
searchDelay = setTimeout(function() {
var searchText = searchEl.value,
resultsEl = document.getElementById('group-details-search-results'),
foundUser = document.createElement('li'),
foundUserImg, foundUserLabel;
foundUser.innerHTML = '<img /><span></span>';
foundUserImg = foundUser.getElementsByTagName('img')[0];
foundUserLabel = foundUser.getElementsByTagName('span')[0];
socket.emit('api:admin.user.search', searchText, function(err, results) {
if (!err && results && results.length > 0) {
var numResults = results.length,
resultsSlug = document.createDocumentFragment(),
x;
if (numResults > 4) numResults = 4;
for (x = 0; x < numResults; x++) {
foundUserImg.src = results[x].picture;
foundUserLabel.innerHTML = results[x].username;
foundUser.setAttribute('title', results[x].username);
foundUser.setAttribute('data-uid', results[x].uid);
resultsSlug.appendChild(foundUser.cloneNode(true));
}
resultsEl.innerHTML = ''; searchResults.on('click', 'li[data-uid]', function() {
resultsEl.appendChild(resultsSlug); var userLabel = this,
} else resultsEl.innerHTML = '<li>No Users Found</li>'; uid = parseInt(this.getAttribute('data-uid')),
}); gid = detailsModal.attr('data-gid'),
}, 200); members = [];
});
searchResults.on('click', 'li[data-uid]', function() { groupMembersEl.find('li[data-uid]').each(function() {
var userLabel = this, members.push(parseInt(this.getAttribute('data-uid')));
uid = parseInt(this.getAttribute('data-uid')), });
gid = detailsModal.attr('data-gid'),
members = [];
groupMembersEl.find('li[data-uid]').each(function() { if (members.indexOf(uid) === -1) {
members.push(parseInt(this.getAttribute('data-uid'))); socket.emit('api:groups.join', {
gid: gid,
uid: uid
}, function(err, data) {
if (!err) {
groupMembersEl.append(userLabel.cloneNode(true));
}
});
}
}); });
if (members.indexOf(uid) === -1) { groupMembersEl.on('click', 'li[data-uid]', function() {
socket.emit('api:groups.join', { var uid = this.getAttribute('data-uid'),
gid = detailsModal.attr('data-gid');
socket.emit('api:groups.leave', {
gid: gid, gid: gid,
uid: uid uid: uid
}, function(err, data) { }, function(err, data) {
if (!err) { if (!err) {
groupMembersEl.append(userLabel.cloneNode(true)); groupMembersEl.find('li[data-uid="' + uid + '"]').remove();
} }
}); });
}
});
groupMembersEl.on('click', 'li[data-uid]', function() {
var uid = this.getAttribute('data-uid'),
gid = detailsModal.attr('data-gid');
socket.emit('api:groups.leave', {
gid: gid,
uid: uid
}, function(err, data) {
if (!err) {
groupMembersEl.find('li[data-uid="' + uid + '"]').remove();
}
}); });
});
detailsModalSave.on('click', function() {
detailsModalSave.on('click', function() { var formEl = detailsModal.find('form'),
var formEl = detailsModal.find('form'), nameEl = formEl.find('#change-group-name'),
nameEl = formEl.find('#change-group-name'), descEl = formEl.find('#change-group-desc'),
descEl = formEl.find('#change-group-desc'), gid = detailsModal.attr('data-gid');
gid = detailsModal.attr('data-gid');
socket.emit('api:groups.update', {
socket.emit('api:groups.update', { gid: gid,
gid: gid, values: {
values: { name: nameEl.val(),
name: nameEl.val(), description: descEl.val()
description: descEl.val() }
} }, function(err) {
}, function(err) { if (!err) {
if (!err) { detailsModal.modal('hide');
detailsModal.modal('hide'); ajaxify.go('admin/groups');
ajaxify.go('admin/groups'); }
} });
}); });
}); };
return Groups;
}); });

@ -1,25 +1,28 @@
define(function() {
var Admin = {};
(function() { Admin.init = function() {
ajaxify.register_events(['api:get_all_rooms']);
socket.on('api:get_all_rooms', function(data) {
ajaxify.register_events(['api:get_all_rooms']); var active_users = document.getElementById('active_users'),
socket.on('api:get_all_rooms', function(data) { total = 0;
active_users.innerHTML = '';
var active_users = document.getElementById('active_users'), for (var room in data) {
total = 0; if (room !== '') {
active_users.innerHTML = ''; var count = data[room].length;
total += count;
for (var room in data) { active_users.innerHTML = active_users.innerHTML + "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>";
if (room !== '') { }
var count = data[room].length;
total += count;
active_users.innerHTML = active_users.innerHTML + "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>";
} }
}
document.getElementById('connections').innerHTML = total; document.getElementById('connections').innerHTML = total;
}); });
app.enter_room('admin'); app.enter_room('admin');
socket.emit('api:get_all_rooms'); socket.emit('api:get_all_rooms');
};
}()); return Admin;
});

@ -1,7 +1,5 @@
var nodebb_admin = nodebb_admin || {}; define(function() {
var Plugins = {
(function() {
var plugins = {
init: function() { init: function() {
var pluginsList = $('.plugins'), var pluginsList = $('.plugins'),
numPlugins = pluginsList[0].querySelectorAll('li').length, numPlugins = pluginsList[0].querySelectorAll('li').length,
@ -31,8 +29,5 @@ var nodebb_admin = nodebb_admin || {};
} }
}; };
jQuery(document).ready(function() { return Plugins;
nodebb_admin.plugins = plugins; });
nodebb_admin.plugins.init();
});
})();

@ -0,0 +1,81 @@
define(function() {
var Settings = {};
Settings.config = {};
Settings.init = function() {
Settings.prepare();
};
Settings.prepare = function() {
// Come back in 500ms if the config isn't ready yet
if (Settings.config === undefined) {
setTimeout(function() {
Settings.prepare();
}, 500);
return;
}
// Populate the fields on the page from the config
var fields = document.querySelectorAll('#content [data-field]'),
numFields = fields.length,
saveBtn = document.getElementById('save'),
x, key, inputType;
for (x = 0; x < numFields; x++) {
key = fields[x].getAttribute('data-field');
inputType = fields[x].getAttribute('type');
if (fields[x].nodeName === 'INPUT') {
if (Settings.config[key]) {
switch (inputType) {
case 'text':
case 'textarea':
case 'number':
fields[x].value = Settings.config[key];
break;
case 'checkbox':
fields[x].checked = Settings.config[key] === '1' ? true : false;
break;
}
}
} else if (fields[x].nodeName === 'TEXTAREA') {
if (Settings.config[key]) fields[x].value = Settings.config[key];
}
}
saveBtn.addEventListener('click', function(e) {
var key, value;
e.preventDefault();
for (x = 0; x < numFields; x++) {
key = fields[x].getAttribute('data-field');
if (fields[x].nodeName === 'INPUT') {
inputType = fields[x].getAttribute('type');
switch (inputType) {
case 'text':
case 'number':
value = fields[x].value;
break;
case 'checkbox':
value = fields[x].checked ? '1' : '0';
break;
}
} else if (fields[x].nodeName === 'TEXTAREA') {
value = fields[x].value;
}
socket.emit('api:config.set', {
key: key,
value: value
});
}
});
};
Settings.remove = function(key) {
socket.emit('api:config.remove', key);
};
return Settings;
});

@ -1,8 +1,91 @@
var nodebb_admin = (function(nodebb_admin) { define(function() {
var Themes = {};
var themes = {}; Themes.init = function() {
var scriptEl = document.createElement('script');
scriptEl.src = 'http://api.bootswatch.com/3/?callback=bootswatchListener';
document.body.appendChild(scriptEl);
themes.render = function(bootswatch) { var bootstrapThemeContainer = document.querySelector('#bootstrap_themes'),
installedThemeContainer = document.querySelector('#installed_themes'),
themeEvent = function(e) {
if (e.target.hasAttribute('data-action')) {
switch (e.target.getAttribute('data-action')) {
case 'preview':
var cssSrc = $(e.target).parents('li').attr('data-css'),
cssEl = document.getElementById('base-theme');
cssEl.href = cssSrc;
break;
case 'use':
var parentEl = $(e.target).parents('li'),
cssSrc = parentEl.attr('data-css'),
cssName = parentEl.attr('data-theme');
socket.emit('api:config.set', {
key: 'theme:id',
value: 'bootswatch:' + cssName
});
socket.emit('api:config.set', {
key: 'theme:src',
value: cssSrc
});
break;
}
}
};
bootstrapThemeContainer.addEventListener('click', themeEvent);
installedThemeContainer.addEventListener('click', themeEvent);
var revertEl = document.getElementById('revert_theme');
revertEl.addEventListener('click', function() {
bootbox.confirm('Are you sure you wish to remove the custom theme and restore the NodeBB default theme?', function(confirm) {
if (confirm) {
require(['forum/admin/settings'], function(Settings) {
Settings.remove('theme:id');
Settings.remove('theme:src');
});
}
});
}, false);
// Installed Themes
socket.emit('api:admin.themes.getInstalled', function(themes) {
var instListEl = document.getElementById('installed_themes'),
themeFrag = document.createDocumentFragment(),
liEl = document.createElement('li');
if (themes.length > 0) {
for (var x = 0, numThemes = themes.length; x < numThemes; x++) {
liEl.setAttribute('data-theme', themes[x].id);
liEl.setAttribute('data-css', themes[x].src);
liEl.innerHTML = '<img src="' + themes[x].screenshot + '" />' +
'<div>' +
'<div class="pull-right">' +
'<button class="btn btn-primary" data-action="use">Use</button> ' +
'<button class="btn btn-default" data-action="preview">Preview</button>' +
'</div>' +
'<h4>' + themes[x].name + '</h4>' +
'<p>' +
themes[x].description +
(themes[x].url ? ' (<a href="' + themes[x].url + '">Homepage</a>)' : '') +
'</p>' +
'</div>' +
'<div class="clear">';
themeFrag.appendChild(liEl.cloneNode(true));
}
} else {
// No themes found
liEl.className = 'no-themes';
liEl.innerHTML = 'No installed themes found';
themeFrag.appendChild(liEl);
}
instListEl.innerHTML = '';
instListEl.appendChild(themeFrag);
});
}
Themes.render = function(bootswatch) {
var themeFrag = document.createDocumentFragment(), var themeFrag = document.createDocumentFragment(),
themeEl = document.createElement('li'), themeEl = document.createElement('li'),
themeContainer = document.querySelector('#bootstrap_themes'), themeContainer = document.querySelector('#bootstrap_themes'),
@ -28,91 +111,5 @@ var nodebb_admin = (function(nodebb_admin) {
themeContainer.appendChild(themeFrag); themeContainer.appendChild(themeFrag);
} }
nodebb_admin.themes = themes; return Themes;
});
return nodebb_admin;
}(nodebb_admin || {}));
(function() {
var scriptEl = document.createElement('script');
scriptEl.src = 'http://api.bootswatch.com/3/?callback=nodebb_admin.themes.render';
document.body.appendChild(scriptEl);
var bootstrapThemeContainer = document.querySelector('#bootstrap_themes'),
installedThemeContainer = document.querySelector('#installed_themes'),
themeEvent = function(e) {
if (e.target.hasAttribute('data-action')) {
switch (e.target.getAttribute('data-action')) {
case 'preview':
var cssSrc = $(e.target).parents('li').attr('data-css'),
cssEl = document.getElementById('base-theme');
cssEl.href = cssSrc;
break;
case 'use':
var parentEl = $(e.target).parents('li'),
cssSrc = parentEl.attr('data-css'),
cssName = parentEl.attr('data-theme');
socket.emit('api:config.set', {
key: 'theme:id',
value: 'bootswatch:' + cssName
});
socket.emit('api:config.set', {
key: 'theme:src',
value: cssSrc
});
break;
}
}
};
bootstrapThemeContainer.addEventListener('click', themeEvent);
installedThemeContainer.addEventListener('click', themeEvent);
var revertEl = document.getElementById('revert_theme');
revertEl.addEventListener('click', function() {
bootbox.confirm('Are you sure you wish to remove the custom theme and restore the NodeBB default theme?', function(confirm) {
if (confirm) {
nodebb_admin.remove('theme:id');
nodebb_admin.remove('theme:src');
}
});
}, false);
// Installed Themes
socket.emit('api:admin.themes.getInstalled', function(themes) {
var instListEl = document.getElementById('installed_themes'),
themeFrag = document.createDocumentFragment(),
liEl = document.createElement('li');
if (themes.length > 0) {
for (var x = 0, numThemes = themes.length; x < numThemes; x++) {
liEl.setAttribute('data-theme', themes[x].id);
liEl.setAttribute('data-css', themes[x].src);
liEl.innerHTML = '<img src="' + themes[x].screenshot + '" />' +
'<div>' +
'<div class="pull-right">' +
'<button class="btn btn-primary" data-action="use">Use</button> ' +
'<button class="btn btn-default" data-action="preview">Preview</button>' +
'</div>' +
'<h4>' + themes[x].name + '</h4>' +
'<p>' +
themes[x].description +
(themes[x].url ? ' (<a href="' + themes[x].url + '">Homepage</a>)' : '') +
'</p>' +
'</div>' +
'<div class="clear">';
themeFrag.appendChild(liEl.cloneNode(true));
}
} else {
// No themes found
liEl.className = 'no-themes';
liEl.innerHTML = 'No installed themes found';
themeFrag.appendChild(liEl);
}
instListEl.innerHTML = '';
instListEl.appendChild(themeFrag);
});
})();

@ -1,127 +1,133 @@
$(document).ready(function() { define(function() {
var topicsListEl = document.querySelector('.topics'), var Topics = {};
loadMoreEl = document.getElementById('topics_loadmore');
Topics.init = function() {
$(topicsListEl).on('click', '[data-action]', function() { var topicsListEl = document.querySelector('.topics'),
var $this = $(this), loadMoreEl = document.getElementById('topics_loadmore');
action = this.getAttribute('data-action'),
tid = $this.parents('[data-tid]').attr('data-tid'); $(topicsListEl).on('click', '[data-action]', function() {
var $this = $(this),
switch (action) { action = this.getAttribute('data-action'),
case 'pin': tid = $this.parents('[data-tid]').attr('data-tid');
if (!$this.hasClass('active')) socket.emit('api:topic.pin', {
tid: tid switch (action) {
case 'pin':
if (!$this.hasClass('active')) socket.emit('api:topic.pin', {
tid: tid
});
else socket.emit('api:topic.unpin', {
tid: tid
});
break;
case 'lock':
if (!$this.hasClass('active')) socket.emit('api:topic.lock', {
tid: tid
});
else socket.emit('api:topic.unlock', {
tid: tid
});
break;
case 'delete':
if (!$this.hasClass('active')) socket.emit('api:topic.delete', {
tid: tid
});
else socket.emit('api:topic.restore', {
tid: tid
});
break;
}
});
loadMoreEl.addEventListener('click', function() {
if (this.className.indexOf('disabled') === -1) {
var topics = document.querySelectorAll('.topics li[data-tid]'),
lastTid = parseInt(topics[topics.length - 1].getAttribute('data-tid'));
this.innerHTML = '<i class="icon-refresh icon-spin"></i> Retrieving topics';
socket.emit('api:admin.topics.getMore', {
limit: 10,
after: lastTid
}, function(topics) {
var btnEl = document.getElementById('topics_loadmore');
topics = JSON.parse(topics);
if (topics.length > 0) {
var html = templates.prepare(templates['admin/topics'].blocks['topics']).parse({
topics: topics
}),
topicsListEl = document.querySelector('.topics');
topicsListEl.innerHTML += html;
btnEl.innerHTML = 'Load More Topics';
} else {
// Exhausted all topics
btnEl.className += ' disabled';
btnEl.innerHTML = 'No more topics';
}
}); });
else socket.emit('api:topic.unpin', { }
tid: tid }, false);
});
break; // Resolve proper button state for all topics
case 'lock': var topicEls = topicsListEl.querySelectorAll('li'),
if (!$this.hasClass('active')) socket.emit('api:topic.lock', { numTopics = topicEls.length;
tid: tid for (var x = 0; x < numTopics; x++) {
}); if (topicEls[x].getAttribute('data-pinned') === '1') topicEls[x].querySelector('[data-action="pin"]').className += ' active';
else socket.emit('api:topic.unlock', { if (topicEls[x].getAttribute('data-locked') === '1') topicEls[x].querySelector('[data-action="lock"]').className += ' active';
tid: tid if (topicEls[x].getAttribute('data-deleted') === '1') topicEls[x].querySelector('[data-action="delete"]').className += ' active';
}); topicEls[x].removeAttribute('data-pinned');
break; topicEls[x].removeAttribute('data-locked');
case 'delete': topicEls[x].removeAttribute('data-deleted');
if (!$this.hasClass('active')) socket.emit('api:topic.delete', {
tid: tid
});
else socket.emit('api:topic.restore', {
tid: tid
});
break;
}
});
loadMoreEl.addEventListener('click', function() {
if (this.className.indexOf('disabled') === -1) {
var topics = document.querySelectorAll('.topics li[data-tid]'),
lastTid = parseInt(topics[topics.length - 1].getAttribute('data-tid'));
this.innerHTML = '<i class="icon-refresh icon-spin"></i> Retrieving topics';
socket.emit('api:admin.topics.getMore', {
limit: 10,
after: lastTid
}, function(topics) {
var btnEl = document.getElementById('topics_loadmore');
topics = JSON.parse(topics);
if (topics.length > 0) {
var html = templates.prepare(templates['admin/topics'].blocks['topics']).parse({
topics: topics
}),
topicsListEl = document.querySelector('.topics');
topicsListEl.innerHTML += html;
btnEl.innerHTML = 'Load More Topics';
} else {
// Exhausted all topics
btnEl.className += ' disabled';
btnEl.innerHTML = 'No more topics';
}
});
} }
}, false);
// Resolve proper button state for all topics
var topicEls = topicsListEl.querySelectorAll('li'),
numTopics = topicEls.length;
for (var x = 0; x < numTopics; x++) {
if (topicEls[x].getAttribute('data-pinned') === '1') topicEls[x].querySelector('[data-action="pin"]').className += ' active';
if (topicEls[x].getAttribute('data-locked') === '1') topicEls[x].querySelector('[data-action="lock"]').className += ' active';
if (topicEls[x].getAttribute('data-deleted') === '1') topicEls[x].querySelector('[data-action="delete"]').className += ' active';
topicEls[x].removeAttribute('data-pinned');
topicEls[x].removeAttribute('data-locked');
topicEls[x].removeAttribute('data-deleted');
}
});
socket.on('api:topic.pin', function(response) { socket.on('api:topic.pin', function(response) {
if (response.status === 'ok') { if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]');
$(btnEl).addClass('active'); $(btnEl).addClass('active');
} }
}); });
socket.on('api:topic.unpin', function(response) { socket.on('api:topic.unpin', function(response) {
if (response.status === 'ok') { if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]');
$(btnEl).removeClass('active'); $(btnEl).removeClass('active');
} }
}); });
socket.on('api:topic.lock', function(response) { socket.on('api:topic.lock', function(response) {
if (response.status === 'ok') { if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]');
$(btnEl).addClass('active'); $(btnEl).addClass('active');
} }
}); });
socket.on('api:topic.unlock', function(response) { socket.on('api:topic.unlock', function(response) {
if (response.status === 'ok') { if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]');
$(btnEl).removeClass('active'); $(btnEl).removeClass('active');
} }
}); });
socket.on('api:topic.delete', function(response) { socket.on('api:topic.delete', function(response) {
if (response.status === 'ok') { if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]');
$(btnEl).addClass('active'); $(btnEl).addClass('active');
} }
}); });
socket.on('api:topic.restore', function(response) {
if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]');
socket.on('api:topic.restore', function(response) { $(btnEl).removeClass('active');
if (response.status === 'ok') { }
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); });
};
$(btnEl).removeClass('active'); return Topics;
}
}); });

@ -1,170 +1,174 @@
(function() { define(function() {
var Users = {};
var yourid = templates.get('yourid');
function isUserAdmin(element) {
var parent = $(element).parents('.users-box');
return (parent.attr('data-admin') !== "0");
}
function isUserBanned(element) {
var parent = $(element).parents('.users-box');
return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0");
}
function getUID(element) {
var parent = $(element).parents('.users-box');
return parent.attr('data-uid');
}
function updateUserButtons() {
jQuery('.ban-btn').each(function(index, element) {
var banBtn = $(element);
var uid = getUID(banBtn);
if (isUserAdmin(banBtn) || uid === yourid)
banBtn.addClass('disabled');
else if (isUserBanned(banBtn))
banBtn.addClass('btn-warning');
else
banBtn.removeClass('btn-warning');
}); Users.init = function() {
} var yourid = templates.get('yourid');
function initUsers() { function isUserAdmin(element) {
var parent = $(element).parents('.users-box');
return (parent.attr('data-admin') !== "0");
}
updateUserButtons(); function isUserBanned(element) {
var parent = $(element).parents('.users-box');
return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0");
}
$('#users-container').on('click', '.ban-btn', function() { function getUID(element) {
var banBtn = $(this); var parent = $(element).parents('.users-box');
var isAdmin = isUserAdmin(banBtn); return parent.attr('data-uid');
var isBanned = isUserBanned(banBtn); }
var parent = banBtn.parents('.users-box');
var uid = getUID(banBtn);
if (!isAdmin) { function updateUserButtons() {
if (isBanned) { jQuery('.ban-btn').each(function(index, element) {
socket.emit('api:admin.user.unbanUser', uid); var banBtn = $(element);
var uid = getUID(banBtn);
if (isUserAdmin(banBtn) || uid === yourid)
banBtn.addClass('disabled');
else if (isUserBanned(banBtn))
banBtn.addClass('btn-warning');
else
banBtn.removeClass('btn-warning'); banBtn.removeClass('btn-warning');
parent.attr('data-banned', 0);
} else {
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) {
if (confirm) {
socket.emit('api:admin.user.banUser', uid);
banBtn.addClass('btn-warning');
parent.attr('data-banned', 1);
}
});
}
}
return false;
});
}
});
}
jQuery('document').ready(function() { function initUsers() {
var timeoutId = 0, updateUserButtons();
loadingMoreUsers = false;
var url = window.location.href, $('#users-container').on('click', '.ban-btn', function() {
parts = url.split('/'), var banBtn = $(this);
active = parts[parts.length - 1]; var isAdmin = isUserAdmin(banBtn);
var isBanned = isUserBanned(banBtn);
var parent = banBtn.parents('.users-box');
var uid = getUID(banBtn);
if (!isAdmin) {
if (isBanned) {
socket.emit('api:admin.user.unbanUser', uid);
banBtn.removeClass('btn-warning');
parent.attr('data-banned', 0);
} else {
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) {
if (confirm) {
socket.emit('api:admin.user.banUser', uid);
banBtn.addClass('btn-warning');
parent.attr('data-banned', 1);
}
});
}
}
jQuery('.nav-pills li').removeClass('active');
jQuery('.nav-pills li a').each(function() {
if (this.getAttribute('href').match(active)) {
jQuery(this.parentNode).addClass('active');
return false; return false;
} });
}); }
jQuery('#search-user').on('keyup', function() {
if (timeoutId !== 0) {
clearTimeout(timeoutId);
timeoutId = 0;
}
timeoutId = setTimeout(function() { jQuery('document').ready(function() {
var username = $('#search-user').val();
jQuery('.icon-spinner').removeClass('none'); var timeoutId = 0,
socket.emit('api:admin.user.search', username); loadingMoreUsers = false;
}, 250); var url = window.location.href,
}); parts = url.split('/'),
active = parts[parts.length - 1];
initUsers(); jQuery('.nav-pills li').removeClass('active');
jQuery('.nav-pills li a').each(function() {
socket.removeAllListeners('api:admin.user.search'); if (this.getAttribute('href').match(active)) {
jQuery(this.parentNode).addClass('active');
socket.on('api:admin.user.search', function(data) { return false;
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ }
users: data });
}),
userListEl = document.querySelector('.users'); jQuery('#search-user').on('keyup', function() {
if (timeoutId !== 0) {
userListEl.innerHTML = html; clearTimeout(timeoutId);
jQuery('.icon-spinner').addClass('none'); timeoutId = 0;
}
if (data && data.length === 0) {
$('#user-notfound-notify').html('User not found!') timeoutId = setTimeout(function() {
.show() var username = $('#search-user').val();
.addClass('label-danger')
.removeClass('label-success'); jQuery('.icon-spinner').removeClass('none');
} else { socket.emit('api:admin.user.search', username);
$('#user-notfound-notify').html(data.length + ' user' + (data.length > 1 ? 's' : '') + ' found!')
.show() }, 250);
.addClass('label-success') });
.removeClass('label-danger');
}
initUsers(); initUsers();
});
function onUsersLoaded(users) { socket.removeAllListeners('api:admin.user.search');
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
users: users socket.on('api:admin.user.search', function(data) {
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
users: data
}),
userListEl = document.querySelector('.users');
userListEl.innerHTML = html;
jQuery('.icon-spinner').addClass('none');
if (data && data.length === 0) {
$('#user-notfound-notify').html('User not found!')
.show()
.addClass('label-danger')
.removeClass('label-success');
} else {
$('#user-notfound-notify').html(data.length + ' user' + (data.length > 1 ? 's' : '') + ' found!')
.show()
.addClass('label-success')
.removeClass('label-danger');
}
initUsers();
}); });
$('#users-container').append(html);
updateUserButtons();
}
function loadMoreUsers() { function onUsersLoaded(users) {
var set = ''; var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
if (active === 'latest') { users: users
set = 'users:joindate'; });
} else if (active === 'sort-posts') { $('#users-container').append(html);
set = 'users:postcount'; updateUserButtons();
} else if (active === 'sort-reputation') {
set = 'users:reputation';
} }
if (set) { function loadMoreUsers() {
loadingMoreUsers = true; var set = '';
socket.emit('api:users.loadMore', { if (active === 'latest') {
set: set, set = 'users:joindate';
after: $('#users-container').children().length } else if (active === 'sort-posts') {
}, function(data) { set = 'users:postcount';
if (data.users.length) { } else if (active === 'sort-reputation') {
onUsersLoaded(data.users); set = 'users:reputation';
} }
loadingMoreUsers = false;
}); if (set) {
loadingMoreUsers = true;
socket.emit('api:users.loadMore', {
set: set,
after: $('#users-container').children().length
}, function(data) {
if (data.users.length) {
onUsersLoaded(data.users);
}
loadingMoreUsers = false;
});
}
} }
}
$('#load-more-users-btn').on('click', loadMoreUsers); $('#load-more-users-btn').on('click', loadMoreUsers);
$(window).off('scroll').on('scroll', function() { $(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9; var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !loadingMoreUsers) { if ($(window).scrollTop() > bottom && !loadingMoreUsers) {
loadMoreUsers(); loadMoreUsers();
} }
}); });
}); });
};
}()); return Users;
});

@ -1,41 +1,86 @@
(function () { define(function () {
var cid = templates.get('category_id'), var Category = {};
room = 'category_' + cid,
twitterEl = document.getElementById('twitter-intent'), Category.init = function() {
facebookEl = document.getElementById('facebook-share'), var cid = templates.get('category_id'),
googleEl = document.getElementById('google-share'), room = 'category_' + cid,
twitter_url = templates.get('twitter-intent-url'), twitterEl = document.getElementById('twitter-intent'),
facebook_url = templates.get('facebook-share-url'), facebookEl = document.getElementById('facebook-share'),
google_url = templates.get('google-share-url'), googleEl = document.getElementById('google-share'),
loadingMoreTopics = false; twitter_url = templates.get('twitter-intent-url'),
facebook_url = templates.get('facebook-share-url'),
app.enter_room(room); google_url = templates.get('google-share-url'),
loadingMoreTopics = false;
twitterEl.addEventListener('click', function () {
window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no'); app.enter_room(room);
return false;
}, false); twitterEl.addEventListener('click', function () {
facebookEl.addEventListener('click', function () { window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no');
window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no'); return false;
return false; }, false);
}, false); facebookEl.addEventListener('click', function () {
googleEl.addEventListener('click', function () { window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no');
window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no'); return false;
return false; }, false);
}, false); googleEl.addEventListener('click', function () {
window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no');
var new_post = document.getElementById('new_post'); return false;
new_post.onclick = function () { }, false);
require(['composer'], function (cmp) {
cmp.push(0, cid); var new_post = document.getElementById('new_post');
new_post.onclick = function () {
require(['composer'], function (cmp) {
cmp.push(0, cid);
});
}
ajaxify.register_events([
'event:new_topic'
]);
socket.on('event:new_topic', Category.onNewTopic);
socket.emit('api:categories.getRecentReplies', cid);
socket.on('api:categories.getRecentReplies', function (posts) {
if (!posts || posts.length === 0) {
return;
}
var recent_replies = document.getElementById('category_recent_replies');
recent_replies.innerHTML = '';
var frag = document.createDocumentFragment(),
li = document.createElement('li');
for (var i = 0, numPosts = posts.length; i < numPosts; i++) {
li.setAttribute('data-pid', posts[i].pid);
li.innerHTML = '<a href="/user/' + posts[i].userslug + '"><img title="' + posts[i].username + '" style="width: 48px; height: 48px; /*temporary*/" class="img-rounded" src="' + posts[i].picture + '" class="" /></a>' +
'<a href="/topic/' + posts[i].topicSlug + '#' + posts[i].pid + '">' +
'<p>' +
posts[i].content +
'</p>' +
'<p class="meta"><strong>' + posts[i].username + '</strong></span> -<span class="timeago" title="' + posts[i].relativeTime + '"></span></p>' +
'</a>';
frag.appendChild(li.cloneNode(true));
recent_replies.appendChild(frag);
}
$('#category_recent_replies span.timeago').timeago();
}); });
}
ajaxify.register_events([ $(window).off('scroll').on('scroll', function (ev) {
'event:new_topic' var bottom = ($(document).height() - $(window).height()) * 0.9;
]);
function onNewTopic(data) { if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
Category.loadMoreTopics(cid);
}
});
};
Category.onNewTopic = function(data) {
var html = templates.prepare(templates['category'].blocks['topics']).parse({ var html = templates.prepare(templates['category'].blocks['topics']).parse({
topics: [data] topics: [data]
}), }),
@ -64,40 +109,7 @@
$('#topics-container span.timeago').timeago(); $('#topics-container span.timeago').timeago();
} }
socket.on('event:new_topic', onNewTopic); Category.onTopicsLoaded = function(topics) {
socket.emit('api:categories.getRecentReplies', cid);
socket.on('api:categories.getRecentReplies', function (posts) {
if (!posts || posts.length === 0) {
return;
}
var recent_replies = document.getElementById('category_recent_replies');
recent_replies.innerHTML = '';
var frag = document.createDocumentFragment(),
li = document.createElement('li');
for (var i = 0, numPosts = posts.length; i < numPosts; i++) {
li.setAttribute('data-pid', posts[i].pid);
li.innerHTML = '<a href="/user/' + posts[i].userslug + '"><img title="' + posts[i].username + '" style="width: 48px; height: 48px; /*temporary*/" class="img-rounded" src="' + posts[i].picture + '" class="" /></a>' +
'<a href="/topic/' + posts[i].topicSlug + '#' + posts[i].pid + '">' +
'<p>' +
posts[i].content +
'</p>' +
'<p class="meta"><strong>' + posts[i].username + '</strong></span> -<span class="timeago" title="' + posts[i].relativeTime + '"></span></p>' +
'</a>';
frag.appendChild(li.cloneNode(true));
recent_replies.appendChild(frag);
}
$('#category_recent_replies span.timeago').timeago();
});
function onTopicsLoaded(topics) {
var html = templates.prepare(templates['category'].blocks['topics']).parse({ var html = templates.prepare(templates['category'].blocks['topics']).parse({
topics: topics topics: topics
@ -113,26 +125,18 @@
} }
function loadMoreTopics(cid) { Category.loadMoreTopics = function(cid) {
loadingMoreTopics = true; loadingMoreTopics = true;
socket.emit('api:category.loadMore', { socket.emit('api:category.loadMore', {
cid: cid, cid: cid,
after: $('#topics-container').children().length after: $('#topics-container').children().length
}, function (data) { }, function (data) {
if (data.topics.length) { if (data.topics.length) {
onTopicsLoaded(data.topics); Category.onTopicsLoaded(data.topics);
} }
loadingMoreTopics = false; loadingMoreTopics = false;
}); });
} }
$(window).off('scroll').on('scroll', function (ev) { return Category;
var bottom = ($(document).height() - $(window).height()) * 0.9; });
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
loadMoreTopics(cid);
}
});
})();

@ -1,7 +1,13 @@
(function() { define(['forum/accountheader'], function(header) {
$(document).ready(function() { var AccountHeader = {};
AccountHeader.init = function() {
header.init();
$('.user-favourite-posts .topic-row').on('click', function() { $('.user-favourite-posts .topic-row').on('click', function() {
ajaxify.go($(this).attr('topic-url')); ajaxify.go($(this).attr('topic-url'));
}); });
}); };
}());
return AccountHeader;
});

@ -1,18 +1,20 @@
(function() { define(['forum/accountheader'], function(header) {
var Followers = {};
var yourid = templates.get('yourid'), Followers.init = function() {
theirid = templates.get('theirid'), header.init();
followersCount = templates.get('followersCount');
$(document).ready(function() { var yourid = templates.get('yourid'),
theirid = templates.get('theirid'),
followersCount = templates.get('followersCount');
if (parseInt(followersCount, 10) === 0) {
$('#no-followers-notice').removeClass('hide');
}
app.addCommasToNumbers(); if (parseInt(followersCount, 10) === 0) {
$('#no-followers-notice').removeClass('hide');
}); }
app.addCommasToNumbers();
};
}()); return Followers;
});

@ -1,10 +1,12 @@
(function() { define(['forum/accountheader'], function(header) {
var Following = {};
var yourid = templates.get('yourid'), Following.init = function() {
theirid = templates.get('theirid'), header.init();
followingCount = templates.get('followingCount');
$(document).ready(function() { var yourid = templates.get('yourid'),
theirid = templates.get('theirid'),
followingCount = templates.get('followingCount');
if (parseInt(followingCount, 10) === 0) { if (parseInt(followingCount, 10) === 0) {
$('#no-following-notice').removeClass('hide'); $('#no-following-notice').removeClass('hide');
@ -34,7 +36,7 @@
} }
app.addCommasToNumbers(); app.addCommasToNumbers();
}); };
return Following;
}()); });

@ -1,60 +1,66 @@
(function() { define(function() {
// Alternate Logins var Login = {};
var altLoginEl = document.querySelector('.alt-logins');
altLoginEl.addEventListener('click', function(e) { Login.init = function() {
var target; // Alternate Logins
switch (e.target.nodeName) { var altLoginEl = document.querySelector('.alt-logins');
case 'LI': altLoginEl.addEventListener('click', function(e) {
target = e.target; var target;
break; switch (e.target.nodeName) {
case 'I': case 'LI':
target = e.target.parentNode; target = e.target;
break; break;
} case 'I':
if (target) { target = e.target.parentNode;
document.location.href = target.getAttribute('data-url'); break;
} }
}); if (target) {
document.location.href = target.getAttribute('data-url');
$('#login').on('click', function() { }
var loginData = { });
'username': $('#username').val(),
'password': $('#password').val(), $('#login').on('click', function() {
'_csrf': $('#csrf-token').val() var loginData = {
}; 'username': $('#username').val(),
'password': $('#password').val(),
$.ajax({ '_csrf': $('#csrf-token').val()
type: "POST", };
url: RELATIVE_PATH + '/login',
data: loginData, $.ajax({
success: function(data, textStatus, jqXHR) { type: "POST",
if (!data.success) { url: RELATIVE_PATH + '/login',
data: loginData,
success: function(data, textStatus, jqXHR) {
if (!data.success) {
$('#login-error-notify').show();
} else {
$('#login-error-notify').hide();
if(app.previousUrl.indexOf('/reset/') != -1)
window.location.replace(RELATIVE_PATH + "/?loggedin");
else
window.location.replace(app.previousUrl + "?loggedin");
app.loadConfig();
}
},
error: function(data, textStatus, jqXHR) {
$('#login-error-notify').show(); $('#login-error-notify').show();
} else { },
$('#login-error-notify').hide(); dataType: 'json',
if(app.previousUrl.indexOf('/reset/') != -1) async: true,
window.location.replace(RELATIVE_PATH + "/?loggedin"); timeout: 2000
else });
window.location.replace(app.previousUrl + "?loggedin");
return false;
app.loadConfig();
}
},
error: function(data, textStatus, jqXHR) {
$('#login-error-notify').show();
},
dataType: 'json',
async: true,
timeout: 2000
}); });
return false; $('#login-error-notify button').on('click', function() {
}); $('#login-error-notify').hide();
return false;
});
$('#login-error-notify button').on('click', function() { document.querySelector('#content input').focus();
$('#login-error-notify').hide(); };
return false;
});
document.querySelector('#content input').focus(); return Login;
}()); });

@ -1,40 +1,56 @@
(function() { define(function() {
var loadingMoreTopics = false; var Recent = {};
app.enter_room('recent_posts'); Recent.newTopicCount = 0;
Recent.newPostCount = 0;
Recent.loadingMoreTopics = false;
ajaxify.register_events([ Recent.init = function() {
'event:new_topic', app.enter_room('recent_posts');
'event:new_post'
]);
var newTopicCount = 0, ajaxify.register_events([
newPostCount = 0; 'event:new_topic',
'event:new_post'
]);
$('#new-topics-alert').on('click', function() { $('#new-topics-alert').on('click', function() {
$(this).hide(); $(this).hide();
}); });
socket.on('event:new_topic', function(data) {
++Recent.newTopicCount;
Recent.updateAlertText();
socket.on('event:new_topic', function(data) { });
socket.on('event:new_post', function(data) {
++Recent.newPostCount;
Recent.updateAlertText();
});
++newTopicCount; $(window).off('scroll').on('scroll', function() {
updateAlertText(); var bottom = ($(document).height() - $(window).height()) * 0.9;
}); if ($(window).scrollTop() > bottom && !Recent.loadingMoreTopics) {
Recent.loadMoreTopics();
}
});
};
function updateAlertText() { Recent.updateAlertText = function() {
var text = ''; var text = '';
if (newTopicCount > 1) if (Recent.newTopicCount > 1)
text = 'There are ' + newTopicCount + ' new topics'; text = 'There are ' + Recent.newTopicCount + ' new topics';
else if (newTopicCount === 1) else if (Recent.newTopicCount === 1)
text = 'There is 1 new topic'; text = 'There is 1 new topic';
else else
text = 'There are no new topics'; text = 'There are no new topics';
if (newPostCount > 1) if (Recent.newPostCount > 1)
text += ' and ' + newPostCount + ' new posts.'; text += ' and ' + Recent.newPostCount + ' new posts.';
else if (newPostCount === 1) else if (Recent.newPostCount === 1)
text += ' and 1 new post.'; text += ' and 1 new post.';
else else
text += ' and no new posts.'; text += ' and no new posts.';
@ -44,12 +60,7 @@
$('#new-topics-alert').html(text).fadeIn('slow'); $('#new-topics-alert').html(text).fadeIn('slow');
} }
socket.on('event:new_post', function(data) { Recent.onTopicsLoaded = function(topics) {
++newPostCount;
updateAlertText();
});
function onTopicsLoaded(topics) {
var html = templates.prepare(templates['recent'].blocks['topics']).parse({ var html = templates.prepare(templates['recent'].blocks['topics']).parse({
topics: topics topics: topics
@ -61,25 +72,17 @@
container.append(html); container.append(html);
} }
function loadMoreTopics() { Recent.loadMoreTopics = function() {
loadingMoreTopics = true; Recent.loadingMoreTopics = true;
socket.emit('api:topics.loadMoreRecentTopics', { socket.emit('api:topics.loadMoreRecentTopics', {
after: $('#topics-container').children().length after: $('#topics-container').children().length
}, function(data) { }, function(data) {
if (data.topics && data.topics.length) { if (data.topics && data.topics.length) {
onTopicsLoaded(data.topics); Recent.onTopicsLoaded(data.topics);
} }
loadingMoreTopics = false; Recent.loadingMoreTopics = false;
}); });
} }
$(window).off('scroll').on('scroll', function() { return Recent;
var bottom = ($(document).height() - $(window).height()) * 0.9; });
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});
})();

@ -1,154 +1,159 @@
(function() { define(function() {
var username = $('#username'), var Register = {};
password = $('#password'),
password_confirm = $('#password-confirm'), Register.init = function() {
register = $('#register'), var username = $('#username'),
emailEl = $('#email'), password = $('#password'),
username_notify = $('#username-notify'), password_confirm = $('#password-confirm'),
email_notify = $('#email-notify'), register = $('#register'),
password_notify = $('#password-notify'), emailEl = $('#email'),
password_confirm_notify = $('#password-confirm-notify'), username_notify = $('#username-notify'),
validationError = false, email_notify = $('#email-notify'),
successIcon = '<i class="icon icon-ok"></i>'; password_notify = $('#password-notify'),
password_confirm_notify = $('#password-confirm-notify'),
$('#referrer').val(app.previousUrl); validationError = false,
successIcon = '<i class="icon icon-ok"></i>';
function showError(element, msg) {
element.html(msg); $('#referrer').val(app.previousUrl);
element.parent()
.removeClass('alert-success') function showError(element, msg) {
.addClass('alert-danger'); element.html(msg);
element.show(); element.parent()
validationError = true; .removeClass('alert-success')
} .addClass('alert-danger');
element.show();
function showSuccess(element, msg) {
element.html(msg);
element.parent()
.removeClass('alert-danger')
.addClass('alert-success');
element.show();
}
function validateEmail() {
if (!emailEl.val()) {
validationError = true; validationError = true;
return;
} }
if (!utils.isEmailValid(emailEl.val())) { function showSuccess(element, msg) {
showError(email_notify, 'Invalid email address.'); element.html(msg);
} else element.parent()
socket.emit('user.email.exists', { .removeClass('alert-danger')
email: emailEl.val() .addClass('alert-success');
}); element.show();
}
emailEl.on('blur', function() {
validateEmail();
});
function validateUsername() {
if (!username.val()) {
validationError = true;
return;
}
if (username.val().length < config.minimumUsernameLength) {
showError(username_notify, 'Username too short!');
} else if (username.val().length > config.maximumUsernameLength) {
showError(username_notify, 'Username too long!');
} else if (!utils.isUserNameValid(username.val())) {
showError(username_notify, 'Invalid username!');
} else {
socket.emit('user.exists', {
username: username.val()
});
}
}
username.on('keyup', function() {
jQuery('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
});
username.on('blur', function() {
validateUsername();
});
function validatePassword() {
if (!password.val()) {
validationError = true;
return;
}
if (password.val().length < config.minimumPasswordLength) {
showError(password_notify, 'Password too short!');
} else if (!utils.isPasswordValid(password.val())) {
showError(password_notify, 'Invalid password!');
} else {
showSuccess(password_notify, successIcon);
} }
if (password.val() !== password_confirm.val() && password_confirm.val() !== '') { function validateEmail() {
showError(password_confirm_notify, 'Passwords must match!'); if (!emailEl.val()) {
validationError = true;
return;
}
if (!utils.isEmailValid(emailEl.val())) {
showError(email_notify, 'Invalid email address.');
} else
socket.emit('user.email.exists', {
email: emailEl.val()
});
} }
}
$(password).on('blur', function() {
validatePassword();
});
function validatePasswordConfirm() { emailEl.on('blur', function() {
if (!password.val() || password_notify.hasClass('alert-error')) { validateEmail();
return; });
function validateUsername() {
if (!username.val()) {
validationError = true;
return;
}
if (username.val().length < config.minimumUsernameLength) {
showError(username_notify, 'Username too short!');
} else if (username.val().length > config.maximumUsernameLength) {
showError(username_notify, 'Username too long!');
} else if (!utils.isUserNameValid(username.val())) {
showError(username_notify, 'Invalid username!');
} else {
socket.emit('user.exists', {
username: username.val()
});
}
} }
if (password.val() !== password_confirm.val()) { username.on('keyup', function() {
showError(password_confirm_notify, 'Passwords must match!'); jQuery('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
} else { });
showSuccess(password_confirm_notify, successIcon); username.on('blur', function() {
validateUsername();
});
function validatePassword() {
if (!password.val()) {
validationError = true;
return;
}
if (password.val().length < config.minimumPasswordLength) {
showError(password_notify, 'Password too short!');
} else if (!utils.isPasswordValid(password.val())) {
showError(password_notify, 'Invalid password!');
} else {
showSuccess(password_notify, successIcon);
}
if (password.val() !== password_confirm.val() && password_confirm.val() !== '') {
showError(password_confirm_notify, 'Passwords must match!');
}
} }
}
$(password_confirm).on('blur', function() { $(password).on('blur', function() {
validatePasswordConfirm(); validatePassword();
}); });
ajaxify.register_events(['user.exists', 'user.email.exists']); function validatePasswordConfirm() {
if (!password.val() || password_notify.hasClass('alert-error')) {
return;
}
socket.on('user.exists', function(data) { if (password.val() !== password_confirm.val()) {
if (data.exists === true) { showError(password_confirm_notify, 'Passwords must match!');
showError(username_notify, 'Username already taken!'); } else {
} else { showSuccess(password_confirm_notify, successIcon);
showSuccess(username_notify, successIcon); }
} }
});
socket.on('user.email.exists', function(data) { $(password_confirm).on('blur', function() {
if (data.exists === true) { validatePasswordConfirm();
showError(email_notify, 'Email address already taken!'); });
} else {
showSuccess(email_notify, successIcon); ajaxify.register_events(['user.exists', 'user.email.exists']);
socket.on('user.exists', function(data) {
if (data.exists === true) {
showError(username_notify, 'Username already taken!');
} else {
showSuccess(username_notify, successIcon);
}
});
socket.on('user.email.exists', function(data) {
if (data.exists === true) {
showError(email_notify, 'Email address already taken!');
} else {
showSuccess(email_notify, successIcon);
}
});
// Alternate Logins
$('.alt-logins li').on('click', function(e) {
document.location.href = $(this).attr('data-url');
});
function validateForm() {
validationError = false;
validateEmail();
validateUsername();
validatePassword();
validatePasswordConfirm();
return validationError;
} }
});
// Alternate Logins
$('.alt-logins li').on('click', function(e) {
document.location.href = $(this).attr('data-url');
});
function validateForm() {
validationError = false;
validateEmail();
validateUsername();
validatePassword();
validatePasswordConfirm();
return validationError;
}
register.on('click', function(e) { register.on('click', function(e) {
if (validateForm()) e.preventDefault(); if (validateForm()) e.preventDefault();
}); });
};
}()); return Register;
});

@ -1,41 +1,47 @@
(function() { define(function() {
var inputEl = document.getElementById('email'), var ResetPassword = {};
errorEl = document.getElementById('error'),
errorTextEl = errorEl.querySelector('p');
document.getElementById('reset').onclick = function() { ResetPassword.init = function() {
if (inputEl.value.length > 0 && inputEl.value.indexOf('@') !== -1) { var inputEl = document.getElementById('email'),
socket.emit('user:reset.send', { errorEl = document.getElementById('error'),
email: inputEl.value errorTextEl = errorEl.querySelector('p');
});
} else { document.getElementById('reset').onclick = function() {
jQuery('#success').hide(); if (inputEl.value.length > 0 && inputEl.value.indexOf('@') !== -1) {
jQuery(errorEl).show(); socket.emit('user:reset.send', {
errorTextEl.innerHTML = 'Please enter a valid email'; email: inputEl.value
} });
}; } else {
jQuery('#success').hide();
jQuery(errorEl).show();
errorTextEl.innerHTML = 'Please enter a valid email';
}
};
ajaxify.register_events(['user.send_reset']); ajaxify.register_events(['user.send_reset']);
socket.on('user.send_reset', function(data) { socket.on('user.send_reset', function(data) {
var submitEl = document.getElementById('reset'); var submitEl = document.getElementById('reset');
if (data.status === 'ok') { if (data.status === 'ok') {
jQuery('#error').hide(); jQuery('#error').hide();
jQuery('#success').show(); jQuery('#success').show();
jQuery('#success p').html('An email has been dispatched to "' + data.email + '" with instructions on setting a new password.'); jQuery('#success p').html('An email has been dispatched to "' + data.email + '" with instructions on setting a new password.');
inputEl.value = ''; inputEl.value = '';
} else { } else {
jQuery('#success').hide(); jQuery('#success').hide();
jQuery(errorEl).show(); jQuery(errorEl).show();
switch (data.message) { switch (data.message) {
case 'invalid-email': case 'invalid-email':
errorTextEl.innerHTML = 'The email you put in (<span>' + data.email + '</span>) is not registered with us. Please try again.'; errorTextEl.innerHTML = 'The email you put in (<span>' + data.email + '</span>) is not registered with us. Please try again.';
break; break;
case 'send-failed': case 'send-failed':
errorTextEl.innerHTML = 'There was a problem sending the reset code. Please try again later.'; errorTextEl.innerHTML = 'There was a problem sending the reset code. Please try again later.';
break; break;
}
} }
} });
}); };
}());
return ResetPassword;
});

@ -1,52 +1,58 @@
(function() { define(function() {
var reset_code = templates.get('reset_code'); var ResetCode = {};
var resetEl = document.getElementById('reset'), ResetCode.init = function() {
password = document.getElementById('password'), var reset_code = templates.get('reset_code');
repeat = document.getElementById('repeat'),
noticeEl = document.getElementById('notice'); var resetEl = document.getElementById('reset'),
password = document.getElementById('password'),
resetEl.addEventListener('click', function() { repeat = document.getElementById('repeat'),
if (password.value.length < 6) { noticeEl = document.getElementById('notice');
$('#error').hide();
noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; resetEl.addEventListener('click', function() {
noticeEl.querySelector('p').innerHTML = 'The password entered is too short, please pick a different password.'; if (password.value.length < 6) {
noticeEl.style.display = 'block'; $('#error').hide();
} else if (password.value !== repeat.value) { noticeEl.querySelector('strong').innerHTML = 'Invalid Password';
$('#error').hide(); noticeEl.querySelector('p').innerHTML = 'The password entered is too short, please pick a different password.';
noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; noticeEl.style.display = 'block';
noticeEl.querySelector('p').innerHTML = 'The two passwords you\'ve entered do not match.'; } else if (password.value !== repeat.value) {
noticeEl.style.display = 'block'; $('#error').hide();
} else { noticeEl.querySelector('strong').innerHTML = 'Invalid Password';
socket.emit('user:reset.commit', { noticeEl.querySelector('p').innerHTML = 'The two passwords you\'ve entered do not match.';
code: reset_code, noticeEl.style.display = 'block';
password: password.value } else {
}); socket.emit('user:reset.commit', {
} code: reset_code,
}, false); password: password.value
});
// Enable the form if the code is valid }
socket.emit('user:reset.valid', { }, false);
code: reset_code
}); // Enable the form if the code is valid
socket.emit('user:reset.valid', {
code: reset_code
ajaxify.register_events(['user:reset.valid', 'user:reset.commit']); });
socket.on('user:reset.valid', function(data) {
if ( !! data.valid) resetEl.disabled = false;
else { ajaxify.register_events(['user:reset.valid', 'user:reset.commit']);
var formEl = document.getElementById('reset-form'); socket.on('user:reset.valid', function(data) {
// Show error message if ( !! data.valid) resetEl.disabled = false;
$('#error').show(); else {
formEl.parentNode.removeChild(formEl); var formEl = document.getElementById('reset-form');
} // Show error message
}) $('#error').show();
formEl.parentNode.removeChild(formEl);
socket.on('user:reset.commit', function(data) { }
if (data.status === 'ok') { })
$('#error').hide();
$('#notice').hide(); socket.on('user:reset.commit', function(data) {
$('#success').show(); if (data.status === 'ok') {
} $('#error').hide();
}); $('#notice').hide();
}()); $('#success').show();
}
});
};
return ResetCode;
});

@ -1,6 +1,7 @@
(function() { define(function() {
var Search = {};
$(document).ready(function() { Search.init = function() {
var searchQuery = $('#topics-container').attr('data-search-query'); var searchQuery = $('#topics-container').attr('data-search-query');
$('.search-result-text').each(function() { $('.search-result-text').each(function() {
@ -21,4 +22,5 @@
}); });
}); });
})(); return Search;
});

File diff suppressed because it is too large Load Diff

@ -1,114 +1,119 @@
(function() { define(function() {
var loadingMoreTopics = false; var Unread = {};
app.enter_room('recent_posts'); Unread.init = function() {
var loadingMoreTopics = false;
ajaxify.register_events([
'event:new_topic', app.enter_room('recent_posts');
'event:new_post'
]); ajaxify.register_events([
'event:new_topic',
var newTopicCount = 0, 'event:new_post'
newPostCount = 0; ]);
$('#new-topics-alert').on('click', function() { var newTopicCount = 0,
$(this).hide(); newPostCount = 0;
});
$('#new-topics-alert').on('click', function() {
socket.on('event:new_topic', function(data) { $(this).hide();
++newTopicCount;
updateAlertText();
});
function updateAlertText() {
var text = '';
if (newTopicCount > 1)
text = 'There are ' + newTopicCount + ' new topics';
else if (newTopicCount === 1)
text = 'There is 1 new topic';
else
text = 'There are no new topics';
if (newPostCount > 1)
text += ' and ' + newPostCount + ' new posts.';
else if (newPostCount === 1)
text += ' and 1 new post.';
else
text += ' and no new posts.';
text += ' Click here to reload.';
$('#new-topics-alert').html(text).fadeIn('slow');
}
socket.on('event:new_post', function(data) {
++newPostCount;
updateAlertText();
});
$('#mark-allread-btn').on('click', function() {
var btn = $(this);
socket.emit('api:topics.markAllRead', {}, function(success) {
if (success) {
btn.remove();
$('#topics-container').empty();
$('#category-no-topics').removeClass('hidden');
app.alertSuccess('All topics marked as read!');
$('#numUnreadBadge')
.removeClass('badge-important')
.addClass('badge-inverse')
.html('0');
} else {
app.alertError('There was an error marking topics read!');
}
}); });
});
function onTopicsLoaded(topics) {
var html = templates.prepare(templates['unread'].blocks['topics']).parse({
topics: topics
}),
container = $('#topics-container');
$('#category-no-topics').remove();
container.append(html);
}
function loadMoreTopics() {
loadingMoreTopics = true;
socket.emit('api:topics.loadMoreUnreadTopics', {
after: parseInt($('#topics-container').attr('data-next-start'), 10)
}, function(data) {
if (data.topics && data.topics.length) {
onTopicsLoaded(data.topics);
$('#topics-container').attr('data-next-start', data.nextStart);
} else {
$('#load-more-btn').hide();
}
loadingMoreTopics = false; socket.on('event:new_topic', function(data) {
++newTopicCount;
updateAlertText();
}); });
}
$(window).off('scroll').on('scroll', function() { function updateAlertText() {
var bottom = ($(document).height() - $(window).height()) * 0.9; var text = '';
if ($(window).scrollTop() > bottom && !loadingMoreTopics) { if (newTopicCount > 1)
loadMoreTopics(); text = 'There are ' + newTopicCount + ' new topics';
else if (newTopicCount === 1)
text = 'There is 1 new topic';
else
text = 'There are no new topics';
if (newPostCount > 1)
text += ' and ' + newPostCount + ' new posts.';
else if (newPostCount === 1)
text += ' and 1 new post.';
else
text += ' and no new posts.';
text += ' Click here to reload.';
$('#new-topics-alert').html(text).fadeIn('slow');
}
socket.on('event:new_post', function(data) {
++newPostCount;
updateAlertText();
});
$('#mark-allread-btn').on('click', function() {
var btn = $(this);
socket.emit('api:topics.markAllRead', {}, function(success) {
if (success) {
btn.remove();
$('#topics-container').empty();
$('#category-no-topics').removeClass('hidden');
app.alertSuccess('All topics marked as read!');
$('#numUnreadBadge')
.removeClass('badge-important')
.addClass('badge-inverse')
.html('0');
} else {
app.alertError('There was an error marking topics read!');
}
});
});
function onTopicsLoaded(topics) {
var html = templates.prepare(templates['unread'].blocks['topics']).parse({
topics: topics
}),
container = $('#topics-container');
$('#category-no-topics').remove();
container.append(html);
} }
});
function loadMoreTopics() {
loadingMoreTopics = true;
socket.emit('api:topics.loadMoreUnreadTopics', {
after: parseInt($('#topics-container').attr('data-next-start'), 10)
}, function(data) {
if (data.topics && data.topics.length) {
onTopicsLoaded(data.topics);
$('#topics-container').attr('data-next-start', data.nextStart);
} else {
$('#load-more-btn').hide();
}
loadingMoreTopics = false;
});
}
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) $(window).off('scroll').on('scroll', function() {
$('#load-more-btn').show(); var bottom = ($(document).height() - $(window).height()) * 0.9;
$('#load-more-btn').on('click', function() { if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
loadMoreTopics(); loadMoreTopics();
}); }
});
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20)
$('#load-more-btn').show();
$('#load-more-btn').on('click', function() {
loadMoreTopics();
});
};
})(); return Unread;
});

@ -1,6 +1,7 @@
(function() { define(function() {
var Users = {};
$(document).ready(function() { Users.init = function() {
var timeoutId = 0; var timeoutId = 0;
var loadingMoreUsers = false; var loadingMoreUsers = false;
@ -131,6 +132,7 @@
loadMoreUsers(); loadMoreUsers();
} }
}); });
}); };
}()); return Users;
});

@ -98,6 +98,3 @@
<input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="yourid" value="{yourid}" />
<input type="hidden" template-variable="theirid" value="{theirid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" />
<input type="hidden" template-type="boolean" template-variable="isFollowing" value="{isFollowing}" /> <input type="hidden" template-type="boolean" template-variable="isFollowing" value="{isFollowing}" />
<script type="text/javascript" src="{relative_path}/src/forum/account.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>

@ -174,9 +174,3 @@
</div> </div>
</div> </div>
<input type="hidden" template-variable="gravatarpicture" value="{gravatarpicture}" />
<input type="hidden" template-variable="uploadedpicture" value="{uploadedpicture}" />
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/accountedit.js"></script>

@ -26,6 +26,3 @@
<a id="submitBtn" href="#" class="btn btn-primary">Save changes</a> <a id="submitBtn" href="#" class="btn btn-primary">Save changes</a>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/accountsettings.js"></script>

@ -101,5 +101,3 @@
<div class="col-md-3"><i class="icon-adn"></i></div><div class="col-md-3"><i class="icon-android"></i></div><div class="col-md-3"><i class="icon-apple"></i></div><div class="col-md-3"><i class="icon-bitbucket"></i></div><div class="col-md-3"><i class="icon-bitbucket-sign"></i></div><div class="col-md-3"><i class="icon-bitcoin"></i></div><div class="col-md-3"><i class="icon-btc"></i></div><div class="col-md-3"><i class="icon-css3"></i></div><div class="col-md-3"><i class="icon-dribbble"></i></div><div class="col-md-3"><i class="icon-dropbox"></i></div><div class="col-md-3"><i class="icon-facebook"></i></div><div class="col-md-3"><i class="icon-facebook-sign"></i></div><div class="col-md-3"><i class="icon-flickr"></i></div><div class="col-md-3"><i class="icon-foursquare"></i></div><div class="col-md-3"><i class="icon-github"></i></div><div class="col-md-3"><i class="icon-github-alt"></i></div><div class="col-md-3"><i class="icon-github-sign"></i></div><div class="col-md-3"><i class="icon-gittip"></i></div><div class="col-md-3"><i class="icon-google-plus"></i></div><div class="col-md-3"><i class="icon-google-plus-sign"></i></div><div class="col-md-3"><i class="icon-html5"></i></div><div class="col-md-3"><i class="icon-instagram"></i></div><div class="col-md-3"><i class="icon-linkedin"></i></div><div class="col-md-3"><i class="icon-linkedin-sign"></i></div><div class="col-md-3"><i class="icon-linux"></i></div><div class="col-md-3"><i class="icon-maxcdn"></i></div><div class="col-md-3"><i class="icon-pinterest"></i></div><div class="col-md-3"><i class="icon-pinterest-sign"></i></div><div class="col-md-3"><i class="icon-renren"></i></div><div class="col-md-3"><i class="icon-skype"></i></div><div class="col-md-3"><i class="icon-stackexchange"></i></div><div class="col-md-3"><i class="icon-trello"></i></div><div class="col-md-3"><i class="icon-tumblr"></i></div><div class="col-md-3"><i class="icon-tumblr-sign"></i></div><div class="col-md-3"><i class="icon-twitter"></i></div><div class="col-md-3"><i class="icon-twitter-sign"></i></div><div class="col-md-3"><i class="icon-vk"></i></div><div class="col-md-3"><i class="icon-weibo"></i></div><div class="col-md-3"><i class="icon-windows"></i></div><div class="col-md-3"><i class="icon-xing"></i></div><div class="col-md-3"><i class="icon-xing-sign"></i></div><div class="col-md-3"><i class="icon-youtube"></i></div><div class="col-md-3"><i class="icon-youtube-play"></i></div><div class="col-md-3"><i class="icon-youtube-sign"></i></div> <div class="col-md-3"><i class="icon-adn"></i></div><div class="col-md-3"><i class="icon-android"></i></div><div class="col-md-3"><i class="icon-apple"></i></div><div class="col-md-3"><i class="icon-bitbucket"></i></div><div class="col-md-3"><i class="icon-bitbucket-sign"></i></div><div class="col-md-3"><i class="icon-bitcoin"></i></div><div class="col-md-3"><i class="icon-btc"></i></div><div class="col-md-3"><i class="icon-css3"></i></div><div class="col-md-3"><i class="icon-dribbble"></i></div><div class="col-md-3"><i class="icon-dropbox"></i></div><div class="col-md-3"><i class="icon-facebook"></i></div><div class="col-md-3"><i class="icon-facebook-sign"></i></div><div class="col-md-3"><i class="icon-flickr"></i></div><div class="col-md-3"><i class="icon-foursquare"></i></div><div class="col-md-3"><i class="icon-github"></i></div><div class="col-md-3"><i class="icon-github-alt"></i></div><div class="col-md-3"><i class="icon-github-sign"></i></div><div class="col-md-3"><i class="icon-gittip"></i></div><div class="col-md-3"><i class="icon-google-plus"></i></div><div class="col-md-3"><i class="icon-google-plus-sign"></i></div><div class="col-md-3"><i class="icon-html5"></i></div><div class="col-md-3"><i class="icon-instagram"></i></div><div class="col-md-3"><i class="icon-linkedin"></i></div><div class="col-md-3"><i class="icon-linkedin-sign"></i></div><div class="col-md-3"><i class="icon-linux"></i></div><div class="col-md-3"><i class="icon-maxcdn"></i></div><div class="col-md-3"><i class="icon-pinterest"></i></div><div class="col-md-3"><i class="icon-pinterest-sign"></i></div><div class="col-md-3"><i class="icon-renren"></i></div><div class="col-md-3"><i class="icon-skype"></i></div><div class="col-md-3"><i class="icon-stackexchange"></i></div><div class="col-md-3"><i class="icon-trello"></i></div><div class="col-md-3"><i class="icon-tumblr"></i></div><div class="col-md-3"><i class="icon-tumblr-sign"></i></div><div class="col-md-3"><i class="icon-twitter"></i></div><div class="col-md-3"><i class="icon-twitter-sign"></i></div><div class="col-md-3"><i class="icon-vk"></i></div><div class="col-md-3"><i class="icon-weibo"></i></div><div class="col-md-3"><i class="icon-windows"></i></div><div class="col-md-3"><i class="icon-xing"></i></div><div class="col-md-3"><i class="icon-xing-sign"></i></div><div class="col-md-3"><i class="icon-youtube"></i></div><div class="col-md-3"><i class="icon-youtube-play"></i></div><div class="col-md-3"><i class="icon-youtube-sign"></i></div>
<div class="col-md-3"><i class="icon-ambulance"></i></div><div class="col-md-3"><i class="icon-h-sign"></i></div><div class="col-md-3"><i class="icon-hospital"></i></div><div class="col-md-3"><i class="icon-medkit"></i></div><div class="col-md-3"><i class="icon-plus-sign-alt"></i></div><div class="col-md-3"><i class="icon-stethoscope"></i></div><div class="col-md-3"><i class="icon-user-md"></i></div> <div class="col-md-3"><i class="icon-ambulance"></i></div><div class="col-md-3"><i class="icon-h-sign"></i></div><div class="col-md-3"><i class="icon-hospital"></i></div><div class="col-md-3"><i class="icon-medkit"></i></div><div class="col-md-3"><i class="icon-plus-sign-alt"></i></div><div class="col-md-3"><i class="icon-stethoscope"></i></div><div class="col-md-3"><i class="icon-user-md"></i></div>
</div></div></div> </div></div></div>
<script type="text/javascript" src="{relative_path}/src/forum/admin/categories.js"></script>

@ -17,10 +17,7 @@
<button class="btn btn-lg btn-primary" id="save">Save</button> <button class="btn btn-lg btn-primary" id="save">Save</button>
<script> <script>
var loadDelay = setInterval(function() { require(['forum/admin/settings'], function(Settings) {
if (nodebb_admin) { Settings.prepare();
nodebb_admin.prepare(); });
clearInterval(loadDelay);
}
}, 500);
</script> </script>

@ -9,7 +9,7 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
$.getScript(RELATIVE_PATH + '/src/forum/admin/footer.js'); require(['forum/admin/footer']);
</script> </script>
</body> </body>

@ -17,10 +17,7 @@
<button class="btn btn-lg btn-primary" id="save">Save</button> <button class="btn btn-lg btn-primary" id="save">Save</button>
<script> <script>
var loadDelay = setInterval(function() { require(['forum/admin/settings'], function(Settings) {
if (nodebb_admin) { Settings.prepare();
nodebb_admin.prepare(); });
clearInterval(loadDelay);
}
}, 500);
</script> </script>

@ -96,5 +96,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/admin/groups.js"></script>

@ -7,7 +7,6 @@
var RELATIVE_PATH = "{relative_path}"; var RELATIVE_PATH = "{relative_path}";
</script> </script>
<link id="base-theme" href="{relative_path}/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen"> <link id="base-theme" href="{relative_path}/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="{relative_path}/vendor/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet" media="screen">
<link rel="stylesheet" href="{relative_path}/vendor/fontawesome/css/font-awesome.min.css"> <link rel="stylesheet" href="{relative_path}/vendor/fontawesome/css/font-awesome.min.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script> <script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript" src="{relative_path}/vendor/bootstrap/js/bootstrap.min.js"></script> <script type="text/javascript" src="{relative_path}/vendor/bootstrap/js/bootstrap.min.js"></script>
@ -25,7 +24,10 @@
<script> <script>
require.config({ require.config({
baseUrl: "{relative_path}/src/modules", baseUrl: "{relative_path}/src/modules",
waitSeconds: 3 waitSeconds: 3,
paths: {
"forum": '../forum'
}
}); });
</script> </script>
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">

@ -18,5 +18,3 @@
</p> </p>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/admin/index.js"></script>

@ -24,10 +24,7 @@
<button class="btn btn-lg btn-primary" id="save" checked>Save</button> <button class="btn btn-lg btn-primary" id="save" checked>Save</button>
<script> <script>
var loadDelay = setInterval(function() { require(['forum/admin/settings'], function(Settings) {
if (nodebb_admin) { Settings.prepare();
nodebb_admin.prepare(); });
clearInterval(loadDelay);
}
}, 500);
</script> </script>

@ -21,5 +21,3 @@
Full documentation regarding plugin authoring can be found in the <a target="_blank" href="https://github.com/designcreateplay/NodeBB/wiki/Writing-Plugins-for-NodeBB">NodeBB Wiki</a>. Full documentation regarding plugin authoring can be found in the <a target="_blank" href="https://github.com/designcreateplay/NodeBB/wiki/Writing-Plugins-for-NodeBB">NodeBB Wiki</a>.
</p> </p>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/admin/plugins.js"></script>

@ -83,10 +83,7 @@
<button class="btn btn-lg btn-primary" id="save">Save</button> <button class="btn btn-lg btn-primary" id="save">Save</button>
<script> <script>
var loadDelay = setInterval(function() { require(['forum/admin/settings'], function(Settings) {
if (nodebb_admin) { Settings.prepare();
nodebb_admin.prepare(); });
clearInterval(loadDelay);
}
}, 500);
</script> </script>

@ -23,4 +23,10 @@
<button class="btn btn-warning" id="revert_theme">Revert</button> This will remove any custom theme applied to your NodeBB, and restore the base theme. <button class="btn btn-warning" id="revert_theme">Revert</button> This will remove any custom theme applied to your NodeBB, and restore the base theme.
</p> </p>
<script type="text/javascript" src="{relative_path}/src/forum/admin/themes.js"></script> <script>
var bootswatchListener = function(data) {
require(['forum/admin/themes'], function(t) {
t.render(data);
});
}
</script>

@ -22,5 +22,3 @@
<div class="text-center"> <div class="text-center">
<button id="topics_loadmore" class="btn btn-primary btn-lg">Load More Topics</button> <button id="topics_loadmore" class="btn btn-primary btn-lg">Load More Topics</button>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/admin/topics.js"></script>

@ -17,10 +17,7 @@
<button class="btn btn-lg btn-primary" id="save">Save</button> <button class="btn btn-lg btn-primary" id="save">Save</button>
<script> <script>
var loadDelay = setInterval(function() { require(['forum/admin/settings'], function(Settings) {
if (nodebb_admin) { Settings.prepare();
nodebb_admin.prepare(); });
clearInterval(loadDelay);
}
}, 500);
</script> </script>

@ -42,6 +42,3 @@
<button id="load-more-users-btn" class="btn btn-primary">Load More</button> <button id="load-more-users-btn" class="btn btn-primary">Load More</button>
</div> </div>
<input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="yourid" value="{yourid}" />
<script type="text/javascript" src="{relative_path}/src/forum/admin/users.js"></script>

@ -97,5 +97,3 @@
<input type="hidden" template-variable="twitter-intent-url" value="{twitter-intent-url}" /> <input type="hidden" template-variable="twitter-intent-url" value="{twitter-intent-url}" />
<input type="hidden" template-variable="facebook-share-url" value="{facebook-share-url}" /> <input type="hidden" template-variable="facebook-share-url" value="{facebook-share-url}" />
<input type="hidden" template-variable="google-share-url" value="{google-share-url}" /> <input type="hidden" template-variable="google-share-url" value="{google-share-url}" />
<script type="text/javascript" src="{relative_path}/src/forum/category.js"></script>

@ -22,6 +22,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/favourites.js"></script>

@ -34,6 +34,3 @@
<input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="yourid" value="{yourid}" />
<input type="hidden" template-variable="theirid" value="{theirid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" />
<input type="hidden" template-variable="followersCount" value="{followersCount}" /> <input type="hidden" template-variable="followersCount" value="{followersCount}" />
<script type="text/javascript" src="{relative_path}/src/forum/followers.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>

@ -35,6 +35,3 @@
<input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="yourid" value="{yourid}" />
<input type="hidden" template-variable="theirid" value="{theirid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" />
<input type="hidden" template-variable="followingCount" value="{followingCount}" /> <input type="hidden" template-variable="followingCount" value="{followingCount}" />
<script type="text/javascript" src="{relative_path}/src/forum/following.js"></script>
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>

@ -53,7 +53,7 @@
</footer> </footer>
<script> <script>
$.getScript(RELATIVE_PATH + '/src/forum/footer.js'); require(['forum/footer']);
</script> </script>
</body> </body>

@ -15,8 +15,14 @@
<script> <script>
require.config({ require.config({
baseUrl: "{relative_path}/src/modules", baseUrl: "{relative_path}/src/modules",
waitSeconds: 3 waitSeconds: 3,
paths: {
"forum": '../forum'
}
}); });
requirejs.onError = function(err) {
console.log(err);
}
</script> </script>
<link rel="stylesheet" type="text/css" href="{relative_path}/css/nodebb.css" /> <link rel="stylesheet" type="text/css" href="{relative_path}/css/nodebb.css" />

@ -60,5 +60,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/login.js"></script>

@ -49,5 +49,3 @@
</ul> </ul>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/recent.js"></script>

@ -80,5 +80,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/register.js"></script>

@ -26,5 +26,3 @@
<button class="btn btn-primary btn-block btn-lg" id="reset" type="submit">Reset Password</button> <button class="btn btn-primary btn-block btn-lg" id="reset" type="submit">Reset Password</button>
</form> </form>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/reset.js"></script>

@ -34,6 +34,3 @@
</form> </form>
</div> </div>
<input type="hidden" template-variable="reset_code" value="{reset_code}" /> <input type="hidden" template-variable="reset_code" value="{reset_code}" />
<script type="text/javascript" src="{relative_path}/src/forum/reset_code.js"></script>

@ -53,5 +53,3 @@
</ul> </ul>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/search.js"></script>

@ -199,7 +199,3 @@
<input type="hidden" template-variable="pinned" value="{pinned}" /> <input type="hidden" template-variable="pinned" value="{pinned}" />
<input type="hidden" template-variable="topic_name" value="{topic_name}" /> <input type="hidden" template-variable="topic_name" value="{topic_name}" />
<input type="hidden" template-variable="postcount" value="{postcount}" /> <input type="hidden" template-variable="postcount" value="{postcount}" />
<script type="text/javascript" src="{relative_path}/src/forum/topic.js"></script>

@ -54,5 +54,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/unread.js"></script>

@ -45,5 +45,3 @@
<button id="load-more-users-btn" class="btn btn-primary">[[users:load_more]]</button> <button id="load-more-users-btn" class="btn btn-primary">[[users:load_more]]</button>
</div> </div>
</div> </div>
<script type="text/javascript" src="{relative_path}/src/forum/users.js"></script>

@ -135,22 +135,22 @@ var express = require('express'),
app.use(function (req, res, next) { app.use(function (req, res, next) {
res.status(404); res.status(404);
// respond with html page if (path.dirname(req.url) === '/src/forum') {
if (req.accepts('html')) { // Handle missing client-side scripts
res.type('text/javascript').send(200, '');
} else if (req.accepts('html')) {
// respond with html page
winston.warn('Route requested but not found: ' + req.url);
res.redirect(nconf.get('relative_path') + '/404'); res.redirect(nconf.get('relative_path') + '/404');
return; } else if (req.accepts('json')) {
} // respond with json
res.json({
// respond with json
if (req.accepts('json')) {
res.send({
error: 'Not found' error: 'Not found'
}); });
return; } else {
// default to plain-text. send()
res.type('txt').send('Not found');
} }
// default to plain-text. send()
res.type('txt').send('Not found');
}); });
app.use(function (err, req, res, next) { app.use(function (err, req, res, next) {

Loading…
Cancel
Save