revamped client side scripts so that they are loaded using Require.js instead.

This commit is contained in:
Julian Lam
2013-10-03 15:04:25 -04:00
parent b49c7b8609
commit 038e04dee6
60 changed files with 2472 additions and 2431 deletions

View File

@@ -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();
});
if (callback) { if (callback) {
callback(); callback();

View File

@@ -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;
});
$('.user-recent-posts .topic-row').on('click', function() {
ajaxify.go($(this).attr('topic-url'));
});
socket.on('api:user.isOnline', Account.handleUserOnline);
socket.emit('api:user.isOnline', theirid, Account.handleUserOnline);
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'); var onlineStatus = $('.account-online-status');
function handleUserOnline(data) { if (data.online) {
if (data.online) { onlineStatus.find('span span').text('online');
onlineStatus.find('span span').text('online'); onlineStatus.find('i').attr('class', 'icon-circle');
onlineStatus.find('i').attr('class', 'icon-circle'); } else {
} else { onlineStatus.find('span span').text('offline');
onlineStatus.find('span span').text('offline'); onlineStatus.find('i').attr('class', 'icon-circle-blank');
onlineStatus.find('i').attr('class', 'icon-circle-blank');
}
} }
};
socket.on('api:user.isOnline', handleUserOnline); return Account;
});
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);
});
});
}());

View File

@@ -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;
if (!$('#userPhotoInput').val()) {
error('select an image to upload!');
return false;
}
$(this).find('#imageUploadCsrf').val($('#csrf_token').val());
$(this).ajaxSubmit({
error: function(xhr) {
error('Error: ' + xhr.status);
},
uploadProgress: function(event, position, total, percent) {
console.log(percent);
$('#upload-progress-bar').css('width', percent + '%');
},
success: function(response) {
if (response.error) {
error(response.error);
return;
}
var imageUrlOnServer = response.path;
$('#user-current-picture').attr('src', imageUrlOnServer);
$('#user-uploaded-picture').attr('src', imageUrlOnServer);
uploadedPicture = imageUrlOnServer;
setTimeout(function() {
hideAlerts();
$('#upload-picture-modal').modal('hide');
}, 750);
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']
});
success('File uploaded successfully!');
} }
$(this).find('#imageUploadCsrf').val($('#csrf_token').val());
$(this).ajaxSubmit({
error: function(xhr) {
AccountEdit.error('Error: ' + xhr.status);
},
uploadProgress: function(event, position, total, percent) {
console.log(percent);
$('#upload-progress-bar').css('width', percent + '%');
},
success: function(response) {
if (response.error) {
AccountEdit.error(response.error);
return;
}
var imageUrlOnServer = response.path;
$('#user-current-picture').attr('src', imageUrlOnServer);
$('#user-uploaded-picture').attr('src', imageUrlOnServer);
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!');
}
});
return false;
}); });
return false; var selectedImageType = '';
});
function hideAlerts() { $('#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();
$('#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) {
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();
});
(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;
});
}());
};
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;
});
}());
}); });

View File

@@ -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;
});

View File

@@ -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;
});

View File

@@ -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() {
socket.emit('api:admin.categories.update', modified_categories);
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 update_blockclass(el) {
el.parentNode.parentNode.className = 'entry-row ' + el.value;
}
jQuery('#entry-container').sortable();
jQuery('.blockclass').each(function() {
jQuery(this).val(this.getAttribute('data-value'));
});
//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() {
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({
categories: [data]
});
$('#entry-container').append(html);
$('#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) {
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] = modified_categories[cid] || {};
modified_categories[cid]['disabled'] = disabled; modified_categories[cid][$(el).attr('data-name')] = $(el).val();
}
save(); function save() {
return false; socket.emit('api:admin.categories.update', modified_categories);
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 update_blockclass(el) {
el.parentNode.parentNode.className = 'entry-row ' + el.value;
}
jQuery('#entry-container').sortable();
jQuery('.blockclass').each(function() {
jQuery(this).val(this.getAttribute('data-value'));
}); });
});
}()); //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();
}
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({
categories: [data]
});
$('#entry-container').append(html);
$('#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) {
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;
});
});
};
return Categories;
});

View File

