@@ -128,7 +128,7 @@ frappe.Application = Class.extend({ | |||
} | |||
// REDESIGN-TODO: Fix preview popovers | |||
//this.link_preview = new frappe.ui.LinkPreview(); | |||
this.link_preview = new frappe.ui.LinkPreview(); | |||
if (!frappe.boot.developer_mode) { | |||
setInterval(function() { | |||
@@ -22,7 +22,6 @@ frappe.ui.LinkPreview = class { | |||
} | |||
}); | |||
this.handle_popover_hide(); | |||
} | |||
identify_doc() { | |||
@@ -122,7 +121,7 @@ frappe.ui.LinkPreview = class { | |||
} | |||
}); | |||
$(window).on('hashchange', () => { | |||
frappe.router.on('change', () => { | |||
this.clear_all_popovers(); | |||
}); | |||
} | |||
@@ -142,18 +141,22 @@ frappe.ui.LinkPreview = class { | |||
let popover_content = this.get_popover_html(preview_data); | |||
this.element.popover({ | |||
container: 'body', | |||
template: ` | |||
<div class="link-preview-popover popover"> | |||
<div class="arrow"></div> | |||
<div class="popover-body popover-content"> | |||
</div> | |||
</div> | |||
`, | |||
html: true, | |||
sanitizeFn: (content) => content, | |||
content: popover_content, | |||
trigger: 'manual', | |||
placement: 'top auto', | |||
animation: false, | |||
placement: 'top', | |||
}); | |||
const $popover = this.element.data('bs.popover').tip(); | |||
$popover.addClass('link-preview-popover'); | |||
const $popover = $(this.element.data('bs.popover').tip); | |||
$popover.toggleClass('control-field-popover', this.is_link); | |||
this.popovers_list.push(this.element.data('bs.popover')); | |||
} | |||
@@ -167,53 +170,63 @@ frappe.ui.LinkPreview = class { | |||
this.href = this.href.replace(new RegExp(' ', 'g'), '%20'); | |||
} | |||
let image_html = ''; | |||
let id_html = ''; | |||
let content_html = ''; | |||
if (preview_data.preview_image) { | |||
let image_url = encodeURI(preview_data.preview_image); | |||
image_html = ` | |||
let popover_content =` | |||
<div class="preview-popover-header"> | |||
<div class="preview-header"> | |||
<img src="${image_url}" onerror="this.src='/assets/frappe/images/fallback-thumbnail.jpg'" class="preview-image"></img> | |||
${this.get_image_html(preview_data)} | |||
<div class="preview-name"> | |||
<a href=${this.href}>${__(preview_data.preview_title)}</a> | |||
</div> | |||
<div class="text-muted preview-title">${this.get_id_html(preview_data)}</div> | |||
</div> | |||
`; | |||
} | |||
</div> | |||
<hr> | |||
<div class="popover-body"> | |||
${this.get_content_html(preview_data)} | |||
</div> | |||
`; | |||
return popover_content; | |||
} | |||
if (preview_data.preview_title != preview_data.name) { | |||
get_id_html(preview_data) { | |||
let id_html = ''; | |||
if (preview_data.preview_title !== preview_data.name) { | |||
id_html = `<a class="text-muted" href=${this.href}>${preview_data.name}</a>`; | |||
} | |||
return id_html; | |||
} | |||
get_image_html(preview_data) { | |||
let avatar_html = frappe.get_avatar( | |||
"avatar-medium", | |||
preview_data.preview_title, | |||
preview_data.preview_image | |||
); | |||
return `<div class="preview-image"> | |||
${avatar_html} | |||
</div>`; | |||
} | |||
get_content_html(preview_data) { | |||
let content_html = ''; | |||
Object.keys(preview_data).forEach(key => { | |||
if (!['preview_image', 'preview_title', 'name'].includes(key)) { | |||
let value = frappe.ellipsis(preview_data[key], 280); | |||
let label = key; | |||
content_html += ` | |||
<div class="preview-field"> | |||
<div class='small preview-label text-muted bold'>${__(label)}</div> | |||
<div class="small preview-value">${value}</div> | |||
<div class="preview-label text-muted">${__(label)}</div> | |||
<div class="preview-value">${value}</div> | |||
</div> | |||
`; | |||
} | |||
}); | |||
content_html = `<div class="preview-table">${content_html}</div>`; | |||
let popover_content =` | |||
<div class="preview-popover-header">${image_html} | |||
<div class="preview-header"> | |||
<div class="preview-main"> | |||
<a class="preview-name bold" href=${this.href}>${__(preview_data.preview_title)}</a> | |||
<span class="text-muted small">${__(this.doctype)} ${id_html}</span> | |||
</div> | |||
</div> | |||
</div> | |||
<hr> | |||
<div class="popover-body"> | |||
${content_html} | |||
</div> | |||
`; | |||
return popover_content; | |||
return `<div class="preview-table">${content_html}</div>`; | |||
} | |||
}; |
@@ -20,27 +20,25 @@ frappe.avatar = function (user, css_class, title, image_url=null, remove_color=f | |||
title = user_info.fullname; | |||
} | |||
let data_attr = ''; | |||
if (filterable) { | |||
css_class += " filterable"; | |||
data_attr = `data-filter="_assign,like,%${user}%"`; | |||
} | |||
return frappe.get_avatar( | |||
user, css_class, title, image_url || user_info.image, remove_color, filterable | |||
css_class, title, image_url || user_info.image, remove_color, data_attr | |||
); | |||
}; | |||
frappe.get_avatar = function(user, css_class, title, image_url=null, remove_color, filterable) { | |||
let data_attr = ''; | |||
frappe.get_avatar = function(css_class, title, image_url=null, remove_color, data_attributes) { | |||
if (!css_class) { | |||
css_class = "avatar-small"; | |||
} | |||
if (filterable) { | |||
css_class += " filterable"; | |||
data_attr = `data-filter="_assign,like,%${user}%"`; | |||
} | |||
if (image_url) { | |||
const image = (window.cordova && image_url.indexOf('http') === -1) ? frappe.base_url + image_url : image_url; | |||
return `<span class="avatar ${css_class}" title="${title}" ${data_attr}> | |||
return `<span class="avatar ${css_class}" title="${title}" ${data_attributes}> | |||
<span class="avatar-frame" style='background-image: url("${image}")' | |||
title="${title}"></span> | |||
</span>`; | |||
@@ -55,7 +53,8 @@ frappe.get_avatar = function(user, css_class, title, image_url=null, remove_colo | |||
if (css_class === 'avatar-small' || css_class == 'avatar-xs') { | |||
abbr = abbr.substr(0, 1); | |||
} | |||
return `<span class="avatar ${css_class}" title="${title}" ${data_attr}> | |||
return `<span class="avatar ${css_class}" title="${title}" ${data_attributes}> | |||
<div class="avatar-frame standard-image" | |||
style="${style}"> | |||
${abbr} | |||
@@ -252,6 +252,7 @@ select.input-xs { | |||
/* popover */ | |||
.popover { | |||
background-color: var(--popover-bg); | |||
border: 0; | |||
} | |||
.bold { | |||
@@ -1,48 +1,61 @@ | |||
.link-preview-popover { | |||
border-radius: 0; | |||
max-width: 100%; | |||
.popover-content { | |||
padding: 0; | |||
.preview-popover-header { | |||
padding: var(--padding-md); | |||
padding: var(--padding-md) 25px; | |||
.preview-header { | |||
display: inline-block; | |||
vertical-align: top; | |||
} | |||
.preview-header { | |||
@include flex(flex, null, center, column); | |||
} | |||
.preview-image { | |||
width: 70px; | |||
height: 70px; | |||
object-fit: cover; | |||
margin-right: var(--margin-sm); | |||
border-radius: var(--border-radius); | |||
} | |||
.preview-image { | |||
margin-bottom: var(--margin-sm); | |||
.preview-name { | |||
display: block; | |||
} | |||
.avatar { | |||
width: 52px; | |||
height: 52px; | |||
.preview-title { | |||
display: block; | |||
.standard-image { | |||
font-size: var(--text-lg); | |||
} | |||
} | |||
} | |||
hr { | |||
margin: 0; | |||
.preview-name { | |||
font-size: var(--text-base); | |||
font-weight: 500; | |||
} | |||
.preview-table { | |||
padding: var(--padding-md); | |||
padding-bottom: var(--padding-xs); | |||
max-width: 330px; | |||
min-width: 200px; | |||
overflow-wrap: break-word; | |||
.preview-field { | |||
padding-bottom: var(--padding-sm); | |||
.preview-label { | |||
padding-bottom: 4px; | |||
.preview-title:not(:empty) { | |||
margin-top: var(--margin-xs); | |||
font-size: var(--text-md); | |||
} | |||
.popover-body { | |||
padding: 0; | |||
.preview-table { | |||
padding-bottom: var(--padding-xs); | |||
max-width: 330px; | |||
min-width: 200px; | |||
overflow-wrap: break-word; | |||
.preview-field { | |||
.preview-label { | |||
padding-bottom: 4px; | |||
} | |||
.preview-value { | |||
font-weight: 500; | |||
} | |||
.ql-snow .ql-editor { | |||
min-height: 0; | |||
} | |||
&:not(:last-child) { | |||
margin-bottom: var(--margin-md); | |||
} | |||
} | |||
} | |||
} | |||
@@ -98,7 +98,7 @@ $mark-padding: 0; | |||
$enable-shadows: true; | |||
$popover-border-radius: var(--border-radius); | |||
$popover-bg: var(--popover-bg); | |||
$popover-box-shadow: var(--shadow-md); | |||
$popover-box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1); | |||
$popover-body-padding-x: var(--padding-md); | |||
$popover-body-padding-y: var(--padding-md); | |||
$popover-border-color: var(--dark-border-color); | |||