From 15fc911bfb27686a001b52c4ecb41a65f9dd1d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 14:32:54 +0100 Subject: [PATCH 1/2] adds js for input type=number to IE<9 --- app/assets/javascripts/ie_lt9.js | 3 ++- vendor/assets/javascripts/number-polyfill.min.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 vendor/assets/javascripts/number-polyfill.min.js diff --git a/app/assets/javascripts/ie_lt9.js b/app/assets/javascripts/ie_lt9.js index 4e45b0282..b10b4b2ff 100644 --- a/app/assets/javascripts/ie_lt9.js +++ b/app/assets/javascripts/ie_lt9.js @@ -1,2 +1,3 @@ //= require respond.min -//= require rem.min \ No newline at end of file +//= require rem.min +//= require number-polyfill.min \ No newline at end of file diff --git a/vendor/assets/javascripts/number-polyfill.min.js b/vendor/assets/javascripts/number-polyfill.min.js new file mode 100644 index 000000000..b5cea8b09 --- /dev/null +++ b/vendor/assets/javascripts/number-polyfill.min.js @@ -0,0 +1 @@ +(function(){(function(e){var t,n;return t=document.createElement("input"),t.setAttribute("type","number"),"text"!==t.type?(e.fn.inputNumber=function(){return e(this)},void 0):(e.fn.inputNumber=function(){return e(this).filter(function(){var t;return t=e(this),t.is('input[type="number"]')&&!(t.parent().is("span")&&t.next().is("div.number-spin-btn-container")&&t.next().children().first().is("div.number-spin-btn-up")&&t.next().children().eq(1).is("div.number-spin-btn-down"))}).each(function(){n.polyfills.push(new n(this))}),e(this)},n=function(t){var i,r,o,s,a=this;if(this.elem=e(t),!(this.elem.is(":root *")&&this.elem.height()>0))throw Error("Element must be in DOM and displayed so that its height can be measured.");s=this.elem.outerHeight()/2+"px",this.upBtn=e("
",{"class":"number-spin-btn number-spin-btn-up",style:"height: "+s}),this.downBtn=e("
",{"class":"number-spin-btn number-spin-btn-down",style:"height: "+s}),this.btnContainer=e("
",{"class":"number-spin-btn-container"}),i=e("",{style:"white-space: nowrap"}),this.upBtn.appendTo(this.btnContainer),this.downBtn.appendTo(this.btnContainer),this.elem.wrap(i),this.btnContainer.insertAfter(this.elem),this.elem.on({focus:function(){a.elem.on({DOMMouseScroll:n.domMouseScrollHandler,mousewheel:n.mouseWheelHandler},{p:a})},blur:function(){a.elem.off({DOMMouseScroll:n.domMouseScrollHandler,mousewheel:n.mouseWheelHandler})}}),this.elem.on({keypress:n.elemKeypressHandler,change:n.elemChangeHandler},{p:this}),this.upBtn.on("mousedown",{p:this,func:"increment"},n.elemBtnMousedownHandler),this.downBtn.on("mousedown",{p:this,func:"decrement"},n.elemBtnMousedownHandler),this.elem.css("textAlign","right"),this.attrMutationHandler("class"),"undefined"!=typeof WebKitMutationObserver&&null!==WebKitMutationObserver||r!==void 0&&null!==r?("undefined"==typeof WebKitMutationObserver||null===WebKitMutationObserver||void 0!==r&&null!==r||(r=WebKitMutationObserver),o=new r(function(e){var t,n,i;for(n=0,i=e.length;i>n;n++)t=e[n],"attributes"===t.type&&a.attrMutationHandler(t.attributeName,t.oldValue,a.elem.attr(t.attributeName))}),o.observe(t,{attributes:!0,attributeOldValue:!0,attributeFilter:["class","style","min","max","step"]})):"undefined"!=typeof MutationEvent&&null!==MutationEvent&&this.elem.on("DOMAttrModified",function(e){a.attrMutationHandler(e.originalEvent.attrName,e.originalEvent.prevValue,e.originalEvent.newValue)})},n.polyfills=[],n.isNumber=function(e){return null!=e&&"function"==typeof e.toString?/^-?\d+(?:\.\d+)?$/.test(""+e):!1},n.isFloat=function(e){return null!=e&&"function"==typeof e.toString?/^-?\d+\.\d+$/.test(""+e):!1},n.isInt=function(e){return null!=e&&"function"==typeof e.toString?/^-?\d+$/.test(""+e):!1},n.isNegative=function(e){return null!=e&&"function"==typeof e.toString?/^-\d+(?:\.\d+)?$/.test(""+e):!1},n.raiseNum=function(e){var t,i,r;if("number"==typeof e||"object"==typeof e&&e instanceof Number)return e%1?{num:""+e,precision:0}:n.raiseNum(""+e);if("string"==typeof e||"object"==typeof e&&e instanceof String){if(n.isFloat(e))return e=e.replace(/(\.\d)0+$/,"$1"),r=n.getPrecision(e),i=e.slice(0,-(r+1))+e.slice(-r),i=i.replace(/^(-?)0+(\d+)/,"$1$2"),t={num:i,precision:r};if(n.isInt(e))return{num:e,precision:0}}},n.raiseNumPrecision=function(e,n){var i,r;if(n>e.precision){for(t=i=r=e.precision;n>=r?n>i:i>n;t=n>=r?++i:--i)e.num+="0";e.precision=n}},n.lowerNum=function(e){if(e.precision>0){for(;e.num.lengthr.precision&&n.raiseNumPrecision(r,i.precision),o=""+(parseInt(i.num,10)+parseInt(r.num,10)),i.precision>0){if(n.isNegative(o))for(;i.precision>o.length-1;)o="-0"+o.slice(1);else for(;i.precision>o.length;)o="0"+o;o=n.lowerNum({num:o,precision:i.precision})}return o=o.replace(/^(-?)\./,"$10."),n.isFloat(o)&&(o=o.replace(/0+$/,"")),o}throw new SyntaxError('Argument "'+t+'" is not a number.')}throw new SyntaxError('Argument "'+e+'" is not a number.')}return n.preciseAdd(""+e,""+t)},n.preciseSubtract=function(e,t){return"number"==typeof t||"object"==typeof t&&t instanceof Number?n.preciseAdd(e,-t):"string"==typeof t||"object"==typeof t&&t instanceof String?n.isNegative(t)?n.preciseAdd(e,t.slice(1)):n.preciseAdd(e,"-"+t):void 0},n.getPrecision=function(e){var t,i;if("number"==typeof e){for(t=0,i=e;i!==Math.floor(i);)i=e*Math.pow(10,++t);return t}return"string"==typeof e&&n.isNumber(e)?n.isFloat(e)?/^-?\d+(?:\.(\d+))?$/.exec(e)[1].length:0:void 0},n.prototype.getParams=function(){var e,t,i,r;return i=this.elem.attr("step"),t=this.elem.attr("min"),e=this.elem.attr("max"),r=this.elem.val(),n.isNumber(i)||(i=null),n.isNumber(t)||(t=null),n.isNumber(e)||(e=null),n.isNumber(r)||(r=t||0),{min:null!=t?t:null,max:null!=e?e:null,step:null!=i?i:"1",val:null!=r?r:null}},n.prototype.clipValues=function(e,t,n){return null!=n&&parseFloat(e)>parseFloat(n)?n:null!=t&&parseFloat(e)s.precision?n.raiseNumPrecision(s,t.precision):t.precisione.originalEvent.detail?t.increment():t.decrement()},n.mouseWheelHandler=function(e){var t;t=e.data.p,e.preventDefault(),e.originalEvent.wheelDelta>0?t.increment():t.decrement()},n.elemKeypressHandler=function(e){var t,n,i;t=e.data.p,38===e.keyCode?t.increment():40===e.keyCode?t.decrement():8!==(n=e.keyCode)&&9!==n&&35!==n&&36!==n&&37!==n&&39!==n&&46!==n&&45!==(i=e.which)&&46!==i&&48!==i&&49!==i&&50!==i&&51!==i&&52!==i&&53!==i&&54!==i&&55!==i&&56!==i&&57!==i&&e.preventDefault()},n.elemChangeHandler=function(e){var t,i,r,o;r=e.data.p,""!==r.elem.val()&&(n.isNumber(r.elem.val())?(o=r.getParams(),i=r.clipValues(o.val,o.min,o.max),i=r.stepNormalize(i),""+i!==r.elem.val()&&r.elem.val(i).change()):(t=r.elem.attr("min"),r.elem.val(null!=t&&n.isNumber(t)?t:"0").change()))},n.elemBtnMousedownHandler=function(t){var n,i,r,o,s=this;i=t.data.p,n=t.data.func,i[n](),o=function(){i[n](),i.timeoutID=window.setTimeout(o,10)},r=function(){window.clearTimeout(i.timeoutID),e(document).off("mouseup",r),e(s).off("mouseleave",r)},e(document).on("mouseup",r),e(this).on("mouseleave",r),i.timeoutID=window.setTimeout(o,700)},n.prototype.attrMutationHandler=function(e){var n,i,r,o,s;if("class"===e||"style"===e){for(i={},n=null,s=["opacity","visibility","-moz-transition-property","-moz-transition-duration","-moz-transition-timing-function","-moz-transition-delay","-webkit-transition-property","-webkit-transition-duration","-webkit-transition-timing-function","-webkit-transition-delay","-o-transition-property","-o-transition-duration","-o-transition-timing-function","-o-transition-delay","transition-property","transition-duration","transition-timing-function","transition-delay"],r=0,o=s.length;o>r;r++)t=s[r],(n=this.elem.css(t))!==this.btnContainer.css(t)&&(i[t]=n);i.display="none"===this.elem.css("display")?"none":"inline-block",this.btnContainer.css(i)}else("min"===e||"max"===e||"step"===e)&&this.elem.change()},n.prototype.increment=function(){var e,t;this.elem.is(":disabled")||this.elem.is("[readonly]")||(t=this.getParams(),e=n.preciseAdd(t.val,t.step),null!=t.max&&parseFloat(e)>parseFloat(t.max)&&(e=t.max),e=this.stepNormalize(e),this.elem.val(e).change())},n.prototype.decrement=function(){var e,t;this.elem.is(":disabled")||this.elem.is("[readonly]")||(t=this.getParams(),e=n.preciseSubtract(t.val,t.step),null!=t.min&&parseFloat(e) Date: Tue, 8 Mar 2016 16:24:34 +0100 Subject: [PATCH 2/2] adds validation for price fields --- .../spending_proposals_controller.rb | 19 +++++++++++++++++-- config/locales/en.yml | 1 + config/locales/es.yml | 1 + .../valuation/spending_proposals_spec.rb | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/controllers/valuation/spending_proposals_controller.rb b/app/controllers/valuation/spending_proposals_controller.rb index f5074ab1e..b0d83d96e 100644 --- a/app/controllers/valuation/spending_proposals_controller.rb +++ b/app/controllers/valuation/spending_proposals_controller.rb @@ -17,8 +17,11 @@ class Valuation::SpendingProposalsController < Valuation::BaseController end def valuate - @spending_proposal.update_attributes(valuation_params) - redirect_to valuation_spending_proposal_path(@spending_proposal), notice: t('valuation.spending_proposals.notice.valuate') + if valid_price_params? && @spending_proposal.update(valuation_params) + redirect_to valuation_spending_proposal_path(@spending_proposal), notice: t('valuation.spending_proposals.notice.valuate') + else + render action: :edit + end end private @@ -35,4 +38,16 @@ class Valuation::SpendingProposalsController < Valuation::BaseController raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || ValuationAssignment.exists?(spending_proposal_id: params[:id], valuator_id: current_user.valuator.id) end + def valid_price_params? + if /\D/.match params[:spending_proposal][:price] + @spending_proposal.errors.add(:price, I18n.t('spending_proposals.wrong_price_format')) + end + + if /\D/.match params[:spending_proposal][:price_first_year] + @spending_proposal.errors.add(:price_first_year, I18n.t('spending_proposals.wrong_price_format')) + end + + @spending_proposal.errors.empty? + end + end diff --git a/config/locales/en.yml b/config/locales/en.yml index e3f51219c..468889c28 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -423,6 +423,7 @@ en: recommendation_two: Any proposal or comment suggesting illegal action will be deleted. recommendations_title: How to create a spending proposal start_new: Create spending proposal + wrong_price_format: Only integer numbers stats: index: visits: Visits diff --git a/config/locales/es.yml b/config/locales/es.yml index 55177e15a..b9701cbf5 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -423,6 +423,7 @@ es: recommendation_two: Cualquier propuesta o comentario que implique acciones ilegales será eliminada. recommendations_title: Cómo crear una propuesta de gasto start_new: Crear una propuesta de gasto + wrong_price_format: Solo puede incluir caracteres numéricos stats: index: visits: Visitas diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb index e5bde98d4..a5b761e65 100644 --- a/spec/features/valuation/spending_proposals_spec.rb +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -284,6 +284,20 @@ feature 'Valuation spending proposals' do click_link @spending_proposal.title expect(page).to have_content('Valuation finished') end + + scenario 'Validates price formats' do + visit valuation_spending_proposals_path + within("#spending_proposal_#{@spending_proposal.id}") do + click_link "Edit" + end + + fill_in 'spending_proposal_price', with: '12345,98' + fill_in 'spending_proposal_price_first_year', with: '9876.6' + click_button 'Save changes' + + expect(page).to have_content('2 errors') + expect(page).to have_content('Only integer numbers', count: 2) + end end end