-
{{@payload.productTitle}}
-
{{@payload.productDescription}}
-
-
+
+ {{#if @payload.productImageSrc}}
+

+ {{/if}}
+
{{@payload.productTitle}}
+
{{@payload.productDescription}}
+ {{#if (and @payload.productButton @payload.productUrl)}}
+
+ {{/if}}
+
{{/if}}
\ No newline at end of file
diff --git a/ghost/admin/lib/koenig-editor/addon/components/koenig-card-product.js b/ghost/admin/lib/koenig-editor/addon/components/koenig-card-product.js
index 95365b8317..f31b388491 100644
--- a/ghost/admin/lib/koenig-editor/addon/components/koenig-card-product.js
+++ b/ghost/admin/lib/koenig-editor/addon/components/koenig-card-product.js
@@ -1,4 +1,10 @@
+import $ from 'jquery';
+import Browser from 'mobiledoc-kit/utils/browser';
import Component from '@glimmer/component';
+import {
+ IMAGE_EXTENSIONS,
+ IMAGE_MIME_TYPES
+} from 'ghost-admin/components/gh-image-uploader';
import {action} from '@ember/object';
import {isBlank} from '@ember/utils';
import {run} from '@ember/runloop';
@@ -12,16 +18,20 @@ export default class KoenigCardProductComponent extends Component {
@service membersUtils;
@service ui;
- get isEmpty() {
- const {productTitle, productDescription, productUrl} = this.args.payload;
+ files= null;
+ imageExtensions = IMAGE_EXTENSIONS;
+ imageMimeTypes = IMAGE_MIME_TYPES;
- return isBlank(productTitle) && isBlank(productDescription) && isBlank(productUrl);
+ get isEmpty() {
+ const {productTitle, productDescription, productUrl, productButton, productImageSrc} = this.args.payload;
+
+ return isBlank(productTitle) && isBlank(productDescription) && isBlank(productUrl) && isBlank(productButton) && isBlank(productImageSrc);
}
get isIncomplete() {
- const {productTitle, productDescription, productUrl} = this.args.payload;
+ const {productTitle, productDescription, productUrl, productButton, productImageSrc} = this.args.payload;
- return isBlank(productTitle) || isBlank(productDescription) || isBlank(productUrl);
+ return isBlank(productTitle) || isBlank(productDescription) || isBlank(productUrl) || isBlank(productButton) || isBlank(productImageSrc);
}
get toolbar() {
@@ -62,13 +72,40 @@ export default class KoenigCardProductComponent extends Component {
}
@action
- setProductTitle(event) {
- this._updatePayloadAttr('productTitle', event.target.value);
+ registerEditor(textReplacementEditor) {
+ let commands = {
+ 'META+ENTER': run.bind(this, this._enter, 'meta'),
+ 'CTRL+ENTER': run.bind(this, this._enter, 'ctrl')
+ };
+
+ Object.keys(commands).forEach((str) => {
+ textReplacementEditor.registerKeyCommand({
+ str,
+ run() {
+ return commands[str](textReplacementEditor, str);
+ }
+ });
+ });
+
+ this._textReplacementEditor = textReplacementEditor;
+
+ run.scheduleOnce('afterRender', this, this._afterRender);
+ }
+
+ _enter(modifier) {
+ if (this.args.isEditing && (modifier === 'meta' || (modifier === 'crtl' && Browser.isWin()))) {
+ this.args.editCard();
+ }
}
@action
- setProductDescription(event) {
- this._updatePayloadAttr('productDescription', event.target.value);
+ setProductTitle(content) {
+ this._updatePayloadAttr('productTitle', content);
+ }
+
+ @action
+ setProductDescription(content) {
+ this._updatePayloadAttr('productDescription', content);
}
@action
@@ -76,6 +113,11 @@ export default class KoenigCardProductComponent extends Component {
this._updatePayloadAttr('productUrl', event.target.value);
}
+ @action
+ setProductButton(event) {
+ this._updatePayloadAttr('productButton', event.target.value);
+ }
+
@action
leaveEditMode() {
if (this.isEmpty) {
@@ -99,4 +141,97 @@ export default class KoenigCardProductComponent extends Component {
// update the mobiledoc and stay in edit mode
this.args.saveCard?.(payload, false);
}
+
+ _afterRender() {
+ this._placeCursorAtEnd();
+ this._focusInput();
+ }
+
+ _placeCursorAtEnd() {
+ if (!this._textReplacementEditor) {
+ return;
+ }
+
+ let tailPosition = this._textReplacementEditor.post.tailPosition();
+ let rangeToSelect = tailPosition.toRange();
+ this._textReplacementEditor.selectRange(rangeToSelect);
+ }
+
+ _focusInput() {
+ let headingInput = this.element.querySelector('.kg-product-card-title .koenig-basic-html-input__editor');
+
+ if (headingInput) {
+ headingInput.focus();
+ }
+ }
+
+ @action
+ setPreviewSrc(files) {
+ let file = files[0];
+ if (file) {
+ let url = URL.createObjectURL(file);
+ this.previewSrc = url;
+
+ let imageElem = new Image();
+ imageElem.onload = () => {
+ // store width/height for use later to avoid saving an image card with no `src`
+ this._imageWidth = imageElem.naturalWidth;
+ this._imageHeight = imageElem.naturalHeight;
+ };
+ imageElem.src = url;
+ }
+ }
+
+ @action
+ resetSrcs() {
+ // this.set('previewSrc', null);
+ this.previewSrc = null;
+ // this._imageWidth = null;
+ // this._imageHeight = null;
+
+ // create undo snapshot when clearing
+ this.args.editor.run(() => {
+ this._updatePayloadAttr('productImageSrc', null);
+ // this._updatePayloadAttr('width', null);
+ // this._updatePayloadAttr('height', null);
+ });
+ }
+
+ @action
+ updateSrc(images) {
+ let [image] = images;
+
+ // create undo snapshot when image finishes uploading
+ this.args.editor.run(() => {
+ this._updatePayloadAttr('productImageSrc', image.url);
+ if (this._imageWidth && this._imageHeight) {
+ // this._updatePayloadAttr('width', this._imageWidth);
+ // this._updatePayloadAttr('height', this._imageHeight);
+ }
+ this._imageWidth = null;
+ this._imageHeight = null;
+ });
+ }
+
+ /**
+ * Opens a file selection dialog - Triggered by "Upload Image" 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) {
+ this._triggerFileDialog(event);
+ }
+
+ _triggerFileDialog(event) {
+ let target = event && event.target || this.element;
+
+ // simulate click to open file dialog
+ // using jQuery because IE11 doesn't support MouseEvent
+ $(target)
+ .closest('.__mobiledoc-card')
+ .find('input[type="file"]')
+ .click();
+ }
}