ghost 5.35.0 → 5.36.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 (154) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.36.0.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.36.0.tgz +0 -0
  3. package/components/{tryghost-adapter-manager-5.35.0.tgz → tryghost-adapter-manager-5.36.0.tgz} +0 -0
  4. package/components/tryghost-api-framework-5.36.0.tgz +0 -0
  5. package/components/tryghost-api-version-compatibility-service-5.36.0.tgz +0 -0
  6. package/components/{tryghost-audience-feedback-5.35.0.tgz → tryghost-audience-feedback-5.36.0.tgz} +0 -0
  7. package/components/tryghost-bootstrap-socket-5.36.0.tgz +0 -0
  8. package/components/{tryghost-constants-5.35.0.tgz → tryghost-constants-5.36.0.tgz} +0 -0
  9. package/components/tryghost-custom-theme-settings-service-5.36.0.tgz +0 -0
  10. package/components/tryghost-data-generator-5.36.0.tgz +0 -0
  11. package/components/{tryghost-domain-events-5.35.0.tgz → tryghost-domain-events-5.36.0.tgz} +0 -0
  12. package/components/tryghost-dynamic-routing-events-5.36.0.tgz +0 -0
  13. package/components/tryghost-email-analytics-provider-mailgun-5.36.0.tgz +0 -0
  14. package/components/tryghost-email-analytics-service-5.36.0.tgz +0 -0
  15. package/components/{tryghost-email-content-generator-5.35.0.tgz → tryghost-email-content-generator-5.36.0.tgz} +0 -0
  16. package/components/{tryghost-email-events-5.35.0.tgz → tryghost-email-events-5.36.0.tgz} +0 -0
  17. package/components/tryghost-email-service-5.36.0.tgz +0 -0
  18. package/components/{tryghost-email-suppression-list-5.35.0.tgz → tryghost-email-suppression-list-5.36.0.tgz} +0 -0
  19. package/components/tryghost-event-aware-cache-wrapper-5.36.0.tgz +0 -0
  20. package/components/{tryghost-express-dynamic-redirects-5.35.0.tgz → tryghost-express-dynamic-redirects-5.36.0.tgz} +0 -0
  21. package/components/tryghost-extract-api-key-5.36.0.tgz +0 -0
  22. package/components/{tryghost-html-to-plaintext-5.35.0.tgz → tryghost-html-to-plaintext-5.36.0.tgz} +0 -0
  23. package/components/tryghost-i18n-5.36.0.tgz +0 -0
  24. package/components/tryghost-importer-revue-5.36.0.tgz +0 -0
  25. package/components/tryghost-job-manager-5.36.0.tgz +0 -0
  26. package/components/{tryghost-link-redirects-5.35.0.tgz → tryghost-link-redirects-5.36.0.tgz} +0 -0
  27. package/components/{tryghost-link-replacer-5.35.0.tgz → tryghost-link-replacer-5.36.0.tgz} +0 -0
  28. package/components/tryghost-link-tracking-5.36.0.tgz +0 -0
  29. package/components/{tryghost-magic-link-5.35.0.tgz → tryghost-magic-link-5.36.0.tgz} +0 -0
  30. package/components/tryghost-mailgun-client-5.36.0.tgz +0 -0
  31. package/components/{tryghost-member-attribution-5.35.0.tgz → tryghost-member-attribution-5.36.0.tgz} +0 -0
  32. package/components/{tryghost-member-events-5.35.0.tgz → tryghost-member-events-5.36.0.tgz} +0 -0
  33. package/components/tryghost-members-api-5.36.0.tgz +0 -0
  34. package/components/{tryghost-members-csv-5.35.0.tgz → tryghost-members-csv-5.36.0.tgz} +0 -0
  35. package/components/{tryghost-members-events-service-5.35.0.tgz → tryghost-members-events-service-5.36.0.tgz} +0 -0
  36. package/components/tryghost-members-importer-5.36.0.tgz +0 -0
  37. package/components/{tryghost-members-offers-5.35.0.tgz → tryghost-members-offers-5.36.0.tgz} +0 -0
  38. package/components/{tryghost-members-payments-5.35.0.tgz → tryghost-members-payments-5.36.0.tgz} +0 -0
  39. package/components/{tryghost-members-ssr-5.35.0.tgz → tryghost-members-ssr-5.36.0.tgz} +0 -0
  40. package/components/tryghost-members-stripe-service-5.36.0.tgz +0 -0
  41. package/components/tryghost-milestones-5.36.0.tgz +0 -0
  42. package/components/tryghost-minifier-5.36.0.tgz +0 -0
  43. package/components/tryghost-mw-api-version-mismatch-5.36.0.tgz +0 -0
  44. package/components/{tryghost-mw-cache-control-5.35.0.tgz → tryghost-mw-cache-control-5.36.0.tgz} +0 -0
  45. package/components/tryghost-mw-error-handler-5.36.0.tgz +0 -0
  46. package/components/tryghost-mw-session-from-token-5.36.0.tgz +0 -0
  47. package/components/{tryghost-mw-update-user-last-seen-5.35.0.tgz → tryghost-mw-update-user-last-seen-5.36.0.tgz} +0 -0
  48. package/components/tryghost-mw-vhost-5.36.0.tgz +0 -0
  49. package/components/tryghost-oembed-service-5.36.0.tgz +0 -0
  50. package/components/tryghost-package-json-5.36.0.tgz +0 -0
  51. package/components/tryghost-referrers-5.36.0.tgz +0 -0
  52. package/components/tryghost-security-5.36.0.tgz +0 -0
  53. package/components/tryghost-session-service-5.36.0.tgz +0 -0
  54. package/components/tryghost-settings-path-manager-5.36.0.tgz +0 -0
  55. package/components/tryghost-slack-notifications-5.36.0.tgz +0 -0
  56. package/components/tryghost-staff-service-5.36.0.tgz +0 -0
  57. package/components/tryghost-stats-service-5.36.0.tgz +0 -0
  58. package/components/tryghost-tiers-5.36.0.tgz +0 -0
  59. package/components/tryghost-update-check-service-5.36.0.tgz +0 -0
  60. package/components/tryghost-verification-trigger-5.36.0.tgz +0 -0
  61. package/components/{tryghost-version-notifications-data-service-5.35.0.tgz → tryghost-version-notifications-data-service-5.36.0.tgz} +0 -0
  62. package/components/tryghost-webmentions-5.36.0.tgz +0 -0
  63. package/core/built/admin/assets/{chunk.143.d49ad252968f2ef3966d.js → chunk.143.d5eaed4616c55cdbdabb.js} +6 -6
  64. package/core/built/admin/assets/{chunk.178.3d45fff87e08a5be5eb8.js → chunk.178.8cafcc33fe672738cc5b.js} +4 -4
  65. package/core/built/admin/assets/{chunk.502.c4afca88c98edad8b268.js → chunk.502.800e1515996bcc900013.js} +3 -3
  66. package/core/built/admin/assets/{chunk.79.ec143a398298020c87e6.js → chunk.79.53e8aa9671b2d5dae8ba.js} +1 -1
  67. package/core/built/admin/assets/codemirror/{codemirror-6c43f4894cbd8db73d7f35cde836c58e.js → codemirror-3f3b9966a7237652dd31484694e38ad5.js} +1 -1
  68. package/core/built/admin/assets/ghost-7ecf5c7934d90798485ee5ac2956f7fe.css +1 -0
  69. package/core/built/admin/assets/{ghost-4a6ed62455c9e367434183980b3ca3e9.js → ghost-b828e9e3c161aae92909c2e163656bb1.js} +295 -267
  70. package/core/built/admin/assets/ghost-dark-e50717df8e57d3e7fee67a0bcea895ad.css +1 -0
  71. package/core/built/admin/assets/img/mentions-background-fa39b7597e875c165b12190eda606993.png +0 -0
  72. package/core/built/admin/assets/simplemde/{simplemde-28049a9bd7f432b0648747eb26958a33.js → simplemde-9cd5549b68db674742d6ec2ecd72ac30.js} +1 -1
  73. package/core/built/admin/assets/vendor-c4684647d4f5213e5dbb6763de430e7e.js +22 -21
  74. package/core/built/admin/index.html +5 -5
  75. package/core/server/adapters/cache/MemoryTTL.js +3 -0
  76. package/core/server/api/endpoints/emails.js +35 -0
  77. package/core/server/api/endpoints/pages-public.js +1 -2
  78. package/core/server/api/endpoints/posts-public.js +2 -1
  79. package/core/server/api/endpoints/tags-public.js +2 -1
  80. package/core/server/api/endpoints/utils/serializers/input/index.js +4 -0
  81. package/core/server/api/endpoints/utils/serializers/input/mentions.js +11 -0
  82. package/core/server/api/endpoints/utils/serializers/output/emails.js +4 -0
  83. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +2 -5
  84. package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +1 -0
  85. package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +19 -11
  86. package/core/server/data/exporter/table-lists.js +2 -1
  87. package/core/server/data/migrations/versions/5.36/2023-02-20-12-22-add-milestones-table.js +10 -0
  88. package/core/server/data/migrations/versions/5.36/2023-02-21-12-29-add-milestone-notifications-column.js +7 -0
  89. package/core/server/data/migrations/versions/5.36/2023-02-23-10-40-set-outbound-link-tagging-based-on-source-tracking.js +31 -0
  90. package/core/server/data/schema/schema.js +9 -0
  91. package/core/server/lib/request-external.js +14 -13
  92. package/core/server/models/milestone.js +9 -0
  93. package/core/server/models/user.js +4 -1
  94. package/core/server/services/email-analytics/lib/queries.js +18 -3
  95. package/core/server/services/email-analytics/wrapper.js +34 -15
  96. package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +2 -0
  97. package/core/server/services/mentions/BookshelfMentionRepository.js +2 -1
  98. package/core/server/services/mentions/ResourceService.js +6 -0
  99. package/core/server/services/mentions/RoutingService.js +2 -1
  100. package/core/server/services/mentions/service.js +1 -3
  101. package/core/server/services/milestones/BookshelfMilestoneRepository.js +136 -0
  102. package/core/server/services/milestones/MilestoneQueries.js +8 -3
  103. package/core/server/services/milestones/service.js +47 -9
  104. package/core/server/services/oembed/nft-oembed.js +1 -2
  105. package/core/server/services/posts-public/service.js +21 -9
  106. package/core/server/services/tags-public/service.js +21 -10
  107. package/core/server/services/websockets/service.js +2 -1
  108. package/core/server/web/api/endpoints/admin/routes.js +3 -0
  109. package/core/shared/config/defaults.json +5 -2
  110. package/core/shared/labs.js +5 -4
  111. package/package.json +125 -124
  112. package/yarn.lock +151 -199
  113. package/components/tryghost-adapter-cache-redis-5.35.0.tgz +0 -0
  114. package/components/tryghost-api-framework-5.35.0.tgz +0 -0
  115. package/components/tryghost-api-version-compatibility-service-5.35.0.tgz +0 -0
  116. package/components/tryghost-bootstrap-socket-5.35.0.tgz +0 -0
  117. package/components/tryghost-custom-theme-settings-service-5.35.0.tgz +0 -0
  118. package/components/tryghost-data-generator-5.35.0.tgz +0 -0
  119. package/components/tryghost-dynamic-routing-events-5.35.0.tgz +0 -0
  120. package/components/tryghost-email-analytics-provider-mailgun-5.35.0.tgz +0 -0
  121. package/components/tryghost-email-analytics-service-5.35.0.tgz +0 -0
  122. package/components/tryghost-email-service-5.35.0.tgz +0 -0
  123. package/components/tryghost-extract-api-key-5.35.0.tgz +0 -0
  124. package/components/tryghost-i18n-5.35.0.tgz +0 -0
  125. package/components/tryghost-importer-revue-5.35.0.tgz +0 -0
  126. package/components/tryghost-job-manager-5.35.0.tgz +0 -0
  127. package/components/tryghost-link-tracking-5.35.0.tgz +0 -0
  128. package/components/tryghost-mailgun-client-5.35.0.tgz +0 -0
  129. package/components/tryghost-members-api-5.35.0.tgz +0 -0
  130. package/components/tryghost-members-importer-5.35.0.tgz +0 -0
  131. package/components/tryghost-members-stripe-service-5.35.0.tgz +0 -0
  132. package/components/tryghost-milestones-5.35.0.tgz +0 -0
  133. package/components/tryghost-minifier-5.35.0.tgz +0 -0
  134. package/components/tryghost-mw-api-version-mismatch-5.35.0.tgz +0 -0
  135. package/components/tryghost-mw-error-handler-5.35.0.tgz +0 -0
  136. package/components/tryghost-mw-session-from-token-5.35.0.tgz +0 -0
  137. package/components/tryghost-mw-vhost-5.35.0.tgz +0 -0
  138. package/components/tryghost-oembed-service-5.35.0.tgz +0 -0
  139. package/components/tryghost-package-json-5.35.0.tgz +0 -0
  140. package/components/tryghost-public-resource-repository-5.35.0.tgz +0 -0
  141. package/components/tryghost-referrers-5.35.0.tgz +0 -0
  142. package/components/tryghost-security-5.35.0.tgz +0 -0
  143. package/components/tryghost-session-service-5.35.0.tgz +0 -0
  144. package/components/tryghost-settings-path-manager-5.35.0.tgz +0 -0
  145. package/components/tryghost-slack-notifications-5.35.0.tgz +0 -0
  146. package/components/tryghost-staff-service-5.35.0.tgz +0 -0
  147. package/components/tryghost-stats-service-5.35.0.tgz +0 -0
  148. package/components/tryghost-tiers-5.35.0.tgz +0 -0
  149. package/components/tryghost-update-check-service-5.35.0.tgz +0 -0
  150. package/components/tryghost-verification-trigger-5.35.0.tgz +0 -0
  151. package/components/tryghost-webmentions-5.35.0.tgz +0 -0
  152. package/core/built/admin/assets/ghost-558c1e319d6e025bfab2054bc0f7fe83.css +0 -1
  153. package/core/built/admin/assets/ghost-dark-a15754df1f9070dc2525482ce22e2251.css +0 -1
  154. /package/core/built/admin/assets/{chunk.502.c4afca88c98edad8b268.js.LICENSE.txt → chunk.502.800e1515996bcc900013.js.LICENSE.txt} +0 -0
