Feature: ResizableTextArea in widget and dashboard (#969)

* Create ResizableTextArea component
* Rubocop fixes and spec fixes

Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
Pranav Raj S 2020-06-18 15:17:45 +05:30 committed by GitHub
parent 04f6460afb
commit 963f173730
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 208 additions and 185 deletions

View file

@ -8,8 +8,17 @@ Lint/RaiseException:
Enabled: true
Lint/StructNewOverride:
Enabled: true
Lint/DeprecatedOpenSSLConstant:
Enabled: true
Lint/MixedRegexpCaptureTypes:
Enabled: true
Layout/LineLength:
Max: 150
Layout/EmptyLinesAroundAttributeAccessor:
Enabled: true
Layout/SpaceAroundMethodCallOperator:
Enabled: true
Metrics/ClassLength:
Max: 125
Exclude:
@ -18,6 +27,8 @@ RSpec/ExampleLength:
Max: 25
Style/Documentation:
Enabled: false
Style/ExponentialNotation:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Style/SymbolArray:
@ -28,6 +39,12 @@ Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
Style/RedundantRegexpCharacterClass:
Enabled: true
Style/RedundantRegexpEscape:
Enabled: true
Style/SlicingWithRange:
Enabled: true
Style/GlobalVars:
Exclude:
- 'config/initializers/redis.rb'

View file

@ -18,56 +18,56 @@ GEM
specs:
action-cable-testing (0.6.1)
actioncable (>= 5.0)
actioncable (6.0.3.1)
actionpack (= 6.0.3.1)
actioncable (6.0.3.2)
actionpack (= 6.0.3.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.0.3.1)
actionpack (= 6.0.3.1)
activejob (= 6.0.3.1)
activerecord (= 6.0.3.1)
activestorage (= 6.0.3.1)
activesupport (= 6.0.3.1)
actionmailbox (6.0.3.2)
actionpack (= 6.0.3.2)
activejob (= 6.0.3.2)
activerecord (= 6.0.3.2)
activestorage (= 6.0.3.2)
activesupport (= 6.0.3.2)
mail (>= 2.7.1)
actionmailer (6.0.3.1)
actionpack (= 6.0.3.1)
actionview (= 6.0.3.1)
activejob (= 6.0.3.1)
actionmailer (6.0.3.2)
actionpack (= 6.0.3.2)
actionview (= 6.0.3.2)
activejob (= 6.0.3.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.0.3.1)
actionview (= 6.0.3.1)
activesupport (= 6.0.3.1)
actionpack (6.0.3.2)
actionview (= 6.0.3.2)
activesupport (= 6.0.3.2)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.3.1)
actionpack (= 6.0.3.1)
activerecord (= 6.0.3.1)
activestorage (= 6.0.3.1)
activesupport (= 6.0.3.1)
actiontext (6.0.3.2)
actionpack (= 6.0.3.2)
activerecord (= 6.0.3.2)
activestorage (= 6.0.3.2)
activesupport (= 6.0.3.2)
nokogiri (>= 1.8.5)
actionview (6.0.3.1)
activesupport (= 6.0.3.1)
actionview (6.0.3.2)
activesupport (= 6.0.3.2)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.0.3.1)
activesupport (= 6.0.3.1)
activejob (6.0.3.2)
activesupport (= 6.0.3.2)
globalid (>= 0.3.6)
activemodel (6.0.3.1)
activesupport (= 6.0.3.1)
activerecord (6.0.3.1)
activemodel (= 6.0.3.1)
activesupport (= 6.0.3.1)
activestorage (6.0.3.1)
actionpack (= 6.0.3.1)
activejob (= 6.0.3.1)
activerecord (= 6.0.3.1)
activemodel (6.0.3.2)
activesupport (= 6.0.3.2)
activerecord (6.0.3.2)
activemodel (= 6.0.3.2)
activesupport (= 6.0.3.2)
activestorage (6.0.3.2)
actionpack (= 6.0.3.2)
activejob (= 6.0.3.2)
activerecord (= 6.0.3.2)
marcel (~> 0.3.1)
activesupport (6.0.3.1)
activesupport (6.0.3.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -91,25 +91,25 @@ GEM
annotate (3.1.1)
activerecord (>= 3.2, < 7.0)
rake (>= 10.4, < 14.0)
ast (2.4.0)
attr_extras (6.2.3)
ast (2.4.1)
attr_extras (6.2.4)
autoprefixer-rails (9.7.6)
execjs
aws-eventstream (1.1.0)
aws-partitions (1.317.0)
aws-sdk-core (3.96.1)
aws-partitions (1.329.0)
aws-sdk-core (3.100.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.31.0)
aws-sdk-core (~> 3, >= 3.71.0)
aws-sdk-kms (1.34.1)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.65.0)
aws-sdk-core (~> 3, >= 3.96.1)
aws-sdk-s3 (1.68.1)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.3)
aws-sigv4 (1.1.4)
aws-eventstream (~> 1.0, >= 1.0.2)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
@ -127,22 +127,22 @@ GEM
bootsnap (1.4.6)
msgpack (~> 1.0)
brakeman (4.8.2)
browser (4.1.0)
browser (4.2.0)
builder (3.2.4)
bullet (6.1.0)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundle-audit (0.1.0)
bundler-audit
bundler-audit (0.6.1)
bundler-audit (0.7.0.1)
bundler (>= 1.2.0, < 3)
thor (~> 0.18)
thor (>= 0.18, < 2)
byebug (11.1.3)
coderay (1.1.2)
coderay (1.1.3)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.1.6)
connection_pool (2.2.2)
connection_pool (2.2.3)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.6)
@ -152,16 +152,17 @@ GEM
declarative-option (0.1.0)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.7.1)
devise (4.7.2)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise_token_auth (1.1.3)
devise_token_auth (1.1.4)
bcrypt (~> 3.0)
devise (> 3.5.2, < 5)
rails (>= 4.2.0, < 6.1)
sprockets (= 3.7.2)
diff-lcs (1.3)
digest-crc (0.5.1)
docile (1.3.2)
@ -182,7 +183,7 @@ GEM
factory_bot_rails (5.2.0)
factory_bot (~> 5.2.0)
railties (>= 4.2.0)
faker (2.11.0)
faker (2.12.0)
i18n (>= 1.6, < 2)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
@ -190,13 +191,13 @@ GEM
faraday (~> 1.0)
fcm (1.0.1)
faraday (~> 1.0.0)
ffi (1.12.2)
ffi (1.13.1)
flag_shih_tzu (0.3.23)
foreman (0.87.1)
gli (2.19.0)
gli (2.19.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
google-api-client (0.39.4)
google-api-client (0.40.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
@ -207,10 +208,10 @@ GEM
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.3.1)
google-cloud-env (1.3.2)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.0)
google-cloud-storage (1.26.1)
google-cloud-errors (1.0.1)
google-cloud-storage (1.26.2)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
@ -234,11 +235,11 @@ GEM
http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
httparty (0.18.0)
httparty (0.18.1)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.8.2)
i18n (1.8.3)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
inflecto (0.0.2)
@ -274,7 +275,7 @@ GEM
listen (3.2.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.5.0)
loofah (2.6.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@ -304,8 +305,8 @@ GEM
oauth (0.5.4)
orm_adapter (0.5.0)
os (1.1.0)
parallel (1.19.1)
parser (2.7.1.2)
parallel (1.19.2)
parser (2.7.1.3)
ast (~> 2.4.0)
pg (1.2.3)
pry (0.13.1)
@ -318,8 +319,8 @@ GEM
nio4r (~> 2.0)
pundit (2.1.0)
activesupport (>= 3.0.0)
rack (2.2.2)
rack-cache (1.11.1)
rack (2.2.3)
rack-cache (1.12.0)
rack (>= 0.4)
rack-cors (1.1.1)
rack (>= 2.0.0)
@ -329,29 +330,29 @@ GEM
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (6.0.3.1)
actioncable (= 6.0.3.1)
actionmailbox (= 6.0.3.1)
actionmailer (= 6.0.3.1)
actionpack (= 6.0.3.1)
actiontext (= 6.0.3.1)
actionview (= 6.0.3.1)
activejob (= 6.0.3.1)
activemodel (= 6.0.3.1)
activerecord (= 6.0.3.1)
activestorage (= 6.0.3.1)
activesupport (= 6.0.3.1)
rails (6.0.3.2)
actioncable (= 6.0.3.2)
actionmailbox (= 6.0.3.2)
actionmailer (= 6.0.3.2)
actionpack (= 6.0.3.2)
actiontext (= 6.0.3.2)
actionview (= 6.0.3.2)
activejob (= 6.0.3.2)
activemodel (= 6.0.3.2)
activerecord (= 6.0.3.2)
activestorage (= 6.0.3.2)
activesupport (= 6.0.3.2)
bundler (>= 1.3.0)
railties (= 6.0.3.1)
railties (= 6.0.3.2)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
railties (6.0.3.1)
actionpack (= 6.0.3.1)
activesupport (= 6.0.3.1)
railties (6.0.3.2)
actionpack (= 6.0.3.2)
activesupport (= 6.0.3.2)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
@ -360,7 +361,7 @@ GEM
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
redis (4.1.4)
redis (4.2.1)
redis-namespace (1.7.0)
redis (>= 3.0.4)
redis-rack-cache (2.2.1)
@ -368,11 +369,12 @@ GEM
redis-store (>= 1.6, < 2)
redis-store (1.8.2)
redis (>= 4, < 5)
regexp_parser (1.7.1)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
responders (3.0.0)
responders (3.0.1)
actionpack (>= 5.0)
railties (>= 5.0)
rest-client (2.1.0)
@ -399,20 +401,24 @@ GEM
rspec-mocks (~> 3.9)
rspec-support (~> 3.9)
rspec-support (3.9.3)
rubocop (0.83.0)
rubocop (0.85.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7)
rexml
rubocop-ast (>= 0.0.3)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-performance (1.5.2)
rubocop-ast (0.0.3)
parser (>= 2.7.0.1)
rubocop-performance (1.6.1)
rubocop (>= 0.71.0)
rubocop-rails (2.5.2)
activesupport
rubocop-rails (2.6.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 0.72.0)
rubocop-rspec (1.39.0)
rubocop (>= 0.82.0)
rubocop-rspec (1.40.0)
rubocop (>= 0.68.1)
ruby-progressbar (1.10.1)
safe_yaml (1.0.5)
@ -421,7 +427,7 @@ GEM
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sassc (2.3.0)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
@ -468,7 +474,7 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (4.0.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
@ -480,7 +486,7 @@ GEM
inflecto
virtus
telephone_number (1.4.7)
thor (0.20.3)
thor (1.0.1)
thread_safe (0.3.6)
tilt (2.0.10)
time_diff (0.3.0)
@ -514,7 +520,7 @@ GEM
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.8)
rack (>= 2.0.6)
web-console (4.0.2)
web-console (4.0.3)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
@ -531,7 +537,7 @@ GEM
webpush (1.0.0)
hkdf (~> 0.2)
jwt (~> 2.0)
websocket-driver (0.7.1)
websocket-driver (0.7.2)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
wisper (2.0.0)

View file

@ -3,7 +3,7 @@
border-bottom: 0;
margin: $space-normal;
margin-top: 0;
max-height: $space-jumbo * 2;
max-height: $space-mega * 3;
transition: height 2s $ease-in-out-cubic;
.reply-box__top {
@ -74,7 +74,8 @@
background: transparent;
// Override min-height : 50px in foundation
//
min-height: 1rem;
max-height: $space-mega * 2.4;
min-height: 4rem;
resize: none;
}
}

