diff options
author | Eric Eastwood <contact@ericeastwood.com> | 2017-10-16 10:58:55 -0500 |
---|---|---|
committer | Eric Eastwood <contact@ericeastwood.com> | 2017-10-17 14:47:47 -0500 |
commit | bc3195da0a44170eabfde6b6d601381345bf818a (patch) | |
tree | cbe9d94f419deaee13b144a1e7d996d59561139b | |
parent | b3f749036ea919de3982c81b157ab2d790ecb4c5 (diff) | |
download | gitlab-ce-add-lazy-option-to-user-avatar-image-component.tar.gz |
Add lazy option to UserAvatarImageadd-lazy-option-to-user-avatar-image-component
3 files changed, 78 insertions, 28 deletions
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue index dd9a2ebb184..1ac61a3c39b 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue @@ -7,6 +7,7 @@ Sample configuration: <user-avatar-image + :lazy="true" :img-src="userAvatarSrc" :img-alt="tooltipText" :tooltip-text="tooltipText" @@ -16,11 +17,17 @@ */ import defaultAvatarUrl from 'images/no_avatar.png'; +import { placeholderImage } from '../../../lazy_loader'; import tooltip from '../../directives/tooltip'; export default { name: 'UserAvatarImage', props: { + lazy: { + type: Boolean, + required: false, + default: false, + }, imgSrc: { type: String, required: false, @@ -56,18 +63,21 @@ export default { tooltip, }, computed: { + // API response sends null when gravatar is disabled and + // we provide an empty string when we use it inside user avatar link. + // In both cases we should render the defaultAvatarUrl + sanitizedSource() { + return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc; + }, + resultantSrcAttribute() { + return this.lazy ? placeholderImage : this.sanitizedSource; + }, tooltipContainer() { return this.tooltipText ? 'body' : null; }, avatarSizeClass() { return `s${this.size}`; }, - // API response sends null when gravatar is disabled and - // we provide an empty string when we use it inside user avatar link. - // In both cases we should render the defaultAvatarUrl - imageSource() { - return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc; - }, }, }; </script> @@ -76,11 +86,16 @@ export default { <img v-tooltip class="avatar" - :class="[avatarSizeClass, cssClasses]" - :src="imageSource" + :class="{ + lazy, + [avatarSizeClass]: true, + [cssClasses]: true + }" + :src="resultantSrcAttribute" :width="size" :height="size" :alt="imgAlt" + :data-src="sanitizedSource" :data-container="tooltipContainer" :data-placement="tooltipPlacement" :title="tooltipText" diff --git a/changelogs/unreleased/add-lazy-option-to-user-avatar-image-component.yml b/changelogs/unreleased/add-lazy-option-to-user-avatar-image-component.yml new file mode 100644 index 00000000000..eef78cd58f9 --- /dev/null +++ b/changelogs/unreleased/add-lazy-option-to-user-avatar-image-component.yml @@ -0,0 +1,5 @@ +--- +title: Add lazy option to UserAvatarImage +merge_request: 14895 +author: +type: changed diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js index 8daa7610274..aa93134f2dd 100644 --- a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js +++ b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js @@ -1,54 +1,84 @@ import Vue from 'vue'; -import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; +import { placeholderImage } from '~/lazy_loader'; +import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; +import mountComponent from '../../../helpers/vue_mount_component_helper'; -const UserAvatarImageComponent = Vue.extend(UserAvatarImage); +const DEFAULT_PROPS = { + size: 99, + imgSrc: 'myavatarurl.com', + imgAlt: 'mydisplayname', + cssClasses: 'myextraavatarclass', + tooltipText: 'tooltip text', + tooltipPlacement: 'bottom', +}; describe('User Avatar Image Component', function () { + let vm; + let UserAvatarImage; + + beforeEach(() => { + UserAvatarImage = Vue.extend(userAvatarImage); + }); + describe('Initialization', function () { beforeEach(function () { - this.propsData = { - size: 99, - imgSrc: 'myavatarurl.com', - imgAlt: 'mydisplayname', - cssClasses: 'myextraavatarclass', - tooltipText: 'tooltip text', - tooltipPlacement: 'bottom', - }; - - this.userAvatarImage = new UserAvatarImageComponent({ - propsData: this.propsData, + vm = mountComponent(UserAvatarImage, { + ...DEFAULT_PROPS, }).$mount(); }); it('should return a defined Vue component', function () { - expect(this.userAvatarImage).toBeDefined(); + expect(vm).toBeDefined(); }); it('should have <img> as a child element', function () { - expect(this.userAvatarImage.$el.tagName).toBe('IMG'); + expect(vm.$el.tagName).toBe('IMG'); + expect(vm.$el.getAttribute('src')).toBe(DEFAULT_PROPS.imgSrc); + expect(vm.$el.getAttribute('data-src')).toBe(DEFAULT_PROPS.imgSrc); + expect(vm.$el.getAttribute('alt')).toBe(DEFAULT_PROPS.imgAlt); }); it('should properly compute tooltipContainer', function () { - expect(this.userAvatarImage.tooltipContainer).toBe('body'); + expect(vm.tooltipContainer).toBe('body'); }); it('should properly render tooltipContainer', function () { - expect(this.userAvatarImage.$el.getAttribute('data-container')).toBe('body'); + expect(vm.$el.getAttribute('data-container')).toBe('body'); }); it('should properly compute avatarSizeClass', function () { - expect(this.userAvatarImage.avatarSizeClass).toBe('s99'); + expect(vm.avatarSizeClass).toBe('s99'); }); it('should properly render img css', function () { - const classList = this.userAvatarImage.$el.classList; + const classList = vm.$el.classList; const containsAvatar = classList.contains('avatar'); const containsSizeClass = classList.contains('s99'); - const containsCustomClass = classList.contains('myextraavatarclass'); + const containsCustomClass = classList.contains(DEFAULT_PROPS.cssClasses); + const lazyClass = classList.contains('lazy'); expect(containsAvatar).toBe(true); expect(containsSizeClass).toBe(true); expect(containsCustomClass).toBe(true); + expect(lazyClass).toBe(false); + }); + }); + + describe('Initialization when lazy', function () { + beforeEach(function () { + vm = mountComponent(UserAvatarImage, { + ...DEFAULT_PROPS, + lazy: true, + }).$mount(); + }); + + it('should add lazy attributes', function () { + const classList = vm.$el.classList; + const lazyClass = classList.contains('lazy'); + + expect(lazyClass).toBe(true); + expect(vm.$el.getAttribute('src')).toBe(placeholderImage); + expect(vm.$el.getAttribute('data-src')).toBe(DEFAULT_PROPS.imgSrc); }); }); }); |