formotion 0.0.3 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +6 -0
- data/LIST_OF_ROW_TYPES.md +163 -0
- data/NEW_ROW_TYPES.md +73 -0
- data/README.md +11 -14
- data/Rakefile +6 -0
- data/app/app_delegate.rb +22 -0
- data/examples/KitchenSink/Rakefile +1 -1
- data/examples/KitchenSink/app/app_delegate.rb +50 -2
- data/examples/Login/.gitignore +5 -0
- data/examples/Login/Rakefile +9 -0
- data/examples/Login/app/app_delegate.rb +16 -0
- data/examples/Login/app/login_controller.rb +47 -0
- data/examples/Login/app/user_controller.rb +38 -0
- data/examples/Login/spec/main_spec.rb +9 -0
- data/lib/formotion.rb +7 -1
- data/lib/formotion/{form.rb → form/form.rb} +0 -0
- data/lib/formotion/{form_delegate.rb → form/form_delegate.rb} +10 -15
- data/lib/formotion/patch/object.rb +9 -0
- data/lib/formotion/patch/ui_action_sheet.rb +27 -0
- data/lib/formotion/patch/ui_text_view.rb +122 -0
- data/lib/formotion/patch/ui_text_view_placeholder.rb +65 -0
- data/lib/formotion/{row.rb → row/row.rb} +37 -27
- data/lib/formotion/row/row_cell_builder.rb +28 -0
- data/lib/formotion/row_type/base.rb +41 -0
- data/lib/formotion/row_type/check_row.rb +30 -0
- data/lib/formotion/row_type/date_row.rb +61 -0
- data/lib/formotion/row_type/email_row.rb +11 -0
- data/lib/formotion/row_type/image_row.rb +99 -0
- data/lib/formotion/row_type/number_row.rb +11 -0
- data/lib/formotion/row_type/options_row.rb +24 -0
- data/lib/formotion/row_type/phone_row.rb +11 -0
- data/lib/formotion/row_type/row_type.rb +21 -0
- data/lib/formotion/row_type/slider_row.rb +43 -0
- data/lib/formotion/row_type/static_row.rb +6 -0
- data/lib/formotion/row_type/string_row.rb +112 -0
- data/lib/formotion/row_type/submit_row.rb +34 -0
- data/lib/formotion/row_type/switch_row.rb +19 -0
- data/lib/formotion/row_type/text_row.rb +76 -0
- data/lib/formotion/{section.rb → section/section.rb} +3 -0
- data/lib/formotion/version.rb +1 -1
- data/spec/form_spec.rb +5 -4
- data/spec/functional/character_spec.rb +70 -0
- data/spec/functional/check_row_spec.rb +42 -0
- data/spec/functional/date_row_spec.rb +63 -0
- data/spec/functional/image_row_spec.rb +82 -0
- data/spec/functional/options_row_spec.rb +27 -0
- data/spec/functional/slider_row_spec.rb +27 -0
- data/spec/functional/submit_row_spec.rb +30 -0
- data/spec/functional/switch_row_spec.rb +28 -0
- data/spec/functional/text_row_spec.rb +60 -0
- data/spec/row_type/check_spec.rb +27 -0
- data/spec/row_type/date_spec.rb +69 -0
- data/spec/row_type/email_spec.rb +22 -0
- data/spec/row_type/image_spec.rb +43 -0
- data/spec/row_type/number_spec.rb +22 -0
- data/spec/row_type/options_spec.rb +37 -0
- data/spec/row_type/phone_spec.rb +22 -0
- data/spec/row_type/slider_spec.rb +47 -0
- data/spec/row_type/static_spec.rb +15 -0
- data/spec/row_type/string_spec.rb +52 -0
- data/spec/row_type/submit_spec.rb +28 -0
- data/spec/row_type/switch_spec.rb +27 -0
- data/spec/row_type/text_spec.rb +41 -0
- data/spec/support/ui_control_wrap_extension.rb +7 -0
- metadata +88 -9
- data/lib/formotion/row_cell_builder.rb +0 -168
- data/lib/formotion/row_type.rb +0 -33
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            #################
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Formotion::RowCellBuilder
         | 
