Add mergeTextWithHistory function
This commit is contained in:
parent
c0333c1146
commit
779579d38f
18 changed files with 285 additions and 100 deletions
|
|
@ -29,26 +29,53 @@
|
|||
</header>
|
||||
|
||||
<main>
|
||||
<div class="text-area diamond-parent">
|
||||
<div class="text-area-card diamond-parent">
|
||||
<label for="original">Original</label>
|
||||
<textarea id="original" name="original"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-area diamond-left">
|
||||
<label for="left">First concurrent edit</label>
|
||||
<div class="text-area-card diamond-left">
|
||||
<label for="left">
|
||||
First concurrent edit
|
||||
<div class="box Left"></div>
|
||||
</label>
|
||||
<textarea id="left" name="left"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-area diamond-right">
|
||||
<label for="right">Second concurrent edit</label>
|
||||
<div class="text-area-card diamond-right">
|
||||
<label for="right"
|
||||
>Second concurrent edit
|
||||
<div
|
||||
class="box Right"
|
||||
title="Indicates changes from the second concurrent edit"
|
||||
></div>
|
||||
</label>
|
||||
<textarea id="right" name="right"></textarea>
|
||||
</div>
|
||||
|
||||
<button id="merge-button" type="button">Merge</button>
|
||||
|
||||
<div class="text-area diamond-result">
|
||||
<label for="merged">Deconflicted result (readonly)</label>
|
||||
<textarea id="merged" name="merged" readonly></textarea>
|
||||
<div class="text-area-card diamond-result">
|
||||
<label
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10 10l-6 6v4h4l6 -6m1.99 -1.99l2.504 -2.504a2.828 2.828 0 1 0 -4 -4l-2.5 2.5"
|
||||
/>
|
||||
<path d="M13.5 6.5l4 4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Deconflicted result (readonly)</label
|
||||
>
|
||||
<div id="merged"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
|
@ -64,9 +91,15 @@
|
|||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||
d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import init, { mergeText } from "./reconcile.js";
|
||||
import init, { mergeText, mergeTextWithHistory } from "./reconcile.js";
|
||||
|
||||
const originalTextArea = document.getElementById("original");
|
||||
const leftTextArea = document.getElementById("left");
|
||||
const rightTextArea = document.getElementById("right");
|
||||
const mergedTextArea = document.getElementById("merged");
|
||||
const mergeButton = document.getElementById("merge-button");
|
||||
|
||||
const sampleTexts = [
|
||||
"The quick brown fox jumps over the lazy dog.",
|
||||
|
|
@ -17,16 +16,35 @@ const sampleTexts = [
|
|||
async function run() {
|
||||
await init();
|
||||
|
||||
mergeButton.addEventListener("click", () => {
|
||||
const original = originalTextArea.value;
|
||||
const left = leftTextArea.value;
|
||||
const right = rightTextArea.value;
|
||||
|
||||
const result = mergeText(original, left, right);
|
||||
mergedTextArea.value = result;
|
||||
});
|
||||
originalTextArea.addEventListener("input", updateMergedText);
|
||||
leftTextArea.addEventListener("input", updateMergedText);
|
||||
rightTextArea.addEventListener("input", updateMergedText);
|
||||
|
||||
loadSample();
|
||||
updateMergedText();
|
||||
|
||||
// Put cursor at the end of the text in leftTextArea
|
||||
leftTextArea.focus();
|
||||
leftTextArea.selectionStart = leftTextArea.value.length;
|
||||
leftTextArea.selectionEnd = leftTextArea.value.length;
|
||||
}
|
||||
|
||||
function updateMergedText() {
|
||||
const original = originalTextArea.value;
|
||||
const left = leftTextArea.value;
|
||||
const right = rightTextArea.value;
|
||||
|
||||
const results = mergeTextWithHistory(original, left, right);
|
||||
|
||||
mergedTextArea.innerHTML = "";
|
||||
|
||||
for (const result of results) {
|
||||
const span = document.createElement("span");
|
||||
span.className = result.history();
|
||||
span.textContent = result.text();
|
||||
mergedTextArea.appendChild(span);
|
||||
result.free();
|
||||
}
|
||||
}
|
||||
|
||||
function loadSample() {
|
||||
|
|
@ -35,7 +53,6 @@ function loadSample() {
|
|||
originalTextArea.value = text;
|
||||
leftTextArea.value = text;
|
||||
rightTextArea.value = text;
|
||||
mergedTextArea.value = "";
|
||||
}
|
||||
|
||||
run();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html,
|
||||
|
|
@ -40,7 +41,7 @@ main {
|
|||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
|
@ -58,34 +59,8 @@ main {
|
|||
}
|
||||
|
||||
.diamond-right {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
#merge-button {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
padding: 12px 36px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(90deg, #2451a6 0%, #3486eb 100%);
|
||||
color: #fff;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 2px 12px 0 rgba(36, 81, 166, 0.08);
|
||||
cursor: pointer;
|
||||
align-self: center;
|
||||
transition: transform 0.2s;
|
||||
margin: 0 32px;
|
||||
}
|
||||
|
||||
#merge-button:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.diamond-right {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.diamond-result {
|
||||
|
|
@ -93,10 +68,9 @@ main {
|
|||
grid-row: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
.text-area-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
|
@ -115,6 +89,15 @@ label {
|
|||
color: #2451a6;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 1ch;
|
||||
height: 1ch;
|
||||
border-radius: 50%;
|
||||
margin-left: 6px;
|
||||
display: inline-block;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
|
@ -128,6 +111,29 @@ textarea {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#merged {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.Left,
|
||||
.AddedFromLeft,
|
||||
.RemovedFromLeft {
|
||||
background: #12d197;
|
||||
}
|
||||
|
||||
.Right,
|
||||
.AddedFromRight,
|
||||
.RemovedFromRight {
|
||||
background: #8575ed;
|
||||
}
|
||||
|
||||
.RemovedFromLeft,
|
||||
.RemovedFromRight {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
main {
|
||||
padding: 24px 2vw;
|
||||
|
|
@ -139,29 +145,25 @@ textarea {
|
|||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto auto auto auto auto;
|
||||
}
|
||||
|
||||
main > * {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.diamond-parent {
|
||||
grid-row: 1;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.diamond-left {
|
||||
grid-row: 2;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.diamond-right {
|
||||
grid-row: 3;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
#merge-button {
|
||||
grid-row: 4;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.diamond-result {
|
||||
grid-row: 5;
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -178,6 +180,7 @@ footer {
|
|||
|
||||
.github-link > svg {
|
||||
position: absolute;
|
||||
color: #5a6272;
|
||||
top: 50%;
|
||||
right: 36px;
|
||||
transform: translateY(-50%);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue