vis-chronicle 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/wikidata.js CHANGED
@@ -88,6 +88,18 @@ const wikidata = module.exports = {
88
88
  const contents = await fs.promises.readFile(path)
89
89
  this.inputSpec = JSON.parse(contents)
90
90
  }
91
+
92
+ // assign default values
93
+ if (!this.inputSpec.chronicle)
94
+ this.inputSpec.chronicle = {}
95
+
96
+ const chronicleOptions = this.inputSpec.chronicle
97
+ if (chronicleOptions.defaultLabel === undefined)
98
+ chronicleOptions.defaultLabel = '<a target="_blank" href="https://www.wikidata.org/wiki/{_QID}">{_LABEL}</a>'
99
+ if (chronicleOptions.maxUncertainTimePrecision === undefined)
100
+ chronicleOptions.maxUncertainTimePrecision = 10
101
+ if (chronicleOptions.shareSuccessiveUncertainty === undefined)
102
+ chronicleOptions.shareSuccessiveUncertainty = true
91
103
  },
92
104
 
93
105
  readCache: async function()
@@ -279,20 +291,29 @@ const wikidata = module.exports = {
279
291
  // runs a SPARQL query for time values on an item or set of items
280
292
  runTimeQueryTerm: async function (queryTermStr, items)
281
293
  {
294
+ // keys that may appear on the query term that provide terms
295
+ const termTimeKeys = [
296
+ "general",
297
+ "start", "start_min", "start_max",
298
+ "end", "end_min", "end_max",
299
+ "value", "min", "max"
300
+ ]
301
+ const termOtherKeys = [ "previous", "next" ]
302
+
282
303
  const entityVarName = '_entity'
283
304
  const entityVar = `?${entityVarName}`
284
305
  const propVar = '?_prop'
285
306
  const rankVar = '?_rank'
286
307
 
287
- const queryBuilder = new SparqlBuilder()
288
- queryBuilder.addCacheBuster(this.cacheBuster)
289
-
290
308
  // create a dummy item representing the collective items
291
309
  //TODO: validate that they match
292
310
  item = { ...items[0] }
293
311
  item.entity = entityVar
294
312
  item.id = "DUMMY"
295
313
 
314
+ const queryBuilder = new SparqlBuilder()
315
+ queryBuilder.addCacheBuster(item.cacheBuster ? item.cacheBuster : this.cacheBuster)
316
+
296
317
  queryTerm = this.getValueQueryTerm(queryTermStr, item)
297
318
 
298
319
  // assembly query targets
@@ -302,21 +323,32 @@ const wikidata = module.exports = {
302
323
  targetEntities.add(`wd:${item.entity}`)
303
324
  }
304
325
  queryBuilder.addQueryTerm(`VALUES ${entityVar}{${[...targetEntities].join(' ')}}`)
305
- queryBuilder.addOutParam(entityVar)
326
+ queryBuilder.addOutParam(entityVar, { groupBy: true })
306
327
 
307
- queryBuilder.addOutParam(rankVar)
328
+ // Group by prop object so that multiple prev/next values on the same property are grouped,
329
+ // but different properties with different prev/next values are separate.
330
+ queryBuilder.addGroupParam(propVar)
331
+
332
+ queryBuilder.addOutParam(rankVar, { groupBy: true })
308
333
  if (queryTerm.general)
309
334
  {
310
335
  queryBuilder.addQueryTerm(queryTerm.general)
311
336
  }
312
337
  if (queryTerm.value) //TODO: could unify better with loop below?
313
338
  {
314
- queryBuilder.addTimeTerm(queryTerm.value, "?_value", "?_value_ti", "?_value_pr")
339
+ queryBuilder.addTimeTerm(queryTerm.value, "?_value", "?_value_ti", "?_value_pr", { groupBy: true })
315
340
  }
316
- for (const termKey in queryTerm) //TODO: only pass recognized terms
341
+ for (const termKey of termTimeKeys)
317
342
  {
343
+ if (!queryTerm[termKey]) continue
318
344
  if (termKey == "general" || termKey == "value") continue
319
- queryBuilder.addOptionalTimeTerm(queryTerm[termKey], `?_${termKey}_value`, `?_${termKey}_ti`, `?_${termKey}_pr`)
345
+ queryBuilder.addOptionalTimeTerm(queryTerm[termKey], `?_${termKey}_value`, `?_${termKey}_ti`, `?_${termKey}_pr`, { groupBy: true })
346
+ }
347
+ for (const termKey of termOtherKeys)
348
+ {
349
+ if (!queryTerm[termKey]) continue
350
+ queryBuilder.addOutParam(`(GROUP_CONCAT(DISTINCT ?_${termKey}_value; SEPARATOR=";") AS ?_${termKey}_out)`)
351
+ queryBuilder.addOptionalQueryTerm(queryTerm[termKey])
320
352
  }
321
353
  queryBuilder.addOptionalQueryTerm(`${propVar} wikibase:rank ${rankVar}.`)
322
354
 
@@ -335,7 +367,7 @@ const wikidata = module.exports = {
335
367
  const readBinding = function(binding)
336
368
  {
337
369
  const result = {}
338
- for (const termKey in queryTerm) //TODO: only use recognized terms
370
+ for (const termKey of termTimeKeys)
339
371
  {
340
372
  if (binding[`_${termKey}_ti`])
341
373
  {
@@ -345,6 +377,15 @@ const wikidata = module.exports = {
345
377
  }
346
378
  }
347
379
  }
380
+ for (const termKey of termOtherKeys)
381
+ {
382
+ const termOtherVar = `_${termKey}_out`
383
+ if (binding[termOtherVar])
384
+ {
385
+ const valueSplit = binding[termOtherVar].value.split(';')
386
+ result[termKey] = wikidata.extractQidFromUrl(valueSplit[0]) //HACK: does not support multiple values
387
+ }
388
+ }
348
389
  return result
349
390
  }
350
391
 
@@ -353,7 +394,18 @@ const wikidata = module.exports = {
353
394
  const results = []
354
395
  for (const binding of bindings)
355
396
  {
356
- results.push(readBinding(binding))
397
+ const newBinding = readBinding(binding)
398
+ const newBindingSerialized = JSON.stringify(newBinding) //HACK: serialization for comparison
399
+
400
+ //HACK: omit perfect duplicates. This can happen with overlapping statements for same position (e.g. Q8423 "position held" for subclass:king)
401
+ var isDupe = false
402
+ for (const result of results)
403
+ {
404
+ isDupe = (JSON.stringify(result) == newBindingSerialized)
405
+ if (isDupe) break
406
+ }
407
+
408
+ if (!isDupe) results.push(readBinding(binding))
357
409
  }
358
410
  return results
359
411
  }
@@ -428,6 +480,7 @@ const wikidata = module.exports = {
428
480
  }
429
481
 
430
482
  const queryBuilder = new SparqlBuilder()
483
+ queryBuilder.distinct = true
431
484
  queryBuilder.addCacheBuster(this.cacheBuster)
432
485
  queryBuilder.addOutParam(itemVar)
433
486
  queryBuilder.addOutParam(itemVar + "Label")
@@ -449,9 +502,10 @@ const wikidata = module.exports = {
449
502
  newItem.entity = this.extractQidFromUrl(binding[itemVarName].value)
450
503
  newItem.generated = true
451
504
  const wikidataLabel = binding[itemVarName + "Label"].value
452
- newItem.label = templateItem.label
453
- ? templateItem.label.replaceAll("{_LABEL}", wikidataLabel).replaceAll("{_QID}", newItem.entity)
454
- : `<a target="_blank" href="https://www.wikidata.org/wiki/${newItem.entity}">${wikidataLabel}</a>`
505
+
506
+ const labelFomat = templateItem.label ? templateItem.label : this.inputSpec.chronicle.defaultLabel
507
+ newItem.label = labelFomat.replaceAll("{_LABEL}", wikidataLabel).replaceAll("{_QID}", newItem.entity)
508
+
455
509
  newItems.push(newItem)
456
510
  }
457
511
 
package/styles/style.css CHANGED
@@ -1,18 +1,35 @@
1
- .vis-item.vis-range.visc-open-right
1
+ .vis-item.vis-range.visc-open-right, .vis-item.vis-background.visc-open-right
2
2
  {
3
3
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0));
4
4
  }
5
- .vis-item.vis-range.visc-open-left
5
+ .vis-item.vis-range.visc-open-left, .vis-item.vis-background.visc-open-left
6
6
  {
7
7
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) 50%);
8
8
  }
