In AEM 6.2 how to make image alt text field mandatory based on image field - aem

I have two fields in dialog, image field and image alt text field. My requirement is to make the "image alt text" field mandatory if image is authored. But if image is not authored, then "image alt text" should not be mandatory.
how can we achieve in AEM 6.2 touch ui?
<image
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/fileupload"
autoStart="{Boolean}false"
class="cq-droptarget"
fieldDescription=“Authored Image"
fieldLabel="Image"
fileNameParameter="./fileName"
fileReferenceParameter="./fileReference"
mimeTypes="[image]"
multiple="{Boolean}false"
name="./imagedragdrop"
title="Upload Image Asset"
uploadUrl="${suffix.path}"
useHTML5="{Boolean}true"/>
<imageAltText
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription=“Image alt text"
fieldLabel="Image Alt Text"
name="./imageAltText"/>

Here is a simple way to achieve this:
When the file upload widget is authored, it will have the class is-filled and when it's not authored, it will not have that class.
First:
We need to give both fields a special selector, I'm going with ID's:
Add the property id="file-upload-special" to your file upload dialog widget
Add the property id="alt-special" to your alt text (textfield) widget
Second:
Create a clientlib with the following categories="[cq.authoring.dialog]"
Third:
Add the following js to the clientlib:
// register a validator
$(window).adaptTo("foundation-registry").register("foundation.validation.validator", {
selector: "#alt-special", // validates the specific alt field
validate: function(el) {
var $el = $(el);
var $form = $el.closest('form'); // get the form
var $upload = $form.find('#file-upload-special'); // find the file-upload widget
if($upload.hasClass('is-filled') && !$el.val()){ // if class exists, return validation msg
return 'this field is required';
} else {
return;
}
}
});
now the alt field should only be validated if the file-upload is authored.

Related

Adding buttons to the interface

I'd like add a button and let performers to copy some text to their clipboard once they click on the button. However, I found:
the element interface { {button}} does not accept an "on-click" property
the original html button tag may work, but when I add the the function to the on_click property and the js section, the page returns the error "the function does not found".
So, my question is, how I can add a user defined js function to a project? Is there any example code/project I can reference to?
Try to add the following code in TASK INTERFACE in your project:
<div>
{{field type="input" name="whatever" value=link size="L" width="70%"}}
{{button label="Copy text to clipboard" href="#" size="L"}}
</div>
<textarea class="hiddenInput"></textarea>
in onRender() in JS field:
onRender: function() {
var _document = this.getDOMElement(),
button = _document.querySelector('.button'),
hiddenInput = _document.querySelector('.hiddenInput'),
task = this;
button.addEventListener('click',function (e) {
e.preventDefault();
hiddenInput.value = task.getTask().input_values.link;
/*hiddenInput.focus();*/
hiddenInput.click();
hiddenInput.select();
document.execCommand('copy');
button.classList.add('button_disabled');
button.querySelector('.button__label').textContent = 'Done';
setTimeout(function () {
button.classList.remove('button_disabled');
button.querySelector('.button__label').textContent = 'Copy text to clipboard';
},1000)
})
},

How to filter tags in a component dialog. Adobe CQ

I am trying to filter the tags in a component dialog. I know that I can filter it by namespace, however that applies only to root level. Can I filter the tag selection one level deeper?
for example:
etc
tags
namespace
article-type
blog
news
asset-type
image
video
I want to filter the tags in the component dialog so the user can only select the tags under 'article-type'.
Thanks,
Yes and no. Officially you can go deeper according to the widget API, but there is a "bug" in the Widget JavaScript file that prevents it to work. I had the same issue and I just overwrite this JavaScript file.
Widget definition:
<article jcr:primaryType="cq:Widget"
fieldLabel="Article Type"
name="./cq:tags"
tagsBasePath="/etc/tags/namespace"
xtype="tags">
<namespaces jcr:primaryType="cq:WidgetCollection">
<ns1 jcr:primaryType="nt:unstructured" maximum="1" name="article-type" />
</namespaces>
</article>
<asset jcr:primaryType="cq:Widget"
fieldLabel="Asset Type"
name="./cq:tags"
namespaces="[asset-type]"
tagsBasePath="/etc/tags/offering"
xtype="tags"/>
In this case only one Tag below article-type can be selected; you can limit the number with the maximum attribute. The asset-type has no limits. So choose the option that suits your need.
JavaScript overwrite:
To make this work, you need to change the method CQ.tagging.parseTag in /libs/cq/tagging/widgets/source/CQ.tagging.js:
// private - splits tagID into namespace and local (also works for title paths)
CQ.tagging.parseTag = function(tag, isPath) {
var tagInfo = {
namespace: null,
local: tag,
getTagID: function() {
return this.namespace + ":" + this.local;
}
};
var tagParts = tag.split(':');
if (tagParts[0] == 'article-type' || tagParts[0] == 'asset-type') {
var realTag = tagParts[1];
var pos = realTag.indexOf('/');
tagInfo.namespace = realTag.substring(0, pos).trim();
tagInfo.local = realTag.substring(pos + 1).trim();
}
else {
// parse tag pattern: namespace:local
var colonPos = tag.indexOf(isPath ? '/' : ':');
if (colonPos > 0) {
// the first colon ":" delimits a namespace
// don't forget to trim the strings (in case of title paths)
tagInfo.namespace = tag.substring(0, colonPos).trim();
tagInfo.local = tag.substring(colonPos + 1).trim();
}
}
return tagInfo;
};

