Some fixes in styling empty key/value

This commit is contained in:
josdejong 2020-05-05 21:25:54 +02:00
parent 3517d185f9
commit 2b73c6e6bf
2 changed files with 89 additions and 11 deletions

View File

@ -7,6 +7,7 @@
import { escapeHTML } from './utils/stringUtils.js' import { escapeHTML } from './utils/stringUtils.js'
import { updateProps } from './utils/updateProps.js' import { updateProps } from './utils/updateProps.js'
import { unescapeHTML } from './utils/stringUtils' import { unescapeHTML } from './utils/stringUtils'
import { getInnerText } from './utils/domUtils'
export let key = undefined export let key = undefined
export let value export let value
@ -41,6 +42,13 @@
$: escapedValue = escapeHTML(value, escapeUnicode) $: escapedValue = escapeHTML(value, escapeUnicode)
$: valueIsUrl = isUrl(value) $: valueIsUrl = isUrl(value)
$: keyClass = classnames('key', {
empty: escapedKey.length === 0,
search: searchResult
? !!searchResult[SEARCH_PROPERTY]
: false
})
$: valueClass = classnames('value', type, { $: valueClass = classnames('value', type, {
url: valueIsUrl, url: valueIsUrl,
empty: escapedValue.length === 0, empty: escapedValue.length === 0,
@ -54,12 +62,12 @@
} }
function handleKeyInput (event) { function handleKeyInput (event) {
const newKey = unescapeHTML(event.target.innerText) const newKey = unescapeHTML(getInnerText(event.target))
onChangeKey(newKey, key) onChangeKey(newKey, key)
} }
function handleValueInput (event) { function handleValueInput (event) {
const valueText = unescapeHTML(event.target.innerText) const valueText = unescapeHTML(getInnerText(event.target))
const newValue = stringConvert(valueText) // TODO: implement support for type "string" const newValue = stringConvert(valueText) // TODO: implement support for type "string"
onChangeValue(newValue, key) onChangeValue(newValue, key)
} }
@ -140,7 +148,7 @@
</button> </button>
{#if typeof key === 'string'} {#if typeof key === 'string'}
<div <div
class="key {searchResult && searchResult[SEARCH_PROPERTY] ? 'search' : ''}" class={keyClass}
contenteditable="true" contenteditable="true"
spellcheck="false" spellcheck="false"
on:input={handleKeyInput} on:input={handleKeyInput}
@ -189,7 +197,7 @@
</button> </button>
{#if typeof key === 'string'} {#if typeof key === 'string'}
<div <div
class="key {searchResult && searchResult[SEARCH_PROPERTY] ? 'search' : ''}" class={keyClass}
contenteditable="true" contenteditable="true"
spellcheck="false" spellcheck="false"
on:input={handleKeyInput} on:input={handleKeyInput}
@ -226,7 +234,7 @@
<div class="contents"> <div class="contents">
{#if typeof key === 'string'} {#if typeof key === 'string'}
<div <div
class="key {searchResult && searchResult[SEARCH_PROPERTY] ? 'search' : ''}" class={keyClass}
contenteditable="true" contenteditable="true"
spellcheck="false" spellcheck="false"
on:input={handleKeyInput} on:input={handleKeyInput}
@ -268,6 +276,10 @@
flex-direction: row; flex-direction: row;
line-height: $line-height; line-height: $line-height;
> * {
display: table-cell;
}
} }
.contents { .contents {
@ -296,8 +308,6 @@
.key, .key,
.value { .value {
display: table-cell;
line-height: $line-height; line-height: $line-height;
min-width: 16px; min-width: 16px;
word-break: normal; word-break: normal;
@ -314,13 +324,11 @@
.separator, .separator,
.delimiter { .delimiter {
display: table-cell;
vertical-align: top; vertical-align: top;
color: $gray; color: $gray;
} }
.tag { .tag {
display: table-cell;
vertical-align: top; vertical-align: top;
border: none; border: none;
font-size: $font-size-small; font-size: $font-size-small;
@ -388,10 +396,9 @@
div.empty::after { div.empty::after {
pointer-events: none; pointer-events: none;
color: lightgray; color: lightgray;
font-size: 8pt;
} }
div.property.empty::after { div.key.empty::after {
content: 'key'; content: 'key';
} }

71
src/utils/domUtils.js Normal file
View File

@ -0,0 +1,71 @@
/**
* Get the inner text of an HTML element (for example a div element)
* @param {Element} element
* @param {Object} [buffer]
* @return {String} innerText
*/
export function getInnerText (element, buffer) {
const first = (buffer === undefined)
if (first) {
buffer = {
'text': '',
'flush': function () {
const text = this.text
this.text = ''
return text
},
'set': function (text) {
this.text = text
}
}
}
// text node
if (element.nodeValue) {
return buffer.flush() + element.nodeValue
}
// divs or other HTML elements
if (element.hasChildNodes()) {
const childNodes = element.childNodes
let innerText = ''
for (let i = 0, iMax = childNodes.length; i < iMax; i++) {
const child = childNodes[i]
if (child.nodeName === 'DIV' || child.nodeName === 'P') {
const prevChild = childNodes[i - 1]
const prevName = prevChild ? prevChild.nodeName : undefined
if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') {
innerText += '\n'
buffer.flush()
}
innerText += getInnerText(child, buffer)
buffer.set('\n')
}
else if (child.nodeName === 'BR') {
innerText += buffer.flush()
buffer.set('\n')
}
else {
innerText += getInnerText(child, buffer)
}
}
return innerText
}
else {
if (element.nodeName === 'P' && getInternetExplorerVersion() !== -1) {
// On Internet Explorer, a <p> with hasChildNodes()==false is
// rendered with a new line. Note that a <p> with
// hasChildNodes()==true is rendered without a new line
// Other browsers always ensure there is a <br> inside the <p>,
// and if not, the <p> does not render a new line
return buffer.flush()
}
}
// br or unknown
return ''
}