9
- .vis-item.vis-range.visc-open-both
9
+ .vis-item.vis-range.visc-open-left, .vis-item.vis-background.visc-open-left
10
10
  {
11
11
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0));
12
12
  }
13
- .visc-uncertain
13
+ .vis-item.vis-range.visc-uncertain
14
14
  {
15
- background: repeating-linear-gradient(45deg, #00000060, #00000060 8px, transparent 8px, transparent 16px)
15
+ background: repeating-linear-gradient(45deg, #404040, #404040 8px, rgba(213, 221, 246, 0.4) 8px, rgba(213, 221, 246, 0.4) 16px);
16
+ border-style: dashed;
17
+ }
18
+ .vis-item.vis-background.visc-uncertain
19
+ {
20
+ mask-image: repeating-linear-gradient(45deg, black, black 8px, transparent 8px, transparent 16px);
21
+ border: none;
22
+ }
23
+ .visc-range-overlay
24
+ {
25
+ z-index: 2;
26
+ }
27
+ .vis-item.visc-toplabel
28
+ {
29
+ z-index: 3;
30
+ background: none !important;
31
+ background-color: transparent !important;
32
+ border: 0;
16
33
  }
17
34
  .vis-item.vis-range.visc-right-connection, .vis-item.vis-range.visc-left-tail
18
35
  {