Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
51 changes: 36 additions & 15 deletions app/assets/javascripts/hera/modules/editor_toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class EditorToolbar {

behaviors() {
var that = this;
this.scrollEventName = 'scroll.editor-toolbar-' + this.$target.attr('id');

this.$target.on('click change keyup select', function () {
that.updateSelectionButtons();
Expand All @@ -92,7 +93,24 @@ class EditorToolbar {
this.$target.on('blur focus textchange input', this.setHeight);

// Handler for setting the correct textarea heights on load (for current values)
this.$target.each(this.setHeight);
if (this.$target.is(':visible')) {
this.$target.each(this.setHeight);
} else {
const $tabPane = this.$target.closest('.tab-pane');
const tabId = $tabPane.attr('id');

// Use delegated event (only attaches once per document)
$(document).on(
'shown.bs.tab',
'a[data-bs-toggle="tab"][href="#' + tabId + '"]',
function () {
// This will still fire for each instance, but at least we're not adding duplicate listeners
if (that.$target.is(':visible')) {
that.$target.each(that.setHeight);
}
},
);
}

// when a toolbar button is clicked
this.$editorToolbar.find('[data-btn]').click(function () {
Expand Down Expand Up @@ -150,26 +168,29 @@ class EditorToolbar {
}

// adjust position on scroll to make toolbar always appear at the top of the textarea
$(window).on('scroll.editor-toolbar', function () {
const parentOffsetTop = $editorField.offset().top;

// keep toolbar at the top of text area when scrolling
if (
$inputElement.height() > inputMinHeightForStickyToolbar &&
parentOffsetTop < $(window).scrollTop() + headerHeight
) {
$editorField.addClass('sticky-toolbar');
} else {
// reset the toolbar to the default position and appearance
$editorField.removeClass('sticky-toolbar');
}
});
$(window)
.off(that.scrollEventName)
.on(that.scrollEventName, function () {
const parentOffsetTop = $editorField.offset().top;

// keep toolbar at the top of text area when scrolling
if (
$inputElement.height() > inputMinHeightForStickyToolbar &&
parentOffsetTop < $(window).scrollTop() + headerHeight
) {
$editorField.addClass('sticky-toolbar');
} else {
// reset the toolbar to the default position and appearance
$editorField.removeClass('sticky-toolbar');
}
});
});

// reset position and hide toolbar once focus is lost
this.$target.on('blur', function () {
const $toolbarElement = $(this).parent().prev();

$(window).off(that.scrollEventName);
$toolbarElement.css({ opacity: 0, visibility: 'hidden' });
});
}
Expand Down
2 changes: 1 addition & 1 deletion app/assets/stylesheets/hera/modules.scss
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@

&.active {
background-color: $primary;
border: none;
border-color: transparent;
color: $white;

&:hover {
Expand Down
13 changes: 13 additions & 0 deletions app/controllers/fields_controller.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
class FieldsController < AuthenticatedController
TEXTILE_FORM_REGEX = /\Atextile_form_body_[0-9a-fA-F]{8}\z/

before_action :set_target_id, only: [:field]

# Returns the form view given a source text
def form
@form_data = FieldParser.source_to_fields_array(params[:source])
@allow_dropdown = params[:allow_dropdown] == 'true'
@target_dom_id = "textile_form_body_#{SecureRandom.hex(4)}"
render layout: false
end

Expand All @@ -15,4 +20,12 @@ def field
def source
render plain: FieldParser.fields_to_source(params[:form])
end

private

def set_target_id
if params[:target] =~ TEXTILE_FORM_REGEX
@target_id = params[:target]
end
end
end
7 changes: 5 additions & 2 deletions app/views/fields/field.js.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<% field_row = render partial: 'field', locals: { index: @index } %>
var fieldGroup = $('<%= escape_javascript(field_row) %>');
$('[data-behavior~=textile-form-body]').append(fieldGroup);
var $targetBody = $('#<%= escape_javascript(@target_id) %>');
var $form = $targetBody.closest('form');

$('.textile').data('plugin_textile').bindFieldGroup(fieldGroup);
$targetBody.append(fieldGroup);

$form.find('textarea.textile').data('plugin_textile')?.bindFieldGroup(fieldGroup);

$('[data-behavior~=rich-toolbar]', fieldGroup).each(function() {
new EditorToolbar($(this));
Expand Down
4 changes: 2 additions & 2 deletions app/views/fields/form.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="textile-form-body" data-behavior="textile-form-body">
<div class="textile-form-body" data-behavior="textile-form-body" id="<%= @target_dom_id %>">
<% if @form_data.any? %>
<% @form_data.each_with_index do |field, index| %>
<%= render partial: 'field', locals: { field: field, index: index } %>
Expand All @@ -9,7 +9,7 @@
</div>

<div class="add-field">
<%= link_to field_fields_path(index: @form_data.length + 1), data: { behavior: 'add-field' }, remote: true do %>
<%= link_to field_fields_path(index: @form_data.length + 1, target: @target_dom_id), data: { behavior: 'add-field' }, remote: true do %>
<i class="fa-solid fa-plus"></i> Add field
<% end %>
</div>
1 change: 1 addition & 0 deletions app/views/issues/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
'tags-path': project_tags_path(current_project)
}%>
<% table_attributes.merge!(tags: @tags.map { |t| [t.display_name, t.color, t.name] }.to_json) if local_assigns[:tags] %>
<%= render_view_hooks('issues/send_to_bulk') %>
<%= tag.table class: 'table table-striped mb-0', data: table_attributes do %>
<% cache ['issues-table', @all_columns, issues.map(&:id), @issues.map(&:updated_at).map(&:to_i).sort.last, @tags] do %>
<thead>
Expand Down
Loading