more fixes to ajaxify, updated /users blocks to sit flush to the left, started work on the ACP including basic templates, added a method to get active users in all rooms (socket connections), added more routes mostly pointing to admin, added a routing folder to start organizing routes better, starting with admin.

v1.18.x
psychobunny 12 years ago
parent 8e1ee88878
commit f3f08a9c94

@ -405,7 +405,8 @@ footer.footer {
.users-box{
display:inline-block;
margin:20px;
margin-right:20px;
margin-top: 20px;
text-align:center;
}

@ -34,9 +34,11 @@ var ajaxify = {};
var tpl_url = templates.get_custom_map(url);
if (tpl_url == false) {
if (tpl_url == false && !templates[url]) {
tpl_url = (url === '' || url === '/') ? 'home' : url.split('/')[0];
}
} else if (templates[url]) {
tpl_url = url;
}
if (templates[tpl_url]) {
window.history.pushState({}, url, "/" + url);

@ -68,7 +68,8 @@ var templates = {};
'header', 'footer', 'register', 'home', 'topic','account', 'category', 'users', 'accountedit',
'login', 'reset', 'reset_code', 'account',
'confirm',
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext'
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext',
'admin/index', 'admin/categories', 'admin/users', 'admin/topics', 'admin/settings', 'admin/themes', 'admin/twitter', 'admin/facebook', 'admin/gplus'
]);
}
@ -168,15 +169,15 @@ function load_template(callback, custom_tpl) {
jQuery.get(API_URL + url, function(data) {
var tpl = templates.get_custom_map(url);
if (tpl == false) {
tpl = url.split('/')[0];
if (tpl == false && !templates[url]) {
tpl = (url === '' || url === '/') ? 'home' : url.split('/')[0];
} else if (templates[url]) {
tpl = url;
}
if (custom_tpl && custom_tpl != "undefined")
tpl = custom_tpl;
document.getElementById('content').innerHTML = templates[tpl].parse(JSON.parse(data));
if (callback) callback();
});

@ -0,0 +1,75 @@
<h1>Categories</h1>
<hr />
<ul class="nav nav-pills">
<li class='active'><a href='/admin/categories/active'>Active</a></li>
<li class=''><a href='/admin/categories/disabled'>Disabled</a></li>
</ul>
<div class="row-fluid admin-categories">
<ul class="span12" id="entry-container">
<!-- BEGIN categories -->
<li class="entry-row {categories.blockclass}">
<form class="form-inline">
<div class="icon">
<i class="{categories.icon} icon-2x"></i>
</div>
<input value="{categories.name}" class="input-medium"></input>
<select class="blockclass input-medium" data-value="{categories.blockclass}" onchange="update_blockclass(this);">
<option value="category-purple">category-purple</option>
<option value="category-darkblue">category-darkblue</option>
<option value="category-blue">category-blue</option>
<option value="category-darkgreen">category-darkgreen</option>
<option value="category-orange">category-orange</option>
</select>
<input value="{categories.icon}" class="input-medium" onchange="update_icon(this);"></input>
<!--<input value="{categories.description}" class="input-medium"></input>-->
<!--<a target="_blank" href="../category/{categories.slug}">category/{categories.slug}</a>-->
<!--<div style="float: right">
<button class="btn btn-large btn-inverse">Save</button>
</div>-->
</form>
</li>
<!-- END categories -->
</ul>
</div>
<script type="text/javascript">
function update_blockclass(el) {
el.parentNode.parentNode.className = 'entry-row ' + el.value;
}
function update_icon(el) {
jQuery(el.parentNode.parentNode);
}
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() {
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;
}
})
});
}());
</script>

@ -0,0 +1,13 @@
<h1>Facebook Social Authentication</h1>
<hr />
<form>
<div class="alert alert-notify">
<p>Create a <strong>Facebook Application</strong> and then paste your application details here.</p><br />
<input type="text" class="" placeholder="App Key"><br />
<input type="text" class="" placeholder="App Secret"><br />
</div>
</form>
<button class="btn btn-large btn-primary" type="submit">Save</button>
<button class="btn btn-large" type="submit" disabled>Delete</button>

