Missing getImage method on Plone Dexterity image content? - plone

Attributes available on a Dexterity Content Type with Image Field:
>>> app.Plone.test.image.
app.Plone.test.image.__class__( app.Plone.test.image.__provides__( app.Plone.test.image._height app.Plone.test.image._p_state
app.Plone.test.image.__delattr__( app.Plone.test.image.__reduce__( app.Plone.test.image._p_activate( app.Plone.test.image._setData(
app.Plone.test.image.__dict__ app.Plone.test.image.__reduce_ex__( app.Plone.test.image._p_changed app.Plone.test.image._width
app.Plone.test.image.__doc__ app.Plone.test.image.__repr__( app.Plone.test.image._p_deactivate( app.Plone.test.image.contentType
app.Plone.test.image.__format__( app.Plone.test.image.__setattr__( app.Plone.test.image._p_delattr( app.Plone.test.image.data
app.Plone.test.image.__getattribute__( app.Plone.test.image.__setstate__( app.Plone.test.image._p_estimated_size app.Plone.test.image.filename
app.Plone.test.image.__getstate__( app.Plone.test.image.__sizeof__( app.Plone.test.image._p_getattr( app.Plone.test.image.getFirstBytes(
app.Plone.test.image.__hash__( app.Plone.test.image.__str__( app.Plone.test.image._p_invalidate( app.Plone.test.image.getImageSize(
app.Plone.test.image.__implemented__( app.Plone.test.image.__subclasshook__( app.Plone.test.image._p_jar app.Plone.test.image.getSize(
app.Plone.test.image.__init__( app.Plone.test.image.__weakref__ app.Plone.test.image._p_mtime app.Plone.test.image.open(
app.Plone.test.image.__module__ app.Plone.test.image._blob app.Plone.test.image._p_oid app.Plone.test.image.openDetached(
app.Plone.test.image.__new__( app.Plone.test.image._data app.Plone.test.image._p_serial app.Plone.test.image.size
app.Plone.test.image.__providedBy__( app.Plone.test.image._getData( app.Plone.test.image._p_setattr(
I would expect a method getImage or getImageURL method to be present… so much so that I found myself working around its absence via the following:
def get_image(self):
return "data:%s;base64,%s" % (self.context.image.contentType,
base64.encodestring(self.context.image.data))
And:
<img tal:attributes="src view/get_image" />
Which works, but is not ideal in many (hopefully obvious) ways. Now, the default view of this type provides the desired functionality via a widget resource:
view/++widget++form.widgets.image/##download/the-image.png
But I don't have access to it (AFAICT) because I've customized the default view of this type. Should there be a getImage method? Or am I missing some other obvious approach.

Have you tried it in plone.app.imagescales-way
<img tal:replace="structure context/##images/shortnameofmyfield/thumb" />

I resolved a similar issue like this:
selected_image.restrictedTraverse("##images").scale('image', width=None, height=None).index_html()
This returns the image in its original size.

Related

Is there a better way to do this in handlebars?

Im using handlebars to spit out some static pages using a partial like so:
{{> component/card size="small" title="Card Title" }}
Now depending on the "size" of the card required, i need to set some different tailwind classes. Im currently doing it like so, but there must be a better way? Adding the class to the container and writing css is not an option.
{{setVariable "additionalHeadingClass" "text-5 md:text-6 mb-4"}}
{{#ifEquals size "small"}}
{{setVariable "additionalHeadingClass" "text-4 mb-1"}}
{{/ifEquals}}
{{#ifEquals size "large"}}
{{setVariable "additionalHeadingClass" "text-4 sm:text-5 md:text-8 mb-4"}}
{{/ifEquals}}
<h3 class="text-primary font-bold {{#root.additionalHeadingClass}}">{{title}}</h3>
and heres the helper im using:
Handlebars.registerHelper("setVariable", function (varName, varValue, options) {
if (!options.data.root) {
options.data.root = {};
}
options.data.root[varName] = varValue;
});
My opinion is that there is too much code in your template for what it actually does. Despite the intimidating number of lines, we really just want to map a size to a string of class names. I would also advise against the setVariable because I find it harder to think about when we creating a side-effect by manipulating a variable on our context object. I would much prefer a more functional-style helper, where we just give it the size and it returns the class names string.
I would create such a helper using a simple switch:
Handlebars.registerHelper('additionalClasses', function(size) {
switch (size) {
case 'large':
return 'text-4 sm:text-5 md:text-8 mb-4';
case 'small':
return 'text-4 mb-1';
default:
return 'text-5 md:text-6 mb-4';
}
});
And then we may reduce our template to the much simpler:
<h3 class="text-primary font-bold {{additionalClasses size}}">{{title}}</h3>
I have created a fiddle for reference.

Is there a way to set up "loading: lazy" instead of default "loading: eager" for all inline images in gatsby-source-wordpress?

I'm trying to decrease page loading time. Right now all images which came from Wordpress content are geting "loading: eager". In result all images are downloading immediately all together on the page. So I would like to know is there an option to set up by default "loading: lazy" for all images which come from content of gatsby-source-wordpress.
To show images I'm just using this way:
<div dangerouslySetInnerHTML={{ __html: content }} />
Gatsby v3.14,
NodeJs 12.22.6,
Gatsby-source-wordpress 5.14,
Gatsby-plugin-image 1.14
I think your best chance is customizing the content that is rendering the dangerouslySetInnerHTML or trying gatsby-wpgraphql-inline-images
For the first approach, a library such as html-react-parser may fit your requirements.
Instead of:
<div dangerouslySetInnerHtml={{__html: content}}/>
You will do:
<div>{parse(content, {replace: replaceMedia})}</div>
Where replaceMedia is a function that gets the nodes and replaces them by a custom markup:
const replaceMedia = node => {
if (node.name === 'img') {
console.log("Check the node data:", node)
return <img src={node.attribs.src} loading="lazy" alt="Some alternative text" />
}
};
Test it to check the data inside node and tweak it accordingly. If your images are locally set, you can even use a custom component to return a GatsbyImage.
The second approach will rely on your set up, which has not been provided in the question.
Useful resources:
https://dimitr.im/optimize-loading-images-wordpress-gatsby
https://www.gatsbyjs.com/plugins/gatsby-wpgraphql-inline-images/
https://www.gatsbyjs.com/plugins/gatsby-wpgraphql-inline-images/

Can't bind since it isn't a known property of angular component

I am trying to conditionally set a classname based on a boolean variable. I have set the variable within the parent component:
public alteredSidebar: boolean;
And this is my though process behind conditionally defining which class it is:
<div [class]="alteredSidebar == false ? 'secondsidenav' : 'sidenav'" id="rollup-sidenav" [ngClass]="{ 'greyout': greyOut }"></div>
I have defined 2 classes with css file, one called secondsidenav and another called sidenav. Wherever I set the boolean as false, I would like the classname to equal the secondsidenav and where it is not false it be sidenav. Here is an instance of where I am using it and I am expecting the class to be set to 'secondsidenav':
<app-rollup [data]="rollupData" (resetCalled)="onRollupReset()" (entrySelected)="onRollupSelectEvent($event)" [alteredSidebar]="false">
</app-rollup>
However I am getting the following error: "Can't bind to 'alteredSidebar' since it isn't a known property of 'app-rollup'."
use #Input() decorator on it
#Input()
public alteredSidebar: boolean;
As #junk said, you should use the #Input() decorator in the app-rollup component and I'd like to add, do not mix [className] with ngClass, this might not be related to your problem but it gets really buggy if you're using a reactive property to programatically add or remove a class, just pick one and try not to mix them it will also make the code more consistent. Oh, and the correct syntax is [className] you're probably confusing it with [class.foo]="expresion" which will apply the 'foo' class if the expression is true
Personally I'd do something like this, also sticking with one approach is considered a best practice
<div id="rollup-sidenav" [ngClass]="{
'greyout': greyOut,
'secondsidenav': !alteredSidebar,
'sidenav': alteredSidebar
}">
</div>
Hope that helps, let me know if it doesn't!
#Berheet.. try this
assign the value alteredSidebar in the component itself and pass it like below
parentComponent.ts
public alteredSidebar: boolean = false;
parentComponent.html
<app-rollup [data]="rollupData" (resetCalled)="onRollupReset()" (entrySelected)="onRollupSelectEvent($event)" [alteredSidebar]="alteredSidebar">
</app-rollup>
Add Input in child component
childComponent.ts
#Input() alteredSidebar: boolean;
childComponent.html
<div [class]="alteredSidebar == false ? 'secondsidenav' : 'sidenav'" id="rollup-sidenav" [ngClass]="{ 'greyout': greyOut }"></div>
I'd suggest to simply set the div-tags class property conditionally as follows
[class]="alteredSidebar ? 'sidenav' : 'secondsidenav'"
This way you get a more readable condition ? positive case : negative case flow and you don't need to compare your variable to anything.

How to update style when a window is scaled in angular

I have a chat window on my app and I want to update the size of an image in this chat window when the chat window is less than a certain width. Is there a way I can update the css style or class based on the width?
I'm using typescript and have the value of my cat window passed in:
#Input()
public chatWidth: number;
In my html, I was attempting to do something like this where I would apply a css class if the chatWidth property was less than 400:
<img *ngIf="upsell?.image?.url; let url" [src]="url" ng-class="{bigger-img : chatWidth < 400}">
However, this doesn't work and I don't seem to even get an error in my console
Use
<img *ngIf="upsell?.image?.url; let url" [src]="url" [ngClass]="{'bigger-img': chatWidth < 400}">
More info here on ngClass.
UPDATE
You can, I believe, wrap the condition in a 'method' that returns a boolean defined in your respective component and call it in the template instead of directly declaring it in the template. Here, in your case,
in component.ts,
checkChatWidth(): boolean {
return this.chatWidth < 400;
}
then, in your template,
<img *ngIf="upsell?.image?.url; let url" [src]="url" [ngClass]="{'bigger-img': checkChatWidth()}">
You have to take care of the possible 'null' checks within your 'method' that may arise due to not having a value for the 'chatWidth' input property based on your code setup.

Adding a "news item" style thumbnail image to a Dexterity content type

I'm working on a listing page for a custom Dexterity content type, and I'd like to pull one of the images to display in the listing, kind of how a listing page for a folder full of news items shows the thumbnails alongside the title and description (i.e. folder_summary_view).
What's the best way to go about this? I tried customizing the folder_summary_view template to change the thumbnail code to look instead for 'item_object/thumbnail' however it returns an error because it's a blob image or something:
<a href="#" tal:condition="exists:item_object/thumbnail" tal:attributes="href python:test(item_type in use_view_action, item_url+'/view', item_url)">
<img src="" alt="" tal:replace="structure python: path('nocall:item_object/thumbnail')(scale='original', css_class='tileImage')" />
</a>
Returns:
Module Products.PageTemplates.ZRPythonExpr, line 48, in __call__
__traceback_info__: path('nocall:item_object/thumbnail')(scale='original', css_class='tileImage')
Module PythonExpr, line 1, in <expression>
TypeError: 'NamedBlobImage' object is not callable
I guess I'd also be interested in finding out how to call any of the other fields. It pulls the title and description automatically. Is there an easy way to call moar fields? i.e. if there's a text field called: developer_name — how would I display that after Title in the folder summary view?
I saw this question in case that helps, but it seemed to be more related to migration and not displaying content.
The folder_summary_view still needs to be updated for Plone's default news item, like this (works with both; Plone's default Archetype- and Dexterity-newsitem):
<a href="#"
tal:condition="exists:item_object/##images/image"
tal:attributes="href python:test(item_type in use_view_action, item_url+'/view', item_url)">
<img src="" alt=""
tal:replace="structure item_object/##images/image/mini" />
</a>
Where 'image' is the fieldname, in case yours differs.
See plone.app.imaging's README for complete reference.
I hope to find some time soon, to commit this, unless someone else is heading to do it ;)
Note: I think I remember it's not recommended to use python:test() though, maybe that part should be adjusted, too.
For generally rendering your field, you can use good ol':
<div tal:content="structure context/developer_name" />
Tested with a TTW-created Dexterity-CT and a text-field.
See also (with a grokked example):
http://developer.plone.org/reference_manuals/external/plone.app.dexterity/custom-views.html#simple-views
if you look closely to the folder_summary_view template you will find that all you need to do is adding some helper methods to you class:
<a href="#"
tal:condition="exists:item_object/image_thumb"
tal:attributes="href python:test(item_type in use_view_action, item_url+'/view', item_url)">
<img src="" alt=""
tal:replace="structure python: path('nocall:item_object/tag')(scale='thumb', css_class='tileImage')" />
</a>
we did something similar in collective.nitf by creating a getImage, imageCaption, tag and image_thumb functions (you probably won't need them all).
also, note the image attribute that will map the getImage function.
class NITF(Container):
implements(INITF)
...
# The purpose of these methods is to emulate those on News Item
def getImage(self):
"""Return the first Image inside the News Article."""
content_filter = {'portal_type': 'Image'}
images = self.listFolderContents(content_filter)
return images[0] if len(images) > 0 else None
image = getImage # XXX: a hack to support summary_view
def imageCaption(self):
image = self.getImage()
if image is not None:
return image.Description()
def tag(self, **kwargs):
# tag original implementation returns object title in both, alt and
# title attributes
image = self.getImage()
if image is not None:
scales = image.restrictedTraverse('##images')
if 'scale' in kwargs:
scale_id = kwargs.get('scale')
del kwargs['scale']
else:
scale_id = 'thumb'
kwargs['alt'] = image.Description()
kwargs['title'] = image.Title()
scale = scales.scale(fieldname='image', scale=scale_id)
return scale.tag(**kwargs)
def image_thumb(self):
"""Return a thumbnail."""
image = self.getImage()
if image is not None:
view = image.unrestrictedTraverse('##images')
# Return the data
return view.scale(fieldname='image', scale='thumb').data
take a look at that code.

Resources