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...
Related
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 am customizing the ribbon tool bar by adding a button to it in TRIDION 2011 SP1 version.
When I click on the button it will open an aspx page.Inside that aspx page I need to access the name of the schema used to create that component before creating the component itself(I mean to say while creating the component itself).
Please provide me a way to solve this issue. Thanks in advance.
You should pass it to your popup. The URI of the Schema is available on the Component model object within the CME - so your button command can access it and pass it to the popup (in the URL, for example).
var schemaId = $display.getView().getItem().getSchemaId();
If you have the component (as an object), you can get it's schema id as Peter indicated. If you only have the component id, you can load the component and through that get to the schema.
When you need to load any item, you have to be aware that it's not a synchronous call in the UI API, so you should use delegate methods for that. For example something like this:
Example.prototype._loadItemInformation = function Example$_loadItemInformation(itemId, reload) {
var item = $models.getItem(itemId);
if (item) {
var self = this;
function Example$_loadItemInformation$_onItemLoaded() {
$evt.removeEventHandler(item, "load", Example$_loadItemInformation$_onItemLoaded);
// proceed with the actions on the loaded item here
};
if (item.isLoaded(true) && !reload) {
Example$_loadItemInformation$_onItemLoaded();
}
else {
$evt.addEventHandler(item, "load", Example$_loadItemInformation$_onItemLoaded);
//$evt.addEventHandler(item, "loadfailed", Example$_loadItemInformation$_onItemLoadFailed);
item.load(reload, $const.OpenMode.VIEW);
}
}
};
Also be aware the item could fail loading, you should actually also register an event handler for loadfailed (as my example code neglects to do).
I have a partial view that is rendered within a main view. The partial view takes advantage of System.ComponentModel.DataAnnotations and Html.EnableClientValidation().
A link is clicked, and div containing the partial view is displayed within a JQuery.Dialog().
I then click the save button without entering any text in my validated input field. This causes the client side validation to fire as expected, and display the '*required' message beside the invalid field.
When the cancel button is clicked, I want to reset the client side MVC validation back to it's default state and remove any messages, ready for when the user opens the dialog again. Is there a recommended way of doing this?
This answer is for MVC3. See comments below for help updating it to MVC 4 and 5
If you just want to clear the validation-messages so that they are not shown to the user you can do it with javascript like so:
function resetValidation() {
//Removes validation from input-fields
$('.input-validation-error').addClass('input-validation-valid');
$('.input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('.field-validation-error').addClass('field-validation-valid');
$('.field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
}
If you need the reset to only work in your popup you can do it like this:
function resetValidation() {
//Removes validation from input-fields
$('#POPUPID .input-validation-error').addClass('input-validation-valid');
$('#POPUPID .input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('#POPUPID .field-validation-error').addClass('field-validation-valid');
$('#POPUPID .field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('#POPUPID .validation-summary-errors').addClass('validation-summary-valid');
$('#POPUPID .validation-summary-errors').removeClass('validation-summary-errors');
}
I hope this is the effect you seek.
If you are using unobtrusive validation that comes with MVC you can simply do:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).find(".field-validation-error").empty();
$(this).trigger('reset.unobtrusiveValidation');
});
};
------------------------------------------------------------------------
Third Party Edit:
This mostly worked in my case, but I had to remove the $(this).find(".field-validation-error").empty(); line. This appeared to affect the re-showing of the validation messages when resubmitting.
I used the following:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).trigger('reset.unobtrusiveValidation');
});
};
and then called it like this:
$('#MyFormId input').clearErrors();
function resetValidation() {
$('.field-validation-error').html("");
}
You can simply define a new function in jQuery:
$.fn.resetValidation = function () {
$(this).each(function (i, e) {
$(e).trigger('reset.unobtrusiveValidation');
if ($(e).next().is('span')) {
$(e).next().empty();
}
});
};
and then use it for your input fields:
$('#formId input').resetValidation();
Thank you. I had a similar question for a slightly different scenario. I have a screen where when you click one of the submit buttons it downloads a file. In MVC when you return a file for download, it doesn't switch screens, so any error messages which were already there in the validation summary remain there forever. I certainly don't want the error messages to stay there after the form has been submitted again. But I also don't want to clear the field-level validations which are caught on the client-side when the submit button is clicked. Also, some of my views have more than one form on them.
I added the following code (thanks to you) at the bottom of the Site.Master page so it applies to all of my views.
<!-- This script removes just the summary errors when a submit button is pressed
for any form whose id begins with 'form' -->
<script type="text/javascript">
$('[id^=form]').submit(function resetValidation() {
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
});
</script>
Thanks again.
You can tap into the validation library methods to do this.
There are two objects of interest: FormContext and FieldContext. You can access the FormContext via the form's __MVC_FormValidation property, and one FieldContext per validated property via the FormContext's fields property.
So, to clear the validation errors, you can do something like this to a form:
var fieldContexts = form.__MVC_FormValidation.fields;
for(i = 0; i < fieldContexts.length; i++) {
var fieldContext = fieldContexts[i];
// Clears validation message
fieldContext.clearErrors();
}
// Clears validation summary
form.__MVC_FormValidation.clearErrors();
Then, you can hook that piece of code to whichever event you need.
Sources for this (quite undocumented) insight:
http://bradwilson.typepad.com/presentations/advanced-asp-net-mvc-2.pdf (Mentions FieldContext)
https://stackoverflow.com/a/3868490/525499 (For pointing out this link, which metions how to trigger client-side validation via javascript)
In order to complete clear the validation artifacts including the message, the coloured background of the input field, and the coloured outline around the input field, I needed to use the following code, where this was (in my case) a Bootstrap modal dialog containing an imbedded form.
$(this).each(function () {
$(this).find(".field-validation-error").empty();
$(this).find(".input-validation-error").removeClass("input-validation-error");
$(this).find(".state-error").removeClass("state-error");
$(this).find(".state-success").removeClass("state-success");
$(this).trigger('reset.unobtrusiveValidation');
});
Here you can use simply remove error message
$('.field-validation-valid span').html('')
OR
$('.field-validation-valid span').text('')
I've this issue for "Validation summery" after form ajax submit and done it like this:
$form.find('.validation-summary-errors ul').html('');
and complete code is:
$("#SubmitAjax").on('click', function (evt) {
evt.preventDefault();
var $form = $(this).closest('form');
if ($form.valid()) {
//Do ajax call . . .
//Clear validation summery
$form.find('.validation-summary-errors ul').html('');
}
});
I am trying to disable validators using jquery.
I have already looked
Disable ASP.NET validators with JavaScript
and couple of others doing the same.
It seems ot be working but its breaking.
My code:
$('.c_MyValdiators').each(function() {
var x = $(this).attr('id');
var y = document.getElementById(x);
ValidatorEnable(y[0], false);
});
I get Error:
val is undefined
[Break on this error] val.enabled = (enable != false);\r\n
Alternatively if I use
$('.c_MyValdiators').each(function() {
ValidatorEnable($(this), false); OR ValidatorEnable($(this[0]), false);
});
I get Error:
val.style is undefined
[Break on this error] val.style.visibility = val.isvalid ? "hidden" : "visible";\r\n
Any idea or suggestions?
I beleive that ValidatorEnable takes the ASP.net ID rather that the ClientID produced by ASP.net. You will also need to make the validation conditional in the CodeBehind.
here is an example:
Of particular use is to be able to enable or disable validators. If you have validation that you want active only in certain scenarios, you may need to change the activation on both server and client, or you will find that the user cannot submit the page.
Here is the previous example with a field that should only be validated when a check box is unchecked:
public class Conditional : Page {
public HtmlInputCheckBox chkSameAs;
public RequiredFieldValidator rfvalShipAddress;
public override void Validate() {
bool enableShip = !chkSameAs.Checked;
rfvalShipAddress.Enabled = enableShip;
base.Validate();
}
}
Here is the client-side equivalent:
<input type=checkbox runat=server id=chkSameAs
onclick="OnChangeSameAs();" >Same as Billing<br>
<script language=javascript>
function OnChangeSameAs() {
var enableShip = !event.srcElement.status;
ValidatorEnable(rfvalShipAddress, enableShip);
}
</script>
Reference: http://msdn.microsoft.com/en-us/library/aa479045.aspx
I just stumbled upon your Question [a year later].
I too wanted to disable all validators on a page using JQuery here is how I handled it.
$('span[evaluationfunction]').each(function(){ValidatorEnable(this,false);});
I look for each span on the page that has the evaluatefunction attribute then call ValidatorEnabled for each one of them.
I think the $('this') part of your code is what was causing the hickup.
ValidatorEnable(document.getElementById($(this).attr('id')), true);
I've got another solution, which is to use the 'enabled' property of the span tag for the validator. I had different divs on a form that would show or hide so I needed to disable the validation for the fields inside the hidden div. This solution turns off validation without firing them.
If you have a set of RequiredFieldvalidator controls that all contain a common string that you can use to grab them the jquery is this:
$("[id*='CommonString']").each(function() {
this.enabled = false; // Disable Validation
});
or
$("[id*='CommonString']").each(function() {
this.enabled = true; // Enable Validation
});
Hope this helps.
John
I'm just running into the same problem, thanks to the other answers, as it helped uncover the problem, but they haven't gone into detail why.
I believe it is due to that ValidatorEnable() expects a DOM object (i.e. the validation control object) opposed to an ID.
$(selector).each() sets "this" to the DOM element being currently iterated over i.e. quoted from the jquery documentation:
"More importantly, the callback is fired in the context of the current
DOM element, so the keyword this refers to the element." - http://api.jquery.com/each/
Therefore you do not need to do: document.getElementById($(this).attr('id')
And instead ValidatorEnable(this, true); is fine.
Interestingly, Russ's answer mentioned needing to disable server side validation as well, which does make sense - but I didn't need to do this (which is concerning!).
Scrap my previous comment, it is because I had my control disabled server-side previously.
The ValidatorEnable function takes an object as the 1st parameter and not a string of the id of the object.
Here is the simple way to handle this.
Add a new class to the Validation control.
Then look for that class with jquery and disable the control.
Example :
if (storageOnly == 1)
{
$('#tblAssignment tr.assdetails').addClass('hidden');
$('span[evaluationfunction]').each(function ()
{
if ($(this).hasClass('assdetail'))
{ ValidatorEnable(this, false); }
});
}
else
{
$('#tblAssignment tr.assdetails').removeClass('hidden');
}
* Works like a charm.
** For you imaginative types, assdetail == assignment detail.
Here depending on the if condition, I am either hiding the rows then disabling the validator , or removing hidden class from the rows..
Various ways to this depending on your needs. Some solutions in the following blog posts:
http://imjo.hn/2013/03/28/javascript-disable-hidden-net-validators/
http://codeclimber.net.nz/archive/2008/05/14/How-to-manage-ASP.NET-validation-from-Javascript-with-jQuery.aspx
I am trying to figure out how to click a button on a web page programmatically.
Specifically, I have a WinForm with a WebBrowser control. Once it navigates to the target ASP.NET login page I'm trying to work with, in the DocumentCompleted event handler I have the following coded:
HtmlDocument doc = webBrowser1.Document;
HtmlElement userID = doc.GetElementById("userIDTextBox");
userID.InnerText = "user1";
HtmlElement password = doc.GetElementById("userPasswordTextBox");
password.InnerText = "password";
HtmlElement button = doc.GetElementById("logonButton");
button.RaiseEvent("onclick");
This fills the userid and password text boxes fine, but I am not having any success getting that darned button to click; I've also tried "click", "Click", and "onClick" -- what else is there?. A search of msdn of course gives me no clues, nor groups.google.com. I gotta be close. Or maybe not -- somebody told me I should call the POST method of the page, but how this is done was not part of the advice given.
BTW The button is coded:
<input type="submit" name="logonButton" value="Login" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="logonButton" tabindex="4" />
How does this work? Works for me
HtmlDocument doc = webBrowser1.Document;
doc.All["userIDTextBox"].SetAttribute("Value", "user1");
doc.All["userPasswordTextBox"].SetAttribute("Value", "Password!");
doc.All["logonButton"].InvokeMember("Click");
var btn = document.getElementById(btnName);
if (btn) btn.click();
There is an example of how to submit the form using InvokeMember here.
http://msdn.microsoft.com/en-us/library/ms171716.aspx
You can try and invoke the Page_ClientValidate() method directly through the clientscript instead of clicking the button, let me dig up an example.
Using MSHTML
mshtml.IHTMLWindow2 myBroserWindow = (mshtml.IHTMLWindow2)MyWebBrowser.Document.Window.DomWindow;
myBroserWindow.execScript("Page_ClientValidate();", "javascript");
Have you tried fireEvent instead of RaiseEvent?
You could call the method directly and pass in generic object and EventArgs parameters. Of course, this might not work if you were looking at the sender and EventArgs parameters for specific data. How I usually handle this is to refactor the guts of the method to a doSomeAction() method and the event handler for the button click will simply call this function. That way I don't have to figure out how to invoke what is usually just an event handler to do some bit of logic on the page/form.
In the case of javascript clicking a button for a form post, you can invoke form.submit() in the client side script -- which will run any validation scripts you defined in the tag -- and then parse the Form_Load event and grab the text value of the submit button on that form (assuming there is only one) -- at least that's the ASP.NET 1.1 way with which I'm very familiar... anyone know of something more elegant with 2.0+?
Just a possible useful extra where the submit button has not been given an Id - as is frequently the case.
private HtmlElement GetInputElement(string name, HtmlDocument doc) {
HtmlElementCollection elems = doc.GetElementsByTagName("input");
foreach (HtmlElement elem in elems)
{
String nameStr = elem.GetAttribute("value");
if (!String.IsNullOrEmpty (nameStr) && nameStr.Equals (name))
{
return elem;
}
}
return null;
}
So you can call it like so:
GetInputElement("Login", webBrowser1.Document).InvokeMember("Click");
It'll raise an exception if the submit input with the value 'Login', but you can break it up if you want to conditionally check before invoking the click.
You posted a comment along the lines of not wanting to use a client side script on #Phunchak's answer. I think what you are trying to do is impossible. The only way to interact with the form is via a client side script. The C# code can only control what happens before the page is sent out to the browser.
try this
button.focus
System.Windows.Forms.SendKeys.Send("{ENTER}")