html5smartimage : Using pathfield as source of image , by disabling drap-drop - adobe

I would like to use html5smartimage widget without letting the users upload images from their desktop and also avoid using the contentfinder. I created a dialog with a pathfield and a html5smartimage inputs. I have set the "allowUpload" to false. I want the user to input/pick the image using the pathfield component and then use it as source image reference to render the image in the html5smartimage widget. I have not been successful so far and any help/hint would be appreciated :). Here is what I have tried so far :
set the same "name" value to the pathfield and the fileReferenceParamter , hoping to pick up the users pathfield input into the smartimage, but the POST results two "./srcImageReference" parameters to be sent resulting in a pathfield change to a String [] on jcr node, thus concatenation of same paths each time.
I have gone through widgets.js to find a usable event function that gets called when a drap-drop is done , so I can simulate a similar one with the value from the pathfield, but I could not find any ..
Is extending the smartimage component and overriding the default drap-drop handlers the only option ? if so how do I go about it .
thanks
Viper

The html5smartimage has a handleDrop( Object dragData ) method that is called when an image is dragged and dropped over it. We can call this from the dialogselect event of the pathfield.
In essence it's like faking a drag-drop. The dragData has a lot of fields but all that matters in this case is the image path and name (source : console.log()s in the handleDrop method ). So on when an image path is selected in the pathfield, use it's path and create hoax dragData object and call the image's handleDrop method.
function(pathfield,path,anchor){
var dialog = pathfield.findParentByType('dialog');
var image = dialog.findByType('html5smartimage')[0];
var pathArray = path.split('/');
var imageName = pathArray[(pathArray.length-1)];
var fakeDragData = {};
var fakeRecord = {};
fakeRecord.path = path;
fakeRecord.name = imageName;
fakeRecord.get = function(name){ return this[name]; };
fakeDragData.records = new Array(fakeRecord);
fakeDragData.single = true;
image.handleDrop(fakeDragData);
}
This way all of the images data is stored on node by the html5smart image widget itself, you will not need to read the value of pathfield in your jsp at all.

If you just want to use the html5smartimage to preview the image selected in the pathfield you can try something like this :
Instead of html5smartimage use a regular panel and use its html property to display the image in the panel. The panel's body.update() method can be called from listeners in the pathfield with markup up to create a preview image.
<tab1 jcr:primaryType="cq:Panel" title="Tab 1">
<items jcr:primaryType="cq:WidgetCollection">
<ImagePathField jcr:primaryType="cq:Widget" fieldLabel="Select Image"
name="./imagePath" rootPath="/content/dam" xtype="pathfield">
<listeners jcr:primaryType="nt:unstructured"
dialogselect="function(pathfield,currentpath,anchor) {
//dialogselect event - fired when a selection
//is made using pathfield's browse dialog
//get the sibling panel through the pathfield
var previewPanel = pathfield.nextSibling();
//update the html property of panel to contain the
//image selected in the pathfield using panel body's update method
previewPanel.body.update('<img style="max-width: 100%;display: block;
margin-left:auto;margin-right:auto;"
src="'+currentpath+'"/>');
}"
loadcontent="function(pathfield,record,path){
//preview the image when dialog is opened for the first time
var previewPanel = pathfield.nextSibling();
if(pathfield.getValue() != '')
previewPanel.body.update('<img style="max-width: 100%;display: block;
margin-left:auto;margin-right:auto;"
src="'+pathfield.getValue()+'"/>');
}"/>
</ImagePathField>
<previewPanel jcr:primaryType="cq:Widget" fieldLabel="Preview Pane"
height="250" html="No image to preview" xtype="panel"/>
</items>
</tab1>

Related

How to attach a callback to a custom confirmation dialog in Google App Maker?

