added topics thumbnails support

v1.18.x
akhoury 11 years ago
parent 9d1a295b85
commit 25207852e8

@ -72,5 +72,12 @@
"composer.discard": "Discard",
"composer.submit": "Submit",
"composer.replying_to": "Replying to",
"composer.new_topic": "New Topic"
"composer.new_topic": "New Topic",
"composer.uploading": "uploading...",
"composer.thumb_url_label": "Paste a topic thumbnail URL",
"composer.thumb_title": "Add a thumbnail to this topic",
"composer.thumb_url_placeholder": "http://example.com/thumb.png",
"composer.thumb_file_label": "Or upload a file",
"composer.thumb_remove": "Clear fields"
}

@ -4,6 +4,11 @@ define(['taskbar'], function(taskbar) {
posts: {}
};
function resetInputFile($el) {
$el.wrap('<form />').closest('form').get(0).reset();
$el.unwrap();
}
function allowed() {
if(!(parseInt(app.uid, 10) > 0 || config.allowGuestPosting)) {
app.alert({
@ -21,16 +26,263 @@ define(['taskbar'], function(taskbar) {
return true;
}
function push(post) {
var uuid = utils.generateUUID();
translator.translate('[[topic:composer.new_topic]]', function(newTopicStr) {
taskbar.push('composer', uuid, {
title: post.title ? post.title : newTopicStr,
icon: post.picture
});
});
composer.posts[uuid] = post;
composer.posts[uuid].uploadsInProgress = [];
composer.load(uuid);
}
//http://stackoverflow.com/questions/14441456/how-to-detect-which-device-view-youre-on-using-twitter-bootstrap-api
function findBootstrapEnvironment() {
var envs = ['xs', 'sm', 'md', 'lg'];
$el = $('<div>');
$el.appendTo($('body'));
for (var i = envs.length - 1; i >= 0; i--) {
var env = envs[i];
$el.addClass('hidden-'+env);
if ($el.is(':hidden')) {
$el.remove();
return env;
}
}
}
function composerAlert(title, message) {
$('.action-bar button').removeAttr('disabled');
app.alert({
type: 'danger',
timeout: 2000,
title: title,
message: message,
alert_id: 'post_error'
});
}
function initializeDragAndDrop(post_uuid) {
if(jQuery.event.props.indexOf('dataTransfer') === -1) {
jQuery.event.props.push('dataTransfer');
}
var draggingDocument = false;
var postContainer = $('#cmp-uuid-' + post_uuid),
fileForm = postContainer.find('#fileForm'),
drop = postContainer.find('.imagedrop'),
tabContent = postContainer.find('.tab-content'),
textarea = postContainer.find('textarea');
$(document).off('dragstart').on('dragstart', function(e) {
draggingDocument = true;
}).off('dragend').on('dragend', function(e) {
draggingDocument = false;
});
textarea.on('dragenter', function(e) {
if(draggingDocument) {
return;
}
drop.css('top', tabContent.position().top + 'px');
drop.css('height', textarea.height());
drop.css('line-height', textarea.height() + 'px');
drop.show();
drop.on('dragleave', function(ev) {
drop.hide();
drop.off('dragleave');
});
});
function cancel(e) {
e.preventDefault();
return false;
}
drop.on('dragover', cancel);
drop.on('dragenter', cancel);
drop.on('drop', function(e) {
e.preventDefault();
var dt = e.dataTransfer,
files = dt.files;
if(files.length) {
var fd = new FormData();
for (var i = 0, file; file = dt.files[i]; i++) {
fd.append('files[]', file, file.name);
}
fileForm[0].reset();
uploadContentFiles({files: files, post_uuid: post_uuid, route: '/api/post/upload', formData: fd});
}
drop.hide();
return false;
});
$(window).off('paste').on('paste', function(event) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
if(items && items.length) {
var blob = items[0].getAsFile();
if(blob) {
blob.name = 'upload-'+ utils.generateUUID();
var fd = new FormData();
fd.append('files[]', blob, blob.name);
fileForm[0].reset();
uploadContentFiles({files: [blob], post_uuid: post_uuid, route: '/api/post/upload', formData: fd});
}
}
});
}
function uploadContentFiles(params) {
var files = params.files,
post_uuid = params.post_uuid,
route = params.route,
formData = params.formData,
callback = params.callback,
postContainer = $('#cmp-uuid-' + post_uuid),
textarea = postContainer.find('textarea'),
text = textarea.val(),
uploadForm = postContainer.find('#fileForm');
uploadForm.attr('action', route);
for(var i = 0; i < files.length; ++i) {
var isImage = files[i].type.match('image.*');
text += (isImage ? '!' : '') + '[' + files[i].name + '](uploading...) ';
if(files[i].size > parseInt(config.maximumFileSize, 10) * 1024) {
uploadForm[0].reset();
return composerAlert('File too big', 'Maximum allowed file size is ' + config.maximumFileSize + 'kbs');
}
}
textarea.val(text);
uploadForm.off('submit').submit(function() {
$(this).find('#postUploadCsrf').val($('#csrf_token').val());
if(formData) {
formData.append('_csrf', $('#csrf_token').val());
}
composer.posts[post_uuid].uploadsInProgress.push(1);
$(this).ajaxSubmit({
resetForm: true,
clearForm: true,
formData: formData,
error: function(xhr) {
app.alertError('Error uploading file! ' + xhr.status);
composer.posts[post_uuid].uploadsInProgress.pop();
if (typeof callback == 'function')
callback(xhr);
},
uploadProgress: function(event, position, total, percent) {
var current = textarea.val();
for(var i=0; i<files.length; ++i) {
var re = new RegExp(files[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, files[i].name+'](uploading ' + percent + '%)'));
}
},
success: function(uploads) {
if(uploads && uploads.length) {
for(var i=0; i<uploads.length; ++i) {
var current = textarea.val();
var re = new RegExp(uploads[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, uploads[i].name + '](' + uploads[i].url + ')'));
}
}
composer.posts[post_uuid].uploadsInProgress.pop();
textarea.focus();
if (typeof callback == 'function')
callback(null, uploads);
}
});
return false;
});
uploadForm.submit();
}
function uploadTopicThumb(params) {
var post_uuid = params.post_uuid,
route = params.route,
formData = params.formData,
callback = params.callback,
postContainer = $('#cmp-uuid-' + post_uuid),
spinner = postContainer.find('.topic-thumb-spinner'),
thumbForm = postContainer.find('#thumbForm');
thumbForm.attr('action', route);
thumbForm.off('submit').submit(function() {
var csrf = $('#csrf_token').val();
$(this).find('#thumbUploadCsrf').val(csrf);
if(formData) {
formData.append('_csrf', csrf);
}
spinner.removeClass('hide');
composer.posts[post_uuid].uploadsInProgress.push(1);
$(this).ajaxSubmit({
formData: formData,
error: function(xhr) {
app.alertError('Error uploading file! ' + xhr.status);
composer.posts[post_uuid].uploadsInProgress.pop();
if (typeof callback == 'function')
callback(xhr);
},
success: function(uploads) {
composer.posts[post_uuid].uploadsInProgress.pop();
postContainer.find('#topic-thumb-url').val((uploads[0] || {}).url || '').trigger('change');
if (typeof callback == 'function')
callback(null, uploads);
},
complete: function(){
spinner.addClass('hide');
}
});
return false;
});
thumbForm.submit();
}
composer.newTopic = function(cid) {
if(allowed()) {
push({
cid: cid,
title: '',
body: '',
modified: false
modified: false,
isMain: true
});
}
}
};
composer.addQuote = function(tid, pid, title, username, text){
if (allowed()) {
@ -58,10 +310,11 @@ define(['taskbar'], function(taskbar) {
tid: tid,
title: title,
body: text,
modified: false
modified: false,
isMain: false
});
}
}
};
composer.editPost = function(pid) {
if(allowed()) {
@ -73,27 +326,13 @@ define(['taskbar'], function(taskbar) {
pid: pid,
title: threadData.title,
body: threadData.body,
modified: false
modified: false,
isMain: !threadData.index,
topic_thumb: threadData.topic_thumb
});
});
}
}
function push(post) {
var uuid = utils.generateUUID();
translator.translate('[[topic:composer.new_topic]]', function(newTopicStr) {
taskbar.push('composer', uuid, {
title: post.title ? post.title : newTopicStr,
icon: post.picture
});
});
composer.posts[uuid] = post;
composer.posts[uuid].uploadsInProgress = [];
composer.load(uuid);
}
};
composer.load = function(post_uuid) {
if($('#cmp-uuid-' + post_uuid).length) {
@ -101,12 +340,15 @@ define(['taskbar'], function(taskbar) {
} else {
composer.createNewComposer(post_uuid);
}
}
};
composer.createNewComposer = function(post_uuid) {
templates.preload_template('composer', function() {
var composerTemplate = templates['composer'].parse({});
var composerTemplate = templates['composer'].parse({
allowTopicsThumbnail: config.allowTopicsThumbnail && composer.posts[post_uuid].isMain && config.hasImageUploadPlugin
});
translator.translate(composerTemplate, function(composerTemplate) {
composerTemplate = $(composerTemplate);
@ -124,7 +366,19 @@ define(['taskbar'], function(taskbar) {
var postData = composer.posts[post_uuid],
titleEl = postContainer.find('.title'),
bodyEl = postContainer.find('textarea');
bodyEl = postContainer.find('textarea'),
thumbToggleBtnEl = postContainer.find('.topic-thumb-toggle-btn'),
toggleThumbEls = function(){
if (config.allowTopicsThumbnail && composer.posts[post_uuid].isMain) {
var url = composer.posts[post_uuid].topic_thumb || '';
postContainer.find('input#topic-thumb-url').val(url);
postContainer.find('img.topic-thumb-preview').attr('src', url);
if (url)
postContainer.find('.topic-thumb-clear-btn').removeClass('hide');
thumbToggleBtnEl.removeClass('hide');
}
};
if (parseInt(postData.tid) > 0) {
translator.translate('[[topic:composer.replying_to]]: ' + postData.title, function(newTitle) {
@ -139,13 +393,44 @@ define(['taskbar'], function(taskbar) {
titleEl.prop('disabled', false);
}
});
toggleThumbEls();
} else {
titleEl.val(postData.title);
titleEl.prop('disabled', false);
toggleThumbEls();
}
bodyEl.val(postData.body);
thumbToggleBtnEl.on('click', function() {
var container = postContainer.find('.topic-thumb-container');
if (container.hasClass('hide')) {
container.removeClass('hide');
} else {
container.addClass('hide');
}
});
postContainer.on('click', '.topic-thumb-clear-btn', function(e) {
postContainer.find('input#topic-thumb-url').val('').trigger('change');
resetInputFile(postContainer.find('input#topic-thumb-file'));
$(this).addClass('hide');
e.preventDefault();
});
postContainer.on('paste change keypress', 'input#topic-thumb-url', function(e) {
var urlEl = $(this);
setTimeout(function(){
var url = urlEl.val();
if (url) {
postContainer.find('.topic-thumb-clear-btn').removeClass('hide');
} else {
resetInputFile(postContainer.find('input#topic-thumb-file'));
postContainer.find('.topic-thumb-clear-btn').addClass('hide');
}
postContainer.find('img.topic-thumb-preview').attr('src', url);
}, 100);
});
postContainer.on('change', 'input, textarea', function() {
composer.posts[post_uuid].modified = true;
@ -236,7 +521,18 @@ define(['taskbar'], function(taskbar) {
$('#files').on('change', function(e) {
var files = e.target.files;
if(files) {
uploadSubmit(files, post_uuid, '/api/post/upload');
uploadContentFiles({files: files, post_uuid: post_uuid, route: '/api/post/upload'});
}
});
postContainer.find('#topic-thumb-file').on('change', function(e) {
var files = e.target.files;
if(files) {
var fd = new FormData();
for (var i = 0, file; file = files[i]; i++) {
fd.append('files[]', file, file.name);
}
uploadTopicThumb({files: files, post_uuid: post_uuid, route: '/api/topic/thumb/upload', formData: fd});
}
});
@ -337,24 +633,6 @@ define(['taskbar'], function(taskbar) {
});
}
//http://stackoverflow.com/questions/14441456/how-to-detect-which-device-view-youre-on-using-twitter-bootstrap-api
function findBootstrapEnvironment() {
var envs = ['xs', 'sm', 'md', 'lg'];
$el = $('<div>');
$el.appendTo($('body'));
for (var i = envs.length - 1; i >= 0; i--) {
var env = envs[i];
$el.addClass('hidden-'+env);
if ($el.is(':hidden')) {
$el.remove();
return env;
}
}
}
composer.activateReposition = function(post_uuid) {
if(composer.active && composer.active !== post_uuid) {
@ -395,7 +673,7 @@ define(['taskbar'], function(taskbar) {
$('body').css({'margin-bottom': postContainer.css('height')});
composer.focusElements(post_uuid);
}
};
composer.focusElements = function(post_uuid) {
var postContainer = $('#cmp-uuid-' + post_uuid),
@ -410,15 +688,18 @@ define(['taskbar'], function(taskbar) {
} else if (parseInt(postData.cid) > 0) {
titleEl.focus();
}
}
};
composer.post = function(post_uuid) {
var postData = composer.posts[post_uuid],
postContainer = $('#cmp-uuid-' + post_uuid),
titleEl = postContainer.find('.title'),
bodyEl = postContainer.find('textarea');
bodyEl = postContainer.find('textarea'),
thumbEl = postContainer.find('input#topic-thumb-url');
titleEl.val(titleEl.val().trim());
bodyEl.val(bodyEl.val().trim());
thumbEl.val(thumbEl.val().trim());
var checkTitle = parseInt(postData.cid, 10) || parseInt(postData.pid, 10);
@ -434,20 +715,22 @@ define(['taskbar'], function(taskbar) {
if (parseInt(postData.cid, 10) > 0) {
socket.emit('topics.post', {
'title' : titleEl.val(),
'content' : bodyEl.val(),
'category_id' : postData.cid
title: titleEl.val(),
content: bodyEl.val(),
topic_thumb: thumbEl.val(),
category_id: postData.cid
}, done);
} else if (parseInt(postData.tid, 10) > 0) {
socket.emit('posts.reply', {
'topic_id' : postData.tid,
'content' : bodyEl.val()
topic_id: postData.tid,
content: bodyEl.val()
}, done);
} else if (parseInt(postData.pid, 10) > 0) {
socket.emit('posts.edit', {
pid: postData.pid,
content: bodyEl.val(),
title: titleEl.val()
title: titleEl.val(),
topic_thumb: thumbEl.val()
}, done);
}
@ -457,18 +740,7 @@ define(['taskbar'], function(taskbar) {
composer.discard(post_uuid);
}
}
}
function composerAlert(title, message) {
$('.action-bar button').removeAttr('disabled');
app.alert({
type: 'danger',
timeout: 2000,
title: title,
message: message,
alert_id: 'post_error'
});
}
};
composer.discard = function(post_uuid) {
if (composer.posts[post_uuid]) {
@ -479,164 +751,14 @@ define(['taskbar'], function(taskbar) {
$('body').css({'margin-bottom': 0});
$('.action-bar button').removeAttr('disabled');
}
}
};
composer.minimize = function(post_uuid) {
var postContainer = $('#cmp-uuid-' + post_uuid);
postContainer.css('visibility', 'hidden');
composer.active = undefined;
taskbar.minimize('composer', post_uuid);
}
function initializeDragAndDrop(post_uuid) {
if(jQuery.event.props.indexOf('dataTransfer') === -1) {
jQuery.event.props.push('dataTransfer');
}
var draggingDocument = false;
var postContainer = $('#cmp-uuid-' + post_uuid),
fileForm = postContainer.find('#fileForm');
drop = postContainer.find('.imagedrop'),
tabContent = postContainer.find('.tab-content'),
textarea = postContainer.find('textarea');
$(document).off('dragstart').on('dragstart', function(e) {
draggingDocument = true;
}).off('dragend').on('dragend', function(e) {
draggingDocument = false;
});
textarea.on('dragenter', function(e) {
if(draggingDocument) {
return;
}
drop.css('top', tabContent.position().top + 'px');
drop.css('height', textarea.height());
drop.css('line-height', textarea.height() + 'px');
drop.show();
drop.on('dragleave', function(ev) {
drop.hide();
drop.off('dragleave');
});
});
function cancel(e) {
e.preventDefault();
return false;
}
drop.on('dragover', cancel);
drop.on('dragenter', cancel);
drop.on('drop', function(e) {
e.preventDefault();
var dt = e.dataTransfer,
files = dt.files;
if(files.length) {
var fd = new FormData();
for (var i = 0, file; file = dt.files[i]; i++) {
fd.append('files[]', file, file.name);
}
fileForm[0].reset();
uploadSubmit(files, post_uuid, '/api/post/upload', fd);
}
drop.hide();
return false;
});
$(window).off('paste').on('paste', function(event) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
if(items && items.length) {
var blob = items[0].getAsFile();
if(blob) {
blob.name = 'upload-'+ utils.generateUUID();
var fd = new FormData();
fd.append('files[]', blob, blob.name);
fileForm[0].reset();
uploadSubmit([blob], post_uuid, '/api/post/upload', fd);
}
}
});
}
function uploadSubmit(files, post_uuid, route, formData, callback) {
var postContainer = $('#cmp-uuid-' + post_uuid),
textarea = postContainer.find('textarea'),
text = textarea.val(),
uploadForm = postContainer.find('#fileForm');
uploadForm.attr('action', route);
for(var i=0; i<files.length; ++i) {
var isImage = files[i].type.match('image.*');
text += (isImage ? '!' : '') + '[' + files[i].name + '](uploading...) ';
if(files[i].size > parseInt(config.maximumFileSize, 10) * 1024) {
uploadForm[0].reset();
return composerAlert('File too big', 'Maximum allowed file size is ' + config.maximumFileSize + 'kbs');
}
}
textarea.val(text);
uploadForm.off('submit').submit(function() {
$(this).find('#postUploadCsrf').val($('#csrf_token').val());
if(formData) {
formData.append('_csrf', $('#csrf_token').val());
}
composer.posts[post_uuid].uploadsInProgress.push(1);
$(this).ajaxSubmit({
resetForm: true,
clearForm: true,
formData: formData,
error: function(xhr) {
app.alertError('Error uploading file! ' + xhr.status);
composer.posts[post_uuid].uploadsInProgress.pop();
},
uploadProgress: function(event, position, total, percent) {
var current = textarea.val();
for(var i=0; i<files.length; ++i) {
var re = new RegExp(files[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, files[i].name+'](uploading ' + percent + '%)'));
}
},
success: function(uploads) {
if(uploads && uploads.length) {
for(var i=0; i<uploads.length; ++i) {
var current = textarea.val();
var re = new RegExp(uploads[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, uploads[i].name + '](' + uploads[i].url + ')'));
}
}
composer.posts[post_uuid].uploadsInProgress.pop();
textarea.focus();
}
});
return false;
});
uploadForm.submit();
}
};
return {
newTopic: composer.newTopic,

@ -35,6 +35,11 @@
<input type="checkbox" data-field="allowGuestSearching"> <strong>Allow guests to search without logging in</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowTopicsThumbnail"> <strong>Allow users to upload topic thumbnails</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="useOutgoingLinksPage"> <strong>Use Outgoing Links Warning Page</strong>

@ -36,8 +36,14 @@
<li class="category-item {topics.deleted-class} {topics.unread-class}" itemprop="itemListElement">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
<!--
todo: tidy this up, not sure what to do with the topic thumbs
todo: fix this nesting if issue#1065 is a win
todo: add a check for config.allowTopicsThumbnail if issue#1066 is a win
-->
<a href="../../user/{topics.userslug}" class="pull-left">
<img class="img-rounded user-img" src="{topics.picture}" title="{topics.username}" />
<img src="<!-- IF topics.thumb -->{topics.thumb}<!-- ELSE -->{topics.picture}<!-- ENDIF topics.thumb -->" class="img-rounded user-img" title="{topics.username}"/>
</a>
<h3>

@ -1,6 +1,40 @@
<div class="composer">
<style>
/* todo: move this to base theme */
.topic-thumb-container { width: 95%; margin-top: 5px; background: rgb(255, 255, 255); background: rgba(255, 255, 255, 0.6); padding: 10px; }
.topic-thumb-btn { cursor: hand; cursor: pointer; }
.topic-thumb-toggle-btn { margin: -25px 3% 0 0; }
.topic-thumb-preview { width: auto; height: auto; max-width: 100px; max-height: 100px }
.topic-thumb-ctrl.form-group { display: inline-block; vertical-align: -50% !important; }
</style>
<div class="composer-container">
<input class="title form-control" type="text" tabIndex="1" placeholder="[[topic:composer.title_placeholder]]" />
<!-- IF allowTopicsThumbnail -->
<i class="fa fa-picture-o pull-right topic-thumb-btn topic-thumb-toggle-btn hide" title="[[topic:composer.thumb_title]]"></i>
<div class="topic-thumb-container center-block hide">
<form id="thumbForm" method="post" class="topic-thumb-form form-inline" enctype="multipart/form-data">
<img class="topic-thumb-preview"></img>
<div class="form-group">
<label for="topic-thumb-url">[[topic:composer.thumb_url_label]]</label>
<input type="text" id="topic-thumb-url" class="form-control" placeholder="[[topic:composer.thumb_url_placeholder]]" />
</div>
<div class="form-group">
<!-- todo: drag and drop? -->
<label for="topic-thumb-file">[[topic:composer.thumb_file_label]]</label>
<input type="file" id="topic-thumb-file" class="form-control" />
</div>
<div class="form-group topic-thumb-ctrl">
<i class="fa fa-spinner fa-spin hide topic-thumb-spinner" title="[[topic:composer.uploading]]"></i>
<i class="fa fa-times topic-thumb-btn hide topic-thumb-clear-btn" title="[[topic:composer.thumb_remove]]"></i>
<input id="thumbUploadCsrf" type="hidden" name="_csrf">
</div>
</form>
</div>
<!-- ENDIF allowTopicsThumbnail -->
<div class="btn-toolbar formatting-bar">
<div class="btn-group">
<span class="btn btn-link" tabindex="-1"><i class="fa fa-bold"></i></span>
@ -44,7 +78,7 @@
<div class="text-center">
<span>
<small>Content is parsed with <a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a>. </small>
<span class="upload-instructions hide"><small>Upload images by dragging & dropping them.</small></span>
<span class="upload-instructions hide"><small>Upload content images by dragging & dropping them.</small></span>
</span>
</div>

@ -217,6 +217,9 @@ var async = require('async'),
}, {
field: 'allowGuestSearching',
value: 0
}, {
field: 'allowTopicsThumbnail',
value: 0
}, {
field: 'allowRegistration',
value: 1

@ -64,7 +64,9 @@ var winston = require('winston'),
}
PostTools.edit = function(uid, pid, title, content) {
PostTools.edit = function(uid, pid, title, content, options) {
options || (options = {});
var websockets = require('./socket.io'),
success = function() {
posts.setPostFields(pid, {
@ -89,6 +91,7 @@ var winston = require('winston'),
topics.setTopicField(tid, 'title', title);
topics.setTopicField(tid, 'slug', slug);
topics.setTopicField(tid, 'thumb', options.topic_thumb);
db.searchRemove('topic', tid, function() {
db.searchIndex('topic', title, tid);

@ -2,9 +2,7 @@ var db = require('./database'),
utils = require('./../public/src/utils'),
user = require('./user'),
topics = require('./topics'),
categories = require('./categories'),
favourites = require('./favourites'),
threadTools = require('./threadTools'),
postTools = require('./postTools'),
categories = require('./categories'),
plugins = require('./plugins'),

@ -57,6 +57,7 @@ var path = require('path'),
config.useOutgoingLinksPage = parseInt(meta.config.useOutgoingLinksPage, 10) === 1;
config.allowGuestPosting = parseInt(meta.config.allowGuestPosting, 10) === 1;
config.allowFileUploads = parseInt(meta.config.allowFileUploads, 10) === 1;
config.allowTopicsThumbnail = parseInt(meta.config.allowTopicsThumbnail, 10) === 1;
config.usePagination = parseInt(meta.config.usePagination, 10) === 1;
config.topicsPerPage = meta.config.topicsPerPage || 20;
config.postsPerPage = meta.config.postsPerPage || 20;
@ -448,7 +449,7 @@ var path = require('path'),
}
});
app.post('/post/upload', function(req, res, next) {
function upload(req, res, filesIterator, next) {
if(!req.user) {
return res.json(403, {message:'not allowed'});
}
@ -469,21 +470,33 @@ var path = require('path'),
}
}
async.map(files, function(file, next) {
async.map(files, filesIterator, function(err, images) {
deleteTempFiles();
if(err) {
return res.json(500, {message: err.message});
}
res.json(200, images);
});
}
app.post('/post/upload', function(req, res, next) {
upload(req, res, function(file, next) {
if(file.type.match('image.*')) {
posts.uploadPostImage(file, next);
} else {
posts.uploadPostFile(file, next);
}
}, function(err, images) {
deleteTempFiles();
}, next)
});
if(err) {
return res.json(500, {message: err.message});
app.post('/topic/thumb/upload', function(req, res, next) {
upload(req, res, function(file, next) {
if(file.type.match('image.*')) {
topics.uploadTopicThumb(file, next);
} else {
res.json(500, {message: 'Invalid File'});
}
res.json(200, images);
});
}, next)
});
app.get('/reset', function (req, res) {

@ -29,19 +29,21 @@ SocketModules.composer.push = function(socket, pid, callback) {
posts.getPostFields(pid, ['content'], next);
},
function(next) {
topics.getTitleByPid(pid, function(title) {
next(null, title);
});
topics.getTopicDataByPid(pid, next);
},
function(next) {
posts.getPidIndex(pid, next);
}
], function(err, results) {
if(err) {
return callback(err);
}
callback(null, {
title: results[1],
pid: pid,
body: results[0].content
body: results[0].content,
title: results[1].title,
topic_thumb: results[1].thumb,
index: results[2]
});
});
}

@ -148,7 +148,7 @@ SocketPosts.edit = function(socket, data, callback) {
return callback(new Error('content-too-short'));
}
postTools.edit(socket.uid, data.pid, data.title, data.content);
postTools.edit(socket.uid, data.pid, data.title, data.content, {topic_thumb: data.topic_thumb});
callback();
};

@ -23,7 +23,7 @@ SocketTopics.post = function(socket, data, callback) {
return callback(new Error('not-logged-in'));
}
topics.post(socket.uid, data.title, data.content, data.category_id, function(err, result) {
topics.post({uid: socket.uid, title: data.title, content: data.content, cid: data.category_id, thumb: data.topic_thumb}, function(err, result) {
if(err) {
if (err.message === 'title-too-short') {
module.parent.exports.emitAlert(socket, 'Title too short', 'Please enter a longer title. At least ' + meta.config.minimumTitleLength + ' characters.');

@ -1,5 +1,6 @@
var async = require('async'),
gravatar = require('gravatar'),
path = require('path'),
nconf = require('nconf'),
validator = require('validator'),
S = require('string'),
@ -8,6 +9,7 @@ var async = require('async'),
db = require('./database'),
posts = require('./posts'),
utils = require('./../public/src/utils'),
plugins = require('./plugins'),
user = require('./user'),
categories = require('./categories'),
categoryTools = require('./categoryTools'),
@ -20,7 +22,12 @@ var async = require('async'),
(function(Topics) {
Topics.create = function(uid, title, cid, callback) {
Topics.create = function(data, callback) {
var uid = data.uid,
title = data.title,
cid = data.cid,
thumb = data.thumb;
db.incrObjectField('global', 'nextTid', function(err, tid) {
if(err) {
return callback(err);
@ -41,7 +48,8 @@ var async = require('async'),
'viewcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
'pinned': 0,
'thumb': thumb || ''
}, function(err) {
if(err) {
return callback(err);
@ -61,7 +69,13 @@ var async = require('async'),
});
};
Topics.post = function(uid, title, content, cid, callback) {
Topics.post = function(data, callback) {
var uid = data.uid,
title = data.title,
content = data.content,
cid = data.cid,
thumb = data.thumb;
if (title) {
title = title.trim();
}
@ -98,7 +112,7 @@ var async = require('async'),
user.isReadyToPost(uid, next);
},
function(next) {
Topics.create(uid, title, cid, next);
Topics.create({uid: uid, title: title, cid: cid}, next);
},
function(tid, next) {
Topics.reply(tid, uid, content, next);
@ -210,7 +224,7 @@ var async = require('async'),
posts.getCidByPid(mainPid, callback);
}
}, function(err, results) {
Topics.create(results.postData.uid, title, results.cid, function(err, tid) {
Topics.create({uid: results.postData.uid, title: title, cid: results.cid}, function(err, tid) {
if(err) {
return callback(err);
}
@ -847,6 +861,7 @@ var async = require('async'),
'pinned': topicData.pinned,
'timestamp': topicData.timestamp,
'slug': topicData.slug,
'thumb': topicData.thumb,
'postcount': topicData.postcount,
'viewcount': topicData.viewcount,
'pageCount': pageCount,
@ -936,13 +951,43 @@ var async = require('async'),
};
Topics.getTitleByPid = function(pid, callback) {
Topics.getTopicFieldByPid('title', pid, callback);
};
Topics.getTopicFieldByPid = function(field, pid, callback) {
posts.getPostField(pid, 'tid', function(err, tid) {
Topics.getTopicField(tid, 'title', function(err, title) {
callback(title);
});
Topics.getTopicField(tid, field, callback);
});
};
Topics.getTopicDataByPid = function(pid, callback) {
posts.getPostField(pid, 'tid', function(err, tid) {
Topics.getTopicData(tid, callback);
});
};
Topics.uploadTopicThumb = function(image, callback) {
if(plugins.hasListeners('filter:uploadImage')) {
plugins.fireHook('filter:uploadImage', image, callback);
} else {
if (meta.config.allowTopicsThumbnail) {
var filename = 'upload-' + utils.generateUUID() + path.extname(image.name);
require('./file').saveFileToLocal(filename, image.path, function(err, upload) {
if(err) {
return callback(err);
}
callback(null, {
url: upload.url,
name: image.name
});
});
} else {
callback(new Error('Topic Thumbnails are disabled!'));
}
}
};
Topics.markAsUnreadForAll = function(tid, callback) {
db.delete('tid:' + tid + ':read_by_uid', function(err) {
if(err) {
@ -1011,10 +1056,9 @@ var async = require('async'),
db.isSetMember('tid:' + tid + ':read_by_uid', uid, function(err, hasRead) {
if (err === null) {
if (!err) {
callback(hasRead);
} else {
console.log(err);
callback(false);
}
});

@ -647,7 +647,7 @@ module.exports.server = server;
topics: topicData
});
});
},
}
], function (err, data) {
if (err) {
if (err.message === 'not-enough-privileges') {
@ -865,7 +865,7 @@ module.exports.server = server;
return custom_routes.templates.map(function(tpl) {
return tpl.template.split('.tpl')[0];
});
}
};
plugins.ready(function() {
plugins.fireHook('filter:server.create_routes', custom_routes, function(err, custom_routes) {

@ -25,7 +25,7 @@ describe('Topic\'s', function() {
describe('.post', function() {
it('should create a new topic with proper parameters', function(done) {
Topics.post(topic.userId, topic.title, topic.content, topic.categoryId, function(err, result) {
Topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function(err, result) {
assert.equal(err, null, 'was created with error');
assert.ok(result);
@ -36,7 +36,7 @@ describe('Topic\'s', function() {
it('should fail to create new topic with wrong parameters', function(done) {
topic.userId = null;
Topics.post(topic.userId, topic.title, topic.content, topic.categoryId, function(err, result) {
Topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function(err, result) {
assert.equal(err.message, 'invalid-user');
done();
});
@ -48,7 +48,7 @@ describe('Topic\'s', function() {
var newPost;
beforeEach(function(done){
Topics.post(topic.userId, topic.title, topic.content, topic.categoryId, function(err, result) {
Topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function(err, result) {
newTopic = result.topicData;
newPost = result.postData;
done();

Loading…
Cancel
Save