<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Programmation &#8211; Kodono</title>
	<atom:link href="https://blog.kodono.info/wordpress/category/programmation/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.kodono.info/wordpress</link>
	<description>Pour tous les technophiles</description>
	<lastBuildDate>Mon, 29 Apr 2024 13:07:56 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.1</generator>
	<item>
		<title>Connect to SharePoint Online from NodeJS using an impersonate (application) Bearer Token</title>
		<link>https://blog.kodono.info/wordpress/2024/04/29/connect-to-sharepoint-online-from-nodejs-using-an-impersonate-application-bearer-token/</link>
					<comments>https://blog.kodono.info/wordpress/2024/04/29/connect-to-sharepoint-online-from-nodejs-using-an-impersonate-application-bearer-token/#comments</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 29 Apr 2024 13:07:56 +0000</pubDate>
				<category><![CDATA[Debug]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2291</guid>

					<description><![CDATA[(duplicate of this StackOverflow answer) Start a new project In a new folder, type npm init to start a new project. Make sure to use a Node &#62;= v14 (I use Node v18 – and Volta can be useful to manage several versions of Node for Windows) Install some dependencies: npm install axios @azure/msal-node uuid [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>(duplicate of this <a href="https://stackoverflow.com/questions/78402212/connect-to-sharepoint-online-from-nodejs-using-an-impersonate-application-bear/78402213#78402213">StackOverflow answer</a>)</p>
<h1 id="start-a-new-project">Start a new project</h1>
<ol>
<li>In a new folder, type <code>npm init</code> to start a new project.</li>
<li>Make sure to use a Node &gt;= v14 (I use Node v18 – and <a href="https://volta.sh/">Volta</a> can be useful to manage several versions of Node for Windows) </li>
<li>Install some dependencies: <code>npm install axios @azure/msal-node uuid</code>  </li>
</ol>
<h1 id="certificate">Certificate</h1>
<p>In the past, we could use the add-in application feature to get a token, but Microsoft <a href="https://learn.microsoft.com/fr-fr/sharepoint/dev/sp-add-ins/retirement-announcement-for-add-ins">announced</a> it will be retired.</p>
<p>We now need to pass through an Azure application to get it. But before creating the Azure app, we need to create a Private Certificate key.</p>
<ol>
<li>Create the file <code>Create-SelfSignedCertificate.ps1</code> using the below code (<a href="https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread#setting-up-an-azure-ad-app-for-app-only-access">source</a>):   </li>
</ol>
<pre class="brush:powershell">#Requires -RunAsAdministrator
<#
.SYNOPSIS
Creates a Self Signed Certificate for use in server to server authentication
.DESCRIPTION
Source: https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread#setting-up-an-azure-ad-app-for-app-only-access
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key.
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Password (ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force)
This will create a new self signed certificate with the common name "CN=MyCert". The password as specified in the Password parameter will be used to protect the private key
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Force
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key. If there is already a certificate with the common name you specified, it will be removed first.
#>
Param(

[Parameter(Mandatory=$true)]
   [string]$CommonName,

[Parameter(Mandatory=$true)]
   [DateTime]$StartDate,

[Parameter(Mandatory=$true)]
   [DateTime]$EndDate,

[Parameter(Mandatory=$false, HelpMessage="Will overwrite existing certificates")]
   [Switch]$Force,

[Parameter(Mandatory=$false)]
   [SecureString]$Password
)

# DO NOT MODIFY BELOW
function CreateSelfSignedCertificate(){
  #Remove and existing certificates with the same common name from personal and root stores
    #Need to be very wary of this as could break something
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
    if($certs -ne $null -and $certs.Length -gt 0)
    {
        if($Force)
        {

foreach($c in $certs)
            {
                remove-item $c.PSPath
            }
        } else {
            Write-Host -ForegroundColor Red "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them";
            return $false
        }
    }

$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
    $name.Encode("CN=$CommonName", 0)

$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
    $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
    $key.KeySpec = 1
    $key.Length = 2048
    $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
    $key.MachineContext = 1
    $key.ExportPolicy = 1 # This is required to allow the private key to be exported
    $key.Create()

$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") # Server Authentication
    $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
    $ekuoids.add($serverauthoid)
    $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
    $ekuext.InitializeEncode($ekuoids)

$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
    $cert.InitializeFromPrivateKey(2, $key, "")
    $cert.Subject = $name
    $cert.Issuer = $cert.Subject
    $cert.NotBefore = $StartDate
    $cert.NotAfter = $EndDate
    $cert.X509Extensions.Add($ekuext)
    $cert.Encode()

$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
    $enrollment.InitializeFromRequest($cert)
    $certdata = $enrollment.CreateRequest(0)
    $enrollment.InstallResponse(2, $certdata, 0, "")
    return $true
}

function ExportPFXFile()
{
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    if($Password -eq $null)
    {
        $Password = Read-Host -Prompt "Enter Password to protect private key" -AsSecureString
    }
    $cert = Get-ChildItem -Path Cert:\LocalMachine\my | where-object{$_.Subject -eq "CN=$CommonName"}

    Export-PfxCertificate -Cert $cert -Password $Password -FilePath "$($CommonName).pfx"
    Export-Certificate -Cert $cert -Type CERT -FilePath "$CommonName.cer"
}

function RemoveCertsFromStore()
{
    # Once the certificates have been been exported we can safely remove them from the store
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
    foreach($c in $certs)
    {
        remove-item $c.PSPath
    }
}

if(CreateSelfSignedCertificate)
{
    ExportPFXFile
    RemoveCertsFromStore
}</pre>
<ol start="2">
<li>Open a PowerShell console as an <em>administrator</em></li>
<li>Create the certificate with a command like <code>.\Create-SelfSignedCertificate.ps1 -CommonName &quot;SharePointOnlinePrivateKey&quot; -StartDate 2024-04-01 -EndDate 2035-01-01</code> (if you receive an error, make sure to allow running this kind of script with the command <code>Set-ExecutionPolicy RemoteSigned</code>)</li>
<li>A password is required (e.g. &quot;HereIsMyPass1223&quot;)</li>
<li>Two files are created: <code>SharePointOnlinePrivateKey.pfx</code> and <code>SharePointOnlinePrivateKey.cer</code></li>
</ol>
<p>We&#39;re going to install OpenSSL to convert the <code>pfx</code> file to a <code>pem</code>:</p>
<ol>
<li>Install <a href="https://www.openssl.org/">OpenSSL</a> (e.g. the light version for Win64) as an <em>administrator</em></li>
<li>Find the OpenSSL installation directory (e.g. <code>C:\Program Files\OpenSSL-Win64\</code>)</li>
<li>Open the <code>start.bat</code> file from this OpenSSL directory</li>
<li>A command window opens – go to the directory where the <code>SharePointOnlinePrivateKey.pfx</code> file is (e.g. <code>cd C:\Users\Aymeric\Documents\nodejs\spo-experiments</code>)</li>
<li>In the OpenSSL command window, type <code>openssl pkcs12 -in SharePointOnlinePrivateKey.pfx -out SharePointOnlinePrivateKey.pem</code> (the password entered in the previous steps will be asked three times)</li>
</ol>
<p>We should now have a file called <code>SharePointOnlinePrivateKey.pem</code></p>
<h1 id="azure-application">Azure Application</h1>
<p>It&#39;s time to create the related Azure application:</p>
<ol>
<li>Go to <a href="https://portal.azure.com">https://portal.azure.com</a></li>
<li>Go to the Microsoft Entra ID section</li>
<li>Go to the &quot;App Registrations&quot;, and click on &quot;New registration&quot;</li>
<li>I won&#39;t detail all the steps to create the app</li>
<li>Give a name to the app (e.g. &quot;<strong>SharePoint Online Remote Access</strong>&quot;)</li>
</ol>
<h2 id="get-thumbprint">Get Thumbprint</h2>
<p>We need the thumbprint:</p>
<ol>
<li>Go to &quot;<strong>Certificates &amp; secrets</strong>&quot; section</li>
<li>Go to &quot;<strong>Certificates</strong>&quot; tab (<a href="https://github.com/SharePoint/sp-dev-docs/issues/5889#issuecomment-645225813">see how</a>) and upload the <code>SharePointOnlinePrivateKey.cer</code> file you created before</li>
<li>Once uploaded, it will provide &quot;<strong>Thumbprint</strong>&quot; (e.g. &quot;F7D8D4F2F140E79B215899BD93A14D0790947789&quot;) – copy this value for a later use.</li>
</ol>
<h2 id="get-client-id-and-tenant-id">Get Client Id and Tenant Id</h2>
<p>We need the <code>clientId</code> and the <code>tenantId</code>:</p>
<ol>
<li>From the overview page of your app, copy the &quot;<strong>Application (client) Id</strong>&quot; (e.g. &quot;75284292-7515-4e2f-aae9-d1777527dd7b&quot;) and the &quot;<strong>Directory (tenant) ID</strong>&quot; (e.g. &quot;945c177a-83a2-4e80-9f8c-5a91be5752dd&quot;)</li>
</ol>
<h2 id="platform-configuration">Platform configuration</h2>
<p>Additional configuration required for the application:</p>
<ol>
<li>Go to &quot;<strong>Authentication</strong>&quot; menu, and under &quot;<strong>Platform configurations</strong>&quot;, click on &quot;<strong>Add a Platform</strong>&quot;</li>
<li>Choose &quot;<strong>Web</strong>&quot; and enter <code>https://localhost</code> for &quot;<strong>Redirect URLs</strong>&quot;</li>
<li>Choose &quot;<strong>Access Token</strong>&quot; and &quot;<strong>ID Token</strong>&quot; in the &quot;<strong>Implicit grant and hybrid flows</strong>&quot; section</li>
</ol>
<h2 id="api-permissions">API Permissions</h2>
<p>We want to give the permissions to the Azure app to get access to only one (or more) specific Sites Collection, but not all of the tenant site collections. To do so, we only need the <code>Sites.Selected</code> permissions (<a href="https://devblogs.microsoft.com/microsoft365dev/controlling-app-access-on-specific-sharepoint-site-collections/">ref1</a> and <a href="https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/develop-applications-that-use-sites-selected-permissions-for-spo/ba-p/3790476">ref2</a>).</p>
<p>First, let&#39;s select it from a Microsoft Graph perspective:</p>
<ol>
<li>Go to the &quot;<strong>API Permissions</strong>&quot; section from the left navigation</li>
<li>Click on &quot;<strong>Add a permission</strong>&quot;</li>
<li>Select &quot;<strong>Microsoft Graph</strong>&quot;</li>
<li>Then &quot;<strong>Application Permissions</strong>&quot;</li>
<li>Select &quot;<strong>Sites.Selected</strong>&quot;</li>
</ol>
<p>Then, let&#39;s select it for SharePoint Online REST perspective:</p>
<ol>
<li>From the same section, select &quot;<strong>SharePoint</strong>&quot;</li>
<li>Then &quot;<strong>Application Permissions</strong>&quot;</li>
<li>Select &quot;<strong>Sites.Selected</strong>&quot;</li>
</ol>
<p><a href="https://i.sstatic.net/19SV6jA3.png"><img decoding="async" src="https://i.sstatic.net/19SV6jA3.png" alt="API Permissions screen"></a><br />
Remark: you might need to contact the IT team to get your API Permissions approved/granted.</p>
<h2 id="get-client-secret">Get Client Secret</h2>
<p>We need the <code>clientSecret</code>:</p>
<ol>
<li>Go to the &quot;<strong>Certificates and Secrets</strong>&quot; section from the left navigation</li>
<li>Go to &quot;<strong>Client Secret</strong>&quot; and click on &quot;<strong>New client secret</strong>&quot;</li>
<li>In &quot;<strong>Description</strong>&quot; you can put something like &quot;SharePoint Online Remote Access&quot;, and choose 365 days for the expiration</li>
<li>Once done, make sure to copy <code>Value</code> (e.g. &quot;rVE7Q~Z1BhRXaljbj7SPg~U2HYJRR-feckrxKbCt&quot;) that is our <code>clientSecret</code></li>
</ol>
<h2 id="app-permissions-on-site-collection">App permissions on Site Collection</h2>
<p>It&#39;s time to indicate that the Azure application can have access to a specific Site Collection (e.g. <a href="https://mycompany.sharepoint.com/sites/contoso">https://mycompany.sharepoint.com/sites/contoso</a>).</p>
<p>To proceed, we need the <code>siteId</code>:</p>
<ol>
<li>Go to the SharePoint website (e.g. <a href="https://mycompany.sharepoint.com/sites/contoso">https://mycompany.sharepoint.com/sites/contoso</a>)</li>
<li>Click right in the page to see the source (or <code>CTRL U</code>)</li>
<li>Search for the variable <code>siteId</code> (e.g. &quot;7d6d9e18-e8de-4b7c-9582-3f978726f356&quot;)</li>
</ol>
<p>To give the permissions to the app, a special command must be entered (see <a href="https://www.youtube.com/watch?v=SNIF3zCYNUk">this video</a> for more information). In theory, the site collection admin can do it, but it might be restricted in your organization, and you&#39;ll need the assistance of a tenant admin.</p>
<p>We need the <code>AppId</code> (as known as <code>clientId</code>) and <code>DisplayName</code> (as known as the Azure app name):</p>
<pre class="brush:powershell">
$targetSiteUri = 'https://mycompany.sharepoint.com/sites/contoso'
Connect-PnpOnline $targetSiteUri
Grant-PnPAzureADAppSitePermission -AppId '75284292-7515-4e2f-aae9-d1777527dd7b' -DisplayName 'SharePoint Online Remote Access' -Site $targetSiteUri -Permissions Write
</pre>
<h1 id="interact-with-sharepoint">Interact with SharePoint</h1>
<p>Microsoft Graph only needs a <code>client_secret</code>, while SharePoint REST API needs a <code>client_assertion</code> from the Certificate Private key.</p>
<p>So, let&#39;s start with Microsoft Graph to verify our Azure app has the correct access permissions.</p>
<h2 id="microsoft-graph">Microsoft Graph</h2>
<p>Below is the script we can use:</p>
<pre class="brush:javascript">
const axios = require('axios');

// our constants that we found previously
// they should not be hard-coded in your script, but store in a safe place
const tenantId = '945c177a-83a2-4e80-9f8c-5a91be5752dd';
const clientId = '75284292-7515-4e2f-aae9-d1777527dd7b';
const clientSecret = 'rVE7Q~Z1BhRXaljbj7SPg~U2HYJRR-feckrxKbCt';
const siteId = '7d6d9e18-e8de-4b7c-9582-3f978726f356';

async function getAccessToken() {
  const resource = 'https://graph.microsoft.com';

  try {
    const response = await axios.post(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: clientId,
      client_secret: clientSecret,
      scope: `${resource}/.default`
    }), {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error getting access token:', error);
    throw error;
  }
}

// get a SharePoint item using Graph
getAccessToken()
.then(token => {
  // we need to find the siteId for each level
  // we could use `https://graph.microsoft.com/v1.0/sites/${siteId}/sites` to find the children sites Id
  // mycompany.sharepoint.com/sites/contoso/Toolbox -> 919f3ff8-2cfd-469d-ac2c-cf58475ee72a
  // mycompany.sharepoint.com/sites/contoso/Toolbox/Demo -> 37af7205-ebd1-49e5-a770-cdb182d2ae81
  return axios.get(`https://graph.microsoft.com/v1.0/sites/${siteId}/sites/919f3ff8-2cfd-469d-ac2c-cf58475ee72a/sites/37af7205-ebd1-49e5-a770-cdb182d2ae81/lists/Assets/items/123?expand=fields(select=Title)`, {
    headers:{
      'Authorization':'Bearer '+token,
      'Accept': 'application/json'
    }
  })
})
.then(res => {
  console.log(res.data);
})
.catch(err => {
  console.log("err => ", err.response.data)
})
</pre>
<h2 id="sharepoint-online-rest-api">SharePoint Online REST API</h2>
<p>If it worked with the Graph version, it means we can now test with the SharePoint REST API:</p>
<pre class="brush:javascript">
const axios = require('axios');
const fs = require("fs");
const crypto = require("crypto");
const msal = require("@azure/msal-node");
const { v4: uuid } = require('uuid');

// our constants that we found previously
// they should not be hard-coded in your script, but store in a safe place
const tenantId = '945c177a-83a2-4e80-9f8c-5a91be5752dd';
const clientId = '75284292-7515-4e2f-aae9-d1777527dd7b';
const clientSecret = 'rVE7Q~Z1BhRXaljbj7SPg~U2HYJRR-feckrxKbCt';
const resource = 'https://mycompany.sharepoint.com';
const privateKeyPassPhrase = "HereIsMyPass1223";
const thumbprint = "F7D8D4F2F140E79B215899BD93A14D0790947789";

// generate the client_assertion
function getClientAssertion () {
  // source: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/certificate-credentials.md
  // decrypt the private key
  const privateKeySource = fs.readFileSync("./SharePointOnlinePrivateKey.pem");
  const privateKeyObject = crypto.createPrivateKey({
      key: privateKeySource,
      passphrase: privateKeyPassPhrase,
      format: "pem",
  });

  const privateKey = privateKeyObject.export({
      format: "pem",
      type: "pkcs8",
  });
  
  const config = {
    auth: {
      clientId: clientId,
      authority: `https://login.microsoftonline.com/${tenantId}`,
      clientCertificate: {
        thumbprint: thumbprint, // a 40-digit hexadecimal string
        privateKey: privateKey,
      },
    },
  };

  // Create msal application object
  const cca = new msal.ConfidentialClientApplication(config);
  const helper = {
    createNewGuid:uuid
  }
  const issuer = clientId;
  const jwtAudience = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
  return cca.clientAssertion.getJwt(helper, issuer, jwtAudience);
}

async function getAccessToken() {
  // see https://github.com/SharePoint/sp-dev-docs/issues/5889 and https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate
  try {
    const response = await axios.post(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, new URLSearchParams({
      client_id: clientId,
      scope: `${resource}/.default`,
      client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
      client_assertion: getClientAssertion(),
      grant_type: 'client_credentials',
    }), {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error getting access token:', error);
    throw error;
  }
}

// run the script
getAccessToken()
.then(token => {
  return axios.get(`https://mycompany.sharepoint.com/sites/contoso/Toolbox/Demo/_api/web/lists/getbytitle('Assets')/items(123)?$select=Title`, {
    headers:{
      'Authorization':'Bearer '+token,
      'Accept': 'application/json; odata=verbose'
    }
  })
})
.then(response => {
  console.log(response.data)
})
.catch(console.log)
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2024/04/29/connect-to-sharepoint-online-from-nodejs-using-an-impersonate-application-bearer-token/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Search and restore an item from a SharePoint Online Recycle Bin</title>
		<link>https://blog.kodono.info/wordpress/2023/11/07/search-and-restore-an-item-from-a-sharepoint-online-recycle-bin/</link>
					<comments>https://blog.kodono.info/wordpress/2023/11/07/search-and-restore-an-item-from-a-sharepoint-online-recycle-bin/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 07 Nov 2023 11:09:37 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2267</guid>

					<description><![CDATA[It might be difficult to search for an item in a SharePoint recycle bin. I was using the end point _api/site/RecycleBin as a Site Collection Administrator, but in some cases it returns an error &#8220;The attempted operation is prohibited because it exceeds the list view threshold.&#8221;. The solution is to use another end point _api/site/getrecyclebinitems [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>It might be difficult to search for an item in a SharePoint recycle bin. I was using the end point <code>_api/site/RecycleBin</code> as a <b>Site Collection Administrator</b>, but in some cases it returns an error &#8220;The attempted operation is prohibited because it exceeds the list view threshold.&#8221;.</p>
<p>The solution is to use another end point <code>_api/site/getrecyclebinitems</code> (<a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.sharepoint.client.site.getrecyclebinitems?view=sharepoint-csom">see the documentation</a> for the various parameters):</p>
<pre class="brush:javascript">
fetch("https://tenant.sharepoint.com/sites/YourSite/_api/site/getrecyclebinitems?rowLimit=%2770000%27&#038;itemState=0&#038;orderby=3&#038;isAscending=false", {
  "headers": {
    "accept": "application/json",
    "content-type": "application/json",
    "x-requestdigest": document.querySelector("#__REQUESTDIGEST").value
  },
  "method": "GET",
})
.then(res => res.json())
.then(json => {
  console.log(json.value);
  // it will show an array with an object that contains several interesting properties:
  // AuthorEmail, AuthorName, DeletedByEmail, DeletedDate, DirName, Id, LeafName, Title, …
})
</pre>
<p>You can then filter the result to get what you need, for example if you&#8217;re looking for an item from the list “Projects” that has the ID 1981:</p>
<pre class="brush:javascript">
json.value.filter(item => item.DirName.includes("Lists/Projects") &#038;& item.LeafName === "1981_.000");
</pre>
<p>Then, to restore an item, we need the <code>Id</code> from the previous result. The famous endpoint to restore an item is <code>_api/site/RecycleBin('Id')/restore</code>, however it could also return the error &#8220;The attempted operation is prohibited because it exceeds the list view threshold&#8221;. In that case, we can use this other endpoint <code>_api/site/RecycleBin/RestoreByIds</code>:</p>
<pre class="brush:javascript">
fetch("https://tenant.sharepoint.com/sites/YourSite/_api/site/RecycleBin/RestoreByIds", {
  "headers": {
    "accept": "application/json",
    "content-type": "application/json",
    "x-requestdigest": document.querySelector("#__REQUESTDIGEST").value
  },
  "method": "POST",
  "body":JSON.stringify({
    "ids": [
      "4f855ee7-472b-414a-a482-4317a114c1a2" // Id to restore
    ],
    "bRenameExistingItems": true
  })
})
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2023/11/07/search-and-restore-an-item-from-a-sharepoint-online-recycle-bin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Calculating HMAC SHA-1 in the Browser</title>
		<link>https://blog.kodono.info/wordpress/2023/04/16/calculating-hmac-sha-1-in-the-browser/</link>
					<comments>https://blog.kodono.info/wordpress/2023/04/16/calculating-hmac-sha-1-in-the-browser/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Sun, 16 Apr 2023 17:23:55 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2258</guid>

					<description><![CDATA[If you&#8217;re looking for the equivalent of hash_hmac('sha1', 'string', 'secret'); in JavaScript, then here you go: async function hmac_sha1 (str, secret) { // see https://stackoverflow.com/a/47332317/1134119 let enc = new TextEncoder("utf-8"); let key = await window.crypto.subtle.importKey( "raw", // raw format of the key - should be Uint8Array enc.encode(secret), { // algorithm details name: "HMAC", hash: {name: [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>If you&#8217;re looking for the equivalent of <code>hash_hmac('sha1', 'string', 'secret');</code> in JavaScript, then here you go:</p>
<pre class="brush:js">
async function hmac_sha1 (str, secret) {
  // see https://stackoverflow.com/a/47332317/1134119
  let enc = new TextEncoder("utf-8");
  let key = await window.crypto.subtle.importKey(
    "raw", // raw format of the key - should be Uint8Array
    enc.encode(secret),
    { // algorithm details
      name: "HMAC",
      hash: {name: "SHA-1"}
    },
    false, // export = false
    ["sign", "verify"] // what this key can do
  );
  let signature = await window.crypto.subtle.sign(
    "HMAC",
    key,
    enc.encode(str)
  );
  let b = new Uint8Array(signature);
  return Array.prototype.map.call(b, x => x.toString(16).padStart(2, '0')).join("");
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2023/04/16/calculating-hmac-sha-1-in-the-browser/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Connect to SharePoint Online using an app clientId and clientSecret</title>
		<link>https://blog.kodono.info/wordpress/2023/03/21/connect-to-sharepoint-online-using-an-app-clientid-and-clientsecret/</link>
					<comments>https://blog.kodono.info/wordpress/2023/03/21/connect-to-sharepoint-online-using-an-app-clientid-and-clientsecret/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 21 Mar 2023 09:56:30 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2234</guid>

					<description><![CDATA[Get `clientId` and `clientSecret` (source) You&#8217;ll need credentials: `clientId` &#8211; required string, client id obtained when registering the addin `clientSecret` &#8211; required string, client secret obtained when registering the addin `realm` &#8211; your SharePoint Online tenant id. The easiest way to find tenant is to open SharePoint Online site collection, click Site Settings &#8594; Site [&#8230;]]]></description>
										<content:encoded><![CDATA[<h3>Get <code>`clientId`</code> and <code>`clientSecret`</code></h3>
<p>(<a href="https://github.com/s-KaiNet/node-sp-auth/wiki/SharePoint-Online-addin-only-authentication">source</a>)</p>
<p>You&#8217;ll need credentials: </p>
<ul>
<li><code>`clientId`</code> &#8211; required string, client id obtained when registering the addin</li>
<li><code>`clientSecret`</code> &#8211; required string, client secret obtained when registering the addin</li>
<li><code>`realm`</code> &#8211; your SharePoint Online tenant id. The easiest way to find tenant is to open SharePoint Online site collection, click <b>Site Settings</b> &rarr; <b>Site App Permissions</b>. Under this page you wll see at least one app &#8220;Microsoft.SharePoint&#8221;. The tenant id (realm) is highlighted in the image below:<br />
<a href="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm.png"><img fetchpriority="high" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm-1024x183.png" alt="" width="1024" height="183" class="aligncenter size-large wp-image-2236" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm-1024x183.png 1024w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm-300x54.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm-768x137.png 768w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/realm.png 1286w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></li>
</ul>
<p>Example of the expected result: </p>
<pre class="brush:javascript">
{
  clientId: '28bq7e56-8c3a-487d-hbfb-ef1a74539cbe',
  clientSecret: 's6LZ4VvoeKOS+MyAhklcavsyJBF4XhWo06OgY6czYJ0=',
  realm: '85e5f09b-4c17-4d80-afea-260bb171c456'
}
</pre>
<p>To get the credentials, you need to register a new addin inside SharePoint Online, by fellowing these steps:</p>
<ol>
<li>Open SharePoint Online app registration page, e.g. <code>https://contoso.sharepoint.com/sites/dev/_layouts/15/appregnew.aspx</code></li>
<li>Click on <b>&#8220;Generate&#8221;</b> for Client id and Client Secret, fill in Title, App Domain, Redirect URI (you can type in any values you want)<br />
         <a href="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_reg.png"><img decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_reg.png" alt="" width="374" height="364" class="aligncenter size-full wp-image-2237" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_reg.png 374w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_reg-300x292.png 300w" sizes="(max-width: 374px) 100vw, 374px" /></a></li>
<li>Click on <b>&#8220;Create&#8221;</b> and save generated Client Id and Client Secret</li>
<li><strong>[IF YOU HAVE TENANT RIGHTS]</strong> Now you need to apply permissions to the newly registered app. If you want to register the app once and use it for any site collection, it&#8217;s better to apply <strong>tenant scope permissions</strong>, so you can use the credentials everywhere inside your SharePoint tenant. To apply tenant scoped permissions, open <code>AppInv.aspx</code> page under SharePoint adminstration web site, e.g. <code>https://[YOUR_ORGANIZATION]-admin.sharepoint.com/_layouts/15/appinv.aspx</code>, copy paste Client Id from step n°3 into App Id field and click <b>&#8220;Lookup&#8221;</b>.</li>
<li><strong>[IF YOU HAVE TENANT RIGHTS]</strong> You will see your registered app, paste in the following XML into the <b>&#8220;Permission Request XML&#8221;</b> field and click <b>&#8220;Create&#8221;</b>:
<pre class="rush:xml">
    &lt;AppPermissionRequests AllowAppOnlyPolicy="true">
      &lt;AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
    &lt;/AppPermissionRequests>
</pre>
<p><a href="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_permission.png"><img decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_permission.png" alt="" width="614" height="580" class="aligncenter size-full wp-image-2238" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_permission.png 614w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_permission-300x283.png 300w" sizes="(max-width: 614px) 100vw, 614px" /></a></li>
<li><strong>[IF YOU ARE NOT A TENANT]</strong> If you only want to give permissions on 1 site collection, you can register the app on a regular site collection by using url <code>https://contoso.sharepoint.com/sites/dev/_layouts/15/appinv.aspx</code>. In this case you are not able to use tenant scoped permissions and can only apply site collection permissions:
<pre class="rush:xml">
    &lt;AppPermissionRequests AllowAppOnlyPolicy="true">
      &lt;AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
    &lt;/AppPermissionRequests>
</pre>
<li>You will see addin &#8220;Trust&#8221; confirmation, click on <b>&#8220;Trust It&#8221;</b>:<br />
<a href="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_trust.png"><img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_trust.png" alt="" width="767" height="322" class="aligncenter size-full wp-image-2239" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_trust.png 767w, https://blog.kodono.info/wordpress/wp-content/uploads/2023/03/online_addinonly_trust-300x126.png 300w" sizes="auto, (max-width: 767px) 100vw, 767px" /></a><br />
 <em>if trust-it button is not enabled and you get a red label saying tenant admin needs to trust the app, go back and try again in a few minutes.</em></li>
<li>Now you can use client id and client secret to send authenticated http requests.</li>
</ol>
<p>To know more about the XML permissions, you can check the <a href="http://(see https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/add-in-permissions-in-sharepoint)">Microsoft documentation</a>.</p>
<h3>Get Access Token</h3>
<p>(you can find a <a href="https://social.technet.microsoft.com/wiki/contents/articles/51982.sharepoint-read-online-list-data-from-c-console-application-using-access-token.aspx">C# code</a> as an example)</p>
<p>You need to do a <b>POST</b> request to <code>https://accounts.accesscontrol.windows.net/[YOUR_TENANT_REALM]/tokens/OAuth/2</code> with a <b>&#8220;Content-Type&#8221;</b> header that has the value <b>&#8220;application/x-www-form-urlencoded&#8221;</b>, and the body parameters that must be:</p>
<ul>
<li>&quot;grant_type&quot;:&quot;client_credentials&quot;</li>
<li>&quot;client_id&quot;:&quot;[YOUR_CLIENT_ID]@[YOUR_TENANT_REALM]&quot;</li>
<li>&quot;client_secret&quot;:&quot;[YOUR_CLIENT_SECRET]&quot;</li>
<li>&quot;resource&quot;:&quot;00000003-0000-0ff1-ce00-000000000000/dell.sharepoint.com@[YOUR_TENANT_REALM]&quot;</li>
</ul>
<p>See below an example in PHP:</p>
<pre class=brush:php">
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://accounts.accesscontrol.windows.net/[YOUR_TENANT_REALM]/tokens/OAuth/2");
curl_setopt($curl, CURLOPT_HTTPHEADER, [ "Content-Type: application/x-www-form-urlencoded" ]);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query([
  "grant_type" => "client_credentials",
  "client_id" => "[YOUR_CLIENT_ID]@[YOUR_TENANT_REALM]",
  "client_secret" => "[YOUR_CLIENT_SECRET]",
  "resource" => "00000003-0000-0ff1-ce00-000000000000/dell.sharepoint.com@[YOUR_TENANT_REALM]"
]));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($curl));
curl_close($curl);

echo $response->access_token;
</pre>
<p>The response should contain an access token. Example:</p>
<pre class="brush:javascript">
{
  "token_type":"Bearer",
  "expires_in":"86399",
  "not_before":"1679393911",
  "expires_on":"1679480611",
  "resource":"00000003-0000-0ff1-ce00-000000000000/dell.sharepoint.com@[YOUR_TENANT_REALM]",
  "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSU[...]SxXA5Lqbk1OcOVdwQ"
}
</pre>
<p>Finally, you can do your REST API request to SharePoint Online with passing the header <b>&#8220;Authorization&#8221;</b> that has the value <b>&#8220;Bearer [YOUR_ACCESS_TOKEN]&#8221;</b>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2023/03/21/connect-to-sharepoint-online-using-an-app-clientid-and-clientsecret/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>spfx error: No development certificate found. Generate a new certificate manually, or set the `canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`</title>
		<link>https://blog.kodono.info/wordpress/2022/12/30/spfx-error-no-development-certificate-found-generate-a-new-certificate-manually-or-set-the-cangeneratenewcertificate-parameter-to-true-when-calling-ensurecertificateasync/</link>
					<comments>https://blog.kodono.info/wordpress/2022/12/30/spfx-error-no-development-certificate-found-generate-a-new-certificate-manually-or-set-the-cangeneratenewcertificate-parameter-to-true-when-calling-ensurecertificateasync/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 30 Dec 2022 14:37:21 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[Anglais]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2225</guid>

					<description><![CDATA[When using the command gulp serve, you could receive the below error: No development certificate found. Generate a new certificate manually, or set the `canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync` To resolve, you can type gulp trust-dev-cert.]]></description>
										<content:encoded><![CDATA[<p>When using the command <code>gulp serve</code>, you could receive the below error:</p>
<blockquote><p>No development certificate found. Generate a new certificate manually, or set the `canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`</p></blockquote>
<p>To resolve, you can type <code>gulp trust-dev-cert</code>.</p>
<p><a href="https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error.png"><img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error-1024x332.png" alt="" width="1024" height="332" class="aligncenter size-large wp-image-2226" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error-1024x332.png 1024w, https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error-300x97.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error-768x249.png 768w, https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error-1536x499.png 1536w, https://blog.kodono.info/wordpress/wp-content/uploads/2022/12/spfx_error.png 1891w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2022/12/30/spfx-error-no-development-certificate-found-generate-a-new-certificate-manually-or-set-the-cangeneratenewcertificate-parameter-to-true-when-calling-ensurecertificateasync/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Detect mobile in JavaScript</title>
		<link>https://blog.kodono.info/wordpress/2022/08/01/detect-mobile-in-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2022/08/01/detect-mobile-in-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 01 Aug 2022 13:58:31 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[Anglais]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2160</guid>

					<description><![CDATA[We could simply check the resolution or user agent: const isMobile = Math.min(window.screen.width, window.screen.height) < 768 &#124;&#124; navigator.userAgent.indexOf("Mobile") > -1;]]></description>
										<content:encoded><![CDATA[<p>We could simply check the resolution or user agent:</p>
<pre class="brush:javascript">
const isMobile = Math.min(window.screen.width, window.screen.height) < 768 || navigator.userAgent.indexOf("Mobile") > -1;
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2022/08/01/detect-mobile-in-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Freebox Player API</title>
		<link>https://blog.kodono.info/wordpress/2020/11/03/freebox-player-api/</link>
					<comments>https://blog.kodono.info/wordpress/2020/11/03/freebox-player-api/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 03 Nov 2020 09:24:54 +0000</pubDate>
				<category><![CDATA[Français]]></category>
		<category><![CDATA[Partage]]></category>
		<category><![CDATA[Programmation]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2048</guid>

					<description><![CDATA[Free ne documente plus ses API depuis quelques années&#8230;. J&#8217;ai donc du faire pas mal de tests et de recherches pour trouver l&#8217;API liée au Freebox Player ! Je partage mes trouvailles sur https://github.com/Aymkdn/assistant-freebox-cloud/wiki/Player-API]]></description>
										<content:encoded><![CDATA[<p>Free ne documente plus ses API depuis quelques années&#8230;. J&#8217;ai donc du faire pas mal de tests et de recherches pour trouver l&#8217;API liée au Freebox Player !</p>
<p>Je partage mes trouvailles sur <a href="https://github.com/Aymkdn/assistant-freebox-cloud/wiki/Player-API">https://github.com/Aymkdn/assistant-freebox-cloud/wiki/Player-API</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2020/11/03/freebox-player-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SharePoint 2013 Search REST API options</title>
		<link>https://blog.kodono.info/wordpress/2019/07/24/sharepoint-2013-search-rest-api-options/</link>
					<comments>https://blog.kodono.info/wordpress/2019/07/24/sharepoint-2013-search-rest-api-options/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 24 Jul 2019 08:23:37 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1973</guid>

					<description><![CDATA[Finding the documentation for the Search REST API of Sharepoint is difficult&#8230;. There is a very old blog post that I&#8217;m going to replicate here to give more visibility: &#160; Location of the Search Rest service The Search REST service is located at the following URI: http://host/site/_api/search &#160; The Search REST API The Search REST [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Finding the documentation for the Search REST API of Sharepoint is difficult&#8230;. There is a very <a href="https://blogs.msdn.microsoft.com/nadeemis/2012/08/24/sharepoint-2013-search-rest-api/">old blog post</a> that I&#8217;m going to replicate here to give more visibility:</p>
<p>&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><strong><span style="text-decoration: underline;">Location of the Search Rest service</span></strong></p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">The Search REST service is located at the following URI: <a href="http://host/site/_api/search">http://host/site/_api/search</a></p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><strong><span style="text-decoration: underline;">The Search REST API</span></strong></p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">The Search REST service exposed by the URI specified above provides the following methods or entry points:</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<div style="direction: ltr;">
<table style="border: 1pt solid #a3a3a3; margin-left: 0.333in; border-collapse: collapse; direction: ltr;" valign="top" cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">query</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 2.709in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><a href="http://host/site/_api/search/query">http://host/site/_api/search/query</a></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 8.953in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">Supports HTTP Get&nbsp;and is used to retrieve search results.</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">postquery</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 2.709in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><a href="http://host/site/_api/search/postquery">http://host/site/_api/search/postquery</a></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 8.953in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">Supports HTTP POST and is used to retrieve search results. This method can be used to overcome URI length restrictions when using the HTTP GET based method &#8220;<span style="font-weight: bold;">query</span>&#8220;.</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">suggest</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 2.709in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><a href="http://host/site/_api/search/suggest">http://host/site/_api/search/suggest</a></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 8.953in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">Supports HTTP GET and is used to retrieve query suggestions.</p>
</td>
</tr>
</tbody>
</table>
</div>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><strong><span style="text-decoration: underline;">Query Parameters</span></strong></p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">The following table lists the query parameters available for the <span style="font-weight: bold;">query </span>entry point:</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<div>
<table style="border: 1pt solid #a3a3a3; margin-left: 0.133in; border-collapse: collapse; direction: ltr;" valign="top" cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Name</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Description</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Type</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Default</span></p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">querytext</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The text of the&nbsp;search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String &#8211; Maximum query text length allowed by the Keyword Query OM is 4096 characters.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;search is cool&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">querytemplate</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The query template text.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enableinterleaving</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies if the result sets which are generated by executing query rule actions to add result&nbsp; block should be mixed with the result set for the original query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enableinterleaving=false</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">sourceid</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the&nbsp;unique identifier of the Result Source to use for executing the search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;term&#8217;&amp;sourceid=&#8217;8413cd39-2156-4e00-b54d-11efd9abdb89&#8242;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">rankingmodelid</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The GUID of the Rank Model to be used for this search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">startrow</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">A zero-based index of the first search result to be returned.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer [ &gt;= 0]</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">0</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;startrow=11</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">rowlimit</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The maximum number of search results to be returned, starting at the index specified in&nbsp; startrow.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer&nbsp;[ &gt;= 0]</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">10</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;startrow=11&amp;rowlimit=3</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">rowsperpage</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The number of&nbsp;results to return per page.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer&nbsp;[ &gt;= 0]</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">0</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">selectproperties</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the list of managed properties to return for each search result item. For a managed property to be returned; the Retrievable flag must be set to &#8220;true&#8221; in the Search Schema.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;selectproperties=&#8217;Path,Url,Title,Author&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">culture</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the identifier of the language culture of the search query. If present, the value must be a valid LCID of a culture name. A list of LCIDs is available <a href="http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx">here</a>.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">-1</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;culture=1044</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">refiners</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies a list of refiners to return as a comma-separated list of strings.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 8pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;refiners=&#8217;companies,contentclass,ContentType,FileExtension,FileType&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">refinementfilters</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The list of refinement tokens for drilldown into search results. Refinement tokens are returned as part of the RefinementResults table for the search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;sharepoint&#8217;&amp;refiners=&#8217;filetype&#8217;&amp;refinementfilters=&#8217;filetype:equals(&#8220;pptx&#8221;)&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">hiddenconstraints</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies additional query terms that will be appended to the query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;hiddenconstraints=&#8217;powerpoint&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">sortlist</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the list of properties to sort the search results by.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;sortlist=&#8217;rank:ascending&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablestemming</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether stemming is enabled for the query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablestemming=false</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">trimduplicates</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether duplicate items should be removed from search results. This property can also<br />&nbsp;be used to collapse hits in the result set.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;trimduplicates=false</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">trimduplicatesincludeid</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the value associated with a collapse group, typically used when a user clicks the duplicates link of an item with duplicates.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">long</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">0L</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;trimduplicates=true&amp;trimduplicatesincludeid=47</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">timeout</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the amount of time, in milliseconds, before the query request times out.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">30000</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;timeout=50000</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablenicknames</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether the exact terms in the search query are used to find matches, or if nicknames<br />&nbsp;are used as well.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablenicknames=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablephonetic</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether the phonetic forms of the query terms are used to find matches.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablephonetic=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablefql</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether the query string is according to the FAST Query Language (FQL) syntax.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablefql=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">hithighlightedproperties</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the list of properties to include in the HitHighlightedProperties for each result item.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;hithighlightedproperties=&#8217;Title,Author&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bypassresulttypes</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies if the search result item type should be returned for the query results.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">processbestbets</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies if the search promoted results should be returned, if available, as a result set.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">clienttype</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Name of a client which issued query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">personalizationdata</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Gets or sets the unique identifier (GUID) for the current user who submitted the search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">resultsurl</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the URL for the page where the search results are going to be displayed.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">querytag</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Any custom tags to be used to identify the query. Multiple tags are separated by semicolons.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4">&nbsp;</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablequeryrules</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies if Query Rules are turned on for this query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablequeryrules=false</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">enablesorting</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Indicates whether results should be sorted.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/query?querytext=&#8217;terms&#8217;&amp;enablesorting=false</span></td>
</tr>
</tbody>
</table>
</div>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><strong><span style="text-decoration: underline;">Suggest Parameters</span></strong></p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">The following table lists the query parameters available from the suggest entry point:</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;&nbsp;</p>
<div style="direction: ltr;">
<table style="border: 1pt solid #a3a3a3; margin-left: 0.133in; border-collapse: collapse; direction: ltr;" valign="top" cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Name</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Description</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Type</span></p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; width: 0.837in; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;"><span style="font-weight: bold;">Default</span></p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">querytext</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The text of the search query.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">String</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Empty</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">inumberofquerysuggestions</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The number of query suggestions to retrieve.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer&nbsp;[ &gt; 0]</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">5</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;inumberofquerysuggestions=6</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">inumberofresultsuggestions</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">The number of personal results to retrieve.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer&nbsp;[ &gt; 0]</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">5</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;inumberofresultsuggestions=6</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">fprequerysuggestions</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether to retrieve pre-query suggestions or post-query suggestions.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;fprequerysuggestions=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">fhithighlighting</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether the query suggestions should be highlighted. If &#8220;true&#8221;, the terms<br />&nbsp;in the returned query suggestions that match terms in the specified query are&nbsp; surrounded with &lt;B&gt; and &lt;/B&gt; HTML tags.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">True</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;fhithighlighting=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">fcapitalizefirstletters</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies whether to capitalize first letters in each term in query suggestions.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;fcapitalizefirstletters=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">showpeoplenamesuggestions</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies if people names should be included in query suggestions.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">bool</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">False</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;showpeoplenamesuggestions=true</span></td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">culture</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Specifies the identifier of the language culture of the search query. If present, the value must be a valid LCID of a culture name. A nice list of LCIDs is available <a href="http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx">here</a>.</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">Integer</p>
</td>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top;">
<p style="margin: 0in; font-family: Calibri; font-size: 9pt;">-1</p>
</td>
</tr>
<tr>
<td style="padding: 4pt; border: 1pt solid #a3a3a3; vertical-align: top; padding-bottom: 8pt;" colspan="4"><span style="color: #5499b9; text-decoration: underline;">http://host/site/_api/search/suggest?querytext=&#8217;nad&#8217;&amp;culture=1044</span></td>
</tr>
</tbody>
</table>
</div>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;</p>
<p style="margin: 0in; font-family: Calibri; font-size: 11pt;">&nbsp;References:</p>
<ul>
<li>
<div style="margin: 0in; font-family: Calibri; font-size: 11pt;"><a href="http://msdn.microsoft.com/en-us/library/hh659202(office.12).aspx">[MS-SRCHCSOM]: Search Client Query Protocol Specification</a></div>
</li>
<li>
<div style="margin: 0in; font-family: Calibri; font-size: 11pt;"><a href="http://msdn.microsoft.com/en-us/library/jj163300(office.15).aspx">Search in SharePoint 2013 on MSDN</a></div>
</li>
</ul>
<h2>Examples</h2>
<p>A <code>postquery</code> request will look like:</p>
<pre class="brush">
POST http://localhost/_api/search/postquery HTTP/1.1
Accept: application/json;odata=verbose
Content-Type: application/json;odata=verbose
Host: localhost
Content-Length: 419

{

 'request': {
     'Querytext': 'sharepoint',
     'StartRow':1,
     'RowLimit':8,
     'SelectProperties': {
          'results': ['Title','ContentSource','DisplayAuthor']
     },
     'TrimDuplicates':true,
     'Refiners':'companies,contentclass,ContentType(filter=7/0/*),FileExtension(filter=7/0/*),FileType(filter=6/0/*)',
     'RefinementFilters': {'results': ['filetype:equals("pptx")'] }
  }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2019/07/24/sharepoint-2013-search-rest-api-options/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SP.Utilities.Utility.SendEmail returns &#8220;The e-mail message cannot be sent. Make sure the e-mail has a valid recipient.&#8221;</title>
		<link>https://blog.kodono.info/wordpress/2019/06/28/sp-utilities-utility-sendemail-returns-the-e-mail-message-cannot-be-sent-make-sure-the-e-mail-has-a-valid-recipient/</link>
					<comments>https://blog.kodono.info/wordpress/2019/06/28/sp-utilities-utility-sendemail-returns-the-e-mail-message-cannot-be-sent-make-sure-the-e-mail-has-a-valid-recipient/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 28 Jun 2019 14:01:58 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1967</guid>

					<description><![CDATA[With Sharepoint you can use SP.Utilities.Utility.SendEmail to send email in JavaScript, however you could receive the below error: &#8220;The e-mail message cannot be sent. Make sure the e-mail has a valid recipient.&#8221; After searching the web, I found the solution: instead of using an email address for the recipients you have to use the userDomain [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>With Sharepoint you can use <a href="https://gist.github.com/BasantPandey/05189832546f2c6cc0bd008fcfec3264">SP.Utilities.Utility.SendEmail</a> to send email in JavaScript, however you could receive the below error:</p>
<blockquote><p>
&#8220;The e-mail message cannot be sent. Make sure the e-mail has a valid recipient.&#8221;
</p></blockquote>
<p>After searching the web, I found <a href="http://sadomovalex.blogspot.com/2015/08/one-of-reasons-of-why-sending-email-via.html">the solution</a>: <b>instead of using an email address for the recipients</b> you have to use the <b>userDomain with &#8220;i:0#.w|&#8221;</b>.</p>
<p>For example, if the user is John Doe, and his email is john_doe@company.com, then you should use something like <b>i:0#.w|domain\\john_doe</b>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2019/06/28/sp-utilities-utility-sendemail-returns-the-e-mail-message-cannot-be-sent-make-sure-the-e-mail-has-a-valid-recipient/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Create a self-signed certificate for localhost testing with IE11 and Webpack</title>
		<link>https://blog.kodono.info/wordpress/2018/08/23/create-a-self-signed-certificate-for-localhost-testing-with-ie11-and-webpack/</link>
					<comments>https://blog.kodono.info/wordpress/2018/08/23/create-a-self-signed-certificate-for-localhost-testing-with-ie11-and-webpack/#comments</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 23 Aug 2018 10:41:50 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[internet explorer]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1912</guid>

					<description><![CDATA[Sources: https://stackoverflow.com/questions/44988163/create-self-signed-certificate-for-testing-localhost-and-have-it-accepted-by-the http://woshub.com/how-to-create-self-signed-certificate-with-powershell/ https://stackoverflow.com/questions/4691699/how-to-convert-crt-to-pem/4691749#4691749 https://webpack.js.org/configuration/dev-server/#devserver-https If you develop with Webpack under Windows and you want to open your localhost server in HTTPS with IE11 you may receive a message like : &#8220;Content was blocked because it was not signed by a valid security certificate.&#8221; Below I explain the steps to make it work with IE11: [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Sources: </p>
<ul>
<li><a href="https://stackoverflow.com/questions/44988163/create-self-signed-certificate-for-testing-localhost-and-have-it-accepted-by-the">https://stackoverflow.com/questions/44988163/create-self-signed-certificate-for-testing-localhost-and-have-it-accepted-by-the</a></li>
<li><a href="http://woshub.com/how-to-create-self-signed-certificate-with-powershell/">http://woshub.com/how-to-create-self-signed-certificate-with-powershell/</a></li>
<li><a href="https://stackoverflow.com/questions/4691699/how-to-convert-crt-to-pem/4691749#4691749">https://stackoverflow.com/questions/4691699/how-to-convert-crt-to-pem/4691749#4691749</a></li>
<li><a href="https://webpack.js.org/configuration/dev-server/#devserver-https">https://webpack.js.org/configuration/dev-server/#devserver-https</a></li>
</ul>
<p>If you develop with Webpack under Windows and you want to open your localhost server in HTTPS with IE11 you may receive a message like :</p>
<blockquote><p>&#8220;Content was blocked because it was not signed by a valid security certificate.&#8221;</p></blockquote>
<p>Below I explain the steps to make it work with IE11:</p>
<ol>
<li>Open <strong>Powershell in Administrator mode</strong></li>
<li>Type (no need to change anything, just copy/paste):
<pre class="brush:bash">New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname localhost -FriendlyName "Dev localhost" -NotAfter (Get-Date).AddMonths(240) -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")</pre>
<p>It should return a <strong>Thumbprint</strong>:</p>
<pre class="brush:bash">   PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\my

Thumbprint                                Subject
----------                                -------
1D97DFF290FBACE0871F16AD1B38172F253CA048  CN=localhost</pre>
<p>You may want to open <code>certlm.msc</code> to see the new certificate in Personal</li>
<li><strong>Export to .cer</strong> with the below Powershell command (make sure to <strong>replace</strong> <code>1D97DFF290FBACE0871F16AD1B38172F253CA048</code> with the <strong>Thumbprint</strong> you received before)&#8230; it will be exported to <code>C:\localhost.cert</code> (but you can change the path):
<pre class="brush:bash">Export-Certificate -Cert Cert:\LocalMachine\My\1D97DFF290FBACE0871F16AD1B38172F253CA048 -FilePath C:\localhost.cer (example: Export-Certificate -Cert Cert:\LocalMachine\My\PREVIOUS_Thumbprint_HERE -FilePath C:\localhost.cer)</pre>
</li>
<li>We now need to <strong>export to .pfx</strong> with the below Powershell commands:
<pre class="brush:bash">
$CertPassword = ConvertTo-SecureString -String "YourPassword" -Force –AsPlainText
Export-PfxCertificate -Cert cert:\LocalMachine\My\2779C7928D055B21AAA0Cfe2F6BE1A5C2CA83B30 -FilePath C:\localhost.pfx -Password $CertPassword
</pre>
</li>
<li>Next we&#8217;ll use the opensource application called <strong>XCA</strong>: <a href="https://hohnstaedt.de/xca/">download</a> and install it.</li>
<li>Open XCA and go to : <code>File > New Database</code></li>
<li>Choose where you want to have this database and provide a password (to make it easy, you can choose the same &#8220;YourPassword&#8221; than before)</li>
<li>Go to tab <strong>Certificates</strong></li>
<li>Click <strong>Import</strong> and select the previous created <strong>localhost.cer</strong></li>
<li>Once imported, right click the cert and <strong>Export > File</strong>, then <strong>select &#8220;*.crt&#8221;</strong> for the file format</li>
<li>Go to the <strong>Private Keys</strong> tab and click on <strong>Import PFX</strong></li>
<li>Select the previously created PFX and click <strong>Import All</strong></li>
<li>Right click on &#8220;localhost_key&#8221; and <strong>Export > File</strong>, then <strong>select &#8220;PEM Private (*.pem)&#8221;</strong> for the file format</li>
<li>Close XCA and go to the folder with all your files</li>
<li>Double-click on the file <code>localhost.crt</code> you have just created</li>
<li>Windows shows a popup with a <code>"Install Certificate..."</code> button; Click on this button</li>
<li>Choose Current User, and next, click on <strong>&#8220;Place all certificates in the following store&#8221;</strong>, and browse to <strong>&#8220;Trusted Root Certification Authorities&#8221;</strong></li>
<li>Finally, in your Webpack config, you should enter something like the below:
<pre class="brush:javascript">
module.exports = {
  //...
  devServer: {
    https: {
      key: fs.readFileSync('C:\\localhost.pem'),
      cert: fs.readFileSync('C:\\localhost.crt')
    }
  }
};
</pre>
</li>
</ol>
<p>Launch your webpack server and open IE to your localhost server. It should work&#8230;</p>
<p>If you need to do <strong>CORS request</strong>, you may need to open <strong>IE settings</strong>, then go to <strong>Security</strong> and make sure to add localhost in the <strong>Local Intranet/Trusted Sites</strong>, then click on <strong>&#8220;Custom Level&#8230;&#8221;</strong>, go to <strong>&#8220;Miscellaneous&#8221;</strong> and select &#8220;Enable&#8221; for <strong>&#8220;Access data sources across domains&#8221;</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2018/08/23/create-a-self-signed-certificate-for-localhost-testing-with-ie11-and-webpack/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Remove custom properties/metadata for an Office document [javascript]</title>
		<link>https://blog.kodono.info/wordpress/2018/04/19/remove-custom-properties-metadata-for-an-office-document-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2018/04/19/remove-custom-properties-metadata-for-an-office-document-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 19 Apr 2018 17:13:30 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1891</guid>

					<description><![CDATA[I have this document library on Sharepoint where I have one custom column called Metadata and that is a lookup to another list on my Sharepoint. When the users download an Office document from this library and then re-upload it we could have the below error message: There is at least one lookup column that [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I have this document library on Sharepoint where I have one custom column called <em>Metadata</em> and that is a lookup to another list on my Sharepoint.</p>
<p>When the users download an Office document from this library and then re-upload it we could have the below error message:</p>
<blockquote><p>There is at least one lookup column that enforces a relationship behavior and contains values that reference one or more non-existent items in the target list.</p></blockquote>
<p>It&#8217;s because the Office documents keep the custom columns from the document library from where they have been downloaded&#8230; In that case the file tries to reassign the <em>Metadata</em> with an ID that doesn&#8217;t exist anymore&#8230; causing this issue!</p>
<p>Because I&#8217;m using a homemade interface to upload documents, I&#8217;ve been able to pass some code to delete the file&#8217;s properties on-the-fly before pushing it into the document library.</p>
<p>To do so, you need <a href="https://stuk.github.io/jszip/">JSZip</a> that will permit to unzip the Office document in order to retrieve the file <b>docProps/custom.xml</b> and to change the properties we want before the final upload.</p>
<p>Let&#8217;s imagine my page contains an <code>&lt;input type="file"&gt;</code>, and that I have already loaded JSZip. Then I use <a href="https://developer.mozilla.org/fr/docs/Web/API/FileReader/readAsArrayBuffer">FileReader</a>:</p>
<pre class="brush:javascript">
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
  // content is the "arraybuffer" that represents my file
  var content = e.target.result;
  // check the file's extension (here "docx", "xlsx", and "pptx", but we could add more extensions
  var ext=file.name.split(".").slice(-1)[0];
  switch (ext) {
    case "docx":
    case "xlsx":
    case "pptx": {
      // load content in JSZip
      JSZip.loadAsync(content)
      .then(function(zip) {
        // unzip the file that contains metadata/properties
        return zip.file("docProps/custom.xml").async("text")
        .then(function(txt) {
          // replace the faulty column
          txt = txt.replace(/name="Metadata">&lt;vt:lpwstr>\d+&lt;\/vt:lpwstr>/,'name="Metadata">&lt;vt:lpwstr>&lt;\/vt:lpwstr>');
          // reinject the new file
          zip.file("docProps/custom.xml", txt);
          return zip.generateAsync({type:"arraybuffer"})
        })
      })
      .then(function(content) {
        // do something with your content
        // for example (https://aymkdn.github.io/SharepointPlus/): $SP().list("my_list").createFile({content:content, filename:file.name})
      })
      break;
    }
    default: {
      // for the other files, treat them normally
      // for example (https://aymkdn.github.io/SharepointPlus/): $SP().list("my_list").createFile({content:content, filename:file.name})
    }
  }
}
fileReader.onerror = function(e) {
  console.error(e.target.error);
}
fileReader.readAsArrayBuffer(file);
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2018/04/19/remove-custom-properties-metadata-for-an-office-document-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to delete a document locked by another user in Sharepoint using JavaScript</title>
		<link>https://blog.kodono.info/wordpress/2017/11/20/how-to-delete-a-document-locked-by-another-user-in-sharepoint-using-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2017/11/20/how-to-delete-a-document-locked-by-another-user-in-sharepoint-using-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 20 Nov 2017 10:37:03 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau expert]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1862</guid>

					<description><![CDATA[When you open a file from Sharepoint, it will receive a short term lock that will prevent others to change some properties on the file. This protection can be useful, but also very annoying, for example when the file is not closed properly, then the lock could stay &#8220;forever&#8221;. There are many posts on the [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>When you open a file from Sharepoint, it will receive a short term lock that will prevent others to change some properties on the file.</p>
<p>This protection can be useful, but also very annoying, for example when the file is not closed properly, then the lock could stay &#8220;forever&#8221;.</p>
<p>There are <a href="https://sharepoint.stackexchange.com/questions/42999/clearing-short-term-file-lock">many</a> <a href="https://sharepoint.stackexchange.com/questions/120246/how-to-delete-a-document-locked-by-another-user-im-a-super-admin">posts</a> <a href="https://sharepoint.stackexchange.com/questions/165970/can-we-unlock-a-shortterm-lock-via-csom-for-sp2013">on</a> <a href="https://sharepoint.stackexchange.com/questions/202665/the-file-is-locked-for-exclusive-use-by-same-person-sharepoint-online">the web</a> about it.</p>
<p>I found one that has been super useful: <a href="https://pholpar.wordpress.com/2014/04/07/how-to-use-javascript-to-delete-short-term-locks-from-documents-opened-from-sharepoint/">https://pholpar.wordpress.com/2014/04/07/how-to-use-javascript-to-delete-short-term-locks-from-documents-opened-from-sharepoint/</a><br />
The author explains very well the different steps what I&#8217;m trying to summarize:</p>
<ol>
<li>Send a request to <code>_vti_bin/_vti_aut/author.dll</code> with special headers/body</li>
<li>Auth.dll will provide the <code>lockid</code></li>
<li>Send a request to <code>_vti_bin/cellstorage.svc/CellStorageService</code> with special headers/body, included the <code>lockid</code></li>
<li>The file is unlocked</li>
</ol>
<p>The code to send to CellStorageService, and provided by the author, didn&#8217;t work for me. I&#8217;ve had to use Fiddler and open the document into Office on my computer to see the kind of requests send by it to unlock a document. Based on it, I&#8217;ve re-built the code and you can find my solution below.</p>
<p>Tested on Sharepoint 2013 On-Promise only. I don&#8217;t know if this solution works for Sharepoint Online or other version.<br />
Also note that I use <code>$SP().ajax()</code> from <a href="https://aymkdn.github.io/SharepointPlus/">SharepointPlus</a>, but it&#8217;s equivalent to the <code>$.ajax</code> from jQuery.</p>
<pre class="brush:javascript">
// full path to the document
var docUrl = "https://website.com/website/Doc_Library/Test.docx";

// start by querying author.dll to find the lockid and the user who locked it
$SP().ajax({
  url: 'https://website.com/website/_vti_bin/_vti_aut/author.dll',
  headers:{
    "Content-Type": "application/x-www-form-urlencoded",
    "MIME-Version": "1.0",
    "Accept": "auth/sicily",
    "X-Vermeer-Content-Type": "application/x-www-form-urlencoded"
  },
  body: 'method=getDocsMetaInfo%3a14%2e0%2e0%2e6009&#038;url%5flist=%5b' + encodeURIComponent(docUrl) + '%5d&#038;listHiddenDocs=false&#038;listLinkInfo=false',
}).then(function(source) {
  // go thru the source page returned to find the lockid and current user
  var nextLine = false;
  var ret = { "lockid":"", "user":"", when:"" };
  source.split("\n").forEach(function(line) {
    if (line.indexOf("vti_sourcecontrollockid") !== -1) nextLine="lockid"; // vti_sourcecontrollockid -> the lockid to use later
    else if (line.indexOf("vti_sourcecontrolcheckedoutby") !== -1) nextLine="user"; // vti_sourcecontrolcheckedoutby -> username of the user who locked it
    else if (line.indexOf("vti_sourcecontrollockexpires") !== -1) nextLine="when"; // vti_sourcecontrollockexpires -> when the server is supposed to unlock it
    else if (nextLine !== false) {
      ret[nextLine] = line.slice(7).replace(/&#([0-9]|[1-9][0-9]|[[01][0-9][0-9]|2[0-4][0-9]|25[0-5]);/g, function (str, match) { return  String.fromCharCode(match); });
      nextLine = false;
    }
  });

  if (!ret.lockid) { alert("Not Locked") }
  else {
    // compose a request based on what Microsoft Office sends to the Sharepoint server
    // found using Fiddler
    var releaseLockReq = '&lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">&lt;s:Body>&lt;RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>&lt;RequestCollection CorrelationId="{96A244BD-D13B-4696-9355-231FB673BC4F}" xmlns="http://schemas.microsoft.com/sharepoint/soap/">&lt;Request Url="'+docUrl+'" UseResourceID="true" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="16.0.8201.2102" MetaData="1031" RequestToken="1">&lt;SubRequest Type="ExclusiveLock" SubRequestToken="1">&lt;SubRequestData ExclusiveLockRequestType="ReleaseLock" ExclusiveLockID="'+ret.lockid+'"/>&lt;/SubRequest>&lt;/Request>&lt;/RequestCollection>&lt;/s:Body>&lt;/s:Envelope>';

    // we send it to the webservice cellstorage.svc
    $SP().ajax({
      url:'https://website.com/website/_vti_bin/cellstorage.svc/CellStorageService',
      body:releaseLockReq,
      headers:{
        'Content-Type':'text/xml; charset=UTF-8',
        'SOAPAction': "http://schemas.microsoft.com/sharepoint/soap/ICellStorages/ExecuteCellStorageRequest"
      }
    })
    .then(function(res) {
      if (res.indexOf('ErrorCode="Success"') !== -1) alert("Success") // the file has been unlocked
      else alert("Failed")
    })
  }
})
</pre>
<p>I hope it will be useful to someone else!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/11/20/how-to-delete-a-document-locked-by-another-user-in-sharepoint-using-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to drag and drop a file into a dropzone in HTML5</title>
		<link>https://blog.kodono.info/wordpress/2017/10/26/how-to-drag-and-drop-a-file-into-a-dropzone-in-html5/</link>
					<comments>https://blog.kodono.info/wordpress/2017/10/26/how-to-drag-and-drop-a-file-into-a-dropzone-in-html5/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 26 Oct 2017 15:19:16 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1858</guid>

					<description><![CDATA[We can find plenty of demo and tutorials about it on the web, but it took me a while to understand how to setup something easy and quick. The purpose is to have a zone where we can drop a file from our computer. You need: A zone where the file will be dropped (for [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>We can find plenty of demo and tutorials about it on the web, but it took me a while to understand how to setup something easy and quick.</p>
<p>The purpose is to have a zone where we can drop a file from our computer.</p>
<p>You need:</p>
<ol>
<li>A zone where the file will be dropped (for example a <code>&lt;div>&lt;/div></code>)</li>
<li>A minimum of three events:
<ul>
<li><code>drop</code></li>
<li><code>dragover</code></li>
<li><code>dragleave</code></li>
</ul>
</li>
</ol>
<p><strong>The three events attached to our dropzone must all call <code>event.preventDefault()</code> otherwise it won&#8217;t work as expected.</strong></p>
<p>Then, you can apply a style to the dropzone based on <code>dragover</code> and <code>dragleave</code>, and read the property <code>event.dataTransfer.files</code> from <code>drop</code> to get the file.</p>
<p>See here the super simple example: <a href="https://codepen.io/Aymkdn/pen/oovXNY">https://codepen.io/Aymkdn/pen/oovXNY</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/10/26/how-to-drag-and-drop-a-file-into-a-dropzone-in-html5/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Overwrite the Created field for a Sharepoint list item</title>
		<link>https://blog.kodono.info/wordpress/2017/08/28/overwrite-the-created-field-for-a-sharepoint-list-item/</link>
					<comments>https://blog.kodono.info/wordpress/2017/08/28/overwrite-the-created-field-for-a-sharepoint-list-item/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 28 Aug 2017 13:42:04 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1852</guid>

					<description><![CDATA[Sharepoint provides automatic fields, like &#8220;Created&#8221; that contains the creation date of a list item. It&#8217;s a readonly field. You could use a webservice to change the ReadOnly property in order to overwrite its value. Using SharepointPlus the code is: // don't change the below information // the details about this field are found using [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Sharepoint provides automatic fields, like &#8220;Created&#8221; that contains the creation date of a list item. It&#8217;s a readonly field.</p>
<p>You could use a webservice to change the <code>ReadOnly</code> property in order to overwrite its value.</p>
<p>Using <a href="http://aymkdn.github.io/SharepointPlus/">SharepointPlus</a> the code is:</p>
<pre class="brush:javascript">
// don't change the below information
// the details about this field are found using $SP().list().info
var updateSystemFields = "<Fields>" +
    '<Method ID="1">' +
    '<Field ID="{8c06beca-0777-48f7-91c7-6da68bc07b69}" Name="Created" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Created" Group="_Hidden" ColName="tp_Created" RowOrdinal="0" ReadOnly="FALSE" Type="DateTime" DisplayName="Created" StorageTZ="TRUE">' +
    "</Field></Method>" +
    "</Fields>";
// send the request to the server
$SP().webService({
  webURL: "https://website.url.com/",
  service: "Lists",
  operation:"UpdateList",
  properties:{
    listName: "Name of the list",
    listProperties: "",
    updateFields: updateSystemFields,
    newFields: "",
    deleteFields: "",
    listVersion: "",
  }
})
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/08/28/overwrite-the-created-field-for-a-sharepoint-list-item/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Classic ASP to get a remote page with NTLM authenticate</title>
		<link>https://blog.kodono.info/wordpress/2017/08/07/classic-asp-to-get-a-remote-page-with-ntlm-authenticate/</link>
					<comments>https://blog.kodono.info/wordpress/2017/08/07/classic-asp-to-get-a-remote-page-with-ntlm-authenticate/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 07 Aug 2017 16:23:02 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1841</guid>

					<description><![CDATA[It&#8217;s very frustrating to have to work with ASP again, after so many years&#8230; I wanted to use an ASP page to get a remote page. However I needed to pass some NTLM authenticate to it. After a few searches I found this solution: &#60;% ' I want this page to be accessible for Cross [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>It&#8217;s very frustrating to have to work with ASP again, after so many years&#8230;</p>
<p>I wanted to use an ASP page to get a remote page. However I needed to pass some NTLM authenticate to it.</p>
<p>After a few searches I found this solution:</p>
<pre class="brush:vb">
&lt;%
' I want this page to be accessible for Cross Domain, especially from http://my.company.com (using JavaScript)
Response.AddHeader "Access-Control-Allow-Origin", "http://my.company.com"
Response.AddHeader "Access-Control-Allow-Credentials", "true"

' get "url" from the parameters
set REMOTE_FILE_URL=Request.QueryString("url")

If REMOTE_FILE_URL &lt;> "" Then
  ' You could use MSXML2.ServerXMLHTTP but you would have to hardcoded the login/password
  ' Example:
  '    Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
  '    http.open "GET", REMOTE_FILE_URL, False, "domain\user_name", "Password"
  ' So here we'll use "WinHttp.WinHttpRequest.5.1" that will pass the IIS' credentials
  set http = CreateObject("WinHttp.WinHttpRequest.5.1")
  http.SetAutoLogonPolicy 0

  ' we can define timeouts (http://msdn.microsoft.com/en-us/library/windows/desktop/aa384061(v=vs.85).aspx)
  ' http.SetTimeouts(resolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout)
  ' example: http.SetTimeouts 60000, 60000, 60000, 60000

  ' we can add some headers to the request that will be done by the server
  ' http.SetRequestHeader "Content-type", "application/json"

  ' multiple options can be defined
  ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa384108(v=vs.85).aspx
  ' examples:
  ' to define the user agent: http.Option(0) = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"
  ' to ignore ssl errors: http.Option(4) = 13056

  ' if you use a proxy
  http.SetProxy 2, "proxy:80"

  ' method: open(http method, absolute uri to request, async (true: async, false: sync)
  http.open "GET", REMOTE_FILE_URL, False
  http.send

  'Response.AddHeader http.GetAllResponseHeaders
  Response.write http.responseText
Else
  Response.write "Parameter 'url' not provided."
End If
%>
</pre>
<p>Here I use the URL parameter <code>url</code> to call that specific page.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/08/07/classic-asp-to-get-a-remote-page-with-ntlm-authenticate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sharepoint WopiFrame allow framing</title>
		<link>https://blog.kodono.info/wordpress/2017/07/25/sharepoint-wopiframe-allow-framing/</link>
					<comments>https://blog.kodono.info/wordpress/2017/07/25/sharepoint-wopiframe-allow-framing/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 25 Jul 2017 09:17:56 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1832</guid>

					<description><![CDATA[In Sharepoint you can use &#60;WebPartPages:AllowFraming runat="server" /> to disable the SAMEORIGIN for X-FRAME-OPTION giving you the opportunity to call your page from an iframe (see this other article). However you cannot use the same trick to preview a file into the browser with WopiFrame.aspx. But there is a way to do it, using the [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In Sharepoint you can use <code>&lt;WebPartPages:AllowFraming runat="server" /></code> to disable the SAMEORIGIN for X-FRAME-OPTION giving you the opportunity to call your page from an iframe (see <a href="https://blog.kodono.info/wordpress/2016/11/08/disable-x-frame-options-on-sharepoint/">this other article</a>).</p>
<p>However you cannot use the same trick to preview a file into the browser with <code>WopiFrame.aspx</code>. But there is a way to do it, using the parameters into the URL.</p>
<p>Let&#8217;s say the url to preview your document is:<br />
<strong>https://my.company.com/sharepoint/_layouts/15/WopiFrame.aspx?sourcedoc=/files/Demo.docx&#038;action=default</strong></p>
<p>You need to replace <code>action=default</code> with <code>action=embedview</code>, AND you need to call <code>WopiFrame2.aspx</code> instead of <code>WopiFrame.aspx</code> (which will lead to a <code>Something Went Wrong - Sorry, you don't have access to this page</code>).</p>
<p>So the URL to use for your iframe will be:<br />
<strong>https://my.company.com/sharepoint/_layouts/15/WopiFrame2.aspx?sourcedoc=/files/Demo.docx&#038;action=embedview</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/07/25/sharepoint-wopiframe-allow-framing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Change a &#8220;Choice with Fill-In&#8221; field into a magic dropdown [Sharepoint]</title>
		<link>https://blog.kodono.info/wordpress/2017/07/19/change-a-choice-with-fill-in-field-into-a-magic-dropdown-sharepoint/</link>
					<comments>https://blog.kodono.info/wordpress/2017/07/19/change-a-choice-with-fill-in-field-into-a-magic-dropdown-sharepoint/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 19 Jul 2017 15:45:48 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1826</guid>

					<description><![CDATA[Sometimes you want to modify the options for a dropdown box by removing some existing options, however you want to be able to keep these old values for reporting or whatever reasons. Below is a way to do it by using jQuery and SharepointPlus. It will hide the &#8220;Specify your own value&#8221; stuff, and add [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Sometimes you want to modify the options for a dropdown box by removing some existing options, however you want to be able to keep these old values for reporting or whatever reasons.</p>
<p>Below is a way to do it by using jQuery and <a href="https://aymkdn.github.io/SharepointPlus/">SharepointPlus</a>. It will hide the &#8220;Specify your own value&#8221; stuff, and add the old value (if any) into the dropdown selection.</p>
<p>For example if you have a Choice field with options &#8220;A&#8221;, &#8220;B&#8221;, &#8220;C&#8221;. Your item ID #1 has value &#8220;B&#8221;.<br />
After a while you decide to delete &#8220;B&#8221; and add &#8220;D&#8221;, but you want to be able to find items with the &#8220;B&#8221; value.<br />
So you choose &#8220;Choice with Fill-In&#8221; and apply the below code:</p>
<pre class="brush:javascript">
// For flexibility reasons we create them as a Choice with Fill-In option,
//    however we hide the free text field and we show only the dropdown
//    in case of the fill-in has a value, then we add it into the list of options
$SP().formfields(["My Fist Dropdown", "Another One"]).each(function() {
  var $e = this.elem();
  // hide all except the dropdown
  //$e.not('select').hide().filter(':radio:last').closest('tr').hide(); // SP2010
  $e.eq(0).closest('table').find('tr:gt(0)').hide(); // SP2013
  // if we have a value into the fill-in box, then:
  //   - add it into the options
  //   - when another value is selected we check the first checkbox
  var fillValue = $e.last().val();
  if (fillValue) {
    $e.filter('select').append('&lt;option data-fillin="true">'+fillValue+'&lt;/option>').each(function() {
      var $this=$(this);
      $this.find('option:last').prop("selected", true);
      $this.removeAttr("onclick").on('change', function(event) {
        var $opt = $(this).find(':selected');
        if ($opt.data("fillin")) {
          $e.filter(':radio:last').prop("checked", true);
        } else {
          $e.filter(':radio:first').prop("checked", true);
        }
      });
    });
  }
})
</pre>
<p>So now, if you create a new item you&#8217;ll see a dropdown with &#8220;A&#8221;, &#8220;C&#8221;, and &#8220;D&#8221; only.<br />
But if you edit your item #1, you&#8217;ll have a dropdown with &#8220;A&#8221;, &#8220;C&#8221;, &#8220;D&#8221; and &#8220;B&#8221;.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/07/19/change-a-choice-with-fill-in-field-into-a-magic-dropdown-sharepoint/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Trigger an event when a file is uploaded on Sharepoint 2013 by drag and drop</title>
		<link>https://blog.kodono.info/wordpress/2017/06/23/trigger-an-event-when-a-file-is-uploaded-on-sharepoint-2013-by-drag-and-drop/</link>
					<comments>https://blog.kodono.info/wordpress/2017/06/23/trigger-an-event-when-a-file-is-uploaded-on-sharepoint-2013-by-drag-and-drop/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 23 Jun 2017 10:32:08 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1817</guid>

					<description><![CDATA[If you want to trigger an event after a drag&#038;drop a file for an upload operation on Sharepoint, then you&#8217;ll have to add some JavaScript into your page. // we need to make sure sp.core.js is loaded SP.SOD.executeOrDelayUntilScriptLoaded(function() { window.UploadFinishFunc=function(b, a) { typeof g_currentControl.postUploadFunc == "function" &#038;&#038; a.status != UploadStatus.CANCELLED &#038;&#038; g_currentControl.postUploadFunc(a.files); a.status != UploadStatus.CANCELLED [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>If you want to trigger an event after a drag&#038;drop a file for an upload operation on Sharepoint, then you&#8217;ll have to add some JavaScript into your page.</p>
<pre class="brush:javascript">
// we need to make sure sp.core.js is loaded
SP.SOD.executeOrDelayUntilScriptLoaded(function() {
  window.UploadFinishFunc=function(b, a) {
    typeof g_currentControl.postUploadFunc == "function" &#038;& a.status != UploadStatus.CANCELLED &#038;& g_currentControl.postUploadFunc(a.files);
    a.status != UploadStatus.CANCELLED &#038;& myPostUploadFunc(a);
    g_currentControl.status = ControlStatus.UPLOADED;
    UpdateProgressBar(ProgressMessage.UPLOADED, a);
    RefreshResult(a);
    g_currentControl.status = ControlStatus.IDLE
  }
}, 'sp.core.js');
SP.SOD.executeFunc('sp.core.js')

// below is the function that will be called
function myPostUploadFunc(data) {
  console.log("myPostUploadFunc => ",data)
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/06/23/trigger-an-event-when-a-file-is-uploaded-on-sharepoint-2013-by-drag-and-drop/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Adding a custom action to a callout in SharePoint 2013</title>
		<link>https://blog.kodono.info/wordpress/2017/06/21/adding-a-custom-action-to-a-callout-in-sharepoint-2013/</link>
					<comments>https://blog.kodono.info/wordpress/2017/06/21/adding-a-custom-action-to-a-callout-in-sharepoint-2013/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 21 Jun 2017 15:15:03 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[Astuce]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1814</guid>

					<description><![CDATA[This article has been VERY useful. But I wanted something lightly different: I wanted to add a custom action, but also have the &#8220;EDIT&#8221; button (but not the &#8220;SHARE&#8221;), and to use the current item info for my custom action. Here is the result: // source: https://www.eliostruyf.com/adding-a-custom-action-to-a-callout-in-sharepoint-2013/ // add a special callout action for our [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>This <a href="https://www.eliostruyf.com/adding-a-custom-action-to-a-callout-in-sharepoint-2013/">article</a> has been VERY useful. But I wanted something lightly different: I wanted to add a custom action, but also have the &#8220;EDIT&#8221; button (but not the &#8220;SHARE&#8221;), and to use the current item info for my custom action.</p>
<p>Here is the result:</p>
<pre class="brush:javascript">
// source: https://www.eliostruyf.com/adding-a-custom-action-to-a-callout-in-sharepoint-2013/
// add a special callout action for our library
SP.SOD.executeFunc("callout.js", "Callout", function () {
  var itemCtx = {};
  itemCtx.Templates = {};
  itemCtx.BaseViewID = 'Callout';
  // Define the list template type
  itemCtx.ListTemplateType = 101;
  itemCtx.Templates.Footer = function (itemCtx) {
    // context, custom action function, show the ECB menu (boolean)
    return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);
  };
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);
});

function AddCustomAction (renderCtx, calloutActionMenu) {
  var itemIndex = renderCtx.CurrentItemIdx
  // Add your custom action
  calloutActionMenu.addAction(new CalloutAction ({
    text: "Custom Action",
    tooltip: 'This is your custom action',
    onClickCallback: function() {
      // all the data related to your item are into `renderCtx.ListData.Row[itemIndex]`
      console.log('Callback from custom action');
    }
  }));
  // re-add EDIT action
  calloutActionMenu.addAction(new CalloutAction ({
    text: "Edit",
    onClickCallback: function(event) {
      // use the default action we have when clicking on the filename into the library
      // or call the EditForm if it's a list item and not a library
      DispEx(this, event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','1','SharePoint.OpenDocuments','','1https://your.sharepoint.com/_layouts/15/WopiFrame.aspx?sourcedoc='+renderCtx.ListData.Row[itemIndex].FileRef+'&#038;action=default','','1','0','0','0x7fffffffffffffff')
    }
  }));
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/06/21/adding-a-custom-action-to-a-callout-in-sharepoint-2013/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sharepoint Callout Documentation</title>
		<link>https://blog.kodono.info/wordpress/2017/06/19/sharepoint-callout-documentation/</link>
					<comments>https://blog.kodono.info/wordpress/2017/06/19/sharepoint-callout-documentation/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 19 Jun 2017 14:47:40 +0000</pubDate>
				<category><![CDATA[À bookmarker]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1812</guid>

					<description><![CDATA[It&#8217;s difficult to find the JavaScript documentation for the Sharepoint Callout popup&#8230; So there is the link for a quick reference: https://msdn.microsoft.com/en-us/library/office/dn135236%28v=office.15%29.aspx]]></description>
										<content:encoded><![CDATA[<p>It&#8217;s difficult to find the JavaScript documentation for the Sharepoint Callout popup&#8230; So there is the link for a quick reference: <a href="https://msdn.microsoft.com/en-us/library/office/dn135236%28v=office.15%29.aspx">https://msdn.microsoft.com/en-us/library/office/dn135236%28v=office.15%29.aspx</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/06/19/sharepoint-callout-documentation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sharepoint CallOut Popup</title>
		<link>https://blog.kodono.info/wordpress/2017/06/14/sharepoint-callout-popup/</link>
					<comments>https://blog.kodono.info/wordpress/2017/06/14/sharepoint-callout-popup/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 14 Jun 2017 15:46:29 +0000</pubDate>
				<category><![CDATA[À bookmarker]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1805</guid>

					<description><![CDATA[You can find the documentation of the cool Sharepoint CallOut Popup on dev.office.com: https://dev.office.com/sharepoint/docs/sp-add-ins/highlight-content-and-enhance-the-functionality-of-sharepoint-hosted-sharepoint]]></description>
										<content:encoded><![CDATA[<p>You can find the documentation of the cool Sharepoint CallOut Popup on dev.office.com: <a href="https://dev.office.com/sharepoint/docs/sp-add-ins/highlight-content-and-enhance-the-functionality-of-sharepoint-hosted-sharepoint">https://dev.office.com/sharepoint/docs/sp-add-ins/highlight-content-and-enhance-the-functionality-of-sharepoint-hosted-sharepoint</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/06/14/sharepoint-callout-popup/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Trigger an event when an element is visible in a scrollable area [JavaScript]</title>
		<link>https://blog.kodono.info/wordpress/2017/05/03/trigger-an-event-when-an-element-is-visible-in-a-scrollable-area-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2017/05/03/trigger-an-event-when-an-element-is-visible-in-a-scrollable-area-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 03 May 2017 09:31:21 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1786</guid>

					<description><![CDATA[EDIT in 2022 It might also be interesting to look at Intersection Observer that is now available in most browsers, and there is also a polyfill. const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { let isVisible=(entry.intersectionRatio===1); }); }, {threshold:1}); observer.observe(document.querySelector('#element'); END EDIT I have this specific need that is to trigger an [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><strong>EDIT in 2022</strong></p>
<p>It might also be interesting to look at <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a> that is now available in most browsers, and there is also a <a href="https://github.com/WICG/IntersectionObserver">polyfill</a>.</p>
<pre class="brush:javascript">
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    let isVisible=(entry.intersectionRatio===1);
  });
}, {threshold:1});
observer.observe(document.querySelector('#element');
</pre>
<p><strong>END EDIT</strong></p>
<p>I have this specific need that is to trigger an event when an element becomes visible/invisible into a scrollable area. Here is the code I came to:</p>
<pre class="brush:javascript">
/**
 * Create the handler
 * @param {NodeElement} holder The scrollable area to monitor (where the 'scroll' event will be apply)
 */
var VisibleEventListener = function(holder) {
  var _this=this;
  _this.started = false;
  _this.holder = holder;
  // detect if an element is visible
  _this.isScrolledIntoView=function(el) {
    var bndElem = el.getBoundingClientRect();
    var bndHolder = _this.holder.getBoundingClientRect();
    return bndElem.top &lt;= bndHolder.top ? !(bndHolder.top - bndElem.top > bndElem.height) : !(bndElem.bottom - bndHolder.bottom > bndElem.height);
  }
  // permits to deal with the scroll
  _this.scrollHandler=function(e) {
    for (var i=0, len=_this.events.length; i&lt;len; i++) {
      _this.events[i].check();
    }
  }
  _this.events=[];
}
/**
 * Add the visible/invisible event for an element into a scrollable area
 * @param {NodeElement}   element  The element to test
 * @param {String}   listener 'visible' or 'invisible'
 * @param {Function} callback The callback function to be called when the event is triggered
 */
VisibleEventListener.prototype.add = function(element, listener, callback) {
  var _this=this;
  var ElementToMonitor=function(element, listener, callback) {
    this._super=_this;
    this.element=element;
    this.isVisible=false;
    this.callback=callback;
    this.listener=listener;
  }
  ElementToMonitor.prototype.check = function() {
    var visible=this._super.isScrolledIntoView(this.element);
    if (visible &#038;& !this.isVisible) { // becomes visible
      this.isVisible=true;
      if (this.listener==='visible') this.callback.call(this.element)
    } else if (!visible &#038;& this.isVisible) { // becomes invisible
      this.isVisible=false;
      if (this.listener==='invisible') this.callback.call(this.element)
    }
  };
  var etm=new ElementToMonitor(element,listener,callback);
  _this.events.push(etm);
  // if we have started to monitor
  if (_this.started===true) etm.check();
}
VisibleEventListener.prototype.start = function() {
  this.holder.addEventListener('scroll', this.scrollHandler);
  this.started = true;
  // trigger the check to verify if the elements are already visible
  this.scrollHandler();
}
VisibleEventListener.prototype.stop = function() {
  this.holder.removeEventListener('scroll', this.scrollHandler);
  this.started = false;
}
</pre>
<p>And to use it:</p>
<pre class="brush:javascript">
// initiate our area with VisibleEventListener
var vel = new VisibleEventListener(document.querySelector('#s4-workspace'));
// add the elements to monitor
vel.add(document.querySelector('.slideshow'), 'invisible', function() {
  console.log(this,' is now invisible')
})
vel.add(document.querySelector('.slideshow'), 'visible', function() {
  console.log(this,' is now visible')
})
// start the monitoring
vel.start();
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/05/03/trigger-an-event-when-an-element-is-visible-in-a-scrollable-area-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Check if an element is visible [JavaScript]</title>
		<link>https://blog.kodono.info/wordpress/2017/05/03/check-if-an-element-is-visible-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2017/05/03/check-if-an-element-is-visible-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 03 May 2017 08:14:02 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1784</guid>

					<description><![CDATA[We can find plenty of answers about how to check if an element is visible. In my case the one which works with opacity, and into a scrollable area, is this one (that I have optimized): function isScrolledIntoView(el, holder) { var bndElem = el.getBoundingClientRect(); var bndHolder = holder.getBoundingClientRect(); return bndElem.top &#60;= bndHolder.top ? !(bndHolder.top - [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>We can find plenty of answers about how to check if an element is visible.</p>
<p>In my case the one which works with <code>opacity</code>, and into a scrollable area, is <a href="http://stackoverflow.com/a/41754707/1134119">this one</a> (that I have optimized):</p>
<pre class="brush:javascript">
function isScrolledIntoView(el, holder) {
  var bndElem = el.getBoundingClientRect();
  var bndHolder = holder.getBoundingClientRect();
  return bndElem.top &lt;= bndHolder.top ? !(bndHolder.top - bndElem.top > bndElem.height) : !(bndElem.bottom - bndHolder.bottom > bndElem.height);
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/05/03/check-if-an-element-is-visible-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Resolve Promise one after another, in sequence</title>
		<link>https://blog.kodono.info/wordpress/2017/04/13/resolve-promise-one-after-another-in-sequence/</link>
					<comments>https://blog.kodono.info/wordpress/2017/04/13/resolve-promise-one-after-another-in-sequence/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 13 Apr 2017 15:30:02 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1779</guid>

					<description><![CDATA[Below is the code that is handy when you want to execute several Promise actions in sequence: function PromiseChain(arr, fct) { var dfd = Promise.resolve(); var res = arr.map(function(item,idx) { dfd = dfd.then(function() { return fct(item,idx) }); return dfd }); return Promise.all(res) } // for short version: // function PromiseChain(n,r){var e=Promise.resolve(),i=n.map(function(n,i){return e=e.then(function(){return r(n,i)})});return Promise.all(i)} And [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Below is the code that is handy when you want to execute several Promise actions in sequence:</p>
<pre class="brush:javascript">
function PromiseChain(arr, fct) {
  var dfd = Promise.resolve();
  var res = arr.map(function(item,idx) {
    dfd = dfd.then(function() {
      return fct(item,idx)
    });
    return dfd
  });
  return Promise.all(res)
}

// for short version:
// function PromiseChain(n,r){var e=Promise.resolve(),i=n.map(function(n,i){return e=e.then(function(){return r(n,i)})});return Promise.all(i)}
</pre>
<p>And an example about how to use it:</p>
<pre class="brush:javascript">
function promFunc(key) {
  return new Promise(function(prom_res) {
    setTimeout(function() { prom_res(key) }, 1000);
  })
}

PromiseChain(["a", "b", "c"], function(val, idx) {
  console.log(idx, val);
  return promFunc(idx+"_"+val);
})
.then(function(res) {
  console.log(res);
})

// result:
// 0 a
// 1 b
// 2 c
// Array [ "0_a", "1_b", "2_c" ]
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/04/13/resolve-promise-one-after-another-in-sequence/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deep clone an object in JavaScript</title>
		<link>https://blog.kodono.info/wordpress/2017/04/12/deep-clone-an-object-in-javascript/</link>
					<comments>https://blog.kodono.info/wordpress/2017/04/12/deep-clone-an-object-in-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 12 Apr 2017 10:52:12 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1776</guid>

					<description><![CDATA[We can find many discussions and solutions about this issue. In my case the one that worked is this code. Below you&#8217;ll find a compressed version of the extend() function (with a fix): function extend(){var r,t,n,o,e=arguments[0]&#124;&#124;{},f=1,i=arguments.length,u=!1,y=function(r){if(null===r&#124;&#124;"object"!=typeof r&#124;&#124;r.nodeType&#124;&#124;null!==r&#038;&#038;r===r.window)return!1;try{if(r.constructor&#038;&#038;!this.hasOwnProperty.call(r.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0};for("boolean"==typeof e&#038;&#038;(u=e,e=arguments[f]&#124;&#124;{},f++),"object"!=typeof e&#038;&#038;"function"!=typeof e&#038;&#038;(e={}),!1;i>f;f+=1)if(null!==(r=arguments[f]))for(t in r)e!==r[t]&#038;&#038;"undefined"==typeof e[t]&#038;&#038;(u&#038;&#038;r[t]&#038;&#038;(y(r[t])&#124;&#124;(n=Array.isArray(r[t])))?(n?(n=!1,o=e[t]&#038;&#038;Array.isArray(e[t])?e[t]:[]):o=e[t]&#038;&#038;y(e[t])?e[t]:{},e[t]=extend(u,o,r[t])):void 0!==r[t]&#038;&#038;(e[t]=r[t]));return e} And here an example: var object_a = { value_1: 'a', [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>We can find many discussions and solutions about this issue.</p>
<p>In my case the one that worked is <a href="http://stackoverflow.com/a/24248152/1134119">this code</a>.</p>
<p>Below you&#8217;ll find a compressed version of the <code>extend()</code> function (<a href="https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript/24248152#comment75410509_24248152">with a fix</a>):</p>
<pre class="brush:javascript">
function extend(){var r,t,n,o,e=arguments[0]||{},f=1,i=arguments.length,u=!1,y=function(r){if(null===r||"object"!=typeof r||r.nodeType||null!==r&#038;&r===r.window)return!1;try{if(r.constructor&#038;&!this.hasOwnProperty.call(r.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0};for("boolean"==typeof e&#038;&(u=e,e=arguments[f]||{},f++),"object"!=typeof e&#038;&"function"!=typeof e&#038;&(e={}),!1;i>f;f+=1)if(null!==(r=arguments[f]))for(t in r)e!==r[t]&#038;&"undefined"==typeof e[t]&#038;&(u&#038;&r[t]&#038;&(y(r[t])||(n=Array.isArray(r[t])))?(n?(n=!1,o=e[t]&#038;&Array.isArray(e[t])?e[t]:[]):o=e[t]&#038;&y(e[t])?e[t]:{},e[t]=extend(u,o,r[t])):void 0!==r[t]&#038;&(e[t]=r[t]));return e}
</pre>
<p>And here an example:</p>
<pre class="brush:javascript">
var object_a = {
    value_1: 'a',
    value_2: true,
    value_3: 354,
    value_4: [
      'x',
      'y',
      'z'
    ],
    value_5: {
      I: 'I',
      II: 'II',
      III: 'III',
      IV: {
        a: 'A',
        b: 'B'
      },
      V: [
        'elm', {
          5: 'five'
        },
        ['my_array']
      ]
    },
    value_6: function() {
      return "pouet"
    },
    value_7: new Date(2017, 0, 1)
  };
var object_b = {};
// clone object_a into object_b
extend(true, object_b, object_a);
object_a.value_2 = false;
object_a.value_1 = "b";
console.log("A => ", object_a);
console.log("B => ", object_b);
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/04/12/deep-clone-an-object-in-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Check permissions in Sharepoint based on a PermMask</title>
		<link>https://blog.kodono.info/wordpress/2017/04/06/check-permissions-in-sharepoint-based-on-a-permmask/</link>
					<comments>https://blog.kodono.info/wordpress/2017/04/06/check-permissions-in-sharepoint-based-on-a-permmask/#comments</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 06 Apr 2017 12:41:34 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1773</guid>

					<description><![CDATA[In some cases you could get this kind of hexadecimal numbers from Sharepoint for the PermMask: 0xb008431061, or 0x1b03c4313ff, and so on. To verify the PermMask against the different level of permissions you can proceed with the below method (using functions from core.js): var permMask = '0x1b03c4313ff'; var permissions = new SP.BasePermissions(); permissions.initPropertiesFromJson({High:GetPermMaskH(permMask), Low:GetPermMaskL(permMask)}); // [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In some cases you could get this kind of hexadecimal numbers from Sharepoint for the PermMask: <code>0xb008431061</code>, or <code>0x1b03c4313ff</code>, and so on.</p>
<p>To verify the PermMask against the different level of permissions you can proceed with the below method (using functions from <code>core.js</code>):</p>
<pre class="brush:javascript">
var permMask = '0x1b03c4313ff';
var permissions = new SP.BasePermissions();
permissions.initPropertiesFromJson({High:GetPermMaskH(permMask), Low:GetPermMaskL(permMask)});
// we can now check permissions using SP.BasePermissions.has()
// and we can compare with SP.PermissionKind — see https://msdn.microsoft.com/en-us/library/office/ee556747(v=office.14).aspx
var canEdit = permissions.has(SP.PermissionKind.editListItems);
</pre>
<p>On Sharepoint 2010 <code>GetPermMaskH</code> and <code>GetPermMaskL</code> are not defined, so here is their code:</p>
<pre class="brush:javascript">
function GetPermMaskH(b) {
    var a = b.length;
    return a &lt;= 10 ? 0 : parseInt(b.substring(2, a - 8), 16)
}

function GetPermMaskL(b) {
    var a = b.length;
    return a &lt;= 10 ? parseInt(b) : parseInt(b.substring(a - 8, a), 16)
}
</pre>
<p>It took me many hours to find how to proceed, so I hope it will help some others.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/04/06/check-permissions-in-sharepoint-based-on-a-permmask/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Decode Sharepoint unicode URL</title>
		<link>https://blog.kodono.info/wordpress/2017/02/17/decode-sharepoint-unicode-url/</link>
					<comments>https://blog.kodono.info/wordpress/2017/02/17/decode-sharepoint-unicode-url/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 17 Feb 2017 10:32:31 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1770</guid>

					<description><![CDATA[Sharepoint encodes the URLs with unicode, so we&#8217;ll see many \u002f to represent /. If you want to decode those unicode strings, you can use this short code: unescape(JSON.parse('"' + s.replace('"', '\\"') + '"'))]]></description>
										<content:encoded><![CDATA[<p>Sharepoint encodes the URLs with unicode, so we&#8217;ll see many <code>\u002f</code> to represent <code>/</code>.</p>
<p>If you want to decode those unicode strings, you can use <a href="http://stackoverflow.com/a/12869914/1134119">this short code</a>:<br />
<code>unescape(JSON.parse('"' + s.replace('"', '\\"') + '"'))</code></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/02/17/decode-sharepoint-unicode-url/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Redirect after Deleting [Sharepoint]</title>
		<link>https://blog.kodono.info/wordpress/2017/02/15/redirect-after-deleting-sharepoint/</link>
					<comments>https://blog.kodono.info/wordpress/2017/02/15/redirect-after-deleting-sharepoint/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 15 Feb 2017 15:42:15 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1768</guid>

					<description><![CDATA[When I open a dialog for an EditFrom and use the &#8220;Delete Item&#8221; button from the ribbon, then the main page is redirected to the related Sharepoint list. This behavior is very bad for the user experience. To change it I used the below Javascript code: // replace the Delete Item default action when into [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>When I open a dialog for an EditFrom and use the &#8220;Delete Item&#8221; button from the ribbon, then the main page is redirected to the related Sharepoint list. This behavior is very bad for the user experience.</p>
<p>To change it I used the below Javascript code:</p>
<pre class="brush:javascript">
// replace the Delete Item default action when into a popup
$(document).ready(function() {
  // if it's in a popup
  if (window !== window.top) {
    $('a[id$="_toolBarTbl_RptControls_diidIODeleteItem"]').attr("href","javascript:commonDeleteItem(); return false")
  }
})
// now when clicking on the Delete item it will call my own function
// here I use http://aymkdn.github.io/SharepointPlus/ to show a waiting message and to delete the current item, and then close the modal
function commonDeleteItem() {
  $SP().waitModalDialog("Deleting...");
  $SP().list("{"+WPQ2FormCtx.ListAttributes.Id+"}").remove({ID:GetUrlKeyValue("ID")}, {
    after:function() {
      $SP().closeModalDialog();
      $SP().closeModalDialog(2);
    }
  })
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/02/15/redirect-after-deleting-sharepoint/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to open an Excel document from SharePoint into Chrome/Firefox in readonly/edit mode</title>
		<link>https://blog.kodono.info/wordpress/2017/02/09/how-to-open-an-excel-document-from-sharepoint-files-into-chromefirefox-in-readonlyedit-mode/</link>
					<comments>https://blog.kodono.info/wordpress/2017/02/09/how-to-open-an-excel-document-from-sharepoint-files-into-chromefirefox-in-readonlyedit-mode/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 09 Feb 2017 18:07:22 +0000</pubDate>
				<category><![CDATA[Debug]]></category>
		<category><![CDATA[Navigateur]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1760</guid>

					<description><![CDATA[With Sharepoint 2010, when you use Internet Explorer you can open an Office document in readonly or in edit mode. Also, when trying to open an Excel file in Firefox/Chrome it will probably open the ugly xslviewer and won&#8217;t let you deal with your file. After searching a bit about it, I found a clue [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>With Sharepoint 2010, when you use Internet Explorer you can open an Office document in readonly or in edit mode. Also, when trying to open an Excel file in Firefox/Chrome it will probably open the ugly <code>xslviewer</code> and won&#8217;t let you deal with your file.</p>
<p>After searching a bit about it, I found <a href="http://stackoverflow.com/a/30929451/1134119">a clue</a> that helped me to find a good solution: on Firefox/Chrome when you click on an Excel file, you&#8217;ll now have a modal asking if you want to open it in edit or readonly mode!<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2017/02/opendocuments1.png" alt="" width="310" height="298" class="aligncenter size-full wp-image-1761" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2017/02/opendocuments1.png 310w, https://blog.kodono.info/wordpress/wp-content/uploads/2017/02/opendocuments1-300x288.png 300w" sizes="auto, (max-width: 310px) 100vw, 310px" /></p>
<p>To achieve this result you have to insert the below Javascript code somewhere into your masterpage:</p>
<pre class="brush:javascript">
/**
 * fix problem with Excel documents on Firefox/Chrome
 * @param  {HTMLElement} p the &lt;A> element
 * @param  {HTMLEvent} a the click event
 * @param  {Boolean} h TRUE
 * @param  {Boolean} e FALSE
 * @param  {Boolean} g FALSE
 * @param  {Strin} k the ActiveX command (e.g. "SharePoint.OpenDocuments.3")
 * @param  {Number} c 0
 * @param  {String} o the activeX command, here we look at "SharePoint.OpenDocuments"
 * @param  {String} m
 * @param  {String} b the replacement URL to the xslviewer
 */
var bak_DispEx;
var modalOpenDocument; // it will be use with the modal
SP.SOD.executeOrDelayUntilEventNotified(function() {
  bak_DispEx = _DispEx;
  _DispEx=function(p, a, h, e, g, k, c, o, m, b, j, l, i, f, d) {
    // if o==="SharePoint.OpenDocuments" &#038;& !IsClientAppInstalled(o)
    // in that case we want to open ask the user if he/she wants to readonly or edit the file
    var fileURL = b.replace(/.*_layouts\/xlviewer\.aspx\?id=(.*)/, "$1");
    if (o === "SharePoint.OpenDocuments" &#038;& !IsClientAppInstalled(o) &#038;& /\.xlsx?$/.test(fileURL)) {
      // if the URL doesn't start with http
      if (!/^http/.test(fileURL)) {
        fileURL = window.location.protocol + "//" + window.location.host + fileURL;
      }
      var ohtml = document.createElement('div');
      ohtml.style.padding = "10px";
      ohtml.style.display = "inline-block";
      ohtml.style.width = "200px";
      ohtml.style.width = "200px";
      ohtml.innerHTML = '&lt;style>'
                      + '.opendocument_button { background-color:#fdfdfd; border:1px solid #ababab; color:#444; display:inline-block; padding: 7px 10px; }'
                      + '.opendocument_button:hover { box-shadow: none }'
                      + '#opendocument_readonly,#opendocument_edit { float:none; font-size: 100%; line-height: 1.15; margin: 0; overflow: visible; box-sizing: border-box; padding: 0; height:auto }'
                      + '.opendocument_ul { list-style-type:none;margin-top:10px;margin-bottom:10px;padding-top:0;padding-bottom:0 }'
                      + '&lt;/style>'
                      + 'You are about to open:'
                      + '&lt;ul class="opendocument_ul">'
                      + '  &lt;li>Name: &lt;b>'+fileURL.split("/").slice(-1)+'&lt;/b>&lt;/li>'
                      + '  &lt;li>From: &lt;b>'+window.location.hostname+'&lt;/b>&lt;/li>'
                      + '&lt;/ul>'
                      + 'How would like to open this file?'
                      + '&lt;ul class="opendocument_ul">'
                      + '  &lt;li>&lt;label>&lt;input type="radio" name="opendocument_choices" id="opendocument_readonly" checked> Read Only&lt;/label>&lt;/li>'
                      + '  &lt;li>&lt;label>&lt;input type="radio" name="opendocument_choices" id="opendocument_edit"> Edit&lt;/label>&lt;/li>'
                      + '&lt;/ul>'
                      + '&lt;div style="text-align: center;margin-top: 20px;">&lt;button type="button" class="opendocument_button" style="background-color: #2d9f2d;color: #fff;" onclick="modalOpenDocument.close(document.getElementById(\'opendocument_edit\').checked)">Open&lt;/button> &lt;button type="button" class="opendocument_button" style="margin-left:10px" onclick="modalOpenDocument.close(-1)">Cancel&lt;/button>&lt;/div>';
      // show the modal
      modalOpenDocument=SP.UI.ModalDialog.showModalDialog({
        html:ohtml,
        dialogReturnValueCallback:function(ret) {
          if (ret!==-1) {
            if (ret === true) { // edit
              // reformat the fileURL
              var ext;
              if (/\.xlsx?$/.test(b)) ext = "ms-excel";
              if (/\.docx?$/.test(b)) ext = "ms-word"; // not currently supported
              fileURL = ext + ":ofe|u|" + fileURL;
            }
            window.location.href = fileURL; // open the file
          }
        }
      });
      a.preventDefault();
      a.stopImmediatePropagation()
      a.cancelBubble = true;
      a.returnValue = false;
      return false;
    }
    return bak_DispEx.apply(this, arguments);
  }
}, "sp.scriptloaded-core.js")
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2017/02/09/how-to-open-an-excel-document-from-sharepoint-files-into-chromefirefox-in-readonlyedit-mode/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Yes, you can be lazy and get more than 5000 SharePoint Items</title>
		<link>https://blog.kodono.info/wordpress/2016/12/06/yes-you-can-be-lazy-and-get-more-than-5000-sharepoint-items/</link>
					<comments>https://blog.kodono.info/wordpress/2016/12/06/yes-you-can-be-lazy-and-get-more-than-5000-sharepoint-items/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 06 Dec 2016 08:32:04 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau débutant]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1733</guid>

					<description><![CDATA[To reply to this blog post I wanted to share the same thing but with SharepointPlus. To use the paging option and get all the content from a large Sharepoint list you can simply do the below code: $SP().list("My List").get({ fields:"ID,Title", rowlimit:5000, paging:true, progress:function progress(nbItemsLoaded) { // for each new page this function will be [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>To reply to <a href="http://sympmarc.com/2016/11/30/25696/">this blog post</a> I wanted to share the same thing but with <a href="http://aymkdn.github.io/SharepointPlus/">SharepointPlus</a>.</p>
<p>To use the paging option and get all the content from a large Sharepoint list you can simply do the below code:</p>
<pre class="brush:javascript">
$SP().list("My List").get({
  fields:"ID,Title",
  rowlimit:5000,
  paging:true,
  progress:function progress(nbItemsLoaded) {
    // for each new page this function will be called
    console.log("It's still loading... already "+nbItemsLoaded+" items have been loaded!");
  }
}, function(data) {
  console.log(data.length); // -> 23587
  for (var i=0, len=data.length; i&lt;len; i++) {
    console.log(data[i].getAttribute("ID"))
  }
})
</pre>
<p>If you only want to get the first 15,000 items, you can use the option <code>page:3</code>. See <a href="http://aymkdn.github.io/SharepointPlus/symbols/%24SP%28%29.list.html#.get">the documentation</a> to know more.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/12/06/yes-you-can-be-lazy-and-get-more-than-5000-sharepoint-items/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
