0

In a publishing site, I would like to extend the ribbon to quickly set/unset a specific audience.

Basically, the user should be able , with a single click, to add or remove a specific audience (the audience has technical meaning elsewhere in the app).

I would like to provide a button in the ribbon similar to the "publish" button. What I mean is that the button should have different icon and meaning depending on the context:

  • The state is undetermined yet --> grayed icon
  • The audience is set --> icon and text to remove the audience,
  • The audience is not set --> icon and text to add the audience,

When looking at the native publish command, I can see this is implemented using a MRUSplitButton with a button for each state, while others are disabled.

I'm trying to mimic this behavior. I build a custom page component, but this is not working as expected:

  • the getGlobalCommands method is fired. In this method I provide my two commands.
  • however, the canHandleCommand method is never fired.
  • The whole split button is grayed. the icon and the arrow to drop down the menu are both grayed.

What is wrong?

Here is my code:

elements.xml

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction
    Id="MyProject.Ribbon.MyAudienceSetter"
    Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Templates._children">
          <GroupTemplate Id="Ribbon.Templates.MyAudienceSetter.LargeRow">
            <Layout Title="MyAudienceSetterOneLarge"
                    LayoutTitle="MyAudienceSetterOneLarge">
              <OverflowSection TemplateAlias="OneRow1" DisplayMode="Large" Type="OneRow"/>
            </Layout>
          </GroupTemplate>
        </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.WikiPageTab.Scaling._children">
          <MaxSize
            Id="MyProject.Ribbon.MyAudienceSetter.MaxSize"
            Sequence="15"
            GroupId="MyProject.Ribbon.MyAudienceSetter"
            Size="MyAudienceSetterOneLarge" />
        </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.WikiPageTab.Groups._children">
          <Group
            Id="MyProject.Ribbon.MyAudienceSetter"
            Sequence="15"
            Description="Used to demo adding a group"
            Title="Promotion d'acutalité"
            Template="Ribbon.Templates.MyAudienceSetter.LargeRow">
            <Controls Id="MyProject.Ribbon.Controls">
              <MRUSplitButton
                Id="MyProject.Ribbon.MyAudienceSetter.MyAudienceSetter"
                Sequence="10"
                Alt="$Resources:core,ButPublish;"
                InitialItem="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Promote"
                MenuAlt="$Resources:core,ButPublish;"
                TemplateAlias="OneRow1"
              >
                <Menu Id="MyProject.Ribbon.MyAudienceSetter.Menu">
                  <MenuSection Id="MyProject.Ribbon.MyAudienceSetter.Menu.Promote"
                               Sequence="10"
                               DisplayMode="Menu32">
                    <Controls Id="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Controls">
                      <Button
                        Id="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Promote"
                        MenuItemId="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Promote"
                        Sequence="10"
                        Alt="$Resources:core,ButPublish;"
                        Command="MyProject.Ribbon.MyAudienceSetter.Promote"
                        Image16by16="/_layouts/15/$Resources:core,Language;/images/formatmap16x16.png?rev=23"
                        Image16by16Top="-271"
                        Image16by16Left="-163"
                        Image32by32="/_layouts/15/$Resources:core,Language;/images/formatmap32x32.png?rev=23"
                        Image32by32Top="-341"
                        Image32by32Left="-375"
                        LabelText="$Resources:core,ButPublish;"
                        ToolTipTitle="$Resources:core,ButPublish;"
                        ToolTipDescription="$Resources:core,cui_STT_ButPublish_page;"
                        />
                      <Button
                        Id="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Demote"
                        MenuItemId="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Demote"
                        Sequence="20"
                        Alt="$Resources:core,ButSubmitForApproval;"
                        Command="MyProject.Ribbon.MyAudienceSetter.Demote"
                        Image16by16="/_layouts/15/$Resources:core,Language;/images/formatmap16x16.png?rev=23"
                        Image16by16Top="-37"
                        Image16by16Left="-133"
                        Image32by32="/_layouts/15/$Resources:core,Language;/images/formatmap32x32.png?rev=23"
                        Image32by32Top="-477"
                        Image32by32Left="-171"
                        LabelText="$Resources:core,ButSubmitForApprovalLabelText;"
                        ToolTipTitle="$Resources:core,ButSubmitForApproval;"
                        ToolTipDescription="$Resources:core,cui_STT_ButSubmitForApproval;"
                        />
                    </Controls>
                  </MenuSection>
                </Menu>
              </MRUSplitButton>
            </Controls>
          </Group>
        </CommandUIDefinition>
      </CommandUIDefinitions>

    </CommandUIExtension>
  </CustomAction>

  <CustomAction ScriptSrc="~SiteCollection/_layouts/15/MyProject/MyProject.MyAudienceSetter.loader.js"
                Location="ScriptLink"
                Sequence="1000" />

