simple form: refactor DText form fields to use SimpleForm.

* Refactors DText form fields to use a custom SimpleForm input instead
  of manually generated html. This fixes it so that DText fields use the
  same markup as normal SimpleForm fields, which lets us apply browser
  maxlength validations to DText input fields.

* Fixes autocomplete for @-mentions only working in comments and forum posts.
  Now @-mention autocomplete works in all DText fields, including dmails.
  Known bug: it applies in artist commentary fields when it shouldn't.
This commit is contained in:
evazion
2020-06-25 15:54:06 -05:00
parent fccdcbe7cc
commit 883856d4af
22 changed files with 75 additions and 77 deletions

View File

@@ -217,21 +217,8 @@ module ApplicationHelper
tag.div(text, class: "prose", **options)
end
def dtext_field(object, name, options = {})
options[:name] ||= name.capitalize
options[:input_id] ||= "#{object}_#{name}"
options[:input_name] ||= "#{object}[#{name}]"
options[:value] ||= instance_variable_get("@#{object}").try(name)
options[:preview_id] ||= "dtext-preview"
options[:classes] ||= ""
options[:hint] ||= ""
options[:type] ||= "text"
render "dtext/form", options
end
def dtext_preview_button(object, name, input_id: "#{object}_#{name}", preview_id: "dtext-preview")
tag.input value: "Preview", type: "button", class: "dtext-preview-button", "data-input-id": input_id, "data-preview-id": preview_id
def dtext_preview_button(preview_field)
tag.input value: "Preview", type: "button", class: "dtext-preview-button", "data-preview-field": preview_field
end
def quick_search_form_for(attribute, url, name, autocomplete: nil, redirect: false, &block)

View File

@@ -38,7 +38,7 @@ Autocomplete.initialize_all = function() {
});
this.initialize_tag_autocomplete();
this.initialize_mention_autocomplete($(".autocomplete-mentions textarea"));
this.initialize_mention_autocomplete($("form div.input.dtext textarea"));
this.initialize_fields($('[data-autocomplete="tag"]'), Autocomplete.tag_source);
this.initialize_fields($('[data-autocomplete="artist"]'), Autocomplete.artist_source);
this.initialize_fields($('[data-autocomplete="pool"]'), Autocomplete.pool_source);

View File