How add mandatory dropdown field in Touch UI

I added "required" as "true" but it is not working. "required" as "true" only works for text field.
As per below document, I do not see any option to add mandatory field from dropdown.
http://docs.adobe.com/docs/en/aem/6-0/author/assets/managing-assets-touch-ui/managing-asset-schema-forms.html
How is it possible to achieve this?
Use $.validator.register to register custom validators.
I have written a detailed blog post on writing custom validators: http://www.nateyolles.com/blog/2016/02/aem-touch-ui-custom-validation.
I have made a comprehensive Touch UI validation library available on GitHub that fixes the issue you described where the "required" property doesn't work for several Granite UI fields as well as other functionality. See https://github.com/nateyolles/aem-touch-ui-validation.
Essentially, you need to modify the field's HTML to include an HTML input that can be validated by either overlaying the foundation component or using JavaScript to modify the DOM when the dialog opens. A hidden input is not eligible for validation, so you need to add a text input hidden by CSS. Use JavaScript to update the "hidden" field when the component action is updated. For example, a color is chosen in the color picker.
Then you register the custom validator against the non-visible text input. Pass in the selector of the non-visible text field and the function that does the actual validation. Also pass in functions for show and clear that show and hide the error message/icon.
The following example is for the color picker taken from the library I linked to above:
/**
* Validation for Granite Touch UI colorpicker.
*
* Additional properties for granite/ui/components/foundation/form/colorpicker
* are:
*
* {Boolean}required
* Is field required
* defaults to false
*
* <myColorPicker
* jcr:primaryType="nt:unstructured"
* sling:resourceType="granite/ui/components/foundation/form/colorpicker"
* fieldLabel="My colorpicker"
* name="./myColorPicker"
* required="{Boolean}true"/>
*/
var COLORPICKER_SELECTOR = '.coral-ColorPicker',
$.validator.register({
selector: '.marker-colorpicker',
validate: function(el) {
var field,
value,
required;
field = el.closest(".coral-Form-field");
value = el.val();
required = field.data('required');
if (required && !value) {
return Granite.I18n.get('Please fill out this field.');
} else {
el.setCustomValidity(null);
el.updateErrorUI();
}
},
show: function (el, message) {
var fieldErrorEl,
field,
error,
arrow;
fieldErrorEl = $("<span class='coral-Form-fielderror coral-Icon coral-Icon--alert coral-Icon--sizeS' data-init='quicktip' data-quicktip-type='error' />");
field = el.closest('.coral-Form-field');
el.add(field)
.attr('aria-invalid', 'true')
.toggleClass('is-invalid', true);
field.nextAll('.coral-Form-fieldinfo')
.addClass('u-coral-screenReaderOnly');
error = field.nextAll('.coral-Form-fielderror');
if (error.length === 0) {
arrow = field.closest('form').hasClass('coral-Form--vertical') ? 'right' : 'top';
fieldErrorEl.clone()
.attr('data-quicktip-arrow', arrow)
.attr('data-quicktip-content', message)
.insertAfter(field);
} else {
error.data('quicktipContent', message);
}
},
clear: function(el) {
var field = el.closest('.coral-Form-field');
el.add(field)
.removeAttr('aria-invalid')
.removeClass('is-invalid');
field.nextAll('.coral-Form-fielderror').tooltip('hide').remove();
field.nextAll('.coral-Form-fieldinfo').removeClass('u-coral-screenReaderOnly');
}
});
/**
* Create hidden field to validate against and click event handler when a
* Granite UI dialog loads.
*/
$(document).on('foundation-contentloaded', function(e) {
var $dialog,
$radioGroups;
$dialog = $(e.target);
$radioGroups = $dialog.find(COLORPICKER_SELECTOR);
$radioGroups.each(function() {
var $radioGroup,
required,
$marker,
$button;
$radioGroup = $(this);
required = $radioGroup.data('required');
if (required) {
$marker = $radioGroup.find('input[type="hidden"]');
$button = $radioGroup.find('.coral-ColorPicker-button')
/* Change to text as hidden is not validated */
$marker.attr('type', 'text');
$marker.addClass('marker-colorpicker');
$marker.attr('aria-required', 'true');
/* revalidate once the button color has changed */
$button.on('stylechange', function(){
$marker.trigger('change');
});
}
});
});
AFAIK, In touch ui dialogs you can apply such validation via jquery. One thing you can try. Create a clientlib folder under component with categories cq.authoring.dialog . Then add the below js snippet as per normal process :
(function (document, $, ns) {
"use strict";
$(document).on("click", ".cq-dialog-submit", function (e) {
e.stopPropagation();
e.preventDefault();
var $form = $(this).closest("form.foundation-form"),
title = $form.find("[name='authoringMode']").val(),
message, clazz = "coral-Button ";
if(!title){
ns.ui.helpers.prompt({
title: Granite.I18n.get("Invalid Input"),
message: "Please Check Values",
actions: [{
id: "CANCEL",
text: "CANCEL",
className: "coral-Button"
}
],
callback: function (actionId) {
if (actionId === "CANCEL") {
}
}
});
}else{
$form.submit();
}
});
})(document, Granite.$, Granite.author);
One thing here you need to change is $form.find("[name='authoringMode']") here name is the property and authoringMode is the value of select box in my dialog. as shown.
Here it will check at dialog submit time whether there is value in drop down and will not let author to submit the dialog till drop-down is blank.
Here is the reference.
http://experience-aem.blogspot.in/2015/02/aem-6-sp2-touch-ui-dialog-before-submit.html

