From da5aef2b752b6fdae039a47af76107d5ba3aa0bb Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Sat, 13 Aug 2016 01:44:41 +0200 Subject: [PATCH] Fix charcounter position in publisher --- .../app/views/publisher/services_view.js | 10 +- app/assets/javascripts/main.js | 2 +- app/assets/javascripts/mobile/mobile.js | 3 +- app/assets/javascripts/mobile/publisher.js | 10 +- app/assets/stylesheets/publisher.scss | 15 +-- lib/assets/javascripts/charcount.js | 33 ++++++ spec/javascripts/lib/charcounter_spec.js | 102 ++++++++++++++++++ vendor/assets/javascripts/jquery.charcount.js | 58 ---------- 8 files changed, 156 insertions(+), 77 deletions(-) create mode 100644 lib/assets/javascripts/charcount.js create mode 100644 spec/javascripts/lib/charcounter_spec.js delete mode 100644 vendor/assets/javascripts/jquery.charcount.js diff --git a/app/assets/javascripts/app/views/publisher/services_view.js b/app/assets/javascripts/app/views/publisher/services_view.js index 1ed4c988b..8fd17a9e8 100644 --- a/app/assets/javascripts/app/views/publisher/services_view.js +++ b/app/assets/javascripts/app/views/publisher/services_view.js @@ -37,7 +37,7 @@ app.views.PublisherServices = Backbone.View.extend({ // keep track of character count _createCounter: function() { // remove any obsolete counters - this.input.siblings('.counter').remove(); + $("#publisher .counter").remove(); // create new counter var min = 40000; @@ -47,7 +47,13 @@ app.views.PublisherServices = Backbone.View.extend({ var num = parseInt($(value).attr('maxchar')); if (min > num) { min = num; } }); - this.input.charCount({allowed: min, warning: min/10 }); + var counter = $("
"); + $("#publisher-images").after(counter); + this.input.charCount({ + allowed: min, + warning: min / 10, + counter: counter + }); } }, diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 07f124d14..e5b5a8688 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -8,7 +8,7 @@ //= require backbone //= require jquery.remotipart //= require autosize -//= require jquery.charcount +//= require charcount //= require jquery-placeholder //= require rails-timeago //= require jquery.events.input diff --git a/app/assets/javascripts/mobile/mobile.js b/app/assets/javascripts/mobile/mobile.js index 1a7b24110..fad57b3f0 100644 --- a/app/assets/javascripts/mobile/mobile.js +++ b/app/assets/javascripts/mobile/mobile.js @@ -4,7 +4,8 @@ * licensed under the Affero General Public License version 3 or later. See * the COPYRIGHT file. */ -//= require jquery.charcount +//= require jquery-textchange +//= require charcount //= require js-routes //= require autosize //= require keycodes diff --git a/app/assets/javascripts/mobile/publisher.js b/app/assets/javascripts/mobile/publisher.js index 9468ac210..6954631cf 100644 --- a/app/assets/javascripts/mobile/publisher.js +++ b/app/assets/javascripts/mobile/publisher.js @@ -20,7 +20,15 @@ $(document).ready(function(){ } }); - $("#status_message_text").charCount({allowed: publisherMaxChars, warning: publisherMaxChars/10 }); + if (selectedServices.length > 0) { + var counter = $(""); + $("#status_message_text").after(counter); + $("#status_message_text").charCount({ + allowed: publisherMaxChars, + warning: publisherMaxChars / 10, + counter: counter + }); + } if(hiddenField.length > 0) { hiddenField.remove(); } else { diff --git a/app/assets/stylesheets/publisher.scss b/app/assets/stylesheets/publisher.scss index e29a64bfd..8dd88a2a8 100644 --- a/app/assets/stylesheets/publisher.scss +++ b/app/assets/stylesheets/publisher.scss @@ -187,12 +187,6 @@ text-align: center; } - .warning { - color: orange; - } - .exceeded { - color: red; - } } } @@ -235,16 +229,9 @@ } } - &.with-location .counter { - bottom: -62px; - } - .counter { - bottom: -25px; - height: 30px; line-height: 30px; - position: absolute; - right: 10px; + margin-right: 10px; } &:not(.with-location) .publisher-buttonbar { diff --git a/lib/assets/javascripts/charcount.js b/lib/assets/javascripts/charcount.js new file mode 100644 index 000000000..bd70a4285 --- /dev/null +++ b/lib/assets/javascripts/charcount.js @@ -0,0 +1,33 @@ +// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later + +/* + * char count plugin + * options are: + * - allowed: number of allowed characters + * - warning: number of left characters when a warning should be displayed + * - counter: jQuery element to use as the counter + */ +$.fn.charCount = function(opts) { + this.each(function() { + var $this = $(this); + var counter = opts.counter; + + var update = function() { + var count = $this.val().length; + + if (count > opts.allowed) { + counter.removeClass("text-warning").addClass("text-danger"); + } else if (count > opts.allowed - opts.warning) { + counter.removeClass("text-danger").addClass("text-warning"); + } else { + counter.removeClass("text-danger").removeClass("text-warning"); + } + + counter.text(opts.allowed - count); + }; + + $this.on("textchange", update); + update(); + }); +}; +// @license-end diff --git a/spec/javascripts/lib/charcounter_spec.js b/spec/javascripts/lib/charcounter_spec.js new file mode 100644 index 000000000..f0287afef --- /dev/null +++ b/spec/javascripts/lib/charcounter_spec.js @@ -0,0 +1,102 @@ +describe("$.fn.charCount", function() { + beforeEach(function() { + this.input = $(""); + this.counter = $("
"); + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat + this.repeat = function(str, count) { + var rpt = ""; + for (;;) { + if ((count & 1) === 1) { + rpt += str; + } + count >>>= 1; + if (count === 0) { + break; + } + str += str; + } + return rpt; + }; + }); + + context("on initialization", function() { + beforeEach(function() { + this.input.val(this.repeat("a", 10)); + }); + + it("shows the correct number of available chars", function() { + this.input.charCount({allowed: 12, warning: 1, counter: this.counter}); + expect(this.counter.text()).toEqual("2"); + }); + + it("shows the normal text if there are enough chars left", function() { + this.input.charCount({allowed: 12, warning: 2, counter: this.counter}); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + }); + + it("shows a warning if there almost no chars left", function() { + this.input.charCount({allowed: 12, warning: 3, counter: this.counter}); + expect(this.counter).toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + }); + + it("shows an error if the limit exceeded", function() { + this.input.charCount({allowed: 9, warning: 3, counter: this.counter}); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).toHaveClass("text-danger"); + }); + }); + + context("on text changes", function() { + it("updates the number of available chars", function() { + this.input.val("a"); + this.input.charCount({allowed: 100, warning: 10, counter: this.counter}); + expect(this.counter.text()).toEqual("99"); + + this.input.val(this.repeat("a", 99)); + this.input.trigger("textchange"); + expect(this.counter.text()).toEqual("1"); + + this.input.val(this.repeat("a", 102)); + this.input.trigger("textchange"); + expect(this.counter.text()).toEqual("-2"); + + this.input.val(""); + this.input.trigger("textchange"); + expect(this.counter.text()).toEqual("100"); + }); + + it("updates the counter classes", function() { + this.input.val("a"); + this.input.charCount({allowed: 100, warning: 10, counter: this.counter}); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + + this.input.val(this.repeat("a", 90)); + this.input.trigger("textchange"); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + + this.input.val(this.repeat("a", 91)); + this.input.trigger("textchange"); + expect(this.counter).toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + + this.input.val(this.repeat("a", 100)); + this.input.trigger("textchange"); + expect(this.counter).toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + + this.input.val(this.repeat("a", 101)); + this.input.trigger("textchange"); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).toHaveClass("text-danger"); + + this.input.val(""); + this.input.trigger("textchange"); + expect(this.counter).not.toHaveClass("text-warning"); + expect(this.counter).not.toHaveClass("text-danger"); + }); + }); +}); diff --git a/vendor/assets/javascripts/jquery.charcount.js b/vendor/assets/javascripts/jquery.charcount.js deleted file mode 100644 index 67d1442d4..000000000 --- a/vendor/assets/javascripts/jquery.charcount.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Character Count Plugin - jQuery plugin - * Dynamic character count for text areas and input fields - * written by Alen Grakalic - * http://cssglobe.com/post/7161/jquery-plugin-simplest-twitterlike-dynamic-character-count-for-textareas - * - * Copyright (c) 2009 Alen Grakalic (http://cssglobe.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * Built for jQuery library - * http://jquery.com - * - */ - -(function($) { - - $.fn.charCount = function(options){ - - // default configuration properties - var defaults = { - allowed: 140, - warning: 25, - css: 'counter', - counterElement: 'span', - cssWarning: 'warning', - cssExceeded: 'exceeded', - counterText: '' - }; - - var options = $.extend(defaults, options); - - function calculate(obj){ - var count = $(obj).val().length; - var available = options.allowed - count; - if(available <= options.warning && available >= 0){ - $(obj).next().addClass(options.cssWarning); - } else { - $(obj).next().removeClass(options.cssWarning); - } - if(available < 0){ - $(obj).next().addClass(options.cssExceeded); - } else { - $(obj).next().removeClass(options.cssExceeded); - } - $(obj).next().html(options.counterText + available); - }; - - this.each(function() { - $(this).after('<'+ options.counterElement +' class="' + options.css + '">'+ options.counterText +''); - calculate(this); - $(this).keyup(function(){calculate(this)}); - $(this).change(function(){calculate(this)}); - }); - - }; - -})(jQuery);