@ -0,0 +1,31 @@
</div>
</div>
<div id="footer" class="container" style="padding-top: 50px; display:none;">
<footer class="footer">Copyright &copy; 2013 <a target="_blank" href="http://www.nodebb.com">NodeBB</a> by <a target="_blank" href="https://github.com/psychobunny">psychobunny</a>, <a href="https://github.com/julianlam" target="_blank">julianlam</a>, <a href="https://github.com/barisusakli" target="_blank">barisusakli</a> from <a target="_blank" href="http://www.designcreateplay.com">designcreateplay</a></footer>
</div>
<script type="text/javascript">
(function() {
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);
});
}())
</script>
</body>
</html>

@ -0,0 +1,13 @@
<h1>Google Plus Social Authentication</h1>
<hr />
<form>
<div class="alert alert-notify">
<p>Create a <strong>Google+ Application</strong> and then paste your application details here.</p><br />
<input type="text" class="" placeholder="App ID"><br />
<input type="text" class="" placeholder="App Secret"><br />
</div>
</form>
<button class="btn btn-large btn-primary" type="submit">Save</button>
<button class="btn btn-large" type="submit" disabled>Delete</button>

@ -0,0 +1,106 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/vendor/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet" media="screen">
<link rel="stylesheet" href="/vendor/fontawesome/css/font-awesome.min.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript" src="/vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="/src/app.js"></script>
<script type="text/javascript" src="/src/templates.js"></script>
<script type="text/javascript" src="/src/ajaxify.js"></script>
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
<style type="text/css">
.entry-row {
border-radius: 10px;
margin-bottom: 10px;
padding: 10px;
cursor: move;
width: 555px;
}
.admin-categories form {
margin: 0 0 0px;
}
.admin-categories input {
height: 20px;
padding: 5px;
margin-left: 10px;
width: 150px;
border: 0;
border-radius: 5px;
margin-top: -8px;
}
.admin-categories select {
border: 0;
margin-left: 10px;
padding: 5px;
margin-top: -8px;
}
.admin-categories button {
margin-top: -7px;
}
.admin-categories .icon{
width: 30px;
height: 30px;
text-align: center;
line-height: 35px;
display: inline-block;
}
</style>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="/admin/index">NodeBB ACP</a>
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="nav-collapse collapse">
<ul class="nav">
<li>
<a href="/admin/index"><i class="icon-home"></i> Home</a>
</li>
<li>
<a href="/admin/settings"><i class="icon-cogs"></i> Settings</a>
</li>
</ul>
<ul class="nav pull-right" id="right-menu">
<li><a href="/users" id="user_label"></a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">NodeBB</li>
<li class='active'><a href='/admin/index'><i class='icon-home'></i> Home</a></li>
<li class=''><a href='/admin/categories'><i class='icon-folder-close-alt'></i> Categories</a></li>
<li class=''><a href='/admin/users'><i class='icon-user'></i> Users</a></li>
<li class=''><a href='/admin/topics'><i class='icon-book'></i> Topics</a></li>
<li class=''><a href='/admin/themes'><i class='icon-th'></i> Themes</a></li>
<li class=''><a href='/admin/settings'><i class='icon-cogs'></i> Settings</a></li>
<li class="nav-header">Social Authentication</li>
<li class=''><a href='/admin/twitter'><i class='icon-twitter'></i>Twitter</a></li>
<li class=''><a href='/admin/facebook'><i class='icon-facebook'></i>Facebook</a></li>
<li class=''><a href='/admin/gplus'><i class='icon-google-plus'></i>Google+</a></li>
<li class="nav-header">Custom Modules</li>
<li class=''><a href=''>Search</a></li>
</ul>
</div><!--/.well -->
</div><!--/span-->
<div class="span9" id="content">

@ -0,0 +1,42 @@
<div class="hero-unit">
<h1>Welcome to NodeBB</h1>
<br />
<p>
<a target="_blank" href="http://www.nodebb.org" class="btn btn-large"><i class="icon-comment"></i> NodeBB Forum</a>
<a target="_blank" href="http://www.nodebb.org" class="btn btn-large"><i class="icon-github-alt"></i> Get Plugins</a>
<a target="_blank" href="http://www.nodebb.org" class="btn btn-large"><i class="icon-github-alt"></i> Get Themes</a>
<a target="_blank" href="http://www.nodebb.org" class="btn btn-large"><i class="icon-twitter"></i> dcplabs</a>
</p>
<p><small>You are running <strong>NodeBB v0.0.1</strong>. This is where we will check to make sure your <strong>NodeBB</strong> is latest, etc.</small></p>
</div>
<div class="">
<h2>Active Users <small><span class="badge" id="connections"></span> socket connections</small></h2>
<p id="active_users">
</p>
</div>
<script type="text/javascript">
ajaxify.register_events(['api:get_all_rooms']);
socket.on('api:get_all_rooms', function(data) {
var active_users = document.getElementById('active_users'),
total = 0;
for(var room in data) {
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><br />";
}
}
document.getElementById('connections').innerHTML = total;
});
socket.emit('api:get_all_rooms');
</script>

