定制Ribbon触发工作流

本文介绍了如何在SharePoint 2013中自定义Ribbon按钮,以创建一个下拉菜单,允许用户直接从列表项上启动工作流,而无需跳转页面。详细步骤包括添加Ribbon按钮,动态生成下拉菜单,并使用SPServices触发工作流。
摘要由CSDN通过智能技术生成

在SharePoint中,如果手动触发工作流,用户需要选中item,然后点击workflow,导向另外一个页面,才可以启动工作流。

这里我想添加一个Ribbon button,这个Ribbon button可以是一个下拉菜单,列出所有可以触发的workflow,用户只需要选中一些item,然后直接点击下拉菜单中的一个就可以触发工作流,不需要页面转向。

下面是具体实现方法的介绍:

第一步,我们添加一个Ribbon Button到Ribbon中。

我使用flyout anchor类型的Ribbon button,将其添加到Ribbon的Ribbon.ListItem.Workflow这个组中:


Ribbon的配置代码:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Control
                  Id="AdditionalPageHead"
                  Sequence="200"
                  ControlClass="shrenky.projects.workflowtrigger.RibbonLoaderControl"
                  ControlAssembly="$SharePoint.Project.AssemblyFullName$">
  </Control>
  <CustomAction Id="shrenky.projects.workflowtrigger.Ribbon"
                Location="CommandUI.Ribbon"
                RegistrationId="100"
                RegistrationType="List"
                Sequence="120"
                Title="Tigger"
                Description="Trigger workflow">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.ListItem.Workflow.Controls._children">
          <FlyoutAnchor Id="shrenky.projects.workflowtrigger.Anchor"
              Sequence="20"
              LabelText="Workflows"
              Image32by32="/_layouts/15/images/shrenky.projects.workflowtrigger/Trigger.jpg"
              PopulateDynamically="true"
              PopulateOnlyOnce="false"
              PopulateQueryCommand="shrenky.projects.workflowtrigger.PopulateMenus"
              ToolTipTitle="Dynamic dropdown"
              ToolTipDescription="Shows dropdown made of buttons defined in JavaScript"
              TemplateAlias="o1">
          </FlyoutAnchor>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="shrenky.projects.workflowtrigger.TriggerMenuClick" CommandAction="javascript:WorkflowTrigger.Ribbon.RibbonComponent.get_instance().TriggerWorkflow(arguments[2].MenuItemId, '');"  EnabledScript="true" />
        <CommandUIHandler Command="shrenky.projects.workflowtrigger.MessageMenuClick" CommandAction="javascript:alert('No workflow associated on current list.')"  EnabledScript="true" />
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>
首先添加了一个delegate control,用来注册一些脚本比如JQuery,SPServices和Ribbon需要使用的PageComponent等等。

然后定义了一个FlyoutAnchor按钮,这个按钮没有配置下拉菜单,因为下拉菜单是通过PopulateQueryCommand这个属性来动态生成的,当用户点击这个按钮时,会执行“shrenky.projects.workflowtrigger.PopulateMenus”这个方法,这个方法是定义在PageComponent中的,用来构造下拉菜单的xml。

除了FlayoutAnchor之外还定义了两个CommandUIHandler,一个是"shrenky.projects.workflowtrigger.TriggerMenuClick",供用户点击FlyoutAnchor动态生成的下拉菜单的时候调用,另外一个暂时没有用处。

delegate control除了用来加载脚本之外,还有一个用途就是将当前list上的所有关联的workflow的信息(association id,Title,Description)等等输出到页面上供之后的操作使用。

第二步,当用户点击Ribbon的时候,显示当前列表中所有可以触发的工作流


向Flyout Anchor动态添加下拉菜单是通过PageComponent(WorkflowTriggerPageComponent.js文件)实现的,关于pagecomponent的介绍可以参考《SharePoint 2010 as development platform》这本书中的例子。具体定义如下:

Type.registerNamespace('WorkflowTrigger.Ribbon');

WorkflowTrigger.Ribbon.RibbonComponent = function () {
    WorkflowTrigger.Ribbon.RibbonComponent.initializeBase(this);
}

WorkflowTrigger.Ribbon.RibbonComponent.get_instance = function () {
    if (!WorkflowTrigger.Ribbon.RibbonComponent.s_instance) {
        WorkflowTrigger.Ribbon.RibbonComponent.s_instance = new WorkflowTrigger.Ribbon.RibbonComponent();
    }
    return WorkflowTrigger.Ribbon.RibbonComponent.s_instance;
}

WorkflowTrigger.Ribbon.RibbonComponent.prototype = {
    focusedCommands: null,
    globalCommands: null,
    registerWithPageManager: function () {
        SP.Ribbon.PageManager.get_instance().addPageComponent(this);
        SP.Ribbon.PageManager.get_instance().get_focusManager().requestFocusForComponent(this);
    },

    unregisterWithPageManager: function () {
        SP.Ribbon.PageManager.get_instance().removePageComponent(this);
    },

    init: function () { },

    getFocusedCommands: function () {
        return ['shrenky.projects.workflowtrigger.PopulateMenus'];
    },

    getGlobalCommands: function () {
        return ['shrenky.projects.workflowtrigger.PopulateMenus'];
    },

    canHandleCommand: function (commandId) {
        if (commandId === 'shrenky.projects.workflowtrigger.PopulateMenus') {
            return true;
        }
        else { return false; }
    },

    handleCommand: function (commandId, properties, sequence) {
        if (commandId === 'shrenky.projects.workflowtrigger.PopulateMenus') {
            properties.PopulationXML = this.GetDynamicMenuXml();
        }
        else {
            return handleCommand(commandId, properties, sequence);
        }
    },

    GetDynamicMenuXml: function () {
        ... ...
    },

    selectedItems: [],
    workflowAssociationId: null,

    TriggerWorkflow : function(workflowAssoId, param)
    {
        ... ...
    },

    TriggerWorkflowExec: function ()
    {
        ... ...
    },

    TriggerWorkflowFailed: function ()
    {
        ... ...
    }
}

WorkflowTrigger.Ribbon.RibbonComponent.registerClass('WorkflowTrigger.Ribbon.RibbonComponent', CUI.Page.PageComponent);
WorkflowTrigger.Ribbon.RibbonComponent.get_instance().registerWithPageManager();
NotifyScriptLoadedAndExecuteWaitingJobs("WorkflowTriggerPageComponent.js");

动态生成下拉菜单是通过以下代码来实现的:

if (commandId === 'shrenky.projects.workflowtrigger.PopulateMenus') {
            properties.PopulationXML = this.GetDynamicMenuXml();
        }

GetDynamicMenuXm这个方法负责产生下拉菜单的xml,在产生xml的时候,需要用到delegate control事先输出到页面上的workflow的信息(即workflowtrigger.data.WorkflowData这个变量,一个json对象,包含了workflow的具体信息例如id,Title等)

 GetDynamicMenuXml: function () {
        var counter = 0;
        var data = workflowtrigger.data.WorkflowData;
        var xml = '<Menu Id = "shrenky.projects.workflowtrigger.Anchor.Menu">'
        + '<MenuSection Id="shrenky.projects.workflowtrigger.Anchor.Menu.MenuSection1" >'
        + '<Controls Id="shrenky.projects.workflowtrigger.Anchor.Menu.MenuSection1.Controls">';
        var len = data.length;
        for (var i = 0;  i < len; i++){
            counter = counter + 1;
            var current = data[i];
            var workflowAssociationId = current.WorkflowAssociationId;
            var workflowName = current.WorkflowTitle;
            var workflowDesc = current.WorkflowDescription;
            var buttonXml = String.format(
                    '<Button Id= "shrenky.projects.workflowtrigger.Anchor.Menu.MenuSection1.Menu{0}" '
                    + 'Command="shrenky.projects.workflowtrigger.TriggerMenuClick" '
                    + 'MenuItemId="{1}" '
                    + 'LabelText="{2}" '
                    + 'ToolTipTitle="{2}" '
                    + 'ToolTipDescription="{3}" TemplateAlias="o1"/>', counter, workflowAssociationId, workflowName, workflowDesc);
            xml += buttonXml;
        }
        if (counter === 0) {
            var msgXml = String.format(
                    '<Button Id= "shrenky.projects.workflowtrigger.Anchor.Menu.MenuSection1.Menu{0}" '
                    + 'Command="shrenky.projects.workflowtrigger.MessageMenuClick" '
                    + 'MenuItemId="1" '
                    + 'LabelText="{0}" '
                    + 'ToolTipTitle="{0}" '
                    + 'ToolTipDescription="{0}" TemplateAlias="o1"/>', 'No workflow associated on current list');
            xml += buttonXml;
        }
        xml += '</Controls>' + '</MenuSection>' + '</Menu>';
        return xml;
    },