I am creating a custom confirmation dialog in Google App Maker and would like the Confirm button to call a passed-in function. I don't see an "onclick" event in the button widget. Any suggestions on how to do this?
function confirmationDialog(msg, confirmFunction)
{
var desc = app.pageFragments.ConfirmationDialog.descendants;
var label = desc.Label;
var confirmButton = desc.Confirm;
label.text = msg;
confirmButton.onClick = confirmFunction; // does not work
app.showDialog(app.pageFragments.ConfirmationDialog);
}
Thanks
It'd be great if this was a bit easier, but the best bet is to use Custom Properties (https://developers.google.com/appmaker/ui/viewfragments).
You can set up a custom property of type "Dynamic" and call it anything, take "onConfirmCallback", for example. Then you can set the function on that custom property:
Code to invoke dialog:
app.pageFragments.ConfirmationDialog.properties.onConfirmCallback = function(param) {
alert(param);
};
app.showDialog(app.pageFragments.ConfirmationDialog);
And then in the onClick for the close button:
app.pageFragments.ConfirmationDialog.properties.onConfirmCallback("hi");
app.closeDialog();
Also note that there are slightly better ways to set up labels than in your example, also using custom properties.
Create custom properties for any widget properties you want to customize, and then bind those custom properties (#properties.propertyName) to the widget property. For example you might have a confirmText property, with the confirm buttons text property boudn to #properties.confirmText.
Then when you invoke your dialog, you can just set those custom properties. Quick modification of your example code using properties for everything:
function confirmationDialog(msg, confirmFunction)
{
var properties = app.pageFragments.ConfirmationDialog.properties;
properties.text = msg;
properties.confirmCallback = confirmFunction;
app.showDialog(app.pageFragments.ConfirmationDialog);
}
For my confirmation dialogs, I just set the onclick of the OK button before I show the dialog (everything is in one place, which is easier for the dummy (me) who will have to maintain it in six months:
var dialog=app.pages.ConfirmationDialog;
dialog.descendants.message.text='Are you sure...?'
dialog.descendants.btnOk.getElement().onclick=function(){
//do something here
app.closeDialog();
});
};
app.showDialog(dialog);
}

Adobe Air Mobile + Camera - Retaining image

I have a page that displays data about an object. At the top of the page is room for an icon, showing a picture of that object. Tapping this icon brings up a new page that allows the user to take a new picture, and save it as a temporary new picture for the object (not put in database, but should persist for the session)
Initial page:
private var source:Object = new Object();
protected function onInitialize():void {
source = navigator.poppedViewReturnedObject;
}
When setting source for the image later...
if (source != null) {
pic.source = source.object;
}
else {
pic.source = "no_picture_available_image.png";
}
2nd Page (User can take picture, and view new picture):
[Bindable]
private var imageSource:Object = null;
<s:Image id="pic" width="90%" height="75%" horizontalCenter="0" source="{imageSource}" />
After taking picture...
protected function mediaPromiseLoaded(evt:Event):void {
var loaderInfo:LoaderInfo = evt.target as LoaderInfo;
imageSource = loaderInfo.loader;
}
This does show the picture just taken correctly on this page.
To get back to old page, i use navigator.popView, and use:
override public function createReturnObject():Object {
return imageSource;
}
Unfortunately, it doesn't work. The imageSource isn't null when it is read from navigator.poppedViewReturnedObject, but no image is shown.
Does the LoaderInfo not persist after popping the view? Are the camera pics not automatically saved? I can't find answers to any of these questions, and I can't debug using the phone in my current environment.
After thinking about this a bit, don't return LoaderInfo.loader as the poppedViewReturnedObject. If I remember correctly, a DisplayObject can only be set as the source of one Image. Instead, return LoaderInfo.loader.content.bitmapData. That BitmapData should be the raw data used to display the image. This data can be used repeatedly to create images and can be set as the source of an Image.
Problem turned out to be in my first page's image declaration - I didn't set a width. Seemingly, the object being displayed couldn't handle not having a specified width.
Note that passing back the loader did work fine.

Widget dialogue that creates new nodes - Adobe CQ5

