diff --git a/src/App.svelte b/src/App.svelte index 97326fd..9da8359 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -31,6 +31,7 @@ } } }, + '': '', 'string': 'Hello World', 'url': 'https://jsoneditoronline.org', 'Lorem Ipsum': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' @@ -117,7 +118,7 @@
diff --git a/src/JSONNode.svelte b/src/JSONNode.svelte index 6834562..029ef7e 100644 --- a/src/JSONNode.svelte +++ b/src/JSONNode.svelte @@ -21,6 +21,9 @@ let limit = DEFAULT_LIMIT + let domKey + let domValue + $: type = valueType (value) let prevValue = undefined @@ -49,13 +52,37 @@ : false }) - $: valueClass = classnames('value', type, { - url: valueIsUrl, - empty: escapedValue.length === 0, - search: searchResult - ? !!searchResult[SEARCH_VALUE] - : false - }) + $: valueClass = getValueClass(value) + + $: if (domKey) { + if (document.activeElement !== domKey || escapedKey === '') { + // synchronize the innerText of the editable div with the escaped value, + // but only when the domValue does not have focus else we will ruin + // the cursor position. + domKey.innerText = escapedKey + } + } + + $: if (domValue) { + if (document.activeElement !== domValue || escapedValue === '') { + // synchronize the innerText of the editable div with the escaped value, + // but only when the domValue does not have focus else we will ruin + // the cursor position. + domValue.innerText = escapedValue + } + } + + function getValueClass (value) { + const type = valueType (value) + + return classnames('value', type, { + url: isUrl(value), + empty: escapedValue.length === 0, + search: searchResult + ? !!searchResult[SEARCH_VALUE] + : false + }) + } function toggle () { expanded = !expanded @@ -66,12 +93,22 @@ onChangeKey(newKey, key) } + function handleKeyBlur () { + // make sure differences in escaped text like with new lines is updated + domKey.innerText = escapedValue + } + function handleValueInput (event) { const valueText = unescapeHTML(getInnerText(event.target)) const newValue = stringConvert(valueText) // TODO: implement support for type "string" onChangeValue(newValue, key) } + function handleValueBlur () { + // make sure differences in escaped text like with new lines is updated + domValue.innerText = escapedValue + } + function handleValueClick (event) { if (valueIsUrl && event.ctrlKey) { event.preventDefault() @@ -152,9 +189,9 @@ contenteditable="true" spellcheck="false" on:input={handleKeyInput} - > - {escapedKey} - + on:blur={handleKeyBlur} + bind:this={domKey} + />
:
{/if} {#if expanded} @@ -201,9 +238,9 @@ contenteditable="true" spellcheck="false" on:input={handleKeyInput} - > - {escapedKey} - + on:blur={handleKeyBlur} + bind:this={domKey} + /> : {/if} {#if expanded} @@ -238,9 +275,9 @@ contenteditable="true" spellcheck="false" on:input={handleKeyInput} - > - {escapedKey} - + on:blur={handleKeyBlur} + bind:this={domKey} + /> : {/if}
- {escapedValue} -
+ /> {/if} @@ -386,24 +423,23 @@ } div.empty { - border: 1px dotted lightgray; - border-radius: 2px; - padding: 0 $input-padding; - line-height: 17px; - } + &:not(:focus) { + outline: 1px dotted lightgray; + -moz-outline-radius: 2px; + } + + &::after { + pointer-events: none; + color: lightgray; + } - div.empty::after, - div.empty::after { - pointer-events: none; - color: lightgray; - } + &.key::after { + content: 'key'; + } - div.key.empty::after { - content: 'key'; - } - - div.value.empty::after { - content: 'value'; + &.value::after { + content: 'value'; + } } .key.search,