@@ -39,8 +39,11 @@ Dtext.call_edit = function(e, $button, $input, $preview) {
Dtext.click_button = function(e) {
var $button = $(e.target);
var $input = $("#" + $button.data("input-id"));
var $preview = $("#" + $button.data("preview-id"));
var $form = $button.parents("form");
var fieldName = $button.data("preview-field");
var $inputContainer = $form.find(`div.input.${fieldName} .dtext-previewable`);
var $input = $inputContainer.find("> input, > textarea");
var $preview = $inputContainer.find("div.dtext-preview");
if ($button.val().match(/preview/i)) {
Dtext.call_preview(e, $button, $input, $preview);

View File

@@ -39,7 +39,7 @@ form.simple_form {
padding-left: 1em;
}
&.text {
&.text, &.dtext {
.hint {
padding-left: 0;
display: block;

View File

@@ -0,0 +1,30 @@
# A custom SimpleForm input for DText fields.
#
# Usage:
#
# <%= f.input :body, as: :dtext %>
# <%= f.input :reason, as: :dtext, inline: true %>
#
# https://github.com/heartcombo/simple_form/wiki/Custom-inputs-examples
# https://github.com/heartcombo/simple_form/blob/master/lib/simple_form/inputs/string_input.rb
# https://github.com/heartcombo/simple_form/blob/master/lib/simple_form/inputs/text_input.rb
class DtextInput < SimpleForm::Inputs::Base
enable :placeholder, :maxlength, :minlength
def input(wrapper_options)
t = template
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
t.tag.div(class: "dtext-previewable") do
if options[:inline]
t.concat @builder.text_field(attribute_name, merged_input_options)
else
t.concat @builder.text_area(attribute_name, { rows: 20, cols: 30 }.merge(merged_input_options))
end
t.concat t.tag.div(id: "dtext-preview", class: "dtext-preview prose")
t.concat t.tag.span(t.link_to("Formatting help", t.dtext_help_path, remote: true, method: :get), class: "hint dtext-hint")
end
end
end

View File

@@ -24,7 +24,7 @@
<% if @bulk_update_request.new_record? %>
<div class="input">
<%= dtext_field "bulk_update_request", "reason", :name => "Reason" %>
<%= f.input :reason, as: :dtext %>
</div>
<% end %>
@@ -44,5 +44,5 @@
<% end %>
<%= f.submit value: "Submit" %>
<%= dtext_preview_button "bulk_update_request", "reason" %>
<%= dtext_preview_button "bulk_update_request_reason" %>
<% end %>

View File

@@ -4,9 +4,9 @@
<% if comment.new_record? %>
<%= f.hidden_field :post_id %>
<% end %>
<%= dtext_field "comment", "body", classes: "autocomplete-mentions", value: comment.body, input_id: "comment_body_for_#{comment.id}", preview_id: "dtext-preview-for-#{comment.id}", hint: link_to_wiki("Comment rules", "howto:comment").html_safe %>
<%= f.input :body, as: :dtext %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "comment", "body", :input_id => "comment_body_for_#{comment.id}", :preview_id => "dtext-preview-for-#{comment.id}" %>
<%= dtext_preview_button "comment_body" %>
<% if comment.new_record? %>
<%= f.input :do_not_bump_post, :label => "No bump" %>
<% end %>

View File

@@ -1,7 +1,7 @@
<%= edit_form_for(dmail) do |f| %>
<%= f.input :to_name, :label => "To", :input_html => { value: dmail.to.try(:name), data: { autocomplete: "user" } } %>
<%= f.input :title, :as => :string %>
<%= dtext_field "dmail", "body" %>
<%= f.input :body, as: :dtext %>
<%= f.button :submit, "Send", :data => { :disable_with => "Sending..." } %>
<%= dtext_preview_button "dmail", "body" %>
<%= dtext_preview_button "dmail_body" %>
<% end %>

View File

@@ -1,19 +0,0 @@
<%# name, input_id, input_name, preview_id, value, type %>
<div class="input text optional <%= classes %>">
<label class="text optional" for="<%= input_id %>"><%= name %></label>
<div class="dtext-previewable">
<% if type == "text" %>
<textarea id="<%= input_id %>" class="text optional" rows="20" name="<%= input_name %>" cols="30"><%= value %></textarea>
<% else %>
<input type="text" id="<%= input_id %>" class="text optional" name="<%= input_name %>" value="<%= value %>">
<% end %>
<div id="<%= preview_id %>" class="dtext-preview prose"></div>
</div>
<span class="hint">
<%= link_to "Formatting help", dtext_help_path, remote: true, method: :get %>.
<% if hint.present? %>
<%= hint %>.
<% end %>
</span>
</div>

View File

@@ -1,8 +1,8 @@
<%= error_messages_for("forum_post") %>
<%= edit_form_for(forum_post) do |f| %>
<%= dtext_field "forum_post", "body", :value => forum_post.body, :classes => "autocomplete-mentions", :input_id => "forum_post_body_for_#{forum_post.id}", :preview_id => "dtext-preview-for-#{forum_post.id}" %>
<%= f.input :body, as: :dtext %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "forum_post", "body", :input_id => "forum_post_body_for_#{forum_post.id}", :preview_id => "dtext-preview-for-#{forum_post.id}" %>
<%= dtext_preview_button "forum_post_body" %>
<% end %>

View File

@@ -6,8 +6,8 @@
<% else %>
<%= f.input :topic_id, :label => "Topic ID" %>
<% end %>
<%= dtext_field "forum_post", "body", :classes => "autocomplete-mentions" %>
<%= f.input :body, as: :dtext %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "forum_post", "body" %>
<%= dtext_preview_button "forum_post_body" %>
<% end %>

View File

@@ -10,7 +10,7 @@
</div>
<%= f.simple_fields_for :original_post do |pf| %>
<%= dtext_field "forum_post", "body", :classes => "autocomplete-mentions", :input_name => "forum_topic[original_post_attributes][body]", :value => forum_topic.original_post.body, :input_id => "forum_post_body_for_#{forum_topic.original_post.id}", :preview_id => "dtext-preview-for-#{forum_topic.original_post.id}" %>
<%= pf.input :body, as: :dtext %>
<% end %>
<% if policy(forum_topic).moderate? %>
@@ -20,6 +20,6 @@
<% end %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "forum_post", "body", :input_id => "forum_post_body_for_#{forum_topic.original_post.id}", :preview_id => "dtext-preview-for-#{forum_topic.original_post.id}" %>
<%= dtext_preview_button "forum_topic_original_post_body" %>
<% end %>
</div>

View File

@@ -1,12 +1,10 @@
<div class="report-dialog-body">
<%= embed_wiki("help:report_notice") %>
<%# XXX dtext_field expects there to be a `moderation_report` instance variable. %>
<% @moderation_report = moderation_report %>
<%= edit_form_for(@moderation_report, format: :js, remote: true) do |f| %>
<%= edit_form_for(moderation_report, format: :js, remote: true) do |f| %>
<%= f.hidden_field :model_type %>
<%= f.hidden_field :model_id %>
<%= dtext_field "moderation_report", "reason", preview_id: "dtext-preview-for-moderation-report", type: "string" %>
<%= dtext_preview_button "moderation_report", "reason", preview_id: "dtext-preview-for-moderation-report" %>
<%= f.input :reason, as: :dtext, inline: true %>
<%= dtext_preview_button "moderation_report_reason" %>
<% end %>
</div>

View File

@@ -6,11 +6,11 @@
<%= error_messages_for "pool" %>
<%= f.input :name, :as => :string, :input_html => { :value => @pool.pretty_name } %>
<%= dtext_field "pool", "description" %>
<%= dtext_preview_button "pool", "description" %>
<%= f.input :description, as: :dtext %>
<%= f.input :post_ids_string, as: :text, label: "Posts" %>
<%= f.input :category, :collection => ["series", "collection"], :include_blank => false %>
<%= f.button :submit %>
<%= dtext_preview_button "pool_description" %>
<% end %>
</div>
</div>

View File

@@ -6,11 +6,11 @@
<%= edit_form_for(@pool) do |f| %>
<%= f.input :name, :as => :string, :required => true %>
<%= dtext_field "pool", "description" %>
<%= f.input :description, as: :dtext %>
<%= f.input :post_ids_string, as: :text, label: "Posts" %>
<%= f.input :category, :collection => ["series", "collection"], :include_blank => true, :selected => "", :required => true %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "pool", "description" %>
<%= dtext_preview_button "pool_description" %>
<% end %>
</div>
</div>

View File

@@ -1,11 +1,9 @@
<div class="appeal-dialog-body">
<%= embed_wiki("help:appeal_notice") %>
<%# XXX dtext_field expects there to be a `post_appeal` instance variable. %>
<% @post_appeal = post_appeal %>
<%= edit_form_for(@post_appeal, format: :js, remote: true) do |f| %>
<%= edit_form_for(post_appeal, format: :js, remote: true) do |f| %>
<%= f.hidden_field :post_id %>
<%= dtext_field "post_appeal", "reason", preview_id: "dtext-preview-for-post-appeal", type: "string" %>
<%= dtext_preview_button "post_appeal", "reason", preview_id: "dtext-preview-for-post-appeal" %>
<%= f.input :reason, as: :dtext, inline: true %>
<%= dtext_preview_button "post_appeal_reason" %>
<% end %>
</div>

View File

@@ -1,11 +1,9 @@
<div class="flag-dialog-body">
<%= embed_wiki("help:flag_notice") %>
<%# XXX dtext_field expects there to be a `post_flag` instance variable. %>
<% @post_flag = post_flag %>
<%= edit_form_for(@post_flag, format: :js, remote: true) do |f| %>
<%= edit_form_for(post_flag, format: :js, remote: true) do |f| %>
<%= f.hidden_field :post_id %>
<%= dtext_field "post_flag", "reason", preview_id: "dtext-preview-for-post-flag", type: "string" %>
<%= dtext_preview_button "post_flag", "reason", preview_id: "dtext-preview-for-post-flag" %>
<%= f.input :reason, as: :dtext, inline: true %>
<%= dtext_preview_button "post_flag_reason" %>
<% end %>
</div>

View File

@@ -9,10 +9,10 @@
<%= edit_form_for(@user_feedback) do |f| %>
<%= f.input :category, :collection => ["positive", "neutral", "negative"], :include_blank => false %>
<%= dtext_field "user_feedback", "body" %>
<%= f.input :body, as: :dtext %>
<%= f.input :is_deleted, label: "Deleted" %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "user_feedback", "body" %>
<%= dtext_preview_button "user_feedback_body" %>
<% end %>
</div>
</div>

View File

@@ -16,9 +16,9 @@
<%= edit_form_for(@user_feedback) do |f| %>
<%= f.input :user_name, :label => "User", :input_html => { value: @user_feedback.user.try(:name), data: { autocomplete: "user" } } %>
<%= f.input :category, :collection => ["positive", "neutral", "negative"], :include_blank => false %>
<%= dtext_field "user_feedback", "body" %>
<%= f.input :body, as: :dtext %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "user_feedback", "body" %>
<%= dtext_preview_button "user_feedback_body" %>
<% end %>
</div>
</div>

View File

@@ -5,7 +5,7 @@
<%= f.input :title, error: false, input_html: { data: { autocomplete: "tag" } }, hint: "Change to rename this wiki page. Update any wikis linking to this page first." %>
<%= f.input :other_names_string, as: :text, input_html: { size: "30x1" }, label: "Other names (#{link_to_wiki "help", "help:translated_tags"})".html_safe, hint: "Names used for this tag on other sites such as Pixiv. Separate with spaces." %>
<%= dtext_field "wiki_page", "body" %>
<%= f.input :body, as: :dtext %>
<% if policy(@wiki_page).can_edit_locked? %>
<%= f.input :is_locked, label: "Locked", hint: "Locked wikis can only be edited by Builders." %>
@@ -14,6 +14,6 @@
<%= f.input :is_deleted, label: "Deleted", hint: "Check to mark this wiki page as deleted." %>
<%= f.submit "Submit" %>
<%= dtext_preview_button "wiki_page", "body" %>
<%= dtext_preview_button "wiki_page_body" %>
<% end %>
</div>

View File

@@ -14,9 +14,9 @@
<%= edit_form_for(@wiki_page) do |f| %>
<%= f.input :title, error: false, input_html: { data: { autocomplete: "tag" } } %>
<%= f.input :other_names_string, as: :text, input_html: { size: "30x1" }, label: "Other names (#{link_to_wiki "help", "help:translated_tags"})".html_safe, hint: "Names used for this tag on other sites such as Pixiv. Separate with spaces." %>
<%= dtext_field "wiki_page", "body" %>
<%= f.input :body, as: :dtext %>
<%= f.submit "Submit" %>
<%= dtext_preview_button "wiki_page", "body" %>
<%= dtext_preview_button "wiki_page_body" %>
<% end %>
<%= render "tag_relationships/alias_and_implication_list", tag: @wiki_page.tag %>