I'm trying to create an edit widget for a page that asks for various details and then stores those details as properties of a newly created node.
So for instance:
Make
Model
Mileage
and I want to store those as a node under a parent node in /content/cars or something similar.
How can I get a widget to create a new node under /content/cars and store those properties there?
Do I have to send the data to a servlet that I create? Or are there options to enable this?
What you'd probably want to do is include a component in the containing page at the path you want the nodes created.
For example, if you have a page /content/cars, and you wanted to create a Chevy node under there at /content/cars/jcr:content/chevy, you'd include the component with this fragment:
<cq:include path="chevy" resourceType="myapp/components/manufacturer" />
This would include the content and render it and allow it to be edited with the component located at /apps/myapp/components/manufacturer.
If you want you can even have the node be at an absolute path, for example if you want to reference the content at /content/data/cars/chevy on another page you could use:
<cq:include path="/content/data/cars/chevy" resourceType="myapp/components/manufacturer" />
Based on the provided cheatsheet from Adobe:
http://dev.day.com/content/ddc/blog/2008/07/cheatsheet/_jcr_content/par/download/file.res/cheatsheet.pdf
The default Sling POST servlet recognizes what JCR properties to update by examining the 'name' attribute of the input tags that are included in the ExtJS dialogs. To configure a widget like a textfield or dropdownfield to target and update a specific property, you will need to specify the property's name in the widget definition.
For example, if you are using an XML file to define your page dialog at /content/cars and you wished for there to be widgets that let users store model, make, and year to the jcr:content node of the cars page. Your associated dialog definition would contain nodes that look like:
<make
jcr:primaryType="cq:Widget"
xtype="textfield"
name="./make"/>
<model
jcr:primaryType="cq:Widget"
xtype="textfield"
name="./model"/>
<year
jcr:primaryType="cq:Widget"
xtype="textfield"
name="./year"/>
To change the widget type you would adjust the xtype attribute and to change the property to target you would adjust the name attribute. Note that it is relative from the content node of the page/component where the dialog is being invoked (in this case, relative from /content/cars/jcr:content).
Another example: say you wanted to store the value of make to a property called 'make' on a node like /content/cars/jcr:content/brands, then your definition would look like:
<make
jcr:primaryType="cq:Widget"
xtype="textfield"
name="./brands/make"/>
For a reference on available xtypes, check out:
http://dev.day.com/docs/en/cq/current/widgets-api/index.html
Try this :
Add this js function to your pages
function doOpenDlg(url, path) {
var d = CQ.WCM.getDialog(url);
var reloadPage = true;
if(d) {
if( reloadPage ) {
d.success = function(form, action) {
CQ.Util.reload(CQ.WCM.getContentWindow());
};
}
d.show();
d.loadContent(path);
}
}
and then create a dialog like file. In this exemple :
/apps/myapp/components/page/mypage/myxmlfile.xml
then you can open a dialog matching this file with :
<input type="button" value="Open my dialog" style="font-size: 14px;font-weight: bold;"
onclick="doOpenDlg('/apps/myapp/components/page/mypage/myxmlfile.infinity.json', '<%=currentNode.getPath() %>');" />
with this, your dialog data will be saved in the currentNode, but you can put any path you want.

Anguilla - Updating a field's value from a popup?

