Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revisions and fixing based on first round of testing

Signed-off-by: shalott <shalott@gmail.com>
  • Loading branch information...
commit 0a8694525236b5b45f300b993507bee72ed86d9f 1 parent 4e6023a
@shalott shalott authored
Showing with 1,503 additions and 897 deletions.
  1. +6 −0 app/controllers/application_controller.rb
  2. +0 −5 app/controllers/challenge_assignments_controller.rb
  3. +2 −8 app/controllers/challenge_claims_controller.rb
  4. +13 −13 app/controllers/challenge_signups_controller.rb
  5. +2 −8 app/controllers/collection_items_controller.rb
  6. +2 −8 app/controllers/collection_participants_controller.rb
  7. +3 −3 app/controllers/collections_controller.rb
  8. +40 −30 app/controllers/owned_tag_sets_controller.rb
  9. +0 −6 app/controllers/potential_matches_controller.rb
  10. +8 −6 app/controllers/prompts_controller.rb
  11. +1 −1  app/controllers/skins_controller.rb
  12. +15 −0 app/controllers/tag_nominations_controller.rb
  13. +105 −46 app/controllers/tag_set_nominations_controller.rb
  14. +18 −8 app/helpers/application_helper.rb
  15. +2 −2 app/helpers/tag_sets_helper.rb
  16. +10 −6 app/helpers/validation_helper.rb
  17. +9 −1 app/models/challenge/gift_exchange.rb
  18. +1 −1  app/models/challenge/prompt_meme.rb
  19. +1 −0  app/models/chapter.rb
  20. +3 −1 app/models/character_nomination.rb
  21. +8 −4 app/models/external_author_name.rb
  22. +11 −0 app/models/fandom_nomination.rb
  23. +49 −8 app/models/owned_tag_set.rb
  24. +18 −9 app/models/prompt.rb
  25. +3 −1 app/models/relationship_nomination.rb
  26. +26 −7 app/models/story_parser.rb
  27. +39 −8 app/models/tag.rb
  28. +32 −11 app/models/tag_nomination.rb
  29. +21 −21 app/models/tag_set.rb
  30. +28 −0 app/models/tag_set_association.rb
  31. +1 −4 app/views/challenge/gift_exchange/_gift_exchange_form.html.erb
  32. +5 −7 app/views/challenge/prompt_meme/_prompt_meme_form.html.erb
  33. +1 −6 app/views/challenge_signups/_signup_form.html.erb
  34. +1 −1  app/views/challenge_signups/_signup_form_general_information.html.erb
  35. +21 −21 app/views/collection_participants/index.html.erb
  36. +2 −13 app/views/collections/_form.html.erb
  37. +9 −18 app/views/owned_tag_sets/_internal_tag_set_fields.html.erb
  38. +47 −0 app/views/owned_tag_sets/_show_fandoms_by_media.html.erb
  39. +3 −3 app/views/owned_tag_sets/_show_tag_set_associations.html.erb
  40. +67 −66 app/views/owned_tag_sets/_show_tag_set_tags.html.erb
  41. +46 −0 app/views/owned_tag_sets/_show_tags_by_alpha.html.erb
  42. +7 −0 app/views/owned_tag_sets/_show_tags_in_single_list.html.erb
  43. +9 −5 app/views/owned_tag_sets/_tag_set_association_fields.html.erb
  44. +2 −11 app/views/owned_tag_sets/_tag_set_associations_remove.html.erb
  45. +30 −16 app/views/owned_tag_sets/_tag_set_form.html.erb
  46. +5 −5 app/views/owned_tag_sets/_tag_set_form_management.html.erb
  47. +3 −8 app/views/owned_tag_sets/batch_load.html.erb
  48. +1 −6 app/views/owned_tag_sets/review_associations.html.erb
  49. +14 −12 app/views/prompts/_prompt_form.html.erb
  50. +6 −6 app/views/prompts/_prompt_form_tag_options.html.erb
  51. +3 −8 app/views/prompts/edit.html.erb
  52. +3 −8 app/views/prompts/new.html.erb
  53. +1 −1  app/views/prompts/show.html.erb
  54. +3 −7 app/views/tag_set_nominations/_nomination_form.html.erb
  55. +55 −47 app/views/tag_set_nominations/_review.html.erb
  56. +43 −30 app/views/tag_set_nominations/_review_individual_nom.html.erb
  57. +9 −0 app/views/tag_set_nominations/_review_thead.html.erb
  58. +4 −2 app/views/tag_set_nominations/_tag_nominations.html.erb
  59. +3 −3 app/views/tag_set_nominations/_tag_nominations_by_fandom.html.erb
  60. +10 −6 app/views/tag_set_nominations/show.html.erb
  61. +1 −1  app/views/user_mailer/invitation_to_claim.html.erb
  62. +2 −2 app/views/users/_legal.html.erb
  63. +5 −8 app/views/users/_passwd.html.erb
  64. +5 −3 app/views/users/new.html.erb
  65. +1 −0  config/routes.rb
  66. +0 −12 features/autocomplete.feature
  67. +14 −15 features/challenge_giftexchange.feature
  68. +16 −30 features/challenge_promptmeme.feature
  69. +1 −0  features/challenge_promptmeme_posting_fills.feature
  70. +31 −32 features/challenge_promptmeme_springkink.feature
  71. +7 −44 features/challenge_promptmeme_unlimited.feature
  72. +16 −17 features/challenge_yuletide.feature
  73. +8 −8 features/collection_anonymity.feature
  74. +6 −6 features/collection_create.feature
  75. +1 −1  features/collection_navigation.feature
  76. +1 −1  features/collection_static.feature
  77. +2 −2 features/pseud_delete.feature
  78. +14 −14 features/skin.feature
  79. +69 −82 features/step_definitions/challenge_steps.rb
  80. +12 −8 features/step_definitions/collection_steps.rb
  81. +46 −9 features/step_definitions/generic_steps.rb
  82. +2 −2 features/step_definitions/skin_steps.rb
  83. +20 −12 features/step_definitions/tag_set_steps.rb
  84. +10 −0 features/step_definitions/web_steps.rb
  85. +7 −1 features/support/paths.rb
  86. +31 −4 features/tag_set.feature
  87. +1 −1  features/work_create.feature
  88. +2 −2 features/work_related.feature
  89. +9 −0 lib/challenge_core.rb
  90. +205 −0 lib/tasks/mass_import.rake
  91. +9 −0 public/help/tagset-batch-load.html
  92. +9 −6 public/javascripts/application.js
  93. +4 −2 public/javascripts/best_in_place.js
  94. +5 −5 public/stylesheets/archive_core.css
  95. +28 −19 public/stylesheets/forms.css
  96. +3 −0  public/stylesheets/ie6_overrides.css
  97. +10 −6 public/stylesheets/site-chrome.css
