Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

overhaul settings library and click_hide 'monkey patch'

patch is not necessary, we can just do data: {click_hide: true} and use UJS to create the same effect
  • Loading branch information...
commit 5aa596d29bc5462ca6d6b31b2024a78d4aeb7ecf 1 parent aa31d24
Alex Robbin authored
1  .rspec
... ... @@ -1,3 +1,2 @@
1 1 --colour
2 2 --format doc
3   -
13 app/assets/javascripts/global.js.coffee
... ... @@ -1,9 +1,14 @@
1   -$(document).on "focus", "input.click-hide", ->
2   - $(@).val "" if $(@).val() is @defaultValue
  1 +click_hide = ->
  2 + $(@).val($(@).data('click-hide')).css "color", "#aaa" if $(@).val() is ""
  3 +
  4 +$ ->
  5 + $("input[data-click-hide]").each click_hide
  6 +
  7 +$(document).on "focus", "input[data-click-hide]", ->
  8 + $(@).val "" if $(@).val() is $(@).data('click-hide')
3 9 $(@).css "color", "#000"
4 10
5   -$(document).on "blur", "input.click-hide", ->
6   - $(@).val(@defaultValue).css "color", "#aaa" if $(@).val() is ""
  11 +$(document).on "blur", "input[data-click-hide]", click_hide