| 4 | 
            +
            # RowCellBuilder handles taking Formotion::Rows
         | 
| 5 | 
            +
            # and configuring UITableViewCells based on their properties.
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #################
         | 
| 8 | 
            +
            module Formotion
         | 
| 9 | 
            +
              class RowCellBuilder
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                # PARAMS row.is_a? Formotion::Row
         | 
| 12 | 
            +
                # RETURNS [cell configured to that row, a UITextField for that row if applicable or nil]
         | 
| 13 | 
            +
                def self.make_cell(row)
         | 
| 14 | 
            +
                  cell, text_field = nil
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  cell = UITableViewCell.alloc.initWithStyle(row.object.cell_style, reuseIdentifier:row.reuse_identifier)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  cell.accessoryType = UITableViewCellAccessoryNone
         | 
| 19 | 
            +
                  cell.textLabel.text = row.title
         | 
| 20 | 
            +
                  cell.detailTextLabel.text = row.subtitle
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  edit_field = row.object.build_cell(cell)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  [cell, edit_field]
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class Base
         | 
| 4 | 
            +
                  attr_accessor :row, :tableView
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def tableView
         | 
| 7 | 
            +
                    @tableView ||= self.row.form.table
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def initialize(row)
         | 
| 11 | 
            +
                    @row = row
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def submit_button?
         | 
| 15 | 
            +
                    false
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # RowCellBuilder uses this to instantiate the UITableViewCell.
         | 
| 19 | 
            +
                  def cell_style
         | 
| 20 | 
            +
                    UITableViewCellStyleSubtitle
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  # builder method for row cell specific implementation
         | 
| 24 | 
            +
                  def build_cell(cell)
         | 
| 25 | 
            +
                    # implement in row class
         | 
| 26 | 
            +
                    nil
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  # called by the Row after all the setup and connections are made
         | 
| 30 | 
            +
                  # in #make_cell
         | 
| 31 | 
            +
                  def after_build(cell)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  # method gets triggered when tableView(tableView, didSelectRowAtIndexPath:indexPath)
         | 
| 35 | 
            +
                  # in UITableViewDelegate is executed
         | 
| 36 | 
            +
                  def on_select(tableView, tableViewDelegate)
         | 
| 37 | 
            +
                    # implement in row class
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class CheckRow < Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  # This is actually called whenever again cell is checked/unchecked
         | 
| 6 | 
            +
                  # in the UITableViewDelegate callbacks. So (for now) don't
         | 
| 7 | 
            +
                  # instantiate long-lived objects in them.
         | 
| 8 | 
            +
                  # Maybe that logic should be moved elsewhere?
         | 
| 9 | 
            +
                  def build_cell(cell)
         | 
| 10 | 
            +
                    cell.accessoryType = row.value ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone
         | 
| 11 | 
            +
                    nil
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def on_select(tableView, tableViewDelegate)
         | 
| 15 | 
            +
                    if row.section.select_one and !row.value
         | 
| 16 | 
            +
                      row.section.rows.each do |other_row|
         | 
| 17 | 
            +
                        other_row.value = (other_row == row)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                        cell = tableView.cellForRowAtIndexPath(other_row.index_path)
         | 
| 20 | 
            +
                        other_row.object.build_cell(cell) if cell
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                    elsif !row.section.select_one
         | 
| 23 | 
            +
                      row.value = !row.value
         | 
| 24 | 
            +
                      build_cell(tableView.cellForRowAtIndexPath(row.index_path))
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class DateRow < StringRow
         | 
| 4 | 
            +
                  # overwrite Character on_change method
         | 
| 5 | 
            +
                  def on_change(text_field)
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def update
         | 
