formotion 0.5.1 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|