@@ -1871,4 +1871,4 @@ return/editor-preview-active/.test(e.className)},Y.prototype.isSideBySideActive=
1871
1871
  return/editor-preview-active-side/.test(e.className)},Y.prototype.isFullscreenActive=function(){return this.codemirror.getOption("fullScreen")},Y.prototype.getState=function(){return m(this.codemirror)},Y.prototype.toTextArea=function(){var e=this.codemirror,t=e.getWrapperElement()
1872
1872
  t.parentNode&&(this.gui.toolbar&&t.parentNode.removeChild(this.gui.toolbar),this.gui.statusbar&&t.parentNode.removeChild(this.gui.statusbar),this.gui.sideBySide&&t.parentNode.removeChild(this.gui.sideBySide)),e.toTextArea(),this.autosaveTimeoutId&&(clearTimeout(this.autosaveTimeoutId),this.autosaveTimeoutId=void 0,this.clearAutosavedValue())},t.exports=Y},{"./codemirror/tablist":17,codemirror:10,"codemirror-spell-checker":4,"codemirror/addon/display/fullscreen.js":5,"codemirror/addon/display/placeholder.js":6,"codemirror/addon/edit/continuelist.js":7,"codemirror/addon/mode/overlay.js":8,"codemirror/addon/selection/mark-selection.js":9,"codemirror/mode/gfm/gfm.js":11,"codemirror/mode/markdown/markdown.js":12,"codemirror/mode/xml/xml.js":14}]},{},[18])(18)}))
1873
1873
 
1874
- //# sourceMappingURL=simplemde-28049a9bd7f432b0648747eb26958a33.map
1874
+ //# sourceMappingURL=simplemde-9cd5549b68db674742d6ec2ecd72ac30.map
@@ -9137,7 +9137,8 @@ a?.finish(),a=n({name:`route:${i}`,op:"navigation",tags:{fromRoute:r,toRoute:i,"
9137
9137
  t[e.object]=r}function c(e,t,i,o){const a=t[e.object]
9138
9138
  if(!a)return
9139
9139
  const s=(0,n.timestampWithMs)()
9140
- if(1e3*(s-a.now)>=o){(0,r.getActiveTransaction)()?.startChild({op:i,description:e.containerKey||e.object,startTimestamp:a.now,endTimestamp:s})}}function d(e){const t="@sentry/ember:initial-load-start",i="@sentry/ember:initial-load-end"
9140
+ if(1e3*(s-a.now)>=o){const t=(0,r.getActiveTransaction)()
9141
+ t?.startChild({op:i,description:e.containerKey||e.object,startTimestamp:a.now,endTimestamp:s})}}function d(e){const t="@sentry/ember:initial-load-start",i="@sentry/ember:initial-load-end"
9141
9142
  let{HAS_PERFORMANCE:o,HAS_PERFORMANCE_TIMING:a}=function(){const e=window.performance,t=Boolean(e&&e.clearMarks&&e.clearMeasures),r=Boolean(e.measure&&e.getEntriesByName&&void 0!==n.browserPerformanceTimeOrigin)
9142
9143
  return{HAS_PERFORMANCE:t,HAS_PERFORMANCE_TIMING:r}}()
9143
9144
  if(!o)return
@@ -9147,8 +9148,8 @@ if(!a)return
9147
9148
  const l="@sentry/ember:initial-load",u=s.getEntriesByName(t).length>0,c=s.getEntriesByName(i).length>0
9148
9149
  if(!u||!c)return
9149
9150
  s.measure(l,t,i)
9150
- const d=s.getEntriesByName(l)[0],h=(d.startTime+n.browserPerformanceTimeOrigin)/1e3,p=h+d.duration/1e3,f=(0,r.getActiveTransaction)()?.startChild({op:"ui.ember.init",startTimestamp:h})
9151
- f?.finish(p),s.clearMarks(t),s.clearMarks(i),s.clearMeasures(l)}async function h(e){const a=o(),h=a.sentry,p=a.browserTracingOptions||a.sentry.browserTracingOptions||{},f=await emberAutoImportDynamic("@sentry/tracing"),m=a.transitionTimeout||5e3,g=h.integrations||[]
9151
+ const d=s.getEntriesByName(l)[0],h=(d.startTime+n.browserPerformanceTimeOrigin)/1e3,p=h+d.duration/1e3,f=(0,r.getActiveTransaction)(),m=f?.startChild({op:"ui.ember.init",startTimestamp:h})
9152
+ m?.finish(p),s.clearMarks(t),s.clearMarks(i),s.clearMeasures(l)}async function h(e){const a=o(),h=a.sentry,p=a.browserTracingOptions||a.sentry.browserTracingOptions||{},f=await emberAutoImportDynamic("@sentry/tracing"),m=a.transitionTimeout||5e3,g=h.integrations||[]
9152
9153
  h.integrations=[...g,new f.Integrations.BrowserTracing({routingInstrumentation:(t,r)=>{const n=e.lookup("router:main")
9153
9154
  let i=e.lookup("service:router")
9154
9155
  i.externalRouter&&(i=i.externalRouter),i._hasMountedSentryPerformanceRouting||i.recognize&&(i._hasMountedSentryPerformanceRouting=!0,l(i,n,a,t,r))},idleTimeout:m,...p})]
@@ -12263,10 +12264,10 @@ Object.entries({loop:!1}).forEach((e=>{let[t,r]=e
12263
12264
  void 0===this.args.payload[t]&&this.updatePayloadAttr(t,r)}))}didInsert(e){this.element=e
12264
12265
  const{triggerBrowse:t,src:r,files:n}=this.args.payload
12265
12266
  delete this.args.payload.triggerBrowse,delete this.args.payload.files,!t||r||n||this.triggerAudioFileDialog(),n&&(this.files=n)}registerAudioFileInput(e){this._audioFileInput=e}registerAudioThumbnailFileInput(e){this._audioThumbnailFileInput=e}triggerAudioFileDialog(e){if(this._audioFileInput)return this._audioFileInput.click()
12266
- const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12267
- t&&t.click()}triggerThumbnailFileDialog(e){if(this._audioThumbnailFileInput)return this._audioThumbnailFileInput.click()
12268
- const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12269
- t&&t.click()}deleteThumbnail(){this.updatePayloadAttr("thumbnailSrc",null)}*extractAudioMetadataTask(e){return yield(0,r.default)(e)}async audioUploadStarted(e){const t=e[0]
12267
+ const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12268
+ r&&r.click()}triggerThumbnailFileDialog(e){if(this._audioThumbnailFileInput)return this._audioThumbnailFileInput.click()
12269
+ const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12270
+ r&&r.click()}deleteThumbnail(){this.updatePayloadAttr("thumbnailSrc",null)}*extractAudioMetadataTask(e){return yield(0,r.default)(e)}async audioUploadStarted(e){const t=e[0]
12270
12271
  if(t){const e=await this.extractAudioMetadataTask.perform(t)
12271
12272
  this.previewPayload.duration=e?.duration,this.previewPayload.mimeType=e?.mimeType}}getFormattedDuration(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:200
12272
12273
  const t=Math.floor(e/60),r=Math.floor(e-60*t)
@@ -12299,8 +12300,8 @@ window.addEventListener("resize",e),this.willDestroy=()=>{window.removeEventList
12299
12300
  n.addEventListener("load",(()=>{let e=this.selectingFile
12300
12301
  this.selectingFile=!1,t({id:e})})),n.src=r}))}uploadSuccess(e,t){let r=new Image
12301
12302
  r.addEventListener("load",(()=>{let n={src:e.url,width:r.naturalWidth,height:r.naturalHeight},i=`${t.id}Image`
12302
- this.args.payload[i]=n,this.updateImageDimensions()})),r.src=e.url}setLayoutWide(){this.args.payload.cardWidth="wide",Ember.run.scheduleOnce("afterRender",this,this.updateImageDimensions)}setLayoutFull(){this.args.payload.cardWidth="full",Ember.run.scheduleOnce("afterRender",this,this.updateImageDimensions)}setStartingPosition(e){this.args.payload.startingPosition=Math.min(100,Math.max(0,parseInt(e.target.value)))}selectBeforeImage(){this.selectingFile="before",this._triggerFileDialog()}selectAfterImage(){this.selectingFile="after",this._triggerFileDialog()}_triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12303
- t?.click()}uploadFailed(){}handleErrors(){}setCaption(e){this.args.payload.caption=e}leaveEditMode(){this.isEmpty&&Ember.run.scheduleOnce("afterRender",this,this.args.deleteCard)}},_=E(y.prototype,"imageWidth",[n],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),E(y.prototype,"preventDefault",[i],Object.getOwnPropertyDescriptor(y.prototype,"preventDefault"),y.prototype),E(y.prototype,"stopPropagation",[o],Object.getOwnPropertyDescriptor(y.prototype,"stopPropagation"),y.prototype),E(y.prototype,"removeFocus",[a],Object.getOwnPropertyDescriptor(y.prototype,"removeFocus"),y.prototype),E(y.prototype,"registerElement",[s],Object.getOwnPropertyDescriptor(y.prototype,"registerElement"),y.prototype),E(y.prototype,"uploadStart",[l],Object.getOwnPropertyDescriptor(y.prototype,"uploadStart"),y.prototype),E(y.prototype,"uploadSuccess",[u],Object.getOwnPropertyDescriptor(y.prototype,"uploadSuccess"),y.prototype),E(y.prototype,"setLayoutWide",[c],Object.getOwnPropertyDescriptor(y.prototype,"setLayoutWide"),y.prototype),E(y.prototype,"setLayoutFull",[d],Object.getOwnPropertyDescriptor(y.prototype,"setLayoutFull"),y.prototype),E(y.prototype,"setStartingPosition",[h],Object.getOwnPropertyDescriptor(y.prototype,"setStartingPosition"),y.prototype),E(y.prototype,"selectBeforeImage",[p],Object.getOwnPropertyDescriptor(y.prototype,"selectBeforeImage"),y.prototype),E(y.prototype,"selectAfterImage",[f],Object.getOwnPropertyDescriptor(y.prototype,"selectAfterImage"),y.prototype),E(y.prototype,"uploadFailed",[m],Object.getOwnPropertyDescriptor(y.prototype,"uploadFailed"),y.prototype),E(y.prototype,"handleErrors",[g],Object.getOwnPropertyDescriptor(y.prototype,"handleErrors"),y.prototype),E(y.prototype,"setCaption",[v],Object.getOwnPropertyDescriptor(y.prototype,"setCaption"),y.prototype),E(y.prototype,"leaveEditMode",[b],Object.getOwnPropertyDescriptor(y.prototype,"leaveEditMode"),y.prototype),y)
12303
+ this.args.payload[i]=n,this.updateImageDimensions()})),r.src=e.url}setLayoutWide(){this.args.payload.cardWidth="wide",Ember.run.scheduleOnce("afterRender",this,this.updateImageDimensions)}setLayoutFull(){this.args.payload.cardWidth="full",Ember.run.scheduleOnce("afterRender",this,this.updateImageDimensions)}setStartingPosition(e){this.args.payload.startingPosition=Math.min(100,Math.max(0,parseInt(e.target.value)))}selectBeforeImage(){this.selectingFile="before",this._triggerFileDialog()}selectAfterImage(){this.selectingFile="after",this._triggerFileDialog()}_triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12304
+ r?.click()}uploadFailed(){}handleErrors(){}setCaption(e){this.args.payload.caption=e}leaveEditMode(){this.isEmpty&&Ember.run.scheduleOnce("afterRender",this,this.args.deleteCard)}},_=E(y.prototype,"imageWidth",[n],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),E(y.prototype,"preventDefault",[i],Object.getOwnPropertyDescriptor(y.prototype,"preventDefault"),y.prototype),E(y.prototype,"stopPropagation",[o],Object.getOwnPropertyDescriptor(y.prototype,"stopPropagation"),y.prototype),E(y.prototype,"removeFocus",[a],Object.getOwnPropertyDescriptor(y.prototype,"removeFocus"),y.prototype),E(y.prototype,"registerElement",[s],Object.getOwnPropertyDescriptor(y.prototype,"registerElement"),y.prototype),E(y.prototype,"uploadStart",[l],Object.getOwnPropertyDescriptor(y.prototype,"uploadStart"),y.prototype),E(y.prototype,"uploadSuccess",[u],Object.getOwnPropertyDescriptor(y.prototype,"uploadSuccess"),y.prototype),E(y.prototype,"setLayoutWide",[c],Object.getOwnPropertyDescriptor(y.prototype,"setLayoutWide"),y.prototype),E(y.prototype,"setLayoutFull",[d],Object.getOwnPropertyDescriptor(y.prototype,"setLayoutFull"),y.prototype),E(y.prototype,"setStartingPosition",[h],Object.getOwnPropertyDescriptor(y.prototype,"setStartingPosition"),y.prototype),E(y.prototype,"selectBeforeImage",[p],Object.getOwnPropertyDescriptor(y.prototype,"selectBeforeImage"),y.prototype),E(y.prototype,"selectAfterImage",[f],Object.getOwnPropertyDescriptor(y.prototype,"selectAfterImage"),y.prototype),E(y.prototype,"uploadFailed",[m],Object.getOwnPropertyDescriptor(y.prototype,"uploadFailed"),y.prototype),E(y.prototype,"handleErrors",[g],Object.getOwnPropertyDescriptor(y.prototype,"handleErrors"),y.prototype),E(y.prototype,"setCaption",[v],Object.getOwnPropertyDescriptor(y.prototype,"setCaption"),y.prototype),E(y.prototype,"leaveEditMode",[b],Object.getOwnPropertyDescriptor(y.prototype,"leaveEditMode"),y.prototype),y)
12304
12305
  e.default=x,Ember._setComponentTemplate(w,x)})),define("koenig-editor/components/koenig-card-bookmark",["exports","koenig-editor/components/koenig-editor","@tryghost/helpers","ember-concurrency"],(function(e,t,r,n){"use strict"
12305
12306
  var i,o,a,s,l,u,c,d,h,p,f,m,g,v,b
12306
12307
  function y(e,t,r,n){r&&Object.defineProperty(e,t,{enumerable:r.enumerable,configurable:r.configurable,writable:r.writable,value:r.initializer?r.initializer.call(n):void 0})}function _(e,t,r){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e
@@ -12480,8 +12481,8 @@ Object.entries({loop:!1}).forEach((e=>{let[t,r]=e
12480
12481
  void 0===this.args.payload[t]&&this.updatePayloadAttr(t,r)}))}didInsert(e){this.element=e
12481
12482
  const{triggerBrowse:t,src:r,files:n}=this.args.payload
12482
12483
  delete this.args.payload.triggerBrowse,delete this.args.payload.files,!t||r||n||this.triggerFileDialog(),n&&(this.files=n)}triggerFileDialog(e){if(this._fileInput)return this._fileInput.click()
12483
- const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12484
- t?.click()}async fileUploadStarted(e){const t=e[0]
12484
+ const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12485
+ r?.click()}async fileUploadStarted(e){const t=e[0]
12485
12486
  t&&(this.previewPayload.fileSize=t.size)}async fileUploadCompleted(e){let[t]=e
12486
12487
  this.previewPayload.src=t.url,this.previewPayload.fileName=t.fileName,this.previewPayload.fileTitle=(0,r.default)(t.fileName),this.previewPayload.fileCaption="",this.args.editor.run((()=>{this.payloadFileAttrs.forEach((e=>{this.updatePayloadAttr(e,this.previewPayload[e])}))})),this.previewPayload=new n.TrackedObject({})}fileUploadFailed(){this.args.editor.run((()=>{this.payloadFileAttrs.forEach((e=>{this.updatePayloadAttr(e,null)}))}))}setFileTitle(e){this.updatePayloadAttr("fileTitle",e)}setFileCaption(e){this.updatePayloadAttr("fileCaption",e)}updatePayloadAttr(e,t){const{payload:r}=this.args
12487
12488
  Ember.set(r,e,t),this.args.saveCard(r,!1)}dragOver(e){e.dataTransfer&&(e.stopPropagation(),e.preventDefault(),this.isDraggedOver=!0)}dragLeave(e){e.preventDefault(),this.isDraggedOver=!1}drop(e){e.preventDefault(),e.stopPropagation(),this.isDraggedOver=!1,e.dataTransfer.files&&(this.files=[e.dataTransfer.files[0]])}_bytesToSize(e){if(!e)return"0 Byte"
@@ -12506,8 +12507,8 @@ r(i)&&(o+=1),e[o]?(i+1)%3==0||r(i+1)||i+1===t?(a.push("pl2"),s.push("ml2")):(a.p
12506
12507
  let l=Object.assign({},n),u=(n.width||1)/(n.height||1)
12507
12508
  l.style=Ember.String.htmlSafe(`flex: ${u} 1 0%`),l.classes=Ember.String.htmlSafe(a.join(" ")),l.overlayClasses=Ember.String.htmlSafe(s.join(" ")),e[o].push(l)})),e}init(){super.init(...arguments),this.payload&&!Ember.isEmpty(this.payload.images)||this._updatePayloadAttr("images",[]),this._buildImages(),this.registerComponent(this)}willDestroyElement(){super.willDestroyElement(...arguments),this._dragDropContainer&&this._dragDropContainer.destroy()}addImage(e){let t=this.images.length+1,r=Math.ceil(t/3)-1,n=this._readDataFromImageFile(e)
12508
12509
  n.row=r,this.images.pushObject(n)}setImageSrc(e){this.images.findBy("fileName",e.fileName).set("src",e.url),this._buildAndSaveImagesPayload()}setFiles(e){this._startUpload(e)}deleteImage(e){let t=this.images.findBy("fileName",e.fileName)
12509
- this.images.removeObject(t),this._recalculateImageRows(),this._buildAndSaveImagesPayload()}updateCaption(e){this._updatePayloadAttr("caption",e)}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12510
- t?.click()}uploadFailed(e){let t=this.images.findBy("fileName",e.fileName)
12510
+ this.images.removeObject(t),this._recalculateImageRows(),this._buildAndSaveImagesPayload()}updateCaption(e){this._updatePayloadAttr("caption",e)}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12511
+ r?.click()}uploadFailed(e){let t=this.images.findBy("fileName",e.fileName)
12511
12512
  this.images.removeObject(t),this._buildAndSaveImagesPayload()
12512
12513
  let r=e.fileName.length>20?`${e.fileName.substr(0,20)}...`:e.fileName
12513
12514
  this.set("errorMessage",`${r} failed to upload`)}handleErrors(e){let t=e[0]&&e[0].message||"Some images failed to upload"
@@ -12554,8 +12555,8 @@ Object.keys(t).forEach((r=>{e.registerKeyCommand({str:r,run:()=>t[r](e,r)})})),t
12554
12555
  Ember.set(r,e,t),this.args.saveCard?.(r,!1)}_afterRender(){this._placeCursorAtEnd(),this._focusInput()}_placeCursorAtEnd(){if(!this._textReplacementEditor)return
12555
12556
  let e=this._textReplacementEditor.post.tailPosition().toRange()
12556
12557
  this._textReplacementEditor.selectRange(e)}_focusInput(){let e=this.element.querySelector(".kg-header-card-header .koenig-basic-html-input__editor")
12557
- e&&e.focus()}toggleButton(){this._updatePayloadAttr("buttonEnabled",!this.args.payload.buttonEnabled)}setSize(e){["small","medium","large"].includes(e)&&this._updatePayloadAttr("size",e)}setStyle(e){["dark","light","accent","image"].includes(e)&&(this._updatePayloadAttr("style",e),"image"!==e||this.args.payload.backgroundImageSrc||this.triggerFileDialog())}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12558
- t&&t.click()}backgroundImageUploadCompleted(e){let[t]=e
12558
+ e&&e.focus()}toggleButton(){this._updatePayloadAttr("buttonEnabled",!this.args.payload.buttonEnabled)}setSize(e){["small","medium","large"].includes(e)&&this._updatePayloadAttr("size",e)}setStyle(e){["dark","light","accent","image"].includes(e)&&(this._updatePayloadAttr("style",e),"image"!==e||this.args.payload.backgroundImageSrc||this.triggerFileDialog())}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12559
+ r&&r.click()}backgroundImageUploadCompleted(e){let[t]=e
12559
12560
  this.args.editor.run((()=>{this._updatePayloadAttr("backgroundImageSrc",t.url)}))}deleteBackgroundImage(){this._updatePayloadAttr("backgroundImageSrc",null)}},O=R(x.prototype,"feature",[o],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),C=R(x.prototype,"store",[a],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),S=R(x.prototype,"membersUtils",[s],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),T=R(x.prototype,"ui",[l],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),P=R(x.prototype,"config",[i.inject],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),R(x.prototype,"registerElement",[u],Object.getOwnPropertyDescriptor(x.prototype,"registerElement"),x.prototype),R(x.prototype,"registerHeaderEditor",[c],Object.getOwnPropertyDescriptor(x.prototype,"registerHeaderEditor"),x.prototype),R(x.prototype,"registerSubheaderEditor",[d],Object.getOwnPropertyDescriptor(x.prototype,"registerSubheaderEditor"),x.prototype),R(x.prototype,"setHeader",[h],Object.getOwnPropertyDescriptor(x.prototype,"setHeader"),x.prototype),R(x.prototype,"setSubheader",[p],Object.getOwnPropertyDescriptor(x.prototype,"setSubheader"),x.prototype),R(x.prototype,"setButtonUrl",[f],Object.getOwnPropertyDescriptor(x.prototype,"setButtonUrl"),x.prototype),R(x.prototype,"setButtonText",[m],Object.getOwnPropertyDescriptor(x.prototype,"setButtonText"),x.prototype),R(x.prototype,"leaveEditMode",[g],Object.getOwnPropertyDescriptor(x.prototype,"leaveEditMode"),x.prototype),R(x.prototype,"focusElement",[v],Object.getOwnPropertyDescriptor(x.prototype,"focusElement"),x.prototype),R(x.prototype,"toggleButton",[b],Object.getOwnPropertyDescriptor(x.prototype,"toggleButton"),x.prototype),R(x.prototype,"setSize",[y],Object.getOwnPropertyDescriptor(x.prototype,"setSize"),x.prototype),R(x.prototype,"setStyle",[_],Object.getOwnPropertyDescriptor(x.prototype,"setStyle"),x.prototype),R(x.prototype,"triggerFileDialog",[k],Object.getOwnPropertyDescriptor(x.prototype,"triggerFileDialog"),x.prototype),R(x.prototype,"backgroundImageUploadCompleted",[E],Object.getOwnPropertyDescriptor(x.prototype,"backgroundImageUploadCompleted"),x.prototype),R(x.prototype,"deleteBackgroundImage",[w],Object.getOwnPropertyDescriptor(x.prototype,"deleteBackgroundImage"),x.prototype),x)