7 12
8 13 $(document).on "click", "a.drawer", (e) ->
9 14 e.preventDefault()
14 app/assets/stylesheets/_mixins.css.scss
@@ -9,16 +9,16 @@ $prefixes: ("", "-moz-", "-ms-", "-o-", "-webkit-");
9 9 }
10 10
11 11 @mixin border-radius($size: 4) {
12   - @include css3-attribute(border-radius, #{$size}px);
13   - border: {
14   - color: #e5e5e5 #dbdbdb #d2d2d2;
15   - width: 1px;
16   - style: solid;
17   - }
  12 + @include css3-attribute(border-radius, #{$size}px);
  13 + border: {
  14 + color: #e5e5e5 #dbdbdb #d2d2d2;
  15 + width: 1px;
  16 + style: solid;
  17 + }
18 18 }
19 19
20 20 @mixin box-shadow($opacity: 0.5, $offset: 1, $size: 5) {
21   - @include css3-attribute(box-shadow, rgba(0, 0, 0, $opacity) 0 #{$offset}px #{$size}px);
  21 + @include css3-attribute(box-shadow, rgba(0, 0, 0, $opacity) 0 #{$offset}px #{$size}px);
22 22 }
23 23
24 24 @mixin gradient($start: #fff, $end: #000, $start_pct: 0%, $end_pct: 100%, $direction: top) {
26 app/models/professor.rb
... ... @@ -1,20 +1,16 @@
1 1 class Professor < User
2 2
3   - SETTINGS = {
4   - widget_order: {
5   - name: 'Order of boxes on the homepage',
6   - type: 'sort',
7   - options: %w(activity gradebook courses events),
8   - default: %w(activity gradebook courses events),
9   - editable: false
10   - },
11   - grading_system: {
12   - name: 'What do you want your default grading system to be',
13   - type: 'radio',
14   - options: [['Point System', 'point'], ['Weighting System', 'weight']],
15   - default: 'point'
16   - }
17   - }
  3 + setting :widget_order,
  4 + name: 'Order of boxes on the homepage',
  5 + type: 'sort',
  6 + options: %w(activity gradebook courses events),
  7 + default: %w(activity gradebook courses events)
  8 + setting :grading_system,
  9 + name: 'What do you want your default grading system to be',
  10 + type: 'radio',
  11 + options: [['Point System', 'point'], ['Weighting System', 'weight']],
  12 + default: 'point',
  13 + editable: true
18 14
19 15 has_many :sections, include: :course
20 16 has_many :events, through: :sections
15 app/models/section.rb
... ... @@ -1,14 +1,11 @@
1 1 class Section < ActiveRecord::Base
2   - include Settings
3 2
4   - SETTINGS = {
5   - grading_system: {
6   - name: 'What kind of grading system do you use for this section',
7   - type: 'radio',
8   - options: [['Point System', 'point'], ['Weighting System', 'weight']],
9   - default: 'point'
10   - }
11   - }
  3 + setting :grading_system,
  4 + name: 'What kind of grading system do you use for this section',
  5 + type: 'radio',
  6 + options: [['Point System', 'point'], ['Weighting System', 'weight']],
  7 + default: 'point',
  8 + editable: true
12 9
13 10 belongs_to :course
14 11 belongs_to :semester
15 app/models/sectionship.rb
... ... @@ -1,14 +1,11 @@
1 1 class Sectionship < ActiveRecord::Base
2   - include Settings
3 2
4   - SETTINGS = {
5   - send_notifications: {
6   - name: "Be notified of changes to this section's information",
7   - type: 'radio',
8   - options: [['Yes', true], ['No', false]],
9   - default: true
10   - }
11   - }
  3 + setting :send_notifications,
  4 + name: "Be notified of changes to this section's information",
  5 + type: 'radio',
  6 + options: [['Yes', true], ['No', false]],
  7 + default: true,
  8 + editable: true
12 9
13 10 belongs_to :section, counter_cache: :students_count
14 11 belongs_to :student
6 app/models/setting.rb
... ... @@ -1,8 +1,6 @@
1 1 class Setting < ActiveRecord::Base
2 2 include ActionView::Helpers::FormTagHelper
3 3
4   - scope :editable, where('editable = 1')
5   -
6 4 belongs_to :resource, polymorphic: true
7 5
8 6 serialize :value
@@ -15,7 +13,7 @@ def key
15 13
16 14 def build_field!(form)
17 15 str = ''
18   - info = resource_type.constantize::SETTINGS[key]
  16 + info = self.class.available_settings[key]
19 17 case info[:type]
20 18 when 'select'
21 19 str += form.label :value, info[:name]
@@ -39,7 +37,7 @@ def build_field!(form)
39 37
40 38 protected
41 39 def typecast_value
42   - case self.value
  40 + case value
43 41 when String
44 42 self.value = value.to_i if value == value.to_i.to_s
45 43 self.value = value == 'true' ? true : value == 'false' ? false : value
26 app/models/student.rb
... ... @@ -1,20 +1,16 @@
1 1 class Student < User
2 2
3   - SETTINGS = {
4   - widget_order: {
5   - name: 'Order of boxes on the homepage',
6   - type: 'sort',
7   - options: %w(activity gradebook courses events),
8   - default: %w(activity gradebook courses events),
9   - editable: false
10   - },
11   - calendar_reminders: {
12   - name: 'When should you be reminded of calendar events',
13   - type: 'checkbox',
14   - options: [['1 week before', 168], ['3 days before', 72], ['1 day before', 24], ['12 hours before', 12]],
15   - default: [168, 72, 24] # hours before
16   - }
17   - }
  3 + setting :widget_order,
  4 + name: 'Order of boxes on the homepage',
  5 + type: 'sort',
  6 + options: %w(activity gradebook courses events),
  7 + default: %w(activity gradebook courses events)
  8 + setting :calendar_reminders,
  9 + name: 'When should you be reminded of calendar events',
  10 + type: 'checkbox',
  11 + options: [['1 week before', 168], ['3 days before', 72], ['1 day before', 24], ['12 hours before', 12]],
  12 + default: [168, 72, 24], # hours before
  13 + editable: true
18 14
19 15 has_many :sectionships
20 16 has_many :sections, through: :sectionships, include: :course
1  app/models/user.rb
... ... @@ -1,5 +1,4 @@
1 1 class User < ActiveRecord::Base
2   - include Settings
3 2
4 3 self.abstract_class = true
5 4
2  app/views/courses/edit.html.haml
@@ -2,7 +2,7 @@
2 2 %h2 Edit this Course Section
3 3 #modal-inner
4 4 = form_for @sectionship || @section, url: course_path(@section), remote: true do |f|
5   - = f.fields_for :settings, (@sectionship || @section).settings.editable do |s|
  5 + = f.fields_for :settings, (@sectionship || @section).editable_settings do |s|
6 6 = s.object.build_field!(s)
7 7 %br
8 8 %br
2  app/views/courses/roster.html.haml
@@ -4,7 +4,7 @@
4 4 = render 'heading'
5 5 #roster
6 6 %h2
7   - %span.right= text_field_tag 'search', nil, class: 'text small', click_hide: 'Search Roster', autocomplete: 'off'
  7 + %span.right= text_field_tag 'search', nil, class: 'text small', autocomplete: 'off', data: {click_hide: 'Search Roster'}
8 8 There #{@section.students_count == 1 ? 'is' : 'are'} #{pluralize @section.students_count, 'student'} enrolled in this course section
9 9 - @students.each do |student|
10 10 .student.left
72 config/initializers/click_hide.rb
... ... @@ -1,72 +0,0 @@
1   -# This 'monkey patch' adds a :click_hide option to all textual input fields
2   -#
3   -# Alex Robbin
4   -# rev 001 . 2010.08.16
5   -# rev 002 . 2010.09.09 - Alex Robbin: minor bug fix within click_hide method
6   -# rev 003 . 2010.09.26 - Alex Robbin: added capability to text_field_tag method
7   -# rev 004 . 2010.11.08 - Alex Robbin: added capability to text_area_tag method
8   -# rev 005 . 2011.05.14 - Alex Robbin: updated to match Rails 3 methods; DRYed up the code
9   -
10   -module ActionView
11   - module Helpers
12   -
13   - module FormTagHelper
14   - def text_field_tag(name, value = nil, options = {})
15   - if value.blank? && click_hide = options.delete(:click_hide)
16   - options[:class] ||= ''
17   - options[:class] += ' click-hide'
18   - options[:value] = click_hide == true ? name.to_s.humanize.titleize : click_hide
19   - end
20   - tag :input, { "type" => "text", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
21   - end
22   -
23   - def text_area_tag(name, content = nil, options = {})
24   - options.stringify_keys!
25   -
26   - if content.blank? && click_hide = options.delete("click_hide")
27   - options["class"] ||= ''
28   - options["class"] += ' click-hide'
29   - content = click_hide == true ? name.to_s.humanize.titleize : click_hide
30   - end
31   -
32   - if size = options.delete("size")
33   - options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
34   - end
35   -
36   - escape = options.key?("escape") ? options.delete("escape") : true
37   - content = ERB::Util.html_escape(content) if escape
38   -
39   - content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
40   - end
41   - end
42   -
43   - def text_field(object_name, method, options = {})
44   - click_hide object_name, method, options do
45   - InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("text", options)
46   - end
47   - end
48   -
49   - def password_field(object_name, method, options = {})
50   - click_hide object_name, method, options do
51   - InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("password", { value: nil }.merge!(options))
52   - end
53   - end
54   -
55   - def text_area(object_name, method, options = {})
56   - click_hide object_name, method, options do
57   - InstanceTag.new(object_name, method, self, options.delete(:object)).to_text_area_tag(options)
58   - end
59   - end
60   -
61   - private
62   - def click_hide(object_name, method, options, &block)
63   - if options[:object].send(method).blank? && click_hide = options.delete(:click_hide)
64   - options[:class] ||= ''
65   - options[:class] += ' click-hide'
66   - options[:value] = click_hide == true ? options[:object].class.human_attribute_name(method) : click_hide
67   - end
68   - yield block
69   - end
70   -
71   - end
72   -end
2  config/initializers/uclass.rb
... ... @@ -1,5 +1,5 @@
1 1 require 'calendar'
2   -require 'email_case_check'
3 2 require 'routing'
4 3 require 'settings'
5 4 require 'uploads'
  5 +require 'validation_display_order'
1  db/migrate/20110301010754_create_base.rb
@@ -84,7 +84,6 @@ def change
84 84 create_table :settings do |t|
85 85 t.references :resource, polymorphic: true
86 86 t.string :key, :value
87   - t.boolean :editable
88 87 t.timestamps
89 88 end
90 89
1  db/schema.rb
@@ -154,7 +154,6 @@
154 154 t.string "resource_type"
155 155 t.string "key"
156 156 t.string "value"
157   - t.boolean "editable"
158 157 t.datetime "created_at", :null => false
159 158 t.datetime "updated_at", :null => false
160 159 end
33 lib/email_case_check.rb
... ... @@ -1,33 +0,0 @@
1   -# This does a case check of your email address before the object is saved.
2   -# It forces a downcase of the @domain.com part of the email address.
3   -
4   -module EmailCaseCheck
5   -
6   - def self.included(klass)
7   - klass.class_eval do
8   - extend ModelClassMethods
9   -
10   - before_save :check_email_case
11   -
12   - private
13   - def check_email_case
14   - array = self.email_address.split('@')
15   - self.email_address = "#{array.first}@#{array.last.downcase}"
16   - end
17   - end
18   - end
19   -
20   - module ModelClassMethods
21   -
22   - HUMANIZED_ATTRIBUTES = {
23   - email_address: "Email address",
24   - email_address_confirmation: "Email address confirmation"
25   - }
26   -
27   - def human_attribute_name(attr)
28   - HUMANIZED_ATTRIBUTES[attr.to_sym] || super
29   - end
30   -
31   - end
32   -
33   -end
75 lib/settings.rb
... ... @@ -1,57 +1,66 @@
1 1 # This Settings module allows you to easily add the settings functionality to any object class throughout the app.
2   -# Will simplify this: Object.find(1).settings.where(key: 'key').value
3   -# To: Object.find(1).key
  2 +# Will simplify this: User.find(1).settings.find_by_key('key').value
  3 +# To: User.find(1).key
4 4 #
5 5 # Also creates an Object.update_settings! method to easily add new settings to already existing objects.
6 6
7 7 module Settings
8 8
9   - def self.included(klass)
10   - klass.class_eval do
11   - extend ModelClassMethods
  9 + def self.included(base)
  10 + base.extend ClassMethods
  11 + base.send :include, InstanceMethods
  12 + end
12 13
13   - has_many :settings, as: :resource
  14 + module ClassMethods
14 15
15   - accepts_nested_attributes_for :settings
  16 + attr_reader :available_settings
16 17
17   - def has_setting?(key)
18   - !setting(key).nil?
  18 + def setting(key, options = {})
  19 + # Inject the association for the settings if this is the first setting loaded for the class
  20 + unless self.reflect_on_association(:settings)
  21 + has_many :settings, as: :resource
  22 + accepts_nested_attributes_for :settings
19 23 end
20 24
21   - def setting(key)
22   - (settings.loaded? ? settings.select{|s| s.key == key} : settings.where(key: key.to_s)).first.value rescue nil
  25 + @available_settings ||= {}
  26 + @available_settings[key] = options unless available_settings.has_key?(key)
  27 +
  28 + define_method key do
  29 + send("find_#{key}").value rescue nil
23 30 end
24 31
25   - def update_setting(key, value)
26   - (settings.loaded? ? settings.select{|s| s.key == key} : settings.where(key: key.to_s)).first.update_attribute(:value, value)
  32 + define_method "find_#{key}" do
  33 + settings.loaded? ? settings.select{|s| s.key == key} : settings.find_by_key(key)
27 34 end
28 35
29   - # Need to do an eval %() because of the following error:
30   - # super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later
31   - eval %(
32   - def method_missing(method_id, *arguments, &block)
33   - unless method_id =~ /id$/ || method_id =~ /^_/ || method_id == :to_ary
34   - s = setting(method_id)
35   - s.nil? ? super : s
36   - else
37   - super
38   - end
39   - end
40   - )
41   - end
42   - end
  36 + define_method "has_#{key}?" do
  37 + send(key).present?
  38 + end
43 39
44   - module ModelClassMethods
  40 + define_method "update_#{key}!" do |value|
  41 + send("find_#{key}").update_attribute(:value, value) if options[:editable]
  42 + end
  43 + end
45 44
46 45 def update_settings!
47   - setting_keys = first.settings.collect(&:key)
48   - class_settings = name.constantize::SETTINGS
49   - (class_settings.keys - setting_keys).each do |new_key|
50   - editable = class_settings[new_key][:editable]
51   - all.each {|object| object.settings.create(key: new_key, value: class_settings[new_key][:default], editable: editable.nil? ? true : editable)}
  46 + # Need to say "`key`" instead of :key because Arel doesn't quote the column name
  47 + existing_settings = first.settings.pluck("`key`")
  48 + (available_settings.keys - existing_settings).each do |new_key|
  49 + all.each {|object| object.settings.create(key: new_key, value: available_settings[new_key][:default])}
52 50 end
53 51 end
54 52
55 53 end
56 54
  55 + module InstanceMethods
  56 +
  57 + def editable_settings
  58 + settings.where(key: self.class.available_settings.select{|k,v| v[:editable]}.keys)
  59 + end
  60 +
  61 + end
  62 +
57 63 end
  64 +
  65 +# Add Settings capabilities to ActiveRecord
  66 +ActiveRecord::Base.send :include, Settings
0  config/initializers/validation_display_order.rb → lib/validation_display_order.rb
File renamed without changes

0 comments on commit 5aa596d

Please sign in to comment.
Something went wrong with that request. Please try again.