├── .gitattributes ├── .gitignore ├── BreezeSP2010Sample ├── App │ ├── App.js │ ├── Default.aspx │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── BreezeSP2010Sample.csproj ├── BreezeSP2010Sample.sln ├── Contacts │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── Features │ └── Feature1 │ │ ├── Feature1.EventReceiver.cs │ │ ├── Feature1.Template.xml │ │ └── Feature1.feature ├── Package │ ├── Package.Template.xml │ └── Package.package ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── Scripts │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── key.snk └── packages.config ├── BreezeSP2013Sample ├── AppManifest.xml ├── BreezeSP2013Sample.csproj ├── BreezeSP2013Sample.sln ├── Contacts │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── Content │ ├── App.css │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── Features │ └── Feature1 │ │ ├── Feature1.Template.xml │ │ └── Feature1.feature ├── Images │ ├── AppIcon.png │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── LICENSE ├── Package │ ├── Package.Template.xml │ └── Package.package ├── Pages │ ├── Default.aspx │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── README.md ├── Scripts │ ├── App.js │ ├── Elements.xml │ ├── SharePointProjectItem.spdata │ └── _references.js └── packages.config ├── LICENSE ├── README.md ├── SpRestBatchSample ├── AppManifest.xml ├── Contacts │ ├── ContactsInstance │ │ ├── Elements.xml │ │ └── SharePointProjectItem.spdata │ ├── Elements.xml │ ├── Schema.xml │ └── SharePointProjectItem.spdata ├── Content │ ├── App.css │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── Features │ └── Feature1 │ │ ├── Feature1.Template.xml │ │ └── Feature1.feature ├── Images │ ├── AppIcon.png │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── Package │ ├── Package.Template.xml │ └── Package.package ├── Pages │ ├── Default.aspx │ ├── Elements.xml │ └── SharePointProjectItem.spdata ├── README.md ├── Scripts │ ├── App.js │ ├── Elements.xml │ ├── SharePointProjectItem.spdata │ ├── _references.js │ ├── jquery-1.9.1.intellisense.js │ ├── jquery-1.9.1.js │ ├── jquery-1.9.1.min.js │ ├── jquery-1.9.1.min.map │ ├── knockout-3.2.0.debug.js │ ├── knockout-3.2.0.js │ ├── q.js │ └── q.min.js ├── SpRestBatchSample.csproj ├── SpRestBatchSample.sln └── packages.config └── adal-cors-client ├── .bowerrc ├── .gitignore ├── README.md ├── bower.json ├── gulpfile.config.js ├── gulpfile.config.ts ├── gulpfile.js ├── gulpfile.ts ├── package.json ├── src ├── app │ ├── app.adal.ts │ ├── app.constants.ts │ ├── app.module.ts │ ├── app.routes.ts │ ├── files │ │ ├── files.controller.ts │ │ └── files.html │ ├── layout │ │ ├── dashboard.html │ │ ├── nav.controller.ts │ │ └── nav.html │ ├── lists │ │ ├── lists.controller.ts │ │ └── lists.html │ ├── services │ │ ├── o365.service.ts │ │ └── sharepoint.service.ts │ └── shared │ │ ├── IAdalSettings.ts │ │ ├── IFile.ts │ │ ├── IHttpResponses.ts │ │ ├── INavRoute.ts │ │ ├── ISettings.ts │ │ └── ISpList.ts ├── content │ └── shuffle-animation.css └── index.html ├── superstatic.json ├── tools └── typings │ ├── angularjs │ ├── angular-animate.d.ts │ ├── angular-route.d.ts │ └── angular.d.ts │ ├── app.d.ts │ ├── gulp │ └── gulp.d.ts │ ├── jquery │ └── jquery.d.ts │ ├── node │ └── node.d.ts │ └── tsd.d.ts ├── tsd.json └── tslint.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior 2 | * text=auto 3 | 4 | *.md eol=crlf 5 | 6 | # Visual Studio files 7 | *.sln eol=crlf 8 | *.csproj eol=crlf 9 | *.ccproj eol=crlf 10 | *.config eol=crlf 11 | *.pubxml eol=crlf 12 | *.cscfg eol=crlf 13 | *.csdef eol=crlf 14 | *.wadcgf eol=crlf 15 | 16 | # source files 17 | *.js eol=crlf 18 | *.ts eol=crlf 19 | *.map eol=crlf 20 | *.json eol=crlf 21 | *.html eol=crlf 22 | *.cshtml eol=crlf 23 | *.cs eol=crlf diff=csharp 24 | *.css eol=crlf 25 | *.bat eol=crlf 26 | 27 | # images 28 | *.png binary 29 | *.jpg binary 30 | *.jpeg binary 31 | *.gif binary 32 | 33 | # OpenXML file formats 34 | *.pptx binary 35 | *.docx binary 36 | *.xlsx binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # ignore generic files from macos 5 | *~ 6 | *.lock 7 | *.DS_Store 8 | *.swp 9 | *.out 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | x64/ 21 | build/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | build/ 26 | 27 | # MSTest test Results 28 | [Tt]est[Rr]esult*/ 29 | [Bb]uild[Ll]og.* 30 | 31 | #NUNIT 32 | *.VisualState.xml 33 | TestResult.xml 34 | 35 | # Build Results of an ATL Project 36 | [Dd]ebugPS/ 37 | [Rr]eleasePS/ 38 | dlldata.c 39 | 40 | *_i.c 41 | *_p.c 42 | *_i.h 43 | *.ilk 44 | *.meta 45 | *.obj 46 | *.pch 47 | *.pdb 48 | *.pgc 49 | *.pgd 50 | *.rsp 51 | *.sbr 52 | *.tlb 53 | *.tli 54 | *.tlh 55 | *.tmp 56 | *.tmp_proj 57 | *.log 58 | *.vspscc 59 | *.vssscc 60 | .builds 61 | *.pidb 62 | *.svclog 63 | *.scc 64 | 65 | # Chutzpah Test files 66 | _Chutzpah* 67 | 68 | # Visual C++ cache files 69 | ipch/ 70 | *.aps 71 | *.ncb 72 | *.opensdf 73 | *.sdf 74 | *.cachefile 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | *.vspx 80 | 81 | # TFS 2012 Local Workspace 82 | $tf/ 83 | 84 | # Guidance Automation Toolkit 85 | *.gpState 86 | 87 | # ReSharper is a .NET coding add-in 88 | _ReSharper*/ 89 | *.[Rr]e[Ss]harper 90 | *.DotSettings.user 91 | 92 | # WebStorm is an IDE 93 | .idea* 94 | 95 | # JustCode is a .NET coding addin-in 96 | .JustCode 97 | 98 | # TeamCity is a build add-in 99 | _TeamCity* 100 | 101 | # DotCover is a Code Coverage Tool 102 | *.dotCover 103 | 104 | # NCrunch 105 | *.ncrunch* 106 | _NCrunch_* 107 | .*crunch*.local.xml 108 | 109 | # MightyMoose 110 | *.mm.* 111 | AutoTest.Net/ 112 | 113 | # Web workbench (sass) 114 | .sass-cache/ 115 | 116 | # Installshield output folder 117 | [Ee]xpress/ 118 | 119 | # DocProject is a documentation generator add-in 120 | DocProject/buildhelp/ 121 | DocProject/Help/*.HxT 122 | DocProject/Help/*.HxC 123 | DocProject/Help/*.hhc 124 | DocProject/Help/*.hhk 125 | DocProject/Help/*.hhp 126 | DocProject/Help/Html2 127 | DocProject/Help/html 128 | 129 | # Click-Once directory 130 | publish/ 131 | 132 | # Publish Web Output 133 | *.[Pp]ublish.xml 134 | *.azurePubxml 135 | 136 | # NuGet Packages Directory 137 | packages/ 138 | ## TODO: If the tool you use requires repositories.config uncomment the next line 139 | #!packages/repositories.config 140 | 141 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 142 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 143 | !packages/build/ 144 | 145 | # Windows Azure Build Output 146 | csx/ 147 | *.build.csdef 148 | 149 | # Windows Store app package directory 150 | AppPackages/ 151 | 152 | # Others 153 | sql/ 154 | *.Cache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | 165 | # RIA/Silverlight projects 166 | Generated_Code/ 167 | 168 | # Backup & report files from converting an old project file to a newer 169 | # Visual Studio version. Backup files are not needed, because we have git ;-) 170 | _UpgradeReport_Files/ 171 | Backup*/ 172 | UpgradeLog*.XML 173 | UpgradeLog*.htm 174 | 175 | # SQL Server files 176 | *.mdf 177 | *.ldf 178 | 179 | # Business Intelligence projects 180 | *.rdl.data 181 | *.bim.layout 182 | *.bim_*.settings 183 | 184 | # Microsoft Fakes 185 | FakesAssemblies/ -------------------------------------------------------------------------------- /BreezeSP2010Sample/App/App.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var metadataStore; 4 | var contactType; 5 | var entityManager; 6 | 7 | jQuery(document).ready(function () { 8 | // STEP 1: configure breeze 9 | configureBreeze(); 10 | 11 | // STEP 2: define the metadata for the entity 12 | createMetadata(); 13 | 14 | // STEP 3: init breeze 15 | initBreeze(); 16 | 17 | // enable the buttons 18 | jQuery('input[type="button"]').removeAttr('disabled'); 19 | }); 20 | 21 | // configure breeze 22 | function configureBreeze() { 23 | // configure breeze to use SharePoint 2010 OData service 24 | var dsAdapter = breeze.config.initializeAdapterInstance('dataService', 'SharePointOData2010', true); 25 | } 26 | 27 | // create the metadata for the rest endpoint 28 | function createMetadata() { 29 | // create a new breeze metadata store 30 | metadataStore = new breeze.MetadataStore(); 31 | 32 | // setup a helper to create entities 33 | var namespace = ''; 34 | var helper = new breeze.config.MetadataHelper(namespace, breeze.AutoGeneratedKeyType.Identity); 35 | // define a new function that uses the helper to 36 | // 1) create a new entity type in the metadata store 37 | // 2) create a default select so we don't have to create the 38 | // OData $select each time 39 | var addType = function (typeDef) { 40 | var entityType = helper.addTypeToStore(metadataStore, typeDef); 41 | _addDefaultSelect(entityType); 42 | return entityType; 43 | }; 44 | 45 | // create entity for contacts 46 | addType({ 47 | name: 'Contacts', 48 | defaultResourceName: 'Contacts', 49 | dataProperties: { 50 | Id: { type: breeze.DataType.Int32 }, 51 | FirstName: { nullable: false }, 52 | LastName: { nullable: false }, // this is actually the last name field in the list 53 | EMailAddress: { 54 | nullable: false, 55 | validators: [breeze.Validator.emailAddress()] 56 | } 57 | } 58 | }); 59 | 60 | // add 'defaultSelect' custom metadata that selects for all mapped data properties 61 | // could be used by SharePoint dataservice adapter to exclude unwanted property data 62 | // in query payload 63 | function _addDefaultSelect(type) { 64 | var custom = type.custom; 65 | // bail out if defined by hand already 66 | if (custom && custom.defaultSelect != null) { return; } 67 | 68 | var select = []; 69 | type.dataProperties.forEach(function (prop) { 70 | if (!prop.isUnmapped) { select.push(prop.name); } 71 | }); 72 | if (select.length) { 73 | if (!custom) { type.custom = custom = {}; } 74 | custom.defaultSelect = select.join(','); 75 | } 76 | return type; 77 | } 78 | 79 | } 80 | 81 | // init breeze for queries 82 | function initBreeze() { 83 | // get reference to contact entity type 84 | contactType = metadataStore.getEntityType('Contacts'); 85 | 86 | // create the data service 87 | var dataService = new breeze.DataService({ 88 | // tell breeze the root REST endpoint to use 89 | // since we only are using lists, point to that 90 | serviceName: 'http://yoursite.sharepoint.com/_vti_bin/listdata.svc/', 91 | // tell breeze not to interrogate sharepoint for it's 92 | // massive OData $metadata response... we created it manually 93 | hasServerMetadata: false 94 | }); 95 | 96 | // create an instance of the entity manager 97 | entityManager = new breeze.EntityManager({ 98 | dataService: dataService, 99 | // tell breeze where the metadata is 100 | metadataStore: metadataStore 101 | }); 102 | } 103 | 104 | // get all items from sharepoint REST API 105 | function getAllItems() { 106 | breeze.EntityQuery 107 | .from(contactType.defaultResourceName) 108 | .using(entityManager) 109 | .execute() 110 | .then(function (response) { 111 | var results = response.results; 112 | // write results > div 113 | if (results && results.length) { 114 | var message = ''; 115 | for (var index = 0; index < results.length; index++) { 116 | message += results[index].FirstName + ' ' + results[index].LastName + ' (' + results[index].EMailAddress + ')
'; 117 | } 118 | jQuery("#results").html(message); 119 | } 120 | }); 121 | return false; 122 | } 123 | 124 | // get a single item 125 | function getOneItem() { 126 | // try to get a single item from the cache, then revert to server 127 | entityManager.fetchEntityByKey('Contacts', 1, true) 128 | .then(function (data) { 129 | var message = data.entity.FirstName + ' ' + data.entity.LastName + ' (' + data.entity.EMailAddress + ')
'; 130 | message += 'pulled from: ' + (data.fromCache ? 'cache' : 'server'); 131 | jQuery("#results").html(message); 132 | }); 133 | } 134 | 135 | // update an item 136 | function updateFirstItem() { 137 | // get the first item 138 | var promise = entityManager.fetchEntityByKey('Contacts', 1, true) 139 | .then(function (data) { 140 | return data.entity; 141 | }); 142 | // update the first item 143 | promise.then(function (contact) { 144 | contact.LastName = 'NewName'; 145 | entityManager.saveChanges().then(function () { 146 | jQuery("#results").html('saved first item in list'); 147 | }); 148 | }); 149 | } 150 | 151 | // create a new contact 152 | function createItem() { 153 | // create entity 154 | var contact = entityManager.createEntity(contactType); 155 | contact.FirstName = 'Lewis'; 156 | contact.LastName = 'Hamilton'; 157 | contact.EMailAddress = 'lewis.hamilton@mercedes.com'; 158 | // save entity 159 | entityManager.saveChanges() 160 | .then(function () { 161 | jQuery("#results").html('new item created'); 162 | }); 163 | } 164 | 165 | // deletes the last item in the list 166 | function deleteItem() { 167 | // delete the last item in the list 168 | breeze.EntityQuery 169 | .from(contactType.defaultResourceName) 170 | .using(entityManager) 171 | .execute() 172 | .then(function (response) { 173 | var results = response.results; 174 | var lastContact = results[results.length - 1]; 175 | lastContact.entityAspect.setDeleted(); 176 | entityManager.saveChanges() 177 | .then(function () { 178 | jQuery("#results").html('last item in list deleted'); 179 | }); 180 | }); 181 | } -------------------------------------------------------------------------------- /BreezeSP2010Sample/App/Default.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page MasterPageFile="~masterurl/default.master" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Breeze JS + SharePoint 2010 Sample 16 | 17 | 18 | 19 |
20 |   21 |   22 |   23 |   24 | 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/App/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/App/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/BreezeSP2010Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B} 8 | Library 9 | Properties 10 | BreezeSP2010Sample 11 | BreezeSP2010Sample 12 | v3.5 13 | 512 14 | {BB1F664B-9266-4fd6-B973-E1E44974B511};{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | False 16 | True 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | true 39 | 40 | 41 | key.snk 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Feature1.feature 55 | 56 | 57 | 58 | 59 | 60 | {533a1d43-1a7d-44f3-9a9e-a7474563834c} 61 | 62 | 63 | {71720931-3293-4ce6-8fed-70f8acd8ae18} 64 | 65 | 66 | {4f37fac1-679c-43ad-b722-009ddcbaaae4} 67 | 68 | 69 | 70 | 71 | {f44222cc-b041-49ee-9e55-a8cb9dc45a3d} 72 | 73 | 74 | Package.package 75 | 76 | 77 | {ee1051d1-937c-461c-af00-652aa504a351} 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | Feature1.feature 88 | 89 | 90 | 91 | 92 | 93 | 10.0 94 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 95 | 96 | 97 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/BreezeSP2010Sample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BreezeSP2010Sample", "BreezeSP2010Sample.csproj", "{E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {E88ACB43-6E54-4DB6-9CE6-EC91C9B7230B}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Contacts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 11 | 12 | Daniil 13 | Kvyat 14 | daniil.kvyat@redbull.com 15 | 16 | 17 | Kimi 18 | Raikkonen 19 | kimi.Raikkonen@ferrari.it 20 | 21 | 22 | Sebastian 23 | Vettel 24 | Sebastian.vettel@ferrari.it 25 | 26 | 27 | Daniel 28 | Ricciardo 29 | daniel.ricciardo@redbull.com 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Contacts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Features/Feature1/Feature1.EventReceiver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Security.Permissions; 4 | using Microsoft.SharePoint; 5 | using Microsoft.SharePoint.Navigation; 6 | 7 | namespace BreezeSP2010Sample.Features.Feature1 { 8 | /// 9 | /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade. 10 | /// 11 | /// 12 | /// The GUID attached to this class may be used during packaging and should not be modified. 13 | /// 14 | 15 | [Guid("9ace6194-caee-447e-8036-06c118bd0b9c")] 16 | public class Feature1EventReceiver : SPFeatureReceiver { 17 | // Uncomment the method below to handle the event raised after a feature has been activated. 18 | 19 | public override void FeatureActivated(SPFeatureReceiverProperties properties) { 20 | var site = properties.Feature.Parent as SPWeb; 21 | if (site != null) { 22 | var topNav = site.Navigation.TopNavigationBar; 23 | topNav.AddAsLast(new SPNavigationNode("BreezeJS DEMO", "App/Default.aspx")); 24 | } 25 | } 26 | 27 | 28 | // Uncomment the method below to handle the event raised before a feature is deactivated. 29 | 30 | public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { 31 | var site = properties.Feature.Parent as SPWeb; 32 | if (site != null) { 33 | // delete the provisioned page 34 | try { 35 | var appFolder = site.GetFolder("App"); 36 | appFolder.Delete(); 37 | } catch { } 38 | 39 | // delete the navigation link 40 | var topNav = site.Navigation.TopNavigationBar; 41 | for (int index = topNav.Count - 1; index >= 0; index--) { 42 | if (topNav[index].Url.Contains("App/Default.aspx")) { 43 | topNav[index].Delete(); 44 | } 45 | } 46 | 47 | // delete the list 48 | var list = site.Lists.TryGetList("Contacts"); 49 | if (list != null) 50 | list.Delete(); 51 | } 52 | } 53 | 54 | 55 | // Uncomment the method below to handle the event raised after a feature has been installed. 56 | 57 | //public override void FeatureInstalled(SPFeatureReceiverProperties properties) 58 | //{ 59 | //} 60 | 61 | 62 | // Uncomment the method below to handle the event raised before a feature is uninstalled. 63 | 64 | //public override void FeatureUninstalling(SPFeatureReceiverProperties properties) 65 | //{ 66 | //} 67 | 68 | // Uncomment the method below to handle the event raised when a feature is upgrading. 69 | 70 | //public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary parameters) 71 | //{ 72 | //} 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Features/Feature1/Feature1.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Features/Feature1/Feature1.feature: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Package/Package.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Package/Package.package: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Security; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("BreezeSP2010Sample")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("BreezeSP2010Sample")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("e88acb43-6e54-4db6-9ce6-ec91c9b7230b")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/README.md: -------------------------------------------------------------------------------- 1 | SharePoint 2010 BreezeJS Reference Implementation 2 | ================================================= 3 | 4 | Sample SharePoint Hosted App that demonstrates using the BreezeJS library with SharePoint 2010's REST API. 5 | 6 | This is based off the work I did with [Ward Bell](http://www.twitter.com/wardbell) to get BreezeJS to work with SharePoint. Which you can read more about on my blog: [BreezeJS Makes Client-Side SharePoint 2013 REST Development a... BREEZE!](http://www.andrewconnell.com/blog/breezejs-makes-client-side-sharepoint-2013-rest-development-a-breeze) 7 | 8 | Work & improvements continue on the SharePoint data service adapter... check out my repository [andrewconnell/breeze.js.labs](http://www.github.com/andrewconnell/breeze.js.labs) which is a fork of the Breeze Labs repo where all SharePoint / Office 365 related work will go. 9 | 10 | Applies To: 11 | ----------- 12 | - SharePoint 2010 On-premises (versions: RTM to present) 13 | 14 | [![Analytics](https://ga-beacon.appspot.com/UA-59891462-1/sp-0365-rest/BreezeSP2010Sample)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /BreezeSP2010Sample/Scripts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/Scripts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2010Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewconnell/sp-o365-rest/58ba46f6f635766b67baab11db79d46d770420ce/BreezeSP2010Sample/key.snk -------------------------------------------------------------------------------- /BreezeSP2010Sample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/AppManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | BreezeSP2013Sample 11 | ~appWebUrl/Pages/Default.aspx?{StandardTokens} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/BreezeSP2013Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {07426DB5-A86F-4F7C-A763-517A8D91B405} 8 | Library 9 | Properties 10 | BreezeSP2013Sample 11 | BreezeSP2013Sample 12 | v4.5 13 | 15.0 14 | 512 15 | {C1CDDADD-2546-481F-9697-4EA41081F2FC};{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | False 17 | SharePointApp 18 | {342f20c5-2052-4a0e-80f5-0d9493945f81} 19 | {de525e08-1d26-456e-8923-32bfcba1d761} 20 | {6ad3d379-6dee-4323-a820-90ba3329bfdd} 21 | {9d441aa8-9020-4edc-87d9-02352903921e} 22 | {0a367f9a-235c-4d0e-aef3-aa3f664eef31} 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | false 33 | 34 | 35 | pdbonly 36 | true 37 | bin\Release\ 38 | TRACE 39 | prompt 40 | 4 41 | false 42 | 43 | 44 | 45 | {01f24112-1f83-4d61-b472-a9c6a63b87ff} 46 | 47 | 48 | 49 | {8553e16f-1395-4288-b246-c65cd1f46c99} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {0a367f9a-235c-4d0e-aef3-aa3f664eef31} 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | {0502a31a-2114-4b4f-bcd7-17bf5f071f04} 66 | 67 | 68 | 69 | 70 | 71 | 72 | manifest-icon 73 | 74 | 75 | 76 | {614d017c-fdc7-40de-be01-e68d3ddad5a5} 77 | 78 | 79 | 80 | 81 | {dbb9a9fb-50aa-48b2-9279-02debd2bd468} 82 | 83 | 84 | Package.package 85 | 86 | 87 | {1cdb43a2-6452-4f07-baa8-315e67f80900} 88 | 89 | 90 | Feature1.feature 91 | 92 | 93 | 94 | 95 | Designer 96 | 97 | 98 | 99 | 100 | 10.0 101 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 102 | 103 | 104 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/BreezeSP2013Sample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BreezeSP2013Sample", "BreezeSP2013Sample.csproj", "{07426DB5-A86F-4F7C-A763-517A8D91B405}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {07426DB5-A86F-4F7C-A763-517A8D91B405}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Contacts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 11 | 12 | Fernando 13 | Alanso 14 | fernando.alonso@ferrari.it 15 | 16 | 17 | Kimi 18 | Raikkonen 19 | kimi.Raikkonen@ferrari.it 20 | 21 | 22 | Sebastian 23 | Vettel 24 | Sebastian.vettel@redbull.com 25 | 26 | 27 | Daniel 28 | Ricciardo 29 | daniel.ricciardo@redbull.com 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Contacts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Content/App.css: -------------------------------------------------------------------------------- 1 | /* Place custom styles below */ 2 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Content/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Content/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Features/Feature1/Feature1.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Features/Feature1/Feature1.feature: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Images/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewconnell/sp-o365-rest/58ba46f6f635766b67baab11db79d46d770420ce/BreezeSP2013Sample/Images/AppIcon.png -------------------------------------------------------------------------------- /BreezeSP2013Sample/Images/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Images/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrew Connell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Package/Package.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Package/Package.package: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Pages/Default.aspx: -------------------------------------------------------------------------------- 1 | <%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%> 2 | 3 | <%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %> 4 | 5 | <%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 6 | <%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 7 | <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 8 | 9 | <%-- The markup and script in the following Content element will be placed in the of the page --%> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | <%-- The markup in the following Content element will be placed in the TitleArea of the page --%> 31 | 32 | Breeze JS + SharePoint 2013 Sample 33 | 34 | 35 | <%-- The markup and script in the following Content element will be placed in the of the page --%> 36 | 37 | 38 |
39 |   40 |   41 |   42 |   43 | 44 |
45 |
46 | 47 |
48 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Pages/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Pages/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/README.md: -------------------------------------------------------------------------------- 1 | SharePoint 2013 BreezeJS Reference Implementation 2 | ================================================= 3 | 4 | Sample SharePoint Hosted App that demonstrates using the BreezeJS library with SharePoint 2013's REST API. 5 | 6 | This is based off the work I did with [Ward Bell](http://www.twitter.com/wardbell) to get BreezeJS to work with SharePoint. Which you can read more about on my blog: [BreezeJS Makes Client-Side SharePoint 2013 REST Development a... BREEZE!](http://www.andrewconnell.com/blog/breezejs-makes-client-side-sharepoint-2013-rest-development-a-breeze) 7 | 8 | Work & improvements continue on the SharePoint data service adapter... check out my repository [andrewconnell/breeze.js.labs](http://www.github.com/andrewconnell/breeze.js.labs) which is a fork of the Breeze Labs repo where all SharePoint / Office 365 related work will go. 9 | 10 | Applies To: 11 | ----------- 12 | - SharePoint 2013 On-premises (versions: RTM to present) 13 | - Office 365 SharePont Online (versions: RTM to present) 14 | 15 | [![Analytics](https://ga-beacon.appspot.com/UA-59891462-1/sp-0365-rest/BreezeSP2013Sample)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /BreezeSP2013Sample/Scripts/App.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var metadataStore; 4 | var contactType; 5 | var entityManager; 6 | 7 | jQuery(document).ready(function () { 8 | // STEP 1: configure breeze 9 | configureBreeze(); 10 | 11 | // STEP 2: define the metadata for the entity 12 | createMetadata(); 13 | 14 | // STEP 3: init breeze 15 | initBreeze(); 16 | 17 | // enable the buttons 18 | jQuery('input[type="button"]').removeAttr('disabled'); 19 | }); 20 | 21 | // configure breeze 22 | function configureBreeze() { 23 | // configure breeze to use SharePoint OData service 24 | var dsAdapter = breeze.config.initializeAdapterInstance('dataService', 'SharePointOData', true); 25 | 26 | // tell breeze how to get the security validation token for 27 | // HTTP POST & DELETE calls 28 | dsAdapter.getRequestDigest = function () { 29 | return jQuery('#__REQUESTDIGEST').val(); 30 | }; 31 | } 32 | 33 | // create the metadata for the rest endpoint 34 | function createMetadata() { 35 | // create a new breeze metadata store 36 | metadataStore = new breeze.MetadataStore(); 37 | 38 | // setup a helper to create entities 39 | var namespace = ''; 40 | var helper = new breeze.config.MetadataHelper(namespace, breeze.AutoGeneratedKeyType.Identity); 41 | // define a new function that uses the helper to 42 | // 1) create a new entity type in the metadata store 43 | // 2) create a default select so we don't have to create the 44 | // OData $select each time 45 | var addType = function (typeDef) { 46 | var entityType = helper.addTypeToStore(metadataStore, typeDef); 47 | _addDefaultSelect(entityType); 48 | return entityType; 49 | }; 50 | 51 | // create entity for contacts 52 | addType({ 53 | name: 'Contacts', 54 | defaultResourceName: 'getbytitle(\'Contacts\')/items', 55 | dataProperties: { 56 | Id: { type: breeze.DataType.Int32 }, 57 | FirstName: { nullable: false }, 58 | Title: { nullable: false }, // this is actually the last name field in the list 59 | Email: { 60 | nullable: false, 61 | validators: [breeze.Validator.emailAddress()] 62 | } 63 | } 64 | }); 65 | 66 | // add 'defaultSelect' custom metadata that selects for all mapped data properties 67 | // could be used by SharePoint dataservice adapter to exclude unwanted property data 68 | // in query payload 69 | function _addDefaultSelect(type) { 70 | var custom = type.custom; 71 | // bail out if defined by hand already 72 | if (custom && custom.defaultSelect != null) { return; } 73 | 74 | var select = []; 75 | type.dataProperties.forEach(function (prop) { 76 | if (!prop.isUnmapped) { select.push(prop.name); } 77 | }); 78 | if (select.length) { 79 | if (!custom) { type.custom = custom = {}; } 80 | custom.defaultSelect = select.join(','); 81 | } 82 | return type; 83 | } 84 | 85 | } 86 | 87 | // init breeze for queries 88 | function initBreeze() { 89 | // get reference to contact entity type 90 | contactType = metadataStore.getEntityType('Contacts'); 91 | 92 | // create the data service 93 | var dataService = new breeze.DataService({ 94 | // tell breeze the root REST endpoint to use 95 | // since we only are using lists, point to that 96 | serviceName: _spPageContextInfo.webAbsoluteUrl + '/_api/web/lists/', 97 | // tell breeze not to interrogate sharepoint for it's 98 | // massive OData $metadata response... we created it manually 99 | hasServerMetadata: false 100 | }); 101 | 102 | // create an instance of the entity manager 103 | entityManager = new breeze.EntityManager({ 104 | dataService: dataService, 105 | // tell breeze where the metadata is 106 | metadataStore: metadataStore 107 | }); 108 | } 109 | 110 | // get all items from sharepoint REST API 111 | function getAllItems() { 112 | breeze.EntityQuery 113 | .from(contactType.defaultResourceName) 114 | .using(entityManager) 115 | .execute() 116 | .then(function (response) { 117 | var results = response.results; 118 | // write results > div 119 | if (results && results.length) { 120 | var message = ''; 121 | for (var index = 0; index < results.length; index++) { 122 | message += results[index].FirstName + ' ' + results[index].Title + ' (' + results[index].Email + ')
'; 123 | } 124 | jQuery("#results").html(message); 125 | } 126 | }); 127 | return false; 128 | } 129 | 130 | // get a single item 131 | function getOneItem() { 132 | // try to get a single item from the cache, then revert to server 133 | entityManager.fetchEntityByKey('Contacts', 1, true) 134 | .then(function (data) { 135 | var message = data.entity.FirstName + ' ' + data.entity.Title + ' (' + data.entity.Email + ')
'; 136 | message += 'pulled from: ' + (data.fromCache ? 'cache' : 'server'); 137 | jQuery("#results").html(message); 138 | }); 139 | } 140 | 141 | // update an item 142 | function updateFirstItem() { 143 | // get the first item 144 | var promise = entityManager.fetchEntityByKey('Contacts', 1, true) 145 | .then(function (data) { 146 | return data.entity; 147 | }); 148 | // update the first item 149 | promise.then(function (contact) { 150 | contact.Title = 'NewName'; 151 | entityManager.saveChanges().then(function () { 152 | jQuery("#results").html('saved first item in list'); 153 | }); 154 | }); 155 | } 156 | 157 | // create a new contact 158 | function createItem() { 159 | // create entity 160 | var contact = entityManager.createEntity(contactType); 161 | contact.FirstName = 'Lewis'; 162 | contact.Title = 'Hamilton'; 163 | contact.Email = 'lewis.hamilton@mercedes.com'; 164 | // save entity 165 | entityManager.saveChanges() 166 | .then(function () { 167 | jQuery("#results").html('new item created'); 168 | }); 169 | } 170 | 171 | // deletes the last item in the list 172 | function deleteItem() { 173 | // delete the last item in the list 174 | breeze.EntityQuery 175 | .from(contactType.defaultResourceName) 176 | .using(entityManager) 177 | .execute() 178 | .then(function (response) { 179 | var results = response.results; 180 | var lastContact = results[results.length - 1]; 181 | lastContact.entityAspect.setDeleted(); 182 | entityManager.saveChanges() 183 | .then(function () { 184 | jQuery("#results").html('last item in list deleted'); 185 | }); 186 | }); 187 | } -------------------------------------------------------------------------------- /BreezeSP2013Sample/Scripts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Scripts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BreezeSP2013Sample/Scripts/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewconnell/sp-o365-rest/58ba46f6f635766b67baab11db79d46d770420ce/BreezeSP2013Sample/Scripts/_references.js -------------------------------------------------------------------------------- /BreezeSP2013Sample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrew Connell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SharePoint & Office 365 REST API Resources 2 | ========================================== 3 | > This is a collection of links, samples & demos I've collected for the SharePoint and Office 365 REST API's. Got something to add? Fork this repo & submit a pull request! 4 | 5 | Samples in this Repo 6 | -------------------- 7 | Look at the readme files in each sample for more information on each of them. 8 | 9 | - **[adal-cors-client](adal-cors-client)**: Demonstrates how to use the ADAL JS & support for OAuth2 Implicit Flow to create a 100% client-side secure solution with Azure AD, Angular & Office 365's SharePoint & Files REST APIs. 10 | - **[BreezeSP2010Sample](BreezeSP2010Sample)**: Demonstrates how to use the [BreezeJS](http://www.breezejs.com) library to simplify client-side interactions with the SharePoint 2010 REST API. 11 | - **[BreezeSP2013Sample](BreezeSP2013Sample)**: Demonstrates how to use the [BreezeJS](http://www.breezejs.com) library to simplify client-side interactions with the SharePoint 2013 REST API. 12 | - **[SpRestBatchSample](SpRestBatchSample)**: Demonstrates how to create and consume OData batch requests using the SharePoint Online RETS API in Office 365. 13 | 14 | Official Documentation References 15 | --------------------------------- 16 | - Ray Fielding's original Thesis: [Representational State Transfer (REST)](http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) 17 | - [OData.org](http://www.odata.org) 18 | + [OData v3.0 Specification](http://www.odata.org/documentation/odata-version-3-0/) 19 | + [OData v4.0 Specification](http://www.odata.org/documentation/odata-version-4-0/) 20 | - [MSDN](http://msdn.microsoft.com) 21 | + [WCF Data Services](http://msdn.microsoft.com/en-us/data/odata.aspx) - Microsoft's product that implements the OData specification on the .NET stack. 22 | + [SharePoint Query OData Protocol Doc](http://msdn.microsoft.com/en-us/library/hh642209.aspx) 23 | + [SharePoint ListData Data Service Protocol Doc](http://msdn.microsoft.com/en-us/library/dd960495.aspx) 24 | + [SharePoint 2013 REST API Reference](http://msdn.microsoft.com/en-us/library/office/dn593591.aspx) 25 | 26 | Links 27 | ----- 28 | - My [REST related blog posts](http://www.andrewconnell.com/Search?q=REST) 29 | - [SharePoint 2013: CSOM vs. REST ... My Preference and Why](http://www.andrewconnell.com/blog/sharepoint-2013-csom-vs.-rest-...-my-preference-and-why) 30 | - [Simplifying SharePoint 2013 REST API](http://www.andrewconnell.com/blog/simplifying-sharepoint-2013-rest-api) 31 | - [Applying Filters to Lookup Fields with the SharePoint 2013 REST API](http://www.andrewconnell.com/blog/Applying-Filters-to-Lookup-Fields-with-the-SP2013-REST-API) 32 | - [Part 1 - SharePoint REST API Batching - Understanding Batching Requests](http://www.andrewconnell.com/blog/part-1-sharepoint-rest-api-batching-understanding-batching-requests) 33 | - [Part 2 - SharePoint REST API Batching - Exploring Batch Requests, Responses and Changesets](http://www.andrewconnell.com/blog/part-2-sharepoint-rest-api-batching-exploring-batch-requests-responses-and-changesets) 34 | - SharePoint 2013 / Office 365 35 | - [BreezeJS Makes Client-Side SharePoint 2013 REST Development a... BREEZE!](http://www.andrewconnell.com/blog/breezejs-makes-client-side-sharepoint-2013-rest-development-a-breeze) 36 | 37 | Training / Classes 38 | ------------------ 39 | - :moneybag: Howard Dierking's Pluralsight Course [REST Fundamentals](http://www.pluralsight.com/courses/rest-fundamentals) 40 | - :moneybag: Rob Windsor's Pluralsight Course [SharePoint 2013 Development: Client Object Model and REST API](http://www.andrewconnell.com/blog/sharepoint-2013-csom-vs.-rest-...-my-preference-and-why) 41 | - :moneybag: Sahil Malik's Pluralsight Course [Understanding SharePoint 2013: Part 5 - REST and CSOM](http://www.pluralsight.com/courses/understanding-sharepoint2013-rest-client-side-object-model) 42 | 43 | [![Analytics](https://ga-beacon.appspot.com/UA-59891462-1/sp-0365-rest/readme)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /SpRestBatchSample/AppManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | SpRestBatchSample 11 | ~appWebUrl/Pages/Default.aspx?{StandardTokens} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /SpRestBatchSample/Contacts/ContactsInstance/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /SpRestBatchSample/Contacts/ContactsInstance/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SpRestBatchSample/Contacts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14 | 15 | -------------------------------------------------------------------------------- /SpRestBatchSample/Contacts/Schema.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | main.xsl 19 | 30 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | main.xsl 36 | clienttemplates.js 37 | 30 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /SpRestBatchSample/Contacts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /SpRestBatchSample/Content/App.css: -------------------------------------------------------------------------------- 1 | /* Place custom styles below */ 2 | -------------------------------------------------------------------------------- /SpRestBatchSample/Content/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SpRestBatchSample/Content/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SpRestBatchSample/Features/Feature1/Feature1.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /SpRestBatchSample/Features/Feature1/Feature1.feature: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SpRestBatchSample/Images/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewconnell/sp-o365-rest/58ba46f6f635766b67baab11db79d46d770420ce/SpRestBatchSample/Images/AppIcon.png -------------------------------------------------------------------------------- /SpRestBatchSample/Images/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SpRestBatchSample/Images/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SpRestBatchSample/Package/Package.Template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /SpRestBatchSample/Package/Package.package: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SpRestBatchSample/Pages/Default.aspx: -------------------------------------------------------------------------------- 1 | <%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%> 2 | 3 | <%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %> 4 | 5 | <%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 6 | <%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 7 | <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 8 | 9 | <%-- The markup and script in the following Content element will be placed in the of the page --%> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | <%-- The markup in the following Content element will be placed in the TitleArea of the page --%> 26 | 27 | REST Batching Support 28 | 29 | 30 | <%-- The markup and script in the following Content element will be placed in the of the page --%> 31 | 32 | 33 |
34 | Jump to the Drivers list. 35 |
36 | 37 |

Contents of the Driver's List

38 |
39 | 40 | Submit requests using OData batches. 41 | 42 |

43 | 44 |   47 |
50 |   53 |   56 |
59 | 62 |
63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 |
IDTeamDriver NameCreated Date
82 |
83 | 84 |
85 | -------------------------------------------------------------------------------- /SpRestBatchSample/Pages/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SpRestBatchSample/Pages/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SpRestBatchSample/README.md: -------------------------------------------------------------------------------- 1 | Sample SharePoint Hosted App that demonstrates how to do simple REST operations with the SharePoint 2013 REST API. 2 | 3 | For an explanation on how batching works, see these two blog posts: 4 | - [Part 1 - SharePoint REST API Batching - Understanding Batching Requests](http://www.andrewconnell.com/blog/part-1-sharepoint-rest-api-batching-understanding-batching-requests) 5 | - [Part 2 - SharePoint REST API Batching - Exploring Batch Requests, Responses and Changesets](http://www.andrewconnell.com/blog/part-2-sharepoint-rest-api-batching-exploring-batch-requests-responses-and-changesets) 6 | 7 | This demonstrates how to do simple CRUD operations but also demonstrates how to create batches of individual requests. Checking the batch button on the page will force the app to use the OData `$batch` operator when adding, deleting & updating the drivers. This will issue a single HTTP request instead of a series of HTTP requests... a significant performance improvement! 8 | 9 | Watch the browser console or use a HTTP debugging proxy like Fiddler to watch the traffic sent across. 10 | 11 | > Note: for the update & delete operations to work, you must first insert drivers for all three teams first. No error checking has been added to ensure you only add one team's drivers once in the list. 12 | 13 | Applies To: 14 | ----------- 15 | - SharePoint 2013 On-premises (versions: *TBD*) 16 | - Office 365 SharePont Online (versions: *TBD*) 17 | 18 | Known Issues: 19 | ---- 20 | - The batch response coming back from SharePoint's REST API is not including changeset references as per the OData [v3.0](http://www.odata.org/documentation/odata-version-3-0/batch-processing/) & [v4.0 spec](http://docs.oasis-open.org/odata/odata/v4.0/errata01/os/complete/part1-protocol/odata-v4.0-errata01-os-part1-protocol-complete.html#_Toc399426860) indicate that it should. However the order of the responses coming back from the batch request match the order of the requests in the initial batch request. 21 | 22 | [![Analytics](https://ga-beacon.appspot.com/UA-59891462-1/sp-0365-rest/SpRestBatchSample)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /SpRestBatchSample/Scripts/App.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * View model used for the page in binding with knockout.js 6 | */ 7 | var DriversModel = function () { 8 | var self = this; 9 | self.drivers = ko.observableArray([]); 10 | self.submitAsBatch = ko.observable(false); 11 | 12 | /** 13 | * @name getAllDrivers 14 | * @description 15 | * Gets all drivers from the SharePoint 'Drivers' list & stuffs them into an observable array. 16 | */ 17 | self.getAllDrivers = function () { 18 | console.log('getAllDrivers()'); 19 | 20 | // build endpoint 21 | var endpoint = _spPageContextInfo.webAbsoluteUrl 22 | + '/_api/web/lists/getbytitle(\'Drivers\')' 23 | + '/items?$orderby=Title'; 24 | 25 | var requestHeaders = { 26 | 'Accept': 'application/json;odata=verbose' 27 | }; 28 | 29 | // issue request 30 | return jQuery.ajax({ 31 | url: endpoint, 32 | type: 'GET', 33 | headers: requestHeaders 34 | } 35 | ).done(function (response) { 36 | console.log(response); 37 | // clear the view model 38 | self.drivers([]); 39 | // set response > drivers collection 40 | self.drivers(response.d.results); 41 | }); 42 | 43 | } 44 | 45 | /** 46 | * @name addDrivers 47 | * @description 48 | * Creates a JSON array of drivers to add to the SharePoint 'Drivers' list. 49 | * 50 | * @param {string} teamId - Name of the F1 team to add two drivers for (mercedes / ferrari / redbull). 51 | */ 52 | self.addDrivers = function (teamId) { 53 | console.log('addDrivers()'); 54 | 55 | var driversAsJson = undefined; 56 | 57 | switch (teamId) { 58 | // if mercedes.... GRRR 59 | case 'mercedes': 60 | driversAsJson = [ 61 | { 62 | __metadata: { 63 | type: 'SP.Data.DriversListItem' 64 | }, 65 | Title: 'Nico Rossberg', 66 | Team: 'Mercedes' 67 | }, 68 | { 69 | __metadata: { 70 | type: 'SP.Data.DriversListItem' 71 | }, 72 | Title: 'Lewis Hamilton', 73 | Team: 'Mercedes' 74 | } 75 | ]; 76 | break; 77 | // if ferrari..... WOOT! 78 | case 'ferrari': 79 | driversAsJson = [ 80 | { 81 | __metadata: { 82 | type: 'SP.Data.DriversListItem' 83 | }, 84 | Title: 'Fernando Alonso', 85 | Team: 'Ferrari' 86 | }, 87 | { 88 | __metadata: { 89 | type: 'SP.Data.DriversListItem' 90 | }, 91 | Title: 'Filipe Massa', 92 | Team: 'Ferrari' 93 | } 94 | ]; 95 | break; 96 | // if red bull.... BOOOO! 97 | case 'redbull': 98 | driversAsJson = [ 99 | { 100 | __metadata: { 101 | type: 'SP.Data.DriversListItem' 102 | }, 103 | Title: 'Sebastian Vettel', 104 | Team: 'Red Bull' 105 | }, 106 | { 107 | __metadata: { 108 | type: 'SP.Data.DriversListItem' 109 | }, 110 | Title: 'Mark Webber', 111 | Team: 'Red Bull' 112 | } 113 | ]; 114 | break; 115 | } 116 | 117 | addTeamDrivers(driversAsJson); 118 | } 119 | 120 | /** 121 | * @name addTeamDrivers 122 | * @description 123 | * Takes a collection of drivers and adds them to the SharePoint 'Drivers' list. 124 | * This doesn't create the drivers, rather it calls other internal functions that create them using 125 | * a single batch request or multiple requests. 126 | * 127 | * @param {Array{Object}} driversAsJson - JSON array of drivers to add. 128 | * 129 | */ 130 | function addTeamDrivers(driversAsJson) { 131 | console.log('addTeamDrivers()' + driversAsJson); 132 | 133 | // send single request or batch? 134 | if (self.submitAsBatch() === true) { 135 | addTeamDriversBatchRequest(driversAsJson); 136 | } else { 137 | addTeamDriverMultipleRequests(driversAsJson); 138 | } 139 | } 140 | 141 | /** 142 | * @name addTeamDriversBatchRequest 143 | * @description 144 | * Adds drivers in a single batch request. 145 | * 146 | * @param {Array{Object}} driversAsJson - JSON array of drivers to add. 147 | */ 148 | function addTeamDriversBatchRequest(driversAsJson) { 149 | console.log('addTeamDriversBatchRequest()', driversAsJson); 150 | 151 | 152 | // generate a batch boundary 153 | var batchGuid = generateUUID(); 154 | 155 | // creating the body 156 | var batchContents = new Array(); 157 | var changeSetId = generateUUID(); 158 | 159 | // get current host 160 | var temp = document.createElement('a'); 161 | temp.href = _spPageContextInfo.webAbsoluteUrl; 162 | var host = temp.hostname; 163 | 164 | // for each driver... 165 | for (var driverIndex = 0; driverIndex < driversAsJson.length; driverIndex++) { 166 | 167 | var driver = driversAsJson[driverIndex]; 168 | 169 | // create the request endpoint 170 | var endpoint = _spPageContextInfo.webAbsoluteUrl 171 | + '/_api/web/lists/getbytitle(\'Drivers\')' 172 | + '/items'; 173 | 174 | // create the changeset 175 | batchContents.push('--changeset_' + changeSetId); 176 | batchContents.push('Content-Type: application/http'); 177 | batchContents.push('Content-Transfer-Encoding: binary'); 178 | batchContents.push(''); 179 | batchContents.push('POST ' + endpoint + ' HTTP/1.1'); 180 | batchContents.push('Content-Type: application/json;odata=verbose'); 181 | batchContents.push(''); 182 | batchContents.push(JSON.stringify(driver)); 183 | batchContents.push(''); 184 | } 185 | // END changeset to create data 186 | batchContents.push('--changeset_' + changeSetId + '--'); 187 | 188 | 189 | // generate the body of the batch 190 | var batchBody = batchContents.join('\r\n'); 191 | 192 | // start with a clean array 193 | batchContents = new Array(); 194 | 195 | // create batch for creating items 196 | batchContents.push('--batch_' + batchGuid); 197 | batchContents.push('Content-Type: multipart/mixed; boundary="changeset_' + changeSetId + '"'); 198 | batchContents.push('Content-Length: ' + batchBody.length); 199 | batchContents.push('Content-Transfer-Encoding: binary'); 200 | batchContents.push(''); 201 | batchContents.push(batchBody); 202 | batchContents.push(''); 203 | 204 | // create request in batch to get all items after all are created 205 | endpoint = _spPageContextInfo.webAbsoluteUrl 206 | + '/_api/web/lists/getbytitle(\'Drivers\')' 207 | + '/items?$orderby=Title'; 208 | 209 | 210 | batchContents.push('--batch_' + batchGuid); 211 | batchContents.push('Content-Type: application/http'); 212 | batchContents.push('Content-Transfer-Encoding: binary'); 213 | batchContents.push(''); 214 | batchContents.push('GET ' + endpoint + ' HTTP/1.1'); 215 | batchContents.push('Accept: application/json;odata=verbose'); 216 | batchContents.push(''); 217 | 218 | batchContents.push('--batch_' + batchGuid + '--'); 219 | 220 | batchBody = batchContents.join('\r\n'); 221 | 222 | // create the batch 223 | console.debug(batchBody); 224 | 225 | // create the request endpoint 226 | var endpoint = _spPageContextInfo.webAbsoluteUrl 227 | + '/_api/$batch'; 228 | 229 | // batches need a specific header 230 | var batchRequestHeader = { 231 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val(), 232 | 'Content-Type': 'multipart/mixed; boundary="batch_' + batchGuid + '"' 233 | }; 234 | 235 | // create request 236 | jQuery.ajax({ 237 | url: endpoint, 238 | type: 'POST', 239 | headers: batchRequestHeader, 240 | data: batchBody, 241 | success: function (response) { 242 | console.log('.. create driver PASS ', response); 243 | 244 | var responseInLines = response.split('\n'); 245 | 246 | // read each line until you find JSON... 247 | for (var currentLine = 0; currentLine < responseInLines.length; currentLine++) { 248 | try { 249 | // parse the JSON response... 250 | var tryParseJson = JSON.parse(responseInLines[currentLine]); 251 | 252 | // clear the view model 253 | self.drivers([]); 254 | // set response > drivers collection 255 | self.drivers(tryParseJson.d.results); 256 | 257 | } catch (e) { 258 | // don't do anything... just keep moving 259 | } 260 | } 261 | }, 262 | fail: function (error) { 263 | console.log('.. create driver FAIL ', error); 264 | } 265 | }); 266 | } 267 | 268 | /** 269 | * @name deleteDriversMultipleRequests 270 | * @description 271 | * Adds drivers in multiple HTTP requests (one per driver). 272 | * 273 | * @param {Array{Object}} driversAsJson - JSON array of drivers to add. 274 | */ 275 | function addTeamDriverMultipleRequests(driversAsJson) { 276 | console.log('addTeamDriversMultipleRequests()', driversAsJson); 277 | 278 | // build request endpoint 279 | var endpoint = _spPageContextInfo.webAbsoluteUrl 280 | + '/_api/web/lists/getbytitle(\'Drivers\')' 281 | + '/items'; 282 | 283 | // build common request headers 284 | var requestHeaders = { 285 | 'Accept': 'application/json;odata=verbose', 286 | 'Content-Type': 'application/json;odata=verbose', 287 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val() 288 | }; 289 | 290 | // will store requests in promise array 291 | var jobs = []; 292 | 293 | // loop through all drivers and create separate requests for each one... 294 | for (var driverIndex = 0; driverIndex < driversAsJson.length; driverIndex++) { 295 | 296 | // create request... 297 | var promise = jQuery.ajax({ 298 | url: endpoint, 299 | type: 'POST', 300 | headers: requestHeaders, 301 | data: JSON.stringify(driversAsJson[driverIndex]), 302 | success: function (response) { 303 | console.log('.. add driver PASS ', response); 304 | }, 305 | fail: function (error) { 306 | console.log('.. add driver FAIL ', error); 307 | } 308 | }); 309 | 310 | // add the request to the collection of jobs 311 | console.log('.. create driver add request # ' + driverIndex); 312 | jobs.push(promise); 313 | } 314 | 315 | console.log('request jobs', jobs); 316 | 317 | // when all jobs are complete... 318 | Q.all(jobs) 319 | .then(function () { 320 | console.log('all requests finished'); 321 | // refresh the collection 322 | self.getAllDrivers(); 323 | }); 324 | 325 | } 326 | 327 | /** 328 | * @name updateDrivers 329 | * @description 330 | * Updates the Ferrari & Red Bull teams > 2014 drivers. 331 | */ 332 | self.updateDrivers = function () { 333 | console.log('updateDrivers()'); 334 | 335 | var driverToUpdate = undefined; 336 | var driversToUpdate = []; 337 | 338 | // update ferrari 339 | driverToUpdate = self.drivers().filter(function (driver) { 340 | return (driver.Title == 'Filipe Massa'); 341 | })[0]; 342 | driverToUpdate.Title = 'Kimi Räikkönen'; 343 | driversToUpdate.push(driverToUpdate); 344 | 345 | // update red bull 346 | driverToUpdate = self.drivers().filter(function (driver) { 347 | return (driver.Title == 'Mark Webber'); 348 | })[0]; 349 | driverToUpdate.Title = 'Daniel Ricciardo'; 350 | driversToUpdate.push(driverToUpdate); 351 | 352 | 353 | // send single request or batch? 354 | if (self.submitAsBatch() === true) { 355 | updateTeamDriversBatchRequest(driversToUpdate); 356 | } else { 357 | updateTeamDriversMultipleRequests(driversToUpdate); 358 | } 359 | } 360 | 361 | /** 362 | * @name updateTeamDriversBatchRequest 363 | * @description 364 | * Submits the updates as a single batch request. 365 | * 366 | * @param {Array{Object}} driversToUpdate - JSON array of drivers to update. 367 | */ 368 | function updateTeamDriversBatchRequest(driversToUpdate) { 369 | console.log('updateTeamDriversBatchRequest()' + driversToUpdate); 370 | 371 | // generate a batch boundary 372 | var batchGuid = generateUUID(); 373 | 374 | // creating the body 375 | var batchContents = new Array(); 376 | var changeSetId = generateUUID(); 377 | 378 | // get current host 379 | var temp = document.createElement('a'); 380 | temp.href = _spPageContextInfo.webAbsoluteUrl; 381 | var host = temp.hostname; 382 | 383 | // for each driver... 384 | for (var driverIndex = 0; driverIndex < driversToUpdate.length; driverIndex++) { 385 | 386 | var driver = driversToUpdate[driverIndex]; 387 | 388 | // convert driver > update object 389 | var driverUpdater = { 390 | __metadata: { 391 | 'type': driver.__metadata.type 392 | }, 393 | Title: driver.Title 394 | }; 395 | 396 | // create the request endpoint 397 | var endpoint = _spPageContextInfo.webAbsoluteUrl 398 | + '/_api/web/lists/getbytitle(\'Drivers\')' 399 | + '/items(' + driver.Id + ')'; 400 | 401 | // create the changeset 402 | batchContents.push('--changeset_' + changeSetId); 403 | batchContents.push('Content-Type: application/http'); 404 | batchContents.push('Content-Transfer-Encoding: binary'); 405 | batchContents.push(''); 406 | batchContents.push('PATCH ' + endpoint + ' HTTP/1.1'); 407 | batchContents.push('Content-Type: application/json;odata=verbose'); 408 | batchContents.push('Accept: application/json;odata=verbose'); 409 | batchContents.push('If-Match: ' +driver.__metadata.etag); 410 | batchContents.push(''); 411 | batchContents.push(JSON.stringify(driverUpdater)); 412 | batchContents.push(''); 413 | } 414 | // END changeset to update data 415 | batchContents.push('--changeset_' + changeSetId + '--'); 416 | 417 | 418 | // generate the body of the batch 419 | var batchBody = batchContents.join('\r\n'); 420 | 421 | // start with a clean array 422 | batchContents = new Array(); 423 | 424 | // create batch for update items 425 | batchContents.push('--batch_' + batchGuid); 426 | batchContents.push('Content-Type: multipart/mixed; boundary="changeset_' + changeSetId + '"'); 427 | batchContents.push('Content-Length: ' + batchBody.length); 428 | batchContents.push('Content-Transfer-Encoding: binary'); 429 | batchContents.push(''); 430 | batchContents.push(batchBody); 431 | batchContents.push(''); 432 | 433 | // create request in batch to get all items after all are deleted 434 | endpoint = _spPageContextInfo.webAbsoluteUrl 435 | + '/_api/web/lists/getbytitle(\'Drivers\')' 436 | + '/items?$orderby=Title'; 437 | 438 | 439 | batchContents.push('--batch_' + batchGuid); 440 | batchContents.push('Content-Type: application/http'); 441 | batchContents.push('Content-Transfer-Encoding: binary'); 442 | batchContents.push(''); 443 | batchContents.push('GET ' + endpoint + ' HTTP/1.1'); 444 | batchContents.push('Accept: application/json;odata=verbose'); 445 | batchContents.push(''); 446 | 447 | batchContents.push('--batch_' + batchGuid + '--'); 448 | 449 | batchBody = batchContents.join('\r\n'); 450 | 451 | // create the batch 452 | console.debug(batchBody); 453 | 454 | // create the request endpoint 455 | var endpoint = _spPageContextInfo.webAbsoluteUrl 456 | + '/_api/$batch'; 457 | 458 | // batches need a specific header 459 | var batchRequestHeader = { 460 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val(), 461 | 'Content-Type': 'multipart/mixed; boundary="batch_' + batchGuid + '"' 462 | }; 463 | 464 | // create request 465 | jQuery.ajax({ 466 | url: endpoint, 467 | type: 'POST', 468 | headers: batchRequestHeader, 469 | data: batchBody, 470 | success: function (response) { 471 | console.log('.. delete driver PASS ', response); 472 | 473 | var responseInLines = response.split('\n'); 474 | 475 | // read each line until you find JSON... 476 | for (var currentLine = 0; currentLine < responseInLines.length; currentLine++) { 477 | try { 478 | // parse the JSON response... 479 | var tryParseJson = JSON.parse(responseInLines[currentLine]); 480 | 481 | // clear the view model 482 | self.drivers([]); 483 | // set response > drivers collection 484 | self.drivers(tryParseJson.d.results); 485 | 486 | } catch (e) { 487 | // don't do anything... just keep moving 488 | } 489 | } 490 | }, 491 | fail: function (error) { 492 | console.log('.. update driver FAIL ', error); 493 | } 494 | }); 495 | } 496 | 497 | /** 498 | * @name updateTeamDriversMultipleRequests 499 | * @description 500 | * Submits the updates in multiple requests (one per update). 501 | * 502 | * @param {Array{Object}} driversToUpdate - JSON array of drivers to update. 503 | */ 504 | function updateTeamDriversMultipleRequests(driversToUpdate) { 505 | console.log('updateTeamDriversMultipleRequest()' + driversToUpdate); 506 | 507 | // store all jobs 508 | var jobs = []; 509 | 510 | for (var driverIndex = 0; driverIndex < driversToUpdate.length; driverIndex++) { 511 | 512 | var driver = driversToUpdate[driverIndex]; 513 | 514 | var requestHeaders = { 515 | 'Accept': 'application/json;odata=verbose', 516 | 'Content-Type': 'application/json;odata=verbose', 517 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val(), 518 | 'X-Http-Method': 'MERGE', 519 | 'If-Match': driver.__metadata.etag 520 | }; 521 | 522 | // create the request endpoint 523 | var endpoint = _spPageContextInfo.webAbsoluteUrl 524 | + '/_api/web/lists/getbytitle(\'Drivers\')' 525 | + '/items(' + driver.Id + ')'; 526 | 527 | // convert driver > update object 528 | var driverUpdater = { 529 | __metadata: { 530 | 'type': driver.__metadata.type 531 | }, 532 | Title: driver.Title 533 | }; 534 | 535 | // create request... 536 | var promise = jQuery.ajax({ 537 | url: endpoint, 538 | type: 'POST', 539 | headers: requestHeaders, 540 | data: JSON.stringify(driverUpdater), 541 | success: function (response) { 542 | console.log('.. update driver PASS ', response); 543 | }, 544 | fail: function (error) { 545 | console.log('.. update driver FAIL ', error); 546 | } 547 | }); 548 | 549 | // add the request to the collection of jobs 550 | console.log('.. created driver update request # ' + driverIndex); 551 | jobs.push(promise); 552 | } 553 | 554 | // when all jobs are complete... 555 | Q.all(jobs) 556 | .then(function () { 557 | console.log('all requests finished'); 558 | // refresh the collection 559 | self.getAllDrivers(); 560 | }); 561 | } 562 | 563 | /** 564 | * @name deleteAllDrivers 565 | * @description 566 | * Based on the flag if batches should be used, deletes all the drivers from the SharePoint 'Drivers 567 | * list using multiple HTTP requests or a single batch request. 568 | */ 569 | self.deleteAllDrivers = function () { 570 | // send single request or batch? 571 | if (self.submitAsBatch() === true) { 572 | deleteDriversBatchRequest(); 573 | } else { 574 | deleteDriversMultipleRequests(); 575 | } 576 | } 577 | 578 | /** 579 | * @name deleteDriversBatchRequest 580 | * @description 581 | * Deletes all drivers in a single HTTP request. 582 | */ 583 | function deleteDriversBatchRequest() { 584 | console.log('deleteDriversBatchRequest()'); 585 | 586 | // generate a batch boundary 587 | var batchGuid = generateUUID(); 588 | 589 | // creating the body 590 | var batchContents = new Array(); 591 | var changeSetId = generateUUID(); 592 | 593 | // get current host 594 | var temp = document.createElement('a'); 595 | temp.href = _spPageContextInfo.webAbsoluteUrl; 596 | var host = temp.hostname; 597 | 598 | // for each driver... 599 | for (var driverIndex = 0; driverIndex < self.drivers().length; driverIndex++) { 600 | 601 | var driver = self.drivers()[driverIndex]; 602 | 603 | // create the request endpoint 604 | var endpoint = _spPageContextInfo.webAbsoluteUrl 605 | + '/_api/web/lists/getbytitle(\'Drivers\')' 606 | + '/items(' + driver.Id + ')'; 607 | 608 | // create the changeset 609 | batchContents.push('--changeset_' + changeSetId); 610 | batchContents.push('Content-Type: application/http'); 611 | batchContents.push('Content-Transfer-Encoding: binary'); 612 | batchContents.push(''); 613 | batchContents.push('DELETE ' + endpoint + ' HTTP/1.1'); 614 | batchContents.push('If-Match: *'); 615 | 616 | batchContents.push(''); 617 | } 618 | // END changeset to delete data 619 | batchContents.push('--changeset_' + changeSetId + '--'); 620 | 621 | 622 | // generate the body of the batch 623 | var batchBody = batchContents.join('\r\n'); 624 | 625 | // start with a clean array 626 | batchContents = new Array(); 627 | 628 | // create batch for deleting items 629 | batchContents.push('--batch_' + batchGuid); 630 | batchContents.push('Content-Type: multipart/mixed; boundary="changeset_' + changeSetId + '"'); 631 | batchContents.push('Content-Length: ' + batchBody.length); 632 | batchContents.push('Content-Transfer-Encoding: binary'); 633 | batchContents.push(''); 634 | batchContents.push(batchBody); 635 | batchContents.push(''); 636 | 637 | // create request in batch to get all items after all are deleted 638 | endpoint = _spPageContextInfo.webAbsoluteUrl 639 | + '/_api/web/lists/getbytitle(\'Drivers\')' 640 | + '/items?$orderby=Title'; 641 | 642 | 643 | batchContents.push('--batch_' + batchGuid); 644 | batchContents.push('Content-Type: application/http'); 645 | batchContents.push('Content-Transfer-Encoding: binary'); 646 | batchContents.push(''); 647 | batchContents.push('GET ' + endpoint + ' HTTP/1.1'); 648 | batchContents.push('Accept: application/json;odata=verbose'); 649 | batchContents.push(''); 650 | 651 | batchContents.push('--batch_' + batchGuid + '--'); 652 | 653 | batchBody = batchContents.join('\r\n'); 654 | 655 | // create the batch 656 | console.debug(batchBody); 657 | 658 | // create the request endpoint 659 | var endpoint = _spPageContextInfo.webAbsoluteUrl 660 | + '/_api/$batch'; 661 | 662 | // batches need a specific header 663 | var batchRequestHeader = { 664 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val(), 665 | 'Content-Type': 'multipart/mixed; boundary="batch_' + batchGuid + '"' 666 | }; 667 | 668 | // create request 669 | jQuery.ajax({ 670 | url: endpoint, 671 | type: 'POST', 672 | headers: batchRequestHeader, 673 | data: batchBody, 674 | success: function (response) { 675 | console.log('.. delete driver PASS ', response); 676 | 677 | var responseInLines = response.split('\n'); 678 | 679 | // read each line until you find JSON... 680 | for (var currentLine = 0; currentLine < responseInLines.length; currentLine++) { 681 | try { 682 | // parse the JSON response... 683 | var tryParseJson = JSON.parse(responseInLines[currentLine]); 684 | 685 | // clear the view model 686 | self.drivers([]); 687 | // set response > drivers collection 688 | self.drivers(tryParseJson.d.results); 689 | 690 | } catch (e) { 691 | // don't do anything... just keep moving 692 | } 693 | } 694 | }, 695 | fail: function (error) { 696 | console.log('.. delete driver FAIL ', error); 697 | } 698 | }); 699 | } 700 | 701 | /** 702 | * @name deleteDriversMultipleRequests 703 | * @description 704 | * Deletes all drivers using multiple HTTP requests (one per driver). 705 | */ 706 | function deleteDriversMultipleRequests() { 707 | console.log('deleteDriversMultipleRequests()'); 708 | 709 | // store all jobs 710 | var jobs = []; 711 | 712 | var requestHeaders = { 713 | 'Accept': 'application/json;odata=verbose', 714 | 'X-RequestDigest': jQuery("#__REQUESTDIGEST").val(), 715 | 'If-Match': '*' 716 | }; 717 | 718 | for (var driverIndex = 0; driverIndex < self.drivers().length; driverIndex++) { 719 | 720 | var driver = self.drivers()[driverIndex]; 721 | 722 | // create the request endpoint 723 | var endpoint = _spPageContextInfo.webAbsoluteUrl 724 | + '/_api/web/lists/getbytitle(\'Drivers\')' 725 | + '/items(' + driver.Id + ')'; 726 | 727 | // create request... 728 | var promise = jQuery.ajax({ 729 | url: endpoint, 730 | type: 'DELETE', 731 | headers: requestHeaders, 732 | success: function (response) { 733 | console.log('.. delete driver PASS ', response); 734 | }, 735 | fail: function (error) { 736 | console.log('.. delete driver FAIL ', error); 737 | } 738 | }); 739 | 740 | // add the request to the collection of jobs 741 | console.log('.. created driver delete request # ' + driverIndex); 742 | jobs.push(promise); 743 | } 744 | 745 | // when all jobs are complete... 746 | Q.all(jobs) 747 | .then(function () { 748 | console.log('all requests finished'); 749 | // refresh the collection 750 | self.getAllDrivers(); 751 | }); 752 | } 753 | 754 | } 755 | 756 | /* 757 | * @name generateUUID 758 | * @description 759 | * Generates a GUID-like string, used in OData HTTP batches. 760 | * 761 | * @returns {string} - A GUID-like string. 762 | */ 763 | function generateUUID() { 764 | var d = new Date().getTime(); 765 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 766 | var r = (d + Math.random() * 16) % 16 | 0; 767 | d = Math.floor(d / 16); 768 | return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16); 769 | }); 770 | return uuid; 771 | }; 772 | 773 | /** 774 | * Attach the view model to the page & enable all buttons. 775 | */ 776 | jQuery(document).ready(function () { 777 | // create & bind the view model it to the page 778 | ko.applyBindings(new DriversModel()); 779 | 780 | // enable all buttons now that the scripts have loaded & view model is bound 781 | jQuery('input[type="button"]').removeAttr('disabled'); 782 | }); 783 | })(); -------------------------------------------------------------------------------- /SpRestBatchSample/Scripts/Elements.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /SpRestBatchSample/Scripts/SharePointProjectItem.spdata: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SpRestBatchSample/Scripts/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | -------------------------------------------------------------------------------- /SpRestBatchSample/Scripts/q.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * Copyright 2009-2012 Kris Kowal under the terms of the MIT 4 | * license found at http://github.com/kriskowal/q/raw/master/LICENSE 5 | * 6 | * With parts by Tyler Close 7 | * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found 8 | * at http://www.opensource.org/licenses/mit-license.html 9 | * Forked at ref_send.js version: 2009-05-11 10 | * 11 | * With parts by Mark Miller 12 | * Copyright (C) 2011 Google Inc. 13 | * 14 | * Licensed under the Apache License, Version 2.0 (the "License"); 15 | * you may not use this file except in compliance with the License. 16 | * You may obtain a copy of the License at 17 | * 18 | * http://www.apache.org/licenses/LICENSE-2.0 19 | * 20 | * Unless required by applicable law or agreed to in writing, software 21 | * distributed under the License is distributed on an "AS IS" BASIS, 22 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | * See the License for the specific language governing permissions and 24 | * limitations under the License. 25 | * 26 | */ 27 | (function(n){if(typeof bootstrap=="function")bootstrap("promise",n);else if(typeof exports=="object")module.exports=n();else if(typeof define=="function"&&define.amd)define(n);else if(typeof ses!="undefined")if(ses.ok())ses.makeQ=n;else return;else Q=n()})(function(){"use strict";function h(n){return function(){return wt.apply(n,arguments)}}function rt(n){return n===Object(n)}function ni(n){return gt(n)==="[object StopIteration]"||n instanceof k}function ut(n,t){var r,i,u;if(v&&t.stack&&typeof n=="object"&&n!==null&&n.stack&&n.stack.indexOf(d)===-1){for(r=[],i=t;!!i;i=i.source)i.stack&&r.unshift(i.stack);r.unshift(n.stack);u=r.join("\n"+d+"\n");n.stack=ti(u)}}function ti(n){for(var t,r=n.split("\n"),u=[],i=0;i=pt&&i<=vt):!1}function et(){if(v)try{throw new Error;}catch(i){var n=i.stack.split("\n"),r=n[0].indexOf("@")>0?n[1]:n[2],t=ft(r);return t?(tt=t[0],t[1]):void 0}}function ui(n,t,i){return function(){return typeof console!="undefined"&&typeof console.warn=="function"&&console.warn(t+" is deprecated, use "+i+" instead.",new Error("").stack),n.apply(n,arguments)}}function n(n){return o(n)?n:ht(n)?ci(n):nt(n)}function r(){function a(n){e=n;s.source=n;y(c,function(t,i){u(function(){n.promiseDispatch.apply(n,i)})},void 0);c=void 0;l=void 0}var c=[],l=[],e,h=b(r.prototype),s=b(t.prototype);if(s.promiseDispatch=function(n,t,r){var f=i(arguments);c?(c.push(f),t==="when"&&r[1]&&l.push(r[1])):u(function(){e.promiseDispatch.apply(e,f)})},s.valueOf=function(){if(c)return s;var n=st(e);return o(n)&&(e=n),n},s.inspect=function(){return e?e.inspect():{state:"pending"}},n.longStackSupport&&v)try{throw new Error;}catch(p){s.stack=p.stack.substring(p.stack.indexOf("\n")+1)}return h.promise=s,h.resolve=function(t){e||a(n(t))},h.fulfill=function(n){e||a(nt(n))},h.reject=function(n){e||a(f(n))},h.notify=function(n){e||y(l,function(t,i){u(function(){i(n)})},void 0)},h}function s(n){if(typeof n!="function")throw new TypeError("resolver must be a function.");var t=r();try{n(t.resolve,t.reject,t.notify)}catch(i){t.reject(i)}return t.promise}function ot(t){return s(function(i,r){for(var u=0,f=t.length;u=r)throw new TypeError;}while(1);for(;i2?n.resolve(i(arguments,1)):n.resolve(r)}};n.Promise=s;n.promise=s;s.race=ot;s.all=c;s.reject=f;s.resolve=n;n.passByCopy=function(n){return n};t.prototype.passByCopy=function(){return this};n.join=function(t,i){return n(t).join(i)};t.prototype.join=function(t){return n([this,t]).spread(function(n,t){if(n===t)return n;throw new Error("Can't join: not the same: "+n+" "+t);})};n.race=ot;t.prototype.race=function(){return this.then(n.race)};n.makePromise=t;t.prototype.toString=function(){return"[object Promise]"};t.prototype.then=function(t,i,e){function c(n){try{return typeof t=="function"?t(n):n}catch(i){return f(i)}}function l(n){if(typeof i=="function"){ut(n,h);try{return i(n)}catch(t){return f(t)}}return f(n)}function a(n){return typeof e=="function"?e(n):n}var h=this,o=r(),s=!1;return u(function(){h.promiseDispatch(function(n){s||(s=!0,o.resolve(c(n)))},"when",[function(n){s||(s=!0,o.resolve(l(n)))}])}),h.promiseDispatch(void 0,"when",[void 0,function(t){var i,r=!1;try{i=a(t)}catch(u){if(r=!0,n.onerror)n.onerror(u);else throw u;}r||o.notify(i)}]),o.promise};n.when=e;t.prototype.thenResolve=function(n){return this.then(function(){return n})};n.thenResolve=function(t,i){return n(t).thenResolve(i)};t.prototype.thenReject=function(n){return this.then(function(){throw n;})};n.thenReject=function(t,i){return n(t).thenReject(i)};n.nearer=st;n.isPromise=o;n.isPromiseAlike=ht;n.isPending=fi;t.prototype.isPending=function(){return this.inspect().state==="pending"};n.isFulfilled=ei;t.prototype.isFulfilled=function(){return this.inspect().state==="fulfilled"};n.isRejected=oi;t.prototype.isRejected=function(){return this.inspect().state==="rejected"};var l=[],p=[],a=!0;return n.resetUnhandledRejections=g,n.getUnhandledReasons=function(){return l.slice()},n.stopUnhandledRejectionTracking=function(){g();a=!1},g(),n.reject=f,n.fulfill=nt,n.master=li,n.spread=ct,t.prototype.spread=function(n,t){return this.all().then(function(t){return n.apply(void 0,t)},t)},n.async=ai,n.spawn=vi,n["return"]=yi,n.promised=pi,n.dispatch=lt,t.prototype.dispatch=function(n,t){var f=this,i=r();return u(function(){f.promiseDispatch(i.resolve,n,t)}),i.promise},n.get=function(t,i){return n(t).dispatch("get",[i])},t.prototype.get=function(n){return this.dispatch("get",[n])},n.set=function(t,i,r){return n(t).dispatch("set",[i,r])},t.prototype.set=function(n,t){return this.dispatch("set",[n,t])},n.del=n["delete"]=function(t,i){return n(t).dispatch("delete",[i])},t.prototype.del=t.prototype["delete"]=function(n){return this.dispatch("delete",[n])},n.mapply=n.post=function(t,i,r){return n(t).dispatch("post",[i,r])},t.prototype.mapply=t.prototype.post=function(n,t){return this.dispatch("post",[n,t])},n.send=n.mcall=n.invoke=function(t,r){return n(t).dispatch("post",[r,i(arguments,2)])},t.prototype.send=t.prototype.mcall=t.prototype.invoke=function(n){return this.dispatch("post",[n,i(arguments,1)])},n.fapply=function(t,i){return n(t).dispatch("apply",[void 0,i])},t.prototype.fapply=function(n){return this.dispatch("apply",[void 0,n])},n["try"]=n.fcall=function(t){return n(t).dispatch("apply",[void 0,i(arguments,1)])},t.prototype.fcall=function(){return this.dispatch("apply",[void 0,i(arguments)])},n.fbind=function(t){var r=n(t),u=i(arguments,1);return function(){return r.dispatch("apply",[this,u.concat(i(arguments))])}},t.prototype.fbind=function(){var n=this,t=i(arguments);return function(){return n.dispatch("apply",[this,t.concat(i(arguments))])}},n.keys=function(t){return n(t).dispatch("keys",[])},t.prototype.keys=function(){return this.dispatch("keys",[])},n.all=c,t.prototype.all=function(){return c(this)},n.allResolved=ui(at,"allResolved","allSettled"),t.prototype.allResolved=function(){return at(this)},n.allSettled=wi,t.prototype.allSettled=function(){return this.then(function(t){return c(w(t,function(t){function i(){return t.inspect()}return t=n(t),t.then(i,i)}))})},n.fail=n["catch"]=function(t,i){return n(t).then(void 0,i)},t.prototype.fail=t.prototype["catch"]=function(n){return this.then(void 0,n)},n.progress=bi,t.prototype.progress=function(n){return this.then(void 0,void 0,n)},n.fin=n["finally"]=function(t,i){return n(t)["finally"](i)},t.prototype.fin=t.prototype["finally"]=function(t){return t=n(t),this.then(function(n){return t.fcall().then(function(){return n})},function(n){return t.fcall().then(function(){throw n;})})},n.done=function(t,i,r,u){return n(t).done(i,r,u)},t.prototype.done=function(t,i,r){var f=function(t){u(function(){if(ut(t,e),n.onerror)n.onerror(t);else throw t;})},e=t||i||r?this.then(t,i,r):this;typeof process=="object"&&process&&process.domain&&(f=process.domain.bind(f));e.then(void 0,f)},n.timeout=function(t,i,r){return n(t).timeout(i,r)},t.prototype.timeout=function(n,t){var i=r(),u=setTimeout(function(){i.reject(new Error(t||"Timed out after "+n+" ms"))},n);return this.then(function(n){clearTimeout(u);i.resolve(n)},function(n){clearTimeout(u);i.reject(n)},i.notify),i.promise},n.delay=function(t,i){return i===void 0&&(i=t,t=void 0),n(t).delay(i)},t.prototype.delay=function(n){return this.then(function(t){var i=r();return setTimeout(function(){i.resolve(t)},n),i.promise})},n.nfapply=function(t,i){return n(t).nfapply(i)},t.prototype.nfapply=function(n){var t=r(),u=i(n);return u.push(t.makeNodeResolver()),this.fapply(u).fail(t.reject),t.promise},n.nfcall=function(t){var r=i(arguments,1);return n(t).nfapply(r)},t.prototype.nfcall=function(){var t=i(arguments),n=r();return t.push(n.makeNodeResolver()),this.fapply(t).fail(n.reject),n.promise},n.nfbind=n.denodeify=function(t){var u=i(arguments,1);return function(){var e=u.concat(i(arguments)),f=r();return e.push(f.makeNodeResolver()),n(t).fapply(e).fail(f.reject),f.promise}},t.prototype.nfbind=t.prototype.denodeify=function(){var t=i(arguments);return t.unshift(this),n.denodeify.apply(void 0,t)},n.nbind=function(t,u){var f=i(arguments,2);return function(){function s(){return t.apply(u,arguments)}var o=f.concat(i(arguments)),e=r();return o.push(e.makeNodeResolver()),n(s).fapply(o).fail(e.reject),e.promise}},t.prototype.nbind=function(){var t=i(arguments,0);return t.unshift(this),n.nbind.apply(void 0,t)},n.nmapply=n.npost=function(t,i,r){return n(t).npost(i,r)},t.prototype.nmapply=t.prototype.npost=function(n,t){var f=i(t||[]),u=r();return f.push(u.makeNodeResolver()),this.dispatch("post",[n,f]).fail(u.reject),u.promise},n.nsend=n.nmcall=n.ninvoke=function(t,u){var e=i(arguments,2),f=r();return e.push(f.makeNodeResolver()),n(t).dispatch("post",[u,e]).fail(f.reject),f.promise},t.prototype.nsend=t.prototype.nmcall=t.prototype.ninvoke=function(n){var u=i(arguments,1),t=r();return u.push(t.makeNodeResolver()),this.dispatch("post",[n,u]).fail(t.reject),t.promise},n.nodeify=ki,t.prototype.nodeify=function(n){if(n)this.then(function(t){u(function(){n(null,t)})},function(t){u(function(){n(t)})});else return this},vt=et(),n}); 28 | /* 29 | //# sourceMappingURL=q.min.js.map 30 | */ -------------------------------------------------------------------------------- /SpRestBatchSample/SpRestBatchSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8} 8 | Library 9 | Properties 10 | SpRestBatchSampel 11 | SpRestBatchSampel 12 | v4.5 13 | 15.0 14 | 512 15 | {C1CDDADD-2546-481F-9697-4EA41081F2FC};{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 12.0 17 | 12.1 18 | False 19 | SharePointApp 20 | {8ee01011-3254-4260-831d-2dbd4415e5a7} 21 | {4e30f4fb-cf64-4f58-b7b6-23bcb0c4a2a5} 22 | {b776f0c2-afda-4553-865b-435e3f27226b} 23 | {b4554888-301f-446c-a7fe-3ca32d6e8679} 24 | {2c0f5eca-5dd8-444d-85fe-3b8b4fe1bf40} 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\Debug\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | pdbonly 38 | true 39 | bin\Release\ 40 | TRACE 41 | prompt 42 | 4 43 | false 44 | 45 | 46 | 47 | {dcf1aa82-b61e-49df-8bab-8d8bb2922d73} 48 | 49 | 50 | {46f12132-50f4-4ec3-8a8c-f8477952c761} 51 | 52 | 53 | 54 | {d49b8eec-cf95-4a30-b855-c9d015eb2613} 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | jquery-1.9.1.js 65 | 66 | 67 | {2c0f5eca-5dd8-444d-85fe-3b8b4fe1bf40} 68 | 69 | 70 | 71 | 72 | jquery-1.9.1.js 73 | 74 | 75 | 76 | jquery-1.9.1.js 77 | 78 | 79 | knockout-3.2.0.js 80 | 81 | 82 | 83 | 84 | q.js 85 | 86 | 87 | 88 | 89 | 90 | {615164f6-de0e-443e-a58e-57ff1c0a6c10} 91 | 92 | 93 | 94 | 95 | 96 | 97 | manifest-icon 98 | 99 | 100 | 101 | {f0b61090-fbe4-4ada-a826-951d2bc3f62c} 102 | 103 | 104 | 105 | 106 | {ce090acb-37f3-40e7-b7dd-61ea2f414a83} 107 | 108 | 109 | Package.package 110 | 111 | 112 | {60e7fc04-24e3-4047-a4fd-b419b5873e61} 113 | 114 | 115 | Feature1.feature 116 | 117 | 118 | 119 | 120 | Designer 121 | 122 | 123 | 124 | 125 | 10.0 126 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 127 | 128 | 129 | -------------------------------------------------------------------------------- /SpRestBatchSample/SpRestBatchSample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpRestBatchSample", "SpRestBatchSample.csproj", "{15F94EF1-9B65-4741-84D7-9CE195EA7FE8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {15F94EF1-9B65-4741-84D7-9CE195EA7FE8}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /SpRestBatchSample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /adal-cors-client/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/bower_packages" 3 | } -------------------------------------------------------------------------------- /adal-cors-client/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 4 | 5 | *.iml 6 | 7 | ## Directory-based project format: 8 | .idea/ 9 | 10 | ### OSX template 11 | .DS_Store 12 | .AppleDouble 13 | .LSOverride 14 | # Icon must end with two \r 15 | Icon 16 | 17 | **/node_modules 18 | **/bower_packages 19 | 20 | # all generated JS 21 | src/appjs 22 | src/app/**/*.js 23 | **/*.js.map -------------------------------------------------------------------------------- /adal-cors-client/README.md: -------------------------------------------------------------------------------- 1 | This is a sample Angular app that demonstrates ADAL JS & CORS support for select SharePoint Online & Office 365 APIs. The app is 100% client side (there is nothing to deploy) and thus you can run it under `localhost`. 2 | 3 | About the Sample 4 | ---------------- 5 | This app is written in TypeScript. The only JavaScript committed to the repo is that within the two gulp files. 6 | 7 | > The only JavaScript committed to the repo is related to gulp so you don't have to compile them from TS => JS just to run the gulp commands. 8 | 9 | To run the app, you should have the following installed: 10 | - **[Node.js](http://www.nodejs.org)** with NPM (included in default Node.js installs). 11 | - **[Bower](http://www.bower.io)** which is used to acquire client-side packages. 12 | Install using NPM: 13 | 14 | ```` 15 | $ npm -g bower 16 | ```` 17 | 18 | - **[superstatic](http://www.npmjs.org/packages/superstatic)** which is used to host a static website locally. You don't need this if you have another way to do this (*like using WebMatrix or Visual Studio on Windows*). 19 | Install using NPM: 20 | 21 | ```` 22 | $ npm -g superstatic 23 | ```` 24 | 25 | 26 | Run the Sample 27 | -------------- 28 | First, it's assumed you have an Office 365 tenant & Azure subscription with an app created in Azure AD. 29 | 30 | ### Configure the Azure AD App for OAuth2 Implicit Flow 31 | See this page for instructions on how to do this: [##########](##########) 32 | 33 | ### Download all External Dependencies 34 | Download all the files needed to run this sample. 35 | 36 | ```` 37 | $ npm install 38 | ```` 39 | 40 | ### Update App Settings 41 | Open the **[src/app.constants.ts](src/app.constants.ts)** file & update all the settings & paths required. 42 | 43 | ### Compile the App 44 | Because the app is written in TypeScript, you must compile it to JavaScript to run it. Do this by running a gulp task defined in the project's [gulpfile.js](gulpfile.js): 45 | 46 | ```` 47 | $ gulp compile-ts 48 | ```` 49 | 50 | ### Run the App! 51 | Simplest way to run the app is to use superstatic. Because it's installed globally, you can run from anywhere. However, make sure you run this form the root of this project, **adal-cors-client**. 52 | 53 | ```` 54 | $ ss --port 8000 55 | ```` 56 | 57 | Now you can test the app by navigating to **[http://localhost:8000](http://localhost:8000)**. 58 | 59 | [![Analytics](https://ga-beacon.appspot.com/UA-59891462-1/sp-0365-rest/adal-cors-client)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /adal-cors-client/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngconf-typescript", 3 | "version": "0.1.0", 4 | "description": "AngularJS and TypeScript", 5 | "homepage": "https://github.com/andrewconnell/ngconf-typescript", 6 | "authors": [ 7 | "Andrew Connell " 8 | ], 9 | "license": "MIT", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "bower_packages", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "angular": "1.3.5", 20 | "angular-animate": "1.3.5", 21 | "angular-route": "1.3.5", 22 | "adal-angular": "~1.0.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /adal-cors-client/gulpfile.config.js: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | var GulpConfig = (function () { 4 | function GulpConfig() { 5 | this.source = './src/'; 6 | this.sourceApp = this.source + 'app/'; 7 | this.tsOutputPath = this.source + '/appjs'; 8 | this.allJavaScript = [this.tsOutputPath + '/**/*.js']; 9 | this.allTypeScript = this.sourceApp + '/**/*.ts'; 10 | this.typings = './tools/typings/'; 11 | this.libraryTypeScriptDefinitions = './tools/typings/**/*.ts'; 12 | this.appTypeScriptReferences = this.typings + 'app.d.ts'; 13 | } 14 | return GulpConfig; 15 | })(); 16 | exports.GulpConfig = GulpConfig; 17 | //# sourceMappingURL=gulpfile.config.js.map -------------------------------------------------------------------------------- /adal-cors-client/gulpfile.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict'; 4 | 5 | export class GulpConfig { 6 | public source = './src/'; 7 | public sourceApp = this.source + 'app/'; 8 | 9 | public tsOutputPath = this.source + '/appjs'; 10 | public allJavaScript = [this.tsOutputPath + '/**/*.js']; 11 | public allTypeScript = this.sourceApp + '/**/*.ts'; 12 | 13 | public typings = './tools/typings/'; 14 | public libraryTypeScriptDefinitions = './tools/typings/**/*.ts'; 15 | public appTypeScriptReferences = this.typings + 'app.d.ts'; 16 | } 17 | -------------------------------------------------------------------------------- /adal-cors-client/gulpfile.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 'use strict'; 4 | var gulp = require('gulp'), debug = require('gulp-debug'), inject = require('gulp-inject'), tsc = require('gulp-typescript'), tslint = require('gulp-tslint'), sourcemaps = require('gulp-sourcemaps'), clean = require('gulp-clean'); 5 | var GulpConfig = require('./gulpfile.config'); 6 | var config = new GulpConfig.GulpConfig; 7 | /** 8 | * Generates the app.d.ts references file dynamically from all application *.ts files. 9 | */ 10 | gulp.task('gen-ts-refs', function () { 11 | var target = gulp.src(config.appTypeScriptReferences); 12 | var sources = gulp.src([config.allTypeScript], { read: false }); 13 | return target.pipe(inject(sources, { 14 | starttag: '//{', 15 | endtag: '//}', 16 | transform: function (filepath) { 17 | return '/// '; 18 | } 19 | })).pipe(gulp.dest(config.typings)); 20 | }); 21 | /** 22 | * Lint all custom TypeScript files. 23 | */ 24 | gulp.task('ts-lint', function () { 25 | return gulp.src(config.allTypeScript).pipe(tslint()).pipe(tslint.report('prose')); 26 | }); 27 | /** 28 | * Compile TypeScript and include references to library and app .d.ts files. 29 | */ 30 | gulp.task('compile-ts', function () { 31 | var sourceTsFiles = [config.allTypeScript, config.libraryTypeScriptDefinitions, config.appTypeScriptReferences]; //reference to app.d.ts files 32 | var tsResult = gulp.src(sourceTsFiles).pipe(sourcemaps.init()).pipe(tsc({ 33 | target: 'ES5', 34 | declarationFiles: false, 35 | noExternalResolve: true 36 | })); 37 | tsResult.dts.pipe(gulp.dest(config.tsOutputPath)); 38 | return tsResult.js.pipe(sourcemaps.write('.')).pipe(gulp.dest(config.tsOutputPath)); 39 | }); 40 | /** 41 | * Remove all generated JavaScript files from TypeScript compiltion. 42 | */ 43 | gulp.task('clean-ts', function () { 44 | var typeScriptGenFiles = [config.tsOutputPath, config.sourceApp + '**/*.js', config.sourceApp + '**/*.js.map']; 45 | // delete the files 46 | return gulp.src(typeScriptGenFiles, { read: false }).pipe(clean()); 47 | }); 48 | gulp.task('watch', function () { 49 | gulp.watch([config.allTypeScript], ['ts-lint', 'compile-ts', 'gen-ts-refs']); 50 | }); 51 | gulp.task('default', ['ts-lint', 'compile-ts', 'gen-ts-refs', 'watch']); 52 | //# sourceMappingURL=gulpfile.js.map -------------------------------------------------------------------------------- /adal-cors-client/gulpfile.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict'; 5 | 6 | var gulp = require('gulp'), 7 | debug = require('gulp-debug'), 8 | inject = require('gulp-inject'), 9 | tsc = require('gulp-typescript'), 10 | tslint = require('gulp-tslint'), 11 | sourcemaps = require('gulp-sourcemaps'), 12 | clean = require('gulp-clean'); 13 | import GulpConfig = require('./gulpfile.config'); 14 | 15 | var config = new GulpConfig.GulpConfig; 16 | 17 | /** 18 | * Generates the app.d.ts references file dynamically from all application *.ts files. 19 | */ 20 | gulp.task('gen-ts-refs', () => { 21 | var target = gulp.src(config.appTypeScriptReferences); 22 | var sources = gulp.src([config.allTypeScript], {read: false}); 23 | return target.pipe(inject(sources, { 24 | starttag: '//{', 25 | endtag: '//}', 26 | transform: function (filepath) { 27 | return '/// '; 28 | } 29 | })).pipe(gulp.dest(config.typings)); 30 | }); 31 | 32 | /** 33 | * Lint all custom TypeScript files. 34 | */ 35 | gulp.task('ts-lint', () => { 36 | return gulp.src(config.allTypeScript).pipe(tslint()).pipe(tslint.report('prose')); 37 | }); 38 | 39 | /** 40 | * Compile TypeScript and include references to library and app .d.ts files. 41 | */ 42 | gulp.task('compile-ts', () => { 43 | var sourceTsFiles = [config.allTypeScript, //path to typescript files 44 | config.libraryTypeScriptDefinitions, //reference to library .d.ts files 45 | config.appTypeScriptReferences]; //reference to app.d.ts files 46 | 47 | var tsResult = gulp.src(sourceTsFiles) 48 | .pipe(sourcemaps.init()) 49 | .pipe(tsc({ 50 | target: 'ES5', 51 | declarationFiles: false, 52 | noExternalResolve: true 53 | })); 54 | 55 | tsResult.dts.pipe(gulp.dest(config.tsOutputPath)); 56 | return tsResult.js 57 | .pipe(sourcemaps.write('.')) 58 | .pipe(gulp.dest(config.tsOutputPath)); 59 | }); 60 | 61 | /** 62 | * Remove all generated JavaScript files from TypeScript compiltion. 63 | */ 64 | gulp.task('clean-ts', () => { 65 | var typeScriptGenFiles = [config.tsOutputPath, // path to generated JS files 66 | config.sourceApp +'**/*.js', // path to all JS files auto gen'd by editor 67 | config.sourceApp +'**/*.js.map' // path to all sourcemap files auto gen'd by editor 68 | ]; 69 | 70 | // delete the files 71 | return gulp.src(typeScriptGenFiles, {read: false}) 72 | .pipe(clean()); 73 | }); 74 | 75 | gulp.task('watch', () => { 76 | gulp.watch([config.allTypeScript], ['ts-lint', 'compile-ts', 'gen-ts-refs']); 77 | }); 78 | 79 | gulp.task('default', ['ts-lint', 'compile-ts', 'gen-ts-refs', 'watch']); 80 | -------------------------------------------------------------------------------- /adal-cors-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "adal-cors-client", 3 | "version": "0.1.0", 4 | "description": "demonstrates a fully client-side solution that talks to Office 365 REST APIs using ADAL JS", 5 | "main": "index.js", 6 | "scripts": { 7 | "init": "npm install", 8 | "install": "bower install" 9 | }, 10 | "author": { 11 | "name": "Andrew Connell", 12 | "email": "me@andrewconnell.com", 13 | "url": "http://www.andrewconnell.com" 14 | }, 15 | "keywords": [ 16 | "adal js", 17 | "adal", 18 | "office 365", 19 | "office", 20 | "sharepoint" 21 | ], 22 | "license": "ISC", 23 | "dependencies": { 24 | "superstatic": "^2.0.2" 25 | }, 26 | "devDependencies": { 27 | "gulp": "^3.8.11", 28 | "gulp-debug": "^2.0.1", 29 | "gulp-clean": "^0.3.1", 30 | "gulp-inject": "^1.1.1", 31 | "gulp-sourcemaps": "^1.3.0", 32 | "gulp-tslint": "^1.4.3", 33 | "gulp-typescript": "^2.4.2", 34 | "merge2": "^0.3.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /adal-cors-client/src/app/app.adal.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | export class Adal { 8 | /** 9 | * Configures ADAL JS with required info for the registered app in Azure AD. 10 | * 11 | * @param $httpProvider Angular's $httpProvider (needed by ADAL) 12 | * @param adalSettings Settings for ADAL 13 | * @param adalProvider ADAL JS' Angular provider. 14 | */ 15 | static configure($httpProvider:ng.IHttpProvider, 16 | adalSettings:shared.IAdalSettings, 17 | adalProvider:any):void { 18 | 19 | // init the ADAL service 20 | adalProvider.init({ 21 | tenant: adalSettings.tenant, 22 | clientId: adalSettings.clientId, 23 | postLogoutRedirectUri: 'http://localhost:8000', 24 | endpoints: adalSettings.aadEndpoints 25 | }, $httpProvider); 26 | } 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/app.constants.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict'; 5 | 6 | module adalO365CorsClient { 7 | 8 | /** 9 | * Global settings used in the app. 10 | */ 11 | var adalSettings:shared.IAdalSettings = { 12 | tenant: '[your-azure-ad-tenant-id-here]', 13 | clientId: '[your-azure-ad-app-id-here]', 14 | aadEndpoints: { 15 | /* 'target endpoint to be called': 'target endpoint's resource ID' */ 16 | 17 | // sharepoint site containing lists 18 | 'https://[your-tenant-here].sharepoint.com/_api/': 'https://[your-tenant-here].sharepoint.com', 19 | // o365 files api 20 | 'https://[your-tenant-here]-my.sharepoint.com/_api/v1.0/me': 'https://[your-tenant-here]-my.sharepoint.com/' 21 | } 22 | }; 23 | // register the setting as a constant 24 | angular.module('adalO365CorsClient').constant('adalSettings', adalSettings); 25 | 26 | /** 27 | * Configuration settings for ADAL authentication. 28 | * 29 | * @type {{baseSPUrl: string, baseOneDriveUrl: string, defaultHttpGetOptions: {headers: {Accept: string}}}} 30 | */ 31 | var appSettings:shared.ISettings = { 32 | baseSPUrl: 'https://[your-tenant-here].sharepoint.com/_api/', 33 | baseOneDriveUrl: 'https://[your-tenant-here]-my.sharepoint.com/_api/v1.0/me/', 34 | defaultSharePointHttpGetOptions: { 35 | headers: { 36 | 'Accept': 'application/json;odata=verbose' 37 | } 38 | }, 39 | defaultO365HttpGetOptions: { 40 | headers: { 41 | 'Accept': 'application/json;odata=verbose' 42 | } 43 | } 44 | 45 | }; 46 | // register the setting as a constant 47 | angular.module('adalO365CorsClient').constant('appSettings', appSettings); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /adal-cors-client/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict'; 5 | 6 | (() : void => { 7 | 8 | // create the application 9 | var app = angular.module('adalO365CorsClient', [ 10 | 'ngRoute', 11 | 'ngAnimate', 12 | 'AdalAngular' 13 | ]); 14 | 15 | /** 16 | * Configure the application. 17 | */ 18 | app.config(['$routeProvider', '$httpProvider', 'adalSettings', 'adalAuthenticationServiceProvider', 19 | ($routeProvider: ng.route.IRouteProvider, 20 | $httpProvider: ng.IHttpProvider, 21 | adalSettings: adalO365CorsClient.shared.IAdalSettings, 22 | adalProvider) : void => { 23 | 24 | // create the routes for the application 25 | adalO365CorsClient.Routes.configure($routeProvider); 26 | 27 | // setup the Azure AD security config 28 | adalO365CorsClient.Adal.configure($httpProvider, adalSettings, adalProvider); 29 | }]); 30 | 31 | })(); 32 | 33 | -------------------------------------------------------------------------------- /adal-cors-client/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | export class Routes { 8 | /** 9 | * Configures the routes for the application. 10 | * @param $routeProvider 11 | */ 12 | static configure($routeProvider:ng.route.IRouteProvider):void { 13 | var baseUrl = 'app/'; 14 | 15 | $routeProvider 16 | .when('/', { 17 | templateUrl: baseUrl + 'layout/dashboard.html', 18 | requireADLogin: false, // unnecessary as default = false 19 | showInNav: false 20 | }) 21 | .when('/login', { 22 | title: 'Login', 23 | requireADLogin: true, // unnecessary as default = false 24 | showInNav: true 25 | }) 26 | .when('/lists', { 27 | title: 'SharePoint Online REST API', 28 | controller: 'adalO365CorsClient.listsController', 29 | templateUrl: baseUrl + 'lists/lists.html', 30 | controllerAs: 'vm', 31 | requireADLogin: true, 32 | showInNav: true 33 | }) 34 | .when('/files', { 35 | title: 'Office 365 Files REST API', 36 | controller: 'adalO365CorsClient.filesController', 37 | templateUrl: baseUrl + 'files/files.html', 38 | controllerAs: 'vm', 39 | requireADLogin: true, 40 | showInNav: true 41 | }) 42 | .otherwise({redirectTo: '/'}); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /adal-cors-client/src/app/files/files.controller.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | class FilesController { 8 | 9 | public files = []; 10 | public oneDriveUrl = ''; 11 | 12 | /** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 13 | 14 | static $inject = ['appSettings', 'adalO365CorsClient.o365Service']; 15 | constructor(private appSettings:shared.ISettings, 16 | private o365Service:adalO365CorsClient.O365Service) { 17 | 18 | this.oneDriveUrl = this.appSettings.baseOneDriveUrl; 19 | 20 | // load all files 21 | this.getOneDriveFiles(); 22 | } 23 | 24 | /** 25 | * Load all files from the user's OneDrive to the collection of files 26 | */ 27 | public getOneDriveFiles() { 28 | this.o365Service.getUserFiles() 29 | .then((oneDriveFiles:shared.IFile[]) => { 30 | this.files = oneDriveFiles; 31 | }); 32 | } 33 | } 34 | 35 | // register the controller with the Angular app 36 | angular.module('adalO365CorsClient').controller('adalO365CorsClient.filesController', FilesController); 37 | 38 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/files/files.html: -------------------------------------------------------------------------------- 1 |
2 |

User's OneDrive Files:

3 | {{::vm.oneDriveUrl}} 4 | 5 | 10 |
-------------------------------------------------------------------------------- /adal-cors-client/src/app/layout/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 | demonstrating ADAL JS & Office 365 APIs with CORS 3 |
-------------------------------------------------------------------------------- /adal-cors-client/src/app/layout/nav.controller.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | class NavContoller { 8 | 9 | public routes = []; 10 | 11 | /** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 12 | 13 | static $inject = ['$route']; 14 | constructor(private $route:ng.route.IRouteService) { 15 | 16 | // load all visible routes 17 | this.loadVisibleRoutes(); 18 | } 19 | 20 | /** 21 | * Load all routes for navigation. 22 | */ 23 | public loadVisibleRoutes() { 24 | for (var route in this.$route.routes) { 25 | if (this.$route.routes[route].showInNav) { 26 | this.routes.push(this.$route.routes[route]); 27 | } 28 | } 29 | } 30 | } 31 | 32 | // register the controller with the Angular app 33 | angular.module('adalO365CorsClient').controller('adalO365CorsClient.navController', NavContoller); 34 | 35 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/layout/nav.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
-------------------------------------------------------------------------------- /adal-cors-client/src/app/lists/lists.controller.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | /** 8 | * @name: adalO365CorsClient.listsController 9 | * 10 | * Controller for the lists screen. 11 | */ 12 | class ListsController { 13 | 14 | public lists = []; 15 | public sharePointSiteUrl = ''; 16 | 17 | /** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 18 | 19 | static $inject = ['appSettings', 'adalO365CorsClient.sharePointService']; 20 | constructor(private appSettings:shared.ISettings, 21 | private spService:adalO365CorsClient.SharePointService) { 22 | 23 | this.sharePointSiteUrl = this.appSettings.baseSPUrl.replace('/_api/', ''); 24 | 25 | // load all lists 26 | this.loadSharePointLists(); 27 | } 28 | 29 | /** 30 | * Load all SharePoint lists into the public array or lists. 31 | */ 32 | public loadSharePointLists():void { 33 | this.spService.getAllLists(this.appSettings.baseSPUrl) 34 | .then((spLists:shared.ISpList[]) => { 35 | this.lists = spLists; 36 | }); 37 | } 38 | } 39 | 40 | // register the controller with the Angular app 41 | angular.module('adalO365CorsClient').controller('adalO365CorsClient.listsController', ListsController); 42 | 43 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/lists/lists.html: -------------------------------------------------------------------------------- 1 |
2 |

SharePoint Lists in Site:

3 | {{::vm.sharePointSiteUrl}} 4 | 5 | 10 |
-------------------------------------------------------------------------------- /adal-cors-client/src/app/services/o365.service.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | /** 8 | * Office 365 REST API Angular service. 9 | */ 10 | export class O365Service { 11 | 12 | static $inject = ['$http', '$q', 'appSettings']; 13 | constructor(private $http:ng.IHttpService, 14 | private $q:ng.IQService, 15 | private appSettings) { 16 | } 17 | 18 | /** 19 | * Get all the user's files. 20 | * 21 | * @returns {IPromise} Collection of all the current user's files. 22 | */ 23 | public getUserFiles():ng.IPromise { 24 | var deferred = this.$q.defer(); 25 | 26 | var endpoint = this.appSettings.baseOneDriveUrl + 'files/getbypath(\'receipts\')/children?' 27 | + '$select=name,webUrl' 28 | + '&$orderby=name'; 29 | 30 | // issue query to the Office 365 Files API 31 | // 32 | // NOTE: because this is a cross domain REST call, the browser will first issue an HTTP OPTIONS request to check 33 | // that the REST API supports CORS requests for specific HTTP methods 34 | this.$http.get(endpoint, this.appSettings.defaultHttpGetOptions) 35 | .then((result:shared.IO365FileOdataResponse) => { 36 | console.log(result); 37 | var files:shared.IFile[] = result.data.value; 38 | deferred.resolve(files); 39 | }); 40 | 41 | return deferred.promise; 42 | } 43 | } 44 | 45 | // register the service with the Angular app 46 | angular.module('adalO365CorsClient').service('adalO365CorsClient.o365Service', O365Service); 47 | 48 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/services/sharepoint.service.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient { 5 | 'use strict'; 6 | 7 | /** 8 | * @name: adalO365CorsClient.sharePointService 9 | * 10 | * SharePoint Angular service used to call the REST API. 11 | */ 12 | export class SharePointService { 13 | 14 | static $inject = ['$http', '$q', 'appSettings']; 15 | constructor(private $http:ng.IHttpService, 16 | private $q:ng.IQService, 17 | private appSettings:shared.ISettings) { 18 | } 19 | 20 | /** 21 | * Get all all lists in the target SharePoint site. 22 | * 23 | * @param sharePointSiteApiUrl {string} URL of the REST API endpoint of the SharePoint site. 24 | * @returns {IPromise} Collection of all the lists in the specified SharePoint 25 | * site. 26 | */ 27 | public getAllLists(sharePointSiteApiUrl:string) { 28 | var deferred = this.$q.defer(); 29 | 30 | var endpoint = sharePointSiteApiUrl + 'web/lists?' 31 | + '$select=Id,Title,DefaultView/ServerRelativeUrl' 32 | + '&$expand=DefaultView' 33 | + '&$orderby=Title'; 34 | 35 | // issue query for all sharepoint lists in specified site 36 | // 37 | // NOTE: because this is a cross domain REST call, the browser will first issue an HTTP OPTIONS request to check 38 | // that the REST API supports CORS requests for specific HTTP methods 39 | this.$http.get(endpoint, this.appSettings.defaultSharePointHttpGetOptions) 40 | .then((result:shared.ISpListOdataResponse) => { 41 | var lists:shared.ISpList[] = result.data.d.results; 42 | deferred.resolve(lists); 43 | }); 44 | 45 | return deferred.promise; 46 | } 47 | } 48 | 49 | // register the service with the Angular app 50 | angular.module('adalO365CorsClient').service('adalO365CorsClient.sharePointService', SharePointService); 51 | 52 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/IAdalSettings.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient.shared { 5 | 'use strict'; 6 | 7 | export interface IAadEndpoints { 8 | // can't define this as they are always different 9 | } 10 | 11 | /** 12 | * Interface for the ADAL settings. 13 | */ 14 | export interface IAdalSettings { 15 | tenant: string; 16 | clientId: string; 17 | aadEndpoints: IAadEndpoints; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/IFile.ts: -------------------------------------------------------------------------------- 1 | 2 | /// 3 | /// 4 | 5 | module adalO365CorsClient.shared { 6 | 'use strict'; 7 | 8 | /** 9 | * Interface for a Office 365 API File object. 10 | */ 11 | export interface IFile { 12 | id?: string; 13 | name?: string; 14 | webUrl?: string; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/IHttpResponses.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient.shared { 5 | 'use strict'; 6 | 7 | /** 8 | * Actual results from an OData response for SharePoint lists. 9 | */ 10 | interface ISpListOdataValue { 11 | results: ISpList[]; 12 | } 13 | 14 | /** 15 | * Data object included in part of OData response for SharePoint lists. 16 | */ 17 | interface ISpListOdataData { 18 | d: ISpListOdataValue; 19 | } 20 | 21 | /** 22 | * HTTP response from OData query for SPList's against SharePoint's REST API. 23 | */ 24 | export interface ISpListOdataResponse extends ng.IHttpPromiseCallbackArg { 25 | data: ISpListOdataData; 26 | } 27 | 28 | /** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 29 | 30 | /** 31 | * Actual results from an OData response for Files using the Office 365 API. 32 | */ 33 | interface IO365FileOdataValue { 34 | name: string; 35 | webUrl: string; 36 | } 37 | 38 | /** 39 | * Data object included in part of OData response for Office 365 Files API. 40 | */ 41 | interface IO365FileOdataData { 42 | value: IO365FileOdataValue[]; 43 | } 44 | 45 | /** 46 | * HTTP response from OData query for Files's against Office 365's Files API. 47 | */ 48 | export interface IO365FileOdataResponse extends ng.IHttpPromiseCallbackArg { 49 | data: IO365FileOdataData; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/INavRoute.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient.shared { 5 | 'use strict'; 6 | 7 | /** 8 | * Interface for navigation routes. 9 | */ 10 | export interface INavRoute { 11 | title?: string; 12 | controller?: string; 13 | templateUrl?: string; 14 | controllerAs?: string; 15 | requireADLogin?: boolean; 16 | showInNav?: boolean; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/ISettings.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module adalO365CorsClient.shared { 5 | 'use strict'; 6 | 7 | /** 8 | * Interface for the app's settings. 9 | */ 10 | export interface ISettings { 11 | baseSPUrl: string; 12 | baseOneDriveUrl: string; 13 | defaultSharePointHttpGetOptions: any; 14 | defaultO365HttpGetOptions: any; 15 | } 16 | } -------------------------------------------------------------------------------- /adal-cors-client/src/app/shared/ISpList.ts: -------------------------------------------------------------------------------- 1 | 2 | /// 3 | /// 4 | 5 | module adalO365CorsClient.shared { 6 | 'use strict'; 7 | 8 | /** 9 | * Interface return for a SharePoint list object. 10 | */ 11 | export interface ISpList { 12 | Id?: string; 13 | Title?: string; 14 | DefaultView?: string; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /adal-cors-client/src/content/shuffle-animation.css: -------------------------------------------------------------------------------- 1 | /* animation container - ensure animate only the body of the page*/ 2 | .view-container { 3 | position: relative; 4 | overflow: hidden; 5 | } 6 | 7 | /*#region angular shuffle animation */ 8 | .shuffle-animation.ng-enter, 9 | .shuffle-animation.ng-leave { 10 | position: relative; 11 | } 12 | 13 | .shuffle-animation.ng-enter { 14 | -moz-transition: ease-out all 0.3s 0.4s; 15 | -o-transition: ease-out all 0.3s 0.4s; 16 | -webkit-transition: ease-out all 0.3s 0.4s; 17 | transition: ease-out all 0.3s 0.4s; 18 | left: 2em; 19 | opacity: 0; 20 | } 21 | 22 | .shuffle-animation.ng-enter.ng-enter-active { 23 | left: 0; 24 | opacity: 1; 25 | } 26 | 27 | .shuffle-animation.ng-leave { 28 | -moz-transition: 0.3s ease-out all; 29 | -o-transition: 0.3s ease-out all; 30 | -webkit-transition: 0.3s ease-out all; 31 | transition: 0.3s ease-out all; 32 | left: 0; 33 | opacity: 1; 34 | } 35 | 36 | .shuffle-animation.ng-leave.ng-leave-active { 37 | left: 2em; 38 | opacity: 0; 39 | } 40 | /*#endregion */ -------------------------------------------------------------------------------- /adal-cors-client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Office 365 & ADAL JS Playground 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /adal-cors-client/superstatic.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "src" 3 | } 4 | -------------------------------------------------------------------------------- /adal-cors-client/tools/typings/angularjs/angular-animate.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Angular JS 1.3 (ngAnimate module) 2 | // Project: http://angularjs.org 3 | // Definitions by: Michel Salib , Adi Dahiya 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | 9 | /////////////////////////////////////////////////////////////////////////////// 10 | // ngAnimate module (angular-animate.js) 11 | /////////////////////////////////////////////////////////////////////////////// 12 | declare module ng.animate { 13 | 14 | /////////////////////////////////////////////////////////////////////////// 15 | // AnimateService 16 | // see http://docs.angularjs.org/api/ngAnimate/service/$animate 17 | /////////////////////////////////////////////////////////////////////////// 18 | interface IAnimateService extends ng.IAnimateService { 19 | /** 20 | * Globally enables / disables animations. 21 | * 22 | * @param value If provided then set the animation on or off. 23 | * @param element If provided then the element will be used to represent the enable/disable operation. 24 | * @returns current animation state 25 | */ 26 | enabled(value?: boolean, element?: JQuery): boolean; 27 | 28 | /** 29 | * Appends the element to the parentElement element that resides in the document and then runs the enter animation. 30 | * 31 | * @param element the element that will be the focus of the enter animation 32 | * @param parentElement the parent element of the element that will be the focus of the enter animation 33 | * @param afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation 34 | * @returns the animation callback promise 35 | */ 36 | enter(element: JQuery, parentElement: JQuery, afterElement?: JQuery): ng.IPromise; 37 | 38 | /** 39 | * Runs the leave animation operation and, upon completion, removes the element from the DOM. 40 | * 41 | * @param element the element that will be the focus of the leave animation 42 | * @returns the animation callback promise 43 | */ 44 | leave(element: JQuery): ng.IPromise; 45 | 46 | /** 47 | * Fires the move DOM operation. Just before the animation starts, the animate service will either append 48 | * it into the parentElement container or add the element directly after the afterElement element if present. 49 | * Then the move animation will be run. 50 | * 51 | * @param element the element that will be the focus of the move animation 52 | * @param parentElement the parent element of the element that will be the focus of the move animation 53 | * @param afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation 54 | * @returns the animation callback promise 55 | */ 56 | move(element: JQuery, parentElement: JQuery, afterElement?: JQuery): ng.IPromise; 57 | 58 | /** 59 | * Triggers a custom animation event based off the className variable and then attaches the className 60 | * value to the element as a CSS class. 61 | * 62 | * @param element the element that will be animated 63 | * @param className the CSS class that will be added to the element and then animated 64 | * @returns the animation callback promise 65 | */ 66 | addClass(element: JQuery, className: string): ng.IPromise; 67 | 68 | /** 69 | * Triggers a custom animation event based off the className variable and then removes the CSS class 70 | * provided by the className value from the element. 71 | * 72 | * @param element the element that will be animated 73 | * @param className the CSS class that will be animated and then removed from the element 74 | * @returns the animation callback promise 75 | */ 76 | removeClass(element: JQuery, className: string): ng.IPromise; 77 | 78 | /** 79 | * Adds and/or removes the given CSS classes to and from the element. Once complete, the done() callback 80 | * will be fired (if provided). 81 | * 82 | * @param element the element which will have its CSS classes changed removed from it 83 | * @param add the CSS classes which will be added to the element 84 | * @param remove the CSS class which will be removed from the element CSS classes have been set on the element 85 | * @returns the animation callback promise 86 | */ 87 | setClass(element: JQuery, add: string, remove: string): ng.IPromise; 88 | 89 | /** 90 | * Cancels the provided animation. 91 | */ 92 | cancel(animationPromise: ng.IPromise): void; 93 | } 94 | 95 | /////////////////////////////////////////////////////////////////////////// 96 | // AngularProvider 97 | // see http://docs.angularjs.org/api/ngAnimate/provider/$animateProvider 98 | /////////////////////////////////////////////////////////////////////////// 99 | interface IAnimateProvider { 100 | /** 101 | * Registers a new injectable animation factory function. 102 | * 103 | * @param name The name of the animation. 104 | * @param factory The factory function that will be executed to return the animation object. 105 | */ 106 | register(name: string, factory: () => ng.IAnimateCallbackObject): void; 107 | 108 | /** 109 | * Gets and/or sets the CSS class expression that is checked when performing an animation. 110 | * 111 | * @param expression The className expression which will be checked against all animations. 112 | * @returns The current CSS className expression value. If null then there is no expression value. 113 | */ 114 | classNameFilter(expression?: RegExp): RegExp; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /adal-cors-client/tools/typings/angularjs/angular-route.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Angular JS 1.3 (ngRoute module) 2 | // Project: http://angularjs.org 3 | // Definitions by: Jonathan Park 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | 9 | /////////////////////////////////////////////////////////////////////////////// 10 | // ngRoute module (angular-route.js) 11 | /////////////////////////////////////////////////////////////////////////////// 12 | declare module ng.route { 13 | 14 | /////////////////////////////////////////////////////////////////////////// 15 | // RouteParamsService 16 | // see http://docs.angularjs.org/api/ngRoute.$routeParams 17 | /////////////////////////////////////////////////////////////////////////// 18 | interface IRouteParamsService { 19 | [key: string]: any; 20 | } 21 | 22 | /////////////////////////////////////////////////////////////////////////// 23 | // RouteService 24 | // see http://docs.angularjs.org/api/ngRoute.$route 25 | // see http://docs.angularjs.org/api/ngRoute.$routeProvider 26 | /////////////////////////////////////////////////////////////////////////// 27 | interface IRouteService { 28 | reload(): void; 29 | routes: any; 30 | 31 | // May not always be available. For instance, current will not be available 32 | // to a controller that was not initialized as a result of a route maching. 33 | current?: ICurrentRoute; 34 | } 35 | 36 | 37 | /** 38 | * see http://docs.angularjs.org/api/ngRoute/provider/$routeProvider#when for API documentation 39 | */ 40 | interface IRoute { 41 | /** 42 | * {(string|function()=} 43 | * Controller fn that should be associated with newly created scope or the name of a registered controller if passed as a string. 44 | */ 45 | controller?: string|Function; 46 | /** 47 | * A controller alias name. If present the controller will be published to scope under the controllerAs name. 48 | */ 49 | controllerAs?: string; 50 | /** 51 | * Undocumented? 52 | */ 53 | name?: string; 54 | /** 55 | * {string=|function()=} 56 | * Html template as a string or a function that returns an html template as a string which should be used by ngView or ngInclude directives. This property takes precedence over templateUrl. 57 | * 58 | * If template is a function, it will be called with the following parameters: 59 | * 60 | * {Array.} - route parameters extracted from the current $location.path() by applying the current route 61 | */ 62 | template?: string|{($routeParams?: ng.route.IRouteParamsService) : string;} 63 | /** 64 | * {string=|function()=} 65 | * Path or function that returns a path to an html template that should be used by ngView. 66 | * 67 | * If templateUrl is a function, it will be called with the following parameters: 68 | * 69 | * {Array.} - route parameters extracted from the current $location.path() by applying the current route 70 | */ 71 | templateUrl?: string|{ ($routeParams?: ng.route.IRouteParamsService): string; } 72 | /** 73 | * {Object.=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired. The map object is: 74 | * 75 | * - key - {string}: a name of a dependency to be injected into the controller. 76 | * - factory - {string|function}: If string then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before its value is injected into the controller. Be aware that ngRoute.$routeParams will still refer to the previous route within these resolve functions. Use $route.current.params to access the new route parameters, instead. 77 | */ 78 | resolve?: {[key: string]: any}; 79 | /** 80 | * {(string|function())=} 81 | * Value to update $location path with and trigger route redirection. 82 | * 83 | * If redirectTo is a function, it will be called with the following parameters: 84 | * 85 | * - {Object.} - route parameters extracted from the current $location.path() by applying the current route templateUrl. 86 | * - {string} - current $location.path() 87 | * - {Object} - current $location.search() 88 | * - The custom redirectTo function is expected to return a string which will be used to update $location.path() and $location.search(). 89 | */ 90 | redirectTo?: string|{($routeParams?: ng.route.IRouteParamsService, $locationPath?: string, $locationSearch?: any) : string}; 91 | /** 92 | * Reload route when only $location.search() or $location.hash() changes. 93 | * 94 | * This option defaults to true. If the option is set to false and url in the browser changes, then $routeUpdate event is broadcasted on the root scope. 95 | */ 96 | reloadOnSearch?: boolean; 97 | /** 98 | * Match routes without being case sensitive 99 | * 100 | * This option defaults to false. If the option is set to true, then the particular route can be matched without being case sensitive 101 | */ 102 | caseInsensitiveMatch?: boolean; 103 | } 104 | 105 | // see http://docs.angularjs.org/api/ng.$route#current 106 | interface ICurrentRoute extends IRoute { 107 | locals: { 108 | $scope: IScope; 109 | $template: string; 110 | }; 111 | 112 | params: any; 113 | } 114 | 115 | interface IRouteProvider extends IServiceProvider { 116 | /** 117 | * Sets route definition that will be used on route change when no other route definition is matched. 118 | * 119 | * @params Mapping information to be assigned to $route.current. 120 | */ 121 | otherwise(params: IRoute): IRouteProvider; 122 | /** 123 | * Adds a new route definition to the $route service. 124 | * 125 | * @param path Route path (matched against $location.path). If $location.path contains redundant trailing slash or is missing one, the route will still match and the $location.path will be updated to add or drop the trailing slash to exactly match the route definition. 126 | * 127 | * - path can contain named groups starting with a colon: e.g. :name. All characters up to the next slash are matched and stored in $routeParams under the given name when the route matches. 128 | * - path can contain named groups starting with a colon and ending with a star: e.g.:name*. All characters are eagerly stored in $routeParams under the given name when the route matches. 129 | * - path can contain optional named groups with a question mark: e.g.:name?. 130 | * 131 | * For example, routes like /color/:color/largecode/:largecode*\/edit will match /color/brown/largecode/code/with/slashes/edit and extract: color: brown and largecode: code/with/slashes. 132 | * 133 | * @param route Mapping information to be assigned to $route.current on route match. 134 | */ 135 | when(path: string, route: IRoute): IRouteProvider; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /adal-cors-client/tools/typings/app.d.ts: -------------------------------------------------------------------------------- 1 | //{ 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | //} -------------------------------------------------------------------------------- /adal-cors-client/tools/typings/gulp/gulp.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Gulp v3.8.x 2 | // Project: http://gulpjs.com 3 | // Definitions by: Drew Noakes 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module gulp { 9 | 10 | /** 11 | * Options to pass to node-glob through glob-stream. 12 | * Specifies two options in addition to those used by node-glob: 13 | * https://github.com/isaacs/node-glob#options 14 | */ 15 | interface ISrcOptions { 16 | /** 17 | * Setting this to false will return file.contents as null 18 | * and not read the file at all. 19 | * Default: true. 20 | */ 21 | read?: boolean; 22 | 23 | /** 24 | * Setting this to false will return file.contents as a stream and not buffer files. 25 | * This is useful when working with large files. 26 | * Note: Plugins might not implement support for streams. 27 | * Default: true. 28 | */ 29 | buffer?: boolean; 30 | 31 | /** 32 | * The current working directory in which to search. 33 | * Defaults to process.cwd(). 34 | */ 35 | cwd?: string; 36 | 37 | /** 38 | * The place where patterns starting with / will be mounted onto. 39 | * Defaults to path.resolve(options.cwd, "/") (/ on Unix systems, and C:\ or some such on Windows.) 40 | */ 41 | root?: string; 42 | 43 | /** 44 | * Include .dot files in normal matches and globstar matches. 45 | * Note that an explicit dot in a portion of the pattern will always match dot files. 46 | */ 47 | dot?: boolean; 48 | 49 | /** 50 | * By default, a pattern starting with a forward-slash will be "mounted" onto the root setting, so that a valid 51 | * filesystem path is returned. Set this flag to disable that behavior. 52 | */ 53 | nomount?: boolean; 54 | 55 | /** 56 | * Add a / character to directory matches. Note that this requires additional stat calls. 57 | */ 58 | mark?: boolean; 59 | 60 | /** 61 | * Don't sort the results. 62 | */ 63 | nosort?: boolean; 64 | 65 | /** 66 | * Set to true to stat all results. This reduces performance somewhat, and is completely unnecessary, unless 67 | * readdir is presumed to be an untrustworthy indicator of file existence. It will cause ELOOP to be triggered one 68 | * level sooner in the case of cyclical symbolic links. 69 | */ 70 | stat?: boolean; 71 | 72 | /** 73 | * When an unusual error is encountered when attempting to read a directory, a warning will be printed to stderr. 74 | * Set the silent option to true to suppress these warnings. 75 | */ 76 | silent?: boolean; 77 | 78 | /** 79 | * When an unusual error is encountered when attempting to read a directory, the process will just continue on in 80 | * search of other matches. Set the strict option to raise an error in these cases. 81 | */ 82 | strict?: boolean; 83 | 84 | /** 85 | * See cache property above. Pass in a previously generated cache object to save some fs calls. 86 | */ 87 | cache?: boolean; 88 | 89 | /** 90 | * A cache of results of filesystem information, to prevent unnecessary stat calls. 91 | * While it should not normally be necessary to set this, you may pass the statCache from one glob() call to the 92 | * options object of another, if you know that the filesystem will not change between calls. 93 | */ 94 | statCache?: boolean; 95 | 96 | /** 97 | * Perform a synchronous glob search. 98 | */ 99 | sync?: boolean; 100 | 101 | /** 102 | * In some cases, brace-expanded patterns can result in the same file showing up multiple times in the result set. 103 | * By default, this implementation prevents duplicates in the result set. Set this flag to disable that behavior. 104 | */ 105 | nounique?: boolean; 106 | 107 | /** 108 | * Set to never return an empty set, instead returning a set containing the pattern itself. 109 | * This is the default in glob(3). 110 | */ 111 | nonull?: boolean; 112 | 113 | /** 114 | * Perform a case-insensitive match. Note that case-insensitive filesystems will sometimes result in glob returning 115 | * results that are case-insensitively matched anyway, since readdir and stat will not raise an error. 116 | */ 117 | nocase?: boolean; 118 | 119 | /** 120 | * Set to enable debug logging in minimatch and glob. 121 | */ 122 | debug?: boolean; 123 | 124 | /** 125 | * Set to enable debug logging in glob, but not minimatch. 126 | */ 127 | globDebug?: boolean; 128 | } 129 | 130 | interface IDestOptions { 131 | /** 132 | * The output folder. Only has an effect if provided output folder is relative. 133 | * Default: process.cwd() 134 | */ 135 | cwd?: string; 136 | 137 | /** 138 | * Octal permission string specifying mode for any folders that need to be created for output folder. 139 | * Default: 0777. 140 | */ 141 | mode?: string; 142 | } 143 | 144 | /** 145 | * Options that are passed to gaze. 146 | * https://github.com/shama/gaze 147 | */ 148 | interface IWatchOptions { 149 | /** Interval to pass to fs.watchFile. */ 150 | interval?: number; 151 | /** Delay for events called in succession for the same file/event. */ 152 | debounceDelay?: number; 153 | /** Force the watch mode. Either 'auto' (default), 'watch' (force native events), or 'poll' (force stat polling). */ 154 | mode?: string; 155 | /** The current working directory to base file patterns from. Default is process.cwd().. */ 156 | cwd?: string; 157 | } 158 | 159 | interface IWatchEvent { 160 | /** The type of change that occurred, either added, changed or deleted. */ 161 | type: string; 162 | /** The path to the file that triggered the event. */ 163 | path: string; 164 | } 165 | 166 | /** 167 | * Callback to be called on each watched file change. 168 | */ 169 | interface IWatchCallback { 170 | (event:IWatchEvent): void; 171 | } 172 | 173 | interface ITaskCallback { 174 | /** 175 | * Defines a task. 176 | * Tasks may be made asynchronous if they are passing a callback or return a promise or a stream. 177 | * @param cb callback used to signal asynchronous completion. Caller includes err in case of error. 178 | */ 179 | (cb?:(err?:any)=>void): any; 180 | } 181 | 182 | interface EventEmitter { 183 | any: any; 184 | } 185 | 186 | interface Gulp { 187 | /** 188 | * Define a task. 189 | * 190 | * @param name the name of the task. Tasks that you want to run from the command line should not have spaces in them. 191 | * @param fn the function that performs the task's operations. Generally this takes the form of gulp.src().pipe(someplugin()). 192 | */ 193 | task(name:string, fn:ITaskCallback): any; 194 | 195 | /** 196 | * Define a task. 197 | * 198 | * @param name the name of the task. Tasks that you want to run from the command line should not have spaces in them. 199 | * @param dep an array of tasks to be executed and completed before your task will run. 200 | * @param fn the function that performs the task's operations. Generally this takes the form of gulp.src().pipe(someplugin()). 201 | */ 202 | task(name:string, dep:string[], fn?:ITaskCallback): any; 203 | 204 | 205 | /** 206 | * Takes a glob and represents a file structure. Can be piped to plugins. 207 | * @param glob a glob string, using node-glob syntax 208 | * @param opt an optional option object 209 | */ 210 | src(glob:string, opt?:ISrcOptions): NodeJS.ReadWriteStream; 211 | 212 | /** 213 | * Takes a glob and represents a file structure. Can be piped to plugins. 214 | * @param glob an array of glob strings, using node-glob syntax 215 | * @param opt an optional option object 216 | */ 217 | src(glob:string[], opt?:ISrcOptions): NodeJS.ReadWriteStream; 218 | 219 | 220 | /** 221 | * Can be piped to and it will write files. Re-emits all data passed to it so you can pipe to multiple folders. 222 | * Folders that don't exist will be created. 223 | * 224 | * @param outFolder the path (output folder) to write files to. 225 | * @param opt 226 | */ 227 | dest(outFolder:string, opt?:IDestOptions): NodeJS.ReadWriteStream; 228 | 229 | /** 230 | * Can be piped to and it will write files. Re-emits all data passed to it so you can pipe to multiple folders. 231 | * Folders that don't exist will be created. 232 | * 233 | * @param outFolder a function that converts a vinyl File instance into an output path 234 | * @param opt 235 | */ 236 | dest(outFolder:(file:string)=>string, opt?:IDestOptions): NodeJS.ReadWriteStream; 237 | 238 | 239 | /** 240 | * Watch files and do something when a file changes. This always returns an EventEmitter that emits change events. 241 | * 242 | * @param glob a single glob or array of globs that indicate which files to watch for changes. 243 | * @param tasks names of task(s) to run when a file changes, added with gulp.task() 244 | */ 245 | watch(glob:string, tasks:string[]): EventEmitter; 246 | watch(glob:string[], tasks:string[]): EventEmitter; 247 | 248 | /** 249 | * Watch files and do something when a file changes. This always returns an EventEmitter that emits change events. 250 | * 251 | * @param glob a single glob or array of globs that indicate which files to watch for changes. 252 | * @param opt options, that are passed to the gaze library. 253 | * @param tasks names of task(s) to run when a file changes, added with gulp.task() 254 | */ 255 | watch(glob:string, opt:IWatchOptions, tasks:string[]): EventEmitter; 256 | watch(glob:string[], opt:IWatchOptions, tasks:string[]): EventEmitter; 257 | 258 | /** 259 | * Watch files and do something when a file changes. This always returns an EventEmitter that emits change events. 260 | * 261 | * @param glob a single glob or array of globs that indicate which files to watch for changes. 262 | * @param fn a callback or array of callbacks to be called on each change. 263 | */ 264 | watch(glob:string, fn:IWatchCallback): EventEmitter; 265 | watch(glob:string[], fn:IWatchCallback): EventEmitter; 266 | watch(glob:string, fn:IWatchCallback[]): EventEmitter; 267 | watch(glob:string[], fn:IWatchCallback[]): EventEmitter; 268 | 269 | /** 270 | * Watch files and do something when a file changes. This always returns an EventEmitter that emits change events. 271 | * 272 | * @param glob a single glob or array of globs that indicate which files to watch for changes. 273 | * @param opt options, that are passed to the gaze library. 274 | * @param fn a callback or array of callbacks to be called on each change. 275 | */ 276 | watch(glob:string, opt:IWatchOptions, fn:IWatchCallback): EventEmitter; 277 | watch(glob:string, opt:IWatchOptions, fn:IWatchCallback[]): EventEmitter; 278 | } 279 | } 280 | 281 | declare module "gulp" { 282 | var _tmp:gulp.Gulp; 283 | export = _tmp; 284 | } 285 | 286 | interface IGulpPlugin { 287 | (...args: any[]): NodeJS.ReadWriteStream; 288 | } 289 | -------------------------------------------------------------------------------- /adal-cors-client/tools/typings/tsd.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | -------------------------------------------------------------------------------- /adal-cors-client/tsd.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v4", 3 | "repo": "borisyankov/DefinitelyTyped", 4 | "ref": "master", 5 | "path": "tools/typings", 6 | "bundle": "tools/typings/tsd.d.ts", 7 | "installed": { 8 | "angularjs/angular.d.ts": { 9 | "commit": "49b821f06b711a86be349c4bbff4351467c024b9" 10 | }, 11 | "jquery/jquery.d.ts": { 12 | "commit": "49b821f06b711a86be349c4bbff4351467c024b9" 13 | }, 14 | "angularjs/angular-route.d.ts": { 15 | "commit": "b85ed86ab874655e81ee99f405b0585541ea8fbc" 16 | }, 17 | "angularjs/angular-animate.d.ts": { 18 | "commit": "b85ed86ab874655e81ee99f405b0585541ea8fbc" 19 | }, 20 | "gulp/gulp.d.ts": { 21 | "commit": "fa20411dd52348e933c2b23b24365236e92fa4ac" 22 | }, 23 | "node/node.d.ts": { 24 | "commit": "fa20411dd52348e933c2b23b24365236e92fa4ac" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /adal-cors-client/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "curly": true, 5 | "eofline": false, 6 | "forin": true, 7 | "indent": [true, 4], 8 | "label-position": true, 9 | "label-undefined": true, 10 | "max-line-length": [true, 140], 11 | "no-arg": true, 12 | "no-bitwise": true, 13 | "no-console": [true, 14 | "debug", 15 | "info", 16 | "time", 17 | "timeEnd", 18 | "trace" 19 | ], 20 | "no-construct": true, 21 | "no-debugger": true, 22 | "no-duplicate-key": true, 23 | "no-duplicate-variable": true, 24 | "no-empty": true, 25 | "no-eval": true, 26 | "no-imports": true, 27 | "no-string-literal": false, 28 | "no-trailing-comma": true, 29 | "no-trailing-whitespace": true, 30 | "no-unused-variable": false, 31 | "no-unreachable": true, 32 | "no-use-before-declare": true, 33 | "one-line": [true, 34 | "check-open-brace", 35 | "check-catch", 36 | "check-else", 37 | "check-whitespace" 38 | ], 39 | "quotemark": [true, "single"], 40 | "radix": true, 41 | "semicolon": true, 42 | "triple-equals": [true, "allow-null-check"], 43 | "variable-name": false, 44 | "whitespace": [true, 45 | "check-branch", 46 | "check-decl", 47 | "check-operator", 48 | "check-separator" 49 | ] 50 | } 51 | } 52 | --------------------------------------------------------------------------------