a0aaa6a0b8
POC: Markdown shortcut buttons ## What does this MR do? Adds markdown shortcut buttons to text area for comments. ## Are there points in the code the reviewer needs to double check? Because changing `textarea.val('something')` kills the natural browser undo stack, I had to implement a custom undo stack using state. You can't use the "undoable" state undo pattern because you need to go back to a previous state regardless of cursor position. The undo also adds an undo history item once you delete stuff or press enter. You can also edit multiple textareas at once and it will keep an undo history for each textarea individually, so the undo state should not collide between textareas. ## Why was this MR needed? It has been requested multiple times and the competition has it. https://gitlab.com/gitlab-org/gitlab-ce/issues/17185#note_12073433 Libraries are available that already implement this functionality but they are enormous and bloaty. I implemented this in very few lines of code and kept it very simple and as minimal as possible. This was also some competitions approach. I believe so as to not include too much JS. Adding extra buttons with new functionality **should only need new HTML and no new JS**. Only extra complex thing was adding a overridden undo stack, which was made as simple as possible as well. ## What are the relevant issue numbers? https://gitlab.com/gitlab-org/gitlab-ce/issues/17185#note_12073433 ## Screenshots (if relevant) **NOTE:** One thing you cannot see in this screenshot is that I am pressing <kbd>Cmd</kbd><kbd>Z</kbd> to undo and <kbd>Cmd</kbd><kbd>Shift</kbd><kbd>Z</kbd> to redo which is the undo/redo stack I implemented. <kbd>Ctrl</kbd><kbd>Y</kbd> also works for redo. ![markdown-editor](/uploads/2517bfb1a7b4269da7fcc4003c88b7f6/markdown-editor.gif) cc @dzaporozhets for UI cc @iamphill @alfredo1 for JS review cc @JobV if you like the idea. Fixes: #17185 See merge request !4305
238 lines
3.7 KiB
SCSS
238 lines
3.7 KiB
SCSS
/**
|
|
* Note Form
|
|
*/
|
|
.comment-btn {
|
|
@extend .btn-create;
|
|
}
|
|
|
|
.diff-file .diff-content {
|
|
tr.line_holder:hover > td .line_note_link {
|
|
opacity: 1.0;
|
|
filter: alpha(opacity=100);
|
|
}
|
|
}
|
|
.diff-file,
|
|
.discussion {
|
|
.new-note {
|
|
margin: 0;
|
|
border: none;
|
|
}
|
|
}
|
|
|
|
.new-note {
|
|
display: none;
|
|
}
|
|
|
|
.new-note, .note-edit-form {
|
|
.note-form-actions {
|
|
margin-top: $gl-padding;
|
|
}
|
|
|
|
.note-preview-holder {
|
|
> p {
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
|
|
img {
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
|
|
.note-textarea {
|
|
display: block;
|
|
padding: 10px 0;
|
|
color: $gl-gray;
|
|
font-family: $regular_font;
|
|
border: 0;
|
|
|
|
&:focus {
|
|
outline: 0;
|
|
}
|
|
}
|
|
|
|
.note-image-attach {
|
|
@extend .col-md-4;
|
|
margin-left: 45px;
|
|
float: none;
|
|
}
|
|
|
|
.common-note-form {
|
|
.md-area {
|
|
padding: $gl-padding-top $gl-padding;
|
|
border: 1px solid $note-form-border-color;
|
|
border-radius: $border-radius-base;
|
|
transition: border-color ease-in-out 0.15s,
|
|
box-shadow ease-in-out 0.15s;
|
|
|
|
&.is-focused {
|
|
@extend .form-control:focus;
|
|
|
|
.comment-toolbar,
|
|
.nav-links {
|
|
border-color: $focus-border-color;
|
|
}
|
|
}
|
|
|
|
&.is-dropzone-hover {
|
|
border-color: $gl-success;
|
|
box-shadow: 0 0 2px $black-transparent,
|
|
0 0 4px $gl-success-focus;
|
|
|
|
.comment-toolbar,
|
|
.nav-links {
|
|
border-color: $gl-success;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.md-header .nav-links {
|
|
display: flex;
|
|
display: -webkit-flex;
|
|
flex-flow: row wrap;
|
|
-webkit-flex-flow: row wrap;
|
|
width: 100%;
|
|
|
|
.pull-right {
|
|
// Flexbox quirk to make sure right-aligned items stay right-aligned.
|
|
margin-left: auto;
|
|
}
|
|
}
|
|
|
|
.confidential-issue-warning {
|
|
background-color: $gray-normal;
|
|
border-radius: 3px;
|
|
padding: 3px 12px;
|
|
margin: auto;
|
|
margin-top: 0;
|
|
text-align: center;
|
|
font-size: 13px;
|
|
|
|
@media (max-width: $screen-md-min) {
|
|
// On smaller devices the warning becomes the fourth item in the list,
|
|
// rather than centering, and grows to span the full width of the
|
|
// comment area.
|
|
order: 4;
|
|
-webkit-order: 4;
|
|
margin: 6px auto;
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.discussion-form {
|
|
padding: $gl-padding-top $gl-padding;
|
|
background-color: $white-light;
|
|
}
|
|
|
|
.note-edit-form {
|
|
display: none;
|
|
font-size: 15px;
|
|
|
|
.md-area {
|
|
background-color: #fff;
|
|
}
|
|
}
|
|
|
|
.js-note-attachment-delete {
|
|
display: none;
|
|
}
|
|
|
|
.parallel-comment {
|
|
padding: 6px;
|
|
}
|
|
|
|
.error-alert > .alert {
|
|
margin-top: 5px;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.discussion-body,
|
|
.diff-file {
|
|
.notes .note {
|
|
padding: 10px 15px;
|
|
}
|
|
|
|
.discussion-reply-holder {
|
|
background-color: $white-light;
|
|
padding: 10px 16px;
|
|
}
|
|
}
|
|
|
|
.discussion-notes-count {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.edit_note {
|
|
.markdown-area {
|
|
min-height: 140px;
|
|
max-height: 500px;
|
|
}
|
|
.note-form-actions {
|
|
background: transparent;
|
|
}
|
|
}
|
|
|
|
.comment-toolbar {
|
|
padding-top: $gl-padding-top;
|
|
color: $note-toolbar-color;
|
|
border-top: 1px solid $border-color;
|
|
}
|
|
|
|
.md-helper {
|
|
padding-top: 10px;
|
|
}
|
|
|
|
.toolbar-button {
|
|
padding: 0;
|
|
background: none;
|
|
border: 0;
|
|
font-size: 14px;
|
|
line-height: 16px;
|
|
|
|
&:hover,
|
|
&:focus {
|
|
color: $gl-link-color;
|
|
outline: 0;
|
|
}
|
|
|
|
@media (min-width: $screen-md-min) {
|
|
float: left;
|
|
margin-right: $gl-padding;
|
|
|
|
&:last-child {
|
|
float: right;
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.toolbar-button-icon {
|
|
position: relative;
|
|
top: 1px;
|
|
margin-right: 3px;
|
|
color: inherit;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.toolbar-text {
|
|
font-size: 14px;
|
|
line-height: 16px;
|
|
|
|
@media (min-width: $screen-md-min) {
|
|
float: left;
|
|
}
|
|
}
|
|
|
|
.note-form-actions {
|
|
@media (max-width: $screen-xs-max) {
|
|
.btn {
|
|
float: none;
|
|
width: 100%;
|
|
|
|
&:not(:last-child) {
|
|
margin-bottom: 10px;
|
|
}
|
|
}
|
|
}
|
|
}
|