diff --git a/Gemfile b/Gemfile index ca32a065a..f49c97cfe 100644 --- a/Gemfile +++ b/Gemfile @@ -112,6 +112,7 @@ source "https://rails-assets.org" do gem "rails-assets-jquery-textchange", "0.2.3" gem "rails-assets-perfect-scrollbar", "0.6.2" gem "rails-assets-jakobmattsson--jquery-elastic", "1.6.11" + gem "rails-assets-autosize", "3.0.6" end gem "facebox-rails", "0.2.0" diff --git a/Gemfile.lock b/Gemfile.lock index 858c83a02..6b6b45921 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -516,6 +516,7 @@ GEM bundler (>= 1.3.0, < 2.0) railties (= 4.2.1) sprockets-rails + rails-assets-autosize (3.0.6) rails-assets-diaspora_jsxc (0.1.1) rails-assets-jquery (~> 1.11.1) rails-assets-jquery-colorbox (~> 1.5.14) @@ -820,6 +821,7 @@ DEPENDENCIES rack-rewrite (= 1.5.1) rack-ssl (= 1.4.1) rails (= 4.2.1) + rails-assets-autosize (= 3.0.6)! rails-assets-diaspora_jsxc (~> 0.1.1)! rails-assets-highlightjs (= 8.5.0)! rails-assets-jakobmattsson--jquery-elastic (= 1.6.11)! diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index 73bc7feda..07efa4f71 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -30,8 +30,8 @@ app.views.CommentStream = app.views.Base.extend({ this.model.comments.each(this.appendComment, this); // add autoexpanders to new comment textarea - this.$("textarea").autoResize({'extraSpace' : 10}); - this.$('textarea').val(this.textareaValue); + this.$("textarea").val(this.textareaValue); + autosize(this.$("textarea")); }, presenter: function(){ @@ -44,7 +44,7 @@ app.views.CommentStream = app.views.Base.extend({ createComment: function(evt) { if(evt){ evt.preventDefault(); } - + var commentText = $.trim(this.$('.comment_box').val()); this.$(".comment_box").val(""); this.$(".comment_box").css("height", ""); @@ -62,7 +62,7 @@ app.views.CommentStream = app.views.Base.extend({ return false; } }, - + appendComment: function(comment) { // Set the post as the comment's parent, so we can check // on post ownership in the Comment view. diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index d4ef03085..94f275338 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -44,9 +44,6 @@ app.views.Publisher = Backbone.View.extend({ // init mentions plugin Mentions.initialize(this.inputEl); - // init autoresize plugin - this.inputEl.autoResize({ "extraSpace" : 10, "maxHeight" : Infinity }); - // if there is data in the publisher we ask for a confirmation // before the user is able to leave the page $(window).on("beforeunload", _.bind(this._beforeUnload, this)); @@ -97,6 +94,9 @@ app.views.Publisher = Backbone.View.extend({ this.viewPollCreator.render(); }); + // init autosize plugin + autosize(this.inputEl); + this.initSubviews(); this.checkSubmitAvailability(); return this; @@ -147,6 +147,7 @@ app.views.Publisher = Backbone.View.extend({ this.prefillText = txt; this.inputEl.trigger("input"); + autosize.update(this.inputEl); this.handleTextchange(); }, @@ -373,6 +374,7 @@ app.views.Publisher = Backbone.View.extend({ this.hiddenInputEl.val(""); this.inputEl.trigger("keyup") .trigger("keydown"); + autosize.update(this.inputEl); // remove mentions this.inputEl.mentionsInput("reset"); @@ -429,6 +431,7 @@ app.views.Publisher = Backbone.View.extend({ // visually 'open' the publisher this.$el.removeClass("closed"); this.wrapperEl.addClass("active"); + autosize.update(this.inputEl); // fetch contacts for mentioning Mentions.fetchContacts(); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index deaf9217a..9c7346c0b 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -8,7 +8,7 @@ //= require backbone //= require jquery.hotkeys //= require jquery.remotipart -//= require jquery.autoresize +//= require autosize //= require jquery.charcount //= require jquery-placeholder //= require rails-timeago diff --git a/app/assets/stylesheets/bookmarklet.scss b/app/assets/stylesheets/bookmarklet.scss index 42c2dadbd..ecdaff4b6 100644 --- a/app/assets/stylesheets/bookmarklet.scss +++ b/app/assets/stylesheets/bookmarklet.scss @@ -1,2 +1,2 @@ -#bookmarklet { padding:10px 10px 30px 10px; margin-top: 0; } -body.page-status_messages.action-bookmarklet { margin-top: 0px } \ No newline at end of file +#bookmarklet { padding-bottom: 30px; margin-top: 0; } +body.page-status_messages.action-bookmarklet { margin-top: 0px } diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index a56a02de9..67a654a93 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -40,6 +40,7 @@ .comment_box { width: 95%; height: 35px; + resize: none; } textarea.comment_box:focus, textarea.comment_box:valid, textarea.comment_box:active { border-color: $border-dark-grey; diff --git a/app/views/status_messages/bookmarklet.html.haml b/app/views/status_messages/bookmarklet.html.haml index 560251dfd..393002b8c 100644 --- a/app/views/status_messages/bookmarklet.html.haml +++ b/app/views/status_messages/bookmarklet.html.haml @@ -1,5 +1,7 @@ -.container#bookmarklet - .row - %h4 - =t('bookmarklet.post_something') - = render partial: 'publisher/publisher', locals: { aspect: :profile, :selected_aspects => @aspects, :aspect_ids => @aspect_ids } +#bookmarklet + .container + .row + .col-md-12 + %h4 + =t('bookmarklet.post_something') + = render partial: 'publisher/publisher', locals: { aspect: :profile, :selected_aspects => @aspects, :aspect_ids => @aspect_ids } diff --git a/config/.jshint.json b/config/.jshint.json index 72b2a4dea..86bcc1cf2 100644 --- a/config/.jshint.json +++ b/config/.jshint.json @@ -38,6 +38,7 @@ "predef": [ "_", + "autosize", "Backbone", "gon", "Handlebars", diff --git a/config/.jshint_ignore b/config/.jshint_ignore index 59dc22151..42b6eb736 100644 --- a/config/.jshint_ignore +++ b/config/.jshint_ignore @@ -1,4 +1,3 @@ vendor/assets/javascripts/**.js lib/assets/javascripts/fileuploader-custom.js -lib/assets/javascripts/jquery.autoresize.js lib/assets/javascripts/jquery.mentionsInput.js diff --git a/lib/assets/javascripts/jquery.autoresize.js b/lib/assets/javascripts/jquery.autoresize.js deleted file mode 100644 index 4bc0959ae..000000000 --- a/lib/assets/javascripts/jquery.autoresize.js +++ /dev/null @@ -1,274 +0,0 @@ -/* - * jQuery.fn.autoResize 1.14 - * -- - * https://github.com/padolsey/jQuery.fn.autoResize - * -- - * This program is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://sam.zoy.org/wtfpl/COPYING for more details. */ - -(function($){ - - var uid = 'ar' + +new Date, - - defaults = autoResize.defaults = { - onResize: function(){}, - onBeforeResize: function(){return 123}, - onAfterResize: function(){return 555}, - animate: { - duration: 200, - complete: function(){} - }, - extraSpace: 50, - minHeight: 'original', - maxHeight: 500, - minWidth: 'original', - maxWidth: 500 - }; - - autoResize.cloneCSSProperties = [ - 'lineHeight', 'textDecoration', 'letterSpacing', - 'fontSize', 'fontFamily', 'fontStyle', 'fontWeight', - 'textTransform', 'textAlign', 'direction', 'wordSpacing', 'fontSizeAdjust', - 'paddingTop', 'paddingLeft', 'paddingBottom', 'paddingRight', 'width' - ]; - - autoResize.cloneCSSValues = { - position: 'absolute', - top: -9999, - left: -9999, - opacity: 0, - overflow: 'hidden' - }; - - autoResize.resizableFilterSelector = [ - 'textarea:not(textarea.' + uid + ')', - 'input:not(input[type])', - 'input[type=text]', - 'input[type=password]', - 'input[type=email]', - 'input[type=url]' - ].join(','); - - autoResize.AutoResizer = AutoResizer; - - $.fn.autoResize = autoResize; - - function autoResize(config) { - this.filter(autoResize.resizableFilterSelector).each(function(){ - new AutoResizer( $(this), config ); - }); - return this; - } - - function AutoResizer(el, config) { - - if (el.data('AutoResizer')) { - el.data('AutoResizer').destroy(); - } - - config = this.config = $.extend({}, autoResize.defaults, config); - this.el = el; - - this.nodeName = el[0].nodeName.toLowerCase(); - - this.originalHeight = el.height(); - this.previousScrollTop = null; - - this.value = el.val(); - - if (config.maxWidth === 'original') config.maxWidth = el.width(); - if (config.minWidth === 'original') config.minWidth = el.width(); - if (config.maxHeight === 'original') config.maxHeight = el.height(); - if (config.minHeight === 'original') config.minHeight = el.height(); - - if (this.nodeName === 'textarea') { - el.css({ - resize: 'none', - overflowY: 'hidden' - }); - } - - el.data('AutoResizer', this); - - // Make sure onAfterResize is called upon animation completion - config.animate.complete = (function(f){ - return function() { - config.onAfterResize.call(el); - return f.apply(this, arguments); - }; - }(config.animate.complete)); - - this.bind(); - - } - - AutoResizer.prototype = { - - bind: function() { - - var check = $.proxy(function(){ - this.check(); - return true; - }, this); - - this.unbind(); - - this.el - .bind('keyup.autoResize', check) - //.bind('keydown.autoResize', check) - .bind('change.autoResize', check) - .bind('paste.autoResize', function() { - setTimeout(function() { check(); }, 0); - }); - - if (!this.el.is(':hidden')) { - this.check(null, true); - } - - }, - - unbind: function() { - this.el.unbind('.autoResize'); - }, - - createClone: function() { - - var el = this.el, - clone = this.nodeName === 'textarea' ? el.clone() : $(''); - - this.clone = clone; - - $.each(autoResize.cloneCSSProperties, function(i, p){ - clone[0].style[p] = el.css(p); - }); - - clone - .removeAttr('name') - .removeAttr('id') - .addClass(uid) - .attr('tabIndex', -1) - .css(autoResize.cloneCSSValues); - - if (this.nodeName === 'textarea') { - clone.height('auto'); - } else { - clone.width('auto').css({ - whiteSpace: 'nowrap' - }); - } - - }, - - check: function(e, immediate) { - - if (!this.clone) { - this.createClone(); - this.injectClone(); - } - - var config = this.config, - clone = this.clone, - el = this.el, - value = el.val(); - - // Do nothing if value hasn't changed - if (value === this.prevValue) { return true; } - this.prevValue = value; - - if (this.nodeName === 'input') { - - clone.text(value); - - // Calculate new width + whether to change - var cloneWidth = clone.width(), - newWidth = (cloneWidth + config.extraSpace) >= config.minWidth ? - cloneWidth + config.extraSpace : config.minWidth, - currentWidth = el.width(); - - newWidth = Math.min(newWidth, config.maxWidth); - - if ( - (newWidth < currentWidth && newWidth >= config.minWidth) || - (newWidth >= config.minWidth && newWidth <= config.maxWidth) - ) { - - config.onBeforeResize.call(el); - config.onResize.call(el); - - el.scrollLeft(0); - - if (config.animate && !immediate) { - el.stop(1,1).animate({ - width: newWidth - }, config.animate); - } else { - el.width(newWidth); - config.onAfterResize.call(el); - } - - } - - return; - - } - - // TEXTAREA - - clone.width(el.width()).height(0).val(value).scrollTop(10000); - - var scrollTop = clone[0].scrollTop; - - // Don't do anything if scrollTop hasen't changed: - if (this.previousScrollTop === scrollTop) { - return; - } - - this.previousScrollTop = scrollTop; - - if (scrollTop + config.extraSpace >= config.maxHeight) { - el.css('overflowY', ''); - scrollTop = config.maxHeight; - immediate = true; - } else if (scrollTop <= config.minHeight) { - scrollTop = config.minHeight; - } else { - el.css('overflowY', 'hidden'); - scrollTop += config.extraSpace; - } - - config.onBeforeResize.call(el); - config.onResize.call(el); - - // Either animate or directly apply height: - if (config.animate && !immediate) { - el.stop(1,1).animate({ - height: scrollTop - }, config.animate); - } else { - el.height(scrollTop); - config.onAfterResize.call(el); - } - - }, - - destroy: function() { - this.unbind(); - this.el.removeData('AutoResizer'); - this.clone.remove(); - delete this.el; - delete this.clone; - }, - - injectClone: function() { - ( - autoResize.cloneContainer || - (autoResize.cloneContainer = $('').appendTo('body')) - ).append(this.clone); - } - - }; - -})(jQuery); diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js index 27cec303f..dfb20219c 100644 --- a/spec/javascripts/app/views/comment_stream_view_spec.js +++ b/spec/javascripts/app/views/comment_stream_view_spec.js @@ -22,10 +22,10 @@ describe("app.views.CommentStream", function(){ }); it("autoResizes the new comment textarea", function(){ - spyOn($.fn, "autoResize"); + spyOn(window, "autosize"); this.view.postRenderTemplate(); - expect($.fn.autoResize).toHaveBeenCalled(); - expect($.fn.autoResize.calls.mostRecent().object.selector).toBe("textarea"); + expect(window.autosize).toHaveBeenCalled(); + expect(window.autosize.calls.mostRecent().args[0].selector).toBe("textarea"); }); }); diff --git a/spec/javascripts/helpers/SpecHelper.js b/spec/javascripts/helpers/SpecHelper.js index 9e7ac46cc..3a3585716 100644 --- a/spec/javascripts/helpers/SpecHelper.js +++ b/spec/javascripts/helpers/SpecHelper.js @@ -42,8 +42,6 @@ var customMatchers = { beforeEach(function() { - $('#jasmine_content').html(spec.readFixture("underscore_templates")); - jasmine.clock().install(); jasmine.Ajax.install(); @@ -64,6 +62,18 @@ beforeEach(function() { // add custom matchers for flash messages jasmine.addMatchers(customMatchers); + + // PhantomJS 1.9.8 doesn't support bind yet + // See https://github.com/ariya/phantomjs/issues/10522 + // and https://github.com/colszowka/phantomjs-gem + /* jshint -W121 */ + Function.prototype.bind = Function.prototype.bind || function (thisp) { + var fn = this; + return function () { + return fn.apply(thisp, arguments); + }; + }; + /* jshint +W121 */ }); afterEach(function() {