Merge pull request #15360 from netchampfaris/marketplaces-fixes
fix(image): New Image component to consistently handle broken images
diff --git a/erpnext/public/js/hub/components/DetailView.vue b/erpnext/public/js/hub/components/DetailView.vue
index 2f1a941..cc09982 100644
--- a/erpnext/public/js/hub/components/DetailView.vue
+++ b/erpnext/public/js/hub/components/DetailView.vue
@@ -28,7 +28,7 @@
<div class="row margin-bottom">
<div class="col-md-3">
<div class="hub-item-image">
- <img v-img-src="image">
+ <base-image :src="image" :alt="title" />
</div>
</div>
<div class="col-md-8">
diff --git a/erpnext/public/js/hub/components/Image.vue b/erpnext/public/js/hub/components/Image.vue
new file mode 100644
index 0000000..9acf421
--- /dev/null
+++ b/erpnext/public/js/hub/components/Image.vue
@@ -0,0 +1,40 @@
+<template>
+ <div class="hub-image">
+ <img :src="src" :alt="alt" v-show="!is_loading && !is_broken"/>
+ <div class="hub-image-loading" v-if="is_loading">
+ <span class="octicon octicon-cloud-download"></span>
+ </div>
+ <div class="hub-image-broken" v-if="is_broken">
+ <span class="octicon octicon-file-media"></span>
+ </div>
+ </div>
+</template>
+<script>
+export default {
+ name: 'Image',
+ props: ['src', 'alt'],
+ data() {
+ return {
+ is_loading: true,
+ is_broken: false
+ }
+ },
+ created() {
+ this.handle_image();
+ },
+ methods: {
+ handle_image() {
+ let img = new Image();
+ img.src = this.src;
+
+ img.onload = () => {
+ this.is_loading = false;
+ };
+ img.onerror = () => {
+ this.is_loading = false;
+ this.is_broken = true;
+ };
+ }
+ }
+};
+</script>
diff --git a/erpnext/public/js/hub/components/ItemCard.vue b/erpnext/public/js/hub/components/ItemCard.vue
index f34fddc..675ad86 100644
--- a/erpnext/public/js/hub/components/ItemCard.vue
+++ b/erpnext/public/js/hub/components/ItemCard.vue
@@ -15,7 +15,7 @@
</i>
</div>
<div class="hub-card-body">
- <img class="hub-card-image" v-img-src="item.image"/>
+ <base-image class="hub-card-image" :src="item.image" :alt="title" />
<div class="hub-card-overlay">
<div v-if="is_local" class="hub-card-overlay-body">
<div class="hub-card-overlay-button">
diff --git a/erpnext/public/js/hub/components/ItemListCard.vue b/erpnext/public/js/hub/components/ItemListCard.vue
index 70cb566..7f6fb77 100644
--- a/erpnext/public/js/hub/components/ItemListCard.vue
+++ b/erpnext/public/js/hub/components/ItemListCard.vue
@@ -1,7 +1,7 @@
<template>
<div class="hub-list-item" :data-route="item.route">
<div class="hub-list-left">
- <img class="hub-list-image" v-img-src="item.image">
+ <base-image class="hub-list-image" :src="item.image" />
<div class="hub-list-body ellipsis">
<div class="hub-list-title">{{item.item_name}}</div>
<div class="hub-list-subtitle ellipsis">
diff --git a/erpnext/public/js/hub/vue-plugins.js b/erpnext/public/js/hub/vue-plugins.js
index 439c1f2..6e6a7cb 100644
--- a/erpnext/public/js/hub/vue-plugins.js
+++ b/erpnext/public/js/hub/vue-plugins.js
@@ -7,6 +7,7 @@
import DetailView from './components/DetailView.vue';
import DetailHeaderItem from './components/DetailHeaderItem.vue';
import EmptyState from './components/EmptyState.vue';
+import Image from './components/Image.vue';
Vue.prototype.__ = window.__;
Vue.prototype.frappe = window.frappe;
@@ -17,6 +18,7 @@
Vue.component('detail-view', DetailView);
Vue.component('detail-header-item', DetailHeaderItem);
Vue.component('empty-state', EmptyState);
+Vue.component('base-image', Image);
Vue.directive('route', {
bind(el, binding) {
@@ -51,16 +53,6 @@
img.src = src;
}
-Vue.directive('img-src', {
- bind(el, binding) {
- handleImage(el, binding.value);
- },
- update(el, binding) {
- if (binding.value === binding.oldValue) return;
- handleImage(el, binding.value);
- }
-});
-
Vue.filter('striphtml', function (text) {
return strip_html(text || '');
});
\ No newline at end of file
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index d40926b..089915d 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -1,4 +1,5 @@
-@import "../../../../frappe/frappe/public/less/variables.less";
+@import "variables.less";
+@import (reference) "desk.less";
body[data-route^="marketplace/"] {
.layout-side-section {
@@ -26,6 +27,22 @@
font-size: @text-medium;
}
+ .hub-image {
+ height: 200px;
+ }
+
+ .hub-image-loading, .hub-image-broken {
+ .img-background();
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ span {
+ font-size: 32px;
+ color: @text-extra-muted;
+ }
+ }
+
.progress-bar {
background-color: #89da28;
}
@@ -136,6 +153,7 @@
}
.hub-item-image {
+ position: relative;
border: 1px solid @border-color;
border-radius: 4px;
overflow: hidden;