textbrowser 0.40.0 → 0.41.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "textbrowser",
3
- "version": "0.40.0",
3
+ "version": "0.41.0",
4
4
  "description": "Multilinear text browser",
5
5
  "main": "dist/index-umd.min.js",
6
6
  "module": "resources/index.js",
@@ -39,62 +39,62 @@
39
39
  "text"
40
40
  ],
41
41
  "dependencies": {
42
- "@babel/core": "^7.14.6",
43
- "@babel/register": "^7.14.5",
42
+ "@babel/core": "^7.16.7",
43
+ "@babel/register": "^7.16.9",
44
44
  "@brettz9/node-static": "^0.1.1",
45
- "command-line-args": "^5.1.1",
45
+ "command-line-args": "^5.2.0",
46
46
  "dialog-polyfill": "^0.5.6",
47
47
  "dom-parser": "^0.1.6",
48
48
  "form-serialization": "^0.11.0",
49
49
  "imf": "5.0.2",
50
- "indexeddbshim": "^7.1.0",
50
+ "indexeddbshim": "^9.0.0",
51
51
  "jamilih": "0.54.0",
52
- "jsdom": "^16.6.0",
52
+ "jsdom": "^19.0.0",
53
53
  "json-refs": "git+https://github.com/brettz9/json-refs.git#browser",
54
54
  "load-stylesheets": "0.10.0",
55
- "node-fetch": "^2.6.1",
55
+ "node-fetch": "^2.6.6",
56
56
  "node-serviceworker": "^0.3.0",
57
- "rtl-detect": "^1.0.3",
57
+ "rtl-detect": "^1.0.4",
58
58
  "simple-get-json": "8.1.1",
59
59
  "url-search-params-polyfill": "^8.1.1"
60
60
  },
61
61
  "devDependencies": {
62
- "@babel/eslint-parser": "^7.14.5",
63
- "@babel/plugin-proposal-object-rest-spread": "^7.14.5",
62
+ "@babel/eslint-parser": "^7.16.5",
63
+ "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
64
64
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
65
- "@babel/preset-env": "^7.14.5",
66
- "@brettz9/eslint-plugin": "^1.0.3",
65
+ "@babel/preset-env": "^7.16.8",
66
+ "@brettz9/eslint-plugin": "^1.0.4",
67
67
  "@rollup/plugin-babel": "^5.3.0",
68
- "@rollup/plugin-commonjs": "^19.0.0",
68
+ "@rollup/plugin-commonjs": "^21.0.1",
69
69
  "@rollup/plugin-json": "^4.1.0",
70
- "@rollup/plugin-node-resolve": "^13.0.0",
70
+ "@rollup/plugin-node-resolve": "^13.1.3",
71
71
  "@stadtlandnetz/rollup-plugin-postprocess": "1.1.0",
72
- "ajv": "8.6.0",
72
+ "ajv": "8.8.2",
73
73
  "babel-plugin-dynamic-import-node": "^2.3.3",
74
74
  "chai": "^4.3.4",
75
- "eslint": "^7.28.0",
76
- "eslint-config-ash-nazg": "^29.17.0",
75
+ "eslint": "^8.6.0",
76
+ "eslint-config-ash-nazg": "^32.3.0",
77
77
  "eslint-config-standard": "^16.0.3",
78
78
  "eslint-plugin-array-func": "^3.1.7",
79
- "eslint-plugin-compat": "^3.9.0",
79
+ "eslint-plugin-compat": "^4.0.1",
80
80
  "eslint-plugin-eslint-comments": "^3.2.0",
81
- "eslint-plugin-html": "^6.1.2",
82
- "eslint-plugin-import": "^2.23.4",
83
- "eslint-plugin-jsdoc": "^35.2.0",
84
- "eslint-plugin-markdown": "^2.2.0",
85
- "eslint-plugin-no-unsanitized": "^3.1.5",
81
+ "eslint-plugin-html": "^6.2.0",
82
+ "eslint-plugin-import": "^2.25.4",
83
+ "eslint-plugin-jsdoc": "^37.6.1",
84
+ "eslint-plugin-markdown": "^2.2.1",
85
+ "eslint-plugin-no-unsanitized": "^4.0.1",
86
86
  "eslint-plugin-no-use-extend-native": "^0.5.0",
87
87
  "eslint-plugin-node": "^11.1.0",
88
- "eslint-plugin-promise": "^5.1.0",
89
- "eslint-plugin-radar": "^0.2.1",
88
+ "eslint-plugin-promise": "^6.0.0",
89
+ "eslint-plugin-sonarjs": "^0.11.0",
90
90
  "eslint-plugin-standard": "^4.1.0",
91
- "eslint-plugin-unicorn": "^33.0.1",
92
- "fast-json-patch": "2.2.1",
91
+ "eslint-plugin-unicorn": "^40.0.0",
92
+ "fast-json-patch": "3.1.0",
93
93
  "json-metaschema": "1.3.0",
94
- "mocha": "^9.0.0",
94
+ "mocha": "^9.1.3",
95
95
  "npm-run-all": "^4.1.5",
96
- "open-cli": "^7.0.0",
97
- "rollup": "2.51.2",
96
+ "open-cli": "^7.0.1",
97
+ "rollup": "2.63.0",
98
98
  "rollup-plugin-re": "^1.0.7",
99
99
  "rollup-plugin-terser": "^7.0.2"
100
100
  }
