8000 Bug fix for issue: `"YYYY" Format` by seanlowe · Pull Request #84 · seanlowe/obsidian-timelines · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Bug fix for issue: "YYYY" Format #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ I've written a brand new GitHub Pages docs site for **Timelines (Revamped)** at

## Release Notes

### v2.2.6
### v2.2.7

Bug Fix for: `Custom attributes on timeline nodes` [#63](https://github.com/seanlowe/obsidian-timelines/issues/63)
Bug fix for issue: `"YYYY" Format` [#81](https://github.com/seanlowe/obsidian-timelines/issues/81)

**Changes:**
- added the correct changes to the `insert event` commands so that events inserted that way have all the applicable attributes.
- added a new page in the docs for understanding how to add custom classes to your timeline events.
- implemented some logic to determine what sections of the provided dates are missing originally and to not display a cleaned version of the normalized date but a "readable" date that should closer match what the user provides in the event.
- tweaked some logic in the nesting / sorting functionality on the vertical timeline. Events now sort the start and end of time ranges correctly (so far as I can tell).

See the [changelog](./changelog.md) for more details on previous releases.

Expand Down
207 changes: 207 additions & 0 deletions archive/pre-vertical-refactor.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { AllNotesData, CardContainer, DivWithCalcFunc } from '../types'
import { buildTimelineDate, createInternalLinkOnNoteCard, handleColor } from '../utils'

export async function buildVerticalTimeline(
timeline: HTMLElement,
timelineNotes: AllNotesData,
timelineDates: string[],
el: HTMLElement
) {
let eventCount = 0
// Build the timeline html element
for ( const date of timelineDates ) {
const align = eventCount % 2 === 0 ? 'left' : 'right'
const datedTo = [ timelineNotes[date][0].startDate.replace( /-0*$/g, '' )
+ ( timelineNotes[date][0].era ? ` ${timelineNotes[date][0].era}` : '' )
]

const noteDivs = [
timeline.createDiv(
{ cls: ['timeline-container', `timeline-${align}`] },
( div ) => {
div.style.setProperty( '--timeline-indent', '0' )
div.setAttribute( 'timeline-date', timelineNotes[date][0].startDate )
div.setAttribute( 'collapsed', 'false' )
}
)
]

const eventsDiv = noteDivs[0].createDiv({
cls: 'timeline-event-list',
attr: { 'style': 'display: block' }
})

const noteHdrs = [noteDivs[0].createEl( 'h2', {
attr: { 'style' : `text-align: ${align};` },
text: datedTo[0]
})]

for ( const rawNote of timelineNotes[date] ) {
// for confirmation of types
const note: CardContainer = rawNote
const { endDate: endDateString, era } = note
const startDate = buildTimelineDate( note.startDate )
const endDate = buildTimelineDate( endDateString )

// skip events that are of type 'box' or 'point', or if the endDate is invalid
if ( ['box', 'point'].includes( note.type ) || endDate < startDate ) {
continue
}

if ( !noteDivs[0].classList.contains( 'timeline-head' )) {
noteDivs[0].classList.add( 'timeline-head' )
}

const dated = endDateString + ( era ?? '' )
const lastTimelineDate = buildTimelineDate( noteDivs.last().getAttribute( 'timeline-date' ))
if ( !datedTo[1] || endDate > lastTimelineDate ) {
datedTo[1] = datedTo[0] + ' to ' + dated
}

const noteDiv = timeline.createDiv(
{ cls: ['timeline-container', `timeline-${align}`, 'timeline-tail'] },
( div ) => {
div.style.setProperty( '--timeline-indent', '0' )
div.setAttribute( 'timeline-date', endDateString )
}
)

const noteHdr = noteDiv.createEl( 'h2', {
attr: { 'style' : `text-align: ${align};` },
text: dated
})

noteHdrs.push( noteHdr )
noteDivs.push( noteDiv )
for ( const n of noteDivs ) {
const timelineDate = buildTimelineDate( n.getAttribute( 'timeline-date' ))

if ( timelineDate > endDate ) {
n.before( noteDiv )
}
}

/* The CSS 'timeline-timespan-length' determines both the length of the event timeline widget on the timeline,
and the length of the vertical segment that spans between the displayed dates. If this value is not recalculated
then these elements will not be responsive to layout changes. */
( noteDivs.last() as DivWithCalcFunc ).calcLength = () => {
const axisMin = noteDivs[0].getBoundingClientRect().top
const axisMax = noteDiv .getBoundingClientRect().top
const spanMin = noteHdrs[0].getBoundingClientRect().top
const spanMax = noteHdr .getBoundingClientRect().top

noteDivs[0].style.setProperty( '--timeline-span-length', `${axisMax - axisMin}px` )
noteDiv .style.setProperty( '--timeline-span-length', `${spanMax - spanMin}px` )
}
}

noteDivs[0].addEventListener( 'click', ( event ) => {
event.preventDefault()

const collapsed = !JSON.parse( noteDivs[0].getAttribute( 'collapsed' ))
noteDivs[0].setAttribute( 'collapsed', String( collapsed ))
for ( const p of noteDivs[0].getElementsByTagName( 'p' )) {
p.setCssProps({ 'display': collapsed ? 'none' : 'block' })
}
/* If this event has a duration (and thus has an end note), we hide all elements between the start and end
note along with the end note itself */
if ( noteDivs.length > 0 ) {
noteHdrs[0].setText( collapsed && datedTo[1] ? datedTo[1] : datedTo[0] )
const notes = [...timeline.children]
const inner = notes.slice( notes.indexOf( noteDivs.first()) + 1, notes.indexOf( noteDivs.last()) + 1 )
inner.forEach(( note: DivWithCalcFunc ) => {
note.style.display = collapsed ? 'none' : 'block'
note.calcLength?.()
})
}

/* The CSS '--timeline-indent' variable allows for scaling down the event when contained within another event,
but in this case it also tells us how many time spanning events have had their length altered as a consequence
of this note's mutation. */
let nested = +noteDivs[0].style.getPropertyValue( '--timeline-indent' ) + noteDivs.length - 1
for ( let f = 'nextElementSibling', sibling = noteDivs[0][f]; nested > 0; sibling = sibling[f] ) {
if ( sibling.classList.contains( 'timeline-tail' )) {
sibling.calcLength?.()
nested--
}
}
})


/*noteContainer[0].addEventListener( 'click', ( event ) => {
event.preventDefault()
const currentStyle = eventContainer.style
if ( currentStyle.getPropertyValue( 'display' ) === 'none' ) {
currentStyle.setProperty( 'display', 'block' )
return
}

// note from https://github.com/Darakah/obsidian-timelines/pull/58
// TODO: Stop Propagation: don't close timeline-card when clicked.
// `vis-timeline-graph2d.js` contains a method called `_updateContents` that makes the display
// attribute disappear on click via line 7426: `element.innerHTML = '';`
currentStyle.setProperty( 'display', 'none' )
})*/

if ( !timelineNotes[date] ) {
continue
}

for ( const eventAtDate of timelineNotes[date] ) {
const noteCard = eventsDiv.createDiv({ cls: 'timeline-card' })
noteCard.className += ` ${eventAtDate.classes}`
// add an image only if available
if ( eventAtDate.img ) {
noteCard.createDiv({
cls: 'thumb',
attr: { style: `background-image: url(${eventAtDate.img});` }
})
}

if ( eventAtDate.color ) {
// todo : add more support for other custom classes
handleColor( eventAtDate.color, noteCard, eventAtDate.id )
}

createInternalLinkOnNoteCard( eventAtDate, noteCard )
eventAtDate.body && noteCard.createEl( 'p', { text: eventAtDate.body.trim() })
}

/* If the previous note is of class 'timeline-tail' then there's a chance that the current node belongs nested within
the previous one. Here we iterate backwards for as long as elements of the class 'timeline-tail' are encountered.

Then we sort an array containing the start and ending date of the current event along with the ending date of the
previous event. If the index of the ending date of the previous event in the new array is greater than 0 then the
note(s) preceding it (either the note belonging to the start date or the notes belonging to both the start and end
dates of the current event) are placed before their predecessor. */
for ( let s = [...timeline.children],i = s.indexOf( noteDivs[0] ); s[i-1]?.classList.contains( 'timeline-tail' ); i-- ) {
const t = s[i-1].getAttribute( 'timeline-date' )
const times = [
t,
...noteDivs.map(( n ) => {
return n.getAttribute( 'timeline-date' )
})
]

const lastTIndex = times.sort().lastIndexOf( t )
for ( let j = lastTIndex; j > 0; s[i-1].before( ...noteDivs.slice( 0, j )), j = 0 ) {
const indent = +noteDivs[0].style.getPropertyValue( '--timeline-indent' ) + 1
noteDivs.forEach(( n ) => {
n.style.setProperty( '--timeline-indent', `${ indent }` )
})
}
}

eventCount++
}

// Replace the selected tags with the timeline html
el.appendChild( timeline )

// Initial length calculation must be done after appending notes to document
el.querySelectorAll( '.timeline-tail' ).forEach(( note: DivWithCalcFunc ) => {
note.calcLength?.()
})

return
}
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## Changelog

### v2.2.6

Bug Fix for: `Custom attributes on timeline nodes` [#63](https://github.com/seanlowe/obsidian-timelines/issues/63)

**Changes:**
- added the correct changes to the `insert event` commands so that events inserted that way have all the applicable attributes.
- added a new page in the docs for understanding how to add custom classes to your timeline events.

### v2.2.5

Implement feature: Custom attributes on timeline nodes [#63](https://github.com/seanlowe/obsidian-timelines/issues/63)
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "timelines-revamped",
"name": "Timelines (Revamped)",
"version": "2.2.6",
"version": "2.2.7",
"minAppVersion": "0.10.11",
"description": "Successor to darakah's Timelines plugin: Generate a chronological timeline in which all 'events' are notes that include a specific tag or set of tags.",
"author": "seanlowe",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "timelines-revamped",
"version": "2.2.6",
"version": "2.2.7",
"description": "Generate a chronological timeline in which all 'events' are notes that include a specific tag or set of tags.",
"main": "main.js",
"scripts": {
Expand Down
40 changes: 38 additions & 2 deletions src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,17 @@ export class TimelineBlockProcessor {
const combinedEventsAndFrontMatter = await getEventsInFile( file, this.appVault, this.metadataCache )
const { numEvents } = await getNumEventsInFile( null, combinedEventsAndFrontMatter )

if ( !combinedEventsAndFrontMatter ) {
// skip this loop
continue
}

combinedEventsAndFrontMatter.forEach(( event ) => {
if ( !event ) {
// skip this loop
return
}

let eventData: EventDataObject | null = null

if ( !isHTMLElementType( event ) && Object.keys( event ).length < 3 ) {
Expand Down Expand Up @@ -177,8 +187,34 @@ export class TimelineBlockProcessor {

const imgUrl = getImgUrl( this.appVault, eventImg )

const { cleanedDateString: cleanedStartDate } = cleanDate( normalizeDate( startDate ))
const { cleanedDateString: cleanedEndDate } = cleanDate( normalizeDate( endDate ))
// normalizedStartDate is the same as noteId
let normalizedEndDate = normalizeDate( endDate )

if ( !noteId ) {
console.error( "Cannot normalize the event's start date! Skipping" )
return
}

if ( !normalizedEndDate ) {
console.warn( "parseFiles | Couldn't normalize the event's end date, setting it to empty." )
normalizedEndDate = ''
}

const cleanedStartDateObject = cleanDate( noteId )
const cleanedEndDateObject = cleanDate( normalizedEndDate )

if ( !cleanedStartDateObject ) {
const message = 'no start date object'
throw new Error( message )
}

if ( !cleanedEndDateObject ) {
const message = 'no end date object'
throw new Error( message )
}

const { cleanedDateString: cleanedStartDate } = cleanedStartDateObject
const { cleanedDateString: cleanedEndDate } = cleanedEndDateObject

const note: CardContainer = {
id: noteId,
Expand Down
12 changes: 9 additions & 3 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export class TimelineCommandProcessor {
// ensure the status bar item is removed
if ( plugin.statusBarItem ) {
plugin.statusBarItem.remove()
plugin.statusBarItem = null
}

return
Expand Down Expand Up @@ -67,11 +66,11 @@ export class TimelineCommandProcessor {
*
* @param workspace
*/
getStatusBarText = async ( workspace: Workspace ): Promise<string | null> => {
getStatusBarText = async ( workspace: Workspace ): Promise<string> => {
const file = workspace.getActiveViewOfType( MarkdownView )?.file

if ( !file ) {
return null
return ''
}

const { totalEvents } = await getNumEventsInFile({ file, appVault: this.appVault, fileCache: this.metadataCache }, null )
Expand All @@ -88,6 +87,10 @@ export class TimelineCommandProcessor {

updateStatusBarText = async ( plugin: TimelinesPlugin ) => {
const text = await this.getStatusBarText( plugin.app.workspace )
if ( text === '' ) {
return
}

plugin.statusBarItem.setText( text )
}

Expand Down Expand Up @@ -180,6 +183,9 @@ export class TimelineCommandProcessor {

const renderedString = `<div class="timeline-rendered">${new Date().toString()}</div>`
const rendered = ( new DOMParser()).parseFromString( renderedString, 'text/html' ).body.firstChild
if ( !rendered ) {
throw new Error( 'Could not generate the statically rendered timeline' )
}
div.appendChild( rendered )

const firstCommentEndIndex = source.indexOf( '-->' )
Expand Down
Loading
Loading
0