@ -0,0 +1,24 @@
<h1>Settings</h1>
<hr />
<form>
<h3>Privilege Thresholds</h3>
<div class="alert alert-notify">
<p>Use <strong>privilege thresholds</strong> to manage how much reputation a user must gain to receive moderator access.</p><br />
<strong>Manage Thread</strong><br /> <input type="text" class="" value="1000"><br />
<strong>Moderate Users</strong><br /> <input type="text" class="" value="10000"><br />
<strong>Create Pinned Topics</strong><br /> <input type="text" class="" value="100000"><br />
</div>
</form>
<form>
<h3>Email Settings</h3>
<div class="alert alert-notify">
<strong>Email Address</strong><br /> <input type="text" class="" value="info@localhost"><br />
</div>
</form>
<button class="btn btn-large btn-primary" type="submit">Save</button>
<button class="btn btn-large" type="submit" disabled>Delete</button>

@ -0,0 +1,2 @@
<h1>Themes</h1>
<hr />

@ -0,0 +1,55 @@
<h1>Topics</h1>
<hr />
<ul class="nav nav-pills">
<li class='active'><a href='/admin/topics'>All</a></li>
<li class=''><a href='/admin/topics/latest'>Latest</a></li>
<li class=''><a href='/admin/topics/active'>Active</a></li>
</ul>
<ul class="topic-container">
<!-- BEGIN topics -->
<a href="../../topic/{topics.slug}"><li class="topic-row">
<div class="row" style="margin: 0">
<div class="span1 topic-row-icon">
<i class="icon-lock icon-4x"></i>
<i class="{topics.pin-icon}"></i><i class="{topics.lock-icon}"></i>
</div>
<div class="span11 topic-row-content">
<div class="top-posters">
<img src="http://www.gravatar.com/avatar/fd37ce111f863c6665045c2d72d199bf?s=60" class="img-polaroid" />
<img src="http://www.gravatar.com/avatar/07c9c7170c3ac676c2561e3eeaee063c?s=60" class="img-polaroid" />
<img src="http://www.gravatar.com/avatar/91050ce0072697b53380c6a03a1bc12a?s=60" class="img-polaroid" />
</div>
<div>
<h3><span class="badge badge-important">3</span> {topics.title} <small>24<i class="icon-star"></i></small></h3>
<p> Posted {topics.relativeTime} ago by
<span class="username">{topics.username}</span>. {topics.post_count} posts.</p>
</div>
</div>
</div>
</li></a>
<!-- END topics -->
</ul>
<script type="text/javascript">
//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() {
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;
}
})
});
}());
</script>

@ -0,0 +1,14 @@
<h1>Twitter Social Authentication</h1>
<hr />
<form>
<div class="alert alert-notify">
<p>Create a <strong>Twitter Application</strong> and then paste your application details here.</p><br />
<input type="text" class="" placeholder="App Key"><br />
<input type="text" class="" placeholder="App Secret"><br />
</div>
</form>
<button class="btn btn-large btn-primary" type="submit">Save</button>
<button class="btn btn-large" type="submit" disabled>Delete</button>