@@ -137,7 +137,7 @@ async function requestPermissions (langs, l) {
137
137
  // rememberRefusal();
138
138
  resolve();
139
139
  return;
140
- // eslint-disable-next-line radar/no-duplicated-branches
140
+ // eslint-disable-next-line sonarjs/no-duplicated-branches
141
141
  case 'default':
142
142
  resolve();
143
143
  return;
@@ -191,6 +191,8 @@ class TextBrowser {
191
191
  ? true
192
192
  : options.localizeParamNames;
193
193
  this.hideFormattingSection = Boolean(options.hideFormattingSection);
194
+
195
+ this.preferencesPlugin = options.preferencesPlugin;
194
196
  this.interlinearSeparator = options.interlinearSeparator;
195
197
  // Todo: Make these user facing options
196
198
  this.showEmptyInterlinear = options.showEmptyInterlinear;
@@ -532,7 +534,8 @@ class TextBrowser {
532
534
  lang, preferredLocale,
533
535
  fallbackLanguages,
534
536
  languageParam,
535
- $p, languages
537
+ $p, languages,
538
+ preferencesPlugin: this.preferencesPlugin
536
539
  });
537
540
  return true;
538
541
  }
@@ -547,7 +547,7 @@ export default {
547
547
  languageParam, lf, paramsSetter, replaceHash,
548
548
  getFieldAliasOrNames, work,
549
549
  langs, imfl, l, localizeParamNames, namespace,
550
- hideFormattingSection, groups
550
+ hideFormattingSection, groups, preferencesPlugin
551
551
  }) => ['div', {
552
552
  style: {textAlign: 'left'}, id: 'preferences', hidden: 'true'
553
553
  }, [
@@ -611,85 +611,10 @@ export default {
611
611
  ]];
612
612
  })]
613
613
  ]],
