Skip to content

Commit

Permalink
Highlight the differences of the updated bio text in Feed (vrcx-team#972
Browse files Browse the repository at this point in the history
)

Co-authored-by: EbonCorvin <{ID}+{username}@users.noreply.github.com>
  • Loading branch information
EbonCorvin and EbonCorvin authored Nov 11, 2024
1 parent cd9729e commit 0b3a767
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 4 deletions.
132 changes: 132 additions & 0 deletions html/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5697,6 +5697,138 @@ speechSynthesis.getVoices();
}
});

/**
* Function that prepare the Longest Common Subsequence (LCS) scores matrix
* @param {*} s1 String 1
* @param {*} s2 String 2
* @returns
*/
$app.methods.lcsMatrix = function (s1, s2) {
const m = s1.length;
const n = s2.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

// Fill the matrix for LCS
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (s1[i - 1] === s2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}

return dp;
};

/**
* Function that find the differences between both strings, and return the differences and their position in the strings.
* @param {*} s1 String 1
* @param {*} s2 String 2
* @returns
*/
$app.methods.findDifferences = function (s1, s2) {
const dp = $app.lcsMatrix(s1, s2);
const differencesS1 = [];
const differencesS2 = [];
let i = s1.length;
let j = s2.length;

// Backtrack to find differences
while (i > 0 && j > 0) {
if (s1[i - 1] === s2[j - 1]) {
i--;
j--;
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
differencesS1.push({ index: i - 1, char: s1[i - 1] }); // Deletion in s1
i--;
} else {
differencesS2.push({ index: j - 1, char: s2[j - 1] }); // Insertion in s2
j--;
}
}

// Remaining characters in s1 (deletions)
while (i > 0) {
differencesS1.push({ index: i - 1, char: s1[i - 1] });
i--;
}

// Remaining characters in s2 (insertions)
while (j > 0) {
differencesS2.push({ index: j - 1, char: s2[j - 1] });
j--;
}

return {
differencesS1: differencesS1.reverse(), // Reverse to maintain original order
differencesS2: differencesS2.reverse()
};
};

$app.methods.findSequeces = function (arr) {
if (arr.length === 0) return [];
return arr.reduce(
(p, c, i) => {
if (i === 0) return p;
let lastSeq = p.pop();
p.push(lastSeq);
if (c - lastSeq[1] !== 1) {
p.push([c, c]);
} else {
lastSeq[1] = c;
}
return p;
},
[[arr[0], arr[0]]]
);
};

/**
* Function that format the differences between two strings with HTML tags
* markerStartTag and markerEndTag are optional, if emitted, the differences will be highlighted with yellow and underlined.
* @param {*} s1
* @param {*} s2
* @param {*} markerStartTag
* @param {*} markerEndTag
* @returns An array that contains both the string 1 and string 2, which the differences are formated with HTML tags
*/
$app.methods.formatDifference = function (
s1,
s2,
markerStartTag = '<u><font color="yellow">',
markerEndTag = '</font></u>'
) {
const texts = [s1, s2];
const differs = $app.findDifferences(s1, s2);
return Object.values(differs)
.map((i) => $app.findSequeces(i.map((j) => j.index)))
.map((i, k) => {
let stringBuilder = [];
let lastPos = 0;
let key = Date.now();
i.forEach((j) => {
stringBuilder.push(texts[k].substring(lastPos, j[0]));
stringBuilder.push(
`{{diffTag-${key}}}${texts[k].substring(j[0], j[1] + 1)}{{diffTagClose-${key}}}`
);
lastPos = j[1] + 1;
});
stringBuilder.push(texts[k].substr(lastPos, texts[k].length));
let returnVal = stringBuilder
.join('')
.replaceAll(/&/g, '&amp;')
.replaceAll(/</g, '&lt;')
.replaceAll(/>/g, '&gt;')
.replaceAll(/"/g, '&quot;')
.replaceAll(/'/g, '&#039;')
.replaceAll(`{{diffTag-${key}}}`, markerStartTag)
.replaceAll(`{{diffTagClose-${key}}}`, markerEndTag);
return returnVal;
});
};

// #endregion
// #region | App: gameLog

Expand Down
8 changes: 4 additions & 4 deletions html/src/mixins/tabs/feed.pug
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ mixin feedTab()
i.x-user-status(:class="statusClass(scope.row.status)")
span(v-text="scope.row.statusDescription")
template(v-else-if="scope.row.type === 'Bio'")
pre(v-text="scope.row.previousBio" style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0")
span
i.el-icon-right
pre(v-text="scope.row.bio" style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0")
template(v-for="(bio,idx) in formatDifference(scope.row.previousBio,scope.row.bio)")
pre(v-html="bio" style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0")
span(v-if="idx===0")
i.el-icon-right
el-table-column(:label="$t('table.feed.date')" prop="created_at" sortable="custom" width="120")
template(v-once #default="scope")
el-tooltip(placement="right")
Expand Down

0 comments on commit 0b3a767

Please sign in to comment.