mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Added Pintura integration page in Admin (#16686)
refs https://github.com/TryGhost/Team/issues/3034 - adds new integration page for Pintura in Admin - allows site owners to enable/disable the image editor integration - allows self-hosters to upload the files for enabling Pintura image editor --------- Co-authored-by: Sodbileg Gansukh <sodbileg.gansukh@gmail.com>
This commit is contained in:
parent
e3fbab9dad
commit
d3c6d8ad13
@ -7,6 +7,7 @@ import {tracked} from '@glimmer/tracking';
|
||||
export default class KoenigImageEditor extends Component {
|
||||
@service ajax;
|
||||
@service feature;
|
||||
@service settings;
|
||||
@service ghostPaths;
|
||||
@tracked scriptLoaded = false;
|
||||
@tracked cssLoaded = false;
|
||||
@ -17,11 +18,20 @@ export default class KoenigImageEditor extends Component {
|
||||
return this.scriptLoaded && this.cssLoaded;
|
||||
}
|
||||
|
||||
get pinturaJsUrl() {
|
||||
return this.config.pintura?.js || this.settings.pinturaJsUrl;
|
||||
}
|
||||
|
||||
get pinturaCSSUrl() {
|
||||
return this.config.pintura?.css || this.settings.pinturaCssUrl;
|
||||
}
|
||||
|
||||
getImageEditorJSUrl() {
|
||||
if (!this.config.pintura?.js) {
|
||||
let importUrl = this.pinturaJsUrl;
|
||||
|
||||
if (!importUrl) {
|
||||
return null;
|
||||
}
|
||||
let importUrl = this.config.pintura.js;
|
||||
|
||||
// load the script from admin root if relative
|
||||
if (importUrl.startsWith('/')) {
|
||||
@ -31,10 +41,11 @@ export default class KoenigImageEditor extends Component {
|
||||
}
|
||||
|
||||
getImageEditorCSSUrl() {
|
||||
if (!this.config.pintura?.css) {
|
||||
let cssImportUrl = this.pinturaCSSUrl;
|
||||
|
||||
if (!cssImportUrl) {
|
||||
return null;
|
||||
}
|
||||
let cssImportUrl = this.config.pintura.css;
|
||||
|
||||
// load the css from admin root if relative
|
||||
if (cssImportUrl.startsWith('/')) {
|
||||
@ -112,8 +123,15 @@ export default class KoenigImageEditor extends Component {
|
||||
|
||||
@action
|
||||
async handleClick() {
|
||||
if (window.pintura) {
|
||||
const imageSrc = `${this.args.imageSrc}?v=${Date.now()}`;
|
||||
if (this.isEditorEnabled && this.args.imageSrc) {
|
||||
// add a timestamp to the image src to bypass cache
|
||||
// avoids cors issues with cached images
|
||||
const imageUrl = new URL(this.args.imageSrc);
|
||||
if (!imageUrl.searchParams.has('v')) {
|
||||
imageUrl.searchParams.set('v', Date.now());
|
||||
}
|
||||
|
||||
const imageSrc = imageUrl.href;
|
||||
const editor = window.pintura.openDefaultEditor({
|
||||
src: imageSrc,
|
||||
util: 'crop',
|
||||
@ -121,11 +139,17 @@ export default class KoenigImageEditor extends Component {
|
||||
'crop',
|
||||
'filter',
|
||||
'finetune',
|
||||
'redact'
|
||||
'redact',
|
||||
'annotate',
|
||||
'trim',
|
||||
'frame',
|
||||
'sticker'
|
||||
],
|
||||
locale: {
|
||||
labelButtonExport: 'Save and close'
|
||||
}
|
||||
},
|
||||
cropEnableButtonToggleCropLimit: true,
|
||||
cropSelectPresetFilter: true
|
||||
});
|
||||
|
||||
editor.on('loaderror', () => {
|
||||
|
97
ghost/admin/app/controllers/settings/integrations/pintura.js
Normal file
97
ghost/admin/app/controllers/settings/integrations/pintura.js
Normal file
@ -0,0 +1,97 @@
|
||||
import Controller from '@ember/controller';
|
||||
import config from 'ghost-admin/config/environment';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
const JS_EXTENSION = ['js'];
|
||||
const JS_MIME_TYPE = ['application/javascript'];
|
||||
const CSS_EXTENSION = ['css'];
|
||||
const CSS_MIME_TYPE = ['text/css'];
|
||||
export default class PinturaController extends Controller {
|
||||
@service notifications;
|
||||
@service settings;
|
||||
@service utils;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked jsSuccess;
|
||||
@tracked jsFailure;
|
||||
@tracked cssSuccess;
|
||||
@tracked cssFailure;
|
||||
|
||||
get showUploadSettings() {
|
||||
return this.settings.pintura && !this.config.pintura;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.jsExtension = JS_EXTENSION;
|
||||
this.jsMimeType = JS_MIME_TYPE;
|
||||
this.jsAccept = [...this.jsMimeType, ...Array.from(this.jsExtension, extension => '.' + extension)];
|
||||
this.cssExtension = CSS_EXTENSION;
|
||||
this.cssMimeType = CSS_MIME_TYPE;
|
||||
this.cssAccept = [...this.cssMimeType, ...Array.from(this.cssExtension, extension => '.' + extension)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file selection dialog - Triggered by "Upload x" buttons,
|
||||
* searches for the hidden file input within the .gh-setting element
|
||||
* containing the clicked button then simulates a click
|
||||
* @param {MouseEvent} event - MouseEvent fired by the button click
|
||||
*/
|
||||
@action
|
||||
triggerFileDialog(event) {
|
||||
// simulate click to open file dialog
|
||||
event?.target.closest('.gh-setting-action')?.querySelector('input[type="file"]')?.click();
|
||||
}
|
||||
|
||||
@action
|
||||
async fileUploadCompleted(fileType, [uploadedFile]) {
|
||||
let successKey = `${fileType}Success`;
|
||||
let failureKey = `${fileType}Failure`;
|
||||
|
||||
if (!uploadedFile || !uploadedFile.url && !uploadedFile.fileName) {
|
||||
this[successKey] = false;
|
||||
this[failureKey] = true;
|
||||
return; // upload failed
|
||||
}
|
||||
this[successKey] = true;
|
||||
this[failureKey] = false;
|
||||
|
||||
window.setTimeout(() => {
|
||||
this[successKey] = null;
|
||||
this[failureKey] = null;
|
||||
}, config.environment === 'test' ? 100 : 5000);
|
||||
|
||||
// Save the uploaded file url to the settings
|
||||
if (fileType === 'js') {
|
||||
this.settings.pinturaJsUrl = uploadedFile.url;
|
||||
} else if (fileType === 'css') {
|
||||
this.settings.pinturaCssUrl = uploadedFile.url;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
update(event) {
|
||||
this.settings.pintura = event.target.checked;
|
||||
}
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.saveTask.perform();
|
||||
}
|
||||
|
||||
@task({drop: true})
|
||||
*saveTask() {
|
||||
try {
|
||||
yield this.settings.validate();
|
||||
return yield this.settings.save();
|
||||
} catch (error) {
|
||||
this.notifications.showAPIError(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
@ -91,6 +91,12 @@ export default Model.extend(ValidationEngine, {
|
||||
editorDefaultEmailRecipients: attr('string'),
|
||||
editorDefaultEmailRecipientsFilter: attr('members-segment-string'),
|
||||
emailVerificationRequired: attr('boolean'),
|
||||
/**
|
||||
* Pintura settings
|
||||
*/
|
||||
pintura: attr('boolean'),
|
||||
pinturaJsUrl: attr('string'),
|
||||
pinturaCssUrl: attr('string'),
|
||||
|
||||
// HACK - not a real model attribute but a workaround for Ember Data not
|
||||
// exposing meta from save responses
|
||||
|
@ -103,6 +103,7 @@ Router.map(function () {
|
||||
this.route('settings.integrations.slack', {path: '/settings/integrations/slack'});
|
||||
this.route('settings.integrations.amp', {path: '/settings/integrations/amp'});
|
||||
this.route('settings.integrations.firstpromoter', {path: '/settings/integrations/firstpromoter'});
|
||||
this.route('settings.integrations.pintura', {path: '/settings/integrations/pintura'});
|
||||
this.route('settings.integrations.unsplash', {path: '/settings/integrations/unsplash'});
|
||||
this.route('settings.integrations.zapier', {path: '/settings/integrations/zapier'});
|
||||
|
||||
|
69
ghost/admin/app/routes/settings/integrations/pintura.js
Normal file
69
ghost/admin/app/routes/settings/integrations/pintura.js
Normal file
@ -0,0 +1,69 @@
|
||||
import AdminRoute from 'ghost-admin/routes/admin';
|
||||
import ConfirmUnsavedChangesModal from '../../../components/modals/confirm-unsaved-changes';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class PinturaIntegrationRoute extends AdminRoute {
|
||||
@service modals;
|
||||
@service settings;
|
||||
|
||||
model() {
|
||||
return this.settings.reload();
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this.confirmModal = null;
|
||||
this.hasConfirmed = false;
|
||||
}
|
||||
|
||||
@action
|
||||
async willTransition(transition) {
|
||||
if (this.hasConfirmed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
transition.abort();
|
||||
|
||||
// wait for any existing confirm modal to be closed before allowing transition
|
||||
if (this.confirmModal) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.controller.saveTask?.isRunning) {
|
||||
await this.controller.saveTask.last;
|
||||
}
|
||||
|
||||
const shouldLeave = await this.confirmUnsavedChanges();
|
||||
|
||||
if (shouldLeave) {
|
||||
this.settings.rollbackAttributes();
|
||||
this.hasConfirmed = true;
|
||||
return transition.retry();
|
||||
}
|
||||
}
|
||||
|
||||
async confirmUnsavedChanges() {
|
||||
if (this.settings.hasDirtyAttributes) {
|
||||
this.confirmModal = this.modals
|
||||
.open(ConfirmUnsavedChangesModal)
|
||||
.finally(() => {
|
||||
this.confirmModal = null;
|
||||
});
|
||||
|
||||
return this.confirmModal;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.controller.send('save');
|
||||
}
|
||||
|
||||
buildRouteInfoMetadata() {
|
||||
return {
|
||||
titleToken: 'Pintura'
|
||||
};
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ export default class SettingsService extends Service.extend(ValidationEngine) {
|
||||
_loadSettings() {
|
||||
if (!this._loadingPromise) {
|
||||
this._loadingPromise = this.store
|
||||
.queryRecord('setting', {group: 'site,theme,private,members,portal,newsletter,email,amp,labs,slack,unsplash,views,firstpromoter,editor,comments,analytics,announcement'})
|
||||
.queryRecord('setting', {group: 'site,theme,private,members,portal,newsletter,email,amp,labs,slack,unsplash,views,firstpromoter,editor,comments,analytics,announcement,pintura'})
|
||||
.then((settings) => {
|
||||
this._loadingPromise = null;
|
||||
return settings;
|
||||
|
@ -616,3 +616,30 @@
|
||||
.apps-card-app-orb.rot-3 {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
/* Pintura integration
|
||||
/* ---------------------------------------------------------- */
|
||||
.gh-pintura-banner.gh-main-section-content {
|
||||
display: grid;
|
||||
grid-template-columns: 4fr 3fr;
|
||||
padding: 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.gh-pintura-banner-content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.gh-pintura-banner-content p {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.gh-pintura-banner-content .gh-btn {
|
||||
margin-top: 1.2em;
|
||||
background-color: var(--black) !important;
|
||||
}
|
||||
|
||||
.gh-pintura-banner-image {
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
@ -204,7 +204,31 @@
|
||||
</article>
|
||||
</LinkTo>
|
||||
</div>
|
||||
|
||||
{{#if (feature 'imageEditor')}}
|
||||
<div class="apps-grid-cell" data-test-app="pintura">
|
||||
<LinkTo @route="settings.integrations.pintura" data-test-link="pintura">
|
||||
<article class="apps-card-app">
|
||||
<div class="apps-card-left">
|
||||
<figure class="apps-card-app-icon id-unsplash" style="background-image:url(assets/img/pintura.png); background-size:36px;"></figure>
|
||||
<div class="apps-card-meta">
|
||||
<h3 class="apps-card-app-title">Pintura</h3>
|
||||
<p class="apps-card-app-desc">Advanced image editing</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gh-card-right">
|
||||
<div class="apps-configured">
|
||||
{{#if this.settings.firstpromoter}}
|
||||
<span class="gh-badge" data-test-app-status>Active</span>
|
||||
{{else}}
|
||||
<span data-test-app-status>Configure</span>
|
||||
{{/if}}
|
||||
{{svg-jar "arrow-right"}}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</LinkTo>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
175
ghost/admin/app/templates/settings/integrations/pintura.hbs
Normal file
175
ghost/admin/app/templates/settings/integrations/pintura.hbs
Normal file
@ -0,0 +1,175 @@
|
||||
<section class="gh-canvas">
|
||||
<GhCanvasHeader class="gh-canvas-header sticky">
|
||||
<div class="flex flex-column">
|
||||
<div class="gh-canvas-breadcrumb">
|
||||
<LinkTo @route="settings">
|
||||
Settings
|
||||
</LinkTo>
|
||||
{{svg-jar "arrow-right-small"}}
|
||||
<LinkTo @route="settings.integrations" data-test-link="integrations-back">
|
||||
Integrations
|
||||
</LinkTo>
|
||||
{{svg-jar "arrow-right-small"}} Pintura
|
||||
</div>
|
||||
</div>
|
||||
<section class="view-actions">
|
||||
<GhTaskButton @task={{this.saveTask}} @class="gh-btn gh-btn-primary gh-btn-icon" data-test-save-button={{true}} />
|
||||
</section>
|
||||
</GhCanvasHeader>
|
||||
|
||||
<section class="view-container">
|
||||
<section class="gh-main-section app-grid">
|
||||
<div class="gh-main-section-block app-detail-heading app-grid">
|
||||
<div class="app-cell">
|
||||
<img class="app-icon" src="assets/img/pintura.png" alt="Pintura icon"/>
|
||||
</div>
|
||||
<div class="app-cell">
|
||||
<h3>Pintura</h3>
|
||||
<p>Advanced image editing</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{#unless this.config.pintura}}
|
||||
<div class="gh-main-section">
|
||||
<div class="gh-pintura-banner gh-main-section-content grey">
|
||||
<div class="gh-pintura-banner-content">
|
||||
<strong>Add advanced image editing to Ghost, with Pintura</strong>
|
||||
<p>Pintura is a powerful JavaScript image editor that allows you to crop, rotate, annotate and modify images directly inside Ghost.</p>
|
||||
<p>Try a demo, purchase a license, and download the required CSS/JS files from pqina.nl/pintura/ to activate this feature.</p>
|
||||
<button type="button" class="gh-btn gh-btn-primary"><span>Find out more →</span></button>
|
||||
</div>
|
||||
<img class="gh-pintura-banner-image" src="assets/img/pintura-screenshot.png" alt="Pintura banner">
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
|
||||
<div class="gh-main-section">
|
||||
<h4 class="gh-main-section-header small bn">Pintura configuration</h4>
|
||||
<section class="gh-main-section-block">
|
||||
<div class="gh-main-section-content grey">
|
||||
<div>
|
||||
<div class="gh-setting-first {{unless this.showUploadSettings "gh-setting-last"}}">
|
||||
<div class="gh-setting-content">
|
||||
<div class="gh-setting-title">Enable Pintura</div>
|
||||
<div class="gh-setting-desc mb0">Enable <a href="#">Pintura</a> for editing your images in Ghost</div>
|
||||
</div>
|
||||
<div class="gh-setting-action">
|
||||
<div class="for-checkbox">
|
||||
<label for="pintura" class="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={{this.settings.pintura}}
|
||||
id="pintura"
|
||||
name="pintura"
|
||||
{{on "click" this.update}}
|
||||
{{!-- onclick={{action "update" value="target.checked"}} --}}
|
||||
data-test-pintura-checkbox
|
||||
>
|
||||
<span class="input-toggle-component"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#unless this.config.pintura}}
|
||||
{{#liquid-if this.settings.pintura class=""}}
|
||||
<div class="gh-setting-last gh-setting-firstpromoter-liquid">
|
||||
<GhUploader
|
||||
@extensions={{this.jsExtension}}
|
||||
@uploadUrl="/files/upload/"
|
||||
@resourceName="files"
|
||||
@onComplete={{fn this.fileUploadCompleted 'js'}}
|
||||
as |uploader|
|
||||
>
|
||||
<div class="gh-expandable-header">
|
||||
<div>
|
||||
<h4 class="gh-expandable-title">Upload Pintura script</h4>
|
||||
<p class="gh-expandable-description">Upload the <code>pintura-umd.js</code> file from the Pintura package</p>
|
||||
</div>
|
||||
<div class="gh-setting-action flex flex-column items-end">
|
||||
{{#if uploader.isUploading}}
|
||||
{{uploader.progressBar}}
|
||||
{{else}}
|
||||
<button
|
||||
type="button"
|
||||
class="gh-btn gh-btn-icon {{if this.jsSuccess "gh-btn-green"}} {{if this.jsFailure "gh-btn-red"}}"
|
||||
onclick={{this.triggerFileDialog}}
|
||||
data-test-button="upload-pintura-js"
|
||||
>
|
||||
<span>
|
||||
{{#if this.jsSuccess}}
|
||||
{{svg-jar "check-circle"}} Uploaded
|
||||
{{else if this.jsFailure}}
|
||||
{{svg-jar "retry"}} Upload Failed
|
||||
{{else}}
|
||||
Upload
|
||||
{{/if}}
|
||||
</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
|
||||
{{#each uploader.errors as |error|}}
|
||||
<div class="gh-setting-error" data-test-error="pintura">{{or error.context error.message}}</div>
|
||||
{{/each}}
|
||||
|
||||
<div style="display:none">
|
||||
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.jsAccept}} data-test-file-input="pintura" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GhUploader>
|
||||
</div>
|
||||
<div class="gh-setting-last gh-setting-firstpromoter-liquid">
|
||||
<GhUploader
|
||||
@extensions={{this.cssExtension}}
|
||||
@uploadUrl="/files/upload/"
|
||||
@resourceName="files"
|
||||
@onComplete={{fn this.fileUploadCompleted 'css'}}
|
||||
as |uploader|
|
||||
>
|
||||
<div class="gh-expandable-header">
|
||||
<div>
|
||||
<h4 class="gh-expandable-title">Upload Pintura styles</h4>
|
||||
<p class="gh-expandable-description">Upload the <code>pintura.css</code> file from the Pintura package</p>
|
||||
</div>
|
||||
<div class="gh-setting-action flex flex-column items-end">
|
||||
{{#if uploader.isUploading}}
|
||||
{{uploader.progressBar}}
|
||||
{{else}}
|
||||
<button
|
||||
type="button"
|
||||
class="gh-btn gh-btn-icon {{if this.cssSuccess "gh-btn-green"}} {{if this.cssFailure "gh-btn-red"}}"
|
||||
onclick={{this.triggerFileDialog}}
|
||||
data-test-button="upload-pintura-css"
|
||||
>
|
||||
<span>
|
||||
{{#if this.cssSuccess}}
|
||||
{{svg-jar "check-circle"}} Uploaded
|
||||
{{else if this.cssFailure}}
|
||||
{{svg-jar "retry"}} Upload Failed
|
||||
{{else}}
|
||||
Upload
|
||||
{{/if}}
|
||||
</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
|
||||
{{#each uploader.errors as |error|}}
|
||||
<div class="gh-setting-error" data-test-error="routes">{{or error.context error.message}}</div>
|
||||
{{/each}}
|
||||
|
||||
<div style="display:none">
|
||||
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.cssAccept}} data-test-file-input="pintura" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GhUploader>
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
@ -103,6 +103,11 @@ export default [
|
||||
setting('firstpromoter', 'firstpromoter', false),
|
||||
setting('firstpromoter', 'firstpromoter_id', null),
|
||||
|
||||
// PINTURA
|
||||
setting('pintura', 'pintura', false),
|
||||
setting('pintura', 'pintura_js_url', null),
|
||||
setting('pintura', 'pintura_css_url', null),
|
||||
|
||||
// LABS
|
||||
setting('labs', 'labs', JSON.stringify({
|
||||
// Keep the GA flags that are not yet cleaned up in frontend code here
|
||||
|
BIN
ghost/admin/public/assets/img/pintura-screenshot.png
Normal file
BIN
ghost/admin/public/assets/img/pintura-screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
BIN
ghost/admin/public/assets/img/pintura.png
Normal file
BIN
ghost/admin/public/assets/img/pintura.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -65,7 +65,10 @@ const EDITABLE_SETTINGS = [
|
||||
'outbound_link_tagging',
|
||||
'announcement_content',
|
||||
'announcement_background',
|
||||
'announcement_visibility'
|
||||
'announcement_visibility',
|
||||
'pintura',
|
||||
'pintura_js_url',
|
||||
'pintura_css_url'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
|
@ -58,7 +58,7 @@ const forTag = (attrs) => {
|
||||
};
|
||||
|
||||
const forSetting = (attrs) => {
|
||||
if (attrs.value && ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image'].includes(attrs.key)) {
|
||||
if (attrs.value && ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image', 'pintura_js_url', 'pintura_css_url'].includes(attrs.key)) {
|
||||
attrs.value = urlUtils.relativeToAbsolute(attrs.value);
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ Settings = ghostBookshelf.Model.extend({
|
||||
},
|
||||
|
||||
formatOnWrite(attrs) {
|
||||
if (attrs.value && ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image'].includes(attrs.key)) {
|
||||
if (attrs.value && ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image', 'pintura_js_url', 'pintura_css_url'].includes(attrs.key)) {
|
||||
attrs.value = urlUtils.toTransformReady(attrs.value);
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ Settings = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
// transform URLs from __GHOST_URL__ to absolute
|
||||
if (['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image'].includes(attrs.key)) {
|
||||
if (['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image', 'pintura_js_url', 'pintura_css_url'].includes(attrs.key)) {
|
||||
attrs.value = urlUtils.transformReadyToAbsolute(attrs.value);
|
||||
}
|
||||
|
||||
|
@ -292,6 +292,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -670,6 +682,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -694,7 +718,7 @@ exports[`Settings API Edit Can edit a setting 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "3934",
|
||||
"content-length": "4043",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
@ -996,6 +1020,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -1321,6 +1357,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -1651,6 +1699,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -2069,6 +2129,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
@ -2459,6 +2531,18 @@ Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
|
@ -8,7 +8,7 @@ const {stringMatching, anyEtag, anyUuid, anyContentLength, anyContentVersion} =
|
||||
const models = require('../../../core/server/models');
|
||||
const {anyErrorId} = matchers;
|
||||
|
||||
const CURRENT_SETTINGS_COUNT = 76;
|
||||
const CURRENT_SETTINGS_COUNT = 79;
|
||||
|
||||
const settingsMatcher = {};
|
||||
|
||||
|
@ -5,7 +5,7 @@ const db = require('../../../core/server/data/db');
|
||||
// Stuff we are testing
|
||||
const models = require('../../../core/server/models');
|
||||
|
||||
const SETTINGS_LENGTH = 87;
|
||||
const SETTINGS_LENGTH = 90;
|
||||
|
||||
describe('Settings Model', function () {
|
||||
before(models.init);
|
||||
|
@ -541,5 +541,27 @@
|
||||
},
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"pintura": {
|
||||
"pintura": {
|
||||
"defaultValue": "false",
|
||||
"validations": {
|
||||
"isIn": [
|
||||
[
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
]
|
||||
},
|
||||
"type": "boolean"
|
||||
},
|
||||
"pintura_js_url": {
|
||||
"defaultValue": null,
|
||||
"type": "string"
|
||||
},
|
||||
"pintura_css_url": {
|
||||
"defaultValue": null,
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user