12560
12561
  e.default=D,Ember._setComponentTemplate(j,D)})),define("koenig-editor/components/koenig-card-hr",["exports","@glimmer/component"],(function(e,t){"use strict"
12561
12562
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -12594,8 +12595,8 @@ let e=["summer","mountains","ufo-attack"]
12594
12595
  this.set("placeholder",e[Math.floor(Math.random()*e.length)]),this.registerComponent(this)}didReceiveAttrs(){super.didReceiveAttrs(...arguments),Ember.isEmpty(this.payload.files)||Ember.run.schedule("afterRender",this,(function(){this.set("files",this.payload.files),delete this.payload.files})),this.isSelected||this.set("isEditingAlt",!1)}didInsertElement(){if(super.didInsertElement(...arguments),this.payload.triggerBrowse&&!this.payload.src&&!this.payload.files){this._updatePayloadAttr("triggerBrowse",void 0)
12595
12596
  let e=this.element.querySelector('input[type="file"]')
12596
12597
  e&&e.click()}this.imageSelector&&this.scrollToCard()}updateSrc(e){let[t]=e
12597
- this.editor.run((()=>{this._updatePayloadAttr("src",t.url),this._imageWidth&&this._imageHeight&&(this._updatePayloadAttr("width",this._imageWidth),this._updatePayloadAttr("height",this._imageHeight)),this._imageWidth=null,this._imageHeight=null}))}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12598
- t?.click()}setPreviewSrc(e){let t=e[0]
12598
+ this.editor.run((()=>{this._updatePayloadAttr("src",t.url),this._imageWidth&&this._imageHeight&&(this._updatePayloadAttr("width",this._imageWidth),this._updatePayloadAttr("height",this._imageHeight)),this._imageWidth=null,this._imageHeight=null}))}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12599
+ r?.click()}setPreviewSrc(e){let t=e[0]
12599
12600
  if(t){let e=URL.createObjectURL(t)
12600
12601
  this.set("previewSrc",e)
12601
12602
  let r=new Image
@@ -12689,8 +12690,8 @@ if(t){let e=URL.createObjectURL(t)
12689
12690
  this.previewSrc=e
12690
12691
  let r=new Image
12691
12692
  r.onload=()=>{this._productImageWidth=r.naturalWidth,this._productImageHeight=r.naturalHeight},r.src=e}}resetSrcs(){this.previewSrc=null,this._productImageWidth=null,this._productImageHeight=null,this.args.editor.run((()=>{this._updatePayloadAttr("productImageSrc",null),this._updatePayloadAttr("productImageWidth",null),this._updatePayloadAttr("productImageHeight",null)}))}updateSrc(e){let[t]=e
12692
- this.args.editor.run((()=>{this._updatePayloadAttr("productImageSrc",t.url),this._productImageWidth&&this._productImageHeight&&(this._updatePayloadAttr("productImageWidth",this._productImageWidth),this._updatePayloadAttr("productImageHeight",this._productImageHeight)),this._productImageWidth=null,this._productImageHeight=null})),this.files=null}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12693
- t?.click()}changeStars(e){this._updatePayloadAttr("productStarRating",e.currentTarget.value)}toggleProductButton(){this._updatePayloadAttr("productButtonEnabled",!this.args.payload.productButtonEnabled)}toggleProductRating(){this._updatePayloadAttr("productRatingEnabled",!this.args.payload.productRatingEnabled)}hoverStarOn(e){const t=e.currentTarget.value,r=this.element.querySelectorAll(".kg-product-card-rating-star")
12693
+ this.args.editor.run((()=>{this._updatePayloadAttr("productImageSrc",t.url),this._productImageWidth&&this._productImageHeight&&(this._updatePayloadAttr("productImageWidth",this._productImageWidth),this._updatePayloadAttr("productImageHeight",this._productImageHeight)),this._productImageWidth=null,this._productImageHeight=null})),this.files=null}triggerFileDialog(e){const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12694
+ r?.click()}changeStars(e){this._updatePayloadAttr("productStarRating",e.currentTarget.value)}toggleProductButton(){this._updatePayloadAttr("productButtonEnabled",!this.args.payload.productButtonEnabled)}toggleProductRating(){this._updatePayloadAttr("productRatingEnabled",!this.args.payload.productRatingEnabled)}hoverStarOn(e){const t=e.currentTarget.value,r=this.element.querySelectorAll(".kg-product-card-rating-star")
12694
12695
  for(let n=0;n+1<=t&&n<r.length;n++)r[n].classList.add("kg-product-card-rating-star-hovered")}hoverStarOff(){const e=this.element.querySelectorAll(".kg-product-card-rating-star")
12695
12696
  for(let t=0;t<e.length;t++)e[t].classList.remove("kg-product-card-rating-star-hovered")}dragOver(e){if(e.dataTransfer){if(navigator.userAgent.indexOf("Chrome")>-1){let t=e.dataTransfer.effectAllowed
12696
12697
  e.dataTransfer.dropEffect="move"===t||"linkMove"===t?"move":"copy"}e.stopPropagation(),e.preventDefault(),this.isDraggedOver=!0}}dragLeave(e){e.preventDefault(),this.isDraggedOver=!1}drop(e){e.preventDefault(),this.isDraggedOver=!1,e.dataTransfer.files&&(this.files=[e.dataTransfer.files[0]])}},D=q(j.prototype,"feature",[o],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),I=q(j.prototype,"store",[a],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),N=q(j.prototype,"membersUtils",[s],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),L=q(j.prototype,"ui",[l],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),F=q(j.prototype,"config",[i.inject],{configurable:!0,enumerable:!0,writable:!0,initializer:null}),z=q(j.prototype,"files",[u],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return null}}),B=q(j.prototype,"previewSrc",[c],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return null}}),H=q(j.prototype,"isDraggedOver",[d],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return!1}}),q(j.prototype,"registerElement",[h],Object.getOwnPropertyDescriptor(j.prototype,"registerElement"),j.prototype),q(j.prototype,"registerTitleEditor",[p],Object.getOwnPropertyDescriptor(j.prototype,"registerTitleEditor"),j.prototype),q(j.prototype,"registerEditor",[f],Object.getOwnPropertyDescriptor(j.prototype,"registerEditor"),j.prototype),q(j.prototype,"setProductTitle",[m],Object.getOwnPropertyDescriptor(j.prototype,"setProductTitle"),j.prototype),q(j.prototype,"setProductDescription",[g],Object.getOwnPropertyDescriptor(j.prototype,"setProductDescription"),j.prototype),q(j.prototype,"setProductUrl",[v],Object.getOwnPropertyDescriptor(j.prototype,"setProductUrl"),j.prototype),q(j.prototype,"setProductButton",[b],Object.getOwnPropertyDescriptor(j.prototype,"setProductButton"),j.prototype),q(j.prototype,"leaveEditMode",[y],Object.getOwnPropertyDescriptor(j.prototype,"leaveEditMode"),j.prototype),q(j.prototype,"focusElement",[_],Object.getOwnPropertyDescriptor(j.prototype,"focusElement"),j.prototype),q(j.prototype,"setPreviewSrc",[k],Object.getOwnPropertyDescriptor(j.prototype,"setPreviewSrc"),j.prototype),q(j.prototype,"resetSrcs",[E],Object.getOwnPropertyDescriptor(j.prototype,"resetSrcs"),j.prototype),q(j.prototype,"updateSrc",[w],Object.getOwnPropertyDescriptor(j.prototype,"updateSrc"),j.prototype),q(j.prototype,"triggerFileDialog",[x],Object.getOwnPropertyDescriptor(j.prototype,"triggerFileDialog"),j.prototype),q(j.prototype,"changeStars",[O],Object.getOwnPropertyDescriptor(j.prototype,"changeStars"),j.prototype),q(j.prototype,"toggleProductButton",[C],Object.getOwnPropertyDescriptor(j.prototype,"toggleProductButton"),j.prototype),q(j.prototype,"toggleProductRating",[S],Object.getOwnPropertyDescriptor(j.prototype,"toggleProductRating"),j.prototype),q(j.prototype,"hoverStarOn",[T],Object.getOwnPropertyDescriptor(j.prototype,"hoverStarOn"),j.prototype),q(j.prototype,"hoverStarOff",[P],Object.getOwnPropertyDescriptor(j.prototype,"hoverStarOff"),j.prototype),q(j.prototype,"dragOver",[M],Object.getOwnPropertyDescriptor(j.prototype,"dragOver"),j.prototype),q(j.prototype,"dragLeave",[A],Object.getOwnPropertyDescriptor(j.prototype,"dragLeave"),j.prototype),q(j.prototype,"drop",[R],Object.getOwnPropertyDescriptor(j.prototype,"drop"),j.prototype),j)
