diff --git a/app/assets/javascripts/content_linking.js b/app/assets/javascripts/content_linking.js index b1bfbf75..bfa77840 100644 --- a/app/assets/javascripts/content_linking.js +++ b/app/assets/javascripts/content_linking.js @@ -12,6 +12,9 @@ $(document).ready(function () { var focused_text_field = $(focus_event.target); var parent_content_field = focused_text_field.closest('.content-field'); + $('.show-when-focused').hide(); + parent_content_field.find('.show-when-focused').show(); + $('.content-field').removeClass('focused'); parent_content_field.addClass('focused'); $('.content-field-link-bar').hide(); @@ -20,6 +23,23 @@ $(document).ready(function () { add_link_bar(parent_content_field.find('.content-field-link-bar-container')); }); + // um sir excuse me why does this need to be in a setTimeout? It doesn't work + // unless it is... for whatever reason. Here be dragons. + setTimeout(function () { + $('.content-field').find('.chips input').focus(function (focus_event) { + var focused_text_field = $(focus_event.target); + var parent_content_field = focused_text_field.closest('.content-field'); + + $('.show-when-focused').hide(); + parent_content_field.find('.show-when-focused').show(); + + $('.content-field').removeClass('focused'); + parent_content_field.addClass('focused'); + $('.content-field-link-bar').hide(); + parent_content_field.find('.content-field-link-bar').show(); + }); + }, 100); + function add_link_bar_click_handlers() { $('.js-content-link-option').click(function (click_event) { var selected_option = $(click_event.target); diff --git a/app/assets/javascripts/page_tags.js b/app/assets/javascripts/page_tags.js new file mode 100644 index 00000000..b4d6e07b --- /dev/null +++ b/app/assets/javascripts/page_tags.js @@ -0,0 +1,8 @@ +$(document).ready(function () { + $('.js-add-tag').click(function() { + var clicked_tag = $(this).find('.badge').data('badge-caption'); + + M.Chips.getInstance($('.chips')).addChip({tag: clicked_tag}); + return false; + }); +}); diff --git a/app/assets/stylesheets/navbar.css b/app/assets/stylesheets/navbar.scss similarity index 100% rename from app/assets/stylesheets/navbar.css rename to app/assets/stylesheets/navbar.scss diff --git a/app/assets/stylesheets/page_tags.scss b/app/assets/stylesheets/page_tags.scss new file mode 100644 index 00000000..9dddd3b2 --- /dev/null +++ b/app/assets/stylesheets/page_tags.scss @@ -0,0 +1,20 @@ +.tags-container { + padding-top: 8px; + + .badge { + margin-bottom: 4px; + margin-left: 0; + margin-right: 5px; + } + +} + +.chip { + i.material-icons { + line-height: 26px; + } +} + +.show-when-focused { + display: none; +} diff --git a/app/controllers/content_controller.rb b/app/controllers/content_controller.rb index 2fb32cb3..58b4a542 100644 --- a/app/controllers/content_controller.rb +++ b/app/controllers/content_controller.rb @@ -26,8 +26,8 @@ class ContentController < ApplicationController @content = @universe_scope.send(pluralized_content_name) else @content = ( - current_user.send(pluralized_content_name) + - current_user.send("contributable_#{pluralized_content_name}") + current_user.send(pluralized_content_name).includes(:page_tags) + + current_user.send("contributable_#{pluralized_content_name}").includes(:page_tags) ) unless @content_type_class == Universe @@ -36,7 +36,19 @@ class ContentController < ApplicationController end end - @content = @content.to_a.flatten.uniq.sort_by(&:name) + @content = @content.to_a.flatten.uniq + + # Filters + @page_tags = PageTag.where( + page_type: @content_type_class.name, + page_id: @content.pluck(:id) + ) + if params.key?(:slug) + filtered_page_tags = @page_tags.where(slug: params[:slug]) + @content.select! { |content| filtered_page_tags.pluck(:page_id).include?(content.id) } + end + + @content = @content.sort_by(&:name) respond_to do |format| format.html { render 'content/index' } @@ -97,6 +109,10 @@ class ContentController < ApplicationController @serialized_categories_and_fields = CategoriesAndFieldsSerializer.new( @content.class.attribute_categories(current_user) ) + @suggested_page_tags = ( + current_user.page_tags.where(page_type: @content.class.name).pluck(:tag) + + PageTagService.suggested_tags_for(@content.class.name) + ).uniq # todo this is a good spot to audit to disable and see if create permissions are ok also unless (current_user || User.new).can_create?(content_type_from_controller(self.class)) @@ -119,6 +135,10 @@ class ContentController < ApplicationController end @serialized_content = ContentSerializer.new(@content) + @suggested_page_tags = ( + current_user.page_tags.where(page_type: content_type_class.name).pluck(:tag) + + PageTagService.suggested_tags_for(content_type_class.name) + ).uniq - @serialized_content.page_tags unless @content.updatable_by? current_user return redirect_to @content, notice: t(:no_do_permission) @@ -162,6 +182,8 @@ class ContentController < ApplicationController upload_files params['image_uploads'], content_type.name, @content.id end + update_page_tags + successful_response(content_creation_redirect_url, t(:create_success, model_name: @content.try(:name).presence || humanized_model_name)) else failed_response('new', :unprocessable_entity, "Unable to save page. Error code: " + @content.errors.map(&:messages).to_sentence) @@ -192,6 +214,8 @@ class ContentController < ApplicationController end end + update_page_tags + if @content.user == current_user # todo this needs some extra validation probably to ensure each attribute is one associated with this page update_success = @content.update_attributes(content_params) @@ -333,6 +357,26 @@ class ContentController < ApplicationController private + def update_page_tags + tag_list = page_tag_params.fetch(:page_tags, "").split(',,,|||,,,') + current_tags = @content.page_tags.pluck(:tag) + + tags_to_add = tag_list - current_tags + tags_to_remove = current_tags - tag_list + + tags_to_add.each do |tag| + @content.page_tags.find_or_create_by( + tag: tag, + slug: PageTagService.slug_for(tag), + user: @content.user + ) + end + + tags_to_remove.each do |tag| + @content.page_tags.find_by(tag: tag).destroy + end + end + def render_json(content) render json: JSON.pretty_generate({ name: content.try(:name), @@ -403,6 +447,15 @@ class ContentController < ApplicationController params.require(content_class).permit(content_param_list + [:deleted_at]) end + def page_tag_params + content_class = content_type_from_controller(self.class) + .name + .downcase + .to_sym + + params.require(content_class).permit(:page_tags) + end + def content_deletion_redirect_url send("#{@content.class.name.underscore.pluralize}_path") end diff --git a/app/models/attribute_field.rb b/app/models/attribute_field.rb index cd651516..69ce156b 100644 --- a/app/models/attribute_field.rb +++ b/app/models/attribute_field.rb @@ -40,6 +40,8 @@ class AttributeField < ApplicationRecord Universe.icon when 'textarea' 'text_fields' + when 'tags' + 'label' else 'text_fields' end @@ -69,6 +71,10 @@ class AttributeField < ApplicationRecord self.field_type == 'universe' end + def tags_field? + self.field_type == 'tags' + end + private def ensure_name diff --git a/app/models/concerns/has_page_tags.rb b/app/models/concerns/has_page_tags.rb new file mode 100644 index 00000000..b1ada5cb --- /dev/null +++ b/app/models/concerns/has_page_tags.rb @@ -0,0 +1,9 @@ +require 'active_support/concern' + +module HasPageTags + extend ActiveSupport::Concern + + included do + has_many :page_tags, as: :page + end +end diff --git a/app/models/concerns/is_content_page.rb b/app/models/concerns/is_content_page.rb new file mode 100644 index 00000000..51e02df6 --- /dev/null +++ b/app/models/concerns/is_content_page.rb @@ -0,0 +1,14 @@ +require 'active_support/concern' + +module IsContentPage + extend ActiveSupport::Concern + + included do + include HasAttributes + include HasPrivacy + include HasContentGroupers + include HasImageUploads + include HasChangelog + include HasPageTags + end +end diff --git a/app/models/content_types/building.rb b/app/models/content_types/building.rb index 1fcebd18..2d772103 100644 --- a/app/models/content_types/building.rb +++ b/app/models/content_types/building.rb @@ -7,11 +7,8 @@ class Building < ActiveRecord::Base validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage + include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/character.rb b/app/models/content_types/character.rb index 2b52df8b..13f4b867 100644 --- a/app/models/content_types/character.rb +++ b/app/models/content_types/character.rb @@ -13,12 +13,7 @@ class Character < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/condition.rb b/app/models/content_types/condition.rb index dd411ca8..e9f3193b 100644 --- a/app/models/content_types/condition.rb +++ b/app/models/content_types/condition.rb @@ -7,11 +7,7 @@ class Condition < ActiveRecord::Base validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/country.rb b/app/models/content_types/country.rb index e7926c34..7261cf89 100644 --- a/app/models/content_types/country.rb +++ b/app/models/content_types/country.rb @@ -9,10 +9,7 @@ class Country < ApplicationRecord include BelongsToUniverse include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/creature.rb b/app/models/content_types/creature.rb index 9c4fede3..4c228777 100644 --- a/app/models/content_types/creature.rb +++ b/app/models/content_types/creature.rb @@ -15,12 +15,7 @@ class Creature < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/deity.rb b/app/models/content_types/deity.rb index 2080421a..13e48989 100644 --- a/app/models/content_types/deity.rb +++ b/app/models/content_types/deity.rb @@ -6,11 +6,7 @@ class Deity < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/flora.rb b/app/models/content_types/flora.rb index f5818e40..530a25ca 100644 --- a/app/models/content_types/flora.rb +++ b/app/models/content_types/flora.rb @@ -8,11 +8,7 @@ class Flora < ApplicationRecord include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/government.rb b/app/models/content_types/government.rb index 2675e2d1..ae8e244d 100644 --- a/app/models/content_types/government.rb +++ b/app/models/content_types/government.rb @@ -6,11 +6,7 @@ class Government < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/group.rb b/app/models/content_types/group.rb index 40a106c7..dff6d0e2 100644 --- a/app/models/content_types/group.rb +++ b/app/models/content_types/group.rb @@ -8,11 +8,7 @@ class Group < ApplicationRecord include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/item.rb b/app/models/content_types/item.rb index 2f639019..1db6dca5 100644 --- a/app/models/content_types/item.rb +++ b/app/models/content_types/item.rb @@ -13,13 +13,7 @@ class Item < ApplicationRecord belongs_to :user include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog - + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/job.rb b/app/models/content_types/job.rb index d072c945..5109c6a6 100644 --- a/app/models/content_types/job.rb +++ b/app/models/content_types/job.rb @@ -7,11 +7,7 @@ class Job < ActiveRecord::Base validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/landmark.rb b/app/models/content_types/landmark.rb index 7cf7f509..996c91b5 100644 --- a/app/models/content_types/landmark.rb +++ b/app/models/content_types/landmark.rb @@ -7,12 +7,7 @@ class Landmark < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/language.rb b/app/models/content_types/language.rb index 63ed53e2..52fc5ffa 100644 --- a/app/models/content_types/language.rb +++ b/app/models/content_types/language.rb @@ -9,10 +9,7 @@ class Language < ApplicationRecord include BelongsToUniverse include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/location.rb b/app/models/content_types/location.rb index 632db517..e77f1ec0 100644 --- a/app/models/content_types/location.rb +++ b/app/models/content_types/location.rb @@ -17,12 +17,7 @@ class Location < ApplicationRecord belongs_to :user include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/magic.rb b/app/models/content_types/magic.rb index 8b12cc77..b9624bae 100644 --- a/app/models/content_types/magic.rb +++ b/app/models/content_types/magic.rb @@ -7,12 +7,7 @@ class Magic < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/planet.rb b/app/models/content_types/planet.rb index 423092dc..6c549771 100644 --- a/app/models/content_types/planet.rb +++ b/app/models/content_types/planet.rb @@ -6,11 +6,7 @@ class Planet < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/race.rb b/app/models/content_types/race.rb index 5f8fb21b..c309a211 100644 --- a/app/models/content_types/race.rb +++ b/app/models/content_types/race.rb @@ -13,12 +13,7 @@ class Race < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/religion.rb b/app/models/content_types/religion.rb index b43b1a5a..bc0227fd 100644 --- a/app/models/content_types/religion.rb +++ b/app/models/content_types/religion.rb @@ -7,12 +7,7 @@ class Religion < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/scene.rb b/app/models/content_types/scene.rb index e732eb77..f5c387a5 100644 --- a/app/models/content_types/scene.rb +++ b/app/models/content_types/scene.rb @@ -7,13 +7,7 @@ class Scene < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog - + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/technology.rb b/app/models/content_types/technology.rb index 0e9762d2..9348a0df 100644 --- a/app/models/content_types/technology.rb +++ b/app/models/content_types/technology.rb @@ -6,11 +6,7 @@ class Technology < ApplicationRecord validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/town.rb b/app/models/content_types/town.rb index da18715b..76668282 100644 --- a/app/models/content_types/town.rb +++ b/app/models/content_types/town.rb @@ -9,11 +9,7 @@ class Town < ApplicationRecord include BelongsToUniverse include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog - + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/tradition.rb b/app/models/content_types/tradition.rb index 031e77f6..782600df 100644 --- a/app/models/content_types/tradition.rb +++ b/app/models/content_types/tradition.rb @@ -7,11 +7,7 @@ class Tradition < ActiveRecord::Base validates :user_id, presence: true include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/content_types/universe.rb b/app/models/content_types/universe.rb index bb70b71a..81cbd988 100644 --- a/app/models/content_types/universe.rb +++ b/app/models/content_types/universe.rb @@ -8,10 +8,7 @@ class Universe < ApplicationRecord acts_as_paranoid - include HasAttributes - include HasPrivacy - include HasImageUploads - include HasChangelog + include IsContentPage include Serendipitous::Concern diff --git a/app/models/content_types/vehicle.rb b/app/models/content_types/vehicle.rb index c2f34966..96179c2d 100644 --- a/app/models/content_types/vehicle.rb +++ b/app/models/content_types/vehicle.rb @@ -6,12 +6,8 @@ class Vehicle < ActiveRecord::Base validates :name, presence: true validates :user_id, presence: true + include IsContentPage include BelongsToUniverse - include HasAttributes - include HasPrivacy - include HasContentGroupers - include HasImageUploads - include HasChangelog include Serendipitous::Concern include Authority::Abilities diff --git a/app/models/page_tag.rb b/app/models/page_tag.rb new file mode 100644 index 00000000..987857ae --- /dev/null +++ b/app/models/page_tag.rb @@ -0,0 +1,4 @@ +class PageTag < ApplicationRecord + belongs_to :page, polymorphic: true + belongs_to :user +end diff --git a/app/models/serializers/content_serializer.rb b/app/models/serializers/content_serializer.rb index 7b1b7338..c30aba40 100644 --- a/app/models/serializers/content_serializer.rb +++ b/app/models/serializers/content_serializer.rb @@ -4,6 +4,7 @@ class ContentSerializer attr_accessor :categories attr_accessor :fields attr_accessor :attribute_values + attr_accessor :page_tags attr_accessor :raw_model attr_accessor :class_name, :class_color, :class_icon @@ -39,6 +40,8 @@ class ContentSerializer self.class_color = content.class.color self.class_icon = content.class.icon + self.page_tags = content.page_tags.pluck(:tag) || [] + self.data = { name: content.try(:name), description: content.try(:description), diff --git a/app/models/user.rb b/app/models/user.rb index 02a72777..4b05723c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -34,6 +34,7 @@ class User < ApplicationRecord has_many :user_content_type_activators, dependent: :destroy has_many :api_keys, dependent: :destroy + has_many :page_tags, dependent: :destroy def contributable_universes @user_contributable_universes ||= begin diff --git a/app/services/page_tag_service.rb b/app/services/page_tag_service.rb new file mode 100644 index 00000000..46d07370 --- /dev/null +++ b/app/services/page_tag_service.rb @@ -0,0 +1,60 @@ +class PageTagService < Service + def self.slug_for(text) + text.downcase.gsub(/[^0-9a-z ]/i, '').gsub(/ /, '-') + end + + def self.suggested_tags_for(class_name) + case class_name + when Building.name + ["School", "Business"] + when Character.name + ["Main character", "Side character", "Background character"] + when Condition.name + ["Disease", "Blessing", "Curse"] + when Country.name + ["Kingdom", "Country", "Region"] + when Creature.name + ["Domesticated", "Wild", "Humanoid"] + when Deity.name + ["Good", "Evil"] + when Flora.name + ["Floral", "Weed"] + when Government.name + ["Republic", "Democracy", "Monarchy", "Dictatorship"] + when Group.name + ["Good", "Evil"] + when Item.name + ["Weapon", "Armor", "Artifact", "Relic"] + when Job.name + ["Military", "Government", "Private sector"] + when Landmark.name + ["Cave", "Mountain", "Temple", "Ruins"] + when Language.name + ["Modern", "Ancient"] + when Location.name + ["Town", "City", "River", "Mountains", "Desert"] + when Magic.name + ["Spell", "Ability", "Superpower"] + when Planet.name + ["Habitable", "Inhabitable"] + when Race.name + ["Race", "Species", "Humanoid"] + when Religion.name + ["Modern", "Ancient", "Monotheistic", "Polytheistic"] + when Scene.name + ["Atmospheric", "Exposition", "Transition"] + when Technology.name + ["Military", "Consumer", "Theoretical"] + when Town.name + ["Village", "Town", "City", "Metropolis"] + when Tradition.name + ["Holiday", "Practice"] + when Universe.name + ["Favorite"] + when Vehicle.name + ["Automobile", "Train", "Plane", "Spaceship"] + else + [] + end + end +end diff --git a/app/views/content/attributes.html.erb b/app/views/content/attributes.html.erb index 88e51cc8..875340fc 100644 --- a/app/views/content/attributes.html.erb +++ b/app/views/content/attributes.html.erb @@ -103,7 +103,7 @@
- <% if attribute_field.name_field? || attribute_field.universe_field? %> + <% if attribute_field.name_field? || attribute_field.universe_field? || attribute_field.tags_field? %>
This field cannot be deleted.
diff --git a/app/views/content/display/_category_panel.html.erb b/app/views/content/display/_category_panel.html.erb index 803697fc..88eb784b 100644 --- a/app/views/content/display/_category_panel.html.erb +++ b/app/views/content/display/_category_panel.html.erb @@ -17,8 +17,7 @@ when 'universe' Universe.find_by(id: serialized_field[:value].to_i) - # TODO: update all textearea/textarea --> text_area in prod data - when 'name', 'text_area', 'textearea', 'textarea' + when 'name', 'text_area' serialized_field[:value] when 'link' @@ -28,6 +27,9 @@ nil end + when 'tags' + content.page_tags + else raise "unknown field type = " + serialized_field[:type].inspect end @@ -61,6 +63,24 @@ <% end %>
+ <% elsif serialized_field[:type] == 'tags' %> +
+ <% value.each do |tag| %> + <% if user_signed_in? && @content.user == current_user %> + <%= + link_to send( + "page_tag_#{content.raw_model.class.name.downcase.pluralize}_path", + slug: PageTagService.slug_for(tag) + ) do + %> + + <% end %> + <% else %> + + <% end %> + <% end %> +
+ <% else # serialized_field[:type] == text %>
<%= diff --git a/app/views/content/form/_panel.html.erb b/app/views/content/form/_panel.html.erb index b3fcad8f..1a0363da 100644 --- a/app/views/content/form/_panel.html.erb +++ b/app/views/content/form/_panel.html.erb @@ -26,6 +26,62 @@ relation: through_class %> + <% elsif field[:type] == 'tags' %> + +
+
+ <%= f.label field[:id], field[:label] %> +
+ <%= f.hidden_field :page_tags, value: content.page_tags.join(',,,|||,,,'), id: 'hidden_page_tags_value' %> + +
+ label + Type and press enter to create a new tag, or click any of the suggested tags below to add it. +
+
+ <% @suggested_page_tags.each do |tag| %> + <%= + link_to '#', class: 'js-add-tag' do + %> + + <% end %> + <% end %> +
+
+
+
+ <%= content_for :javascript do %> + function update_hidden_page_tag_value(e) { + var chips = M.Chips.getInstance($('.chips')).chipsData.map(function (c) { + return c['tag']; + }); + + var hidden_input = $('#hidden_page_tags_value').first(); + hidden_input.val(chips.join(',,,|||,,,')); + } + + var chips = $('.chips-autocomplete').chips({ + placeholder: 'Tag this page', + secondaryPlaceholder: '+ Tag', + autocompleteOptions: { + data: { + <% @content.page_tags.pluck(:tag).each do |tag| %> + '<%= tag %>': null, + <% end %> + }, + limit: 100, + minLength: 1 + }, + data: [ + <% @content.page_tags.pluck(:tag).each do |tag| %> + {tag: '<%= tag %>'}, + <% end %> + ], + onChipAdd: update_hidden_page_tag_value, + onChipDelete: update_hidden_page_tag_value + }); + <% end %> + <% elsif field[:type] == 'universe' %>
diff --git a/app/views/content/index.html.erb b/app/views/content/index.html.erb index a9bad32a..98845854 100644 --- a/app/views/content/index.html.erb +++ b/app/views/content/index.html.erb @@ -6,7 +6,29 @@ <%= render partial: 'content/components/parallax_header', locals: { content_type: content_type, content_class: @content_type_class } %> <% end %> + +<% if @page_tags.any? %> +
+ View by tag:  + <%= link_to polymorphic_path(@content_type_class) do %> + + <% end %> + <% @page_tags.each do |tag| %> + <%= + link_to send( + "page_tag_#{content_type.pluralize}_path", + slug: PageTagService.slug_for(tag.tag) + ) do + %> + + <% end %> + <% end %> +
+
+<% end %> + <% if @content.any? %> + <%= render partial: 'content/components/list_filter_bar', locals: { } %>
<%= render partial: 'content/list/list', locals: { content_list: @content, content_type: @content_type_class, show_add_another_form: true } %> diff --git a/app/views/content/list/_list.html.erb b/app/views/content/list/_list.html.erb index 465e3c99..046ff70c 100644 --- a/app/views/content/list/_list.html.erb +++ b/app/views/content/list/_list.html.erb @@ -53,7 +53,23 @@ data-position="bottom" data-delay="100" data-tooltip="You have been added as a contributor to this universe and its content."> <% end %> -

+

+ <% content.page_tags.each do |tag| %> + <% if user_signed_in? && content.user == current_user %> + <%= + link_to send( + "page_tag_#{content.class.name.downcase.pluralize}_path", + slug: PageTagService.slug_for(tag.tag) + ) do + %> + + <% end %> + <% else %> + + <% end %> + <% end %> +

+

<% if user_signed_in? %> " style="font-size: 80%"> mode_edit @@ -71,7 +87,7 @@ <% end %>

- <% if user_signed_in? && content.user_id == current_user.id %> + <% if user_signed_in? && content.updatable_by?(current_user) %> <%# todo also show if you're a contributor %> <%= link_to edit_polymorphic_path(content.page_type.downcase, id: content.id), class: 'js-edit-hover' do %> edit diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2ce23e94..c514f245 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -31,12 +31,12 @@ <%= render partial: 'content/keyboard_controls_help_modal' %> diff --git a/config/attributes/building.yml b/config/attributes/building.yml index 0482028c..cf0faca3 100644 --- a/config/attributes/building.yml +++ b/config/attributes/building.yml @@ -15,6 +15,9 @@ :label: Type of building - :name: alternate_names :label: Alternate names + - :name: + :label: Tags + :field_type: tags :occupants: :label: Occupants :icon: recent_actors diff --git a/config/attributes/character.yml b/config/attributes/character.yml index 4da44ef5..18fde3e3 100644 --- a/config/attributes/character.yml +++ b/config/attributes/character.yml @@ -16,6 +16,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :looks: :label: Looks :icon: face diff --git a/config/attributes/condition.yml b/config/attributes/condition.yml index 7560f31a..e54585b9 100644 --- a/config/attributes/condition.yml +++ b/config/attributes/condition.yml @@ -15,6 +15,9 @@ :label: Type of condition - :name: alternate_names :label: Alternate names + - :name: + :label: Tags + :field_type: tags :causes: :label: Causes :icon: bubble_chart diff --git a/config/attributes/country.yml b/config/attributes/country.yml index 1c7f5c6c..32be95f5 100644 --- a/config/attributes/country.yml +++ b/config/attributes/country.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :points_of_interest: :label: Points of interest :icon: location_on diff --git a/config/attributes/creature.yml b/config/attributes/creature.yml index 8aefa426..2586b2ae 100644 --- a/config/attributes/creature.yml +++ b/config/attributes/creature.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :looks: :label: Looks :icon: pets diff --git a/config/attributes/deity.yml b/config/attributes/deity.yml index 18aedd01..c11b5f26 100644 --- a/config/attributes/deity.yml +++ b/config/attributes/deity.yml @@ -13,6 +13,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :appearance: :label: Appearance :icon: accessibility diff --git a/config/attributes/flora.yml b/config/attributes/flora.yml index 5b8ca97a..7bd4a5c6 100644 --- a/config/attributes/flora.yml +++ b/config/attributes/flora.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :classification: :label: Classification :icon: bubble_chart diff --git a/config/attributes/government.yml b/config/attributes/government.yml index cdb0a836..654b213e 100644 --- a/config/attributes/government.yml +++ b/config/attributes/government.yml @@ -11,6 +11,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :structure: :label: Structure :icon: view_list diff --git a/config/attributes/group.yml b/config/attributes/group.yml index e46fa891..deda3d30 100644 --- a/config/attributes/group.yml +++ b/config/attributes/group.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :hierarchy: :label: Hierarchy :icon: call_split diff --git a/config/attributes/item.yml b/config/attributes/item.yml index f37cbc2d..1d162394 100644 --- a/config/attributes/item.yml +++ b/config/attributes/item.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :looks: :label: Looks :icon: redeem diff --git a/config/attributes/job.yml b/config/attributes/job.yml index a8bb58ce..7e75732e 100644 --- a/config/attributes/job.yml +++ b/config/attributes/job.yml @@ -14,6 +14,9 @@ :label: Type of job - :name: alternate_names :label: Alternate names + - :name: + :label: Tags + :field_type: tags :requirements: :label: Requirements :icon: storage diff --git a/config/attributes/landmark.yml b/config/attributes/landmark.yml index a030f362..933b990a 100644 --- a/config/attributes/landmark.yml +++ b/config/attributes/landmark.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :location: :label: Whereabouts :icon: location_on diff --git a/config/attributes/language.yml b/config/attributes/language.yml index c89bc9a0..5f3cd32e 100644 --- a/config/attributes/language.yml +++ b/config/attributes/language.yml @@ -10,6 +10,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :info: :label: Info :icon: forum diff --git a/config/attributes/location.yml b/config/attributes/location.yml index 198f8487..cf391f0f 100644 --- a/config/attributes/location.yml +++ b/config/attributes/location.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :culture: :label: Culture :icon: face diff --git a/config/attributes/magic.yml b/config/attributes/magic.yml index 0d4e11c6..370781e1 100644 --- a/config/attributes/magic.yml +++ b/config/attributes/magic.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :appearance: :label: Appearance :icon: flash_on diff --git a/config/attributes/planet.yml b/config/attributes/planet.yml index 564cc9e0..f99fe942 100644 --- a/config/attributes/planet.yml +++ b/config/attributes/planet.yml @@ -11,6 +11,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :geography: :label: Geography :icon: layers diff --git a/config/attributes/race.yml b/config/attributes/race.yml index d540cb69..7c729b36 100644 --- a/config/attributes/race.yml +++ b/config/attributes/race.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :looks: :label: Looks :icon: face diff --git a/config/attributes/religion.yml b/config/attributes/religion.yml index 1caa4b27..5e913ca3 100644 --- a/config/attributes/religion.yml +++ b/config/attributes/religion.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :history: :label: History :icon: date_range diff --git a/config/attributes/scene.yml b/config/attributes/scene.yml index 844835a2..e09c38cf 100644 --- a/config/attributes/scene.yml +++ b/config/attributes/scene.yml @@ -10,6 +10,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :looks: :label: members :icon: face diff --git a/config/attributes/technology.yml b/config/attributes/technology.yml index 9437f794..356a97b2 100644 --- a/config/attributes/technology.yml +++ b/config/attributes/technology.yml @@ -12,6 +12,9 @@ - :name: universe_id :label: Universe :field_type: universe + - :name: + :label: Tags + :field_type: tags :production: :label: Production :icon: build diff --git a/config/attributes/town.yml b/config/attributes/town.yml index 3f704be2..795cc789 100644 --- a/config/attributes/town.yml +++ b/config/attributes/town.yml @@ -15,6 +15,9 @@ - :name: countries :label: Country :field_type: link + - :name: + :label: Tags + :field_type: tags :populace: :label: Populace :icon: group diff --git a/config/attributes/tradition.yml b/config/attributes/tradition.yml index c5f269ab..8cf232d1 100644 --- a/config/attributes/tradition.yml +++ b/config/attributes/tradition.yml @@ -14,6 +14,9 @@ :label: Type of tradition - :name: alternate_names :label: Alternate names + - :name: + :label: Tags + :field_type: tags :observance: :label: Observance :icon: track_changes diff --git a/config/attributes/universe.yml b/config/attributes/universe.yml index 937c61a6..a81450ea 100644 --- a/config/attributes/universe.yml +++ b/config/attributes/universe.yml @@ -9,6 +9,12 @@ :label: Description - :name: genre :label: Genre + - :name: + :label: Tags + :field_type: tags + - :name: + :label: Tags + :field_type: tags :history: :label: History :icon: date_range diff --git a/config/attributes/vehicle.yml b/config/attributes/vehicle.yml index b22230a0..7abde0ac 100644 --- a/config/attributes/vehicle.yml +++ b/config/attributes/vehicle.yml @@ -14,6 +14,9 @@ :label: Type of vehicle - :name: alternate_names :label: Alternate names + - :name: + :label: Tags + :field_type: tags :looks: :label: Looks :icon: airport_shuttle diff --git a/config/routes.rb b/config/routes.rb index c70c4aea..8e3c7f04 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,6 +10,7 @@ Rails.application.routes.draw do # get :characters, on: :member <...etc...> Rails.application.config.content_types[:all].each do |content_type| get content_type.name.downcase.pluralize.to_sym, on: :member + # todo page tags here end end scope '/my' do @@ -82,11 +83,13 @@ Rails.application.routes.draw do get content_type.name.downcase.pluralize.to_sym, on: :member end get :changelog, on: :member + get '/tagged/:slug', action: :index, on: :collection, as: :page_tag end Rails.application.config.content_types[:all_non_universe].each do |content_type| # resources :characters do resources content_type.name.downcase.pluralize.to_sym do get :changelog, on: :member + get '/tagged/:slug', action: :index, on: :collection, as: :page_tag end end diff --git a/db/migrate/20190212220053_create_page_tags.rb b/db/migrate/20190212220053_create_page_tags.rb new file mode 100644 index 00000000..aa6112e1 --- /dev/null +++ b/db/migrate/20190212220053_create_page_tags.rb @@ -0,0 +1,13 @@ +class CreatePageTags < ActiveRecord::Migration[5.2] + def change + create_table :page_tags do |t| + t.references :page, polymorphic: true + t.string :tag + t.string :slug + t.string :color + t.references :user, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20190216080611_add_index_to_page_types.rb b/db/migrate/20190216080611_add_index_to_page_types.rb new file mode 100644 index 00000000..09e81327 --- /dev/null +++ b/db/migrate/20190216080611_add_index_to_page_types.rb @@ -0,0 +1,5 @@ +class AddIndexToPageTypes < ActiveRecord::Migration[5.2] + def change + add_index(:page_tags, [:user_id, :page_type]) + end +end diff --git a/db/schema.rb b/db/schema.rb index 94b5373c..a38cbe42 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_01_09_201055) do +ActiveRecord::Schema.define(version: 2019_02_16_080611) do create_table "api_keys", force: :cascade do |t| t.integer "user_id" @@ -1434,6 +1434,20 @@ ActiveRecord::Schema.define(version: 2019_01_09_201055) do t.datetime "updated_at", null: false end + create_table "page_tags", force: :cascade do |t| + t.string "page_type" + t.integer "page_id" + t.string "tag" + t.string "slug" + t.string "color" + t.integer "user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["page_type", "page_id"], name: "index_page_tags_on_page_type_and_page_id" + t.index ["user_id", "page_type"], name: "index_page_tags_on_user_id_and_page_type" + t.index ["user_id"], name: "index_page_tags_on_user_id" + end + create_table "past_ownerships", force: :cascade do |t| t.integer "user_id" t.integer "item_id" @@ -2374,11 +2388,13 @@ ActiveRecord::Schema.define(version: 2019_01_09_201055) do t.string "age" t.string "gender" t.string "interests" + t.string "slug" t.index ["deleted_at", "username"], name: "index_users_on_deleted_at_and_username" t.index ["deleted_at"], name: "index_users_on_deleted_at" t.index ["email"], name: "index_users_on_email", unique: true t.index ["id", "deleted_at"], name: "index_users_on_id_and_deleted_at" t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + t.index ["slug"], name: "index_users_on_slug", unique: true t.index ["username"], name: "index_users_on_username", unique: true end diff --git a/test/fixtures/page_tags.yml b/test/fixtures/page_tags.yml new file mode 100644 index 00000000..951895e4 --- /dev/null +++ b/test/fixtures/page_tags.yml @@ -0,0 +1,15 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + page: one + page_type: Page + tag: MyString + color: MyString + user: one + +two: + page: two + page_type: Page + tag: MyString + color: MyString + user: two diff --git a/test/models/page_tag_test.rb b/test/models/page_tag_test.rb new file mode 100644 index 00000000..dae927c8 --- /dev/null +++ b/test/models/page_tag_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PageTagTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end