</Elements>

MyAudienceSetter.js

Type.registerNamespace('MyProject');

MyProject.MyAudienceSetter = function () {
    MyProject.MyAudienceSetter.initializeBase(this);
}

MyProject.MyAudienceSetter.initialize = function () {
    SP.SOD.executeOrDelayUntilScriptLoaded(Function.createDelegate(null, MyProject.MyAudienceSetter.initializePageComponent), 'SP.Ribbon.js');
}

MyProject.MyAudienceSetter.initializePageComponent = function () {
    var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
    if (null !== ribbonPageManager) {
        ribbonPageManager.addPageComponent(MyProject.MyAudienceSetter.instance);
    }
}

MyProject.MyAudienceSetter.prototype = {
    init: function () {
        this.audienceIsSetChecked = false;
        this.audienceIsSet = 'Unknown';
    },
    getFocusedCommands: function () {
        return [];
    },
    buildCommands: function () {
        if (SP.ScriptUtility.isNullOrUndefined(this.commands)) {
            this.commands = [];
            this.commands.push('MyProject.Ribbon.MyAudienceSetter.Promote');
            this.commands.push('MyProject.Ribbon.MyAudienceSetter.Demote');
        }

        return this.commands;
    },
    getGlobalCommands: function () {
        return this.buildCommands();
    },
    canHandleCommand: function (commandId) {
        for (var i = 0; i < this.commands.length; i++) {
            if (this.commands[i] === commandId) {
                if (!this.audienceIsSetChecked) {
                    this.checkIfAudienceIsSet();
                }

                return true;
            }
        }
        return false;
    },
    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'MyProject.Ribbon.MyAudienceSetter.Promote':
                break;
            case 'MyProject.Ribbon.MyAudienceSetter.Demote':
                break;
        }
    },
    checkIfAudienceIsSet: function () {
        this.audienceIsSetChecked = true;

        var context = new SP.ClientContext(_spPageContextInfo.webServerRelativeUrl);
        var list = context.get_web().get_lists().getById(_spPageContextInfo.pageListId);
        var item = list.getItemById(_spPageContextInfo.pageItemId);


        context.load(item, 'Include(Audience)');

        context.executeQueryAsync(Function.createDelegate(this, function () {
            var audience = item.get_item('Audience');
            RefreshCommandUI();
        }), Function.createDelegate(this, function () {
            alert(JSON.stringify(arguments));
        }));
    }
}

MyProject.MyAudienceSetter.registerClass('MyProject.MyAudienceSetter', CUI.Page.PageComponent);
MyProject.MyAudienceSetter.instance = new MyProject.MyAudienceSetter();

SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs('myaudienceSetter.js');

and the loader :

/// <reference path="c:\Program Files\common Files\microsoft Shared\web Server Extensions\15\TEMPLATE\LAYOUTS\MicrosoftAjax.js" />
/// <reference path="c:\Program Files\common Files\microsoft Shared\web Server Extensions\15\TEMPLATE\LAYOUTS\SP.debug.js" />
/// <reference path="c:\Program Files\common Files\microsoft Shared\web Server Extensions\15\TEMPLATE\LAYOUTS\SP.Core.debug.js" />

SP.SOD.executeOrDelayUntilScriptLoaded(function () {
    SP.SOD.executeOrDelayUntilScriptLoaded(function () {
        var ctx = SP.ClientContext.get_current();
        var site = ctx.get_site();
        ctx.load(site);
        ctx.executeQueryAsync(Function.createDelegate(this, function (sender, args) {
            var pageComponentScriptUrl = SP.Utilities.UrlBuilder.urlCombine(site.get_url(), "_layouts/15/MyProject/MyAudienceSetter.js");
            SP.SOD.registerSod('myaudienceSetter.js', pageComponentScriptUrl);
            SP.SOD.execute('myaudienceSetter.js', 'MyProject.MyAudienceSetter.initialize');
        }));
    }, "cui.js");
}, "sp.js");
0

Not yet finished the implementation, but at least, I managed to make the canHandleCommand fire.

Actually, I have to implements the Command on the menu itself.

So I introduced a new command on the menu :

          <MRUSplitButton
            Id="SoSP.VDD.Intranet.Ribbon.PromoteNewToHomePage.PromoteNewToHomePage"
            Sequence="10"
            Alt="$Resources:core,ButPublish;"
            InitialItem="MyProject.Ribbon.MyAudienceSetter.Menu.Promote.Promote"
            MenuAlt="$Resources:core,ButPublish;"
            TemplateAlias="OneRow1"
            Command="MyProject.Ribbon.MyAudienceSetter.Split"
          >

I also ensure this command is returned by the getGlobalCommands function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.