| 9 | 
            +
                    self.row.text_field && self.row.text_field.text = self.formatted_value
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def date_value
         | 
| 13 | 
            +
                    value = self.row.value
         | 
| 14 | 
            +
                    if value.is_a? Numeric
         | 
| 15 | 
            +
                      NSDate.dateWithTimeIntervalSince1970(value.to_i)
         | 
| 16 | 
            +
                    else
         | 
| 17 | 
            +
                      nil
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def formatter
         | 
| 22 | 
            +
                    @formatter ||= begin
         | 
| 23 | 
            +
                      formatter = NSDateFormatter.new
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                      date_style = self.row.format
         | 
| 26 | 
            +
                      if date_style && date_style.to_s[-5..-1] != "style"
         | 
| 27 | 
            +
                        date_style = (date_style.to_s + "_style").to_sym
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                      formatter.dateStyle = self.row.send(:const_int_get, "NSDateFormatter", date_style || NSDateFormatterShortStyle)
         | 
| 30 | 
            +
                      formatter
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def formatted_value
         | 
| 35 | 
            +
                    return formatter.stringFromDate(self.date_value) if self.date_value
         | 
| 36 | 
            +
                    self.row.value
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def after_build(cell)
         | 
| 40 | 
            +
                    self.row.text_field.inputView = self.picker
         | 
| 41 | 
            +
                    update
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def picker
         | 
| 45 | 
            +
                    @picker ||= begin
         | 
| 46 | 
            +
                      picker = UIDatePicker.alloc.initWithFrame(CGRectZero)
         | 
| 47 | 
            +
                      picker.datePickerMode = UIDatePickerModeDate
         | 
| 48 | 
            +
                      picker.hidden = false
         | 
| 49 | 
            +
                      picker.date = self.date_value || NSDate.date
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      picker.when(UIControlEventValueChanged) do
         | 
| 52 | 
            +
                        self.row.value = @picker.date.timeIntervalSince1970.to_i
         | 
| 53 | 
            +
                        update
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                      picker
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| @@ -0,0 +1,99 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class ImageRow < Base
         | 
| 4 | 
            +
                  include BW::KVO
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  IMAGE_VIEW_TAG=1100
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def build_cell(cell)
         | 
| 9 | 
            +
                    add_plus_accessory(cell)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    observe(self.row, "value") do |old_value, new_value|
         | 
| 12 | 
            +
                      @image_view.image = new_value
         | 
| 13 | 
            +
                      if new_value
         | 
| 14 | 
            +
                        self.row.rowHeight = 200
         | 
| 15 | 
            +
                        cell.accessoryView = nil
         | 
| 16 | 
            +
                      else
         | 
| 17 | 
            +
                        self.row.rowHeight = 44
         | 
| 18 | 
            +
                        add_plus_accessory(cell)
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                      row.form.reload_data
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    @image_view = UIImageView.alloc.init
         | 
| 24 | 
            +
                    @image_view.image = row.value if row.value
         | 
| 25 | 
            +
                    @image_view.tag = IMAGE_VIEW_TAG
         | 
| 26 | 
            +
                    @image_view.contentMode = UIViewContentModeScaleAspectFit
         | 
| 27 | 
            +
                    @image_view.backgroundColor = UIColor.clearColor
         | 
| 28 | 
            +
                    cell.addSubview(@image_view)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    cell.swizzle(:layoutSubviews) do
         | 
| 31 | 
            +
                      def layoutSubviews
         | 
| 32 | 
            +
                        old_layoutSubviews
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                        # viewWithTag is terrible, but I think it's ok to use here...
         | 
| 35 | 
            +
                        formotion_field = self.viewWithTag(IMAGE_VIEW_TAG)
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        field_frame = formotion_field.frame
         | 
| 38 | 
            +
                        field_frame.origin.y = 10
         | 
| 39 | 
            +
                        field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + 20
         | 
