Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add default widgets to an area #3908

Closed
wants to merge 13 commits into from
Closed
18 changes: 16 additions & 2 deletions modules/@apostrophecms/area/index.js
Expand Up @@ -245,12 +245,15 @@ module.exports = {
// options to sanitize against. Thus h5 can be legal
// in one rich text widget and not in another.
//
// `forcePlaceholder` is used to choose whether to render the widgets
// with their placeholder or not, depending on their manager options.
//
// If any errors occur sanitizing the individual widgets,
// an array of errors with `path` and `error` properties
// is thrown.
//
// Returns a new array of sanitized items.
async sanitizeItems(req, items, options) {
async sanitizeItems(req, items, options, forcePlaceholder = false) {
options = options || {};
const result = [];
const errors = [];
Expand All @@ -265,14 +268,19 @@ module.exports = {
self.warnMissingWidgetType(item.type);
continue;
}

if (forcePlaceholder && manager.options.placeholder) {
item.aposPlaceholder = true;
}

const widgetOptions = widgetsOptions[item.type];
if (!widgetOptions) {
// This widget is not specified for this area at all
continue;
}
let newItem;
try {
newItem = await manager.sanitize(req, item, widgetOptions);
newItem = await manager.sanitize(req, item, widgetOptions, forcePlaceholder);
newItem._id = self.apos.launder.id(item._id) || self.apos.util.generateId();
} catch (e) {
if (Array.isArray(e)) {
Expand Down Expand Up @@ -554,6 +562,8 @@ module.exports = {
const widgetEditors = {};
const widgetManagers = {};
const widgetIsContextual = {};
const widgetHasPlaceholder = {};
const widgetHasInitialModal = {};
const contextualWidgetDefaultData = {};

_.each(self.widgetManagers, function (manager, name) {
Expand All @@ -563,6 +573,8 @@ module.exports = {
widgetEditors[name] = (browserData && browserData.components && browserData.components.widgetEditor) || 'AposWidgetEditor';
widgetManagers[name] = manager.__meta.name;
widgetIsContextual[name] = manager.options.contextual;
widgetHasPlaceholder[name] = manager.options.placeholder;
widgetHasInitialModal[name] = !widgetHasPlaceholder[name] && manager.options.initialModal !== false;
contextualWidgetDefaultData[name] = manager.options.defaultData;
});

Expand All @@ -573,6 +585,8 @@ module.exports = {
widgetEditors
},
widgetIsContextual,
widgetHasPlaceholder,
widgetHasInitialModal,
contextualWidgetDefaultData,
widgetManagers,
action: self.action
Expand Down
30 changes: 27 additions & 3 deletions modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue
Expand Up @@ -422,17 +422,28 @@ export default {
} else if (this.widgetIsContextual(name)) {
return this.insert({
widget: {
_id: cuid(),
type: name,
...this.contextualWidgetDefaultData(name)
...this.contextualWidgetDefaultData(name),
...this.widgetAreaDefaultData(name)
},
index
});
} else if (!this.widgetHasInitialModal(name)) {
const widgetAreaDefaultData = this.widgetAreaDefaultData(name);
const aposPlaceholder = this.widgetHasPlaceholder(name) && !widgetAreaDefaultData;
return this.insert({
widget: {
type: name,
...widgetAreaDefaultData,
aposPlaceholder
},
index
});
} else {
const componentName = this.widgetEditorComponent(name);
apos.area.activeEditor = this;
const widget = await apos.modal.execute(componentName, {
value: null,
value: this.widgetAreaDefaultData(name),
options: this.options.widgets[name],
type: name,
docId: this.docId
Expand All @@ -449,6 +460,13 @@ export default {
contextualWidgetDefaultData(type) {
return this.moduleOptions.contextualWidgetDefaultData[type];
},
widgetAreaDefaultData(type) {
const defaults = this.options.widgets[type]._def;

return defaults && Object.keys(defaults).length
? defaults
: null;
},
async insert({ index, widget }) {
if (!widget._id) {
widget._id = cuid();
Expand Down Expand Up @@ -478,6 +496,12 @@ export default {
widgetIsContextual(type) {
return this.moduleOptions.widgetIsContextual[type];
},
widgetHasPlaceholder(type) {
return this.moduleOptions.widgetHasPlaceholder[type];
},
widgetHasInitialModal(type) {
return this.moduleOptions.widgetHasInitialModal[type];
},
widgetEditorComponent(type) {
return this.moduleOptions.components.widgetEditors[type];
},
Expand Down
4 changes: 2 additions & 2 deletions modules/@apostrophecms/doc-type/index.js
Expand Up @@ -368,8 +368,8 @@ module.exports = {
},
// Returns a new instance of the doc type, with the appropriate default
// values for each schema field.
newInstance() {
const doc = self.apos.schema.newInstance(self.schema);
async newInstance(req) {
const doc = await self.apos.schema.newInstance(req, self.schema);
doc.type = self.name;
return doc;
},
Expand Down
Expand Up @@ -605,6 +605,7 @@ export default {
async loadNewInstance () {
this.docReady = false;
const newInstance = await this.getNewInstance();
console.log('🚀 ~ file: AposDocEditor.vue ~ line 610 ~ loadNewInstance ~ newInstance', newInstance);
this.original = newInstance;
if (newInstance && newInstance.type !== this.docType) {
this.docType = newInstance.type;
Expand Down
2 changes: 1 addition & 1 deletion modules/@apostrophecms/global/index.js
Expand Up @@ -82,7 +82,7 @@ module.exports = {
const req = self.apos.task.getReq();
const existing = await self.apos.doc.db.findOne({ slug: self.slug });
if (!existing) {
const _new = self.newInstance();
const _new = await self.newInstance(req);
Object.assign(_new, {
slug: self.slug,
type: self.name
Expand Down
2 changes: 2 additions & 0 deletions modules/@apostrophecms/i18n/i18n/en.json
Expand Up @@ -161,6 +161,7 @@
"home": "Home",
"image": "Image",
"imageFile": "Image File",
"imagePlaceholder": "Image placeholder",
"imageTag": "Image Tag",
"imageTags": "Image Tags",
"images": "Images",
Expand Down Expand Up @@ -263,6 +264,7 @@
"richTextItalic": "Italic",
"richTextLink": "Link",
"richTextParagraph": "Paragraph (P)",
"richTextPlaceholder": "Start Typing Here...",
"richTextH2": "Heading 2 (H2)",
"richTextH3": "Heading 3 (H3)",
"richTextH4": "Heading 4 (H4)",
Expand Down
2 changes: 2 additions & 0 deletions modules/@apostrophecms/i18n/i18n/es.json
Expand Up @@ -150,6 +150,7 @@
"home": "Inicio",
"image": "Imagen",
"imageFile": "Archivo de Imagen",
"imagePlaceholder": "Marcador de posición de imagen",
"imageTag": "Etiqueta de Imagen",
"imageTags": "Etiquetas de Imágenes",
"images": "Imágenes",
Expand Down Expand Up @@ -242,6 +243,7 @@
"richTextItalic": "Cursiva",
"richTextLink": "Liga",
"richTextParagraph": "Párrafo (P)",
"richTextPlaceholder": "Comience a escribir aquí...",
"richTextH2": "Título 2 (H2)",
"richTextH3": "Título 3 (H3)",
"richTextH4": "Título 4 (H4)",
Expand Down
2 changes: 2 additions & 0 deletions modules/@apostrophecms/i18n/i18n/fr.json
Expand Up @@ -148,6 +148,7 @@
"home": "Accueil",
"image": "Image",
"imageFile": "Fichier d'image",
"imagePlaceholder": "Espace réservé pour l'image",
"imageTag": "Tag d'image",
"imageTags": "Tags d'image",
"images": "Images",
Expand Down Expand Up @@ -249,6 +250,7 @@
"richTextItalic": "Italique",
"richTextLink": "Lien",
"richTextParagraph": "Paragraphe (P)",
"richTextPlaceholder": "Commencez à écrire ici...",
"richTextH2": "Titre de niveau 2 (H2)",
"richTextH3": "Titre de niveau 3 (H3)",
"richTextH4": "Titre de niveau 4 (H4)",
Expand Down
2 changes: 2 additions & 0 deletions modules/@apostrophecms/i18n/i18n/pt-BR.json
Expand Up @@ -150,6 +150,7 @@
"home": "Home",
"image": "Imagem",
"imageFile": "Arquivo de Imagem",
"imagePlaceholder": "Espaço reservado para imagem",
"imageTag": "Tag de Imagem",
"imageTags": "Tags de Imagem",
"images": "Imagens",
Expand Down Expand Up @@ -240,6 +241,7 @@
"richTextItalic": "Itálico",
"richTextLink": "Link",
"richTextParagraph": "Parágrafo (P)",
"richTextPlaceholder": "Comece a digitar aqui...",
"richTextH2": "Título 2 (H2)",
"richTextH3": "Título 3 (H3)",
"richTextH4": "Título 4 (H4)",
Expand Down
2 changes: 2 additions & 0 deletions modules/@apostrophecms/i18n/i18n/sk.json
Expand Up @@ -154,6 +154,7 @@
"home": "Domovská stránka",
"image": "Obrázok",
"imageFile": "Súbor s obrázkom",
"imagePlaceholder": "Zástupný symbol obrázka",
"imageTag": "Značku obrázku",
"imageTags": "Značky obrázkov",
"images": "Obrázky",
Expand Down Expand Up @@ -252,6 +253,7 @@
"richTextItalic": "Kurzíva",
"richTextLink": "Link",
"richTextParagraph": "Odstavec (P)",
"richTextPlaceholder": "Začnite písať tu...",
"richTextH2": "Nadpis 2 (H2)",
"richTextH3": "Nadpis 3 (H3)",
"richTextH4": "Nadpis 4 (H4)",
Expand Down
5 changes: 4 additions & 1 deletion modules/@apostrophecms/image-widget/index.js
Expand Up @@ -4,7 +4,10 @@ module.exports = {
label: 'apostrophe:image',
className: false,
icon: 'image-icon',
dimensionAttrs: false
dimensionAttrs: false,
placeholder: true,
placeholderClass: false,
placeholderUrl: '/modules/@apostrophecms/image-widget/placeholder.jpg'
},
fields: {
add: {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions modules/@apostrophecms/image-widget/ui/src/index.scss
@@ -0,0 +1,3 @@
.image-widget-placeholder {
width: 100%;
}
62 changes: 35 additions & 27 deletions modules/@apostrophecms/image-widget/views/widget.html
@@ -1,31 +1,39 @@
{% if data.options.className %}
{% set className = data.options.className %}
{% elif data.manager.options.className %}
{% set className = data.manager.options.className %}
{% endif %}
{% if data.widget.aposPlaceholder and data.manager.options.placeholderUrl %}
<img
src="{{ apos.asset.url(data.manager.options.placeholderUrl) }}"
alt="{{ __t('apostrophe:imagePlaceholder') }}"
class="image-widget-placeholder"
/>
{% else %}
{% if data.options.className %}
{% set className = data.options.className %}
{% elif data.manager.options.className %}
{% set className = data.manager.options.className %}
{% endif %}

{% if data.options.dimensionAttrs %}
{% set dimensionAttrs = data.options.dimensionAttrs %}
{% elif data.manager.options.dimensionAttrs %}
{% set dimensionAttrs = data.manager.options.dimensionAttrs %}
{% endif %}
{% if data.options.dimensionAttrs %}
{% set dimensionAttrs = data.options.dimensionAttrs %}
{% elif data.manager.options.dimensionAttrs %}
{% set dimensionAttrs = data.manager.options.dimensionAttrs %}
{% endif %}

{% set attachment = apos.image.first(data.widget._image) %}
{% set attachment = apos.image.first(data.widget._image) %}

{% if attachment %}
<img {% if className %} class="{{ className }}"{% endif %}
srcset="{{ apos.image.srcset(attachment) }}"
src="{{ apos.attachment.url(attachment, { size: data.options.size or 'full' }) }}"
alt="{{ attachment._alt or '' }}"
{% if dimensionAttrs %}
{% if attachment.width %} width="{{ apos.attachment.getWidth(attachment) }}" {% endif %}
{% if attachment.height %} height="{{ apos.attachment.getHeight(attachment) }}" {% endif %}
{% endif %}
{% if data.contextOptions and data.contextOptions.sizes %}
sizes="{{ data.contextOptions.sizes }}"
{% endif %}
{% if apos.attachment.hasFocalPoint(attachment) %}
style="object-position: {{ apos.attachment.focalPointToObjectPosition(attachment) }}"
{%- endif -%}
/>
{% if attachment %}
<img {% if className %} class="{{ className }}"{% endif %}
srcset="{{ apos.image.srcset(attachment) }}"
src="{{ apos.attachment.url(attachment, { size: data.options.size or 'full' }) }}"
alt="{{ attachment._alt or '' }}"
{% if dimensionAttrs %}
{% if attachment.width %} width="{{ apos.attachment.getWidth(attachment) }}" {% endif %}
{% if attachment.height %} height="{{ apos.attachment.getHeight(attachment) }}" {% endif %}
{% endif %}
{% if data.contextOptions and data.contextOptions.sizes %}
sizes="{{ data.contextOptions.sizes }}"
{% endif %}
{% if apos.attachment.hasFocalPoint(attachment) %}
style="object-position: {{ apos.attachment.focalPointToObjectPosition(attachment) }}"
{%- endif -%}
/>
{% endif %}
{% endif %}
3 changes: 3 additions & 0 deletions modules/@apostrophecms/module/index.js
Expand Up @@ -186,6 +186,9 @@ module.exports = {
res.status(200);
res.send(result);
} catch (err) {
console.log('------------------ ERR ----------------------');
console.error(err);
console.log('------------------ END ERR ----------------------');
return self.routeSendError(req, err);
}
};
Expand Down
14 changes: 7 additions & 7 deletions modules/@apostrophecms/page/index.js
Expand Up @@ -235,7 +235,7 @@ module.exports = {
// simply get a new page doc and return it
const parentPage = await self.findForEditing(req, { _id: targetId })
.permission('edit', '@apostrophecms/any-page-type').toObject();
const newChild = self.newChild(parentPage);
const newChild = self.newChild(req, parentPage);
newChild._previewable = true;
return newChild;
}
Expand All @@ -252,13 +252,13 @@ module.exports = {
}
let page;
if ((position === 'firstChild') || (position === 'lastChild')) {
page = self.newChild(targetPage);
page = self.newChild(req, targetPage);
} else {
const parentPage = targetPage._ancestors[targetPage._ancestors.length - 1];
if (!parentPage) {
throw self.apos.error('notfound');
}
page = self.newChild(parentPage);
page = self.newChild(req, parentPage);
}
await manager.convert(req, input, page, {
onlyPresentFields: true,
Expand Down Expand Up @@ -963,7 +963,7 @@ database.`);
// such that no child page types are permitted, this method
// returns null. Visibility settings are inherited from the
// parent page.
newChild(parentPage) {
async newChild(req, parentPage) {
const pageType = self.allowedChildTypes(parentPage)[0];
if (!pageType) {
self.apos.util.warn('No allowed Page types are specified.');
Expand All @@ -977,7 +977,7 @@ database.`);
throw self.apos.error('error', `The page type module ${pageType} does not exist in the project.`);
}
}
const page = manager.newInstance();
const page = await manager.newInstance(req);
_.extend(page, {
title: 'New Page',
slug: self.apos.util.addSlashIfNeeded(parentPage.slug) + 'new-page',
Expand Down Expand Up @@ -1883,14 +1883,14 @@ database.`);
delete cloned._defaults;
let ordinaryDefaults;
if (parent) {
ordinaryDefaults = self.newChild(parent);
ordinaryDefaults = self.newChild(req, parent);
} else {
// The home page is being parked
const type = item.type || parkedDefaults.type;
if (!type) {
throw new Error('Parked home page must have an explicit page type:\n\n' + JSON.stringify(item, null, ' '));
}
ordinaryDefaults = self.apos.doc.getManager(type).newInstance();
ordinaryDefaults = await self.apos.doc.getManager(type).newInstance(req);
}
const _item = {
...ordinaryDefaults,
Expand Down