I have a modal popup that appears whenever an editor tries to save a component with some values (a date field in the past in this case).
In this popup I show the editor a few options (very similar to the default "Open Shared Item" dialog) and an OK/Cancel button combo. On Cancel I fire the "cancel" event and the editor goes back to the editing screen, all good here. On "OK" I want to change the value of the field to match whatever the editor selected, then save.
I tried to use an approach with FieldBuilder and the sample Boris mentioned on this other topic but I can't get to the field from my popup dialog.
Any suggestions on how I can go and modify the xml of the item (could be also a page) from a modal popup?
EDIT: Code used in getControlForFieldName
function getControlForFieldName(name) {
var fieldBuilder = $display.getView().properties.controls.fieldBuilder;
var fieldsContainer = fieldBuilder.properties.input;
var fieldsNode = fieldsContainer.getElement();
var fieldContainer = $dom.getFirstElementChild(fieldsNode);
while (fieldContainer) {
var labelNode = $dom.getFirstElementChild(fieldContainer);
var fieldNode = $dom.getNextElementSibling(labelNode);
var control = fieldNode.control;
if (control.getFieldName() == name) {
return control;
}
fieldContainer = $dom.getNextElementSibling(fieldContainer);
}
}
EDIT #2
After Frank's advice, and some help from Jaime & Frank offline, I got it to work as follows:
The popup is called from a Command Extension (Save & Close in my case)
The command.js specifies an event handler that gets called on "submit" (== OK was pressed)
$evt.addEventHandler(p.dialogPopup, "submit",
this.getDelegate(this._onPopupSubmit));
In my popup I am passing the selected item (it's a keyword ID) to the event handler:
this.fireEvent("submit", { id: select.options[select.selectedIndex].value });
and now back in the event handler _onPopupSubmit(e) I just read e.data.id, load this keyword, get properties like ID & Title, and update the metadata of the item using item.setMetadata("new metadata with updated values").
Simple :)
Your code runs in a popup, so any references you make to global variables will be taken from the popup window.
So when you get the fieldBuilder:
var fieldBuilder = $display.getView().properties.controls.fieldBuilder;
$display is a reference to a global variable. So this actually looks for the FieldBuilder in the popup window (which doesn't have one).
To get the FieldBuilder of the Component window, you can get it from the opener:
var fieldBuilder = opener.$display.getView().properties.controls.fieldBuilder;
You might want to consider actually passing the updated value to either a callback function or with a (custom) event though, since that makes your popup less dependent on opener. trick.

Flex 3: Is it possible to use a remote image as the icon for a LinkButton?

We are creating a LinkButton programmatically and would like to set it's icon to an image retrieved from the remote server rather than something embedded within the SWF. The .icon property expects a Class but I can't figure out how to create one equivalent to an #Embed but from a dynamically generated URLRequest or URL String.
var myImage:Image = new Image();
myImage.source = "http://www.domain.com/img/1234.png";
myImage.width = 16;
myImage.height = 16;
myImage.scaleContent = true;
var myButton:LinkButton = new LinkButton();
myButton.label = "Some text"
// This is what I'm trying to figure out.
myButton.setStyle("icon", ???)
I'm probably missing something obvious - I've tried passing in the URL and myImage separately but both throw errors. Stepping into the setStyle() method shows that the code is expecting a Class - so what do I pass in place of the ???
I can't embed the image itself because it's dynamic - the URL is different each time the software runs.
Thanks for any assistance!
Why not just set the buttonMode of a mx:Image to true then add a click event?
<mx:Image source="{imageSource}" buttonMode="true" click="action()" />
I'm not sure its possible without using an embedded images with a linkButton
This might be worth a read
Edit... in AS3:
var img:Image = new Image();
img.source = "...";
img.buttonMode = true;
img.addEventListenever(MouseEvent.CLICK, funcName);
I think that instead of trying to set the style, you need to change the child object that holds the icon. You can access it by something like:
Var:Bitmap icon = myButton.getChildByName("upIcon") as Bitmap
It should be easy to replace the bitmapData in there with the one from a Loader.
If memory serves, you'll want to use button.setStyle('icon', img), where img is an image loaded via Loader class.
for laalto,
this may be too late of an answer but somebody might find it useful or as a starting point to a solution to your problem. Have you tried referencing your image icon as a class? I don't know if this will work for an image which is in a dynamic URL but this worked for me:
[Embed("assets/LinkButton.png")]
private const linkButtonIcon:Class;
Then in your code:
myButton.setStyle("icon", linkButtonIcon);
See this example here:
http://blog.flexexamples.com/2008/09/03/setting-the-icon-on-a-linkbutton-control-in-flex/
<mx:Button id="example" label="Example" icon="{IconUtility.getClass(example, 'http://www.exampledomain.com/image.jpg')}" />
http://blog.benstucki.net/?p=42

Resources