| 40 | 
            +
                        field_frame.size.width  = self.frame.size.width - field_frame.origin.x - 20
         | 
| 41 | 
            +
                        field_frame.size.height = self.frame.size.height - 20
         | 
| 42 | 
            +
                        formotion_field.frame = field_frame
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def on_select(tableView, tableViewDelegate)
         | 
| 48 | 
            +
                    @action_sheet = UIActionSheet.alloc.init
         | 
| 49 | 
            +
                    @action_sheet.delegate = self
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    @action_sheet.destructiveButtonIndex = (@action_sheet.addButtonWithTitle "Delete") if row.value
         | 
| 52 | 
            +
                    @action_sheet.addButtonWithTitle "Take" if BW::Device.camera.front? or BW::Device.camera.rear?
         | 
| 53 | 
            +
                    @action_sheet.addButtonWithTitle "Choose"
         | 
| 54 | 
            +
                    @action_sheet.cancelButtonIndex = (@action_sheet.addButtonWithTitle "Cancel")
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    @action_sheet.showInView @image_view
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def actionSheet actionSheet, clickedButtonAtIndex: index
         | 
| 60 | 
            +
                    source = nil
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    if index == actionSheet.destructiveButtonIndex
         | 
| 63 | 
            +
                      row.value = nil
         | 
| 64 | 
            +
                      return
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    case actionSheet.buttonTitleAtIndex(index)
         | 
| 68 | 
            +
                    when "Take"
         | 
| 69 | 
            +
                      source = :camera
         | 
| 70 | 
            +
                    when "Choose"
         | 
| 71 | 
            +
                      source = :photo_library
         | 
| 72 | 
            +
                    when "Cancel"
         | 
| 73 | 
            +
                    else
         | 
| 74 | 
            +
                      p "Unrecognized button title #{actionSheet.buttonTitleAtIndex(index)}"
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    if source
         | 
| 78 | 
            +
                      @camera = BW::Device.camera.any
         | 
| 79 | 
            +
                      @camera.picture(source_type: source, media_types: [:image]) do |result|
         | 
| 80 | 
            +
                        if result[:original_image]
         | 
| 81 | 
            +
                          row.value = result[:original_image]
         | 
| 82 | 
            +
                        end
         | 
| 83 | 
            +
                      end
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def add_plus_accessory(cell)
         | 
| 88 | 
            +
                    @add_button ||= begin
         | 
| 89 | 
            +
                      button = UIButton.buttonWithType(UIButtonTypeContactAdd)
         | 
| 90 | 
            +
                      button.when(UIControlEventTouchUpInside) do
         | 
| 91 | 
            +
                        self.on_select(nil, nil)
         | 
| 92 | 
            +
                      end
         | 
| 93 | 
            +
                      button
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
                    cell.accessoryView = @add_button
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class OptionsRow < Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  SLIDER_VIEW_TAG = 1200
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def build_cell(cell)
         | 
| 8 | 
            +
                    cell.selectionStyle = UITableViewCellSelectionStyleNone
         | 
| 9 | 
            +
                    slideView = UISegmentedControl.alloc.initWithItems(row.items || [])
         | 
| 10 | 
            +
                    slideView.selectedSegmentIndex = row.items.index(row.value) if row.value
         | 
| 11 | 
            +
                    slideView.segmentedControlStyle = UISegmentedControlStyleBar
         | 
| 12 | 
            +
                    cell.accessoryView = slideView
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    slideView.when(UIControlEventValueChanged) do
         | 
| 15 | 
            +
                      row.value = row.items[slideView.selectedSegmentIndex]
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    nil
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                ROW_TYPES = Formotion::RowType.constants(false).select { |constant_name| constant_name =~ /Row$/ }
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class << self
         | 
| 6 | 
            +
                  def for(string_or_sym)
         | 
| 7 | 
            +
                    type = string_or_sym
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    if type.is_a?(Symbol) or type.is_a? String
         | 
