jenkins-bot has submitted this change and it was merged. Change subject: Update Autosize to 3.0.15 from 1.17.2 ......................................................................
Update Autosize to 3.0.15 from 1.17.2 https://github.com/jackmoore/autosize/blob/master/changelog.md Removed now unnecessary workarounds related to resizing. Tweaked the insertables positioning to be better (consistent padding around the buttons) and consistent across browsers (height of the buttons) since I had to tweak those due to removal of the append feature in autosize. This also brings those closer to the original design. Tested in recent versions of Chome (Linux), Firefox (Linux), IE11 and Edge. Change-Id: I3a4ee2742fe8076add5699b26d7c25024d798132 --- M .jshintrc M resources/css/ext.translate.editor.css M resources/js/ext.translate.editor.js M resources/js/ext.translate.quickedit.js M resources/js/jquery.autosize.js 5 files changed, 236 insertions(+), 232 deletions(-) Approvals: Nikerabbit: Looks good to me, approved Siebrand: Looks good to me, but someone else must approve jenkins-bot: Verified diff --git a/.jshintrc b/.jshintrc index 31ce942..c89d583 100644 --- a/.jshintrc +++ b/.jshintrc @@ -15,6 +15,7 @@ "predef": [ "mediaWiki", "jQuery", - "QUnit" + "QUnit", + "autosize" ] } diff --git a/resources/css/ext.translate.editor.css b/resources/css/ext.translate.editor.css index bd1c4bf..77f42d5 100644 --- a/resources/css/ext.translate.editor.css +++ b/resources/css/ext.translate.editor.css @@ -47,7 +47,8 @@ .tux-message-editor textarea { border: 1px solid #555; font-size: 16px; - padding: 5px 5px 30px 5px; + /* The (30px + 5px paddings) 40px for bottom is for the insertables */ + padding: 5px 5px 40px 5px; height: 100px; min-height: 150px; overflow-y: auto; @@ -332,7 +333,8 @@ /* Temporary fix for T111685 */ .grid .tux-editor-actions-block .tux-editor-insert-buttons { position: absolute; - top: -38px; + /* 30px + 5px padding on bottom */ + top: -35px; margin: 0 10px; z-index: 110; } @@ -343,6 +345,7 @@ background: #FBFBFB; color: #252525; font-size: 13px; + height: 30px; } .tux-editor-insert-buttons .tux-editor-paste-original-button { diff --git a/resources/js/ext.translate.editor.js b/resources/js/ext.translate.editor.js index 2631b78..d255d03 100644 --- a/resources/js/ext.translate.editor.js +++ b/resources/js/ext.translate.editor.js @@ -1,4 +1,4 @@ -( function ( $, mw ) { +( function ( $, mw, autosize ) { 'use strict'; /** @@ -43,7 +43,6 @@ this.storage = this.options.storage || new mw.translate.TranslationApiStorage(); this.canDelete = mw.translate.canDelete(); this.delayValidation = delayer(); - this.delayResize = delayer(); } TranslateEditor.prototype = { @@ -530,11 +529,6 @@ if ( mw.translate.isPlaceholderSupported( $textarea ) ) { $textarea.prop( 'placeholder', mw.msg( 'tux-editor-placeholder' ) ); } - - // The extra newlines is supposed to leave enough space for the - // insertion buttons. Seems to work as long as all the buttons - // are only in one line. - $textarea.autosize( { append: '\n\n\n' } ); // Shortcuts for various insertable things $textarea.on( 'keyup keydown', function ( e ) { @@ -1056,13 +1050,7 @@ this.$editor.removeClass( 'hide' ); $textarea.focus(); - // Apparently there is still something going on that affects the - // layout of the text area after this function. Use very small - // delay to have it settle down and have correct results. Otherwise - // there will be a size change once the first letter is typed. - this.delayResize( function () { - $textarea.trigger( 'autosize.resizeIncludeStyle' ); - }, 1 ); + autosize( $textarea ); this.shown = true; this.$editTrigger.addClass( 'open' ); @@ -1220,4 +1208,4 @@ }; }() ); } -}( jQuery, mediaWiki ) ); +}( jQuery, mediaWiki, autosize ) ); diff --git a/resources/js/ext.translate.quickedit.js b/resources/js/ext.translate.quickedit.js index 5a51081..3d9e8cb 100644 --- a/resources/js/ext.translate.quickedit.js +++ b/resources/js/ext.translate.quickedit.js @@ -16,7 +16,7 @@ * @license GPL-2.0+ */ -( function ( $, mw, undefined ) { +( function ( $, mw, autosize ) { 'use strict'; var dialogwidth = false, preloads = {}; @@ -138,7 +138,7 @@ textarea = form.find( '.mw-translate-edit-area' ); textarea.css( 'display', 'block' ); - textarea.autosize(); + autosize( textarea ); textarea[ 0 ].focus(); if ( form.find( '.mw-translate-messagechecks' ) ) { @@ -394,4 +394,4 @@ } ); $( document ).ready( mw.translate.init ); -} )( jQuery, mediaWiki ); +} )( jQuery, mediaWiki, autosize ); diff --git a/resources/js/jquery.autosize.js b/resources/js/jquery.autosize.js index 406ca01..6287305 100644 --- a/resources/js/jquery.autosize.js +++ b/resources/js/jquery.autosize.js @@ -1,242 +1,254 @@ /*! - Autosize v1.17.2 - 2013-07-30 - Automatically adjust textarea height based on user input. - (c) 2013 Jack Moore - http://www.jacklmoore.com/autosize - license: http://www.opensource.org/licenses/mit-license.php - https://raw.github.com/jackmoore/autosize/1.17.2/jquery.autosize.js + Autosize 3.0.15 + license: MIT + http://www.jacklmoore.com/autosize */ -( function ( factory ) { - if ( typeof define === 'function' && define.amd ) { - // AMD. Register as an anonymous module. - define( [ 'jquery' ], factory ); +(function (global, factory) { + if (typeof define === 'function' && define.amd) { + define(['exports', 'module'], factory); + } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') { + factory(exports, module); } else { - // Browser globals: jQuery or jQuery-like library, such as Zepto - factory( window.jQuery || window.$ ); + var mod = { + exports: {} + }; + factory(mod.exports, mod); + global.autosize = mod.exports; } -}( function ( $ ) { - var - defaults = { - className: 'autosizejs', - append: '', - callback: false, - resizeDelay: 10 - }, +})(this, function (exports, module) { + 'use strict'; - // border:0 is unnecessary, but avoids a bug in FireFox on OSX - copy = '<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>', + var set = typeof Set === 'function' ? new Set() : (function () { + var list = []; - // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value. - typographyStyles = [ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'letterSpacing', - 'textTransform', - 'wordSpacing', - 'textIndent' - ], + return { + has: function has(key) { + return Boolean(list.indexOf(key) > -1); + }, + add: function add(key) { + list.push(key); + }, + 'delete': function _delete(key) { + list.splice(list.indexOf(key), 1); + } }; + })(); - // to keep track which textarea is being mirrored when adjust() is called. - mirrored, - - // the mirror element, which is used to calculate what size the mirrored element should be. - mirror = $( copy ).data( 'autosize', true )[ 0 ]; - - // test that line-height can be accurately copied. - mirror.style.lineHeight = '99px'; - if ( $( mirror ).css( 'lineHeight' ) === '99px' ) { - typographyStyles.push( 'lineHeight' ); + var createEvent = function createEvent(name) { + return new Event(name); + }; + try { + new Event('test'); + } catch (e) { + // IE does not support `new Event()` + createEvent = function (name) { + var evt = document.createEvent('Event'); + evt.initEvent(name, true, false); + return evt; + }; } - mirror.style.lineHeight = ''; - $.fn.autosize = function ( options ) { - options = $.extend( {}, defaults, options || {} ); + function assign(ta) { + var _ref = arguments[1] === undefined ? {} : arguments[1]; - if ( mirror.parentNode !== document.body ) { - $( document.body ).append( mirror ); + var _ref$setOverflowX = _ref.setOverflowX; + var setOverflowX = _ref$setOverflowX === undefined ? true : _ref$setOverflowX; + var _ref$setOverflowY = _ref.setOverflowY; + var setOverflowY = _ref$setOverflowY === undefined ? true : _ref$setOverflowY; + + if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || set.has(ta)) return; + + var heightOffset = null; + var overflowY = null; + var clientWidth = ta.clientWidth; + + function init() { + var style = window.getComputedStyle(ta, null); + + overflowY = style.overflowY; + + if (style.resize === 'vertical') { + ta.style.resize = 'none'; + } else if (style.resize === 'both') { + ta.style.resize = 'horizontal'; + } + + if (style.boxSizing === 'content-box') { + heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom)); + } else { + heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth); + } + // Fix when a textarea is not on document body and heightOffset is Not a Number + if (isNaN(heightOffset)) { + heightOffset = 0; + } + + update(); } - return this.each( function () { - var - ta = this, - $ta = $( ta ), - maxHeight, - minHeight, - boxOffset = 0, - callback = $.isFunction( options.callback ), - originalStyles = { - height: ta.style.height, - overflow: ta.style.overflow, - overflowY: ta.style.overflowY, - wordWrap: ta.style.wordWrap, - resize: ta.style.resize - }, - timeout, - width = $ta.width(); + function changeOverflow(value) { + { + // Chrome/Safari-specific fix: + // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space + // made available by removing the scrollbar. The following forces the necessary text reflow. + var width = ta.style.width; + ta.style.width = '0px'; + // Force reflow: + /* jshint ignore:start */ + ta.offsetWidth; + /* jshint ignore:end */ + ta.style.width = width; + } - if ( $ta.data( 'autosize' ) ) { - // exit if autosize has already been applied, or if the textarea is the mirror element. + overflowY = value; + + if (setOverflowY) { + ta.style.overflowY = value; + } + + resize(); + } + + function resize() { + var htmlTop = window.pageYOffset; + var bodyTop = document.body.scrollTop; + var originalHeight = ta.style.height; + + ta.style.height = 'auto'; + + var endHeight = ta.scrollHeight + heightOffset; + + if (ta.scrollHeight === 0) { + // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM. + ta.style.height = originalHeight; return; } - $ta.data( 'autosize', true ); - if ( $ta.css( 'box-sizing' ) === 'border-box' || $ta.css( '-moz-box-sizing' ) === 'border-box' || $ta.css( '-webkit-box-sizing' ) === 'border-box' ) { - boxOffset = $ta.outerHeight() - $ta.height(); - } + ta.style.height = endHeight + 'px'; - // IE8 and lower return 'auto', which parses to NaN, if no min-height is set. - minHeight = Math.max( parseInt( $ta.css( 'minHeight' ), 10 ) - boxOffset || 0, $ta.height() ); + // used to check if an update is actually necessary on window.resize + clientWidth = ta.clientWidth; - $ta.css( { - overflow: 'hidden', - overflowY: 'hidden', - wordWrap: 'break-word', // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width - resize: ( $ta.css( 'resize' ) === 'none' || $ta.css( 'resize' ) === 'vertical' ) ? 'none' : 'horizontal' - } ); + // prevents scroll-position jumping + document.documentElement.scrollTop = htmlTop; + document.body.scrollTop = bodyTop; + } - function initMirror() { - var styles = {}, ignore; + function update() { + var startHeight = ta.style.height; - mirrored = ta; - mirror.className = options.className; - maxHeight = parseInt( $ta.css( 'maxHeight' ), 10 ); + resize(); - // mirror is a duplicate textarea located off-screen that - // is automatically updated to contain the same text as the - // original textarea. mirror always has a height of 0. - // This gives a cross-browser supported way getting the actual - // height of the text, through the scrollTop property. - $.each( typographyStyles, function ( i,val ) { - styles[ val ] = $ta.css( val ); - } ); - $( mirror ).css( styles ); + var style = window.getComputedStyle(ta, null); - // The textarea overflow is probably now hidden, but Chrome doesn't reflow the text to account for the - // new space made available by removing the scrollbars. This workaround causes Chrome to reflow the text. - if ( 'oninput' in ta ) { - var width = ta.style.width; - ta.style.width = '0px'; - ignore = ta.offsetWidth; // This value isn't used, but getting it triggers the necessary reflow - ta.style.width = width; - } - } - - // Using mainly bare JS in this function because it is going - // to fire very often while typing, and needs to very efficient. - function adjust() { - var height, original, width, style; - - if ( mirrored !== ta ) { - initMirror(); - } - - mirror.value = ta.value + options.append; - mirror.style.overflowY = ta.style.overflowY; - original = parseInt( ta.style.height, 10 ); - - // window.getComputedStyle, getBoundingClientRect returning a width are unsupported in IE8 and lower. - // The mirror width must exactly match the textarea width, so using getBoundingClientRect because it doesn't round the sub-pixel value. - if ( 'getComputedStyle' in window ) { - style = window.getComputedStyle( ta ); - width = ta.getBoundingClientRect().width; - - $.each( [ 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth' ], function ( i,val ) { - width -= parseInt( style[ val ], 10 ); - } ); - - mirror.style.width = width + 'px'; - } else { - mirror.style.width = Math.max( $ta.width(), 0 ) + 'px'; - } - - // Needed for IE8 and lower to reliably return the correct scrollTop - mirror.scrollTop = 0; - - mirror.scrollTop = 9e4; - - // Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding. - height = mirror.scrollTop; - - if ( maxHeight && height > maxHeight ) { - ta.style.overflowY = 'scroll'; - height = maxHeight; - } else { - ta.style.overflowY = 'hidden'; - if ( height < minHeight ) { - height = minHeight; - } - } - - height += boxOffset; - - if ( original !== height ) { - ta.style.height = height + 'px'; - if ( callback ) { - options.callback.call( ta, ta ); - } - } - } - - function resize() { - clearTimeout( timeout ); - timeout = setTimeout( function () { - if ( $ta.width() !== width ) { - adjust(); - } - }, parseInt( options.resizeDelay, 10 ) ); - } - - if ( 'onpropertychange' in ta ) { - if ( 'oninput' in ta ) { - // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions, - // so binding to onkeyup to catch most of those occasions. There is no way that I - // know of to detect something like 'cut' in IE9. - $ta.on( 'input.autosize keyup.autosize', adjust ); - } else { - // IE7 / IE8 - $ta.on( 'propertychange.autosize', function () { - if ( event.propertyName === 'value' ) { - adjust(); - } - } ); + if (style.height !== ta.style.height) { + if (overflowY !== 'visible') { + changeOverflow('visible'); } } else { - // Modern Browsers - $ta.on( 'input.autosize', adjust ); + if (overflowY !== 'hidden') { + changeOverflow('hidden'); + } } - // Set options.resizeDelay to false if using fixed-width textarea elements. - // Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize. - - if ( options.resizeDelay !== false ) { - $( window ).on( 'resize.autosize', resize ); + if (startHeight !== ta.style.height) { + var evt = createEvent('autosize:resized'); + ta.dispatchEvent(evt); } + } - // Event for manual triggering if needed. - // Should only be needed when the value of the textarea is changed through JavaScript rather than user input. - $ta.on( 'autosize.resize', adjust ); + var pageResize = function pageResize() { + if (ta.clientWidth !== clientWidth) { + update(); + } + }; - // Event for manual triggering that also forces the styles to update as well. - // Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method. - $ta.on( 'autosize.resizeIncludeStyle', function () { - mirrored = null; - adjust(); - } ); + var destroy = (function (style) { + window.removeEventListener('resize', pageResize, false); + ta.removeEventListener('input', update, false); + ta.removeEventListener('keyup', update, false); + ta.removeEventListener('autosize:destroy', destroy, false); + ta.removeEventListener('autosize:update', update, false); + set['delete'](ta); - $ta.on( 'autosize.destroy', function () { - mirrored = null; - clearTimeout( timeout ); - $( window ).off( 'resize', resize ); - $ta - .off( 'autosize' ) - .off( '.autosize' ) - .css( originalStyles ) - .removeData( 'autosize' ); - } ); + Object.keys(style).forEach(function (key) { + ta.style[key] = style[key]; + }); + }).bind(ta, { + height: ta.style.height, + resize: ta.style.resize, + overflowY: ta.style.overflowY, + overflowX: ta.style.overflowX, + wordWrap: ta.style.wordWrap }); - // Call adjust in case the textarea already contains text. - adjust(); - } ); - }; -} ) ); + ta.addEventListener('autosize:destroy', destroy, false); + + // IE9 does not fire onpropertychange or oninput for deletions, + // so binding to onkeyup to catch most of those events. + // There is no way that I know of to detect something like 'cut' in IE9. + if ('onpropertychange' in ta && 'oninput' in ta) { + ta.addEventListener('keyup', update, false); + } + + window.addEventListener('resize', pageResize, false); + ta.addEventListener('input', update, false); + ta.addEventListener('autosize:update', update, false); + set.add(ta); + + if (setOverflowX) { + ta.style.overflowX = 'hidden'; + ta.style.wordWrap = 'break-word'; + } + + init(); + } + + function destroy(ta) { + if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return; + var evt = createEvent('autosize:destroy'); + ta.dispatchEvent(evt); + } + + function update(ta) { + if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return; + var evt = createEvent('autosize:update'); + ta.dispatchEvent(evt); + } + + var autosize = null; + + // Do nothing in Node.js environment and IE8 (or lower) + if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') { + autosize = function (el) { + return el; + }; + autosize.destroy = function (el) { + return el; + }; + autosize.update = function (el) { + return el; + }; + } else { + autosize = function (el, options) { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], function (x) { + return assign(x, options); + }); + } + return el; + }; + autosize.destroy = function (el) { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], destroy); + } + return el; + }; + autosize.update = function (el) { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], update); + } + return el; + }; + } + + module.exports = autosize; +}); -- To view, visit https://gerrit.wikimedia.org/r/274871 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I3a4ee2742fe8076add5699b26d7c25024d798132 Gerrit-PatchSet: 4 Gerrit-Project: mediawiki/extensions/Translate Gerrit-Branch: master Gerrit-Owner: Siebrand <[email protected]> Gerrit-Reviewer: Nikerabbit <[email protected]> Gerrit-Reviewer: Siebrand <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
