How to create button in context menu on component/page right click.
I tried to configure my extension.config file by refering as mentioned in "http://www.julianwraith.com/2010/10/helloworld-extension-for-tridion-2011/" but i was unable to see any button available.
Could anyone suggest me.
Check your configuration file (F:\Program Files (x86)\Tridion\customizations\HelloWorld\config\HelloWorld.config) for unclosed tags or some typo.
To create button in context menu:
Check that your HelloWorld.config extends contextmenu node
<ext:contextmenus>
<ext:add>
<ext:extension name="Hello World" assignid="" insertbefore="cm_preview">
<ext:menudeclaration>
<cmenu:ContextMenuItem id="HelloWorld" name="Hello World" command="HelloWorld"/>
</ext:menudeclaration>
<ext:dependencies>
<cfg:dependency>RandomStringThatNeedsToBeCompiled2</cfg:dependency>
</ext:dependencies>
<ext:apply>
<ext:view name="DashboardView"/>
</ext:apply>
</ext:extension>
</ext:add>
</ext:contextmenus>
Modify your helloworld.js to enable button only for Components
Common.Tridion.MVP.HelloWorld.prototype.isAvailable = function HelloWorld$isAvailable(selection)
{
var itemID = selection.getItem(0);
if ($models.getItemType(itemID) != $const.ItemType.COMPONENT) {
return false;
}
};
Don't forget to clear your cache
Related
I am using multifield of type pathfield in my dialog. To add new path field, user has to click Add Item link.
Is it possible to display at least one path field in the dialog by default (without clicking Add Item)?
Yes, it is possible. There was a similar question for which I have answered it here.
However, for future references, providing the answer here too.
You can listen to the loadcontent event fired by the Multifield after the content has been loaded and use the addItem() method.
<paths
jcr:primaryType="cq:Widget"
fieldLabel="Select Paths"
name="./paths"
xtype="multifield">
<fieldConfig
jcr:primaryType="nt:unstructured"
xtype="pathfield" />
<listeners
jcr:primaryType="nt:unstructured"
loadcontent="function(field, record)
{
if(record.get('paths') == undefined)
{
field.addItem(); field.doLayout();
}
}" />
</paths>
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.
I managed to get a new ribbon group by following the article mentioned in How to create the custom buttons horizontally one below the other in ribbon of Tridion
I'm now trying to get a Javascript running whenever something changes in the Gui (hiding/showing buttons).
I have this in the configuration:
<!-- In the cfg:groups part -->
<cfg:group name="ClientGuiMods.ContentGroup" description="">
<cfg:fileset>
<cfg:file type="script">/Scripts/CreateRibbonGroup.js</cfg:file>
</cfg:fileset>
<cfg:dependencies>
<cfg:dependency>Tridion.Web.UI.Editors.CME</cfg:dependency>
</cfg:dependencies>
</cfg:group>
<!-- In the ribbontoolbars add part -->
<ext:extension pageid="HomePage" name="Content" assignid="ContentGroupId">
<ext:group>~/Scripts/ContentGroup.ascx</ext:group>
<ext:dependencies>
<cfg:dependency>ClientGuiMods.ContentGroup</cfg:dependency>
</ext:dependencies>
<ext:apply>
<ext:view name="DashboardView">
<ext:control id="DashboardToolbar" />
</ext:view>
</ext:apply>
</ext:extension>
And this in the Javascript:
Type.registerNamespace("ClientGuiMods");
ClientGuiMods.ContentGroup = function ContentGroup(element)
{
console.log('RibbonGroupCreated');
Tridion.OO.enableInterface(this, "ClientGuiMods.ContentGroup");
this.addInterface("Tridion.Controls.RibbonItemsGroup", [element]);
};
I've tried different arguments for this.addInterface(), but it never gets called. Is this the correct way? Or is there maybe another way to get a script called on the Home ribbon toolbar?
I never really looked at the group as anything other than a container for commands (read buttons). So the only interface I used is Tridion.Cme.Command on the button JavaScript.
But I think what you are looking for is the ControlResource which you can specify in your ContentGroup.ascx.cs
using Tridion.Web.UI.Core;
using Tridion.Web.UI.Controls;
using Tridion.Web.UI.Core.Controls;
namespace ClientGuiMods
{
[ControlResources("ClientGuiMods.ContentGroup")]
public class ContentGroup : TridionUserControl
{
}
}
Now, you can use the Tridion.ControlBase interface in your JavaScript.
Type.registerNamespace("ClientGuiMods");
ClientGuiMods.ContentGroup = function ContentGroup(element) {
console.log('RibbonGroupCreated');
Tridion.OO.enableInterface(this, "ClientGuiMods.ContentGroup");
this.addInterface("Tridion.ControlBase", [element]);
};
ClientGuiMods.ContentGroup.prototype.initialize = function ContentGroup$initialize() {
// the control is initialized here, we can use the following properties now
var props = this.properties;
var controls = props.controls;
var container = this.getElement();
};
#Bart, I tried the solution, but couln't get that to work.
Digging a bit further in the Javascripts in chrome I found there is no hook to fire any extra Javascript as a RibbonGroup (correct me if I'm wrong).
I did however find a way to get to the 'HomePage' RibbonPage and get it to fire events from there.
The extra thing I need is a "c:pagetype='Homepage'" on the RibbonPage named HomePage in the DOM, which isn't there by default. This can be set by including a load event script at the end.
So now my script looks like this.
Type.registerNamespace("ClientGuiMods");
ClientGuiMods.CreateRibbonPage = function CreateRibbonPage(element)
{
Tridion.OO.enableInterface(this, "ClientGuiMods.CreateRibbonPage");
this.addInterface("Tridion.Controls.RibbonPage", [element]);
};
ClientGuiMods.CreateRibbonPage.prototype.updateState = function CreateRibbonPage$updateState(stateObject)
{
//...
//Ribbonpage logic to update the state of your buttons and groups
};
console.log('Homepage: ' + document.getElementById('HomePage')); //.setAttribute('c:pagetype', 'HomePage');
var ClientScripts = {
registerHomepage: function() {
console.log('adding c:pagetype att');
var homepage = document.getElementById('HomePage');
if (homepage) {
homepage.setAttribute('c:pagetype', 'HomePage');
}
}
}
if (document.addEventListener && !Tridion.Utils.Dom.isIE)
$evt.addEventHandler(window, "DOMContentLoaded", ClientScripts.registerHomepage);
else
$evt.addEventHandler(window, "readystatechange", ClientScripts.registerHomepage);
Tridion.Controls.Deck.registerPageType(ClientGuiMods.CreateRibbonPage, "HomePage");
I might be off mark here, but it sounds like you have a series of buttons under the same group, and you want to have them behave consistently in terms of availability.
I had a similar case where I need to fire the same event on Save, Save & Close and Save & New operations. What I ended up doing was to write the code as a Save command extension (broadly based off Jaime's details here) and then, from the SaveClose and SaveNew extensions I would call the Save._isEnabled and Save._isAvailable functions to determine whether my commands were available, and the Save._execute whenever the editors clicks on SaveClose & SaveNew.
Not as elegant as Peter's suggestion though, but got the job done.
I need to create buttons one below the other in tridion ribbon.
I have created an usercontrol and it was appearing on the ribbon but in disabled mode.
In the "http://tridiondeveloper.com/ribbon-item-group"; it was mentioned to include <ext:issmallbutton>true</ext:issmallbutton> inside my extension element in the configuration. I have included it in the extension.config file. But i am facing error like "Loading extension failed - has invalid child element 'issmallbutton'. So, currently i ignored this step and the buttons were in disabled mode.
Could you please let me understand where i need to add this.(<ext:issmallbutton>true</ext:issmallbutton> ) and to make the buttons enable.
As indicated by Jeremy's answer, you don't need the ext:issmallbutton to enable your button (you mention my article on Tridion Developer, where I specifically state that the ext:issmallbutton is not to be used when you want to stack buttons on top of eachother).
You probably should try to debug your JavaScript and see what is happening in your _isAvailable(selection, pipeline) and _isEnabled(selection, pipeline) methods.
The isAvailable method should indicate whether the command is applicable for the selected item(s) and the isEnabled method indicates whether the command can be executed. I usually just let the isEnabled method return the result of the isAvailable one (since when the button is available, it should most of the time also be enabled). An example of how to enable a button when you have selected a Page would look something like this:
Example.PageBtn.prototype._isAvailable = function PageBtn$_isAvailable(selection, pipeline) {
if (pipeline) {
pipeline.stop = false;
}
if (selection.getCount() == 1) {
var itemType = $models.getItemType(selection.getItem(0));
return itemType && (itemType == $const.ItemType.PAGE);
}
return false;
};
Example.PageBtn.prototype._isEnabled = function PageBtn$_isEnabled(selection, pipeline) {
if (pipeline) {
pipeline.stop = false;
}
return this._isAvailable(selection);
};
Now the ext:issmallbutton element has nothing to do with this all, but if you would like to know where that should be used exactly, it is supposed to go inside the ext:extensionelement like so:
<ext:extension assignid="PageBtn" groupid="MyGroup" name="Example" pageid="HomePage">
<ext:command>PageBtn</ext:command>
<ext:title>Example</ext:title>
<ext:issmallbutton>true</ext:issmallbutton>
<ext:dependencies>
<cfg:dependency>Example.Commands</cfg:dependency>
</ext:dependencies>
<ext:apply>
<ext:view name="DashboardView">
<ext:control id="DashboardToolbar" />
</ext:view>
</ext:apply>
</ext:extension>
You can find more information in Setting up a SDL Tridion 2011 GUI extension in 8 steps.
To enable a button you need its isEnabled method to return true. issmallbutton only determines the size of the button in the toolbar. For information on how to create a button extension please look at the many other questions on this same subject...
Know someone, how to create "Browse for folder" dialog in Adobe FLEX? And it is possible?
Thanx.
If it's an Air app you can do :
var f : File = new File;
f.addEventListener(Event.SELECT, onFolderSelected);
f.browseForDirectory("Choose a directory");
If it's a pure As3 app, you cannot Browse for folder, you can just browse for file via FileReference class.
in Web, for multiple file upload, (for single file upload, use FileRefernce)
private var _refAddFiles:FileReferenceList;
private function browse():void
{
_refAddFiles = new FileReferenceList();
var fileFilter:FileFilter=new FileFilter("*.jpg","*.jpg;*.jpeg;");
_refAddFiles.addEventListener(Event.SELECT, onSelectFile);
_refAddFiles.browse([fileFilter]);
}
<mx:Button click="browse"/>
This will work, and what you want to do after selection,
private function onSelectFile(event:Event):void
{
_arrUploadFiles = [ ];
if (_refAddFiles.fileList.length >= 1)
{
for (var k:Number = 0; k < _refAddFiles.fileList.length; k++)
{
_arrUploadFiles.push({ name: _refAddFiles.fileList[k].name,
file: _refAddFiles.fileList[k]});
}
}
}
This is a quick function set to create a nice folder browser in Flex:
private var file:File = new File();
private function pickFile(event:MouseEvent):void {
file.addEventListener(Event.SELECT, openFile);
file.browseForDirectory("Select folder...");
}
private function openFile(event:Event):void{
folderPath.text = file.nativePath;
}
The first function deals with the folder browser, the second one populates a text input with the full folder path.
Howto:
On the stage, create a simple mx:button and add a call to the pickFile() function for the click event:
<mx:Button click="{pickFile(event);}" />
Then, put also on the stage an mx:TextInput component, to show the folder path after selection:
<mx:TextInput id="folderPath" editable="false" />
This way you have a button to click in order to show the system folder browser, and a text input to show the full folder path after selection.
To improve the button look, you can embed a nice folder icon :-)
Just my 2c. :-)