【问题标题】:Personalizing Add In Parts with javascript in Sharepoint 2013在 Sharepoint 2013 中使用 javascript 个性化添加部件
【发布时间】:2016-01-29 06:21:48
【问题描述】:

我们有一位客户希望让用户更轻松地自定义其 Web 部件页面。因此,我们使用 javascript 构建一个简单的网格,用户可以在其中从当前页面的不同 webpart 区域添加、删除和移动 Add In Parts(webparts 和 AppParts 以及 OOTB 和自定义)。大多数功能都运行良好,但我们有两个问题似乎无法找到答案。在这种情况下,我们正在使用农场解决方案,但我们希望它也可以与 Office365 一起使用。

  1. Add In Part 是共享的还是个人的?

我们希望用户能够删除/隐藏他们不想要的 Add In Parts,我们正在使用 SP.WebParts.WebPartDefinition.deleteWebPart() 来实现。这适用于用户添加到他/她的个人站点的附加部件,但如果您尝试使用共享的附加部件,则会出现错误。我们想知道 Add In Part 是否共享,在这种情况下设置 hidden=true。我们似乎找不到任何关于如何检查 Add In Part 是否共享的信息,然后首先尝试“deleteWebPart()”,如果出现错误,请尝试“hidden=true”。

  1. 获取 ClientWebPart (AppPart) xml

为了能够从图库中将 Add In Part 添加到页面,您需要它在此方法中的 xml:importWebPart()。对于 webpart,我们可以通过检查 "~siteUrl/_api/web/getCatalog(113)/items" 中的项目找到 .webpart 文件,但此列表中不存在 AppParts。要获取我们正在使用的所有应用程序 SP.AppCatalog.getAppInstances(context, web) 并从中我们获取每个应用程序名称、guid 等,但不是 xml。我们在哪里可以找到它?建议到处问同样问题的人只手动导出 xml 并在代码中使用它,但这还不够好。这需要是动态的并且适用于所有 AppPart。

感谢您的帮助。

致管理员:我首先在sharepoint.stackexchange.com 上发布了这个问题,但我不确定是否应该在此处或那里发布有关代码的 Sharepoint 问题。如果你告诉我应该怎么做,我会删除另一个。

