From f29b375ed4be7fa88bfd6646324133821201f12c Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Fri, 20 Dec 2013 18:41:56 -0500 Subject: [PATCH] refactored composer so that it uses a different div for each instance, closes #575 --- public/src/modules/composer.js | 685 +++++++++++++++++---------------- src/websockets.js | 17 +- 2 files changed, 363 insertions(+), 339 deletions(-) diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 63988eaaa0..62505897f6 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -1,381 +1,294 @@ define(['taskbar'], function(taskbar) { var composer = { - initialized: false, active: undefined, taskbar: taskbar, - posts: {}, - postContainer: undefined, + posts: {} }; - function createImagePlaceholder(img) { - var text = $('.post-window textarea').val(), - textarea = $('.post-window textarea'), - imgText = "!["+img.name+"](uploading...)", - uuid = $('.post-window .imagedrop').parents('[data-uuid]').attr('data-uuid'); - - text += imgText; - textarea.val(text + " "); - if(!composer.posts[uuid].uploadsInProgress) { - composer.posts[uuid].uploadsInProgress = []; - } - - composer.posts[uuid].uploadsInProgress.push(1); + composer.push = function(tid, cid, pid, text) { - socket.emit("api:posts.uploadImage", img, function(err, data) { - if(err) { - return app.alertError(err.message); + socket.emit('api:composer.push', { + tid: tid, // Replying + cid: cid, // Posting + pid: pid, // Editing + body: text // Predefined text + }, function(threadData) { + + if(threadData.error) { + app.alert({ + type: 'danger', + timeout: 5000, + alert_id: 'post_error', + title: 'Please Log In to Post', + message: 'Posting is currently restricted to registered members only, click here to log in', + clickfn: function() { + ajaxify.go('login'); + } + }); + return; } - var currentText = textarea.val(); - imgText = "!["+data.name+"](uploading...)"; - - if(!err) - textarea.val(currentText.replace(imgText, "!["+data.name+"]("+data.url+")")); - else - textarea.val(currentText.replace(imgText, "!["+data.name+"](upload error)")); - composer.posts[uuid].uploadsInProgress.pop(); - }); - } - function loadFile(file) { - var reader = new FileReader(), - dropDiv = $('.post-window .imagedrop'); + var uuid = utils.generateUUID(); - $(reader).on('loadend', function(e) { - var bin = this.result; - bin = bin.split(',')[1]; + composer.taskbar.push('composer', uuid, { + title: (!threadData.cid ? (threadData.title || '') : 'New Topic'), + icon: threadData.picture + }); - var img = { - name: file.name, - data: bin + composer.posts[uuid] = { + tid: threadData.tid, + cid: threadData.cid, + pid: threadData.pid, + title: threadData.title || '', + body: threadData.body || '', + modified: false }; - createImagePlaceholder(img); - - dropDiv.hide(); + composer.load(uuid); }); + } - reader.readAsDataURL(file); + composer.load = function(post_uuid) { + if($('#cmp-uuid-' + post_uuid).length) { + composer.activateReposition(post_uuid); + } else { + composer.createNewComposer(post_uuid); + } } - function initializeFileReader() { - jQuery.event.props.push( "dataTransfer" ); + composer.createNewComposer = function(post_uuid) { - var draggingDocument = false; + templates.preload_template('composer', function() { - if(window.FileReader) { - var drop = $('.post-window .imagedrop'), - textarea = $('.post-window textarea'); + var composerTemplate = templates['composer'].parse({}); + composerTemplate = $(composerTemplate); - $(document).on('dragstart', function(e) { - draggingDocument = true; - }).on('dragend', function(e) { - draggingDocument = false; - }); + composerTemplate.attr('id', 'cmp-uuid-' + post_uuid); - textarea.on('dragenter', function(e) { - if(draggingDocument) { - return; - } - drop.css('top', textarea.position().top + 'px'); - drop.show(); + $(document.body).append(composerTemplate); - drop.on('dragleave', function(ev) { - drop.hide(); - drop.off('dragleave'); - }); - }); + composer.activateReposition(post_uuid); - function cancel(e) { - e.preventDefault(); - return false; - } + var postContainer = $(composerTemplate[0]); - drop.on('dragover', cancel); - drop.on('dragenter', cancel); + if(config.imgurClientIDSet) { + initializeFileReader(post_uuid); + } - drop.on('drop', function(e) { - e.preventDefault(); - var uuid = drop.parents('[data-uuid]').attr('data-uuid'), - dt = e.dataTransfer, - files = dt.files; + var postData = composer.posts[post_uuid], + titleEl = postContainer.find('.title'), + bodyEl = postContainer.find('textarea'); + + if (parseInt(postData.tid) > 0) { + titleEl.val('Replying to: ' + postData.title); + titleEl.prop('readOnly', true); + } else if (parseInt(postData.pid) > 0) { + titleEl.val(postData.title); + titleEl.prop('readOnly', true); + socket.emit('api:composer.editCheck', postData.pid, function(editCheck) { + if (editCheck.titleEditable) { + postContainer.find('input').prop('readonly', false); + } + }); + } else { + titleEl.val(postData.title); + titleEl.prop('readOnly', false); + } - for (var i=0; i 0) { - titleEl.value = 'Replying to: ' + post_data.title; - titleEl.readOnly = true; - } else if (parseInt(post_data.pid) > 0) { - titleEl.value = post_data.title; - titleEl.readOnly = true; - socket.emit('api:composer.editCheck', post_data.pid); - } else { - titleEl.value = post_data.title; - titleEl.readOnly = false; + if (percentage) { + if (bodyRect.width >= 768) { + postContainer.css('width', Math.floor(bodyRect.width * percentage) + 'px'); + } else { + postContainer.css('width', '100%'); + } } - bodyEl.value = post_data.body; + postContainer.css('visibility', 'visible'); - // Direct user focus to the correct element - if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) { - bodyEl.focus(); - bodyEl.selectionStart = bodyEl.value.length; - bodyEl.selectionEnd = bodyEl.value.length; - } else if (parseInt(post_data.cid) > 0) { - titleEl.focus(); - } + composer.focusElements(post_uuid); } - composer.reposition = function(post_uuid) { - // Resize the composer to the saved size - var percentage = localStorage.getItem('composer:resizePercentage'), - bodyRect = document.body.getBoundingClientRect(); + composer.focusElements = function(post_uuid) { + var postContainer = $('#cmp-uuid-' + post_uuid), + postData = composer.posts[post_uuid], + titleEl = postContainer.find('.title'), + bodyEl = postContainer.find('textarea'); - if (percentage) { - if (bodyRect.width >= 768) { - composer.postContainer.style.width = Math.floor(bodyRect.width * percentage) + 'px'; - } else { - composer.postContainer.style.width = '100%'; - } + if ((parseInt(postData.tid) || parseInt(postData.pid)) > 0) { + bodyEl.focus(); + bodyEl.selectionStart = bodyEl.val().length; + bodyEl.selectionEnd = bodyEl.val().length; + } else if (parseInt(postData.cid) > 0) { + titleEl.focus(); } - - composer.postContainer.style.visibility = 'visible'; } 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'); + postContainer = $('#cmp-uuid-' + post_uuid), + titleEl = postContainer.find('.title'), + bodyEl = postContainer.find('textarea'); - titleEl.value = titleEl.value.trim(); - bodyEl.value = bodyEl.value.trim(); + titleEl.val(titleEl.val().trim()); + bodyEl.val(bodyEl.val().trim()); if(postData.uploadsInProgress && postData.uploadsInProgress.length) { return app.alert({ @@ -387,7 +300,7 @@ define(['taskbar'], function(taskbar) { }); } - if (titleEl.value.length < config.minimumTitleLength) { + if (titleEl.val().length < config.minimumTitleLength) { return app.alert({ type: 'danger', timeout: 2000, @@ -397,7 +310,7 @@ define(['taskbar'], function(taskbar) { }); } - if (bodyEl.value.length < config.minimumPostLength) { + if (bodyEl.val().length < config.minimumPostLength) { return app.alert({ type: 'danger', timeout: 2000, @@ -410,20 +323,20 @@ define(['taskbar'], function(taskbar) { // Still here? Let's post. if (parseInt(postData.cid) > 0) { socket.emit('api:topics.post', { - 'title' : titleEl.value, - 'content' : bodyEl.value, + 'title' : titleEl.val(), + 'content' : bodyEl.val(), 'category_id' : postData.cid }); } else if (parseInt(postData.tid) > 0) { socket.emit('api:posts.reply', { 'topic_id' : postData.tid, - 'content' : bodyEl.value + 'content' : bodyEl.val() }); } else if (parseInt(postData.pid) > 0) { socket.emit('api:posts.edit', { pid: postData.pid, - content: bodyEl.value, - title: titleEl.value + content: bodyEl.val(), + title: titleEl.val() }); } @@ -432,20 +345,130 @@ define(['taskbar'], function(taskbar) { composer.discard = function(post_uuid) { if (composer.posts[post_uuid]) { - $(composer.postContainer).find('.imagedrop').hide(); + $('#cmp-uuid-' + post_uuid).remove(); delete composer.posts[post_uuid]; - composer.minimize(); + composer.active = undefined; taskbar.discard('composer', post_uuid); } } - composer.minimize = function(uuid) { - composer.postContainer.style.visibility = 'hidden'; + composer.minimize = function(post_uuid) { + var postContainer = $('#cmp-uuid-' + post_uuid); + postContainer.css('visibility', 'hidden'); composer.active = undefined; - taskbar.minimize('composer', uuid); + taskbar.minimize('composer', post_uuid); } - composer.init(); + function initializeFileReader(post_uuid) { + if(jQuery.event.props.indexOf('dataTransfer') === -1) { + jQuery.event.props.push('dataTransfer'); + } + + var draggingDocument = false; + + if(window.FileReader) { + var postContainer = $('#cmp-uuid-' + post_uuid), + drop = postContainer.find('.imagedrop'), + 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', textarea.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; + + for (var i=0; i 0 || parseInt(meta.config.allowGuestPosting, 10) === 1) { if (parseInt(data.tid) > 0) { topics.getTopicData(data.tid, function(err, topicData) { - if (data.body) + if (data.body) { topicData.body = data.body; + } - socket.emit('api:composer.push', { + callback({ tid: data.tid, title: topicData.title, body: topicData.body @@ -815,7 +816,7 @@ websockets.init = function(io) { } else if (parseInt(data.cid) > 0) { user.getUserFields(uid, ['username', 'picture'], function(err, userData) { if (!err && userData) { - socket.emit('api:composer.push', { + callback({ tid: 0, cid: data.cid, username: userData.username, @@ -836,7 +837,7 @@ websockets.init = function(io) { }); } ], function(err, results) { - socket.emit('api:composer.push', { + callback({ title: results[1], pid: data.pid, body: results[0].content @@ -844,16 +845,16 @@ websockets.init = function(io) { }); } } else { - socket.emit('api:composer.push', { + callback({ error: 'no-uid' }); } }); - socket.on('api:composer.editCheck', function(pid) { + socket.on('api:composer.editCheck', function(pid, callback) { posts.getPostField(pid, 'tid', function(err, tid) { postTools.isMain(pid, tid, function(err, isMain) { - socket.emit('api:composer.editCheck', { + callback({ titleEditable: isMain }); })