Merge pull request #1407 from nextcloud/multiline_comments

Bring back multiline comments
This commit is contained in:
Morris Jobke 2016-10-11 16:17:51 +02:00 committed by GitHub
commit 675230f86d
9 changed files with 348 additions and 7 deletions

View File

@ -21,15 +21,16 @@
width: calc(100% - 81px); /* 36 (left margin) + 30 (right padding) + 15 (right padding of surrounding box) */ width: calc(100% - 81px); /* 36 (left margin) + 30 (right padding) + 15 (right padding of surrounding box) */
margin-left: 36px; margin-left: 36px;
padding-right: 30px; padding-right: 30px;
display: block;
} }
#commentsTabView .newCommentForm .submit { #commentsTabView .newCommentForm .submit {
position: absolute; position: absolute;
top: 1px; bottom: 0px;
right: 8px; right: 8px;
width: 30px; width: 30px;
margin: 0; margin: 0;
padding: 9px; padding: 7px 9px;
background-color: transparent; background-color: transparent;
border: none; border: none;
opacity: .3; opacity: .3;
@ -47,6 +48,10 @@
margin-right: 6px; margin-right: 6px;
} }
#commentsTabView .newCommentForm textarea {
resize: none;
}
#commentsTabView .comment { #commentsTabView .comment {
position: relative; position: relative;
z-index: 1; z-index: 1;

View File

@ -32,7 +32,7 @@
'{{/if}}' + '{{/if}}' +
' </div>' + ' </div>' +
' <form class="newCommentForm">' + ' <form class="newCommentForm">' +
' <input type="text" class="message" placeholder="{{newMessagePlaceholder}}" value="{{message}}" />' + ' <textarea rows="1" class="message" placeholder="{{newMessagePlaceholder}}">{{message}}</textarea>' +
' <input class="submit icon-confirm" type="submit" value="" />' + ' <input class="submit icon-confirm" type="submit" value="" />' +
'{{#if isEditMode}}' + '{{#if isEditMode}}' +
' <input class="cancel pull-right" type="button" value="{{cancelText}}" />' + ' <input class="cancel pull-right" type="button" value="{{cancelText}}" />' +
@ -174,6 +174,8 @@
} }
this.delegateEvents(); this.delegateEvents();
this.$el.find('.message').on('keydown input change', this._onTypeComment); this.$el.find('.message').on('keydown input change', this._onTypeComment);
autosize(this.$el.find('.newCommentRow textarea'))
}, },
_formatItem: function(commentModel) { _formatItem: function(commentModel) {
@ -281,6 +283,9 @@
$formRow.find('.avatar').replaceWith($comment.find('.avatar').clone()); $formRow.find('.avatar').replaceWith($comment.find('.avatar').clone());
$formRow.find('.has-tooltip').tooltip(); $formRow.find('.has-tooltip').tooltip();
// Enable autosize
autosize($formRow.find('textarea'));
return false; return false;
}, },
@ -346,7 +351,6 @@
} }
}); });
return false; return false;
}, },

View File

@ -328,7 +328,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
expect($formRow.length).toEqual(1); expect($formRow.length).toEqual(1);
$formRow.find('input').val('modified message'); $formRow.find('textarea').val('modified message');
$formRow.find('form').submit(); $formRow.find('form').submit();
expect(saveStub.calledOnce).toEqual(true); expect(saveStub.calledOnce).toEqual(true);

View File

@ -31,6 +31,7 @@
"davclient.js": "https://github.com/evert/davclient.js.git", "davclient.js": "https://github.com/evert/davclient.js.git",
"es6-promise": "https://github.com/jakearchibald/es6-promise.git#~2.3.0", "es6-promise": "https://github.com/jakearchibald/es6-promise.git#~2.3.0",
"base64": "~0.3.0", "base64": "~0.3.0",
"clipboard": "^1.5.12" "clipboard": "^1.5.12",
"autosize": "^3.0.17"
} }
} }

View File