【问题讨论】:

    标签: javascript sharepoint sharepoint-2013 csom personalization


    【解决方案1】:

    我发现我公司的一些人做了类似的功能,我和他们一起找到了一个令人满意的解决方案。如果将来有其他人想做与此相同的事情,我会分享我是如何做到的。

    问题 1:Add In Part 是共享的还是个人的

    如果 AddInPart 是由用户共享或创建的,我找不到任何属性,所以我通过简单地加载所有共享的 AddInPart 并将它们的 GUID 存储在一个数组中来解决这个问题。通过这样做,我可以检查我想要删除的 AddInPart 是否在该数组中,并在这种情况下采取正确的操作。我就是这样做的:

    var sharedWebPartGuids = new Array(); // An array containing guids from all shared webparts
    
    function fetchSharedWebparts() {
      //get the client context
      var clientContext = new SP.ClientContext(_spPageContextInfo.webServerRelativeUrl);
      //get the current page as a file
      var oFile = clientContext.get_web().getFileByServerRelativeUrl(_spPageContextInfo.serverRequestPath);
      // Fetch all webparts that are shared
      var limitedWebPartManagerShared = oFile.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
      //get the web parts on the current page
      var collWebPart = limitedWebPartManagerUser.get_webParts();
      //request the web part collection and load it from the server
      clientContext.load(collWebPart);
      clientContext.executeQueryAsync(Function.createDelegate(this, function() {
        // Go through all webparts
        for (var x = 0; x < collWebPart.get_count(); x++) {
          var webPartDef = collWebPart.get_item(x);
          sharedWebPartGuids.push(webPartDef.get_id().toString());
        }
      }), Function.createDelegate(this, function() {
        alert("failed to fetch shared webparts from page")
      }));
    }

    问题2:获取ClientWebPart(AppPart)xml

    不幸的是,如果不为每个具有应该能够添加的 AppPart 的应用程序手动提供 ProductID(GUID),我就无法做到这一点。为此,我部署了一个名为 AvailableAppParts 的列表,其中包含两列; TitleProductId。然后,我通过比较 Title 将列表中的项目与已安装的应用程序匹配。 GUID 可以在 App 中的 AppManifest.xml 中找到,或者将 AppPart 添加到页面然后导出。我还必须在我的代码中包含一个 xml 模板并替换唯一值。由于一切都是异步完成的,我有一个名为 initMethods 的计数器,我为每个异步方法添加了它,然后在它们结束时调用 initMethodDone() 来检查是否所有异步方法在我向用户展示任何内容之前完成。我就是这样做的:

    var webpartsFromGallery = new Array(); // An array where I store an object for each AppPart
    // The xml template:
    var appPartXml = '<webParts><webPart xmlns="http://schemas.microsoft.com/WebPart/v3"><metaData><type name="Microsoft.SharePoint.WebPartPages.ClientWebPart, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /><importErrorMessage>Cannot import this Web Part.</importErrorMessage> </metaData><data><properties><property name="TitleIconImageUrl" type="string" /><property name="Direction" type="direction">NotSet</property><property name="ExportMode" type="exportmode">NonSensitiveData</property><property name="HelpUrl" type="string" /><property name="Hidden" type="bool">False</property><property name="Description" type="string">AppPart Description</property><property name="FeatureId" type="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">{FeatureId}</property><property name="Title" type="string">{Title}</property><property name="AllowHide" type="bool">True</property><property name="ProductWebId" type="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">{ProductWebId}</property><property name="AllowZoneChange" type="bool">True</property><property name="TitleUrl" type="string" /><property name="ChromeType" type="chrometype">Default</property><property name="AllowConnect" type="bool">True</property><property name="Width" type="unit" /><property name="Height" type="unit" /><property name="WebPartName" type="string">AppPart</property><property name="HelpMode" type="helpmode">Navigate</property><property name="AllowEdit" type="bool">True</property><property name="AllowMinimize" type="bool">True</property><property name="ProductId" type="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">{ProductId}</property><property name="AllowClose" type="bool">True</property><property name="ChromeState" type="chromestate">Normal</property></properties></data></webPart></webParts>';
    
    function fetchAppPartsFromGallery() {
      initMethods++;
      var ctx = SP.ClientContext.get_current();
      var web = ctx.get_web();
      // Fetch all installed Apps on this site (SPWeb)
      var appInstances = SP.AppCatalog.getAppInstances(ctx, web);
      ctx.load(appInstances);
      ctx.executeQueryAsync(
        function() {
          if (appInstances.get_count() == 0) {
            // No apps found, stop here
            return;
          }
          // Iterate through the app instances and store them in a map
          // Also create a filter string
          var map = new Object();
          var filterString = "";
          for (var i = 0; i < appInstances.get_count(); i++) {
            var instance = appInstances.getItemAtIndex(i);
            var title = instance.get_title();
            map[title] = instance;
    
            // Append filter
            if (filterString.length > 0) {
              filterString += "or";
            }
            filterString += "(Title+eq+'" + title + "')";
          }
          if (filterString.length > 0) {
            filterString = "?$filter=" + filterString;
          }
    
          // Fetch available apps from my list
          $.ajax({
            url: siteApiUrl + "/web/lists/getbytitle('AvailableAppParts')/items" + filterString,
            type: "GET",
            headers: {
              "accept": "application/json;odata=verbose",
            },
            success: function(data) {
              // Go through all returned apps and build the xml for each one
              var results = data.d.results;
              for (var i = 0; i < results.length; i++) {
                var listItem = results[i];
                var title = listItem.Title;
                var productId = listItem.ProductId;
    
                var appInstance = map[title];
                if (!appInstance) {
                  console.log("Could not find app with title '" + title + "'");
                  continue;
                }
                var instanceId = appInstance.get_id();
                var webId = appInstance.get_webId();
                var featureId = calculateFeatureIdFromProductId(productId);
    
                // This is the values we have to replace with our unique ones
                var xml = appPartXml.replace(/{Title}/g, title);
                xml = xml.replace(/{ProductId}/g, productId);
                xml = xml.replace(/{ProductWebId}/g, webId);
                xml = xml.replace(/{FeatureId}/g, featureId);
    
                webpartsFromGallery.push({
                  id: instanceId,
                  title: title,
                  xml: xml
                });
              }
    
              function calculateFeatureIdFromProductId(productID) {
                // Calculate featureId since it is always one hexadecimal value higher than productId
                var lastIndex = productID.lastIndexOf('-');
                var lastNumber = productID.substring(lastIndex + 12);
                // We are using hexadecimal numbers therefor using parseInt(..., 16) and toString(16)
                var increment = parseInt(lastNumber, 16) + 1;
                var incrementHex = increment.toString(16);
                var featureID = productID.substring(0, lastIndex + 12) + incrementHex;
                return featureID;
              }
    
              initMethodDone();
            },
            error: function(error) {
              alert(JSON.stringify(error));
    
              initMethodDone();
            }
    
          });
        },
        function(sender, args) {
          console.log(JSON.stringify(args));
    
          initMethodDone();
        });
    }

    【讨论】:

      猜你喜欢
      • 2012-12-24
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多