better category and field creation

This commit is contained in:
Matthew Werner 2016-10-25 16:37:35 -07:00
parent 5b58364c97
commit 9299699f4b
26 changed files with 185 additions and 89 deletions

View File

@ -9,5 +9,9 @@ $(document).ready ->
window.scrollTo(0, 0);
), 1
$('.new-attribute-field-link').click (e) ->
e.preventDefault()
$("#attribute-field-modal").openModal()
$('.share').click ->
$('#share-modal').openModal()

View File

@ -29,4 +29,4 @@ p.long-form {
.content-field {
min-height: 140px;
}
}

View File

@ -1,7 +1,31 @@
# Controller for the Attribute model
class AttributeFieldsController < ContentController
def create
initialize_object
if @content.save
successful_response(:back, t(:create_success, model_name: humanized_model_name))
else
failed_response('new', :unprocessable_entity)
end
end
private
def initialize_object
category = current_user.attribute_categories.where(label: content_params[:attribute_category]).first_or_initialize.tap do |c|
c.entity_type = params[:entity_type]
c.save!
end
@content = AttributeField.new(label: content_params[:label]).tap do |f|
f.attribute_category_id = category.id
f.user_id = current_user.id
f.field_type = 'textearea'
end
end
def content_params
params.require(:attribute_field).permit(content_param_list)
end
@ -9,7 +33,7 @@ class AttributeFieldsController < ContentController
def content_param_list
[
:universe_id, :user_id,
:attribute_category_id,
:attribute_category,
:name, :field_type,
:label, :description
]

View File

