apostrophe 4.1.0 → 4.2.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/lib/mongodb-connect.js +1 -1
  3. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarMenu.vue +1 -0
  4. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +22 -16
  5. package/modules/@apostrophecms/area/index.js +1 -1
  6. package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +6 -1
  7. package/modules/@apostrophecms/db/index.js +0 -6
  8. package/modules/@apostrophecms/doc/index.js +19 -31
  9. package/modules/@apostrophecms/doc/lib/migrations.js +59 -0
  10. package/modules/@apostrophecms/doc-type/index.js +5 -2
  11. package/modules/@apostrophecms/express/index.js +3 -2
  12. package/modules/@apostrophecms/i18n/i18n/de.json +5 -1
  13. package/modules/@apostrophecms/i18n/i18n/en.json +5 -1
  14. package/modules/@apostrophecms/i18n/i18n/es.json +5 -1
  15. package/modules/@apostrophecms/i18n/i18n/fr.json +5 -1
  16. package/modules/@apostrophecms/i18n/i18n/it.json +5 -1
  17. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +5 -1
  18. package/modules/@apostrophecms/i18n/i18n/sk.json +5 -1
  19. package/modules/@apostrophecms/i18n/index.js +1 -1
  20. package/modules/@apostrophecms/migration/index.js +5 -0
  21. package/modules/@apostrophecms/modal/ui/apos/apps/AposModals.js +2 -2
  22. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +188 -187
  23. package/modules/@apostrophecms/modal/ui/apos/composables/AposFocus.js +2 -2
  24. package/modules/@apostrophecms/notification/index.js +2 -0
  25. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +2 -2
  26. package/modules/@apostrophecms/rich-text-widget/index.js +19 -8
  27. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +49 -16
  28. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapMarks.vue +226 -0
  29. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +90 -18
  30. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Classes.js +70 -6
  31. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Default.js +2 -1
  32. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Document.js +1 -1
  33. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Heading.js +1 -1
  34. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +1 -1
  35. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +1 -1
  36. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputColor.js +4 -0
  37. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +3 -0
  38. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +2 -2
  39. package/modules/@apostrophecms/ui/ui/apos/lib/i18next.js +4 -8
  40. package/modules/@apostrophecms/user/index.js +40 -14
  41. package/modules/@apostrophecms/user/lib/password-hash.js +122 -0
  42. package/modules/@apostrophecms/util/ui/src/http.js +7 -0
  43. package/package.json +3 -5
  44. package/test/docs.js +151 -0
  45. package/test/password-hash.js +56 -0
  46. package/test/users.js +19 -3
  47. package/.github/workflows/outdated-dependencies.yml +0 -43
  48. package/modules/@apostrophecms/modal/ui/apos/mixins/AposFocusMixin.js +0 -91
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.2.0 (2024-04-18)
4
+
5
+ * Typing a `/` in the title field of a page no longer confuses the slug field. Thanks to [Gauav Kumar](https://github.com/gkumar9891).
6
+
7
+ ### Changes
8
+
9
+ * Rich text styles are now split into Nodes and Marks, with independent toolbar controls for a better user experience when applying text styles.
10
+ There is no change in how the `styles` option is configured.
11
+ * Rich text style labels are fully localized.
12
+ * `i18n` module now uses the regular `req.redirect` instead of a direct `res.redirect` to ensure redirection, enabling more possibilities for `@apostrophecms/redirect` module
13
+ * Refactors `AposModal` component with composition api to get rid of duplicated code in `AposFocusMixin` and `AposFocus`.
14
+ * `APOS_MONGODB_LOG_LEVEL` has been removed. According to [mongodb documentation](https://github.com/mongodb/node-mongodb-native/blob/main/etc/notes/CHANGES_5.0.0.md#mongoclientoptionslogger-and-mongoclientoptionsloglevel-removed) "Both the logger and the logLevel options had no effect and have been removed."
15
+ * Update `connect-mongo` to `5.x`. Add `@apostrophecms/emulate-mongo-3-driver` dependency to keep supporting `mongodb@3.x` queries while using `mongodb@6.x`.
16
+
17
+ ### Fixes
18
+
19
+ * Updates the docs `beforeInsert` handler to avoid ending with different modes being set between `_id`, `aposLocale` and `aposMode`.
20
+ * Adds a migration to fix potential corrupted data having different modes set between `_id`, `aposLocale` and `aposMode`.
21
+ * Fix a crash in `notification` when `req.body` was not present. Thanks to Michelin for contributing this fix.
22
+ * Addresses a console error observed when opening and closing the `@apostrophecms-pro/palette` module across various projects.
23
+ * Fixes the color picker field in `@apostrophecms-pro/palette` module.
24
+ * Ensures that the `data-apos-test` attribute in the admin bar's tray item buttons is set by passing the `action` prop to `AposButton`.
25
+ * Prevents stripping of query parameters from the URL when the page is either switched to edit mode or reloaded while in edit mode.
26
+ * Add the missing `metaType` property to newly inserted widgets.
27
+
28
+ ### Security
29
+
30
+ * New passwords are now hashed with `scrypt`, the best password hash available in the Node.js core `crypto` module, following guidance from [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).
31
+ This reduces login time while improving overall security.
32
+ * Old passwords are automatically re-hashed with `scrypt` on the next successful login attempt, which
33
+ adds some delay to that next attempt, but speeds them up forever after compared to the old implementation.
34
+ * Custom `scrypt` parameters for password hashing can be passed to the `@apostrophecms/user` module via the `scrypt` option. See the [Node.js documentation for `scrypt`]. Note that the `maxmem` parameter is computed automatically based on the other parameters.
35
+
36
+ ## 4.1.1 (2024-03-21)
37
+
38
+ ### Fixes
39
+
40
+ * Hotfix for a bug that broke the rich text editor when the rich text widget has
41
+ a `styles` property. The bug was introduced in 4.0.0 as an indirect side effect of deeper
42
+ watching behavior by Vue 3.
43
+
3
44
  ## 4.1.0 (2024-03-20)
4
45
 
5
46
  ### Fixes
@@ -21,7 +62,7 @@ actually exists before calling `attachment.url` still lies with the developer.
21
62
  ## 4.0.0 (2024-03-12)
22
63
 
23
64
  ### Adds
24
-
65
+ * Add Marks tool to the Rich Text widget for handling toggling marks.
25
66
  * Add translation keys used by the multisite assembly module.
26
67
  * Add side by side comparison support in AposSchema component.
27
68
  * Add `beforeLocalize` and `afterLocalize` events.
@@ -1,4 +1,4 @@
1
- const mongo = require('mongodb');
1
+ const mongo = require('@apostrophecms/emulate-mongo-3-driver');
2
2
  const dns = require('dns');
3
3
 
4
4
  // Connect to MongoDB, using the modern topology and parser, and
@@ -70,6 +70,7 @@
70
70
  :icon="item.options.icon"
71
71
  :icon-only="true"
72
72
  :label="item.label"
73
+ :action="item.action"
73
74
  :state="trayItemState[item.name] ? [ 'active' ] : []"
74
75
  @click="emitEvent(item.action)"
75
76
  />
@@ -383,6 +383,10 @@ export default {
383
383
  mode = mode || this.draftMode;
384
384
  locale = locale || apos.i18n.locale;
385
385
  doc = doc || this.context;
386
+ if (!doc) {
387
+ return;
388
+ }
389
+
386
390
  if ((mode === this.draftMode) && (locale === apos.i18n.locale)) {
387
391
  if ((this.context._id === doc._id) && (!this.urlDiffers(doc._url))) {
388
392
  return;
@@ -545,6 +549,7 @@ export default {
545
549
 
546
550
  if (this.urlDiffers(doc._url)) {
547
551
  // Slug changed, change browser URL to reflect the actual url of the doc
552
+ doc._url = doc._url + (window.location.search || '');
548
553
  history.replaceState(null, '', doc._url);
549
554
  }
550
555
 
@@ -557,17 +562,17 @@ export default {
557
562
  } : {})
558
563
  };
559
564
 
560
- const content = await apos.http.get(doc._url, {
561
- qs,
562
- headers: {
563
- 'Cache-Control': 'no-cache'
564
- },
565
- draft: true,
566
- busy: true,
567
- prefix: false
568
- });
569
-
570
- refreshable.innerHTML = content;
565
+ if (doc._url) {
566
+ refreshable.innerHTML = await apos.http.get(doc._url, {
567
+ qs,
568
+ headers: {
569
+ 'Cache-Control': 'no-cache'
570
+ },
571
+ draft: true,
572
+ busy: true,
573
+ prefix: false
574
+ });
575
+ }
571
576
 
572
577
  if (this.editMode && (!this.original)) {
573
578
  // the first time we enter edit mode on the page, we need to
@@ -691,13 +696,14 @@ export default {
691
696
  }
692
697
  },
693
698
  urlDiffers(url) {
694
- // URL might or might not include hostname part
695
- url = url.replace(/^https?:\/\/.*?\//, '/');
696
- if (url === (window.location.pathname + (window.location.search || ''))) {
699
+ if (!url) {
697
700
  return false;
698
- } else {
699
- return true;
700
701
  }
702
+
703
+ const normalizedUrl = url.replace(/^https?:\/\/[^/]+\//, '/');
704
+ const currentPageUrl = window.location.pathname + window.location.search;
705
+
706
+ return normalizedUrl !== currentPageUrl;
701
707
  },
702
708
  lockNotAvailable() {
703
709
  if (this.contextStack.length) {
@@ -622,7 +622,7 @@ module.exports = {
622
622
  widgetIsContextual[name] = manager.options.contextual;
623
623
  widgetHasPlaceholder[name] = manager.options.placeholder;
624
624
  widgetHasInitialModal[name] = !manager.options.placeholder && manager.options.initialModal !== false;
625
- contextualWidgetDefaultData[name] = manager.options.defaultData;
625
+ contextualWidgetDefaultData[name] = manager.options.defaultData || {};
626
626
  });
627
627
 
628
628
  return {
@@ -429,7 +429,9 @@ export default {
429
429
  },
430
430
  async update(widget) {
431
431
  widget.aposPlaceholder = false;
432
-
432
+ if (!widget.metaType) {
433
+ widget.metaType = 'widget';
434
+ }
433
435
  if (this.docId === window.apos.adminBar.contextId) {
434
436
  apos.bus.$emit('context-edited', {
435
437
  [`@${widget._id}`]: widget
@@ -513,6 +515,9 @@ export default {
513
515
  if (!widget._id) {
514
516
  widget._id = cuid();
515
517
  }
518
+ if (!widget.metaType) {
519
+ widget.metaType = 'widget';
520
+ }
516
521
  const push = {
517
522
  $each: [ widget ]
518
523
  };
@@ -96,12 +96,6 @@ module.exports = {
96
96
  self.connectionReused = true;
97
97
  return;
98
98
  }
99
- let Logger;
100
- if (process.env.APOS_MONGODB_LOG_LEVEL) {
101
- Logger = require('mongodb').Logger;
102
- // Set debug level
103
- Logger.setLevel(process.env.APOS_MONGODB_LOG_LEVEL);
104
- }
105
99
  let uri = 'mongodb://';
106
100
  if (process.env.APOS_MONGODB_URI) {
107
101
  uri = process.env.APOS_MONGODB_URI;
@@ -37,8 +37,7 @@ module.exports = {
37
37
  self.apos.isNew = await self.detectNew();
38
38
  await self.createIndexes();
39
39
  self.addLegacyMigrations();
40
- self.addCacheFieldMigration();
41
- self.addSetPreviousDocsAposModeMigration();
40
+ self.addMigrations();
42
41
  },
43
42
  restApiRoutes(self) {
44
43
  return {
@@ -120,10 +119,23 @@ module.exports = {
120
119
  '@apostrophecms/doc-type:beforeInsert': {
121
120
  setLocaleAndMode(req, doc, options) {
122
121
  const manager = self.getManager(doc.type);
123
- if (manager.isLocalized()) {
124
- doc.aposLocale = doc.aposLocale || `${req.locale}:${req.mode}`;
125
- doc.aposMode = req.mode;
122
+ if (!manager.isLocalized()) {
123
+ return;
124
+ }
125
+
126
+ if (doc._id) {
127
+ const [ _id, locale, mode ] = doc._id.split(':');
128
+ doc.aposLocale = `${locale}:${mode}`;
129
+ doc.aposMode = mode;
130
+ return;
126
131
  }
132
+
133
+ const [ locale, mode ] = doc.aposLocale
134
+ ? doc.aposLocale.split(':')
135
+ : [ req.locale, req.mode ];
136
+
137
+ doc.aposLocale = `${locale}:${mode}`;
138
+ doc.aposMode = mode;
127
139
  },
128
140
  testPermissionsAndAddIdAndCreatedAt(req, doc, options) {
129
141
  self.testInsertPermissions(req, doc, options);
@@ -1751,38 +1763,14 @@ module.exports = {
1751
1763
  }
1752
1764
  }
1753
1765
  },
1754
- // Add the "cacheInvalidatedAt" field to the documents that do not have it yet,
1755
- // and set it to equal doc.updatedAt.
1756
- setCacheField() {
1757
- return self.apos.migration.eachDoc({ cacheInvalidatedAt: { $exists: 0 } }, 5, async doc => {
1758
- await self.apos.doc.db.updateOne({ _id: doc._id }, {
1759
- $set: { cacheInvalidatedAt: doc.updatedAt }
1760
- });
1761
- });
1762
- },
1763
- addCacheFieldMigration() {
1764
- self.apos.migration.add('add-cache-invalidated-at-field', self.setCacheField);
1765
- },
1766
-
1767
- async addSetPreviousDocsAposModeMigration () {
1768
- self.apos.migration.add('set-previous-docs-apos-mode', async () => {
1769
- await self.apos.doc.db.updateMany({
1770
- _id: { $regex: ':previous$' },
1771
- aposMode: { $ne: 'previous' }
1772
- }, {
1773
- $set: {
1774
- aposMode: 'previous'
1775
- }
1776
- });
1777
- });
1778
- },
1779
1766
 
1780
1767
  async bestAposDocId(criteria) {
1781
1768
  const existing = await self.apos.doc.db.findOne(criteria, { projection: { aposDocId: 1 } });
1782
1769
  return existing?.aposDocId || self.apos.util.generateId();
1783
1770
  },
1784
1771
 
1785
- ...require('./lib/legacy-migrations')(self)
1772
+ ...require('./lib/legacy-migrations')(self),
1773
+ ...require('./lib/migrations')(self)
1786
1774
  };
1787
1775
  }
1788
1776
  };
@@ -0,0 +1,59 @@
1
+ module.exports = (self) => {
2
+ return {
3
+ addMigrations() {
4
+ self.addCacheFieldMigration();
5
+ self.addSetPreviousDocsAposModeMigration();
6
+ self.addSetDocumentModesMigration();
7
+ },
8
+
9
+ addCacheFieldMigration() {
10
+ self.apos.migration.add('add-cache-invalidated-at-field', self.setCacheField);
11
+ },
12
+
13
+ async addSetPreviousDocsAposModeMigration () {
14
+ self.apos.migration.add('set-previous-docs-apos-mode', async () => {
15
+ await self.apos.doc.db.updateMany({
16
+ _id: { $regex: ':previous$' },
17
+ aposMode: { $ne: 'previous' }
18
+ }, {
19
+ $set: {
20
+ aposMode: 'previous'
21
+ }
22
+ });
23
+ });
24
+ },
25
+
26
+ addSetDocumentModesMigration() {
27
+ self.apos.migration.add('set-document-modes', async () => {
28
+ return self.apos.migration.eachDoc({}, 5, async (doc) => {
29
+ const manager = self.getManager(doc.type);
30
+ if (!manager.isLocalized()) {
31
+ return;
32
+ }
33
+ const idMode = doc._id.split(':').pop(); ;
34
+ const [ locale, localeMode ] = doc.aposLocale.split(':');
35
+ const aposMode = doc.aposMode;
36
+
37
+ if (idMode !== localeMode || idMode !== aposMode) {
38
+ await self.apos.doc.db.updateOne({ _id: doc._id }, {
39
+ $set: {
40
+ aposLocale: `${locale}:${idMode}`,
41
+ aposMode: idMode
42
+ }
43
+ });
44
+ }
45
+ });
46
+ });
47
+ },
48
+
49
+ // Add the "cacheInvalidatedAt" field to the documents that do not have it yet,
50
+ // and set it to equal doc.updatedAt.
51
+ setCacheField() {
52
+ return self.apos.migration.eachDoc({ cacheInvalidatedAt: { $exists: 0 } }, 5, async doc => {
53
+ await self.apos.doc.db.updateOne({ _id: doc._id }, {
54
+ $set: { cacheInvalidatedAt: doc.updatedAt }
55
+ });
56
+ });
57
+ }
58
+ };
59
+ };
@@ -2703,8 +2703,11 @@ module.exports = {
2703
2703
  subquery.limit(undefined);
2704
2704
  subquery.page(undefined);
2705
2705
  subquery.perPage(undefined);
2706
- const mongo = await subquery.toMongo();
2707
- const count = await mongo.count();
2706
+ await subquery.finalize();
2707
+ const count = await self.apos.doc.db.countDocuments({
2708
+ ...subquery.get('criteria'),
2709
+ ...(subquery.get('lateCriteria') || {})
2710
+ });
2708
2711
  if (query.get('perPage')) {
2709
2712
  const perPage = query.get('perPage');
2710
2713
  const totalPages = Math.ceil(count / perPage);
@@ -554,12 +554,13 @@ module.exports = {
554
554
  }
555
555
  if (!sessionOptions.store.name) {
556
556
  // require from this module's dependencies
557
- Store = require('connect-mongo')(expressSession);
557
+ const MongoStore = require('connect-mongo');
558
+ sessionOptions.store = MongoStore.create(sessionOptions.store.options);
558
559
  } else {
559
560
  // require from project's dependencies
560
561
  Store = self.apos.root.require(sessionOptions.store.name)(expressSession);
562
+ sessionOptions.store = new Store(sessionOptions.store.options);
561
563
  }
562
- sessionOptions.store = new Store(sessionOptions.store.options);
563
564
  }
564
565
  // Exported for the benefit of code that needs to
565
566
  // interoperate in a compatible way with express-sessions
@@ -339,13 +339,17 @@
339
339
  "richTextHorizontalRule": "Horizontale Linie",
340
340
  "richTextItalic": "Kursiv",
341
341
  "richTextLink": "Link",
342
+ "richTextMarkApplyStyles": "Stil anwenden",
343
+ "richTextMarkMultipleStyles": "Mehrere stile...",
344
+ "richTextMarkStyles": "Inline Stile",
345
+ "richTextNodeStyles": "Block Stile",
346
+ "richTextNodeMultipleStyles": "Mehrere blocks...",
342
347
  "richTextOrderedList": "Nummerierte Liste",
343
348
  "richTextParagraph": "Paragraph",
344
349
  "richTextPlaceholder": "Beginne dein Text hier...",
345
350
  "richTextRedo": "Wiederholen",
346
351
  "richTextStrikethrough": "Durchgestrichen",
347
352
  "richTextStyleConfigWarning": "Falsche Konfiguration des Text-Stiles: {{ label }}, {{ tag }}",
348
- "richTextStyles": "Stile",
349
353
  "richTextUnderline": "Unterstrichen",
350
354
  "richTextUndo": "Rückgängig",
351
355
  "safeModeActive": "Sicherer Modus aktiv, HTML-Code wird nicht gerendert.",
@@ -398,6 +398,11 @@
398
398
  "richTextInsertMenuHeading": "Insert element...",
399
399
  "richTextItalic": "Italic",
400
400
  "richTextLink": "Link",
401
+ "richTextMarkApplyStyles": "Apply Styles",
402
+ "richTextMarkMultipleStyles": "Multiple Styles...",
403
+ "richTextMarkStyles": "Inline Styles",
404
+ "richTextNodeStyles": "Block Styles",
405
+ "richTextNodeMultipleStyles": "Multiple Blocks...",
401
406
  "richTextOrderedList": "Ordered List",
402
407
  "richTextParagraph": "Paragraph (P)",
403
408
  "richTextPlaceholder": "Start Typing Here...",
@@ -405,7 +410,6 @@
405
410
  "richTextRedo": "Redo",
406
411
  "richTextStrikethrough": "Strike",
407
412
  "richTextStyleConfigWarning": "Misconfigured rich text style: label: {{ label }}, {{ tag }}",
408
- "richTextStyles": "Styles",
409
413
  "richTextUnderline": "Underline",
410
414
  "richTextUndo": "Undo",
411
415
  "safeModeActive": "Running in safe mode, not showing raw HTML.",
@@ -324,13 +324,17 @@
324
324
  "richTextHorizontalRule": "Regla Horizontal",
325
325
  "richTextItalic": "Cursiva",
326
326
  "richTextLink": "Liga",
327
+ "richTextMarkApplyStyles": "Aplicar estilo",
328
+ "richTextMarkMultipleStyles": "Estilo múltiple...",
329
+ "richTextMarkStyles": "Estilos en línea",
330
+ "richTextNodeStyles": "Estilos en bloque",
331
+ "richTextNodeMultipleStyles": "Bloque múltiple...",
327
332
  "richTextOrderedList": "Lista Ordenada",
328
333
  "richTextParagraph": "Párrafo (P)",
329
334
  "richTextPlaceholder": "Comience a escribir aquí...",
330
335
  "richTextRedo": "Rehacer",
331
336
  "richTextStrikethrough": "Tachar",
332
337
  "richTextStyleConfigWarning": "Estilo de texto enriquecido mal configurado: etiqueta: {{ label }}, {{ tag }}",
333
- "richTextStyles": "Estilos",
334
338
  "richTextUnderline": "Subrayar",
335
339
  "richTextUndo": "Deshacer",
336
340
  "safeModeActive": "Trabajando en modo seguro, HTML sin procesar no aparece.",
@@ -332,13 +332,17 @@
332
332
  "richTextHorizontalRule": "Règle Horizontale",
333
333
  "richTextItalic": "Italique",
334
334
  "richTextLink": "Lien",
335
+ "richTextMarkApplyStyles": "Appliquer le style",
336
+ "richTextMarkMultipleStyles": "Plusieurs styles...",
337
+ "richTextMarkStyles": "Styles de ligne",
338
+ "richTextNodeStyles": "Styles de bloc",
339
+ "richTextNodeMultipleStyles": "Plusieurs blocs...",
335
340
  "richTextOrderedList": "Liste numérotée",
336
341
  "richTextParagraph": "Paragraphe (P)",
337
342
  "richTextPlaceholder": "Commencez à écrire ici...",
338
343
  "richTextRedo": "Refaire",
339
344
  "richTextStrikethrough": "Barrer",
340
345
  "richTextStyleConfigWarning": "Style du Texte Riche mal configuré : label : {{ label }}, {{ tag }}",
341
- "richTextStyles": "Styles",
342
346
  "richTextUnderline": "Souligner",
343
347
  "richTextUndo": "Annuler",
344
348
  "safeModeActive": "Fonctionne en mode sans échec, n'affiche pas le code HTML brut.",
@@ -384,6 +384,11 @@
384
384
  "richTextInsertMenuHeading": "Inserisci elemento...",
385
385
  "richTextItalic": "Corsivo",
386
386
  "richTextLink": "Link",
387
+ "richTextMarkApplyStyles": "Applicare lo stile",
388
+ "richTextMarkMultipleStyles": "Stile multiplo...",
389
+ "richTextMarkStyles": "Stili in linea",
390
+ "richTextNodeStyles": "Stili di blocco",
391
+ "richTextNodeMultipleStyles": "Blocco multiplo...",
387
392
  "richTextOrderedList": "Lista ordinata",
388
393
  "richTextParagraph": "Paragrafo (P)",
389
394
  "richTextPlaceholder": "Inizia a scrivere qui...",
@@ -391,7 +396,6 @@
391
396
  "richTextRedo": "Ricomincia",
392
397
  "richTextStrikethrough": "Barrato",
393
398
  "richTextStyleConfigWarning": "Stile del rich-text configurato in modo errato: etichetta: {{ label }}, {{ tag }}",
394
- "richTextStyles": "Stili",
395
399
  "richTextUnderline": "Sottolinea",
396
400
  "richTextUndo": "Annulla",
397
401
  "safeModeActive": "Esecuzione in modalità sicura, non visualizzando l'HTML grezzo.",
@@ -321,13 +321,17 @@
321
321
  "richTextHorizontalRule": "Regra Horizontal",
322
322
  "richTextItalic": "Itálico",
323
323
  "richTextLink": "Link",
324
+ "richTextMarkApplyStyles": "Aplicar estilo",
325
+ "richTextMarkMultipleStyles": "Estilo múltiplo...",
326
+ "richTextMarkStyles": "Estilos incorporado",
327
+ "richTextNodeStyles": "Estilos de bloco",
328
+ "richTextNodeMultipleStyles": "Bloco múltiplo...",
324
329
  "richTextOrderedList": "Lista Ordenada",
325
330
  "richTextParagraph": "Parágrafo (P)",
326
331
  "richTextPlaceholder": "Comece a digitar aqui...",
327
332
  "richTextRedo": "Refazer",
328
333
  "richTextStrikethrough": "Tachar",
329
334
  "richTextStyleConfigWarning": "Estilo do editor desconfigurado: etiqueta: {{ label }}, {{ tag }}",
330
- "richTextStyles": "Estilos",
331
335
  "richTextUnderline": "Sublinhar",
332
336
  "richTextUndo": "Desfazer",
333
337
  "safeModeActive": "Executando em modo de segurança, não mostrando HTML puro.",
@@ -336,13 +336,17 @@
336
336
  "richTextHorizontalRule": "Horizontálne pravítko",
337
337
  "richTextItalic": "Kurzíva",
338
338
  "richTextLink": "Link",
339
+ "richTextMarkApplyStyles": "Aplikovať štýl",
340
+ "richTextMarkMultipleStyles": "Viacnásobný štýl...",
341
+ "richTextMarkStyles": "Inline štýly",
342
+ "richTextNodeStyles": "Blokový štýly",
343
+ "richTextNodeMultipleStyles": "Viacnásobný Blokový...",
339
344
  "richTextOrderedList": "Číslovaný zoznam",
340
345
  "richTextParagraph": "Odstavec (P)",
341
346
  "richTextPlaceholder": "Začnite písať tu...",
342
347
  "richTextRedo": "Prerobiť",
343
348
  "richTextStrikethrough": "Preškrtnúť ",
344
349
  "richTextStyleConfigWarning": "Nesprávne nakonfigurovaný štýl: popiska: {{ label }}, {{ tag }}",
345
- "richTextStyles": "Štýly",
346
350
  "richTextUnderline": "Podčiarknúť",
347
351
  "richTextUndo": "Vrátiť späť",
348
352
  "safeModeActive": "Beží v núdzovom režime, nezobrazuje sa zdrojový HTML.",
@@ -309,7 +309,7 @@ module.exports = {
309
309
  // Remove locale prefix so URL parsing can proceed normally from here
310
310
  if (req.path === localeOptions.prefix) {
311
311
  // Add / for home page
312
- return res.redirect(`${req.url}/`);
312
+ req.redirect = `${req.url}/`;
313
313
  }
314
314
  if (req.path.substring(0, localeOptions.prefix.length + 1) === localeOptions.prefix + '/') {
315
315
  req.path = req.path.replace(localeOptions.prefix, '');
@@ -115,6 +115,11 @@ module.exports = {
115
115
  // https://groups.google.com/forum/#!topic/mongodb-user/AFC1ia7MHzk
116
116
  const cursor = collection.find(criteria);
117
117
  cursor.sort({ _id: 1 });
118
+ // TODO use a variant of the code below instead
119
+ // cursor.batchSize(limit);
120
+ // for await (const docs of cursor) {
121
+ // // await iterator(docs);
122
+ // }
118
123
  return require('util').promisify(broadband)(cursor, limit, async function (doc, cb) {
119
124
  try {
120
125
  await iterator(doc);
@@ -58,8 +58,8 @@ function onTopOf(el1, el2) {
58
58
  if (el2 === document) {
59
59
  return true;
60
60
  }
61
- const index1 = apos.modal.stack.findIndex(modal => modal.$el === el1);
62
- const index2 = apos.modal.stack.findIndex(modal => modal.$el === el2);
61
+ const index1 = apos.modal.stack.findIndex(modal => modal.modalEl === el1);
62
+ const index2 = apos.modal.stack.findIndex(modal => modal.modalEl === el2);
63
63
  if (index1 === -1) {
64
64
  throw new Error('apos.modal.onTopOf: el1 is not in the modal stack');
65
65
  }