@@ -12732,8 +12733,8 @@ Object.entries({loop:!1}).forEach((e=>{let[t,r]=e
12732
12733
  void 0===this.args.payload[t]&&this.updatePayloadAttr(t,r)}))}didInsert(e){this.element=e
12733
12734
  const{triggerBrowse:t,src:r,files:n}=this.args.payload
12734
12735
  delete this.args.payload.triggerBrowse,delete this.args.payload.files,!t||r||n||this.triggerVideoFileDialog(),n&&(this.files=n)}registerVideoFileInput(e){this._videoFileInput=e}triggerVideoFileDialog(e){if(this._videoFileInput)return this._videoFileInput.click()
12735
- const t=(e?.target||this.element).closest(".__mobiledoc-card")?.querySelector('input[type="file"]')
12736
- t&&t.click()}async videoUploadStarted(e){const t=e[0]
12736
+ const t=(e?.target||this.element).closest(".__mobiledoc-card"),r=t?.querySelector('input[type="file"]')
12737
+ r&&r.click()}async videoUploadStarted(e){const t=e[0]
12737
12738
  if(t){const e=await this.extractVideoMetadataTask.perform(t)
12738
12739
  this.previewPayload.duration=e.duration,this.previewPayload.width=e.width,this.previewPayload.height=e.height,this.previewPayload.mimeType=e.mimeType,e.thumbnailBlob&&(this.previewPayload.thumbnailSrc||(this.previewThumbnailSrc=URL.createObjectURL(e.thumbnailBlob)),this._thumbnailBlob=e.thumbnailBlob)}}async videoUploadCompleted(e){let[t]=e
12739
12740
  if(this.previewPayload.src=t.url,this.previewPayload.fileName=t.fileName,await this.extractVideoMetadataTask.last,this._thumbnailBlob)try{const e=await this.uploadThumbnailFromBlobTask.perform(t.url,this._thumbnailBlob)
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.35%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.36%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -37,7 +37,7 @@
37
37
  </style>
38
38
 
39
39
  <link integrity="" rel="stylesheet" href="assets/vendor-3e6947aa681f0fb82b193090e520dc73.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-558c1e319d6e025bfab2054bc0f7fe83.css" title="light">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-7ecf5c7934d90798485ee5ac2956f7fe.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -57,8 +57,8 @@
57
57
  <div id="ember-basic-dropdown-wormhole"></div>
58
58
 
59
59
  <script src="assets/vendor-c4684647d4f5213e5dbb6763de430e7e.js"></script>
60
- <script src="assets/chunk.502.c4afca88c98edad8b268.js"></script>
61
- <script src="assets/chunk.143.d49ad252968f2ef3966d.js"></script>
62
- <script src="assets/ghost-4a6ed62455c9e367434183980b3ca3e9.js"></script>
60
+ <script src="assets/chunk.502.800e1515996bcc900013.js"></script>
61
+ <script src="assets/chunk.143.d5eaed4616c55cdbdabb.js"></script>
62
+ <script src="assets/ghost-b828e9e3c161aae92909c2e163656bb1.js"></script>
63
63
  </body>
64
64
  </html>
@@ -0,0 +1,3 @@
1
+ const TTLMemoryCache = require('@tryghost/adapter-cache-memory-ttl');
2
+
3
+ module.exports = TTLMemoryCache;
@@ -4,6 +4,7 @@ const errors = require('@tryghost/errors');
4
4
  const megaService = require('../../services/mega');
5
5
  const emailService = require('../../services/email-service');
6
6
  const labs = require('../../../shared/labs');
7
+ const emailAnalytics = require('../../services/email-analytics');
7
8
 
8
9
  const messages = {
9
10
  emailNotFound: 'Email not found.',
@@ -140,5 +141,39 @@ module.exports = {
140
141
  const filter = `email_id:'${frame.data.id}'` + (frame.options.filter ? `+(${frame.options.filter})` : '');
141
142
  return await models.EmailRecipientFailure.findPage({...frame.options, filter});
142
143
  }
144
+ },
145
+
146
+ analyticsStatus: {
147
+ permissions: {
148
+ method: 'browse'
149
+ },
150
+ async query() {
151
+ return emailAnalytics.service.getStatus();
152
+ }
153
+ },
154
+
155
+ scheduleAnalytics: {
156
+ permissions: {
157
+ method: 'browse'
158
+ },
159
+ data: [
160
+ 'id'
161
+ ],
162
+ async query(frame) {
163
+ const model = await models.Email.findOne(frame.data, frame.options);
164
+ return emailAnalytics.service.schedule({
165
+ begin: model.get('created_at'),
166
+ end: new Date(Math.min(Date.now() - 60 * 60 * 1000, model.get('created_at').getTime() + 24 * 60 * 60 * 1000 * 7))
167
+ });
168
+ }
169
+ },
170
+
171
+ cancelScheduledAnalytics: {
172
+ permissions: {
173
+ method: 'browse'
174
+ },
175
+ async query() {
176
+ return emailAnalytics.service.cancelScheduled();
177
+ }
143
178
  }
144
179
  };
@@ -1,7 +1,6 @@
1
1
  const tpl = require('@tryghost/tpl');
2
2
  const errors = require('@tryghost/errors');
3
3
  const models = require('../../models');
4
- const postsPublicService = require('../../services/posts-public');
5
4
 
6
5
  const ALLOWED_INCLUDES = ['tags', 'authors', 'tiers'];
7
6
 
@@ -36,7 +35,7 @@ module.exports = {
36
35
  },
37
36
  permissions: true,
38
37
  query(frame) {
39
- return postsPublicService.api.browse(frame.options);
38
+ return models.Post.findPage(frame.options);
40
39
  }
41
40
  },