614
- ['div', [
615
- ['button', {
616
- title: l('bookmark_generation_tooltip'),
617
- $on: {
618
- async click () { // Todo: Give option to edit (keywords and work URLs)
619
- const date = Date.now();
620
- const ADD_DATE = date;
621
- const LAST_MODIFIED = date;
622
- const blob = new Blob([
623
- new XMLSerializer().serializeToString(
624
- jml({$document: {
625
- $DOCTYPE: {name: 'NETSCAPE-Bookmark-file-1'},
626
- title: l('Bookmarks'),
627
- body: [
628
- ['h1', [l('Bookmarks_Menu')]],
629
- ...(await getFieldAliasOrNames()).flatMap(({groupName, worksToFields}) => {
630
- return [
631
- ['dt', [
632
- ['h3', {
633
- ADD_DATE,
634
- LAST_MODIFIED
635
- }, [
636
- groupName
637
- ]]
638
- ]],
639
- ['dl', [
640
- ['p'],
641
- ...worksToFields.map(({fieldAliasOrNames, workName, shortcut: SHORTCUTURL}) => {
642
- // Todo (low): Add anchor, etc. (until handled by `work-startEnd`); &aqdas-anchor1-1=2&anchorfield1=Paragraph
643
- // Todo: option for additional browse field groups (startEnd2, etc.)
644
- // Todo: For link text, use `heading` or `alias` from metadata files in place of workName (requires loading all metadata files though)
645
- // Todo: Make Chrome NativeExt add-on to manipulate its search engines (to read a bookmarks file from Firefox properly, i.e., including keywords) https://www.makeuseof.com/answers/export-google-chrome-search-engines-address-bar/
646
-
647
- const paramsCopy = paramsSetter({
648
- ...getDataForSerializingParamsAsURL(),
649
- fieldAliasOrNames,
650
- workName: work, // Delete work of current page
651
- type: 'shortcutResult'
652
- });
653
- const url = replaceHash(paramsCopy) + `&work=${workName}&${workName}-startEnd1=%s`; // %s will be escaped if set as param; also add changeable workName here
654
-
655
- return ['dt', [
656
- ['a', {
657
- href: url,
658
- ADD_DATE,
659
- LAST_MODIFIED,
660
- SHORTCUTURL
661
- }, [
662
- workName
663
- ]]
664
- ]];
665
- })
666
- ]]
667
- ];
668
- })
669
- ]
670
- }})
671
- ).replace(
672
- // Chrome has a quirk that requires this (and not
673
- // just any whitespace)
674
- // We're not getting the keywords with Chrome,
675
- // but at least usable for bookmarks (though
676
- // not the groups apparently)
677
- /<dt>/g,
678
- '\n<dt>'
679
- )
680
- ], {type: 'text/html'});
681
- const url = window.URL.createObjectURL(blob);
682
- const a = jml('a', {
683
- hidden: true,
684
- download: 'bookmarks.html',
685
- href: url
686
- }, $('#main'));
687
- a.click();
688
- URL.revokeObjectURL(url);
689
- }
690
- }
691
- }, [l('Generate_bookmarks')]]
692
- ]]
614
+ (preferencesPlugin ? preferencesPlugin({
615
+ $, l, jml, paramsSetter, getDataForSerializingParamsAsURL, work,
616
+ replaceHash, getFieldAliasOrNames
617
+ }) : '')
693
618
  ]],
694
619
  addBrowseFields ({browseFields, fieldInfo, ld, i, iil, $p, content}) {
695
620
  const work = $p.get('work');
@@ -830,7 +755,7 @@ export default {
830
755
  getFieldAliasOrNames,
831
756
  hideFormattingSection, $p,
832
757
  metadataObj, il, le, ld, iil, fieldMatchesLocale,
833
- preferredLocale, schemaItems, content, groups
758
+ preferredLocale, schemaItems, content, groups, preferencesPlugin
834
759
  }) {
835
760
  const work = $p.get('work');
836
761
  const serializeParamsAsURLWithData = ({type}) => {
@@ -863,7 +788,7 @@ export default {
863
788
  languageParam, lf, paramsSetter, replaceHash,
864
789
  getFieldAliasOrNames, work,
865
790
  langs, imfl, l, localizeParamNames, namespace,
866
- groups, hideFormattingSection
791
+ groups, hideFormattingSection, preferencesPlugin
867
792
  })
868
793
  ]],
869
794
  ['h2', [heading]],
