formotion 0.5.1 → 1.0
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/CHANGELOG.md +24 -0
- data/LIST_OF_ROW_TYPES.md +1 -1
- data/Rakefile +20 -5
- data/app/app_delegate.rb +89 -17
- data/examples/FormModel/.gitignore +5 -0
- data/examples/FormModel/Rakefile +9 -0
- data/examples/FormModel/app/app_delegate.rb +11 -0
- data/examples/FormModel/app/user.rb +18 -0
- data/examples/FormModel/app/users_controller.rb +52 -0
- data/examples/FormModel/spec/main_spec.rb +9 -0
- data/examples/KitchenSink/app/app_delegate.rb +2 -2
- data/gh-pages/assets/css/bootstrap-responsive.css +815 -0
- data/gh-pages/assets/css/bootstrap-responsive.min.css +9 -0
- data/gh-pages/assets/css/bootstrap.css +4983 -0
- data/gh-pages/assets/css/bootstrap.min.css +9 -0
- data/gh-pages/assets/css/formotion.css +117 -0
- data/gh-pages/assets/css/pygments.css +62 -0
- data/gh-pages/assets/img/glyphicons-halflings-white.png +0 -0
- data/gh-pages/assets/img/glyphicons-halflings.png +0 -0
- data/gh-pages/assets/js/bootstrap-alert.js +90 -0
- data/gh-pages/assets/js/bootstrap-button.js +96 -0
- data/gh-pages/assets/js/bootstrap-carousel.js +169 -0
- data/gh-pages/assets/js/bootstrap-collapse.js +157 -0
- data/gh-pages/assets/js/bootstrap-dropdown.js +100 -0
- data/gh-pages/assets/js/bootstrap-modal.js +218 -0
- data/gh-pages/assets/js/bootstrap-popover.js +98 -0
- data/gh-pages/assets/js/bootstrap-scrollspy.js +151 -0
- data/gh-pages/assets/js/bootstrap-tab.js +135 -0
- data/gh-pages/assets/js/bootstrap-tooltip.js +275 -0
- data/gh-pages/assets/js/bootstrap-transition.js +61 -0
- data/gh-pages/assets/js/bootstrap-typeahead.js +285 -0
- data/gh-pages/assets/js/bootstrap.js +1825 -0
- data/gh-pages/assets/js/bootstrap.min.js +6 -0
- data/gh-pages/index.html +205 -0
- data/lib/formotion.rb +15 -2
- data/lib/formotion/base.rb +5 -5
- data/lib/formotion/{form_controller.rb → controller/form_controller.rb} +22 -3
- data/lib/formotion/controller/formable_controller.rb +21 -0
- data/lib/formotion/form/form.rb +31 -8
- data/lib/formotion/form/form_delegate.rb +26 -3
- data/lib/formotion/model/formable.rb +78 -0
- data/lib/formotion/row/row.rb +54 -21
- data/lib/formotion/row/row_cell_builder.rb +1 -1
- data/lib/formotion/row_type/back_row.rb +11 -0
- data/lib/formotion/row_type/base.rb +42 -1
- data/lib/formotion/row_type/button.rb +30 -0
- data/lib/formotion/row_type/check_row.rb +9 -5
- data/lib/formotion/row_type/date_row.rb +5 -0
- data/lib/formotion/row_type/edit_row.rb +14 -0
- data/lib/formotion/row_type/image_row.rb +7 -7
- data/lib/formotion/row_type/options_row.rb +18 -8
- data/lib/formotion/row_type/slider_row.rb +14 -5
- data/lib/formotion/row_type/string_row.rb +17 -5
- data/lib/formotion/row_type/subform_row.rb +16 -0
- data/lib/formotion/row_type/submit_row.rb +1 -24
- data/lib/formotion/row_type/switch_row.rb +10 -2
- data/lib/formotion/row_type/template_row.rb +77 -0
- data/lib/formotion/row_type/text_row.rb +12 -4
- data/lib/formotion/section/section.rb +9 -1
- data/lib/formotion/version.rb +1 -1
- data/spec/form_spec.rb +24 -0
- data/spec/formable_spec.rb +100 -0
- data/spec/functional/formable_controller_spec.rb +47 -0
- data/spec/functional/image_row_spec.rb +2 -2
- data/spec/functional/subform_row.rb +33 -0
- data/spec/functional/template_row_spec.rb +57 -0
- data/spec/helpers/row_test_helpers.rb +26 -0
- data/spec/row_type/back_spec.rb +31 -0
- data/spec/row_type/check_spec.rb +9 -9
- data/spec/row_type/date_spec.rb +3 -10
- data/spec/row_type/email_spec.rb +1 -9
- data/spec/row_type/image_spec.rb +3 -12
- data/spec/row_type/number_spec.rb +1 -9
- data/spec/row_type/options_spec.rb +18 -10
- data/spec/row_type/phone_spec.rb +1 -9
- data/spec/row_type/picker_spec.rb +2 -11
- data/spec/row_type/slider_spec.rb +11 -10
- data/spec/row_type/static_spec.rb +1 -9
- data/spec/row_type/string_spec.rb +13 -9
- data/spec/row_type/subform_spec.rb +47 -0
- data/spec/row_type/submit_spec.rb +1 -9
- data/spec/row_type/switch_spec.rb +9 -9
- data/spec/row_type/template_spec.rb +14 -0
- data/spec/row_type/text_spec.rb +9 -9
- metadata +58 -6
@@ -0,0 +1,6 @@
|
|
1
|
+
/*!
|
2
|
+
* Bootstrap.js by @fat & @mdo
|
3
|
+
* Copyright 2012 Twitter, Inc.
|
4
|
+
* http://www.apache.org/licenses/LICENSE-2.0.txt
|
5
|
+
*/
|
6
|
+
!function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var b=a(this),c=b.data("target")||b.attr("href"),d=/^#\w/.test(c)&&a(c);return d&&c.length&&[[d.position().top,c]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu")&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery);
|
data/gh-pages/index.html
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Formotion</title>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<meta name="description" content="">
|
8
|
+
<meta name="author" content="">
|
9
|
+
|
10
|
+
<!-- Le styles -->
|
11
|
+
<link href="assets/css/bootstrap.min.css" rel="stylesheet">
|
12
|
+
<style>
|
13
|
+
body {
|
14
|
+
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
15
|
+
}
|
16
|
+
</style>
|
17
|
+
<link href="assets/css/bootstrap-responsive.min.css" rel="stylesheet">
|
18
|
+
<link href="assets/css/pygments.css" rel="stylesheet">
|
19
|
+
<link href="assets/css/formotion.css" rel="stylesheet">
|
20
|
+
|
21
|
+
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
22
|
+
<!--[if lt IE 9]>
|
23
|
+
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
24
|
+
<![endif]-->
|
25
|
+
|
26
|
+
<!-- Le fav and touch icons -->
|
27
|
+
</head>
|
28
|
+
|
29
|
+
<body>
|
30
|
+
<a id="fork-me" href="https://github.com/clayallsopp/formotion" target="_blank">Fork me on GitHub</a>
|
31
|
+
|
32
|
+
<div class="container">
|
33
|
+
|
34
|
+
<div class="hero-unit">
|
35
|
+
<h1><span><a href="http://github.com/clayallsopp/formotion" id="formotion" class="no-decoration">Formotion</a> </span><small>for RubyMotion</small></h1>
|
36
|
+
<p>Painless, productive views on iOS.</p>
|
37
|
+
<iframe src="http://ghbtns.com/github-btn.html?user=clayallsopp&repo=formotion&type=watch&count=true&size=large" allowtransparency="true" frameborder="0" scrolling="0" width="150px" height="30px"></iframe>
|
38
|
+
<iframe src="http://ghbtns.com/github-btn.html?user=clayallsopp&repo=formotion&type=fork&count=true&&size=large" allowtransparency="true" frameborder="0" scrolling="0" width="170px" height="30px"></iframe>
|
39
|
+
</div>
|
40
|
+
|
41
|
+
<div class="row">
|
42
|
+
<div class="span4">
|
43
|
+
<h2>Construct UI...</h2>
|
44
|
+
<img src="http://i.imgur.com/TMwXI.png" alt="Complex data form">
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<div class="span8">
|
48
|
+
<h2>...With A Hash</h2>
|
49
|
+
<div class="highlight"><pre class='codehilite'><code class="ruby syntax"><span class="vi">@form</span> <span class="o">=</span> <span class="no">Formotion</span><span class="o">::</span><span class="no">Form</span><span class="o">.</span><span class="n">new</span><span class="p">({</span>
|
50
|
+
<span class="n">sections</span><span class="p">:</span> <span class="o">[</span><span class="p">{</span>
|
51
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Register"</span><span class="p">,</span>
|
52
|
+
<span class="n">rows</span><span class="p">:</span> <span class="o">[</span><span class="p">{</span>
|
53
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Email"</span><span class="p">,</span>
|
54
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:email</span><span class="p">,</span>
|
55
|
+
<span class="n">placeholder</span><span class="p">:</span> <span class="s2">"me@mail.com"</span><span class="p">,</span>
|
56
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:email</span><span class="p">,</span>
|
57
|
+
<span class="n">auto_correction</span><span class="p">:</span> <span class="ss">:no</span><span class="p">,</span>
|
58
|
+
<span class="n">auto_capitalization</span><span class="p">:</span> <span class="ss">:none</span>
|
59
|
+
<span class="p">},</span> <span class="p">{</span>
|
60
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Password"</span><span class="p">,</span>
|
61
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:password</span><span class="p">,</span>
|
62
|
+
<span class="n">placeholder</span><span class="p">:</span> <span class="s2">"required"</span><span class="p">,</span>
|
63
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span>
|
64
|
+
<span class="n">secure</span><span class="p">:</span> <span class="kp">true</span>
|
65
|
+
<span class="p">},</span> <span class="p">{</span>
|
66
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Password"</span><span class="p">,</span>
|
67
|
+
<span class="n">subtitle</span><span class="p">:</span> <span class="s2">"Confirmation"</span><span class="p">,</span>
|
68
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:confirm</span><span class="p">,</span>
|
69
|
+
<span class="n">placeholder</span><span class="p">:</span> <span class="s2">"required"</span><span class="p">,</span>
|
70
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span>
|
71
|
+
<span class="n">secure</span><span class="p">:</span> <span class="kp">true</span>
|
72
|
+
<span class="p">},</span> <span class="p">{</span>
|
73
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Remember?"</span><span class="p">,</span>
|
74
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:remember</span><span class="p">,</span>
|
75
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:switch</span><span class="p">,</span>
|
76
|
+
<span class="p">}</span><span class="o">]</span>
|
77
|
+
<span class="p">},</span> <span class="p">{</span>
|
78
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Account Type"</span><span class="p">,</span>
|
79
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:account_type</span><span class="p">,</span>
|
80
|
+
<span class="n">select_one</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span>
|
81
|
+
<span class="n">rows</span><span class="p">:</span> <span class="o">[</span><span class="p">{</span>
|
82
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Free"</span><span class="p">,</span>
|
83
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:free</span><span class="p">,</span>
|
84
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:check</span><span class="p">,</span>
|
85
|
+
<span class="p">},</span> <span class="p">{</span>
|
86
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Basic"</span><span class="p">,</span>
|
87
|
+
<span class="n">value</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span>
|
88
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:basic</span><span class="p">,</span>
|
89
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:check</span><span class="p">,</span>
|
90
|
+
<span class="p">},</span> <span class="p">{</span>
|
91
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Pro"</span><span class="p">,</span>
|
92
|
+
<span class="n">key</span><span class="p">:</span> <span class="ss">:pro</span><span class="p">,</span>
|
93
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:check</span><span class="p">,</span>
|
94
|
+
<span class="p">}</span><span class="o">]</span>
|
95
|
+
<span class="p">},</span> <span class="p">{</span>
|
96
|
+
<span class="n">rows</span><span class="p">:</span> <span class="o">[</span><span class="p">{</span>
|
97
|
+
<span class="n">title</span><span class="p">:</span> <span class="s2">"Sign Up"</span><span class="p">,</span>
|
98
|
+
<span class="n">type</span><span class="p">:</span> <span class="ss">:submit</span><span class="p">,</span>
|
99
|
+
<span class="p">}</span><span class="o">]</span>
|
100
|
+
<span class="p">}</span><span class="o">]</span>
|
101
|
+
<span class="p">})</span>
|
102
|
+
|
103
|
+
<span class="o">.</span><span class="n">.</span><span class="o">.</span>
|
104
|
+
|
105
|
+
<span class="vi">@form_controller</span> <span class="o">=</span> <span class="no">Formotion<span class="o">::</span>FormController</span><span class="o">.</span><span class="n">alloc</span><span class="o">.</span><span class="n">initWithForm</span><span class="p">(</span><span class="vi">@form</span><span class="p">)</span>
|
106
|
+
<span class="vi">@window</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="vi">@form_controller</span></code></pre>
|
107
|
+
</div>
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
|
111
|
+
<hr />
|
112
|
+
|
113
|
+
<div class="row">
|
114
|
+
<div class="span8">
|
115
|
+
<h2>Sync Models...</h2>
|
116
|
+
<div class="highlight"><pre id="syncmodels" class='codehilite'><code class="ruby syntax"><span class="k">class</span> <span class="nc">User</span>
|
117
|
+
<span class="kp">attr_accessor</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:score</span><span class="p">,</span> <span class="ss">:team</span>
|
118
|
+
|
119
|
+
<span class="kp">include</span> <span class="no">Formotion</span><span class="o">::</span><span class="no">Formable</span>
|
120
|
+
|
121
|
+
<span class="n">form_property</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:string</span>
|
122
|
+
<span class="n">form_property</span> <span class="ss">:score</span><span class="p">,</span> <span class="ss">:number</span><span class="p">,</span> <span class="n">transform</span><span class="p">:</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">value</span><span class="o">|</span> <span class="n">value</span><span class="o">.</span><span class="n">to_i</span> <span class="p">}</span>
|
123
|
+
|
124
|
+
<span class="n">form_property</span> <span class="ss">:team</span><span class="p">,</span> <span class="ss">:picker</span><span class="p">,</span> <span class="n">items</span><span class="p">:</span> <span class="o">[</span><span class="s2">"Red"</span><span class="p">,</span> <span class="s2">"Blue"</span><span class="p">,</span> <span class="s2">"Green"</span><span class="o">]</span>
|
125
|
+
|
126
|
+
<span class="n">form_title</span> <span class="s2">"Edit User"</span>
|
127
|
+
<span class="k">end</span>
|
128
|
+
|
129
|
+
<span class="o">.</span><span class="n">.</span><span class="o">.</span>
|
130
|
+
|
131
|
+
<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"Harry"</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="s2">"Green"</span><span class="p">)</span>
|
132
|
+
<span class="n">controller</span> <span class="o">=</span> <span class="no">Formotion</span><span class="o">::</span><span class="no">FormableController</span><span class="o">.</span><span class="n">alloc</span><span class="o">.</span><span class="n">initWithModel</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
133
|
+
<span class="nb">self</span><span class="o">.</span><span class="n">navigationController</span><span class="o">.</span><span class="n">pushViewController</span><span class="p">(</span><span class="n">controller</span><span class="p">,</span> <span class="n">animated</span><span class="ss">:true</span><span class="p">)</span>
|
134
|
+
</code></pre>
|
135
|
+
</div>
|
136
|
+
</div>
|
137
|
+
|
138
|
+
<div class="span4">
|
139
|
+
<h2>...To A View <small>(KVO)</small></h2>
|
140
|
+
<img src="https://a248.e.akamai.net/camo.github.com/18a55fe6aa9a33235867169a0a98d47ba5d02fe0/687474703a2f2f692e696d6775722e636f6d2f534b5133522e706e67" alt="Complex data form" id="sync-models">
|
141
|
+
</div>
|
142
|
+
</div>
|
143
|
+
|
144
|
+
<hr />
|
145
|
+
|
146
|
+
<div class="row" id="more-container">
|
147
|
+
<div class="span12">
|
148
|
+
<h2 id="andwaymore">And way more:</h2>
|
149
|
+
</div>
|
150
|
+
<div class="span4">
|
151
|
+
<h3>UI Elements</h3>
|
152
|
+
<img src="http://i.imgur.com/BKFIh.png">
|
153
|
+
<hr class="hidden-desktop" />
|
154
|
+
</div>
|
155
|
+
<div class="span4">
|
156
|
+
<h3>Subforms</h3>
|
157
|
+
<img src="http://i.imgur.com/Sfiq1.png" alt="Complex data form">
|
158
|
+
<hr class="hidden-desktop" />
|
159
|
+
</div>
|
160
|
+
<div class="span4">
|
161
|
+
<h3>Templates</h3>
|
162
|
+
<img src="http://i.imgur.com/kwG08.png" alt="Complex data form">
|
163
|
+
<hr class="hidden-desktop" />
|
164
|
+
</div>
|
165
|
+
</div>
|
166
|
+
|
167
|
+
<hr class="hidden-phone" />
|
168
|
+
|
169
|
+
<div class="row">
|
170
|
+
<div class="span12">
|
171
|
+
<div class="well">
|
172
|
+
<h1>Instructions <small><a href="http://github.com/clayallsopp/formotion" class="no-decoration">(full docs)</a></h1>
|
173
|
+
<hr />
|
174
|
+
<div class="row lead">
|
175
|
+
<div class="span3 install-instruct">
|
176
|
+
<h3>1. Install</h3>
|
177
|
+
<code>
|
178
|
+
gem install formotion
|
179
|
+
</code>
|
180
|
+
</div>
|
181
|
+
<div class="span3 install-instruct">
|
182
|
+
<h3>2. Rakefile</h3>
|
183
|
+
<code>
|
184
|
+
require 'formotion'
|
185
|
+
</code>
|
186
|
+
</div>
|
187
|
+
<div class="span5 install-instruct">
|
188
|
+
<h3>2. Use</h3>
|
189
|
+
<div class="highlight"><pre class='codehilite'><code class="ruby syntax"><span class="vi">@form</span> <span class="o">=</span> <span class="no">Formotion</span><span class="o">::</span><span class="no">Form</span><span class="o">.</span><span class="n">new</span><span class="p">({...})</span>
|
190
|
+
|
191
|
+
<span class="vi">@form_controller</span> <span class="o">=</span><br /> <span class="no">Formotion<span class="o">::</span>FormController</span><span class="o">.</span><span class="n">alloc</span><span class="o">.</span><span class="n">initWithForm</span><span class="p">(</span><span class="vi">@form</span><span class="p">)</span>
|
192
|
+
<span class="vi">@window</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="vi">@form_controller</span></code></pre>
|
193
|
+
</div>
|
194
|
+
</div>
|
195
|
+
</div>
|
196
|
+
</div>
|
197
|
+
</div>
|
198
|
+
</div>
|
199
|
+
|
200
|
+
<hr />
|
201
|
+
|
202
|
+
|
203
|
+
</div> <!-- /container -->
|
204
|
+
</body>
|
205
|
+
</html>
|
data/lib/formotion.rb
CHANGED
@@ -3,13 +3,26 @@ require 'bubble-wrap/core'
|
|
3
3
|
require 'bubble-wrap/camera'
|
4
4
|
|
5
5
|
BW.require File.expand_path('../formotion/**/*.rb', __FILE__) do
|
6
|
-
|
6
|
+
base_row_type = 'lib/formotion/row_type/base.rb'
|
7
|
+
|
8
|
+
# hack to make sure base row type is compiled early
|
9
|
+
file('lib/formotion/base.rb').depends_on base_row_type
|
10
|
+
|
11
|
+
row_types = Dir.glob('lib/formotion/row_type/**/*.rb')
|
12
|
+
row_types.each {|file|
|
13
|
+
next if file == base_row_type
|
14
|
+
file(file).depends_on base_row_type
|
15
|
+
}
|
16
|
+
|
7
17
|
['date_row', 'email_row', 'number_row', 'phone_row'].each {|file|
|
8
18
|
file("lib/formotion/row_type/#{file}.rb").depends_on 'lib/formotion/row_type/string_row.rb'
|
9
19
|
}
|
20
|
+
['submit_row', 'back_row'].each {|file|
|
21
|
+
file("lib/formotion/row_type/#{file}.rb").depends_on 'lib/formotion/row_type/button.rb'
|
22
|
+
}
|
10
23
|
|
11
24
|
['form/form.rb', 'row/row.rb', 'section/section.rb'].each {|file|
|
12
25
|
file("lib/formotion/#{file}").depends_on 'lib/formotion/base.rb'
|
13
26
|
}
|
14
|
-
file("lib/formotion/form_controller.rb").depends_on 'lib/formotion/patch/ui_text_field.rb'
|
27
|
+
file("lib/formotion/controller/form_controller.rb").depends_on 'lib/formotion/patch/ui_text_field.rb'
|
15
28
|
end
|
data/lib/formotion/base.rb
CHANGED
@@ -3,7 +3,7 @@ module Formotion
|
|
3
3
|
def initialize(params = {})
|
4
4
|
params.each { |key, value|
|
5
5
|
if self.class.const_get(:PROPERTIES).member? key.to_sym
|
6
|
-
self.send(
|
6
|
+
self.send("#{key}=".to_sym, value)
|
7
7
|
end
|
8
8
|
}
|
9
9
|
end
|
@@ -23,20 +23,20 @@ module Formotion
|
|
23
23
|
encoder.encodeObject(self.send(prop), forKey: prop.to_s)
|
24
24
|
}
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def initWithCoder(decoder)
|
28
28
|
self.init
|
29
29
|
self.class.const_get(:SERIALIZE_PROPERTIES).each {|prop|
|
30
30
|
value = decoder.decodeObjectForKey(prop.to_s)
|
31
|
-
self.send(
|
31
|
+
self.send("#{prop}=".to_sym, value) if not value.nil?
|
32
32
|
}
|
33
33
|
self
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def copyWithZone(zone)
|
37
37
|
copy = self.class.allocWithZone(zone).init
|
38
38
|
self.class.const_get(:SERIALIZE_PROPERTIES).each {|prop|
|
39
|
-
copy.send(
|
39
|
+
copy.send("#{prop}=".to_sym, self.send(prop))
|
40
40
|
}
|
41
41
|
copy
|
42
42
|
end
|
@@ -15,6 +15,8 @@ module Formotion
|
|
15
15
|
def initWithForm(form)
|
16
16
|
self.initWithStyle(UITableViewStyleGrouped)
|
17
17
|
self.form = form
|
18
|
+
#self.view.setEditing true, animated: true
|
19
|
+
self.tableView.allowsSelectionDuringEditing = true
|
18
20
|
self
|
19
21
|
end
|
20
22
|
|
@@ -32,11 +34,9 @@ module Formotion
|
|
32
34
|
def viewDidLoad
|
33
35
|
super
|
34
36
|
|
35
|
-
self.title = self.form.title
|
36
|
-
|
37
37
|
# Triggers this block when the enter key is pressed
|
38
38
|
# while editing the last text field.
|
39
|
-
@form.sections[-1] && @form.sections[-1].rows[-1].on_enter do |row|
|
39
|
+
@form.sections[-1] && @form.sections[-1].rows && @form.sections[-1].rows[-1] && @form.sections[-1].rows[-1].on_enter do |row|
|
40
40
|
if row.text_field
|
41
41
|
@form.submit
|
42
42
|
row.text_field.resignFirstResponder
|
@@ -48,5 +48,24 @@ module Formotion
|
|
48
48
|
# and reloads the data.
|
49
49
|
@form.controller = self
|
50
50
|
end
|
51
|
+
|
52
|
+
# Subview Methods
|
53
|
+
def push_subform(form)
|
54
|
+
@subform_controller = self.class.alloc.initWithForm(form)
|
55
|
+
|
56
|
+
if self.navigationController
|
57
|
+
self.navigationController.pushViewController(@subform_controller, animated: true)
|
58
|
+
else
|
59
|
+
self.presentModalViewController(@subform_controller, animated: true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def pop_subform
|
64
|
+
if self.navigationController
|
65
|
+
self.navigationController.popViewControllerAnimated true
|
66
|
+
else
|
67
|
+
self.dismissModalViewControllerAnimated true
|
68
|
+
end
|
69
|
+
end
|
51
70
|
end
|
52
71
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Formotion
|
2
|
+
class FormableController < Formotion::FormController
|
3
|
+
extend BW::KVO
|
4
|
+
include BW::KVO
|
5
|
+
|
6
|
+
attr_accessor :model
|
7
|
+
|
8
|
+
def initWithModel(model)
|
9
|
+
self.initWithForm(model.to_form)
|
10
|
+
self.model = model
|
11
|
+
self.form.sections.each { |section|
|
12
|
+
section.rows.each { |row|
|
13
|
+
observe(row, "value") do |old_value, new_value|
|
14
|
+
self.model.send("#{row.key}=", new_value)
|
15
|
+
end
|
16
|
+
}
|
17
|
+
}
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/formotion/form/form.rb
CHANGED
@@ -3,7 +3,7 @@ module Formotion
|
|
3
3
|
PROPERTIES = [
|
4
4
|
# By default, Formotion::Controller will set it's title to this
|
5
5
|
# (so navigation bars will reflect it).
|
6
|
-
:title,
|
6
|
+
:title,
|
7
7
|
# If you want to have some internal id to track the form.
|
8
8
|
:id
|
9
9
|
]
|
@@ -87,7 +87,7 @@ module Formotion
|
|
87
87
|
|
88
88
|
# Stores the callback block when you do #submit.
|
89
89
|
# EX
|
90
|
-
# @form.on_submit do
|
90
|
+
# @form.on_submit do
|
91
91
|
# do_something(@form.render)
|
92
92
|
# end
|
93
93
|
#
|
@@ -103,13 +103,18 @@ module Formotion
|
|
103
103
|
# Handles either zero or one arguments,
|
104
104
|
# as shown above.
|
105
105
|
def submit
|
106
|
+
if @on_submit_callback.nil?
|
107
|
+
p "`Form#submit` invoked without a callback, doing nothing."
|
108
|
+
return
|
109
|
+
end
|
110
|
+
|
106
111
|
if @on_submit_callback.arity == 0
|
107
112
|
@on_submit_callback.call
|
108
113
|
elsif @on_submit_callback.arity == 1
|
109
114
|
@on_submit_callback.call(self)
|
110
115
|
end
|
111
116
|
end
|
112
|
-
|
117
|
+
|
113
118
|
#########################
|
114
119
|
# Retreiving data
|
115
120
|
|
@@ -123,7 +128,7 @@ module Formotion
|
|
123
128
|
# super handles all of the ::PROPERTIES
|
124
129
|
h = super
|
125
130
|
h[:sections] = self.sections.collect { |section|
|
126
|
-
section.to_hash
|
131
|
+
section.to_hash
|
127
132
|
}
|
128
133
|
recursive_delete_nil(h)
|
129
134
|
h
|
@@ -134,8 +139,8 @@ module Formotion
|
|
134
139
|
# EX
|
135
140
|
# @form = Formotion::Form.new(sections: [{
|
136
141
|
# rows: [{
|
137
|
-
# key: 'Email',
|
138
|
-
# editable: true,
|
142
|
+
# key: 'Email',
|
143
|
+
# editable: true,
|
139
144
|
# title: 'Email'
|
140
145
|
# }]}])
|
141
146
|
# ...user plays with the Form...
|
@@ -152,15 +157,33 @@ module Formotion
|
|
152
157
|
}
|
153
158
|
else
|
154
159
|
section.rows.each {|row|
|
155
|
-
next if row.
|
156
|
-
|
160
|
+
next if row.button?
|
161
|
+
if row.template_parent
|
162
|
+
# If this row is part of a template
|
163
|
+
# use the parent's key
|
164
|
+
kv[row.template_parent.key] ||= []
|
165
|
+
kv[row.template_parent.key] << row.value
|
166
|
+
else
|
167
|
+
kv[row.key] ||= row.value
|
168
|
+
end
|
157
169
|
}
|
158
170
|
end
|
159
171
|
}
|
172
|
+
kv.merge! sub_render
|
160
173
|
kv.delete_if {|k, v| k.nil? }
|
161
174
|
kv
|
162
175
|
end
|
163
176
|
|
177
|
+
def sub_render
|
178
|
+
kv = {}
|
179
|
+
rows = sections.map(&:rows).flatten
|
180
|
+
subform_rows = rows.select{ |row| row.subform != nil }
|
181
|
+
subform_rows.each do |subform_row|
|
182
|
+
kv[subform_row.key] = subform_row.subform.to_form.render
|
183
|
+
end
|
184
|
+
kv
|
185
|
+
end
|
186
|
+
|
164
187
|
private
|
165
188
|
def recursive_delete_nil(h)
|
166
189
|
delete_empty = Proc.new { |k, v|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Formotion
|
2
|
-
class Form
|
2
|
+
class Form < Formotion::Base
|
3
3
|
attr_reader :table
|
4
4
|
attr_reader :controller
|
5
5
|
attr_reader :active_row
|
@@ -17,6 +17,7 @@ module Formotion
|
|
17
17
|
# Table Methods
|
18
18
|
def controller=(controller)
|
19
19
|
@controller = controller
|
20
|
+
@controller.title = self.title
|
20
21
|
self.table = controller.respond_to?(:table_view) ? controller.table_view : controller.tableView
|
21
22
|
end
|
22
23
|
|
@@ -31,7 +32,7 @@ module Formotion
|
|
31
32
|
def reload_data
|
32
33
|
previous_row, next_row = nil
|
33
34
|
|
34
|
-
last_row = self.sections[-1].rows[-1]
|
35
|
+
last_row = self.sections[-1] && self.sections[-1].rows[-1]
|
35
36
|
if last_row
|
36
37
|
last_row.return_key ||= UIReturnKeyDone
|
37
38
|
end
|
@@ -69,14 +70,36 @@ module Formotion
|
|
69
70
|
|
70
71
|
def tableView(tableView, heightForRowAtIndexPath: indexPath)
|
71
72
|
row = row_for_index_path(indexPath)
|
72
|
-
row.
|
73
|
+
row.row_height || tableView.rowHeight
|
73
74
|
end
|
74
75
|
|
76
|
+
def tableView(tableView, commitEditingStyle: editingStyle, forRowAtIndexPath: indexPath)
|
77
|
+
row = row_for_index_path(indexPath)
|
78
|
+
case editingStyle
|
79
|
+
when UITableViewCellEditingStyleInsert
|
80
|
+
row.object.on_insert(tableView, self)
|
81
|
+
when UITableViewCellEditingStyleDelete
|
82
|
+
row.object.on_delete(tableView, self)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
75
87
|
# UITableViewDelegate Methods
|
76
88
|
def tableView(tableView, didSelectRowAtIndexPath:indexPath)
|
77
89
|
tableView.deselectRowAtIndexPath(indexPath, animated:true)
|
78
90
|
row = row_for_index_path(indexPath)
|
79
91
|
row.object.on_select(tableView, self)
|
80
92
|
end
|
93
|
+
|
94
|
+
def tableView(tableView, editingStyleForRowAtIndexPath:indexPath)
|
95
|
+
row = row_for_index_path(indexPath)
|
96
|
+
row.object.cellEditingStyle
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def tableView(tableView, shouldIndentWhileEditingRowAtIndexPath: indexPath)
|
101
|
+
row = row_for_index_path(indexPath)
|
102
|
+
row.object.indentWhileEditing?
|
103
|
+
end
|
81
104
|
end
|
82
105
|
end
|