Skip to content

Commit

Permalink
Fix Rich-Text & Image Upload in FRESHLY Posted Comments (publiclab#9162)
Browse files Browse the repository at this point in the history
* delete unused code; add semicolon publiclab#9072

* attach eventHandlers to #legacy-editor-container publiclab#9072

* add image upload functionality to new comments publiclab#9072

* add imagebar caption publiclab#9072

* add #legacy-editor-container class to attach eventHandlers publiclab#9072

* add system test for rich-text & image upload on fresh comments publiclab#9072
  • Loading branch information
noi5e authored and lagunasmel committed Mar 2, 2021
1 parent d7421d2 commit 16c26bc
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 146 deletions.
5 changes: 1 addition & 4 deletions app/assets/javascripts/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class Editor {
$("textarea").off("input.save"); // input.save is a custom jQuery eventHandler
const thisEditor = this; // save a reference to this editor, because inside the eventListener, "this" points to e.target
this.textAreaElement.on("input.save", function() {
thisEditor.save(thisEditor)
thisEditor.save(thisEditor);
});
}
save(thisEditor) {
Expand All @@ -132,9 +132,6 @@ class Editor {
this.textAreaElement.val(this.textAreaValue+'\n\n'+this.templates[template])
}
}
generate_preview(id,text) {
$('#' + id)[0].innerHTML = marked(text)
}
toggle_preview() {
// if the element is part of a multi-comment page,
// ensure to grab the current element and not the other comment element.
Expand Down
208 changes: 106 additions & 102 deletions app/assets/javascripts/editorToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,126 +7,130 @@

// * * * * * * * * * * *

// used to create fileupload functionality for:
// 1. existing comments at document.load
// 2. dynamically inserted (freshly posted) comments, see /app/views/comments/create.js.erb
function getFileUploadOptions(dropZone, isSmallDropzone = false) {
return {
url: "/images",
paramName: "image[photo]",
dropZone: isSmallDropzone ? null : dropZone,
dataType: 'json',
formData: {
'uid':$D.uid,
'nid':$D.nid
},
// 'start' function runs:
// 1. when user drag-and-drops image
// 2. when user clicks on upload button.
start: function(e) {
$E.setState(e.target.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$(e.target).removeClass('hover');
$("#image-upload-progress-container-" + $E.commentFormID).show();
$("#image-upload-text-" + $E.commentFormID).show();
$("#choose-one-" + $E.commentFormID).hide();
},
done: function (e, data) {
$("#image-upload-progress-container-" + $E.commentFormID).hide();
$("#image-upload-text-" + $E.commentFormID).hide();
$("#choose-one-" + $E.commentFormID).show();
$("#image-upload-progress-bar-" + $E.commentFormID).css('width', 0);
var extension = data.result['filename'].split('.')[data.result['filename'].split('.').length - 1]; var file_url = data.result.url.split('?')[0]; var file_type;
if (['gif', 'GIF', 'jpeg', 'JPEG', 'jpg', 'JPG', 'png', 'PNG'].includes(extension))
file_type = 'image'
else if (['csv', 'CSV'].includes(extension))
file_type = 'csv'
switch (file_type) {
case 'image':
orig_image_url = file_url + '?s=o' // size = original
$E.wrap('[![', '](' + file_url + ')](' + orig_image_url + ')', true, data.result['filename']);
break;
case 'csv':
$E.wrap('[graph:' + file_url + ']', '', true);
break;
default:
$E.wrap('<a href="'+data.result.url.split('?')[0]+'"><i class="fa fa-file"></i> ', '</a>', true, data.result['filename'].replace(/[()]/g , "-")); // on its own line; see /app/assets/js/editor.js
}
// here append the image id to the wiki edit form:
if ($('#node_images').val() && $('#node_images').val().split(',').length > 1) $('#node_images').val([$('#node_images').val(),data.result.id].join(','))
else $('#node_images').val(data.result.id)
},
fileuploadfail: function(e, data) {
console.log(e);
},
progressall: function (e, data) {
const closestProgressBar = $("#image-upload-progress-bar-" + $E.commentFormID);
return progressAll(closestProgressBar, data);
}
};
}

function progressAll(elem, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$(elem).css(
'width',
progress + '%'
);
}

// attach eventListeners on document.load:
// 1. rich-text buttons
// 2. save & recover buttons
// 3. textareas
// 4. image upload .dropzones & buttons
$(function() {
// for rich-text buttons (bold, italic, header, and link):
$('.rich-text-button').on('click', function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
const action = e.currentTarget.dataset.action // 'bold', 'italic', etc.
$E[action](); // call the appropriate editor function
});

// for save & recover buttons
$('.save-button').on('click', function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$E.save($E);
});

$('.recover-button').on('click', function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$E.recover();
});

// textAreas
$('.text-input').on('click', function(e) {
$E.setState(e.currentTarget.dataset.formId);
});

// image upload event listeners for both:
// 1. click-to-upload
// 2. drag & drop
// based on the basic plugin from jQuery file upload:
// https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin
$('.dropzone').each(function() {
// attach all events to #legacy-editor-container
// this is so dynamically inserted forms (ie. freshly posted comments) will have events automatically attached too.
$("#legacy-editor-container")
// for rich-text buttons (bold, italic, header, and link):
.on("click", ".rich-text-button", function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
const action = e.currentTarget.dataset.action // 'bold', 'italic', etc.
$E[action](); // call the appropriate editor function
})
// for save & recover buttons
.on("click", ".save-button", function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$E.save($E);
})
.on("click", ".recover-button", function(e) {
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$E.recover();
})
// textAreas
.on("click", ".text-input", function(e) {
$E.setState(e.currentTarget.dataset.formId);
})
// style changes for dragging an image over a dropzone
$(this).on('dragenter',function(e) {
.on("dragenter", ".dropzone", function(e) {
e.preventDefault();
$(e.currentTarget).addClass('hover');
});

$(this).on('dragleave',function(e) {
})
.on("dragleave", ".dropzone", function(e) {
$(e.currentTarget).removeClass('hover');
});

// runs on drag & drop
$(this).on('drop',function(e) {
})
// set the editor's comment form state on drop
.on("drop", ".dropzone", function(e) {
e.preventDefault();
$E.setState(e.currentTarget.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
});

// image upload functionality for both:
// 1. click-to-upload
// 2. drag & drop
// based on the basic plugin from jQuery file upload:
// https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin

// this instantiates fileupload for every comment form present at document.load
// for freshly posted comments, see /app/views/comments/create.js.erb
$('.dropzone').each(function() {
// disable drag-and-drop image upload on small dropzones
// small dropzones are the image upload button in the comment form toolbar
let dropZone = $(this);
if ($(this).hasClass("dropzone-small")) {
dropZone = null;
}

$(this).fileupload({
url: "/images",
paramName: "image[photo]",
dropZone: dropZone,
dataType: 'json',
formData: {
'uid':$D.uid,
'nid':$D.nid
},
// 'start' function runs:
// 1. when user drag-and-drops image
// 2. when user clicks on upload button.
start: function(e) {
$E.setState(e.target.dataset.formId); // string that is: "main", "reply-123", "edit-123" etc.
$(e.target).removeClass('hover');
$("#image-upload-progress-container-" + $E.commentFormID).show();
$("#image-upload-text-" + $E.commentFormID).show();
$("#choose-one-" + $E.commentFormID).hide();
},
done: function (e, data) {
$("#image-upload-progress-container-" + $E.commentFormID).hide();
$("#image-upload-text-" + $E.commentFormID).hide();
$("#choose-one-" + $E.commentFormID).show();
$("#image-upload-progress-bar-" + $E.commentFormID).css('width', 0);
var extension = data.result['filename'].split('.')[data.result['filename'].split('.').length - 1]; var file_url = data.result.url.split('?')[0]; var file_type;
if (['gif', 'GIF', 'jpeg', 'JPEG', 'jpg', 'JPG', 'png', 'PNG'].includes(extension))
file_type = 'image'
else if (['csv', 'CSV'].includes(extension))
file_type = 'csv'
switch (file_type) {
case 'image':
orig_image_url = file_url + '?s=o' // size = original
$E.wrap('[![', '](' + file_url + ')](' + orig_image_url + ')', true, data.result['filename']);
break;
case 'csv':
$E.wrap('[graph:' + file_url + ']', '', true);
break;
default:
$E.wrap('<a href="'+data.result.url.split('?')[0]+'"><i class="fa fa-file"></i> ', '</a>', true, data.result['filename'].replace(/[()]/g , "-")); // on its own line; see /app/assets/js/editor.js
}
// here append the image id to the wiki edit form:
if ($('#node_images').val() && $('#node_images').val().split(',').length > 1) $('#node_images').val([$('#node_images').val(),data.result.id].join(','))
else $('#node_images').val(data.result.id)
},
fileuploadfail: function(e, data) {
console.log(e);
},
progressall: function (e, data) {
const closestProgressBar = $("#image-upload-progress-bar-" + $E.commentFormID);
return progressAll(closestProgressBar, data);
}
});
const isSmallDropzone = $(this).hasClass("dropzone-small");
const fileUploadOptions = getFileUploadOptions($(this), isSmallDropzone);
$(this).fileupload(fileUploadOptions);
});

const progressAll = (elem, data) => {
var progress = parseInt(data.loaded / data.total * 100, 10);
$(elem).css(
'width',
progress + '%'
);
}

// #side-dropzone, is for the main image of research notes, in /app/views/editor/post.html.erb
$('#side-dropzone').on('dragover',function(e) {
e.preventDefault();
Expand Down
17 changes: 15 additions & 2 deletions app/views/comments/create.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@
<% else %>
$('#comment-<%= @comment.reply_to %>-reply').before('<%= escape_javascript(render :partial => "notes/comment", :locals => {comment: @comment, answer_id: @answer_id}) %>')
<% end %>
// create image upload functionality for fresh comment form
// see editorToolbar.js
const replyFormBody = $('#comment-form-body-reply-<%= @comment.cid %>');
const editFormBody = $('#comment-form-body-edit-<%= @comment.cid %>');
const replyButton = $('#dropzone-small-reply-<%= @comment.cid %>');
const editButton = $('#dropzone-small-edit-<%= @comment.cid %>');
const replyFormOptions = getFileUploadOptions(replyFormBody, false);
const editFormOptions = getFileUploadOptions(editFormBody, false);
const replyButtonOptions = getFileUploadOptions(replyButton, true);
const editButtonOptions = getFileUploadOptions(editButton, true);
replyFormBody.fileupload(replyFormOptions);
editFormBody.fileupload(editFormOptions);
replyButton.fileupload(replyButtonOptions);
editButton.fileupload(editButtonOptions);

$('#answer-<%= @answer_id %>-comment-section .help-block').remove();
notyNotification('mint', 3000, 'success', 'topRight', 'Comment Added!');
$('#comment-count')[0].innerHTML = parseInt($('#comment-count')[0].innerHTML, 10)+1;


19 changes: 17 additions & 2 deletions app/views/editor/_editor.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,23 @@
<span
id="image-upload-text-main"
class="uploading-text"
style="display:none;">
Uploading...
style="display:none;"
>
<%= translation('comments._form.uploading') %>
</span>
<span id="choose-one-main" class="prompt choose-one-prompt-text">
<span style="padding-right:4px;float:left;" class="d-none d-md-inline">
<%= raw translation('comments._form.drag_and_drop') %>
</span>
<!-- http://stackoverflow.com/questions/11235206/twitter-bootstrap-form-file-element-upload-button -->
<label for="fileinput-choose-one-main">
<input id="fileinput-choose-one-main" type="file" name="image[photo]" style="display:none;" />
<a style="cursor: pointer;" class="d-none d-md-inline text-underline"><%= translation('comments._form.choose_one') %></a>
<span class="d-md-none">
<i class="fa fa-upload"></i>
<a><%= translation('comments._form.upload_image') %></a>
</span>
</label>
</span>
</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/editor/post.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<% if f.error_messages != "" %><div class="alert alert-danger"><%= f.error_messages :header_message => "Your note couldn't be saved." %></div><% end %>
<% end %>
<div class="card bg-light">
<div class="card-body">
<div id="legacy-editor-container" class="card-body">
<%= form_for :revision, :as => :revision, :url => url, :html => {:class => "form well legacy-form row"} do |f| %>

<% if f.error_messages != "" %><div class="alert alert-danger"><%= f.error_messages :header_message => "Your note couldn't be saved." %></div><% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/editor/question.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<%= render partial: 'layouts/errorMessages', locals: { model: @revision } if @revision.present? %>
<%= render :partial => "editor/main_image" %>

<div class="col-lg-9 order-md-1">
<div id="legacy-editor-container" class="col-lg-9 order-md-1">

<% if params[:template] == "question" %>
<h3>Ask a question of the community</h3>
Expand Down
6 changes: 3 additions & 3 deletions app/views/features/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
}
})()
</script>

<%= render :partial => 'editor/editor' %>

<div id="legacy-editor-container">
<%= render :partial => 'editor/editor' %>
</div>
<div>
<input type="submit" id="publish" tabindex="5" class="publish btn btn-primary btn-lg" value="Save" />
<a tabindex="6" data-previewing-text="Previewing (click to edit)" class="btn btn-outline-secondary btn-lg preview-btn" onClick="$E.toggle_preview()">Preview</a>
Expand Down
2 changes: 1 addition & 1 deletion app/views/notes/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
<% end %>
<% if !@preview %>
<%= render partial: "notes/responses" %>
<div><%= render partial: "notes/comments" %></div>
<div id="legacy-editor-container"><%= render partial: "notes/comments" %></div>
<% end %>
</div>

Expand Down
Loading

0 comments on commit 16c26bc

Please sign in to comment.