@@ -33,9 +33,14 @@ export const getMetaProp = function getMetaProp (lang, metadataObj, properties,
33
33
  // file.anyOf.splice(1, 1, {$ref: schemaFile});
34
34
  // Todo: Allow use of dbs and fileGroup together in base directories?
35
35
  export const getMetadata = async (file, property, basePath) => {
36
+ const url = new URL(basePath || getCurrDir());
37
+ url.search = ''; // Clear out query string, e.g., `?fbclid` from Facebook
38
+ url.pathname = file;
39
+ url.hash = property ? '#/' + property : '';
40
+
36
41
  return (await JsonRefs
37
42
  .resolveRefsAt(
38
- (basePath || getCurrDir()) + file + (property ? '#/' + property : ''),
43
+ url.toString(),
39
44
  {
40
45
  loaderOptions: {
41
46
  processContent (res, callback) {
@@ -12,6 +12,7 @@ export default async function workDisplay ({
12
12
  l, languageParam,
13
13
  lang, preferredLocale, languages, fallbackLanguages, $p
14
14
  }) {
15
+ const {preferencesPlugin} = this;
15
16
  const langs = this.langData.languages;
16
17
 
17
18
  const fallbackDirection = this.getDirectionForLanguageCode(fallbackLanguages[0]);
@@ -41,7 +42,6 @@ export default async function workDisplay ({
41
42
  ? key => l(['params', 'indexed', key])
42
43
  : key => key;
43
44
 
44
- // eslint-disable-next-line unicorn/prefer-prototype-methods -- Convenient
45
45
  const localeFromLangData = languages.localeFromLangData.bind(languages);
46
46
  const imfLang = IMF({
47
47
  locales: lang.map(localeFromLangData),
@@ -137,7 +137,8 @@ export default async function workDisplay ({
137
137
  hideFormattingSection, $p,
138
138
  metadataObj, il, le, ld, iil,
139
139
  fieldMatchesLocale,
140
- preferredLocale, schemaItems, content
140
+ preferredLocale, schemaItems, content,
141
+ preferencesPlugin
141
142
  });
142
143
  }
143
144
 
@@ -13,14 +13,9 @@ function ownKeys(object, enumerableOnly) {
13
13
 
14
14
  if (Object.getOwnPropertySymbols) {
15
15
  var symbols = Object.getOwnPropertySymbols(object);
16
-
17
- if (enumerableOnly) {
18
- symbols = symbols.filter(function (sym) {
19
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
20
- });
21
- }
22
-
23
- keys.push.apply(keys, symbols);
16
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
17
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
18
+ })), keys.push.apply(keys, symbols);
24
19
  }
25
20
 
26
21
  return keys;
@@ -28,19 +23,12 @@ function ownKeys(object, enumerableOnly) {
28
23
 
29
24
  function _objectSpread2(target) {
30
25
  for (var i = 1; i < arguments.length; i++) {
31
- var source = arguments[i] != null ? arguments[i] : {};
32
-
33
- if (i % 2) {
34
- ownKeys(Object(source), true).forEach(function (key) {
35
- _defineProperty(target, key, source[key]);
36
- });
37
- } else if (Object.getOwnPropertyDescriptors) {
38
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
39
- } else {
40
- ownKeys(Object(source)).forEach(function (key) {
41
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
42
- });
43
- }
26
+ var source = null != arguments[i] ? arguments[i] : {};
27
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
28
+ _defineProperty(target, key, source[key]);
29
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
30
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
31
+ });
44
32
  }
45
33
 
46
34
  return target;
@@ -772,7 +760,8 @@ var workDisplay = {
772
760
  localizeParamNames,
773
761
  namespace,
774
762
  hideFormattingSection,
775
- groups
763
+ groups,
764
+ preferencesPlugin
776
765
  }) => ['div', {
777
766
  style: {
778
767
  textAlign: 'left'
@@ -839,73 +828,16 @@ var workDisplay = {
839
828
  }
840
829
 
841
830
  return ['option', atts, [imfl(['languages', lan.code])]];
842
- })]]], ['div', [['button', {
843
- title: l('bookmark_generation_tooltip'),
844
- $on: {
845
- async click() {
846
- // Todo: Give option to edit (keywords and work URLs)
847
- const date = Date.now();
848
- const ADD_DATE = date;
849
- const LAST_MODIFIED = date;
850
- const blob = new Blob([new XMLSerializer().serializeToString(jamilih.jml({
851
- $document: {
852
- $DOCTYPE: {
853
- name: 'NETSCAPE-Bookmark-file-1'
854
- },
855
- title: l('Bookmarks'),
856
- body: [['h1', [l('Bookmarks_Menu')]], ...(await getFieldAliasOrNames()).flatMap(({
857
- groupName,
858
- worksToFields
859
- }) => {
860
- return [['dt', [['h3', {
861
- ADD_DATE,
862
- LAST_MODIFIED
863
- }, [groupName]]]], ['dl', [['p'], ...worksToFields.map(({
864
- fieldAliasOrNames,
865
- workName,
866
- shortcut: SHORTCUTURL
867
- }) => {
868
- // Todo (low): Add anchor, etc. (until handled by `work-startEnd`); &aqdas-anchor1-1=2&anchorfield1=Paragraph
869
- // Todo: option for additional browse field groups (startEnd2, etc.)
870
- // Todo: For link text, use `heading` or `alias` from metadata files in place of workName (requires loading all metadata files though)
871
- // Todo: Make Chrome NativeExt add-on to manipulate its search engines (to read a bookmarks file from Firefox properly, i.e., including keywords) https://www.makeuseof.com/answers/export-google-chrome-search-engines-address-bar/
872
- const paramsCopy = paramsSetter(_objectSpread2(_objectSpread2({}, getDataForSerializingParamsAsURL()), {}, {
873
- fieldAliasOrNames,
874
- workName: work,
875
- // Delete work of current page
876
- type: 'shortcutResult'
877
- }));
878
- const url = replaceHash(paramsCopy) + `&work=${workName}&${workName}-startEnd1=%s`; // %s will be escaped if set as param; also add changeable workName here
879
-
880
- return ['dt', [['a', {
881
- href: url,
882
- ADD_DATE,
883
- LAST_MODIFIED,
884
- SHORTCUTURL
885
- }, [workName]]]];
886
- })]]];
887
- })]
888
- }
889
- })).replace( // Chrome has a quirk that requires this (and not
890
- // just any whitespace)
891
- // We're not getting the keywords with Chrome,
892
- // but at least usable for bookmarks (though
893
- // not the groups apparently)
894
- /<dt>/g, '\n<dt>')], {
895
- type: 'text/html'
896
- });
897
- const url = window.URL.createObjectURL(blob);
898
- const a = jamilih.jml('a', {
899
- hidden: true,
900
- download: 'bookmarks.html',
901
- href: url
902
- }, jamilih.$('#main'));
903
- a.click();
904
- URL.revokeObjectURL(url);
905
- }
906
-
907
- }
908
- }, [l('Generate_bookmarks')]]]]]],
831
+ })]]], preferencesPlugin ? preferencesPlugin({
832
+ $: jamilih.$,
833
+ l,
834
+ jml: jamilih.jml,
835
+ paramsSetter,
836
+ getDataForSerializingParamsAsURL,
837
+ work,
838
+ replaceHash,
839
+ getFieldAliasOrNames
840
+ }) : '']],
909
841
 
