--- myst: html_meta: "description": "" "property=og:description": "" "property=og:title": "" "keywords": "" --- # Exercise 6: Using A Pattern In A Z3C Form Widget ```{warning} This exercise requires a working buildout using a fork of the `collective.jstraining` package. ``` This exercise will go through adding a widget that checks the minimum size of an image before it is uploaded. You will be working in the `exercise6` directory of the `collective.jstraining` package. ## Add Your JavaScript File First off, in your `exercise6/static` directory, add a file named `script.js`. Use this file to do anything you would like to the page ```javascript /* global require, FileReader, Image */ require([ 'jquery', 'pat-base', ], function($, Base) { 'use strict'; Base.extend({ name: 'exercise6', trigger: '.pat-exercise6', parser: 'mockup', defaults: { minHeight: 200, minWidth: 200 }, init: function() { var that = this; that.$el.on('change', function(){ if(this.files.length === 0){ return; } var fr = new FileReader(); fr.onload = function() { var img = new Image(); img.onload = function() { if(img.width < that.options.minWidth || img.height < that.options.minHeight){ alert('Invalid image size. The image must be at least ' + that.options.minWidth + 'x' + that.options.minHeight + '.'); that.$el[0].value = ''; } }; img.src = fr.result; }; fr.readAsDataURL(this.files[0]); }); } }); }); ``` This pattern simply has `minWidth` and `minHeight` options and, when a file is selected for upload, will check to make sure it is a valid size. ## Register Static Resource Directory Next, let us register the static directory we just placed our script into. To register it, you need to add {term}`ZCML` registration for the static directory your script is in. Add this to the `exercise6/configure.zcml` file ```xml ``` ## Register JavaScript Resource Register our script as a JavaScript resource with Plone. In the `exercise6/profiles/default/registry.xml` file, add the following configuration to register your script. ```xml ++plone++exercise6/script.js ``` ## Create A Custom Widget Our custom widget will apply to all lead images. Add a file `widget.py` to your `exercise6` directory with the following contents: ```python from .interfaces import IExercise6Layer from .interfaces import IMinSizeImageWidget from plone.app.contenttypes.behaviors.leadimage import ILeadImage from plone.formwidget.namedfile.widget import NamedImageWidget from plone.namedfile.interfaces import INamedImageField from Products.CMFPlone.resources import add_resource_on_request from z3c.form.interfaces import IFieldWidget from z3c.form.util import getSpecification from zope.component import adapter from zope.interface import implementer from zope.interface import implements import json import z3c.form.widget class MinSizeImageWidget(NamedImageWidget): """A widget for a named file object """ implements(IMinSizeImageWidget) def pattern_options(self): # provide the pattern options return json.dumps({ 'minHeight': 300, 'minWidth': 300 }) def render(self): # add the registered resource add_resource_on_request(self.request, 'exercise6') return super(MinSizeImageWidget, self).render() @adapter(INamedImageField, IExercise6Layer) @implementer(IFieldWidget) def LeadImageMinSizeImageFieldWidget(field, request): widget = z3c.form.widget.FieldWidget(field, MinSizeImageWidget(request)) return widget ``` Notice in the `render` method we utilize the `add_resource_on_request` function to load our pattern. The code for `image_widget.pt` is already provided for this example since it is quite long. Review the file and notice where we are passing the value from the `pattern_options` method into our widget. ## Register Widget Customization Next, we need to register our custom widget so it is used. In your `configure.zcml` file, add the following ```xml ``` ## Installation 1. Start up your Plone instance 2. Install the `Exercise 6` add-on Now, try to add/edit a lead image to content on the site. ```{warning} To make sure your resource registry configuration changes apply, you will need to be in development mode. You can also toggle development mode on and off, click save, to force configuration to be re-built after changes instead of keeping development mode on. ```