How can I reset an image property to blank/null when changing another select in a dialog?

I need to remove the image and hide its label in the dialog when a value is selected from another dropdown. I also want to remove the image from the component itself.
Currently, I am able to hide the image in the dialog, but the image is not removed and is passed to the JSP file. I am using html5smartimage as xtype.
This is the dialog.xml code:
<imagepath jcr:primaryType="cq:Widget"
ddGroups="[media]"
fieldDescription="Best display supported image for large (400 x 270px)
and for small(260 x 193px)."
fieldLabel="Thumbnail Image"
fileReferenceParameter="./thumbnail"
height="200"
id="thumbnail"
name="./bkgimage"
rootPath=""
width="150"
xtype="html5smartimage"/>
Here's the JavaScript function:
function(comp) {
var panel = comp.findParentByType("panel");
var thumbnail = panel.getComponent("thumbnail");
var dropdown = panel.findById("height");
var width = panel.findById("width");
var thumbnailAltText = panel.findById("thumbnailAltText");
if (dropdown.getValue() == 'half-height') {
thumbnail.hide();
thumbnailAltText.hide();
thumbnail.setValue(' ');
} else {
thumbnail.show();
thumbnailAltText.show();
}
}

jeditable showing placeholder text in edit textbox

I have an issue with jeditable and trying to customize the style of the placeholder text.
$(".labeledit").editable("....", {
event: "click",
onblur: "submit",
width:($(".labeledit").width() + 40) + "px",
placeholder: "<span class='placeholder'>add label</span>",
tooltip: "Click to update"
});
In the placeholder text I add a span and associate a class. This works fine in the view but when I click on the add label text it places the placeholder text into the textbox so I get
<span class='placeholder'>add label</span>
appearing in the textbox.
If I just have placeholder: "add label" then the add label text doesn't show in the textbox.
What am I doing wrong?
Here it is! Instead of:
...
placeholder: "<span class='placeholder'>add label</span>",
...
try switching the quote marks:
...
placeholder: '<span class="placeholder">add label</span>',
...