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 user_signed_in? %>