mirror of
https://github.com/indentlabs/notebook.git
synced 2025-10-26 11:19:22 +00:00
Merge pull request #326 from indentlabs/page-tags
Add taggable functionality to content pages
This commit is contained in:
commit
e5592e5dff
@ -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);
|
||||
|
||||
8
app/assets/javascripts/page_tags.js
Normal file
8
app/assets/javascripts/page_tags.js
Normal file
@ -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;
|
||||
});
|
||||
});
|
||||
20
app/assets/stylesheets/page_tags.scss
Normal file
20
app/assets/stylesheets/page_tags.scss
Normal file
@ -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;
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
9
app/models/concerns/has_page_tags.rb
Normal file
9
app/models/concerns/has_page_tags.rb
Normal file
@ -0,0 +1,9 @@
|
||||
require 'active_support/concern'
|
||||
|
||||
module HasPageTags
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_many :page_tags, as: :page
|
||||
end
|
||||
end
|
||||
14
app/models/concerns/is_content_page.rb
Normal file
14
app/models/concerns/is_content_page.rb
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -9,10 +9,7 @@ class Country < ApplicationRecord
|
||||
include BelongsToUniverse
|
||||
|
||||
include HasAttributes
|
||||
include HasPrivacy
|
||||
include HasContentGroupers
|
||||
include HasImageUploads
|
||||
include HasChangelog
|
||||
include IsContentPage
|
||||
|
||||
include Serendipitous::Concern
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -8,11 +8,7 @@ class Flora < ApplicationRecord
|
||||
|
||||
include BelongsToUniverse
|
||||
|
||||
include HasAttributes
|
||||
include HasPrivacy
|
||||
include HasContentGroupers
|
||||
include HasImageUploads
|
||||
include HasChangelog
|
||||
include IsContentPage
|
||||
|
||||
include Serendipitous::Concern
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -8,11 +8,7 @@ class Group < ApplicationRecord
|
||||
|
||||
include BelongsToUniverse
|
||||
|
||||
include HasAttributes
|
||||
include HasPrivacy
|
||||
include HasContentGroupers
|
||||
include HasImageUploads
|
||||
include HasChangelog
|
||||
include IsContentPage
|
||||
|
||||
include Serendipitous::Concern
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -9,10 +9,7 @@ class Language < ApplicationRecord
|
||||
include BelongsToUniverse
|
||||
|
||||
include HasAttributes
|
||||
include HasPrivacy
|
||||
include HasContentGroupers
|
||||
include HasImageUploads
|
||||
include HasChangelog
|
||||
include IsContentPage
|
||||
|
||||
include Serendipitous::Concern
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -8,10 +8,7 @@
|
||||
class Universe < ApplicationRecord
|
||||
acts_as_paranoid
|
||||
|
||||
include HasAttributes
|
||||
include HasPrivacy
|
||||
include HasImageUploads
|
||||
include HasChangelog
|
||||
include IsContentPage
|
||||
|
||||
include Serendipitous::Concern
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
4
app/models/page_tag.rb
Normal file
4
app/models/page_tag.rb
Normal file
@ -0,0 +1,4 @@
|
||||
class PageTag < ApplicationRecord
|
||||
belongs_to :page, polymorphic: true
|
||||
belongs_to :user
|
||||
end
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
60
app/services/page_tag_service.rb
Normal file
60
app/services/page_tag_service.rb
Normal file
@ -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
|
||||
@ -103,7 +103,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<% if attribute_field.name_field? || attribute_field.universe_field? %>
|
||||
<% if attribute_field.name_field? || attribute_field.universe_field? || attribute_field.tags_field? %>
|
||||
<div>
|
||||
This field cannot be deleted.
|
||||
</div>
|
||||
|
||||
@ -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 %>
|
||||
</div>
|
||||
|
||||
<% elsif serialized_field[:type] == 'tags' %>
|
||||
<div class="tags-container">
|
||||
<% 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
|
||||
%>
|
||||
<span class="new badge <%= @content.class.color %> left" data-badge-caption="<%= tag %>"></span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="new badge <%= @content.class.color %> left" data-badge-caption="<%= tag %>"></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% else # serialized_field[:type] == text %>
|
||||
<div class="col s9 m9 l9 markdownable">
|
||||
<%=
|
||||
|
||||
@ -26,6 +26,62 @@
|
||||
relation: through_class
|
||||
%>
|
||||
|
||||
<% elsif field[:type] == 'tags' %>
|
||||
|
||||
<div class="content-field">
|
||||
<div class="input-field">
|
||||
<small><%= f.label field[:id], field[:label] %></small>
|
||||
<div class="chips chips-autocomplete chips-initial"></div>
|
||||
<%= f.hidden_field :page_tags, value: content.page_tags.join(',,,|||,,,'), id: 'hidden_page_tags_value' %>
|
||||
|
||||
<div class="help-text show-when-focused">
|
||||
<i class="material-icons tiny">label</i>
|
||||
Type and press enter to create a new tag, or click any of the suggested tags below to add it.
|
||||
</div>
|
||||
<div class="tags-container show-when-focused">
|
||||
<% @suggested_page_tags.each do |tag| %>
|
||||
<%=
|
||||
link_to '#', class: 'js-add-tag' do
|
||||
%>
|
||||
<span class="new badge grey left hoverable" data-badge-caption="<%= tag %>"></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<%= 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' %>
|
||||
<div class="content-field">
|
||||
<div class="input-field">
|
||||
|
||||
@ -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? %>
|
||||
<div class="tags-container">
|
||||
<span class="left grey-text">View by tag: </span>
|
||||
<%= link_to polymorphic_path(@content_type_class) do %>
|
||||
<span class="new badge <%= params.key?(:slug) ? 'grey' : @content_type_class.color %> left" data-badge-caption="All <%= content_type.pluralize %>"></span>
|
||||
<% end %>
|
||||
<% @page_tags.each do |tag| %>
|
||||
<%=
|
||||
link_to send(
|
||||
"page_tag_#{content_type.pluralize}_path",
|
||||
slug: PageTagService.slug_for(tag.tag)
|
||||
) do
|
||||
%>
|
||||
<span class="new badge <%= params[:slug] == tag.slug ? @content_type_class.color : 'grey' %> left" data-badge-caption="<%= tag.tag %>"></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
<% end %>
|
||||
|
||||
<% if @content.any? %>
|
||||
|
||||
<%= render partial: 'content/components/list_filter_bar', locals: { } %>
|
||||
<div class="card">
|
||||
<%= render partial: 'content/list/list', locals: { content_list: @content, content_type: @content_type_class, show_add_another_form: true } %>
|
||||
|
||||
@ -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."></span>
|
||||
<% end %>
|
||||
</span>
|
||||
<p class='grey-text'>
|
||||
<p class="tags-container">
|
||||
<% 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
|
||||
%>
|
||||
<span class="new badge <%= params[:slug] == tag.slug ? @content_type_class.color : 'grey' %> left" data-badge-caption="<%= tag.tag %>"></span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="new badge <%= params[:slug] == tag.slug ? @content_type_class.color : 'grey' %> left" data-badge-caption="<%= tag.tag %>"></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</p>
|
||||
<p class='grey-text' style="clear: both">
|
||||
<% if user_signed_in? %>
|
||||
<span class="timestamp tooltipped" data-position="bottom" data-delay="500" data-tooltip="<%= content.updated_at.strftime("%m/%d/%Y %H:%M") %>" style="font-size: 80%">
|
||||
<i class="material-icons">mode_edit</i>
|
||||
@ -71,7 +87,7 @@
|
||||
<% end %>
|
||||
</p>
|
||||
<span class="secondary-content hide-on-med-and-up">
|
||||
<% 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 %>
|
||||
<i class="material-icons">edit</i>
|
||||
|
||||
@ -31,12 +31,12 @@
|
||||
<%= render partial: 'content/keyboard_controls_help_modal' %>
|
||||
|
||||
<script type="text/javascript">
|
||||
<%= yield :javascript %>
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.tooltipped').tooltip({ enterDelay: 50 });
|
||||
M.AutoInit();
|
||||
$('.dropdown-trigger').dropdown({coverTrigger: false});
|
||||
|
||||
<%= yield :javascript %>
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:looks:
|
||||
:label: Looks
|
||||
:icon: face
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:looks:
|
||||
:label: Looks
|
||||
:icon: pets
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:appearance:
|
||||
:label: Appearance
|
||||
:icon: accessibility
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:classification:
|
||||
:label: Classification
|
||||
:icon: bubble_chart
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:structure:
|
||||
:label: Structure
|
||||
:icon: view_list
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:hierarchy:
|
||||
:label: Hierarchy
|
||||
:icon: call_split
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:looks:
|
||||
:label: Looks
|
||||
:icon: redeem
|
||||
|
||||
@ -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
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:location:
|
||||
:label: Whereabouts
|
||||
:icon: location_on
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:info:
|
||||
:label: Info
|
||||
:icon: forum
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:culture:
|
||||
:label: Culture
|
||||
:icon: face
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:appearance:
|
||||
:label: Appearance
|
||||
:icon: flash_on
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:geography:
|
||||
:label: Geography
|
||||
:icon: layers
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:looks:
|
||||
:label: Looks
|
||||
:icon: face
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:history:
|
||||
:label: History
|
||||
:icon: date_range
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:looks:
|
||||
:label: members
|
||||
:icon: face
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
- :name: universe_id
|
||||
:label: Universe
|
||||
:field_type: universe
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:production:
|
||||
:label: Production
|
||||
:icon: build
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
- :name: countries
|
||||
:label: Country
|
||||
:field_type: link
|
||||
- :name:
|
||||
:label: Tags
|
||||
:field_type: tags
|
||||
:populace:
|
||||
:label: Populace
|
||||
:icon: group
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
13
db/migrate/20190212220053_create_page_tags.rb
Normal file
13
db/migrate/20190212220053_create_page_tags.rb
Normal file
@ -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
|
||||
5
db/migrate/20190216080611_add_index_to_page_types.rb
Normal file
5
db/migrate/20190216080611_add_index_to_page_types.rb
Normal file
@ -0,0 +1,5 @@
|
||||
class AddIndexToPageTypes < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_index(:page_tags, [:user_id, :page_type])
|
||||
end
|
||||
end
|
||||
18
db/schema.rb
18
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
|
||||
|
||||
|
||||
15
test/fixtures/page_tags.yml
vendored
Normal file
15
test/fixtures/page_tags.yml
vendored
Normal file
@ -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
|
||||
7
test/models/page_tag_test.rb
Normal file
7
test/models/page_tag_test.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class PageTagTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user