View
6 app/controllers/application_controller.rb
@@ -168,6 +168,12 @@ def collection_owners_only
logged_in? && @collection && @collection.user_is_owner?(current_user) || access_denied
end
+ def not_allowed(fallback=nil)
+ flash[:error] = ts("Sorry, you're not allowed to do that.")
+ redirect_to (fallback || root_path) rescue redirect_to '/'
+ end
+
+
@over_anon_threshold = true if @over_anon_threshold.nil?
def get_page_title(fandom, author, title, options = {})
View
5 app/controllers/challenge_assignments_controller.rb
@@ -98,11 +98,6 @@ def allowed_to_destroy
@challenge_assignment.user_allowed_to_destroy?(current_user) || not_allowed
end
- def not_allowed
- flash[:error] = t('challenge_signups.not_allowed', :default => "Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
- end
# ACTIONS
View
10 app/controllers/challenge_claims_controller.rb
@@ -61,15 +61,9 @@ def owner_only
end
def allowed_to_destroy
- @challenge_claim.user_allowed_to_destroy?(current_user) || not_allowed
+ @challenge_claim.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
end
-
- def not_allowed
- flash[:error] = ts("Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
- end
-
+
# ACTIONS
View
26 app/controllers/challenge_signups_controller.rb
@@ -39,7 +39,7 @@ def signup_owner_only
end
def maintainer_or_signup_owner_only
- not_allowed and return unless (@challenge_signup.pseud.user == current_user || @collection.user_is_maintainer?(current_user))
+ not_allowed(@collection) and return unless (@challenge_signup.pseud.user == current_user || @collection.user_is_maintainer?(current_user))
end
def not_signup_owner
@@ -49,13 +49,7 @@ def not_signup_owner
end
def allowed_to_destroy
- @challenge_signup.user_allowed_to_destroy?(current_user) || not_allowed
- end
-
- def not_allowed
- flash[:error] = ts("Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
+ @challenge_signup.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
end
def load_signup_from_id
@@ -95,7 +89,7 @@ def index
elsif params[:user_id] && (@user = User.find_by_login(params[:user_id]))
@challenge_signups = @collection.signups.by_user(current_user)
else
- not_allowed
+ not_allowed(@collection)
end
}
format.csv {
@@ -139,19 +133,25 @@ def show
protected
def build_prompts
- @challenge.class::PROMPT_TYPES.each do |prompt_type|
- num_to_build = params["num_#{prompt_type}"].to_i || @challenge.required(prompt_type)
+ notice = ""
+ @challenge.class::PROMPT_TYPES.each do |prompt_type|
+ num_to_build = params["num_#{prompt_type}"] ? params["num_#{prompt_type}"].to_i : @challenge.required(prompt_type)
if num_to_build < @challenge.required(prompt_type)
- flash[:notice] = ts("You must submit at least %{required} #{prompt_type}.", :required => @challenge.required(prompt_type))
+ notice += ts("You must submit at least %{required} #{prompt_type}. ", :required => @challenge.required(prompt_type))
num_to_build = @challenge.required(prompt_type)
elsif num_to_build > @challenge.allowed(prompt_type)
- flash[:notice] = ts("You can only submit up to %{allowed} #{prompt_type}.", :allowed => @challenge.allowed(prompt_type))
+ notice += ts("You can only submit up to %{allowed} #{prompt_type}. ", :allowed => @challenge.allowed(prompt_type))
num_to_build = @challenge.allowed(prompt_type)
+ elsif params["num_#{prompt_type}"]
+ notice += ts("Set up %{num} #{prompt_type.pluralize}. ", :num => num_to_build)
end
num_to_build.times do |i|
prompt = @challenge_signup.send(prompt_type)[i] || @challenge_signup.send(prompt_type).build
end
end
+ unless notice.blank?
+ flash[:notice] = notice
+ end
end
public
View
10 app/controllers/collection_items_controller.rb
@@ -6,25 +6,19 @@ class CollectionItemsController < ApplicationController
cache_sweeper :collection_sweeper
- def not_allowed
- flash[:error] = t('collection_items.not_allowed', :default => "Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
- end
-
def load_item_and_collection
if params[:collection_item]
@collection_item = CollectionItem.find(params[:collection_item][:id])
else
@collection_item = CollectionItem.find(params[:id])
end
- not_allowed and return unless @collection_item
+ not_allowed(@collection) and return unless @collection_item
@collection = @collection_item.collection
end
def allowed_to_destroy
- @collection_item.user_allowed_to_destroy?(current_user) || not_allowed
+ @collection_item.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
end
def index
View
10 app/controllers/collection_participants_controller.rb
@@ -15,12 +15,6 @@ def owners_required
false
end
- def not_allowed
- flash[:error] = t('collection_participants.not_allowed', :default => "Sorry, you're not allowed to do that.")
- redirect_to collection_participants_path(@collection)
- false
- end
-
def no_participant
flash[:error] = t('no_participant', :default => "Which participant did you want to work with?")
redirect_to root_path
@@ -38,11 +32,11 @@ def load_participant_and_collection
end
def allowed_to_promote
- @participant.user_allowed_to_promote?(current_user, @new_role) || not_allowed
+ @participant.user_allowed_to_promote?(current_user, @new_role) || not_allowed(@collection)
end
def allowed_to_destroy
- @participant.user_allowed_to_destroy?(current_user) || not_allowed
+ @participant.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
end
def has_other_owners
View
6 app/controllers/collections_controller.rb
@@ -20,11 +20,11 @@ def index
@collections = @user.owned_collections.by_title.paginate(:page => params[:page])
else
if params[:user_id]
- flash[:error].now = ts("We couldn't find a user by that name, sorry.")
+ flash.now[:error] = ts("We couldn't find a user by that name, sorry.")
elsif params[:collection_id]
- flash[:error].now = ts("We couldn't find a collection by that name.")
+ flash.now[:error] = ts("We couldn't find a collection by that name.")
elsif params[:work_id]
- flash[:error].now = ts("We couldn't find that work.")
+ flash.now[:error] = ts("We couldn't find that work.")
end
@sort_and_filter = true
params[:collection_filters] ||= {}
View
70 app/controllers/owned_tag_sets_controller.rb
@@ -3,7 +3,7 @@ class OwnedTagSetsController < ApplicationController
before_filter :load_tag_set, :except => [ :index, :new, :create ]
before_filter :users_only, :only => [ :new, :create, :nominate ]
- before_filter :moderators_only, :except => [ :index, :new, :create ]
+ before_filter :moderators_only, :except => [ :index, :new, :create, :show ]
before_filter :owners_only, :only => [ :destroy ]
def load_tag_set
@@ -51,31 +51,39 @@ def index
end
def show
- unless @tag_set.visible || @tag_set.user_is_moderator?(current_user)
- flash[:error] = ts("That tag set is not available for public viewing.")
- redirect_to tag_sets_path and return
- end
- #
- # if params[:tag_type] && TagSet::TAG_TYPES.include?(params[:tag_type])
- # @topmost_tag_type = params[:tag_type]
- # else
- # @topmost_tag_type = @tag_set.tag_set.topmost_tag_type
- # end
- #
- # # Get all the tags of the topmost type with any children in the set, and the associated tags of this set
- # @topmost_tags = @tag_set.tag_set.tags.where(:type => @topmost_tag_type.classify).value_of :id, :name
- # topmost_ids = @topmost_tags.collect {|tt| tt.first}
- # child_ids = @tag_set.tag_set_associations.where(:parent_tag_id => topmost_ids).value_of :tag_id
- #
+ if @tag_set.visible || @tag_set.user_is_moderator?(current_user)
+ #
+ # if params[:tag_type] && TagSet::TAG_TYPES.include?(params[:tag_type])
+ # @topmost_tag_type = params[:tag_type]
+ # else
+ # @topmost_tag_type = @tag_set.tag_set.topmost_tag_type
+ # end
+ #
+ # # Get all the tags of the topmost type with any children in the set, and the associated tags of this set
+ # @topmost_tags = @tag_set.tag_set.tags.where(:type => @topmost_tag_type.classify).value_of :id, :name
+ # topmost_ids = @topmost_tags.collect {|tt| tt.first}
+ # child_ids = @tag_set.tag_set_associations.where(:parent_tag_id => topmost_ids).value_of :tag_id
+ #
+
+ # @associations = @tag_set.tag_set_associations
+ if @tag_set.tag_set.has_type?("fandom")
+ @fandom_hash = Tag.names_by_parent(Fandom.in_tag_set(@tag_set.tag_set), "media")
+ end
+
+ if @tag_set.tag_set.has_type?("character")
+ @character_hash = TagSetAssociation.names_by_parent(TagSetAssociation.for_tag_set(@tag_set), "character")
+ canonical_hash = Tag.names_by_parent(Character.in_tag_set(@tag_set.tag_set), "fandom")
+ # merge the values of the two hashes (each value is an array) as a set (ie remove duplicates)
+ @character_hash.merge!(canonical_hash) {|key, oldval, newval| (oldval | newval) }
+ end
+
+ if @tag_set.tag_set.has_type?("relationship")
+ @relationship_hash = TagSetAssociation.names_by_parent(TagSetAssociation.for_tag_set(@tag_set), "relationship")
+ canonical_hash = Tag.names_by_parent(Relationship.in_tag_set(@tag_set.tag_set), "fandom")
+ @relationship_hash.merge!(canonical_hash) {|key, oldval, newval| (oldval | newval) }
+ end
- if params[:tag_type] && TagSet::TAG_TYPES.include?(params[:tag_type])
- @tag_type = params[:tag_type]
- @tags = @tag_set.tag_set.with_type(@tag_type)
- else
- @tags = @tag_set.tag_set.tags
- @associations = @tag_set.tag_set_associations
end
-
end
def new
@@ -132,16 +140,18 @@ def batch_load
def do_batch_load
if params[:batch_associations]
- rejected = @tag_set.load_batch_associations!(params[:batch_associations], :do_relationships => (params[:batch_do_relationship] ? true : false))
- if rejected.blank?
- flash[:notice] = ts("Batch associations loaded!")
+ failed = @tag_set.load_batch_associations!(params[:batch_associations], :do_relationships => (params[:batch_do_relationship] ? true : false))
+ if failed.empty?
+ flash[:notice] = ts("Tags and associations loaded!")
+ redirect_to tag_set_path(@tag_set) and return
else
- flash[:notice] = ts("Not all associations could be loaded. Please check over the results.")
+ flash.now[:notice] = ts("We couldn't add all the tags and associations you wanted -- the ones left below didn't work. See the help for suggestions!")
+ @failed_batch_associations = failed.join("\n")
+ render :action => :batch_load and return
end
- redirect_to tag_set_path(@tag_set) and return
else
flash[:error] = ts("What did you want to load?")
- redirect_to :action => :batch_load_associations and return
+ redirect_to :action => :batch_load and return
end
end
View
6 app/controllers/potential_matches_controller.rb
@@ -41,12 +41,6 @@ def signup_open
false
end
- def not_allowed
- flash[:error] = t('potential_match.not_allowed', :default => "Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
- end
-
def check_assignments_not_sent
assignments_sent and return unless @challenge.assignments_sent_at.nil?
end
View
14 app/controllers/prompts_controller.rb
@@ -10,6 +10,7 @@ class PromptsController < ApplicationController
before_filter :signup_owner_only, :only => [:edit, :update]
before_filter :maintainer_or_signup_owner_only, :only => [:show]
before_filter :check_signup_open, :only => [:new, :create, :edit, :update]
+ before_filter :allowed_to_see, :only => [:show]
# def promptmeme_only
# unless @collection.challenge_type == "PromptMeme"
@@ -55,7 +56,7 @@ def signup_owner_only
end
def maintainer_or_signup_owner_only
- not_allowed and return unless (@challenge_signup.pseud.user == current_user || @collection.user_is_maintainer?(current_user))
+ not_allowed(@collection) and return unless (@challenge_signup.pseud.user == current_user || @collection.user_is_maintainer?(current_user))
end
def not_signup_owner
@@ -65,13 +66,11 @@ def not_signup_owner
end
def allowed_to_destroy
- @challenge_signup.user_allowed_to_destroy?(current_user) || not_allowed
+ @challenge_signup.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
end
- def not_allowed
- flash[:error] = ts("Sorry, you're not allowed to do that.")
- redirect_to collection_path(@collection) rescue redirect_to '/'
- false
+ def allowed_to_see
+ @challenge.user_allowed_to_see_prompt?(current_user, @prompt) || not_allowed(@collection)
end
def load_prompt_from_id
@@ -98,13 +97,16 @@ def show
def new
if params[:prompt_type] == "offer"
+ @index = @challenge_signup.offers.count
@prompt = @challenge_signup.offers.build
else
+ @index = @challenge_signup.requests.count
@prompt = @challenge_signup.requests.build
end
end
def edit
+ @index = @challenge_signup.send(@prompt.class.name.downcase.pluralize).index(@prompt)
end
def create
View
2  app/controllers/skins_controller.rb
@@ -56,7 +56,7 @@ def create
@skin.author = current_user
if @skin.save
redirect_to @skin
- flash[:notice] = "Skin was created successfully"
+ flash[:notice] = "Skin was successfully created"
else
if params[:wizard]
render :new_wizard
View
15 app/controllers/tag_nominations_controller.rb
@@ -0,0 +1,15 @@
+class TagNominationsController < ApplicationController
+
+ # This gets called from the edit-in-place code for the tag set nominations review page
+ def update
+ @tag_nomination = TagNomination.find(params[:id])
+ respond_to do |format|
+ if @tag_nomination && @tag_nomination.owned_tag_set.user_is_moderator?(current_user) && @tag_nomination.update_attributes(params[:tag_nomination])
+ format.json {head :ok}
+ else
+ format.json { render :json => [ts("That didn't work.")], :status => :unprocessable_entity}
+ end
+ end
+ end
+
+end
View
151 app/controllers/tag_set_nominations_controller.rb
@@ -130,16 +130,8 @@ def destroy
# set up various variables for reviewing nominations
def setup_for_review
set_limit
- nom_limit = 50
- if @limit[:fandom] > 0
- # char and rel tags under fandom noms
- @tag_types = %w(fandom freeform).select {|type| @limit[type] > 0}
- if @limit[:character] > 0 || @limit[:relationship] > 0
- nom_limit = 20
- end
- else
- @tag_types = TagSet::TAG_TYPES_INITIALIZABLE.select {|type| @limit[type] > 0}
- end
+ nom_limit = 30
+ @tag_types = TagSet::TAG_TYPES_INITIALIZABLE.select {|type| @limit[type] > 0}
@nominations = HashWithIndifferentAccess.new
@tag_types.each do |tag_type|
@@ -150,58 +142,125 @@ def setup_for_review
@nominations[tag_type][:nonexistent] = noms.where(:exists => false)
end
end
+
+ def destroy_multiple
+ unless @tag_set.user_is_owner?(current_user)
+ flash[:error] = ts("You don't have permission to do that.")
+ redirect_to tag_set_path(@tag_set) and return
+ end
+ @tag_set.clear_nominations!
+ flash[:notice] = ts("All nominations for this tag set have been cleared.")
+ redirect_to tag_set_path(@tag_set)
+ end
# update_multiple gets called from the index/review form.
- # we get params like "approve_My Awesome Tag" and "reject_My Lousy Tag" for any tag nominations which were
- # marked to be rejected
+ # we expect params like "character_approve_My Awesome Tag" and "fandom_reject_My Lousy Tag"
def update_multiple
unless @tag_set.user_is_moderator?(current_user)
flash[:error] = ts("You don't have permission to do that.")
redirect_to tag_set_path(@tag_set) and return
end
- setup_for_review
+
+ @errors = []
+
+ # We start by just sorting out the data the mod has sent us
+ @approve = HashWithIndifferentAccess.new
+ @synonym = HashWithIndifferentAccess.new
+ @reject = HashWithIndifferentAccess.new
+ @change = HashWithIndifferentAccess.new
+ TagSet::TAG_TYPES.each do |tag_type|
+ @approve[tag_type] = []
+ @synonym[tag_type] = []
+ @reject[tag_type] = []
+ @change[tag_type] = []
+ end
- @tagnames_to_approve = []
- @tagnames_to_reject = []
- params.each_pair do |key,val|
- if val && key.match(/^(approve|synonym)_(.*)$/)
- @tagnames_to_approve << $2
- elsif val && key.match(/^reject_(.*)$/)
- @tagnames_to_reject << $1
+ params.each_pair do |key, val|
+ next unless val.present?
+ if key.match(/^([a-z]+)_(approve|reject|synonym|change)_(.*)$/)
+ type = $1
+ action = $2
+ name = $3
+ if TagSet::TAG_TYPES.include?(type)
+ # we're safe
+ case action
+ when "reject"
+ @reject[type] << name
+ when "synonym"
+ @synonym[type] << name
+ when "approve"
+ @approve[type] << name unless params["#{type}_change_#{name}"] != name
+ when "change"
+ next if val == name
+ # this is the tricky one: make sure we can do this name change
+ tagnom = TagNomination.for_tag_set(@tag_set).where(:type => "#{type.classify}Nomination", :tagname => name).first
+ if !tagnom
+ @errors << ts("Couldn't find a #{type} nomination for #{name}")
+ elsif !tagnom.change_tagname?(val)
+ @errors << ts("Invalid name change for #{name} to #{val}: %{msg}", :msg => tagnom.errors.full_messages.join(', '))
+ else
+ @change[type] << [name, val]
+ end
+ end
+ end
end
end
- unless (intersect = (@tagnames_to_approve & @tagnames_to_reject)).empty?
- flash[:error] = ts("You have both approved and rejected the following tags: %{intersect}", :intersect => intersect.join(", "))
- render :action => "index" and return
+ TagSet::TAG_TYPES.each do |tag_type|
+ unless (intersect = @approve[tag_type] & @reject[tag_type]).empty?
+ @errors << ts("You have both approved and rejected the following %{type} tags: %{intersect}", :type => tag_type, :intersect => intersect.join(", "))
+ end
end
- @tag_set.tag_set.send("#{@tag_type}_tagnames_to_add=", @tagnames_to_approve.join(","))
- @tag_set.tag_set.tagnames_to_remove = @tagnames_to_reject.join(",")
-
- if @tag_set.save &&
- TagNomination.where("tagname IN (?)", @tagnames_to_approve).update_all(:approved => true, :rejected => false) &&
- TagNomination.where("tagname IN (?)", @tagnames_to_reject).update_all(:rejected => true, :approved => false)
- flash[:notice] = ts("Successfully approved: %{approved}", :approved => @tagnames_to_approve.join(', ')) + " " +
- ts("Successfully rejected: %{rejected}", :rejected => @tagnames_to_reject.join(', '))
- redirect_to tag_set_path(@tag_set) and return
- else
- flash[:error] = ts("We were unable to save your updates.")
+ # If we have errors don't move ahead
+ unless @errors.empty?
setup_for_review
- render :action => "index"
- end
- end
-
- def destroy_multiple
- unless @tag_set.user_is_owner?(current_user)
- flash[:error] = ts("You don't have permission to do that.")
- redirect_to tag_set_path(@tag_set) and return
+ render :action => "index" and return
end
- @tag_set.clear_nominations!
- flash[:notice] = ts("All nominations for this tag set have been cleared.")
- redirect_to tag_set_path(@tag_set)
+ # OK, now we're going ahead and making piles of db changes! eep! D:
+ TagSet::TAG_TYPES.each do |tag_type|
+ @tagnames_to_add = @approve[tag_type] + @synonym[tag_type]
+ @tagnames_to_remove = @reject[tag_type]
+
+ # do the name changes
+ @change[tag_type].each do |oldname, newname|
+ tagnom = TagNomination.for_tag_set(@tag_set).where(:type => "#{tag_type.classify}Nomination", :tagname => oldname).first
+ if tagnom && tagnom.change_tagname!(newname)
+ @tagnames_to_add << newname
+ @tagnames_to_remove << oldname
+ else
+ # ughhhh
+ @errors = tagnom.errors.full_messages
+ flash[:error] = ts("Oh no! We ran into a problem partway through saving your updates -- please check over your tag set closely!")
+ setup_for_review
+ render :action => "index" and return
+ end
+ end
+
+ # update the tag set
+ @tag_set.tag_set.send("#{tag_type}_tagnames_to_add=", @tagnames_to_add.join(","))
+ @tag_set.tag_set.tagnames_to_remove = @tagnames_to_remove.join(",")
+ unless @tag_set.save
+ # ughhhh
+ @errors = @tag_set.errors.full_messages
+ flash[:error] = ts("Oh no! We ran into a problem partway through saving your updates -- please check over your tag set closely!")
+ setup_for_review
+ render :action => "index" and return
+ end
+
+ # update the nominations -- approve any where an approved tag was either a synonym or the tag itself
+ TagNomination.for_tag_set(@tag_set).where(:type => "#{tag_type.classify}Nomination").where("tagname IN (?)", @tagnames_to_add).update_all(:approved => true, :rejected => false)
+ TagNomination.for_tag_set(@tag_set).where(:type => "#{tag_type.classify}Nomination").where("synonym IN (?)", @tagnames_to_add).update_all(:approved => true, :rejected => false)
+ TagNomination.for_tag_set(@tag_set).where(:type => "#{tag_type.classify}Nomination").where("tagname IN (?)", @tagnames_to_remove).update_all(:rejected => true, :approved => false)
+ @notice << '<li>'.html_safe + ts("Successfully added to set: %{approved}", :approved => @tagnames_to_add.join(', ')) + '</li>'.html_safe
+ @notice << '<li>'.html_safe + ts("Successfully rejected: %{rejected}", :rejected => @tagnames_to_remove.join(', ')) + '</li>'.html_safe
+ end
+
+ # If we got here we made it through, YAY
+ flash[:notice] = '<ul>' + @notice.join("\n").html_safe + '</ul>'.html_safe
+ redirect_to tag_set_nominations_path(@tag_set) and return
end
-
+
end
View
26 app/helpers/application_helper.rb
@@ -34,7 +34,7 @@ def link_to_rss(link_to_feed)
def allowed_html_instructions(show_list = true)
h(ts("Plain text with limited html")) +
link_to_help("html-help") + (show_list ?
- "<br /><code>a, abbr, acronym, address, [alt], [axis], b, big, blockquote, br, caption, center, cite, [class], code,
+ "<code>a, abbr, acronym, address, [alt], [axis], b, big, blockquote, br, caption, center, cite, [class], code,
col, colgroup, dd, del, dfn, div, dl, dt, em, h1, h2, h3, h4, h5, h6, [height], hr, [href], i, img,
ins, kbd, li, [name], ol, p, pre, q, s, samp, small, span, [src], strike, strong, sub, sup, table, tbody, td,
tfoot, th, thead, [title], tr, tt, u, ul, var, [width]</code>" : "").html_safe
@@ -263,10 +263,10 @@ def generate_countdown_html(field_id, max)
# See the jquery code in application.js
# Note that these start hidden because if javascript is not available, we
# don't want to show the user the buttons at all.
- def expand_contract_shuffle(list_id)
- ('<span class="navigation expand hidden" action_target="#' + list_id + '"><a href="#">[ + ]</a></span>
- <span class="navigation contract hidden" action_target="#' + list_id + '"><a href="#">[ - ]</a></span>
- <span class="navigation shuffle hidden" action_target="#' + list_id + '"><a href="#">[ &#8645; ]</a></span>').html_safe
+ def expand_contract_shuffle(list_id, shuffle=true)
+ ('<span class="action expand hidden" title="expand" action_target="#' + list_id + '"><a href="#">&#8595;</a></span>
+ <span class="action contract hidden" title="contract" action_target="#' + list_id + '"><a href="#">&#8593;</a></span>').html_safe +
+ (shuffle ? ('<span class="action shuffle hidden" title="shuffle" action_target="#' + list_id + '"><a href="#">&#8645;</a></span>') : '').html_safe
end
# returns the default autocomplete attributes, all of which can be overridden
@@ -293,9 +293,10 @@ def link_to_add_section(linktext, form, nested_model_name, partial_to_render, lo
link_to_function(linktext, "add_section(this, \"#{nested_model_name}\", \"#{escape_javascript(rendered_partial_to_add)}\")", :class => "hidden showme")
end
+ # This is only shown via javascript anyway
def link_to_remove_section(linktext, form, class_of_section_to_remove="removeme")
form.hidden_field(:_destroy) + "\n" +
- link_to_function(linktext, "remove_section(this, \"#{class_of_section_to_remove}\")", :class => "hidden showme")
+ link_to_function(linktext, "remove_section(this, \"#{class_of_section_to_remove}\")")
end
def time_in_zone(time, zone=nil, user=User.current_user)
@@ -350,7 +351,7 @@ def nested_field_id(form, nested_object, attribute)
end
def nested_field_name(form, nested_object, attribute)
- "#{form.object_name}[#{nested_object.class.name.underscore}_attributes][#{nested_object.id}][#{field_attribute(attribute)}]"
+ "#{form.object_name}[#{nested_object.class.table_name}_attributes][#{nested_object.id}][#{field_attribute(attribute)}]"
end
@@ -451,10 +452,19 @@ def checkbox_section_css_class(size)
end
def check_all_none
- '<ul class="navigation actions">
+ '<ul class="actions">
<li><a href="#" class="check_all">Check All</a></li>
<li><a href="#" class="check_none">Check None</a></li>
</ul>'.html_safe
end
+
+ def submit_button(form, button_text=nil)
+ button_text ||= form.object.new_record? ? ts("Submit") : ts("Update")
+ content_tag(:p, form.submit(button_text), :class=>"submit")
+ end
+
+ def submit_fieldset(form, button_text=nil)
+ content_tag(:fieldset, content_tag(:legend, ts("Actions")) + submit_button(form, button_text))
+ end
end # end of ApplicationHelper
View
4 app/helpers/tag_sets_helper.rb
@@ -47,9 +47,9 @@ def nomination_status(nomination=nil)
if nomination && nomination.approved
'<span class="symbol approved" tooltip="This nomination has been approved!"><span>&#x2714;</span></span>'.html_safe
elsif nomination && nomination.rejected
- '<span class="symbol rejected" tooltip="This nomination was rejected."><span>X</span></span>'.html_safe
+ '<span class="symbol rejected" tooltip="This nomination was rejected (but an alternate version may have been approved instead)."><span>&#x2718;</span></span>'.html_safe
else
- '<span class="symbol unreviewed" tooltip="This nomination has not been reviewed yet and can still be changed."><span>?</span></span>'.html_safe
+ '<span class="symbol unreviewed" tooltip="This nomination has not been reviewed yet and can still be changed."><span>&#x2753;</span></span>'.html_safe
end
end
View
16 app/helpers/validation_helper.rb
@@ -22,15 +22,19 @@ def error_messages_for(object)
end
if object && object.errors.any?
- error_messages = object.errors.full_messages.map {|msg| content_tag(:li, msg.gsub(/^(.+)\^/, '').html_safe)}.join("\n").html_safe
- message = '<div class="error" id="error">'.html_safe
- message += content_tag(:h2, h(ts("We couldn't save this %{objectname}, sorry!", :objectname => object.class.name.to_s.gsub(/_/, ' '))))
- message += content_tag(:p, h(ts("Here are the problems we found: ")))
- message += content_tag(:ul, error_messages)
- message += '</div>'.html_safe
+ errors = object.errors.full_messages
+ intro = content_tag(:h2, h(ts("We couldn't save this %{objectname}, sorry!", :objectname => object.class.name.to_s.gsub(/_/, ' '))))
+ intro += content_tag(:p, h(ts("Here are the problems we found: ")))
+ error_messages_formatted(errors, intro)
end
end
+ def error_messages_formatted(errors, intro = "")
+ return unless errors && !errors.empty?
+ error_messages = errors.map {|msg| content_tag(:li, msg.gsub(/^(.+)\^/, '').html_safe)}.join("\n").html_safe
+ content_tag(:div, intro.html_safe + content_tag(:ul, error_messages), :id =>"error", :class=>"error")
+ end
+
# use to make sure we have consistent name throughout
def live_validation_varname(id)
"validation_for_#{id}"
View
10 app/models/challenge/gift_exchange.rb
@@ -64,6 +64,11 @@ def copy_tag_set_from_offer_to_request
end
end
+ # override core
+ def allow_name_change?
+ false
+ end
+
def topmost_tag_type
self.request_restriction.topmost_tag_type
end
@@ -71,5 +76,8 @@ def topmost_tag_type
def user_allowed_to_see_requests_summary?(user)
self.collection.user_is_maintainer?(user) || self.requests_summary_visible?
end
-
+
+ def user_allowed_to_see_prompt?(user, prompt)
+ self.collection.user_is_maintainer?(user) || prompt.pseud.user == user
+ end
end
View
2  app/models/challenge/prompt_meme.rb
@@ -25,7 +25,7 @@ class PromptMeme < ActiveRecord::Base
PROMPT_TYPES.each do |type|
%w(required allowed).each do |setting|
prompt_limit_field = "#{type}_num_#{setting}"
- validates_numericality_of prompt_limit_field, :only_integer => true, :less_than_or_equal_to => ArchiveConfig.PROMPTS_MAX, :greater_than_or_equal_to => 0
+ validates_numericality_of prompt_limit_field, :only_integer => true, :less_than_or_equal_to => ArchiveConfig.PROMPT_MEME_PROMPTS_MAX, :greater_than_or_equal_to => 0
end
end
View
1  app/models/chapter.rb
@@ -7,6 +7,7 @@ class Chapter < ActiveRecord::Base
has_many :pseuds, :through => :creatorships
belongs_to :work
+ validates_presence_of :work
# acts_as_list :scope => 'work_id = #{work_id}'
acts_as_commentable
View
4 app/models/character_nomination.rb
@@ -16,7 +16,9 @@ def set_tag_set_nomination
end
def get_parent_tagname
- (self.parent_tagname.blank? ? self.parent_tagname : nil) || (self.fandom_nomination ? self.fandom_nomination.tagname : nil)
+ self.parent_tagname.blank? ? self.parent_tagname : (
+ self.fandom_nomination ? self.fandom_nomination.tagname :
+ Tag.find_by_name(self.tagname).try(:parents).try(:first).try(:name))
end
end
View
12 app/models/external_author_name.rb
@@ -10,17 +10,21 @@ class ExternalAuthorName < ActiveRecord::Base
validates_length_of :name,
:within => NAME_LENGTH_MIN..NAME_LENGTH_MAX,
- :too_short => t('name_too_short', :default => "is too short (minimum is %{min} characters)", :min => NAME_LENGTH_MIN),
- :too_long => t('name_too_long', :default => "is too long (maximum is %{max} characters)", :max => NAME_LENGTH_MAX)
+ :too_short => ts("is too short (minimum is %{min} characters)", :min => NAME_LENGTH_MIN),
+ :too_long => ts("is too long (maximum is %{max} characters)", :max => NAME_LENGTH_MAX)
validates_uniqueness_of :name, :scope => :external_author_id, :case_sensitive => false
validates_format_of :name,
- :message => t('name_invalid_characters', :default => 'can contain letters, numbers, spaces, underscores, @-signs, dots, and dashes.'),
+ :message => ts('can contain letters, numbers, spaces, underscores, @-signs, dots, and dashes.'),
:with => /\A\w[ \w\-\@\.]*\Z/
validates_format_of :name,
- :message => t('name_no_letters_or_numbers', :default => 'must contain at least one letter or number.'),
+ :message => ts('must contain at least one letter or number.'),
:with => /[a-zA-Z0-9]/
+
+ def to_s
+ self.name + ' <' + self.external_author.email + '>'
+ end
end
View
11 app/models/fandom_nomination.rb
@@ -14,5 +14,16 @@ def relationship_tagnames
RelationshipNomination.for_tag_set(owned_tag_set).where(:parent_tagname => tagname).value_of :tagname
end
+ after_save :reject_children, :if => "rejected?"
+ def reject_children
+ character_nominations.each {|char| char.rejected = true; char.save}
+ relationship_nominations.each {|rel| rel.rejected = true; rel.save}
+ end
+
+ after_save :update_child_parent_tagnames, :if => "tagname_changed?"
+ def update_child_parent_tagnames
+ character_nominations.each {|char| char.parent_tagname = self.tagname; char.save}
+ relationship_nominations.each {|rel| rel.parent_tagname = self.tagname; rel.save}
+ end
end
View
57 app/models/owned_tag_set.rb
@@ -30,8 +30,8 @@ class OwnedTagSet < ActiveRecord::Base
has_many :owned_set_taggings, :dependent => :destroy
has_many :set_taggables, :through => :owned_set_taggings
- validates_presence_of :title, :message => ts("Please enter a title for your tag set.")
- validates_uniqueness_of :title, :case_sensitive => false, :message => ts('Sorry, that name is already taken. Try again, please!')
+ validates_presence_of :title, :message => ts("^Please enter a title for your tag set.")
+ validates_uniqueness_of :title, :case_sensitive => false, :message => ts('^Sorry, that name is already taken. Try again, please!')
validates_length_of :title,
:minimum => ArchiveConfig.TITLE_MIN,
:too_short=> ts("must be at least %{min} characters long.", :min => ArchiveConfig.TITLE_MIN)
@@ -40,7 +40,7 @@ class OwnedTagSet < ActiveRecord::Base
:too_long=> ts("must be less than %{max} characters long.", :max => ArchiveConfig.TITLE_MAX)
validates_format_of :title,
:with => /\A[^,*<>^{}=`\\%]+\z/,
- :message => 'of a tag set can not include the following restricted characters: , ^ * < > { } = ` \\ %'
+ :message => '^The title of a tag set can not include the following restricted characters: , ^ * < > { } = ` \\ %'
validates_length_of :description,
:allow_blank => true,
@@ -178,19 +178,60 @@ def clear_nominations!
##### MANAGING ASSOCIATIONS
+ def associations_to_remove=(assoc_ids)
+ TagSetAssociation.for_tag_set(self).where(:id => assoc_ids).delete_all
+ end
+
def load_batch_associations!(batch_associations, options = {})
options.reverse_merge!({:do_relationships => false})
association_lines = batch_associations.split("\n")
+ fandom_tagnames_to_add = []
+ child_tagnames_to_add = []
+ assocs_to_save = []
+ failed = []
+
association_lines.each do |line|
children_names = line.split(',')
- parent_tag_id = Tag.where(:name => children.pop.strip).value_of :id
- next unless parent_tag_id
- children_names.each do |child|
- child_tag_id = Tag.where(:name => child.strip).value_of :id
+ parent_name = children_names.shift.strip
+ parent_tag_id = Fandom.where(:name => parent_name).value_of(:id).first
+ unless parent_tag_id
+ failed << line
+ next
+ end
+ failed_children = []
+ added_parent = false
+ children_names.map {|c| c.strip}.each_with_index do |child_name|
+ child_tag_id = (options[:do_relationships] ? Relationship : Character).where(:name => child_name).value_of(:id).first
+ unless child_tag_id
+ failed_children << child_name
+ next
+ end
assoc = tag_set_associations.build(:tag_id => child_tag_id, :parent_tag_id => parent_tag_id)
- assoc.save
+ unless assoc.valid?
+ failed_children << child_name
+ next
+ end
+ assocs_to_save << assoc
+ child_tagnames_to_add << child_name
+ fandom_tagnames_to_add << parent_name unless added_parent
+ added_parent = true
end
+ failed << "#{parent_name}, #{failed_children.join(', ')}" unless failed_children.empty?
+ end
+
+ # add the tags to the set
+ tag_set.fandom_tagnames_to_add = fandom_tagnames_to_add
+ tag_set.send (options[:do_relationships] ? :relationship_tagnames_to_add= : :character_tagnames_to_add=), child_tagnames_to_add
+
+ if tag_set.save
+ # save the associations
+ assocs_to_save.each {|assoc| assoc.save}
+ else
+ # whoops, nothing worked
+ failed = association_lines
end
+
+ return failed
end
View
27 app/models/prompt.rb
@@ -96,23 +96,32 @@ def correct_number_of_tags
end
# make sure that if there is a specified set of allowed tags, the user's choices
- # are within that set
+ # are within that set, or otherwise canonical
validate :allowed_tags
def allowed_tags
restriction = get_prompt_restriction
- if restriction
+ if restriction && tag_set
TagSet::TAG_TYPES.each do |tag_type|
# if we have a specified set of tags of this type, make sure that all the
# tags in the prompt are in the set.
if TagSet::TAG_TYPES_RESTRICTED_TO_FANDOM.include?(tag_type) && restriction.send("#{tag_type}_restrict_to_fandom")
- # skip the check, there might be some tags in the set used just for adding associations
+ # skip the check, these will be tested in restricted_tags below
elsif restriction.has_tags?(tag_type)
- disallowed_taglist = tag_set ? (tag_set.send("#{tag_type}_taglist") - restriction.tags(tag_type)) : []
+ disallowed_taglist = tag_set.send("#{tag_type}_taglist") - restriction.tags(tag_type)
unless disallowed_taglist.empty?
- errors.add(:base, ts("^These tags in your %{prompt_type} are not allowed in this challenge: %{taglist}",
- :prompt_type => self.class.name,
+ errors.add(:base, ts("^These %{tag_type} tags in your %{prompt_type} are not allowed in this challenge: %{taglist}",
+ :tag_type => tag_type,
+ :prompt_type => self.class.name.downcase,
:taglist => disallowed_taglist.collect(&:name).join(ArchiveConfig.DELIMITER_FOR_OUTPUT)))
end
+ else
+ noncanonical_taglist = tag_set.send("#{tag_type}_taglist").reject {|t| t.canonical}
+ unless noncanonical_taglist.empty?
+ errors.add(:base, ts("These %{tag_type} tags in your %{prompt_type} are not canonical and can't be used unless the moderator adds them: %{taglist}",
+ :tag_type => tag_type,
+ :prompt_type => self.class.name.downcase,
+ :taglist => noncanonical_taglist.collect(&:name).join(ArchiveConfig.DELIMITER_FOR_OUTPUT)))
+ end
end
end
end
@@ -131,8 +140,8 @@ def restricted_tags
# check for tag set associations
disallowed_taglist.reject! {|tag| TagSetAssociation.where(:tag_id => tag.id, :parent_tag_id => tag_set.fandom_taglist).exists?}
unless disallowed_taglist.empty?
- errors.add(:base, ts("^Your %{prompt_type} has some %{tag_type} tags that are not in the selected fandom(s), %{fandom}: %{taglist} (If this is an error, please let us know via the support form!)",
- :prompt_type => self.class.name,
+ errors.add(:base, ts("^These %{tag_type} tags in your %{prompt_type} are not in the selected fandom(s), %{fandom}: %{taglist} (Your moderator may be able to fix this.)",
+ :prompt_type => self.class.name.downcase,
:tag_type => tag_type, :fandom => tag_set.fandom_taglist.collect(&:name).join(ArchiveConfig.DELIMITER_FOR_OUTPUT),
:taglist => disallowed_taglist.collect(&:name).join(ArchiveConfig.DELIMITER_FOR_OUTPUT)))
end
@@ -140,7 +149,7 @@ def restricted_tags
end
end
end
-
+
# make sure we are not blank
def blank?
return false if (url || description)
View
4 app/models/relationship_nomination.rb
@@ -16,7 +16,9 @@ def set_tag_set_nomination
end
def get_parent_tagname
- (self.parent_tagname.blank? ? self.parent_tagname : nil) || (self.fandom_nomination ? self.fandom_nomination.tagname : nil)
+ self.parent_tagname.blank? ? self.parent_tagname : (
+ self.fandom_nomination ? self.fandom_nomination.tagname :
+ Tag.find_by_name(self.tagname).try(:parents).try(:first).try(:name))
end
View
33 app/models/story_parser.rb
@@ -78,6 +78,7 @@ def import_from_urls(urls, options = {})
begin
work = download_and_parse_story(url, options)
if work && work.save
+ work.chapters.each {|chap| chap.save}
works << work
else
failed_urls << url
@@ -244,7 +245,7 @@ def set_chapter_attributes(work, chapter, location, options = {})
return chapter
end
- def set_work_attributes(work, location, options = {})
+ def set_work_attributes(work, location="", options = {})
raise Error, "Work could not be downloaded" if work.nil?
work.imported_from_url = location
work.expected_number_of_chapters = work.chapters.length
@@ -263,7 +264,7 @@ def set_work_attributes(work, location, options = {})
# handle importing works for others
if options[:importing_for_others]
- external_author_name = parse_author(location)
+ external_author_name = options[:external_author_name] || parse_author(location)
if external_author_name
if external_author_name.external_author.do_not_import
# we're not allowed to import works from this address
@@ -292,7 +293,8 @@ def set_work_attributes(work, location, options = {})
work.posted = true if options[:post_without_preview]
work.chapters.each do |chapter|
chapter.posted = true
- chapter.save
+ # ack! causing the chapters to exist even if work doesn't get created!
+ # chapter.save
end
return work
end
@@ -688,7 +690,6 @@ def parse_story_from_deviantart(story)
return work_params
end
-
# Parses a story from the Yuletide archive (an AutomatedArchive)
def parse_story_from_yuletide(story)
work_params = {:chapter_attributes => {}}
@@ -1086,14 +1087,32 @@ def convert_rating_string(rating)
return convert_rating(rating)
end
- def convert_revised_at(date)
+ def convert_revised_at(date_string)
begin
- date = Date.parse(date)
+ date = nil
+ if date_string.match(/^(\d+)$/)
+ # probably seconds since the epoch
+ date = Time.at($1.to_i)
+ end
+ date ||= Date.parse(date_string)
return '' if date > Date.today
return date
- rescue ArgumentError
+ rescue ArgumentError, TypeError
return ''
end
end
+
+ # tries to find appropriate existing collections and converts them to comma-separated collection names only
+ def get_collection_names(collection_string)
+ cnames = ""
+ collection_string.split(',').map {|cn| cn.squish}.each do |collection_name|
+ collection = Collection.find_by_name(collection_name) || Collection.find_by_title(collection_name)
+ if collection
+ cnames += ", " unless cnames.blank?
+ cnames += collection.name
+ end
+ end
+ cnames
+ end
end
View
47 app/models/tag.rb
@@ -161,12 +161,6 @@ def update_wrangler(tag)
scope :by_date, order('created_at DESC')
scope :visible, where('type in (?)', VISIBLE).by_name
- scope :by_name_without_articles, order("case when lower(substring(name from 1 for 4)) = 'the ' then substring(name from 5)
- when lower(substring(name from 1 for 2)) = 'a ' then substring(name from 3)
- when lower(substring(name from 1 for 3)) = 'an ' then substring(name from 4)
- else name
- end")
-
scope :by_pseud, lambda {|pseud|
joins(:works => :pseuds).
where(:pseuds => {:id => pseud.id})
@@ -177,9 +171,9 @@ def update_wrangler(tag)
# This will return all tags that have one of the given tags as a parent
scope :with_parents, lambda {|parents|
- joins(:common_taggings).where("filterable_id in (?)", parents.collect(&:id))
+ joins(:common_taggings).where("filterable_id in (?)", parents.first.is_a?(Integer) ? parents : (parents.respond_to?(:value_of) ? parents.value_of(:id) : parents.collect(&:id)))
}
-
+
scope :with_no_parents,
joins("LEFT JOIN common_taggings ON common_taggings.common_tag_id = tags.id").
where("filterable_id IS NULL")
@@ -313,6 +307,43 @@ def self.in_prompt_restriction(restriction)
INNER JOIN prompt_restrictions ON (prompt_restrictions.id = owned_set_taggings.set_taggable_id AND owned_set_taggings.set_taggable_type = 'PromptRestriction')").
where("prompt_restrictions.id = ?", restriction.id)
end
+
+ def self.by_name_without_articles(fieldname = "name")
+ fieldname = "name" unless fieldname.match(/^([\w]+\.)?[\w]+$/)
+ order("case when lower(substring(#{fieldname} from 1 for 4)) = 'the ' then substring(#{fieldname} from 5)
+ when lower(substring(#{fieldname} from 1 for 2)) = 'a ' then substring(#{fieldname} from 3)
+ when lower(substring(#{fieldname} from 1 for 3)) = 'an ' then substring(#{fieldname} from 4)
+ else #{fieldname}
+ end")
+ end
+
+ def self.in_tag_set(tag_set)
+ joins(:set_taggings).where("set_taggings.tag_set_id = ?", tag_set.id)
+ end
+
+ # gives you: tags.parent_names each {|tag| [tag.parent_name, tag.child_names]} - parent child,child,child,child...
+ def self.parent_names(parent_type = 'fandom')
+ joins(:parents).where("parents_tags.type = ?", parent_type.capitalize).
+ by_name_without_articles("parents_tags.name").
+ group('parents_tags.name').
+ select("parents_tags.name as parent_name,
+ group_concat(distinct tags.name order by case when lower(substring(tags.name from 1 for 4)) = 'the ' then substring(tags.name from 5)
+ when lower(substring(tags.name from 1 for 2)) = 'a ' then substring(tags.name from 3)
+ when lower(substring(tags.name from 1 for 3)) = 'an ' then substring(tags.name from 4)
+ else tags.name
+ end) as child_names")
+ end
+
+ # Because this can be called by a gigantor tag set and all we need are names not objects,
+ # we do an end-run around ActiveRecord and just get the results straight from the db, but
+ # we borrow the sql from parent_names above
+ # returns a hash[parent_name] = child_names
+ def self.names_by_parent(child_relation, parent_type = 'fandom')
+ hash = {}
+ results = ActiveRecord::Base.connection.execute(child_relation.parent_names(parent_type).to_sql)
+ results.each {|row| hash[row.first] = row.second.split(',')}
+ hash
+ end
# Used for associations, such as work.fandoms.string
# Yields a comma-separated list of tag names
View
43 app/models/tag_nomination.rb
@@ -52,27 +52,22 @@ def set_parented
((!tag.parents.empty? && get_parent_tagname.blank?) || tag.parents.collect(&:name).include?(get_parent_tagname))
# if this is an existing tag and has matching parents, or no parent specified and it already has one
self.parented = true
+ self.parent_tagname ||= get_parent_tagname
else
self.parented = false
- self.parent_tagname = get_parent_tagname unless self.parent_tagname
+ self.parent_tagname ||= get_parent_tagname
end
true
end
-
- # here so we can override it in char/relationship noms
- def get_parent_tagname
- (self.parent_tagname.blank? ? self.parent_tagname : nil)
- end
-
# sneaky bit: if the tag set moderator has already rejected or approved this tag, don't
# show it to them again.
before_save :set_approval_status
def set_approval_status
- nom = tag_set_nomination
- nom = fandom_nomination.tag_set_nomination if !nom && from_fandom_nomination
- self.rejected = nom.owned_tag_set.already_rejected?(tagname)
- self.approved = nom.owned_tag_set.already_in_set?(tagname) || nom.owned_tag_set.already_approved?(tagname)
+ set_noms = tag_set_nomination
+ set_noms = fandom_nomination.tag_set_nomination if !set_noms && from_fandom_nomination
+ self.rejected = set_noms.owned_tag_set.already_rejected?(tagname) || false
+ self.approved = set_noms.owned_tag_set.already_in_set?(tagname) || (synonym && set_noms.owned_tag_set.already_in_set?(synonym)) || false
true
end
@@ -98,6 +93,32 @@ def self.nominated_parents(child_tagname, parent_search_term="")
end
parents.group("parent_tagname").order("count_id DESC").count('id').keys
end
+
+ # Can we change the name to this new name?
+ def change_tagname?(new_tagname)
+ tagname = new_tagname
+ if self.valid?
+ return true
+ else
+ return false
+ end
+ end
+
+ # If the mod is changing our name, change all other noms in this set as well
+ # NOTE: YOU CAN ONLY USE THIS IF YOU SUBSEQUENTLY MANUALLY UPDATE THE STATUS OF ALL THE TAG NOMS
+ def change_tagname!(new_tagname)
+ if change_tagname?(new_tagname)
+ # name change is ok - we use update_all because we assume our status is being updated up a level
+ TagNomination.for_tag_set(owned_tag_set).where(:tagname => tagname).update_all(:tagname => new_tagname)
+ return true
+ end
+ return false
+ end
+
+ # here so we can override it in char/relationship noms
+ def get_parent_tagname
+ (self.parent_tagname.blank? ? self.parent_tagname : nil)
+ end
def unreviewed?
!approved && !rejected
View
42 app/models/tag_set.rb
@@ -8,6 +8,8 @@ class TagSet < ActiveRecord::Base
TAG_TYPES_RESTRICTED_TO_FANDOM = %w(character relationship)
TAGS_AS_CHECKBOXES = %w(category rating warning)
+ attr_accessor :from_owned_tag_set
+
has_many :set_taggings, :dependent => :destroy
has_many :tags, :through => :set_taggings
@@ -115,7 +117,7 @@ def assign_tags
end
# Tags must already exist unless they are being added to an owned tag set
- validate :tagnames_must_exist, :if => "owned_tag_set.nil?"
+ validate :tagnames_must_exist, :unless => :from_owned_tag_set
def tagnames_must_exist
nonexist = []
if @tagnames
@@ -155,16 +157,16 @@ def -(other)
TagSet.new(:tags => (self.tags - other.tags))
end
- def has_tag?(tag)
- self.tags.include?(tag)
+ def with_type(type)
+ self.tags.with_type(type)
end
- def with_type(type)
- return self.new_record? ? self.tags.select {|t| t.type == type.classify} : self.tags.with_type(type)
+ def has_type?(type)
+ with_type(type).exists?
end
-
- def tags_with_type(type)
- return with_type(type)
+
+ def with_type_from_redis(type)
+
end
def empty?
@@ -173,14 +175,12 @@ def empty?
# returns the topmost tag type we have in this set
def topmost_tag_type
- topmost_type = ""
TagSet::TAG_TYPES.each do |tag_type|
if self.tags.with_type(tag_type).exists?
- topmost_type = tag_type
- break
+ return tag_type
end
end
- topmost_type
+ ""
end
@@ -189,14 +189,14 @@ def topmost_tag_type
def match_rank(another, type=nil)
# if we don't have any tags of this type, anything matches us
return ALL if tags.empty?
- return ALL if type && tags_with_type(type).empty?
+ return ALL if type && with_type(type).empty?
return ALL if is_subset_of?(another, type)
matching_tags(another, type).size
end
def exact_match?(another, type=nil)
if type
- self.tags_with_type(type).to_a == another.tags_with_type(type).to_a
+ self.with_type(type).to_a == another.with_type(type).to_a
else
self.tags == another.tags
end
@@ -204,7 +204,7 @@ def exact_match?(another, type=nil)
def no_match?(another, type=nil)
if type
- (self.tags_with_type(type).to_a & another.tags_with_type(type).to_a).empty? && !self.tags.empty?
+ (self.with_type(type).to_a & another.with_type(type).to_a).empty? && !self.tags.empty?
else
(self.tags & another.tags).empty? && !self.tags.empty?
end
@@ -212,29 +212,29 @@ def no_match?(another, type=nil)
def partial_match?(another, type=nil)
if type
- !(self.tags_with_type(type).to_a & another.tags_with_type(type).to_a).empty?
+ !(self.with_type(type).to_a & another.with_type(type).to_a).empty?
else
!(self.tags & another.tags).empty?
end
end
# checks to see if this is a subset of another tagset
- # note: we have to cast tags_with_type to an array because one of the tag sets may actually
+ # note: we have to cast with_type to an array because one of the tag sets may actually
# be an activequery object
def is_subset_of?(another, type=nil)
if type
- (self.tags_with_type(type).to_a & another.tags_with_type(type).to_a) == self.tags_with_type(type).to_a
+ (self.with_type(type).to_a & another.with_type(type).to_a) == self.with_type(type).to_a
else
(self.tags & another.tags) == self.tags
end
end
# checks to see if this is a superset of another tagset
- # note: we have to cast tags_with_type to an array because one of the tag sets may actually
+ # note: we have to cast with_type to an array because one of the tag sets may actually
# be an activequery object
def is_superset_of?(another, type=nil)
if type
- (self.tags_with_type(type).to_a & another.tags_with_type(type).to_a) == another.tags_with_type(type).to_a
+ (self.with_type(type).to_a & another.with_type(type).to_a) == another.with_type(type).to_a
else
(self.tags & another.tags) == another.tags
end
@@ -243,7 +243,7 @@ def is_superset_of?(another, type=nil)
# returns matching tags
def matching_tags(another, type=nil)
if type
- self.tags_with_type(type).to_a & another.tags_with_type(type).to_a
+ self.with_type(type).to_a & another.with_type(type).to_a
else
self.tags & another.tags
end
View
28 app/models/tag_set_association.rb
@@ -16,10 +16,38 @@ def not_existing
attr_accessor :create_association
+ def to_s
+ "#{tag.name} (#{parent_tag.name})"
+ end
+
def self.for_tag_set(tagset)
where(:owned_tag_set_id => tagset.id)
end
+ # almost exactly like the same code in tag.rb
+ def self.parent_names(child_type, parent_type = "fandom")
+ joins(:tag, :parent_tag).where("tags.type = ? AND parent_tags_tag_set_associations.type = ?", child_type.capitalize, parent_type.capitalize).
+ order("case when lower(substring(parent_tags_tag_set_associations.name from 1 for 4)) = 'the ' then substring(parent_tags_tag_set_associations.name from 5)
+ when lower(substring(parent_tags_tag_set_associations.name from 1 for 2)) = 'a ' then substring(parent_tags_tag_set_associations.name from 3)
+ when lower(substring(parent_tags_tag_set_associations.name from 1 for 3)) = 'an ' then substring(parent_tags_tag_set_associations.name from 4)
+ else parent_tags_tag_set_associations.name
+ end").
+ group('parent_tags_tag_set_associations.name').
+ select("parent_tags_tag_set_associations.name as parent_name,
+ group_concat(distinct tags.name order by case when lower(substring(tags.name from 1 for 4)) = 'the ' then substring(tags.name from 5)
+ when lower(substring(tags.name from 1 for 2)) = 'a ' then substring(tags.name from 3)
+ when lower(substring(tags.name from 1 for 3)) = 'an ' then substring(tags.name from 4)
+ else tags.name
+ end) as child_names")
+ end
+
+ def self.names_by_parent(child_relation, child_type, parent_type = "fandom")
+ hash = {}
+ results = ActiveRecord::Base.connection.execute(child_relation.parent_names(child_type, parent_type).to_sql)
+ results.each {|row| hash[row.first] = row.second.split(',')}
+ hash
+ end
+
def parent_tagname
@parent_tagname || self.parent_tag.name
end
View
5 app/views/challenge/gift_exchange/_gift_exchange_form.html.erb
@@ -48,10 +48,7 @@
<!-- instructions from moderator -->
<%= render "challenge/shared/challenge_form_instructions", :f => f %>
- <fieldset>
- <legend><%= ts('Submit') %></legend>
- <p class="submit"><%= f.submit ts('Submit') %></p>
- </fieldset>
+ <%= submit_fieldset f %>
<% end %>
View
12 app/views/challenge/prompt_meme/_prompt_meme_form.html.erb
@@ -24,9 +24,10 @@
<h3>Prompts</h3>
<dl>
<dt><%= f.label :anonymous, ts("Prompts anonymous by default? (Participants can override)") %></dt>
- <dd><%= f.check_box :anonymous %>
- <dt><%= f.label :requests_num_required, ts("Number of prompts per signup: ") %></dt>
- <dd><%= f.text_field :requests_num_required, :class => "number" %></dt>
+ <dd><%= f.check_box :anonymous %></dd>
+ <dt><%= f.label :requests_num_required, ts("Number of prompts per signup") %>:</dt>
+ <%= required_and_allowed(f, "requests", false) %>
+
</dl>
</fieldset>
@@ -35,10 +36,7 @@
<%= render "challenge/shared/challenge_form_instructions", :f => f %>
- <fieldset>
- <legend><%= ts('Submit') %></legend>
- <p class="submit"><%= f.submit ts('Submit') %></p>
- </fieldset>
+ <%= submit_fieldset f %>
<% end %>
View
7 app/views/challenge_signups/_signup_form.html.erb
@@ -61,12 +61,7 @@
</fieldset>
<% end # requests & offers section %>
- <fieldset>
- <legend><%= 'Submit' %></legend>
- <p class="submit">
- <%= signup_form.submit ts('Submit') %>
- </p>
- </fieldset>
+ <%= submit_fieldset signup_form %>
<% end %>
View
2  app/views/challenge_signups/_signup_form_general_information.html.erb
@@ -9,7 +9,7 @@
<dl>
<dt><%= form.label :pseud_id, ts("Name: ") -%></dt>
<dd>
- <% if form.object.new_record? && current_user.pseuds.size > 1 %>
+ <% if (form.object.new_record? || @challenge.allow_name_change?) && current_user.pseuds.size > 1 %>
<%= form.select :pseud_id, options_from_collection_for_select(current_user.pseuds, :id, :name, current_user.default_pseud.id) %>
<% else %>
<% pseud = form.object.new_record? ? current_user.default_pseud : form.object.pseud %>
View
42 app/views/collection_participants/index.html.erb
@@ -1,25 +1,25 @@
<!--Descriptive page name, messages and instructions-->
-<h2><%=h t('.participants', :default => "Participants in") %> <%= @collection.title %></h2>
+<h2><%= ts("Members of %{title}", :title => @collection.title) %></h2>
<!--descriptions-->
<table id="collection_participants_table" summary="This table shows the participants in your collection; you can change their roles, remove participants and add new ones">
-<caption><%=h t('.list', :default => "List of participants") %></caption>
-<thead>
- <tr>
- <th scope="col"><%= ts("Participant") %></th>
- <th scope="col"><%= ts("Role") %></th>
- <th scope="col"><%= ts("Manage") %></th>
-</tr>
-</thead>
-<tbody>
-<% @collection_participants.each do |participant| %>
- <%= render :partial => 'participant_form', :locals => {:participant => participant} %>
-<% end %>
-</tbody>
-<tfoot>
- <tr>
- <th scope="col" colspan="3"><%= ts("Add Participant") %></th>
-<%= render :partial => 'add_participants_form' %>
-</tr>
-</tfoot>
-</table>
+ <caption><%= ts("List of members") %></caption>
+ <thead>
+ <tr>
+ <th scope="col"><%= ts("Member") %></th>
+ <th scope="col"><%= ts("Role") %></th>
+ <th scope="col"><%= ts("Manage") %></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @collection_participants.each do |participant| %>
+ <%= render :partial => 'participant_form', :locals => {:participant => participant} %>
+ <% end %>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th scope="col" colspan="3"><%= ts("Add New Members") %></th>
+ <%= render :partial => 'add_participants_form' %>
+ </tr>
+ </tfoot>
+</table>
View
15 app/views/collections/_form.html.erb
@@ -132,18 +132,7 @@
<% end %>
</fieldset>
- <fieldset>
- <% if @collection.name.blank? %>
- <legend><%= ts('Submit') %></legend>
- <p class="submit actions">
- <%= collection_form.submit ts('Submit') %>
- </p>
- <% else %>
- <legend><%= ts('Update') %></legend>
- <p class="submit actions">
- <%= collection_form.submit ts('Update') %>
- </p>
-<% end %>
-</fieldset>
+ <%= submit_fieldset collection_form %>
+
<% end %>
View
27 app/views/owned_tag_sets/_internal_tag_set_fields.html.erb
@@ -1,13 +1,9 @@
-<% first_checkbox_type = true %>
-
-<% # cannot have fieldset as first child of dl, only of dt/dd %>
-
<% TagSet::TAG_TYPES.each do |tag_type| %>
<% unless TagSet::TAGS_AS_CHECKBOXES.include?(tag_type) %>
- <% # we need this fieldset or the check all/none will happen too broadly %>
+ <% # fandoms, chars, relationships, freeforms %>
<fieldset class="tagset">
<dl>
- <% if @tag_set.tag_set.tags_with_type(tag_type).empty? %>
+ <% if @tag_set.tag_set.with_type(tag_type).empty? %>
<% add_label = ts("Add #{tag_type.classify.pluralize}:") %>
<% else %>
<% add_label = ts("Add:") %>
@@ -21,21 +17,16 @@
<dd title="add tags"><%= form.text_field "#{tag_type}_tagnames_to_add".to_sym, autocomplete_options("tag_type") %></dd>
</dl>
</fieldset>
- <% else %>
- <% if first_checkbox_type %>
- <% # we've hit the first of the type of tags that just get checkboxes and no autocomplete so we close & reopen the fieldset and dl %>
- <% first_checkbox_type = false %>
- <% end %>
- <% # we need this fieldset or the check all/none will happen too broadly %>
+ <% else %>
+ <% # ratings, categories, warnings %>
<fieldset class="tagset">
<dl>
- <% # ratings, etc %>
- <dt><%= tag_type.classify.pluralize %></dt>
- <dd><%= check_all_none %>
- <%= checkbox_section(form, "#{tag_type}_tagnames_to_add", tag_type.classify.constantize.all,
- :checked_method => "#{tag_type}_taglist",
- :value_method => "name", :include_toggle => false, :checkbox_side => "right") %></dd>
+ <dt><%= tag_type.classify.pluralize %></dt>
+ <dd><%= check_all_none %>
+ <%= checkbox_section(form, "#{tag_type}_tagnames", tag_type.classify.constantize.value_of(:name),
+ :checked_method => "#{tag_type}_tagnames", :value_method => "to_s", :name_method => "to_s",
+ :checkbox_side => "right") %></dd>
</dl>
</fieldset>
<% end %>
View
47 app/views/owned_tag_sets/_show_fandoms_by_media.html.erb
@@ -0,0 +1,47 @@
+<% @fandom_hash.keys.each do |media| %>
+ <li class="media listbox <%= cycle :odd, :even %>">
+ <h3 class="expander_parent">
+ <%= ts("%{media}", :media => media) %>
+ <% list_id = "list_for_media_#{media.gsub(/[^\w]/, '_')}" %>
+ (<%= @fandom_hash[media].size %>)
+ <%= expand_contract_shuffle(list_id) %>
+ </h3>
+ <ol id="<%= list_id %>" class="tags index" force_contract="true">
+ <% unless @character_hash || @relationship_hash %>
+ <% # we're just doing fandoms -- pop them into li and move on! %>
+ <%= @fandom_hash[media].map {|fandom| content_tag(:li, fandom)}.join("\n").html_safe %>
+ <% else %>
+ <% # some fandoms have chars or rels underneath %>
+ <% @fandom_hash[media].each do |fandom| %>
+ <% # test to make sure we've actually got chars or rels for this individual fandom %>
+ <% has_characters = (@character_hash && @character_hash[fandom]) ? @character_hash[fandom].size : 0 %>
+ <% has_relationships = (@relationship_hash && @relationship_hash[fandom]) ? @relationship_hash[fandom].size : 0 %>
+ <%
+ # this gets called a ton if there are a lot of fandoms so not doing it in a partial to save on time, although
+ # as a result it's duplicated in show_tag_set_tags :(
+ %>
+ <li class="fandom listbox <%= cycle :odd, :even %>">
+ <% if (has_relationships + has_characters) > 0 %>
+ <h3 class="expander_parent">
+ <%= ts("%{fandom}", :fandom => fandom) %>
+ <% list_id = "list_for_fandom_#{fandom.gsub(/[^\w]/, '_')}" %>
+ (<%= has_relationships + has_characters %>)
+ <%= expand_contract_shuffle(list_id) %>
+ </h3>
+ <ol id="<%= list_id %>" class="tags index" force_contract="true">
+ <% if has_characters > 0 %>
+ <%= @character_hash[fandom].map {|character| content_tag(:li, character)}.join("\n").html_safe %>
+ <% end %>
+ <% if has_relationships > 0 %>
+ <%= @relationship_hash[fandom].map {|relationship| content_tag(:li, relationship)}.join("\n").html_safe %>
+ <% end %>
+ </ol>
+ <% else %>
+ <h3><%= ts("%{fandom}", :fandom => fandom) %> (0)</h3>
+ <% end %>
+ </li>
+ <% end %>
+ <% end %>
+ </ol>
+ </li>
+<% end %>
View
6 app/views/owned_tag_sets/_show_tag_set_associations.html.erb
@@ -1,12 +1,12 @@
<% if @associations && !@associations.empty? %>
<h4><%= ts("Tag Set Associations") %> (<%= @associations.count %>)</h4>
- <ol class="tagset fandom index">
+ <ol class="tagset index">
<% @associations.group(:parent_tag_id).joins(:tag, :parent_tag).
select("parent_tags_tag_set_associations.name as parent, group_concat(tags.name ORDER BY tags.name) as children").each do |assoc| %>
- <li>
+ <li class="association listbox">
<h3><%= assoc.parent %></h3>
- <ol class="tags">
+ <ol class="child tags">
<%= assoc.children.split(',').map {|child| content_tag(:li, child)}.join("\n").html_safe %>
</ol>
</li>
View
133 app/views/owned_tag_sets/_show_tag_set_tags.html.erb
@@ -1,74 +1,75 @@
-<% if @tag_type %>
- <h4><%= @tag_type.classify.pluralize %> (<%= @tags.count %>)</h4>
+<ol class="tagset index">
+ <% # first show any ratings, categories, or warnings, since there will only be a small number if any %>
+ <% TagSet::TAGS_AS_CHECKBOXES.each do |tag_type| %>
+ <% if @tag_set.tag_set.with_type(tag_type).exists? %>
+ <%= render "show_tags_in_single_list", :tag_type => tag_type %>
+ <% end %>
+ <% end %>
- <% if @tag_type == "fandom" && @tags.count > ArchiveConfig.MAX_OPTIONS_TO_SHOW %>
+ <% if @fandom_hash %>
+ <% # we're doing the fandoms by media and any char/rel tags will be nested %>
+ <%= render "show_fandoms_by_media" %>
+ <% end %>
- <!-- sort tags out by media -->
- <ol class="tagset media index">
- <% Media.by_name.each do |medium| %>
- <% if @tags.with_parents([medium]).count > 0 %>
- <li class="category <%= cycle :odd, :even %>">
- <h3><%= medium.name %> (<%= @tags.with_parents([medium]).count %>) <%= expand_contract_shuffle("list_for_media_#{medium.id}") %></h3>
- <ol id="list_for_media_<%= medium.id %>" class="tags">
- <%= tag_relation_to_list @tags.with_parents([medium]) %>
- </ol>
- </li>
- <% end %>
- <% end %>
- <% if @tags.with_no_parents.count > 0 %>
- <li class="category">
- <h3>No Media Specified (<%= @tags.with_no_parents.count %>)</h3>
- <ol class="tags">
- <%= tag_relation_to_list @tags.with_no_parents %>
- </ol>
- </li>
- <% end %>
- </ol>
-
- <% elsif (@tag_type == "character" || @tag_type == "relationship") && @tags.count > ArchiveConfig.MAX_OPTIONS_TO_SHOW %>
+ <% if @character_hash || @relationship_hash %>
+ <% # if there was a fandom display, check for any that weren't shown in the fandom display %>
+ <% all_fandom_keys = (@character_hash.keys | @relationship_hash.keys).sort {|a,b| a.gsub(/^(the |an |a )/, '') <=> b.gsub(/^(the |an |a )/, '')} %>
+ <% all_fandom_keys -= @tag_set.tag_set.with_type("fandom").value_of :name %>
+
+ <% if @fandom_hash && !all_fandom_keys.empty? %>
- <!-- sort tags out by fandom -->
- <ol class="tagset fandom index">
-
- <% @tag_set.with_type("fandom").by_name_without_articles.each do |fandom_id, fandom_name| %>
- <% if @tags.with_parents([fandom]).count > 0 %>
- <li class="category <%= cycle :odd, :even %>">
- <h3><%= fandom.name %> (<%= @tags.with_parents([fandom]).count %>) <%= expand_contract_shuffle("list_for_fandom_#{fandom.id}") %></h3>
- <ol id="list_for_fandom_<%= fandom.id %>" class="tags">
- <%= tag_relation_to_list @tags.with_parents([fandom]) %>
+ <% # DEAR FRONT END I suspect there is a better way to do this within the list and feel free to replace it with that better way! %>
+ <% # start of the ugly %>
+ </ol>
+ <h4><%= ts("The following characters and relationships in the set don't seem to be connected to any fandom in the set as far as we can tell. You might want to set up associations for them.") %></h4>
+ <% # reopen new ol %>
+ <ol class="tagset index">
+ <% # end of ugly %>
+
+ <li class="cast listbox">
+ <h3><%= ts("Unassociated Characters & Relationships") %> <%= expand_contract_shuffle("list_for_unassociated_char_and_rel") %></h3>
+ <ol id="list_for_unassociated_char_and_rel" class="tags index">
+ <% # we have to use the splat operator here because values_at uses args %>
+ <%= @character_hash.values_at(*all_fandom_keys).flatten.uniq.sort {|a,b| a.gsub(/^(the |an |a )/, '') <=> b.gsub(/^(the |an |a )/, '')}.map {|tag| content_tag(:li, tag)}.join("\n").html_safe %>
+ <%= @relationship_hash.values_at(*all_fandom_keys).flatten.uniq.sort {|a,b| a.gsub(/^(the |an |a )/, '') <=> b.gsub(/^(the |an |a )/, '')}.map {|tag| content_tag(:li, tag)}.join("\n").html_safe %>
+ </ol>
+ </li>
+
+ <% else %>
+
+ <% all_fandom_keys.each do |fandom| %>
+ <%
+ # this gets called a ton if there are a lot of fandoms so not doing it in a partial for performance, although
+ # as a result it's mostly duplicated in show_fandoms_by_media :(
+ %>
+ <% has_characters = (@character_hash && @character_hash[fandom]) ? @character_hash[fandom].size : 0 %>
+ <% has_relationships = (@relationship_hash && @relationship_hash[fandom]) ? @relationship_hash[fandom].size : 0 %>
+ <li class="fandom listbox <%= cycle :odd, :even %>">
+ <% if (has_relationships + has_characters) > 0 %>
+ <h3 class="expander_parent">
+ <%= ts("%{fandom}", :fandom => fandom) %>
+ (<%= has_relationships + has_characters %>)
+ <%= expand_contract_shuffle(list_id) %>
+ <% list_id = "list_for_fandom_#{fandom.gsub(/[^\w]/, '_')}" %>
+ <%= expand_contract_shuffle(list_id) %>
+ </h3>
+ <ol id="<%= list_id %>" class="tags index">
+ <% if has_characters > 0 %>
+ <%= @character_hash[fandom].map {|character| content_tag(:li, character)}.join("\n").html_safe %>
+ <% end %>
+ <% if has_relationships > 0 %>
+ <%= @relationship_hash[fandom].map {|relationship| content_tag(:li, relationship)}.join("\n").html_safe %>
+ <% end %>
</ol>
- </li>
- <% end %>
- <% end %>
- <% if @tags.with_no_parents.count > 0 %>
- <li class="category">
- <h3>No Fandom Specified (<%= @tags.with_no_parents.count %>)</h3>
- <ol class="tags">
- <%= tag_relation_to_list @tags.with_no_parents %>
- </ol>
- </li>
+ <% else %>
+ <h3><%= ts("%{fandom}", :fandom => fandom) %> (0)</h3>
+ <% end %>
+ </li>
<% end %>
- </ol>
-
- <% else %>
-
- <!-- show all the tags alphabetically -->
- <ol class="tagset tags index">
- <%= tag_relation_to_list @tags %>
- </ol>
-
- <% end %>
-
-<% else %>
-
- <!-- recursively render by type -->
- <% TagSet::TAG_TYPES.each do |type| %>
- <% @tag_type = type %>
- <% @tags = @tags.with_type(type) %>
- <% if @tags.count > 0 %>
- <%= render "show_tag_set_tags" %>
+
<% end %>
<% end %>
-<% end %>
-
+ <% # finally, freeform tags, if necessary broken up into alphabetical lists %>
+ <%= render "show_tags_by_alpha", :tag_type => "freeform" %>
+</ol>
View
46 app/views/owned_tag_sets/_show_tags_by_alpha.html.erb
@@ -0,0 +1,46 @@
+<% # expects tag_type %>
+<% if (tags = @tag_set.tag_set.with_type(tag_type)).exists? %>
+ <% if tags.count <= ArchiveConfig.MAX_OPTIONS_TO_SHOW %>
+ <%= render "show_tags_in_single_list", :tag_type => tag_type %>
+ <% else %>
+ <%
+ # too many tags to throw at the user!
+ # this gets a little tricky: here's what this code does
+ # every time we see a new letter at the start of a tagname, we want to start a new heading + inner ol
+ # we only want one heading for 0-9
+ # we start with that one, but we might not see any tags with a number, so we only display
+ # the heading if we actually see one
+ # once we've opened a new heading and inner ol if we're going to, we just show the tagname
+ # in a list item
+ %>
+ <% ranges = %w(0-9 abc def ghi jkl mno pqr st uvw xyz) %>
+ <li class="freeform alphabet tagset index">
+ <% current_range = 0 %>
+ <% current_range_unseen = true %>
+ <% tags.by_name_without_articles.value_of(:name).each do |tagname| %>
+ <% if !(tagname.match /^(the|an|a)?\s*[#{ranges[current_range]}]/i) %>
+ <% # close and reopen the inner ol %>
+ <% unless current_range_unseen %></ol></li><% end %>
+ <% first_letter = tagname.gsub(/^(the |an |a )?/i, '')[0,1] %>
+ <% while !(first_letter.match /[#{ranges[current_range]}]/i) do current_range = current_range+1 end