SharePoint 2013 - Add-ins

1. App Web & Host Web

The special website to which the app is deployed is called an App Web.

The website to which the app is installed is called the Host Web.

 例子:

Suppose, you are developing a SharePoint 2013 app for your organization. In that, you would require the App to access and to use the SharePoint components such as the lists, content types, workflows, and pages. In this Case, all your SharePoint components should be deployed in a separate SharePoint site, called as the App Web.
 
The Host Web is nothing but the SharePoint site where the App is actually installed. So, to conclude, all the resources accessed by a SharePoint web has to be deployed in a different site, named as the App web. And, the actual site where the app is deployed (from VS) is called the Host Web.
 
2. Client Authentication with Office 365
使用SharePointOnlineCredentials对象
复制代码
ClientContext context = new ClientContext(url);
            System.Security.SecureString passWord = new System.Security.SecureString();
            foreach (char c in password.ToCharArray())
            {
                passWord.AppendChar(c);
            }
            context.Credentials = new SharePointOnlineCredentials(userName, passWord);
复制代码

3. App中的Client Web Part是否加入到Feature或者package中不影响App中的内容,App文件会将项目中的所有信息加入进去;

4. App的链接中已默认包含了这个参数:SPHostUrl, SPLanguage, SPClientTag, SPProductNumber, 和SPAppWebUrl。

5. 动态创建Tile的方法:

在页面上定义一个container:

<!-- Tiles will be rendered here -->
<div id="tileArea" style="width:600px;"></div>

定义CSS:

/* Custom styles for the tiles */
.tile{
    width:150px;
    height:150px;
    color:#FFFFFF;
    margin-top:5px;
    margin-left:0px;
    margin-right:10px;
    margin-bottom:10px;
    cursor:pointer;
    padding:5px;
    float:left;
    text-align:right;
    font-family:Segoe UI, sans-serif; 
    font-size:14px;
    background-image:url(../images/MetroPlay.png);
    background-repeat: no-repeat; 
    background-position:bottom right;
    background-color:#FFAAAA;
}
.tileNumber{
    text-align:center;
    font-family:Segoe UI Light, sans-serif; 
    font-size:72px;
    margin-top:10px;
    margin-bottom:10px;
}
a, a:hover, a:visited {text-decoration:none; outline:none;color:#FFFFFF}
a:active, a:focus {outline:0}

使用JavaScript,根据列表数目动态生成tile:

// Variables used to hold objects for use in callback functions
var context;
var lists;
//var list;
var listItems;
var tileArea;
// This code runs when the DOM is ready and creates a context object which is needed 
// to use the SharePoint object model
$(document).ready(function () {
    
    context = SP.ClientContext.get_current();
    var web = context.get_web();
    lists = web.get_lists();
    context.load(lists);
    context.executeQueryAsync(Function.createDelegate(this, renderListTiles), Function.createDelegate(this, errorLoadingLists));
});

function errorLoadingLists(sender, args) {
    tileArea = document.getElementById("tileArea");

    // Remove all nodes from the chart <DIV> so we have a clean space to write to
    while (tileArea.hasChildNodes()) {
        tileArea.removeChild(tileArea.lastChild);
    }

    // Write a message to let the user know the operation has failed
    var errMessage = document.createElement("div");
    errMessage.appendChild(document.createTextNode("Lists could not be retrieved."+args.get_message()));
}

function renderListTiles(sender, args) {
    var listEnumerator = lists.getEnumerator();

    while (listEnumerator.moveNext()) {
        var list = listEnumerator.get_current();
        var listTitle = list.get_title();
        if ((listTitle == "Employees") || (listTitle == "MarketSize") || (listTitle == "Sales")) {
            var itemCount = list.get_itemCount();
            var tile = document.createElement("a");
            tile.setAttribute("class", "tile");
            tile.setAttribute("href", "../Lists/" + listTitle);
            tile.appendChild(document.createTextNode(listTitle));
            
            $("#tileArea").appendChild(tile);
            var tileBody = document.createElement("div");
            tileBody.setAttribute("class", "tileNumber");
            tileBody.appendChild(document.createTextNode(itemCount.toString()));
            tile.appendChild(tileBody);
        }
    }
}

效果:

6. 向SharePoint Log中添加记录时,需要用到SP.Analytics命名空间(SP.js);

 var eventGuid = new SP.Guid("101c16a5-3abd-4020-921f-cc40090c6ff7");

    // When you have entered a valid GUID, you can then call the logAnalyticsAppEvent
    // as follows:
SP.Analytics.AnalyticsUsageEntry.logAnalyticsAppEvent(context, eventGuid, "Test App Page");
context.executeQueryAsync(
// This is the success callback: function () { status.innerText = "Success! The event for 'Test App Page' has been logged."; }, // This is the failure callback: function (sender, e) { status.innerText = "Failed to log event for 'Test App Page': " + e.get_message(); });

7. sp.userprofiles.js中包含了获取user profle信息的方法和对象(但除了accountName属性,其它属性可能为null)

// This code runs when the DOM is ready and creates a context object 
// which is needed to use the SharePoint object model. We also wire
// up the click event handler of the listProfiles button in default.aspx.
$(document).ready(function () {
    context = SP.ClientContext.get_current();
    $('#listProfiles').click(function () { listProfilesClick();});
});

// This function handles the click event of the listProfiles button in default.aspx
function listProfilesClick() {
   
    // Our way into the current user's profile is through the PeopleManager class 
    // so we'll instantiate a new object and pass in the current context,
    peopleMgr = new SP.UserProfiles.PeopleManager(context);

    // We'll then load the object...
    context.load(peopleMgr);

    // ... and we'll get the user profile properties and load them as well.
    profileProperties = peopleMgr.getMyProperties();
    context.load(profileProperties);

    // Next we ask SharePoint to run all of our previously batched commands...
    context.executeQueryAsync(

        // ... and if we're successful, the following success callback will run
        function () {
            
            if (peopleMgr.get_isMyPeopleListPublic()) {
                publicDiv.appendChild(document.createTextNode("Your followers and those you follow are publicly visible"));
            }
            else {
                publicDiv.appendChild(document.createTextNode("Your followers and those you follow are not publicly visible"));
            }
            $('#profileList').append(publicDiv);
            
            // Then we'll add a few simple properties from the profile.
            // The first one is the account name
            var accountName = profileProperties.get_accountName();
 
            // The second one is the display name.
            // Note that we'll check for null in case this property hasn't been set.
            var displayName = profileProperties.get_displayName();

            // The third thing to show the user is their profile picture.
            // Note that we'll check for null in case this property hasn't been set.
            // If it's not null, we'll render the actual picture.
            var myPicture = profileProperties.get_pictureUrl();

            // Finally, we'll add three links:
            // One for editing the profile...
            var myProfileLink = peopleMgr.get_editProfileLink();
           
            // One for going to the user's personal site...
            var myPersonalSite = profileProperties.get_personalUrl();
            
            // And one that shows the user what their page looks like when 
            // viewed by other users.
            var myPublicPersona = profileProperties.get_userUrl();

        },

        // If we haven't been successful, the following failure callback
        // will run, so we'll clear the profile list div, and then use it
        // to tell the user what went wrong
        function (sender, e) {
            $('#profileList').children().remove();
            $('#profileList').append(docume.createTextNode(e.get_message()));
        });
}

8. SP.RequestExecutor.js文件就是cross-domain library,SP.RequestExecutor对象用于执行与其它数据源交互的操作,比如host-web,app-web;但需要注意的是,如果在APP中使用SP.RequestExecutor对象与Host Web的数据进行交互,由于在App中,默认的context site是app web, 所以我们还需要使用SP.AppContextSite()来设置当前的context site为 host web,然后还要再AppManifest.xml中设置app在host web中的权限(在使用SP.AppContextSite时必须使用SP.AppContextSite(@target) 和?@target='<host web url>'的格式,不能直接将host web地址写在参数括号中);

var hostweburl;
var appWebUrl;

// Load the required SharePoint libraries
$(document).ready(function () {
  //Get the URI decoded URLs.
  hostweburl =
      decodeURIComponent(
          getQueryStringParameter("SPHostUrl")
  );

  appWebUrl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

  // Load the js file and continue to the 
  //   success event handler
  $.getScript(hostweburl+"/_layouts/15/SP.RequestExecutor.js", execCrossDomainRequest);
});

// Function to prepare and issue the request to get
//  SharePoint data
function execCrossDomainRequest() {
  var executor;

  // Initialize the RequestExecutor with the app web URL.
  executor = new SP.RequestExecutor("/");

  // Issue the call against the host web.
  // To get the title using REST we can hit the endpoint:
  //   app_web_url/_api/SP.AppContextSite(@target)/web/title?@target='siteUrl'
  // The response formats the data in the JSON format.
  // The functions successHandler and errorHandler attend the
  //      success and error events respectively.
  executor.executeAsync(
      {
        url:
            appWebUrl+"/_api/SP.AppContextSite(@target)/web/title?@target='" +
            hostweburl + "'",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: successHandler,
        error: errorHandler
      }
  );
}

// Function to handle the success event.
// Prints the host web's title to the page.
function successHandler(data) {
  var jsonObject = JSON.parse(data.body);

  document.getElementById("HostwebTitle").innerHTML =
      "<b>" + jsonObject.d.Title + "</b>";
}

// Function to handle the error event.
// Prints the error message to the page.
function errorHandler(data, errorCode, errorMessage) {
  document.getElementById("HostwebTitle").innerText =
      "Could not complete cross-domain call: " + errorMessage;
}
View Code

9.  在app中搜索host web内容时,需要在AppManifest.xml文件的Permissions中为app添加Search权限,搜索时使用的url路径就是app web的路径,但依然可以搜索到host web的内容;

function executeQuery() {
    alert(_spPageContextInfo.webAbsoluteUrl);
    $.ajax(
            {
                url: _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='" + $("#queryTerms").val() + "'",
                method: "GET",
                headers: {
                    "Accept": "application/json;odata=verbose"
                },
                success: onSuccess,
                error: onError
            }
        );
}

function onSuccess(data) {
            var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
            alert(JSON.stringify(data.d.query)); //display json as string
            var html = "<table>";

            for (var i = 0; i < results.length; i++) {
                html += "<tr><td>";
                html += results[i].Cells.results[3].Value;
                html += "</td><td>"
                html += results[i].Cells.results[6].Value;
                html += "</td><tr>";
            }

            html += "</table>";

            $("#resultsDiv").append($(html));
        }

        function onError(err) {
            alert(JSON.stringify(err));
        }

10. _spPageContextInfo.webAbsoluteUrl可以直接在app中获取到当前站点的web绝对路径;

11. 

 

 

 

posted @ 2014-08-12 16:15  Jacky Ge  阅读(494)  评论(0编辑  收藏  举报