View file

@ -13,13 +13,12 @@
v-on-clickaway="hideEmojiPicker"
:on-click="emojiOnClick"
/>
<textarea
<resizable-text-area
ref="messageInput"
v-model="message"
rows="1"
class="input"
type="text"
:placeholder="$t(messagePlaceHolder())"
:min-height="4"
@focus="onFocus"
@blur="onBlur"
/>
@ -93,12 +92,14 @@ import FileUpload from 'vue-upload-component';
import EmojiInput from '../emoji/EmojiInput';
import CannedResponse from './CannedResponse';
import ResizableTextArea from 'shared/components/ResizableTextArea';
export default {
components: {
EmojiInput,
CannedResponse,
FileUpload,
ResizableTextArea,
},
mixins: [clickaway],
data() {

View file

@ -0,0 +1,56 @@
<template>
<textarea
ref="textarea"
:placeholder="placeholder"
:value="value"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
/>
</template>
<script>
export default {
props: {
placeholder: {
type: String,
default: '',
},
value: {
type: String,
default: '',
},
minHeight: {
type: Number,
default: 3.2,
},
},
watch: {
value() {
this.resizeTextarea();
},
},
methods: {
resizeTextarea() {
if (!this.value) {
this.$el.style.height = `${this.minHeight}rem`;
} else {
this.$el.style.height = `${this.$el.scrollHeight}px`;
}
},
onInput(event) {
this.$emit('input', event.target.value);
this.resizeTextarea();
},
onBlur() {
this.$emit('blur');
},
onFocus() {
this.$emit('focus');
},
focus() {
this.$refs.textarea.focus();
},
},
};
</script>

View file

@ -1,56 +0,0 @@
<template>
<resizable-textarea>
<textarea
class="form-input user-message-input"
:placeholder="placeholder"
:value="value"
@input="$emit('input', $event.target.value)"
@focus="onFocus"
@blur="onBlur"
/>
</resizable-textarea>
</template>
<script>
import ResizableTextarea from 'widget/components/ResizableTextarea.vue';
export default {
components: {
ResizableTextarea,
},
props: {
placeholder: {
type: String,
default: '',
},
value: {
type: String,
default: '',
},
},
methods: {
onBlur() {
this.toggleTyping('off');
},
onFocus() {
this.toggleTyping('on');
},
toggleTyping(typingStatus) {
this.$store.dispatch('conversation/toggleUserTyping', { typingStatus });
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
.user-message-input {
border: 0;
height: $space-large;
min-height: $space-large;
resize: none;
padding-top: $space-small;
}
</style>

View file

@ -1,8 +1,11 @@
<template>
<div class="chat-message--input">
<chat-input-area
<resizable-text-area
v-model="userInput"
:placeholder="$t('CHAT_PLACEHOLDER')"
class="form-input user-message-input"
@focus="onFocus"
@blur="onBlur"
/>
<div class="button-wrap">
<chat-attachment-button
@ -34,7 +37,7 @@ import emojione from 'emojione';
import { mixin as clickaway } from 'vue-clickaway';
import ChatSendButton from 'widget/components/ChatSendButton.vue';
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
import ChatInputArea from 'widget/components/ChatInputArea.vue';
import ResizableTextArea from 'shared/components/ResizableTextArea';
import EmojiInput from 'dashboard/components/widgets/emoji/EmojiInput';
export default {
@ -42,8 +45,8 @@ export default {
components: {
ChatAttachmentButton,
ChatSendButton,
ChatInputArea,
EmojiInput,
ResizableTextArea,
},
mixins: [clickaway],
props: {
@ -109,6 +112,16 @@ export default {
`${this.userInput}${emoji.shortname} `
);
},
onBlur() {
this.toggleTyping('off');
},
onFocus() {
this.toggleTyping('on');
},
toggleTyping(typingStatus) {
this.$store.dispatch('conversation/toggleUserTyping', { typingStatus });
},
},
};
</script>
@ -140,4 +153,13 @@ export default {
display: flex;
align-items: center;
}
.user-message-input {
border: 0;
height: $space-large;
min-height: $space-large;
max-height: 2.4 * $space-mega;
resize: none;
padding-top: $space-small;
}
</style>

View file

@ -1,26 +0,0 @@
<script>
export default {
mounted() {
this.$nextTick(() => {
this.$el.setAttribute(
'style',
`height: ${this.$el.scrollHeight}px;overflow-y:hidden;`
);
});
this.$el.addEventListener('input', this.resizeTextarea);
},
beforeDestroy() {
this.$el.removeEventListener('input', this.resizeTextarea);
},
methods: {
resizeTextarea(event) {
event.target.style.height = '3.2rem';
event.target.style.height = `${event.target.scrollHeight}px`;
},
},
render() {
return this.$slots.default[0];
},
};
</script>

View file

@ -43,6 +43,7 @@ export default {
line-height: 1.5;
padding: $space-slab $space-normal $space-slab $space-normal;
text-align: left;
word-break: break-word;
> a {
color: $color-primary;

View file

@ -80,7 +80,7 @@ class MailPresenter < SimpleDelegator
{
reply: content[0..(index - 1)].strip,
quoted_text: content[index..-1].strip
quoted_text: content[index..].strip
}
end

View file

@ -12,3 +12,4 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules')
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.precompile += %w[dashboardChart.js]