| 10 | 
            +
                      string = "#{type.to_s.downcase}_row".camelize
         | 
| 11 | 
            +
                      if not const_defined? string
         | 
| 12 | 
            +
                        raise Formotion::InvalidClassError, "Invalid RowType value #{string_or_sym}. Create a class called #{string}"
         | 
| 13 | 
            +
                      end
         | 
| 14 | 
            +
                      Formotion::RowType.const_get(string)
         | 
| 15 | 
            +
                    else
         | 
| 16 | 
            +
                      raise Formotion::InvalidClassError, "Attempted row type #{type.inspect} is not a valid RowType."
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class SliderRow < Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  SLIDER_VIEW_TAG = 1200
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def build_cell(cell)
         | 
| 8 | 
            +
                    cell.selectionStyle = UITableViewCellSelectionStyleNone
         | 
| 9 | 
            +
                    slideView = UISlider.alloc.initWithFrame(CGRectZero)
         | 
| 10 | 
            +
                    cell.accessoryView = slideView
         | 
| 11 | 
            +
                    row.range ||= (1..10)
         | 
| 12 | 
            +
                    slideView.minimumValue = row.range.first
         | 
| 13 | 
            +
                    slideView.maximumValue = row.range.last
         | 
| 14 | 
            +
                    slideView.tag = SLIDER_VIEW_TAG
         | 
| 15 | 
            +
                    slideView.setValue(row.value, animated:true) if row.value
         | 
| 16 | 
            +
                    slideView.accessibilityLabel = row.title + " Slider"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    slideView.when(UIControlEventValueChanged) do
         | 
| 19 | 
            +
                      row.value = slideView.value
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    cell.swizzle(:layoutSubviews) do
         | 
| 23 | 
            +
                      def layoutSubviews
         | 
| 24 | 
            +
                        old_layoutSubviews
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                        # viewWithTag is terrible, but I think it's ok to use here...
         | 
| 27 | 
            +
                        formotion_field = self.viewWithTag(SLIDER_VIEW_TAG)
         | 
| 28 | 
            +
                        formotion_field.sizeToFit
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                        field_frame = formotion_field.frame
         | 
| 31 | 
            +
                        field_frame.origin.y = 10
         | 
| 32 | 
            +
                        field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + 20
         | 
| 33 | 
            +
                        field_frame.size.width  = self.frame.size.width - field_frame.origin.x - 20
         | 
| 34 | 
            +
                        field_frame.size.height = self.frame.size.height - 20
         | 
| 35 | 
            +
                        formotion_field.frame = field_frame
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                    nil
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            module Formotion
         | 
| 2 | 
            +
              module RowType
         | 
| 3 | 
            +
                class StringRow < Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  # The new UITextField in a UITableViewCell
         | 
| 6 | 
            +
                  # will be assigned this tag, if applicable.
         | 
| 7 | 
            +
                  TEXT_FIELD_TAG=1000
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def keyboardType
         | 
| 10 | 
            +
                    UIKeyboardTypeDefault
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  # Configures the cell to have a new UITextField
         | 
| 14 | 
            +
                  # which is used to enter data. Consists of
         | 
| 15 | 
            +
                  # 1) setting up that field with the appropriate properties
         | 
| 16 | 
            +
                  # specified by `row` 2) configures the callbacks on the field
         | 
| 17 | 
            +
                  # to call any callbacks `row` listens for.
         | 
| 18 | 
            +
                  # Also does the layoutSubviews swizzle trick
         | 
| 19 | 
            +
                  # to size the UITextField so it won't bump into the titleLabel.
         | 
| 20 | 
            +
                  def build_cell(cell)
         | 
| 21 | 
            +
                    field = UITextField.alloc.initWithFrame(CGRectZero)
         | 
| 22 | 
            +
                    field.tag = TEXT_FIELD_TAG
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    field.placeholder = row.placeholder
         | 