@@ -1,121 +1,44 @@
var nodebb_admin = (function(nodebb_admin) { jQuery('document').ready(function() {
// On menu click, change "active" state
var menuEl = document.querySelector('.sidebar-nav'),
liEls = menuEl.querySelectorAll('li')
parentEl = null;
nodebb_admin.config = undefined; menuEl.addEventListener('click', function(e) {
parentEl = e.target.parentNode;
nodebb_admin.prepare = function() { if (parentEl.nodeName === 'LI') {
// Come back in 500ms if the config isn't ready yet for (var x = 0, numLis = liEls.length; x < numLis; x++) {
if (nodebb_admin.config === undefined) { if (liEls[x] !== parentEl) jQuery(liEls[x]).removeClass('active');
setTimeout(function() { else jQuery(parentEl).addClass('active');
nodebb_admin.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 (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++) { socket.emit('api:config.get');
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': socket.on('api:config.set', function(data) {
value = fields[x].checked ? '1' : '0'; if (data.status === 'ok') {
break; app.alert({
} alert_id: 'config_status',
} else if (fields[x].nodeName === 'TEXTAREA') { timeout: 2500,
value = fields[x].value; title: 'Changes Saved',
} message: 'Your changes to the NodeBB configuration have been saved.',
type: 'success'
socket.emit('api:config.set', { });
key: key, } else {
value: value app.alert({
}); alert_id: 'config_status',
} timeout: 2500,
title: 'Changes Not Saved',
message: 'NodeBB encountered a problem saving your changes',
type: 'danger'
}); });
} }
});
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 || {}));

View File

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

View File

@@ -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;
});

View File

@@ -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();
});
})();

View File

@@ -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;
});

View File

@@ -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);
});
})();

View File

@@ -1,127 +1,133 @@
$(document).ready(function() { define(function() {
var topicsListEl = document.querySelector('.topics'), var Topics = {};
loadMoreEl = document.getElementById('topics_loadmore');
$(topicsListEl).on('click', '[data-action]', function() { Topics.init = function() {
var $this = $(this), var topicsListEl = document.querySelector('.topics'),
action = this.getAttribute('data-action'), loadMoreEl = document.getElementById('topics_loadmore');
tid = $this.parents('[data-tid]').attr('data-tid');
switch (action) { $(topicsListEl).on('click', '[data-action]', function() {
case 'pin': var $this = $(this),
if (!$this.hasClass('active')) socket.emit('api:topic.pin', { action = this.getAttribute('data-action'),
tid: tid tid = $this.parents('[data-tid]').attr('data-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() { socket.on('api:topic.pin', function(response) {
if (this.className.indexOf('disabled') === -1) { if (response.status === 'ok') {
var topics = document.querySelectorAll('.topics li[data-tid]'), var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]');
lastTid = parseInt(topics[topics.length - 1].getAttribute('data-tid'));
this.innerHTML = '<i class="icon-refresh icon-spin"></i> Retrieving topics'; $(btnEl).addClass('active');
socket.emit('api:admin.topics.getMore', { }
limit: 10, });
after: lastTid
}, function(topics) {
var btnEl = document.getElementById('topics_loadmore');
topics = JSON.parse(topics); socket.on('api:topic.unpin', function(response) {
if (topics.length > 0) { if (response.status === 'ok') {
var html = templates.prepare(templates['admin/topics'].blocks['topics']).parse({ var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]');
topics: topics
}),
topicsListEl = document.querySelector('.topics');
topicsListEl.innerHTML += html; $(btnEl).removeClass('active');
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 socket.on('api:topic.lock', function(response) {
var topicEls = topicsListEl.querySelectorAll('li'), if (response.status === 'ok') {
numTopics = topicEls.length; var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]');
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) { $(btnEl).addClass('active');
if (response.status === 'ok') { }
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); });
$(btnEl).addClass('active'); socket.on('api:topic.unlock', function(response) {
} if (response.status === 'ok') {
}); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]');
socket.on('api:topic.unpin', function(response) { $(btnEl).removeClass('active');
if (response.status === 'ok') { }
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); });
$(btnEl).removeClass('active'); socket.on('api:topic.delete', function(response) {
} if (response.status === 'ok') {
}); var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]');
socket.on('api:topic.lock', function(response) { $(btnEl).addClass('active');
if (response.status === 'ok') { }
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); });
$(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.unlock', function(response) { $(btnEl).removeClass('active');
if (response.status === 'ok') { }
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); });
};
$(btnEl).removeClass('active'); return Topics;
}
});
socket.on('api:topic.delete', function(response) {
if (response.status === 'ok') {
var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]');
$(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"]');
$(btnEl).removeClass('active');
}
}); });

View File

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

View File

@@ -1,41 +1,86 @@
(function () { define(function () {
var cid = templates.get('category_id'), var Category = {};
room = 'category_' + cid,
twitterEl = document.getElementById('twitter-intent'),
facebookEl = document.getElementById('facebook-share'),
googleEl = document.getElementById('google-share'),
twitter_url = templates.get('twitter-intent-url'),
facebook_url = templates.get('facebook-share-url'),
google_url = templates.get('google-share-url'),
loadingMoreTopics = false;
app.enter_room(room); Category.init = function() {
var cid = templates.get('category_id'),
room = 'category_' + cid,
twitterEl = document.getElementById('twitter-intent'),
facebookEl = document.getElementById('facebook-share'),
googleEl = document.getElementById('google-share'),
twitter_url = templates.get('twitter-intent-url'),
facebook_url = templates.get('facebook-share-url'),
google_url = templates.get('google-share-url'),
loadingMoreTopics = false;
twitterEl.addEventListener('click', function () { app.enter_room(room);
window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no');
return false;
}, false);
facebookEl.addEventListener('click', function () {
window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no');
return false;
}, false);
googleEl.addEventListener('click', function () {
window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no');
return false;
}, false);
var new_post = document.getElementById('new_post'); twitterEl.addEventListener('click', function () {
new_post.onclick = function () { window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no');
require(['composer'], function (cmp) { return false;
cmp.push(0, cid); }, false);
facebookEl.addEventListener('click', function () {
window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no');
return false;
}, false);
googleEl.addEventListener('click', function () {
window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no');
return false;
}, false);
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);
}
});
})();

View File

@@ -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;
});

View File

@@ -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'); if (parseInt(followersCount, 10) === 0) {
} $('#no-followers-notice').removeClass('hide');
}
app.addCommasToNumbers(); app.addCommasToNumbers();
};
}); return Followers;
});
}());

