Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change #dropzone-large ID to #comment-form-body #9123

Merged
merged 6 commits into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 117 additions & 123 deletions app/assets/javascripts/editor.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// jQuery (document).ready function:
class Editor {
// default parameters:
// defaultForm - when the Editor is initialized, there needs to be a default editor form:
// 1. the main comment form in multi-comment wikis, questions, & research notes.
// 2. the only editor form on /wiki/new and /wiki/edit
// elementIDPrefixes - the ID naming conventions are different depending on context:
// 1. multi-form pages with multiple comments: #comment-preview-123
// 2. /wiki/new and /wiki/edit: #preview-main
constructor(defaultForm = "main", elementIDPrefixes = {}) {
this.commentFormID = defaultForm;
this.elementIDPrefixes = elementIDPrefixes;
this.textarea = $("#text-input-" + this.commentFormID);

$E = {
initialize: function() {
// call setState with no parameters, aka. default parameters.
// default parameters point toward either:
// 1. the comment form at the bottom of multi-comment wikis/questions/research notes
// 2. the only editor form on /wiki/new and /wiki/edit
$E.setState();

// this will get deleted in the next few PRs, so collapsing into one line to pass codeclimate
this.templates = { 'blog': "## The beginning\n\n## What we did\n\n## Why it matters\n\n## How can you help", 'default': "## What I want to do\n\n## My attempt and results\n\n## Questions and next steps\n\n## Why I'm interested", 'support': "## Details about the problem\n\n## A photo or screenshot of the setup", 'event': "## Event details\n\nWhen, where, what\n\n## Background\n\nWho, why", 'question': "## What I want to do or know\n\n## Background story" };

marked.setOptions({
gfm: true,
tables: true,
Expand All @@ -23,131 +29,119 @@ $E = {
return code;
}
});
},
setState: function(textarea = 'text-input', preview = 'comment-preview-main', title = 'title') {
$E.title = $('#' + title + 'title'); // not sure why this exists? seems like $E.title is always #title
$E.textarea = $('#' + textarea);
}
setState(commentFormID) {
this.commentFormID = commentFormID;
this.textarea = $("#text-input-" + commentFormID);
$E.textarea.bind('input propertychange', $E.save);
$E.preview = $('#' + preview);
},
is_editing: function() {
return ($E.textarea[0].selectionStart == 0 && $E.textarea[0].selectionEnd == 0)
},
refresh: function() {
// textarea
$E.textarea = ($D.selected).find('textarea').eq(0);
$E.textarea.bind('input propertychange',$E.save);
// preview
$E.preview = ($D.selected).find('.comment-preview').eq(0);
},
isRichTextEditor: function(url) {
// this RegEx matches three different cases where the legacy editor is still used:
// 1. /wiki/new
// 2. /wiki/{wiki name}/edit
// 3. /features/new
const legacyEditorPath = RegExp(/\/(wiki|features)(\/[^\/]+\/edit|\/new)/);
return !legacyEditorPath.test(url); // if we're not on one of these pages, we are using the rich-text editor.
},
// wraps currently selected text in textarea with strings a and b
wrap: function(a, b, args) {
// we only refresh $E's values if we are on a page using the rich-text editor (most pages).
// the legacy editor pages only have one editor form, unlike pages with multiple comments.
if (this.isRichTextEditor(window.location.pathname)) { this.refresh(); }
var len = $E.textarea.val().length;
var start = $E.textarea[0].selectionStart;
var end = $E.textarea[0].selectionEnd;
const fallbackParameterExists = args && args['fallback'];
const newlineParameterExists = args && args['newline'];
var sel = fallbackParameterExists ? args['fallback'] : $E.textarea.val().substring(start, end); // // fallback if nothing has been selected, and we're simply dealing with an insertion point
var replace = a + sel + b;
if (newlineParameterExists) {
replace = replace + "\n\n";
}
if (newlineParameterExists && $E.textarea[0].selectionStart > 0) {
replace = "\n" + replace;
}
get textAreaElement() {
const textAreaID = "#text-input-" + this.commentFormID;
return $(textAreaID);
}
get textAreaValue() {
return this.textAreaElement.val();
}
get previewElement() {
let previewIDPrefix = "#comment-preview-";
if (this.elementIDPrefixes.hasOwnProperty("preview")) {
// eg. on /wiki/new & /wiki/edit, the preview element is called #preview-main
previewIDPrefix = "#" + this.elementIDPrefixes["preview"] + "-";
}
$E.textarea.val($E.textarea.val().substring(0,start) + replace + $E.textarea.val().substring(end,len));
},
bold: function() {
$E.wrap('**','**')
},
italic: function() {
$E.wrap('_','_')
},
link: function(uri) {
const previewID = previewIDPrefix + this.commentFormID;
return $(previewID);
}
// wraps currently selected text in textarea with strings a and b
wrap(a, b, newlineDesired = false, fallback) {
const selectionStart = this.textAreaElement[0].selectionStart;
const selectionEnd = this.textAreaElement[0].selectionEnd;
const selection = fallback || this.textAreaValue.substring(selectionStart, selectionEnd); // fallback if nothing has been selected, and we're simply dealing with an insertion point

let newText = a + selection + b; // ie. ** + selection + ** (wrapping selection in bold)
if (newlineDesired) { newText = newText + "\n\n"; }
const selectionStartsMidText = this.textAreaElement[0].selectionStart > 0;
if (newlineDesired && selectionStartsMidText) { newText = "\n" + newText; }

const textLength = this.textAreaValue.length;
const textBeforeSelection = this.textAreaValue.substring(0, selectionStart);
const textAfterSelection = this.textAreaValue.substring(selectionEnd, textLength);
this.textAreaElement.val(textBeforeSelection + newText + textAfterSelection);
}
bold() {
this.wrap('**', '**');
}
italic() {
this.wrap('_', '_');
}
link(uri) {
uri = prompt('Enter a URL');
if (uri === null) { uri = ""; }
$E.wrap('[', '](' + uri + ')');
},
image: function(src) {
$E.wrap('\n![',']('+src+')\n')
},
h1: function() {
$E.wrap('#','')
},
h2: function() {
$E.wrap('##','')
},
h3: function() {
$E.wrap('###','')
},
h4: function() {
$E.wrap('####','')
},
h5: function() {
$E.wrap('#####','')
},
h6: function() {
$E.wrap('######','')
},
h7: function() {
$E.wrap('#######','')
},
this.wrap(
'[',
'](' + uri + ')'
);
}
image(src) {
this.wrap(
'\n![',
'](' + src + ')\n'
);
}
// these header formatting functions are not used anywhere, so commenting them out for now to pass codeclimate:

// h1() {
// this.wrap('#','')
// }
h2() {
this.wrap('##', '');
}
// h3() {
// this.wrap('###','')
// }
// h4() {
// this.wrap('####','')
// }
// h5() {
// this.wrap('#####','')
// }
// h6() {
// this.wrap('######','')
// }
// h7() {
// this.wrap('#######','')
// }
// this function is dedicated to Don Blair https://github.com/donblair
save: function() {
localStorage.setItem('plots:lastpost',$E.textarea.val())
localStorage.setItem('plots:lasttitle',$E.title.val())
},
recover: function() {
$E.textarea.val(localStorage.getItem('plots:lastpost'))
$E.title.val(localStorage.getItem('plots:lasttitle'))
},
apply_template: function(template) {
if($E.textarea.val() == ""){
$E.textarea.val($E.templates[template])
}else if(($E.textarea.val() == $E.templates['event']) || ($E.textarea.val() == $E.templates['default']) || ($E.textarea.val() == $E.templates['support'])){
$E.textarea.val($E.templates[template])
save() {
localStorage.setItem('plots:lastpost', this.textAreaValue);
}
recover() {
this.textAreaElement.val(localStorage.getItem('plots:lastpost'));
}
apply_template(template) {
if(this.textAreaValue == ""){
this.textAreaElement.val(this.templates[template])
}else if((this.textAreaValue == this.templates['event']) || (this.textAreaValue == this.templates['default']) || (this.textAreaValue == this.templates['support'])){
this.textAreaElement.val(this.templates[template])
}else{
$E.textarea.val($E.textarea.val()+'\n\n'+$E.templates[template])
this.textAreaElement.val(this.textAreaValue+'\n\n'+this.templates[template])
}
},
templates: {
'blog': "## The beginning\n\n## What we did\n\n## Why it matters\n\n## How can you help",
'default': "## What I want to do\n\n## My attempt and results\n\n## Questions and next steps\n\n## Why I'm interested",
'support': "## Details about the problem\n\n## A photo or screenshot of the setup",
'event': "## Event details\n\nWhen, where, what\n\n## Background\n\nWho, why",
'question': "## What I want to do or know\n\n## Background story"
},
previewing: false,
previewed: false,
generate_preview: function(id,text) {
$('#'+id)[0].innerHTML = marked(text)
},
toggle_preview: function() {
let previewBtn;
let dropzone;
}
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.
previewBtn = $(this.textarea.context).find('.preview-btn');
dropzone = $(this.textarea.context).find('.dropzone');
const previewBtn = $("#toggle-preview-button-" + this.commentFormID);
const commentFormBody = $("#comment-form-body-" + this.commentFormID);

$E.preview[0].innerHTML = marked($E.textarea.val());
$E.preview.toggle();
dropzone.toggle();
this.previewElement[0].innerHTML = marked(this.textAreaValue);
this.previewElement.toggle();
commentFormBody.toggle();

this.toggleButtonPreviewMode(previewBtn);
},
toggleButtonPreviewMode: function (previewBtn) {
}
toggleButtonPreviewMode(previewBtn) {
let isPreviewing = previewBtn.attr('data-previewing');

// If data-previewing attribute is not present -> we are not in "preview" mode
Expand All @@ -166,4 +160,4 @@ $E = {
previewBtn.text('Preview');
}
}
}
}
Loading