@ -8,7 +8,7 @@ module AttributesHelper
end
end
link = content_tag(:a, category.label, href: "##{category.name}_panel")
link = content_tag(:a, category.label, href: "##{category.name.gsub("'", '')}_panel")
content_tag(:li, link, class: "tab col s3 #{is_disabled}")
end
end

View File

@ -0,0 +1,15 @@
module ContentHelper
def new_content_button(content)
icon = content_tag(:i, content.icon, class: "material-icons #{content.color}-text")
link = link_to("+ #{icon}".html_safe, new_polymorphic_path(content.build), class: "btn white #{content.color}-text")
content_tag(:small, link, class: 'right')
end
def content_settings_button(content)
icon = content_tag(:i, 'chrome_reader_mode', class: "material-icons #{content.color}-text")
link = link_to("+ #{icon}".html_safe, new_attribute_category_for_entity_path(content.content_name), class: "btn white #{content.color}-text")
content_tag(:small, link, class: 'right')
end
end

View File

@ -1,19 +1,33 @@
class AttributeCategory < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
has_many :attribute_fields
include HasAttributes
include Serendipitous::Concern
before_validation :ensure_name
def self.color
'amber'
end
def self.icon
'chrome_reader_mode'
'tab'
end
def self.content_name
'attribute_category'
end
def icon
self['icon'] || self.class.icon
end
private
def ensure_name
self.name ||= "#{label}-#{Time.now.to_i}".underscore.gsub(' ', '_')
end
end

View File

@ -1,4 +1,6 @@
class AttributeField < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
belongs_to :attribute_category
has_many :attribute_values, class_name: 'Attribute'
@ -8,6 +10,8 @@ class AttributeField < ActiveRecord::Base
attr_accessor :system
before_validation :ensure_name
scope :is_public, -> { eager_load(:universe).where('universes.privacy = ? OR attribute_fields.privacy = ?', 'public', 'public') }
def self.color
@ -22,10 +26,6 @@ class AttributeField < ActiveRecord::Base
'attribute'
end
def name
(self['name'] || "custom field #{Time.now.to_i}").downcase.gsub(' ','_')
end
def humanize
label
end
@ -37,4 +37,10 @@ class AttributeField < ActiveRecord::Base
def system?
!!self.system
end
private
def ensure_name
self.name ||= "#{label}-#{Time.now.to_i}".underscore.gsub(' ', '_')
end
end

View File

@ -9,13 +9,13 @@ module HasAttributes
def self.attribute_categories(user = nil)
categories = YAML.load_file(Rails.root.join('config', 'attributes', "#{content_name}.yml")).map do |category_name, details|
category = AttributeCategory.new(entity_type: self.name, name: category_name.to_s, label: details[:label], icon: details[:icon])
category = AttributeCategory.new(entity_type: self.content_name, name: category_name.to_s, label: details[:label], icon: details[:icon])
category.attribute_fields << details[:attributes].map { |field| AttributeField.new(field.merge(system: true)) }
category
end
return categories if user.nil?
[categories, user.attribute_categories.joins(:attribute_fields).where(['attribute_categories.entity_type = ?', content_name])].flatten.uniq
[categories, user.attribute_categories.where(['attribute_categories.entity_type = ?', content_name]).includes(:attribute_fields)].flatten.uniq
end
def update_custom_attributes

View File

@ -0,0 +1,37 @@
<div id="attribute-field-modal" class="modal">
<%= form_for AttributeField.new do |f| %>
<%= hidden_field_tag :entity_type, content.class.content_name %>
<div class="modal-content">
<h4>New attribute field</h4>
<div class="row">
<div class="input-field">
<%= f.label :attribute_category, 'Category' %><br />
<%= f.text_area :attribute_category, class: "materialize-textarea autocomplete" %>
</div>
</div>
<div class="row">
<%= f.text_area :label, class: "materialize-textarea", placeholder: "Field Name" %>
</div>
</div>
<div class="modal-footer">
<%= f.submit "Create field", class: "btn waves-effect waves-green" %>
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">close</a>
</div>
<% end %>
<script type="text/javascript">
$(function() {
$('#attribute_field_attribute_category').autocomplete({
data: {
<% current_user.attribute_categories.where(entity_type: content.class.content_name).each do |category| %>
"<%= category.label %>": null,
<% end %>
}
});
});
</script>
</div>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -17,7 +17,7 @@
<ul class="hoverable tabs hide-on-small-only">
<% content.class.attribute_categories(current_user).each do |category| %>
<li class="tab col s12">
<a href="#<%= category.name %>_panel">
<a href="#<%= category.name.gsub("'", '') %>_panel">
<i class="material-icons hide-on-med-and-down" style="font-size: 18px; position: relative; top: 3px;"><%= category.icon %></i>
<%= category.label %>
</a>
@ -28,7 +28,7 @@
<ul class="tabs hide-on-med-and-up">
<% content.class.attribute_categories(current_user).each do |category| %>
<li class="tab col s12">
<a href="#<%= category.name %>_panel" class="tooltipped" data-position="bottom" data-delay="100" data-tooltip="<%= category.label %>">
<a href="#<%= category.name.gsub("'", '') %>_panel" class="tooltipped" data-position="bottom" data-delay="100" data-tooltip="<%= category.label %>">
<i class="material-icons" style="font-size: 18px; position: relative; top: 3px;"><%= category.icon %></i>
</a>
</li>

View File

@ -31,7 +31,7 @@ set_meta_tags title: content.name, description: content.description
</ul>
<% categories.each do |category| %>
<div id="<%= category.name %>_panel" class="row">
<div id="<%= category.name.gsub("'", '') %>_panel" class="row">
<% category.attribute_fields.each do |attribute| %>
<% next if attribute.name.start_with?("private") && @content.user != current_user %>

View File

@ -1,15 +1,18 @@
<% if content.persisted? %>
<a class='dropdown-button black-text' href='#' data-activates='options-menu' data-constrainwidth='false'>
<i class="material-icons">more_vert</i>
</a>
<% end %>
<a class='dropdown-button black-text' href='#' data-activates='options-menu' data-constrainwidth='false'>
<i class="material-icons">more_vert</i>
</a>
<ul id='options-menu' class='dropdown-content'>
<!-- Broken on content edit pages
<li><a href="#!" class="share">Share this <%= content.class.to_s.downcase %></a></li>
<li class="divider"></li>
-->
<li>
<%= link_to "Create new attribute", '#attr-modal', class: 'black-text new-attribute-field-link' %>
</li>
<% if content.persisted? %>
<!-- Broken on content edit pages
<li><a href="#!" class="share">Share this <%= content.class.to_s.downcase %></a></li>
<li class="divider"></li>
-->
<li>
<%= link_to "Delete this #{content.class.content_name.humanize.downcase} forever", content,
:class => 'red-text',

View File

@ -1,23 +1,22 @@
<div id="<%= category.name %>_panel" class="row">
<% category.attribute_fields.each do |field| %>
<% # Do some dynamic resizing of columns based on how many columns there are
# TODO: move this into some service or something? Dunno, doesn't belong here.
<div id="<%= category.name.gsub("'", '') %>_panel" class="row">
<% # Do some dynamic resizing of columns based on how many columns there are
# TODO: move this into some service or something? Dunno, doesn't belong here.
s_width = 12
m_width = 6
l_width = 4
if category.attribute_fields.length == 1
# If there's only one field on this tab, go full-width on all screen sizes
s_width = m_width = l_width = 12
elsif category.attribute_fields.length == 2
# If there's two fields on this tab, go half-width on medium- and large-screens
s_width = 12
m_width = 6
l_width = 4
if category.attribute_fields.length == 1
# If there's only one field on this tab, go full-width on all screen sizes
s_width = m_width = l_width = 12
elsif category.attribute_fields.length == 2
# If there's two fields on this tab, go half-width on medium- and large-screens
s_width = 12
m_width = l_width = 6
elsif category.attribute_fields.length > 2
# If there's at least 3 fields, use the defaults (detailed above)
end
%>
m_width = l_width = 6
elsif category.attribute_fields.length > 2
# If there's at least 3 fields, use the defaults (detailed above)
end
%>
<% category.attribute_fields.each do |field| %>
<div class="col <%= "s#{s_width} m#{m_width} l#{l_width}" %>">
<% value = nil %>
@ -32,7 +31,7 @@
<% through_class = content.class.reflect_on_association(field.name).options[:through].to_s %>
<%= render 'content/form/relation_input', f: f, attribute: field.name, relation: through_class %>
<% elsif attribute == 'archetype' %>
<% elsif field.name == 'archetype' %>
<div class="input-field input-select">
<%= f.label field.name, class: 'active' %><br />
<%= f.select field.name, options_for_select(t('archetypes'), selected: f.object.archetype), include_blank: true %>
@ -57,10 +56,7 @@
</div>
<% elsif field.name == 'entity_type' %>
<div class="input-field">
<%= f.label field.name, field.label %><br />
<%= f.select field.name, %w(Character Item Location Universe).map { |tf| [tf, tf.downcase] } %>
</div>
<%= f.hidden_field :entity_type, value: f.object.entity_type %>
<% elsif field.name == 'privacy' %>
<div class="input-field">

View File

@ -1,6 +1,13 @@
<%
class_name = f.object.class.name.downcase
value = content.send(field.name.to_sym)
content_name = f.object.class.content_name
field_id = "#{content_name}_#{field.name}"
value = nil
if f.object.respond_to?(field.name.to_sym)
value = f.object.send(field.name.to_sym)
else
value = Attribute.where(user: current_user, attribute_field: field, entity: f.object).first
end
# TODO: Enable autocomplete when we can actually hide the dropdown if someone tabs out of a field.
# Not the easiest thing in the world to do, apparently.
@ -9,9 +16,9 @@
<div class="input-field content-field">
<%= f.label field.name, field.label %>
<%
placeholder = I18n.translate "attributes.#{class_name}.#{field.name}",
placeholder = I18n.translate "attributes.#{content_name}.#{field.name}",
scope: :serendipitous_questions,
name: f.object.send('name') || "this #{class_name}",
name: f.object.send('name') || "this #{content_name}",
attribute: "test",
default: 'Write as little or as much as you want!'
%>
@ -19,15 +26,15 @@
<% if field.system? %>
<%= f.text_area field.name, value: value, class: "materialize-textarea #{defined?(autocomplete) && false ? 'autocomplete' : ''}", placeholder: placeholder %>
<% else %>
<%= hidden_field_tag "#{content.content_name}[custom_attributes][][name]", field.name %>
<%= text_area_tag "#{content.content_name}[custom_attributes][][value]", value, class: "materialize-textarea #{defined?(autocomplete) && false ? 'autocomplete' : ''}", placeholder: placeholder %>
<%= hidden_field_tag "#{content_name}[custom_attribute_values][][name]", field.name %>
<%= text_area_tag "#{content_name}[custom_attribute_values][][value]", value && value.value, class: "materialize-textarea #{defined?(autocomplete) && false ? 'autocomplete' : ''}", placeholder: placeholder %>
<% end %>
</div>
<% if defined?(autocomplete) && false %>
<script type="text/javascript">
$(function() {
$('#<%= "#{content.content_name}_#{field.name}" %>').autocomplete({
$('#<%= "#{content_name}_#{field.name}" %>').autocomplete({
data: {
<% autocomplete.each do |autocomplete_option| %>
"<%= autocomplete_option %>": null,

View File

@ -2,5 +2,5 @@
<%= content.name %>
<% else %>
<%- content_name = content.class.respond_to?(:content_name) ? content.class.content_name: content.class.to_s %>
Create your new <%= content_name.downcase %>
Create your new <%= content_name.humanize.downcase %>
<% end %>

View File

@ -9,17 +9,9 @@
<% if @content.any? %>
<h4>
You've created <%= pluralize(@content.count, @content.content_name) %>
<% if @content.count > 0 %>
<small class="right">
<%= link_to new_polymorphic_path(@content.build), class: "btn white #{content_type_class.color}-text" do %>
+
<i class="material-icons <%= content_type_class.color %>-text">
<%= content_type_class.icon %>
</i>
<% end %>
</small>
<% end %>
<%= new_content_button(@content) if @content.count > 0 %>
</h4>
<%= render partial: 'content/list/list', locals: { content_list: @content } %>
<%= link_to "Create another #{@content.content_name}", new_polymorphic_path(@content.build), :class => 'btn' %>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -17,9 +17,6 @@
<li><%= link_to 'Your characters', characters_path %></li>
<li><%= link_to 'Your locations', locations_path %></li>
<li><%= link_to 'Your items', items_path %></li>
<li><%= link_to 'Your attribute categories', attribute_categories_path %></li>
<li><%= link_to 'Your attributes', attribute_fields_path %></li>
<li class="divider"></li>
<li><%= link_to 'Your author profile', current_user if current_user %></li>
<li><%= link_to 'Account settings', edit_user_registration_path %></li>
@ -80,16 +77,6 @@
<i class="material-icons">beach_access</i>
</a>
</li>
<li>
<a href="<%= attribute_categories_url %>" class="tooltipped" data-position="bottom" data-delay="100" data-tooltip="Attribute Categories">
<i class="material-icons">chrome_reader_mode</i>
</a>
</li>
<li>
<a href="<%= attribute_fields_url %>" class="tooltipped" data-position="bottom" data-delay="100" data-tooltip="Attributes">
<i class="material-icons">assignment</i>
</a>
</li>
<li>
<a class="dropdown-button tooltipped" href="#!" data-activates="desktop-user-dropdown" data-position="bottom" data-delay="100" data-tooltip="You">
<i class="material-icons">person</i>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -3,3 +3,4 @@
<% end %>
<%= render partial: 'content/share', locals: { shared_content: @content} %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -1,3 +1,5 @@
<%= form_for @content do |form| %>
<%= render partial: 'content/form', locals: { f: form, content: @content } %>
<% end %>
<% end %>
<%= render 'attribute_fields/modal', content: @content %>

View File

@ -2,11 +2,7 @@
:label: General
:icon: info
:attributes:
- :name: label
:label: Name
- :name: entity_type
:label: Entity Type
- :name: name
:label: Name
- :name: label
:label: Label
- :name: icon
:label: Icon