| 25 | 
            +
                    field.text = row.value.to_s
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    field.clearButtonMode = UITextFieldViewModeWhileEditing
         | 
| 28 | 
            +
                    field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
         | 
| 29 | 
            +
                    field.textAlignment = UITextAlignmentRight
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    field.keyboardType = keyboardType
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    field.secureTextEntry = true if row.secure?
         | 
| 34 | 
            +
                    field.returnKeyType = row.return_key || UIReturnKeyNext
         | 
| 35 | 
            +
                    field.autocapitalizationType = row.auto_capitalization if row.auto_capitalization
         | 
| 36 | 
            +
                    field.autocorrectionType = row.auto_correction if row.auto_correction
         | 
| 37 | 
            +
                    field.clearButtonMode = row.clear_button || UITextFieldViewModeWhileEditing
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    add_callbacks(field)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    cell.swizzle(:layoutSubviews) do
         | 
| 42 | 
            +
                      def layoutSubviews
         | 
| 43 | 
            +
                        old_layoutSubviews
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                        # viewWithTag is terrible, but I think it's ok to use here...
         | 
| 46 | 
            +
                        formotion_field = self.viewWithTag(TEXT_FIELD_TAG)
         | 
| 47 | 
            +
                        formotion_field.sizeToFit
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        field_frame = formotion_field.frame
         | 
| 50 | 
            +
                        field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + 20
         | 
| 51 | 
            +
                        field_frame.origin.y = ((self.frame.size.height - field_frame.size.height) / 2.0).round
         | 
| 52 | 
            +
                        field_frame.size.width = self.frame.size.width - field_frame.origin.x - 20
         | 
| 53 | 
            +
                        formotion_field.frame = field_frame
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    cell.addSubview(field)
         | 
| 58 | 
            +
                    field
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def add_callbacks(field)
         | 
| 63 | 
            +
                    if row.on_enter_callback
         | 
| 64 | 
            +
                      field.should_return? do |text_field|
         | 
| 65 | 
            +
                        if row.on_enter_callback.arity == 0
         | 
| 66 | 
            +
                          row.on_enter_callback.call
         | 
| 67 | 
            +
                        elsif row.on_enter_callback.arity == 1
         | 
| 68 | 
            +
                          row.on_enter_callback.call(row)
         | 
| 69 | 
            +
                        end
         | 
| 70 | 
            +
                        false
         | 
| 71 | 
            +
                      end
         | 
| 72 | 
            +
                    elsif field.returnKeyType == UIReturnKeyDone
         | 
| 73 | 
            +
                      field.should_return? do |text_field|
         | 
| 74 | 
            +
                        text_field.resignFirstResponder
         | 
| 75 | 
            +
                        false
         | 
| 76 | 
            +
                      end
         | 
| 77 | 
            +
                    else
         | 
| 78 | 
            +
                      field.should_return? do |text_field|
         | 
| 79 | 
            +
                        if row.next_row && row.next_row.text_field
         | 
| 80 | 
            +
                          row.next_row.text_field.becomeFirstResponder
         | 
| 81 | 
            +
                        else
         | 
| 82 | 
            +
                          text_field.resignFirstResponder
         | 
| 83 | 
            +
                        end
         | 
| 84 | 
            +
                        true
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    field.on_begin do |text_field|
         | 
| 89 | 
            +
                      row.on_begin_callback && row.on_begin_callback.call
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    field.should_begin? do |text_field|
         | 
| 93 | 
            +
                      row.section.form.active_row = row
         | 
| 94 | 
            +
                      true
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    field.on_change do |text_field|
         | 
| 98 | 
            +
                      on_change(text_field)
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  def on_change(text_field)
         | 
| 103 | 
            +
                    row.value = text_field.text
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  def on_select(tableView, tableViewDelegate)
         | 
| 107 | 
            +
                    row.text_field.becomeFirstResponder
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
            end
         |