@ -0,0 +1,55 @@
<h1>Users</h1>
<hr />
<ul class="nav nav-pills">
<li class='active'><a href='/admin/users'>Latest Users</a></li>
<li class=''><a href='/admin/users/sort-posts'>Top Posters</a></li>
<li class=''><a href='/admin/users/sort-reputation'>Most Reputation</a></li>
<li class=''><a href='/admin/users/search'>Search</a></li>
</ul>
<div class="search {search_display} well">
<input type="text" placeholder="Enter a username to search" onkeypress="jQuery('.icon-spinner').removeClass('none');" /><br />
<i class="icon-spinner icon-spin none"></i>
</div>
<!-- BEGIN users -->
<div class="users-box well">
<a href="/users/{users.username}">
<img src="{users.picture}"/>
</a>
<br/>
<a href="/users/{users.username}">{users.username}</a>
<br/>
<div title="reputation">
<span id='reputation'>{users.reputation}</span>
<i class='icon-star'></i>
</div>
<div title="post count">
<span id='postcount'>{users.postcount}</span>
<i class='icon-pencil'></i>
</div>
</div>
<!-- END users -->
<script type="text/javascript">
//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() {
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;
}
})
});
}());
</script>

@ -1,5 +1,8 @@
{
"custom_mapping": {
"admin/topics[^]*": "admin/topics",
"admin/categories[^]*": "admin/categories",
"admin/users[^]*": "admin/users",
"users[^]*edit": "accountedit",
"users": "account",
"latest": "category",

@ -0,0 +1,62 @@
(function(Admin) {
Admin.create_routes = function(app) {
(function() {
var routes = ['categories', 'users', 'topics', 'settings', 'themes', 'twitter', 'facebook', 'gplus'];
for (var i=0, ii=routes.length; i<ii; i++) {
(function(route) {
app.get('/admin/' + route, function(req, res) {
res.send(templates['admin/header'] + app.create_route('admin/' + route) + templates['admin/footer']);
});
}(routes[i]));
}
}());
//todo consolidate.
app.get('/admin', function(req, res) {
res.send(templates['admin/header'] + app.create_route('admin/index') + templates['admin/footer']);
});
app.get('/admin/index', function(req, res) {
res.send(templates['admin/header'] + app.create_route('admin/index') + templates['admin/footer']);
});
function api_method(req, res) {
switch(req.params.method) {
case 'users' :
if (req.params.tab == 'search') {
res.send(JSON.stringify({search_display: 'block', users: []}))
} else {
global.modules.user.getUserList(function(data){
res.send(JSON.stringify({search_display: 'none', users:data}));
});
}
break;
case 'categories':
if (req.params.tab == 'disabled') {
res.send(JSON.stringify({categories: []}));
} else {
global.modules.categories.get(function(data) {
res.send(JSON.stringify(data));
});
}
break;
case 'topics' :
global.modules.topics.get(function(data) {
res.send(JSON.stringify(data));
});
break;
default :
res.send('{}');
}
}
app.get('/api/admin/:method/:tab?*', api_method);
app.get('/api/admin/:method*', api_method);
};
}(exports));

@ -1,4 +1,4 @@
// to be deprecated in favour of client-side only templates.
(function(Templates) {
@ -28,6 +28,7 @@
'header', 'footer', 'register', 'home', 'topic', 'account',
'login', 'reset', 'reset_code', 'logout',
'403',
'admin/header', 'admin/footer', 'admin/index',
'emails/header', 'emails/footer',
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext'
]);

@ -13,6 +13,7 @@ var express = require('express'),
passportFacebook = require('passport-facebook').Strategy,
user = require('./user.js'),
utils = require('./utils.js'),
admin = require('./routes/admin.js'),
login_strategies = [];
passport.use(new passportLocal(function(user, password, next) {
@ -122,9 +123,10 @@ passport.deserializeUser(function(uid, done) {
});
function create_route(url, tpl) {
function create_route(url, tpl) { // to remove
return '<script>templates.ready(function(){ajaxify.go("' + url + '", null, "' + tpl + '");});</script>';
}
app.create_route = create_route;
// Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section)
@ -162,6 +164,8 @@ passport.deserializeUser(function(uid, done) {
res.send(templates['header'] + '<script>templates.ready(function(){ajaxify.go("confirm/' + req.params.code + '");});</script>' + templates['footer']);
});
admin.create_routes(app);
// These functions are called via ajax once the initial page is loaded to populate templates with data
function api_method(req, res) {

@ -65,7 +65,10 @@ var SocketIO = require('socket.io').listen(global.server,{log:false}),
delete users[hs.sessionID];
});
socket.on('api:get_all_rooms', function(data) {
console.log('recieve');
socket.emit('api:get_all_rooms', io.sockets.manager.rooms);
})
socket.on('event:enter_room', function(data) {
if (data.leave !== null) socket.leave (data.leave);

Loading…
Cancel
Save