View File

@@ -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;
}()); });

View File

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

View File

@@ -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) { socket.on('event:new_topic', function(data) {
++newTopicCount; ++Recent.newTopicCount;
updateAlertText(); Recent.updateAlertText();
}); });
function updateAlertText() { socket.on('event:new_post', function(data) {
++Recent.newPostCount;
Recent.updateAlertText();
});
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !Recent.loadingMoreTopics) {
Recent.loadMoreTopics();
}
});
};
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();
}
});
})();

View File

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

View File

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

View File

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

View File

@@ -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

View File

@@ -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([ app.enter_room('recent_posts');
'event:new_topic',
'event:new_post'
]);
var newTopicCount = 0, ajaxify.register_events([
newPostCount = 0; 'event:new_topic',
'event:new_post'
]);
$('#new-topics-alert').on('click', function() { var newTopicCount = 0,
$(this).hide(); newPostCount = 0;
});
socket.on('event:new_topic', function(data) { $('#new-topics-alert').on('click', function() {
$(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) { socket.on('event:new_topic', function(data) {
var html = templates.prepare(templates['unread'].blocks['topics']).parse({ ++newTopicCount;
topics: topics updateAlertText();
}),
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;
}); });
}
$(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;
});
}
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20)
$('#load-more-btn').show(); $('#load-more-btn').show();
$('#load-more-btn').on('click', function() { $('#load-more-btn').on('click', function() {
loadMoreTopics(); loadMoreTopics();
}); });
};
})(); return Unread;
});

View File

@@ -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;
});

View File

@@ -97,7 +97,4 @@
<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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -25,7 +25,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">

View File

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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -96,6 +96,4 @@
<input type="hidden" template-variable="category_id" value="{category_id}" /> <input type="hidden" template-variable="category_id" value="{category_id}" />
<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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -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" />

View File

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

View File

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

View File

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

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -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>

View File

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

View File

@@ -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>

View File

@@ -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) {