@ -11,7 +11,8 @@
"backbone/backbone.js", "backbone/backbone.js",
"es6-promise/dist/es6-promise.js", "es6-promise/dist/es6-promise.js",
"davclient.js/lib/client.js", "davclient.js/lib/client.js",
"clipboard/dist/clipboard.js" "clipboard/dist/clipboard.js",
"autosize/dist/autosize.js"
], ],
"libraries": [ "libraries": [
"jquery-showpassword.js", "jquery-showpassword.js",

View File

@ -142,3 +142,10 @@ base64/*min.js
clipboard/** clipboard/**
!clipboard/dist !clipboard/dist
!clipboard/dist/clipboard.js !clipboard/dist/clipboard.js
# autosize
autosize/**
!autosize/dist
!autosize/dist/autosize.js
!autosize/.bower.json
!autosize/LICENCE.md

40
core/vendor/autosize/.bower.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"name": "autosize",
"description": "Autosize is a small, stand-alone script to automatically adjust textarea height to fit text.",
"dependencies": {},
"keywords": [
"textarea",
"form",
"ui"
],
"authors": [
{
"name": "Jack Moore",
"url": "http://www.jacklmoore.com",
"email": "hello@jacklmoore.com"
}
],
"license": "MIT",
"homepage": "http://www.jacklmoore.com/autosize",
"ignore": [],
"repository": {
"type": "git",
"url": "http://github.com/jackmoore/autosize.git"
},
"main": "dist/autosize.js",
"moduleType": [
"amd",
"node"
],
"version": "3.0.17",
"_release": "3.0.17",
"_resolution": {
"type": "version",
"tag": "3.0.17",
"commit": "144040e4f545fbea9b304706a5200eba9961ee3f"
},
"_source": "https://github.com/jackmoore/autosize.git",
"_target": "^3.0.17",
"_originalSource": "autosize",
"_direct": true
}

21
core/vendor/autosize/LICENSE.md vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Jack Moore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

262
core/vendor/autosize/dist/autosize.js vendored Normal file
View File

@ -0,0 +1,262 @@
/*!
Autosize 3.0.17
license: MIT
http://www.jacklmoore.com/autosize
*/
(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 {
var mod = {
exports: {}
};
factory(mod.exports, mod);
global.autosize = mod.exports;
}
})(this, function (exports, module) {
'use strict';
var set = typeof Set === 'function' ? new Set() : (function () {
var list = [];
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);
} };
})();
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;
};
}
function assign(ta) {
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || set.has(ta)) return;
var heightOffset = null;
var clientWidth = ta.clientWidth;
var cachedHeight = null;
function init() {
var style = window.getComputedStyle(ta, null);
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();
}
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;
}
ta.style.overflowY = value;
resize();
}
function getParentOverflows(el) {
var arr = [];
while (el && el.parentNode && el.parentNode instanceof Element) {
if (el.parentNode.scrollTop) {
arr.push({
node: el.parentNode,
scrollTop: el.parentNode.scrollTop });
}
el = el.parentNode;
}
return arr;
}
function resize() {
var originalHeight = ta.style.height;
var overflows = getParentOverflows(ta);
var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
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.style.height = endHeight + 'px';
// used to check if an update is actually necessary on window.resize
clientWidth = ta.clientWidth;
// prevents scroll-position jumping
overflows.forEach(function (el) {
el.node.scrollTop = el.scrollTop;
});
if (docTop) {
document.documentElement.scrollTop = docTop;
}
}
function update() {
resize();
var computed = window.getComputedStyle(ta, null);
var computedHeight = Math.round(parseFloat(computed.height));
var styleHeight = Math.round(parseFloat(ta.style.height));
// The computed height not matching the height set via resize indicates that
// the max-height has been exceeded, in which case the overflow should be set to visible.
if (computedHeight !== styleHeight) {
if (computed.overflowY !== 'visible') {
changeOverflow('visible');
}
} else {
// Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
if (computed.overflowY !== 'hidden') {
changeOverflow('hidden');
}
}
if (cachedHeight !== computedHeight) {
cachedHeight = computedHeight;
var evt = createEvent('autosize:resized');
ta.dispatchEvent(evt);
}
}
var pageResize = function pageResize() {
if (ta.clientWidth !== clientWidth) {
update();
}
};
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);
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 });
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);
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;
});