pict-section-dochistory
v1.0.0
Published
Version history for a document tree in Pict: a timeline of versions that says who changed what and from which side, and a rendered line diff between any two of them. Host-agnostic - it reads through two callbacks and ships no transport.
Readme
pict-section-dochistory
Version history for a document tree, as two Pict views:
- a timeline of versions that says who changed a document, from which side, and when;
- a line diff between any two of those versions.
It ships no transport. Both views read through host callbacks, so the section carries no assumption about where the history lives or what the backing store is called.
Install
npm install pict-section-dochistoryUse
The two views register independently, so a host places them wherever it likes (a timeline in
a sidebar, a diff in a main pane) instead of accepting one fixed layout. Wire the timeline's
onSelectVersion to the diff view's showDiff and they work as a pair.
const libDocHistory = require('pict-section-dochistory');
pict.addView('Doc-Timeline', Object.assign({}, libDocHistory.TimelineView.default_configuration,
{
Path: 'architecture/data-model.md',
onLoadHistory: (pPath, pLimit, fCallback) => myAPI.history(pPath, pLimit, fCallback),
onSelectVersion: (pEvent, pPrevious) =>
pict.views['Doc-Diff'].showDiff(pPrevious ? pPrevious.Commit : '', pEvent.Commit, 'architecture/data-model.md')
}), libDocHistory.TimelineView);
pict.addView('Doc-Diff', Object.assign({}, libDocHistory.DiffView.default_configuration,
{ onLoadDiff: (pFrom, pTo, pPath, fCallback) => myAPI.diff(pFrom, pTo, pPath, fCallback) }),
libDocHistory.DiffView);
pict.views['Doc-Timeline'].loadHistory();Give the page the two containers the default configurations render into
(#DocHistory-Timeline-Container and #DocHistory-Diff-Container), or override
DefaultDestinationAddress on either view.
The event shape
Both views understand one event object:
{ Commit, Parent, Date, Source, AuthorName, AuthorEmail, IDUser,
UpstreamCommitSHA, IDDocSyncBinding, Message, FilesChanged, PathChange }Only Commit and Date are really needed; everything else degrades to a sensible blank.
Unknown extra fields are carried through untouched, so a host can hang its own data off an
event and read it back in a callback.
Source is an open string. These values get a friendly label and their own style hook:
| Source | Shown as |
|---|---|
| platform | Edited here |
| github | Pulled from the repository |
| merge | Merged from both sides |
| agent | Written by a tool |
| import | Imported |
Anything else is shown exactly as given, so a host with its own vocabulary still renders.
Timeline view
libDocHistory.TimelineView
| Option | Default | What it does |
|---|---|---|
| Path | '' | The document to show history for. Empty means the whole tree. |
| Title | 'Version history' | Heading above the list. Empty hides the header row. |
| PageSize | 40 | How many versions to ask the host for. |
| ShowCommitHash | false | Show each version's short content address. |
| ShowUpstreamRef | false | Show the originating upstream commit for a pulled change. |
| EmptyMessage | see source | Shown when the document has no versions. |
| LoadingMessage | see source | Shown while the host is loading. |
Callbacks:
onLoadHistory(pPath, pLimit, fCallback)required - call back with(error, { Events: [...], More: bool }).onSelectVersion(pEvent, pPreviousEvent, pPath)- a version was clicked.pPreviousEventis the next-older version in the list, so(previous -> event)is the change that version introduced. It isnullfor the oldest loaded version, falling back to a stub carrying the event's ownParentwhen there is one.onError(pError)- the host surfaces a failed load its own way. Without it the view shows its own error row.
Methods: loadHistory(), setPath(pPath), events(), selectedEvent().
Diff view
libDocHistory.DiffView
| Option | Default | What it does |
|---|---|---|
| ContextLines | 3 | Unchanged lines kept either side of a change. 0 shows the whole document. |
| ShowLineNumbers | true | Show original and new line numbers. |
| EmptyMessage / IdenticalMessage / BinaryMessage / LoadingMessage | see source | The states that are not a diff. |
Callbacks:
onLoadDiff(pFrom, pTo, pPath, fCallback)required - call back with(error, { FromContent, ToContent, Binary, FromExists, ToExists }).FromContentisnullwhen the document did not exist at that version;Binary: truemeans there is no line diff to render (an image, a PDF) and the view says so.
Methods: showDiff(pFrom, pTo, pPath), clear(), diffRows().
pFrom may be empty: the first version of a document is all additions.
Model
libDocHistory.Model is the pure, DOM-free half, exported for hosts and tests:
diffLines(pFrom, pTo, pOptions)- LCS line diff returning{ Kind: 'same' | 'add' | 'del', Text, FromLine, ToLine }rows. Normalizes CRLF, treats a trailing newline as a terminator, and falls back to a whole-file replace pastpOptions.MaxCellsso a huge pair cannot hang a render.collapseUnchanged(pDiff, pContext)- collapse long unchanged runs into{ Kind: 'gap', Skipped }markers.diffStats(pDiff),splitLines,sourceLabel,sourceKind,relativeDate,shortCommit,escapeHTML.
Notes
- Document text is escaped before it reaches a template. A diff renders an author's prose, which may legitimately contain markup.
- Added and removed lines carry a marker character as well as a tint, so a diff stays readable without colour vision.
- All colors are theme tokens, so an active
pict-section-themerecolors both views.
Testing
npm testLicense
MIT
