From 676ddcd3e3273391a6495e81669728ade8418219 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 4 Jun 2013 16:20:27 -0400 Subject: [PATCH] integrating the new post window into the forum --- public/css/style.less | 29 ++++- public/src/forum/category.js | 4 +- public/src/forum/topic.js | 21 ++-- public/src/modules/composer.js | 196 +++++++++++++++++++++++++++++++-- src/websockets.js | 20 +++- 5 files changed, 244 insertions(+), 26 deletions(-) diff --git a/public/css/style.less b/public/css/style.less index e9743a8533..96232cbb47 100644 --- a/public/css/style.less +++ b/public/css/style.less @@ -827,6 +827,7 @@ body .navbar .nodebb-inline-block { display: none; -moz-opacity: 0.5; opacity: 0.5; + margin-top: 0; -webkit-transition: opacity 250ms ease-in; -moz-transition: opacity 250ms ease-in; -ms-transition: opacity 250ms ease-in; @@ -862,18 +863,31 @@ body .navbar .nodebb-inline-block { .post-window { position: fixed; bottom: 45px; - height: 30%; + height: 450px; + display: none; - div { + > div { height: 100%; - background: rgba(64, 64, 64, 0.2); + background: rgba(64, 64, 64, 0.6); + + .btn-toolbar { + width: 90%; + margin: 0 auto; + + span { + color: white; + } + } input { width: 100%; text-align: center; - background: none; + background: rgba(255, 255, 255, 0.9); border: none; padding: 0.5em 0; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; } textarea { @@ -885,6 +899,13 @@ body .navbar .nodebb-inline-block { margin: 1em auto; resize: none; color: white; + height: 330px; } } +} + +@media (max-width: 979px) { + .post-window { + position: static; + } } \ No newline at end of file diff --git a/public/src/forum/category.js b/public/src/forum/category.js index 582366f119..620ba2eae9 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -6,7 +6,9 @@ var new_post = document.getElementById('new_post'); new_post.onclick = function() { - app.open_post_window('topic', cid); + require(['composer'], function(cmp) { + cmp.push(0, cid); + }); } ajaxify.register_events([ diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index c11128eb86..c180adfa66 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -430,16 +430,23 @@ else div = '#' + div; jQuery(div + ' .post_reply').click(function() { - if (thread_state.locked !== '1') app.open_post_window('reply', tid, topic_name); + if (thread_state.locked !== '1') { + require(['composer'], function(cmp) { + cmp.push(tid); + }); + } }); jQuery(div + ' .quote').click(function() { - if (thread_state.locked !== '1') app.open_post_window('quote', tid, topic_name); - - var pid = $(this).parents('li').attr('data-pid'); - - $('#post_content').val('> ' + $('#content_' + pid).html() + '\n'); - console.log("POST ID "+pid); + if (thread_state.locked !== '1') { + var pid = $(this).parents('li').attr('data-pid'); + + require(['composer'], function(cmp) { + cmp.push(tid); + console.log($('.post-window textarea'), $('#content_' + pid)); + $('.post-window textarea').val('> ' + $('#content_' + pid).html() + '\n'); + }); + } }); jQuery(div + ' .edit, ' + div + ' .delete').each(function() { diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 0713134035..c6ae89ae7d 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -1,7 +1,8 @@ define(function() { var composer = { initialized: false, - posts: [], + active: 0, + posts: {}, btnContainer: undefined, postContainer: undefined, listEl: undefined @@ -9,7 +10,7 @@ define(function() { composer.init = function() { // Create the fixed bottom bar - var contentEl = document.getElementById('content'); + var footerEl = document.getElementById('footer'); composer.btnContainer = document.createElement('div'); composer.btnContainer.innerHTML = ''; @@ -17,21 +18,122 @@ define(function() { composer.postContainer = document.createElement('div'); composer.postContainer.className = 'post-window row-fluid'; - composer.postContainer.innerHTML = '
'; + composer.postContainer.innerHTML = '
' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '
'; composer.listEl = composer.btnContainer.querySelector('ul'); - document.body.insertBefore(composer.btnContainer, contentEl); + document.body.insertBefore(composer.btnContainer, footerEl); document.body.insertBefore(composer.postContainer, composer.btnContainer); socket.on('api:composer.push', function(threadData) { - console.log(threadData); var uuid = utils.generateUUID(), btnEl = document.createElement('li'); btnEl.innerHTML = '' + threadData.title + ''; btnEl.setAttribute('data-uuid', uuid); composer.listEl.appendChild(btnEl); - composer.posts.push(uuid); + composer.posts[uuid] = { + tid: threadData.tid, + cid: threadData.cid, + title: threadData.tid ? threadData.title : '', + body: '' + }; + composer.active++; composer.update(); + composer.load(uuid); + }); + + // Posts bar events + $(composer.btnContainer).on('click', 'li', function() { + var uuid = this.getAttribute('data-uuid'); + composer.load(uuid); + }); + + // Post Window events + var jPostContainer = $(composer.postContainer), + postContentEl = composer.postContainer.querySelector('textarea') + jPostContainer.on('change', 'input, textarea', function() { + var uuid = $(this).parents('.post-window')[0].getAttribute('data-uuid'); + if (this.nodeName === 'INPUT') composer.posts[uuid].title = this.value; + else if (this.nodeName === 'TEXTAREA') composer.posts[uuid].body = this.value; + }); + jPostContainer.on('click', '.action-bar button', function() { + var action = this.getAttribute('data-action'), + uuid = $(this).parents('.post-window').attr('data-uuid'); + switch(action) { + case 'post': composer.post(uuid); break; + case 'minimize': composer.minimize(); break; + case 'discard': composer.discard(uuid); break; + } + }); + jPostContainer.on('click', '.formatting-bar span', function() { + var iconClass = this.querySelector('i').className, + cursorEnd = postContentEl.value.length, + selectionStart = postContentEl.selectionStart, + selectionEnd = postContentEl.selectionEnd, + selectionLength = selectionEnd - selectionStart; + + switch(iconClass) { + case 'icon-bold': + if (selectionStart === selectionEnd) { + // Nothing selected + postContentEl.value = postContentEl.value + '**bolded text**'; + postContentEl.selectionStart = cursorEnd+2; + postContentEl.selectionEnd = postContentEl.value.length - 2; + } else { + // Text selected + postContentEl.value = postContentEl.value.slice(0, selectionStart) + '**' + postContentEl.value.slice(selectionStart, selectionEnd) + '**' + postContentEl.value.slice(selectionEnd); + postContentEl.selectionStart = selectionStart + 2; + postContentEl.selectionEnd = selectionEnd + 2; + } + break; + case 'icon-italic': + if (selectionStart === selectionEnd) { + // Nothing selected + postContentEl.value = postContentEl.value + '*italicised text*'; + postContentEl.selectionStart = cursorEnd+1; + postContentEl.selectionEnd = postContentEl.value.length - 1; + } else { + // Text selected + postContentEl.value = postContentEl.value.slice(0, selectionStart) + '*' + postContentEl.value.slice(selectionStart, selectionEnd) + '*' + postContentEl.value.slice(selectionEnd); + postContentEl.selectionStart = selectionStart + 1; + postContentEl.selectionEnd = selectionEnd + 1; + } + break; + case 'icon-list': + // Nothing selected + postContentEl.value = postContentEl.value + "\n\n* list item"; + postContentEl.selectionStart = cursorEnd+4; + postContentEl.selectionEnd = postContentEl.value.length; + break; + case 'icon-link': + if (selectionStart === selectionEnd) { + // Nothing selected + postContentEl.value = postContentEl.value + '[link text](link url)'; + postContentEl.selectionStart = cursorEnd+12; + postContentEl.selectionEnd = postContentEl.value.length - 1; + } else { + // Text selected + postContentEl.value = postContentEl.value.slice(0, selectionStart) + '[' + postContentEl.value.slice(selectionStart, selectionEnd) + '](link url)' + postContentEl.value.slice(selectionEnd); + postContentEl.selectionStart = selectionStart + selectionLength + 3; + postContentEl.selectionEnd = selectionEnd + 11; + } + break; + } }); composer.initialized = true; @@ -39,7 +141,7 @@ define(function() { composer.update = function() { if (composer.initialized) { - if (composer.posts.length > 0) { + if (composer.active > 0) { composer.btnContainer.setAttribute('data-active', '1'); } else { composer.btnContainer.removeAttribute('data-active'); @@ -47,13 +149,87 @@ define(function() { } } - composer.push = function(tid) { - socket.emit('api:composer.push', tid); + composer.push = function(tid, cid) { + socket.emit('api:composer.push', { + tid: tid, + cid: cid + }); + } + + composer.load = function(post_uuid) { + var post_data = composer.posts[post_uuid], + titleEl = composer.postContainer.querySelector('input'), + bodyEl = composer.postContainer.querySelector('textarea'); + + composer.postContainer.style.display = 'block'; + composer.postContainer.style.bottom = composer.btnContainer.offsetHeight + "px"; + composer.postContainer.setAttribute('data-uuid', post_uuid); + if (post_data.tid > 0) { + titleEl.value = 'Replying to: ' + post_data.title; + titleEl.readonly = true; + } else { + titleEl.value = post_data.title; + } + bodyEl.value = post_data.body + + // Highlight the button + $('.posts-bar li').removeClass('active'); + composer.btnContainer.querySelector('[data-uuid="' + post_uuid + '"]').className += ' active'; + } + + composer.post = function(post_uuid) { + // Check title and post length + var postData = composer.posts[post_uuid], + titleEl = composer.postContainer.querySelector('input'), + bodyEl = composer.postContainer.querySelector('textarea'); + if (titleEl.value.length <= 3) { + return app.alert({ + type: 'error', + timeout: 5000, + title: 'Title too short', + message: "Please enter a longer title.", + alert_id: 'post_error' + }); + } + + // Still here? Let's post. + if (postData.tid === 0 || postData.cid) { + socket.emit('api:topics.post', { + 'title' : titleEl.value, + 'content' : bodyEl.value, + 'category_id' : postData.cid + }); + } else if (parseInt(postData.tid) > 0) { + socket.emit('api:posts.reply', { + 'topic_id' : postData.tid, + 'content' : bodyEl.value + }); + } + + composer.discard(post_uuid); + } + + composer.discard = function(post_uuid) { + if (composer.posts[post_uuid]) { + // Commit + var btnEl = composer.btnContainer.querySelector('[data-uuid="' + post_uuid + '"]'); + delete composer.posts[post_uuid]; + composer.active--; + btnEl.parentNode.removeChild(btnEl); + composer.minimize(); + composer.update(); + } + } + + composer.minimize = function() { + composer.postContainer.style.display = 'none'; + $('.posts-bar li').removeClass('active'); } composer.init(); return { - push: composer.push + push: composer.push, + load: composer.load }; }); \ No newline at end of file diff --git a/src/websockets.js b/src/websockets.js index 09cea3505d..9e00d73889 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -305,10 +305,22 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }); }); - socket.on('api:composer.push', function(tid) { - topics.get_topic(tid, uid, function(topicData) { - socket.emit('api:composer.push', topicData); - }); + socket.on('api:composer.push', function(data) { + if (data.tid > 0) { + topics.get_topic(data.tid, uid, function(topicData) { + topicData.tid = data.tid; + socket.emit('api:composer.push', topicData); + }); + } else { + user.getUserField(uid, 'username', function(username) { + socket.emit('api:composer.push', { + tid: 0, + cid: data.cid, + username: username, + title: 'New Topic' + }); + }); + } }); });