在构造xml的时候,我们把下拉菜单的Command属性赋予了“shrenky.projects.workflowtrigger.TriggerMenuClick”这个方法,就个方法就是之前定义的CommandUIHandler其中之一。当用户点击下拉菜单时,触发“shrenky.projects.workflowtrigger.TriggerMenuClick”这个方法,这个方法实际上是调用了另外一个方法TriggerWorkflow:

    selectedItems: [],
    workflowAssociationId: null,

    TriggerWorkflow : function(workflowAssoId, param)
    {
        this.workflowAssociationId = workflowAssoId;
        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();
        var lists = web.get_lists();
        var listId = SP.ListOperation.Selection.getSelectedList();
        var list = lists.getById(listId);
        var items = SP.ListOperation.Selection.getSelectedItems();
        this.selectedItems = [];
        if (items.length > 0) {
            for (var i in items) {
                var id = items[i].id;
                var item = list.getItemById(id);
                this.selectedItems.push(item);
                ctx.load(item);
            }
            ctx.executeQueryAsync(Function.createDelegate(this, this.TriggerWorkflowExec), Function.createDelegate(this, this.TriggerWorkflowFailed));
        }
        else {
            alert("Please select item");
        }
    },
这个方法首先获取用户选择的所有item,将这些item保存在selectedItems这个变量中,然后使用executeQueryAsync方法获取这些item的信息,供最后在这些item上触发工作流使用。如果这些item的信息获取成功,则会调用回调函数TriggerWorkflowExec,正式触发工作流了:

 TriggerWorkflowExec: function ()
    {
        for (var i in this.selectedItems) {
            var item = this.selectedItems[i];
            var itemId = item.get_item("ID");
            var itemTitle = item.get_item("Title");
            var itemFileRef = item.get_item("FileRef");
            var webUrl = _spPageContextInfo.webAbsoluteUrl;
            var url = webUrl + itemFileRef;
            var id = this.workflowAssociationId;
            !function outer(id, url, itemTitle) {
                $().SPServices({
                    debug: true,
                    operation: "StartWorkflow",
                    async: true,
                    item: url,
                    templateId: id,
                    workflowParameters: "<Data/>",
                    completefunc: function () { SP.UI.Notify.addNotification("Start workflow on " + itemTitle + " Successfully", true); }
                });
            }(id, url, itemTitle);
        }
    },

这里遍历用户选择的items,使用SPServices触发工作流,使用SPServices触发工作流的方法参见: 点击打开链接

第三步, 选中需要启动的工作流然后使用SPServices来触发工作流,工作流正常启动之后会有消息通知(这里“Thinkpad”是item的title):


目前这个工具只能运行在列表上,还很不完善,但是是一个很好的自定义ribbon的一个例子。

具体代码可以在github上下载:https://github.com/shrenky/sharepointprojects.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值