910
842
  addBrowseFields({
911
843
  browseFields,
@@ -1057,7 +989,8 @@ var workDisplay = {
1057
989
  preferredLocale,
1058
990
  schemaItems,
1059
991
  content,
1060
- groups
992
+ groups,
993
+ preferencesPlugin
1061
994
  }) {
1062
995
  const work = $p.get('work');
1063
996
 
@@ -1108,7 +1041,8 @@ var workDisplay = {
1108
1041
  localizeParamNames,
1109
1042
  namespace,
1110
1043
  groups,
1111
- hideFormattingSection
1044
+ hideFormattingSection,
1045
+ preferencesPlugin
1112
1046
  })]], ['h2', [heading]], ['br'], ['form', {
1113
1047
  id: 'browse',
1114
1048
  $custom: {
@@ -2182,7 +2116,12 @@ const getMetaProp = function getMetaProp(lang, metadataObj, properties, allowObj
2182
2116
  // Todo: Allow use of dbs and fileGroup together in base directories?
2183
2117
 
2184
2118
  const getMetadata = async (file, property, basePath) => {
2185
- return (await JsonRefs$1.resolveRefsAt((basePath || getCurrDir()) + file + (property ? '#/' + property : ''), {
2119
+ const url = new URL(basePath || getCurrDir());
2120
+ url.search = ''; // Clear out query string, e.g., `?fbclid` from Facebook
2121
+
2122
+ url.pathname = file;
2123
+ url.hash = property ? '#/' + property : '';
2124
+ return (await JsonRefs$1.resolveRefsAt(url.toString(), {
2186
2125
  loaderOptions: {
2187
2126
  processContent(res, callback) {
2188
2127
  callback(undefined, JSON.parse(res.text || // `.metadata` not a recognized extension, so
package/sw-sample.js CHANGED
@@ -1,12 +1,11 @@
1
1
  /* eslint-env browser, serviceworker -- Service worker */
2
2
 
3
3
  import {getJSON} from './node_modules/simple-get-json/dist/index-es.js';
4
- import activateCallback from './node_modules/textbrowser/resources/activateCallback.js';
5
- import {getWorkFiles} from './node_modules/textbrowser/resources/utils/WorkInfo.js';
4
+ import activateCallback from './node_modules/textbrowser/dist/activateCallback-es.js';
5
+ import {getWorkFiles} from './node_modules/textbrowser/dist/WorkInfo-es.js';
6
6
 
7
- const CACHE_VERSION = '0.40.0';
8
7
  const CURRENT_CACHES = {
9
- prefetch: 'prefetch-cache-v' + CACHE_VERSION
8
+ prefetch: 'prefetch-cache-v'
10
9
  };
11
10
  const minutes = 60 * 1000;
12
11
 
@@ -31,6 +30,7 @@ async function post ({type, message = type}) {
31
30
  clients.forEach((client) => {
32
31
  // Although we only need one client to which to send
33
32
  // arguments, we want to signal phase complete to all
33
+ // eslint-disable-next-line unicorn/require-post-message-target-origin -- In worker
34
34
  client.postMessage({message, type});
35
35
  });
36
36
  }
@@ -50,7 +50,7 @@ function log (...messages) {
50
50
  *
51
51
  * @param {Error} error
52
52
  * @param {string[]} messages
53
- * @returns {Promise<void>}
53
+ * @returns {Promise<void>}
54
54
  */
55
55
  function logError (error, ...messages) {
56
56
  const message = messages.join(' ');
@@ -182,13 +182,15 @@ async function install (time) {
182
182
  namespace, languages, files, userStaticFiles
183
183
  } = getConfigDefaults(json);
184
184
 
185
- console.log('opening cache', namespace + CURRENT_CACHES.prefetch);
185
+ const {version} = await getJSON('./package.json');
186
+
187
+ console.log('opening cache', namespace + CURRENT_CACHES.prefetch + version);
186
188
  const [
187
189
  cache,
188
190
  userDataFiles,
189
191
  {languages: langs}
190
192
  ] = await Promise.all([
191
- caches.open(namespace + CURRENT_CACHES.prefetch),
193
+ caches.open(namespace + CURRENT_CACHES.prefetch + version),
192
194
  getWorkFiles(files),
193
195
  getJSON(languages)
194
196
  ]);
@@ -230,7 +232,7 @@ async function install (time) {
230
232
  return cache.put(urlToPrefetch, response);
231
233
  } catch (error) {
232
234
  logError(error, 'Not caching ' + urlToPrefetch + ' due to ' + error);
233
- return Promise.reject(error);
235
+ throw error;
234
236
  }
235
237
  });
236
238
  await Promise.all(cachePromises);
@@ -263,8 +265,9 @@ async function activate (time) {
263
265
  caches.keys()
264
266
  ]);
265
267
  const {namespace, files, basePath} = getConfigDefaults(json);
268
+ const {version} = await getJSON('./package.json');
266
269
 
267
- const expectedCacheNames = Object.values(CURRENT_CACHES).map((n) => namespace + n);
270
+ const expectedCacheNames = Object.values(CURRENT_CACHES).map((n) => namespace + n + version);
268
271
  cacheNames.map(async (cacheName) => {
269
272
  if (!expectedCacheNames.includes(cacheName)) {
270
273
  log('Activate: Deleting out of date cache:', cacheName);