42
41
 
@@ -13,6 +13,7 @@ module.exports = {
13
13
  docName: 'posts',
14
14
 
15
15
  browse: {
16
+ cache: postsPublicService.api?.cache,
16
17
  options: [
17
18
  'include',
18
19
  'filter',
@@ -36,7 +37,7 @@ module.exports = {
36
37
  },
37
38
  permissions: true,
38
39
  query(frame) {
39
- return postsPublicService.api.browse(frame.options);
40
+ return models.Post.findPage(frame.options);
40
41
  }
41
42
  },
42
43
 
@@ -14,6 +14,7 @@ module.exports = {
14
14
  docName: 'tags',
15
15
 
16
16
  browse: {
17
+ cache: tagsPublicService.api?.cache,
17
18
  options: [
18
19
  'include',
19
20
  'filter',
@@ -32,7 +33,7 @@ module.exports = {
32
33
  },
33
34
  permissions: true,
34
35
  query(frame) {
35
- return tagsPublicService.api.browse(frame.options);
36
+ return models.TagPublic.findPage(frame.options);
36
37
  }
37
38
  },
38
39
 
@@ -51,6 +51,10 @@ module.exports = {
51
51
  return require('./webhooks');
52
52
  },
53
53
 
54
+ get mentions() {
55
+ return require('./mentions');
56
+ },
57
+
54
58
  get comments() {
55
59
  return require('./comments');
56
60
  }
@@ -0,0 +1,11 @@
1
+ module.exports = {
2
+ browse(_apiConfig, frame) {
3
+ // Force source:-~^'https://brid.gy/' to be added to the filter
4
+ const filterBridgy = `source:-~^'https://brid.gy/'`;
5
+ if (frame.options.filter) {
6
+ frame.options.filter = `${frame.options.filter}+${filterBridgy}`;
7
+ } else {
8
+ frame.options.filter = filterBridgy;
9
+ }
10
+ }
11
+ };
@@ -28,5 +28,9 @@ module.exports = {
28
28
  if (response.meta) {
29
29
  frame.response.meta = response.meta;
30
30
  }
31
+ },
32
+
33
+ analyticsStatus(response, apiConfig, frame) {
34
+ frame.response = response;
31
35
  }
32
36
  };
@@ -23,11 +23,8 @@ const labs = require('../../../../../../../shared/labs');
23
23
 
24
24
  module.exports = async (model, frame, options = {}) => {
25
25
  const {tiers: tiersData} = options || {};
26
- const extendedOptions = Object.assign(_.cloneDeep(frame.options), {
27
- extraProperties: ['canonical_url']
28
- });
29
26
 
30
- const jsonModel = model.toJSON(extendedOptions);
27
+ const jsonModel = model.toJSON(frame.options);
31
28
 
32
29
  // Map email_recipient_filter to email_segment
33
30
  jsonModel.email_segment = jsonModel.email_recipient_filter;
@@ -35,7 +32,7 @@ module.exports = async (model, frame, options = {}) => {
35
32
 
36
33
  url.forPost(model.id, jsonModel, frame);
37
34
 
38
- extraAttrs.forPost(frame, model, jsonModel);
35
+ extraAttrs.forPost(frame.options, model, jsonModel);
39
36
 
40
37
  // Attach tiers to custom nql visibility filter
41
38
  if (jsonModel.visibility) {
@@ -36,6 +36,7 @@ const author = (attrs, frame) => {
36
36
  delete attrs.paid_subscription_started_notification;
37
37
  delete attrs.paid_subscription_canceled_notification;
38
38
  delete attrs.mention_notifications;
39
+ delete attrs.milestone_notifications;
39
40
 
40
41
  // @NOTE: used for night shift
41
42
  delete attrs.accessibility;
@@ -1,11 +1,18 @@
1
1
  const readingMinutes = require('@tryghost/helpers').utils.readingMinutes;
2
2
 
3
- module.exports.forPost = (frame, model, attrs) => {
3
+ /**
4
+ *
5
+ * @param {Object} options - frame options
6
+ * @param {import('../../../../../../models/post')} model - Bookshelf model of Post
7
+ * @param {Object} attrs - JSON object of Post
8
+ * @returns {void} - modifies attrs
9
+ */
10
+ module.exports.forPost = (options, model, attrs) => {
4
11
  const _ = require('lodash');
5
12
  // This function is split up in 3 conditions for 3 different purposes:
6
13
  // 1. Gets excerpt from post's plaintext. If custom_excerpt exists, it overrides the excerpt but the key remains excerpt.
7
- if (Object.prototype.hasOwnProperty.call(frame.options, 'columns') || _.includes(frame.options.columns, 'excerpt') || _.includes(frame.options.columns, 'excerpt') && frame.options.formats && frame.options.formats.includes('plaintext')) {
8
- if (_.includes(frame.options.columns, 'excerpt')) {
14
+ if (Object.prototype.hasOwnProperty.call(options, 'columns') || _.includes(options.columns, 'excerpt') || _.includes(options.columns, 'excerpt') && options.formats && options.formats.includes('plaintext')) {
15
+ if (_.includes(options.columns, 'excerpt')) {
9
16
  if (!attrs.custom_excerpt || attrs.custom_excerpt === null) {
10
17
  let plaintext = model.get('plaintext');
11
18
  if (plaintext) {
@@ -13,21 +20,22 @@ module.exports.forPost = (frame, model, attrs) => {
13
20
  } else {
14
21
  attrs.excerpt = null;
15
22
  }
16
- if (!frame.options.columns.includes('custom_excerpt')) {
23
+ if (!options.columns.includes('custom_excerpt')) {
17
24
  delete attrs.custom_excerpt;
18
25
  }
19
26
  } else {
20
27
  attrs.excerpt = attrs.custom_excerpt;
21
- if (!_.includes(frame.options.columns, 'custom_excerpt')) {
28
+ if (!_.includes(options.columns, 'custom_excerpt')) {
22
29
  delete attrs.custom_excerpt;
23
30
  }
24
31
  }
25
32
  }
26
33
  }
34
+
27
35
  // 2. Displays plaintext if requested by user as a field. Also works if used as format.
28
- if (_.includes(frame.options.columns, 'plaintext') || frame.options.formats && frame.options.formats.includes('plaintext')) {
36
+ if (_.includes(options.columns, 'plaintext') || options.formats && options.formats.includes('plaintext')) {
29
37
  let plaintext = model.get('plaintext');
30
- if (plaintext){
38
+ if (plaintext) {
31
39
  attrs.plaintext = plaintext;
32
40
  } else {
33
41
  delete attrs.plaintext;
@@ -36,11 +44,11 @@ module.exports.forPost = (frame, model, attrs) => {
36
44
 
37
45
  // 3. Displays excerpt if no columns was requested - specifically needed for the Admin Posts API.
38
46
 
39
- if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns')) {
47
+ if (!Object.prototype.hasOwnProperty.call(options, 'columns')) {
40
48
  let plaintext = model.get('plaintext');
41
49
  let customExcerpt = model.get('custom_excerpt');
42
50
 
43
- if (customExcerpt !== null){
51
+ if (customExcerpt !== null) {
44
52
  attrs.excerpt = customExcerpt;
45
53
  } else {
46
54
  if (plaintext) {
@@ -53,8 +61,8 @@ module.exports.forPost = (frame, model, attrs) => {
53
61
 
54
62
  // reading_time still only works when used along with formats=html.
55
63
 
56
- if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns') ||
57
- (frame.options.columns.includes('reading_time'))) {
64
+ if (!Object.prototype.hasOwnProperty.call(options, 'columns') ||
65
+ (options.columns.includes('reading_time'))) {
58
66
  if (attrs.html) {
59
67
  let additionalImages = 0;
60
68
 
@@ -46,7 +46,8 @@ const BACKUP_TABLES = [
46
46
  'members_click_events',
47
47
  'members_feedback',
48
48
  'suppressions',
49
- 'email_spam_complaint_events'
49
+ 'email_spam_complaint_events',
50
+ 'milestones'
50
51
  ];
51
52
 
52
53
  // NOTE: exposing only tables which are going to be included in a "default" export file
@@ -0,0 +1,10 @@
1
+ const {addTable} = require('../../utils');
2
+
3
+ module.exports = addTable('milestones', {
4
+ id: {type: 'string', maxlength: 24, nullable: false, primary: true},
5
+ type: {type: 'string', maxlength: 24, nullable: false},
6
+ value: {type: 'integer', nullable: false},
7
+ currency: {type: 'string', maxlength: 24, nullable: true},
8
+ created_at: {type: 'dateTime', nullable: false},
9
+ email_sent_at: {type: 'dateTime', nullable: true}
10
+ });
@@ -0,0 +1,7 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('users', 'milestone_notifications', {
4
+ type: 'boolean',
5
+ nullable: false,
6
+ defaultTo: true
7
+ });
@@ -0,0 +1,31 @@
1
+ const logging = require('@tryghost/logging');
2
+ const {createTransactionalMigration} = require('../../utils');
3
+
4
+ // Set outbound_link_tagging to the current value of members_track_sources
5
+ module.exports = createTransactionalMigration(
6
+ async function up(connection) {
7
+ const reuseValueOfSetting = await connection('settings')
8
+ .where('key', '=', 'members_track_sources')
9
+ .first();
10
+
11
+ if (!reuseValueOfSetting) {
12
+ logging.warn(`Skipped setting outbound_link_tagging to current value of members_track_sources - members_track_sources not found`);
13
+ return;
14
+ }
15
+
16
+ const affectedRows = await connection('settings')
17
+ .update({
18
+ value: reuseValueOfSetting.value
19
+ })
20
+ .where('key', '=', 'outbound_link_tagging');
21
+
22
+ if (affectedRows === 1) {
23
+ logging.info(`Set outbound_link_tagging to ${reuseValueOfSetting.value} (current members_track_sources value)`);
24
+ } else {
25
+ logging.warn(`Tried setting outbound_link_tagging to ${reuseValueOfSetting.value} — ${affectedRows} changes`);
26
+ }
27
+ },
28
+ async function down() {
29
+ // no-op: we don't need to change it back
30
+ }
31
+ );
@@ -155,6 +155,7 @@ module.exports = {
155
155
  paid_subscription_started_notification: {type: 'boolean', nullable: false, defaultTo: true},
156
156
  paid_subscription_canceled_notification: {type: 'boolean', nullable: false, defaultTo: false},
157
157
  mention_notifications: {type: 'boolean', nullable: false, defaultTo: true},
158
+ milestone_notifications: {type: 'boolean', nullable: false, defaultTo: true},
158
159
  created_at: {type: 'dateTime', nullable: false},
159
160
  created_by: {type: 'string', maxlength: 24, nullable: false},
160
161
  updated_at: {type: 'dateTime', nullable: true},
@@ -997,5 +998,13 @@ module.exports = {
997
998
  payload: {type: 'text', maxlength: 65535, nullable: true},
998
999
  deleted: {type: 'boolean', nullable: false, defaultTo: false},
999
1000
  verified: {type: 'boolean', nullable: false, defaultTo: false}
1001
+ },
1002
+ milestones: {
1003
+ id: {type: 'string', maxlength: 24, nullable: false, primary: true},
1004
+ type: {type: 'string', maxlength: 24, nullable: false},
1005
+ value: {type: 'integer', nullable: false},
1006
+ currency: {type: 'string', maxlength: 24, nullable: true},
1007
+ created_at: {type: 'dateTime', nullable: false},
1008
+ email_sent_at: {type: 'dateTime', nullable: true}
1000
1009
  }
1001
1010
  };
@@ -20,22 +20,32 @@ function isPrivateIp(addr) {
20
20
  async function errorIfHostnameResolvesToPrivateIp(options) {
21
21
  // allow requests through to local Ghost instance
22
22
  const siteUrl = new URL(config.get('url'));
23
- const requestUrl = new URL(options.href);
23
+ const requestUrl = new URL(options.url.href);
24
24
  if (requestUrl.host === siteUrl.host) {
25
25
  return Promise.resolve();
26
26
  }
27
27
 
28
- const result = await dnsPromises.lookup(options.hostname);
28
+ const result = await dnsPromises.lookup(options.url.hostname);
29
29
 
30
30
  if (isPrivateIp(result.address)) {
31
31
  return Promise.reject(new errors.InternalServerError({
32
32
  message: 'URL resolves to a non-permitted private IP block',
33
33
  code: 'URL_PRIVATE_INVALID',
34
- context: options.href
34
+ context: options.url.href
35
35
  }));
36
36
  }
37
37
  }
38
38
 
39
+ async function errorIfInvalidUrl(options) {
40
+ if (!options.url.hostname || !validator.isURL(options.url.hostname)) {
41
+ throw new errors.InternalServerError({
42
+ message: 'URL invalid.',
43
+ code: 'URL_MISSING_INVALID',
44
+ context: options.url.href
45
+ });
46
+ }
47
+ }
48
+
39
49
  // same as our normal request lib but if any request in a redirect chain resolves
40
50
  // to a private IP address it will be blocked before the request is made.
41
51
  const externalRequest = got.extend({
@@ -44,16 +54,7 @@ const externalRequest = got.extend({
44
54
  },
45
55
  timeout: 10000, // default is no timeout
46
56
  hooks: {
47
- init: [(options) => {
48
- if (!options.hostname || !validator.isURL(options.hostname)) {
49
- throw new errors.InternalServerError({
50
- message: 'URL empty or invalid.',
51
- code: 'URL_MISSING_INVALID',
52
- context: options.href
53
- });
54
- }
55
- }],
56
- beforeRequest: [errorIfHostnameResolvesToPrivateIp],
57
+ beforeRequest: [errorIfInvalidUrl,errorIfHostnameResolvesToPrivateIp],
57
58
  beforeRedirect: [errorIfHostnameResolvesToPrivateIp]
58
59
  }
59
60
  });
@@ -0,0 +1,9 @@
1
+ const ghostBookshelf = require('./base');
2
+
3
+ const Milestone = ghostBookshelf.Model.extend({
4
+ tableName: 'milestones'
5
+ });
6
+
7
+ module.exports = {
8
+ Milestone: ghostBookshelf.model('Milestone', Milestone)
9
+ };
@@ -69,7 +69,8 @@ User = ghostBookshelf.Model.extend({
69
69
  free_member_signup_notification: true,
70
70
  paid_subscription_started_notification: true,
71
71
  paid_subscription_canceled_notification: false,
72
- mention_notifications: true
72
+ mention_notifications: true,
73
+ milestone_notifications: true
73
74
  };
74
75
  },
75
76
 
@@ -507,6 +508,8 @@ User = ghostBookshelf.Model.extend({
507
508
  filter += '+paid_subscription_canceled_notification:true';
508
509
  } else if (type === 'mention-received') {
509
510
  filter += '+mention_notifications:true';
511
+ } else if (type === 'milestone-received') {
512
+ filter += '+milestone_notifications:true';
510
513
  }
511
514
  const updatedOptions = _.merge({}, options, {filter, withRelated: ['roles']});
512
515
  return this.findAll(updatedOptions).then((users) => {