<?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>Niveau intermédiaire &#8211; Kodono</title>
	<atom:link href="https://blog.kodono.info/wordpress/category/niveau-intermediaire/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.kodono.info/wordpress</link>
	<description>Pour tous les technophiles</description>
	<lastBuildDate>Mon, 30 Dec 2024 18:39:49 +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>Animated favicon in Chrome/Edge</title>
		<link>https://blog.kodono.info/wordpress/2024/12/30/animated-favicon-in-chrome-edge/</link>
					<comments>https://blog.kodono.info/wordpress/2024/12/30/animated-favicon-in-chrome-edge/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 30 Dec 2024 18:39:49 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Navigateur]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2348</guid>

					<description><![CDATA[To animate a favicon with Chrome / Edge, we can create an animated canvas and a web worker. See the Github repository I created about it.]]></description>
										<content:encoded><![CDATA[<p>To animate a favicon with Chrome / Edge, we can create an animated canvas and a web worker.</p>
<p>See the <a href="https://github.com/Aymkdn/animated-favicon">Github repository</a> I created about it.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2024/12/30/animated-favicon-in-chrome-edge/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Remove lazy loading for a custom SPFx webpart</title>
		<link>https://blog.kodono.info/wordpress/2024/12/15/remove-lazy-loading-for-a-custom-spfx-webpart/</link>
					<comments>https://blog.kodono.info/wordpress/2024/12/15/remove-lazy-loading-for-a-custom-spfx-webpart/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Sun, 15 Dec 2024 22:09:45 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[english]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2344</guid>

					<description><![CDATA[SharePoint Online is doing lazy loading when we hit a page with webparts. If you created a SPFx webpart, and if it&#8217;s not visible right after the page load, then it will only be loaded once the user scrolls to it&#8230; To remove this behavior, and load the webpart as soon as possible, you must [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>SharePoint Online is doing lazy loading when we hit a page with webparts. If you created a SPFx webpart, and if it&#8217;s not visible right after the page load, then it will only be loaded once the user scrolls to it&#8230;</p>
<p>To remove this behavior, and load the webpart as soon as possible, <a href="https://github.com/SharePoint/sp-dev-docs/discussions/7918">you must declare your webpart as a dynamic data source</a>.</p>
<p>Here is the minimal code example (in pure JS, not in TS):</p>
<pre class="brush:javascript">
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { DisplayMode } from '@microsoft/sp-core-library';

export default class HtmlViewerWebPart extends BaseClientSideWebPart {
  constructor() {
    super();
    // the below is used by the dynamic data source to avoid lazy loading
    this._sourceId = 'my_webpart';
  }

  onInit() {
    // to avoid lazy loading of the webpart, we register it as a dynamic data source
    // we only need to do it during the Edit of the page
    if (this.isPageInEditMode() &#038;& this.context.dynamicDataSourceManager) {
      this.context.dynamicDataSourceManager.initializeSource(this);
      console.log('Dynamic Data Source initialized to avoid lazy loading.');
    }
    
    return Promise.resolve();
  }

  isPageInEditMode() {
    return this.displayMode === DisplayMode.Edit;
  }

  // we need to declare this method because it's used by the data source to avoid lazy loading
  getPropertyDefinitions() {
    return []
  }

  // we need to declare this method because it's used by the data source to avoid lazy loading
  getPropertyValue(propertyId) {
    return propertyId;
  }
}
</pre>
<p>Then, edit the page, which will trigger the dynamic data source registration, and publish it.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2024/12/15/remove-lazy-loading-for-a-custom-spfx-webpart/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Determine an element `height` and `width` in CSS only and reuse it within another CSS rule</title>
		<link>https://blog.kodono.info/wordpress/2024/12/13/determine-an-element-height-and-width-in-css-only-and-reuse-it-within-another-css-rule/</link>
					<comments>https://blog.kodono.info/wordpress/2024/12/13/determine-an-element-height-and-width-in-css-only-and-reuse-it-within-another-css-rule/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 13 Dec 2024 15:44:36 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[english]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=2333</guid>

					<description><![CDATA[I found this technic on https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/ – it only works on modern browsers (mainly Chrome and Edge) Let&#8217;s define the properties: @property --_x { syntax: "&#60;number>"; inherits: true; initial-value: 0; } @property --_y { syntax: "&#60;number>"; inherits: true; initial-value: 0; } @property --w { syntax: "&#60;integer>"; inherits: true; initial-value: 0; } @property --h { syntax: [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I found this technic on <a href="https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/">https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/</a> – <strong>it only works on modern browsers (mainly Chrome and Edge)</strong></p>
<p>Let&#8217;s define the properties:</p>
<pre class="brush:css">
@property --_x {
  syntax: "&lt;number>";
  inherits: true;
  initial-value: 0; 
}
@property --_y {
  syntax: "&lt;number>";
  inherits: true;
  initial-value: 0; 
}
@property --w {
  syntax: "&lt;integer>";
  inherits: true;
  initial-value: 0; 
}
@property --h {
  syntax: "&lt;integer>";
  inherits: true;
  initial-value: 0; 
}
</pre>
<p>Then, let&#8217;s find an element that is a common parent for both the element where we&#8217;ll calculate the height/width, and the element that will use this height/width, and we apply some CSS:</p>
<pre class="brush:css">
.parent {
  timeline-scope: --cx,--cy;
  --w:calc(1/(1 - var(--_x)));
  --h:calc(1/(1 - var(--_y)));
  animation: x linear,y linear;
  animation-timeline: --cx,--cy !important;
  animation-range: entry 100% exit 100%;
}
</pre>
<p>We finish up with some additional CSS:</p>
<pre class="brush:css">
.get-dimension {
  overflow: hidden;
  position: relative;
}
.get-dimension:before {
  content:"";
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  aspect-ratio: 1;
  view-timeline: --cx inline,--cy block;
}
@keyframes x {to{--_x:1}}
@keyframes y {to{--_y:1}}
</pre>
<p>And finally, we can use <code>--w</code> and <code>--h</code> in the other element:</p>
<pre class="brush:css">
.apply-dimension {
  height: calc(var(--h)*1px);
  width: calc(var(--w)*1px);
}
</pre>
<p>Here is a demo:<br />
<p class='codepen'  data-height='500' data-theme-id='1' data-slug-hash='vEByKod' data-default-tab='result' data-animations='run' data-editable='' data-embed-version='2'>

</p>
</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2024/12/13/determine-an-element-height-and-width-in-css-only-and-reuse-it-within-another-css-rule/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Envoie d&#8217;email et spam (via OVH)</title>
		<link>https://blog.kodono.info/wordpress/2019/01/20/envoie-demail-et-spam-via-ovh/</link>
					<comments>https://blog.kodono.info/wordpress/2019/01/20/envoie-demail-et-spam-via-ovh/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Sun, 20 Jan 2019 15:52:22 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Français]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[email]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1926</guid>

					<description><![CDATA[Si on envoie des emails depuis notre propre serveur, avec notre propre domaine, certaines mailbox (comme Gmail) pourraient vous détecter comme du spam ! Pour éviter cela, il faut prendre quelques précautions. Type &#8220;SPF&#8221; Tout d&#8217;abord, il faut ajouter une entrée SPF via le gestionnaire de domaine d&#8217;OVH. Le wizard va aider à composer la [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Si on envoie des emails depuis notre propre serveur, avec notre propre domaine, certaines mailbox (comme Gmail) pourraient vous détecter comme du spam !</p>
<p>Pour éviter cela, il faut prendre quelques précautions.</p>
<h2>Type &#8220;SPF&#8221;</h2>
<p>Tout d&#8217;abord, il faut ajouter une entrée SPF via le gestionnaire de domaine d&#8217;OVH. Le <em>wizard</em> va aider à composer la chaine qui sera enregistrée pour le domaine.</p>
<p>Il faudra fournir : </p>
<ul>
<li>L&#8217;IPv4 du serveur qui envoie les emails</li>
<li>L&#8217;IPv6 du serveur qui envoie les emails</li>
<li>Inclure le MX d&#8217;OVH (<code>include:mx.ovh.com</code>)</li>
</ul>
<p>Au final, le champ SPF devrait ressembler à ça :<br />
<code>300 IN TXT "v=spf1 a mx ip4:1.2.3.4 ip6:2001:41d0:a:abcd::1/128 include:mx.ovh.com -all"</code></p>
<h2>Type &#8220;DKIM&#8221;</h2>
<p>Cette fois on va ajouter une entrée de type &#8220;DKIM&#8221;.</p>
<p>Il faudra utiliser  <a href="https://dkimcore.org/tools/">https://dkimcore.org/tools/</a> et :</p>
<ul>
<li>Le sous domaine est fourni par l&#8217;outil (exemple : <code>1547992053.kodono._domainkey</code>)</li>
<li>Choisir la version &#8220;DKIM 1&#8221;</li>
<li>Type de clé : RSA</li>
<li>La clé publique générée par l&#8217;outil dkimcore</li>
</ul>
<p>Au final, le champ DKIM devrait ressembler à ça :<br />
<code>1547992053.kodono._domainkey.kodono.info. 	0 	DKIM 	v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQE...anzmm2RIpt0tV3gwTGwuLQIDAQAB;t=s;</code></p>
<p>On pourra ensuite utiliser <a href="https://github.com/louisameline/php-mail-signature">https://github.com/louisameline/php-mail-signature</a> qui est une librairie PHP et qui aide à signer les emails qu&#8217;on envoie en PHP.</p>
<h2>Type &#8220;DMARC&#8221;</h2>
<p>Enfin, on ajoute une entrée de type &#8220;DMARC&#8221;.</p>
<p>Il faudra utiliser :</p>
<ol>
<li>Le sous-domaine doit être <code>_dmarc</code></li>
<li>Règle pour le domaine : none</li>
</ol>
<p>Au final, le champ DMARC devrait ressemble à ça :<br />
<code>_dmarc.kodono.info.	0 	DMARC 	v=DMARC1; p=none;</code></p>
<h2>Ajout d&#8217;un reverse</h2>
<p>Il va falloir ajouter un reverse (PTR) pour l&#8217;IPv4 et l&#8217;IPv6 du serveur. Cela se fait via la console de votre serveur (par exemple via le site Kimsufi si votre serveur est là bas).</p>
<h2>Tester</h2>
<p>Une fois vos emails créés, vous pouvez les tester grâce aux sites <a href="https://www.mail-tester.com/">https://www.mail-tester.com/</a> et <a href="https://dkimvalidator.com/">https://dkimvalidator.com/</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2019/01/20/envoie-demail-et-spam-via-ovh/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Émuler Raspberry Pi sous Windows</title>
		<link>https://blog.kodono.info/wordpress/2018/01/04/emuler-raspberry-pi-sous-windows/</link>
					<comments>https://blog.kodono.info/wordpress/2018/01/04/emuler-raspberry-pi-sous-windows/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 04 Jan 2018 11:36:13 +0000</pubDate>
				<category><![CDATA[Debug]]></category>
		<category><![CDATA[Français]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1878</guid>

					<description><![CDATA[Depuis que j&#8217;ai fait assistant-plugins, j&#8217;ai plusieurs utilisateurs qui m&#8217;ont demandé comment l&#8217;installer sur leur Raspberry. Ce système est censé être similaire à une Debian, cependant ils semblent y avoir des différences&#8230; J&#8217;ai donc cherché à émuler cet OS sous mon Windows 10. Sources : https://blogs.msdn.microsoft.com/iliast/2016/11/10/how-to-emulate-raspberry-pi/ https://enavarro.me/emuler-un-raspberry-pi-avec-qemu.html Voici les étapes : Télécharger la dernière version [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Depuis que j&#8217;ai fait <a href="https://aymkdn.github.io/assistant-plugins/">assistant-plugins</a>, j&#8217;ai plusieurs utilisateurs qui m&#8217;ont demandé comment l&#8217;installer sur leur Raspberry. Ce système est censé être similaire à une Debian, cependant ils semblent y avoir des différences&#8230; J&#8217;ai donc cherché à émuler cet OS sous mon Windows 10.</p>
<p>Sources :</p>
<ul>
<li><a href="https://blogs.msdn.microsoft.com/iliast/2016/11/10/how-to-emulate-raspberry-pi/">https://blogs.msdn.microsoft.com/iliast/2016/11/10/how-to-emulate-raspberry-pi/</a></li>
<li><a href="https://enavarro.me/emuler-un-raspberry-pi-avec-qemu.html">https://enavarro.me/emuler-un-raspberry-pi-avec-qemu.html</a></li>
</ul>
<p>Voici les étapes :</p>
<ol id="steps-rpi">
<li style="margin-bottom:20px">Télécharger la dernière version disponible de QEMU sur le site <a href="https://qemu.weilnetz.de/w32/">https://qemu.weilnetz.de/w32/</a> (par exemple <em><a href="https://qemu.weilnetz.de/w32/2017/qemu-w32-setup-20171211.exe">qemu-w32-setup-20171211.exe</a></em> au moment où j&#8217;écris cet article)</li>
<li style="margin-bottom:20px">Une fois téléchargé, on va faire un clique-droit et dézipper <b>qemu-w32-setup-20171211.exe</b> vers <b>qemu-w32-setup-20171211</b></li>
<li style="margin-bottom:20px">Télécharger la dernière version de Raspbian via <a href="https://www.raspberrypi.org/downloads/raspbian/">https://www.raspberrypi.org/downloads/raspbian/</a> dans le répertoire <b>qemu-w32-setup-20171211/</b> (ou via ce lien <a href="https://downloads.raspberrypi.org/raspbian_latest">https://downloads.raspberrypi.org/raspbian_latest</a>) (par exemple je prends la version lite qui se nomme <em>2017-11-29-raspbian-stretch-lite.zip</em>)</li>
<li style="margin-bottom:20px">Télécharger le kernel dans le répertoire <b>qemu-w32-setup-20171211/</b> via <a href="https://github.com/dhruvvyas90/qemu-rpi-kernel">https://github.com/dhruvvyas90/qemu-rpi-kernel</a> (par exemple j&#8217;ai pris <em><a href="https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/kernel-qemu-4.4.34-jessie">kernel-qemu-4.4.34-jessie</a></em>)</li>
<li style="margin-bottom:20px">On va immédiatement agrandir la taille de notre image de 5G (pour éviter d&#8217;avoir des problèmes d&#8217;espace disque plus tard). Pour cela on va se rendre dans le dossier <b>qemu-w32-setup-20171211/</b> avec CMD et on va taper : <code>qemu-img.exe resize 2017-11-29-raspbian-stretch-lite +5G</code></li>
<li style="margin-bottom:20px">On peut lancer l&#8217;émulation avec la commande (<a href="https://qemu.weilnetz.de/doc/qemu-doc.html">voir tous les paramètres disponibles</a>) : <code>qemu-system-arm.exe -kernel <your_kernel_image> -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -drive "file=<your_rapsbian_image>,index=0,media=disk,format=raw" -redir tcp:2222::22</code> <br />(ce qui va donner chez moi : <code>qemu-system-arm.exe -kernel kernel-qemu-4.4.34-jessie -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -drive "file=2017-11-29-raspbian-stretch-lite.img,index=0,media=disk,format=raw" -redir tcp:2222::22</code>)</li>
<li style="margin-bottom:20px">Si tout se passe comme prévu l&#8217;image devrait démarrer et arriver jusqu&#8217;à vous demander un login (<b>pi</b>) et pass (<b>raspberry</b>) &#8230; Attention, par défaut c&#8217;est un clavier QWERTY qui est appliqué, il faut donc taper <b>rqspberry</b> pour le password.</li>
<li>On va passer le clavier en français en tapant : <code>sudo apt-get install console-data</code>, puis <code>sudo sudo dpkg-reconfigure console-data</code><br />On choisit <b>select keymap from fullist</b> puis <b>pc / azerty / French / Same as X11 (latin 9) / Standard</b>.</li>
<li>Si le clavier continue à être en anglais, taper : <code>sudo dpkg-reconfigure keyboard-configuration</code> en sélectionnant le clavier par défaut proposé, puis pour la langue, choisir <b>Other</b> puis <b>French</b>, et ensuite les propositions par défaut.<br />Et finalement la commande : <code>sudo setupcon</code></li>
<li>On va maintenant finir d&#8217;agrandir notre partition. Pour cela on tape : <code>sudo fdisk /dev/sda</code> et on suit les instructions ci-dessous :
<ul>
<li>On affiche la table des partitions avec la lettre <b>&#8220;p&#8221;</b>. On va noter le chiffre qui apparait dans la colonne <b>Start</b> pour la deuxième ligne (celle qui correspond à la partition de type Linux) (chez moi cela vaut <em>94208</em>)</li>
<li>On efface la partition principale avec la lettre <b>&#8220;d&#8221;</b> (cela devrait être la 2)</li>
<li>On crée une nouvelle partition avec la lettre <b>&#8220;n&#8221;</b>, puis on choisit primary avec <b>&#8220;p&#8221;</b> et la position <b>&#8220;2&#8221;</b></li>
<li>Pour le premier secteur on va utiliser la valeur trouvée précédemment (<em>94208</em> pour moi)</li>
<li>On appuie sur <b>&#8220;Enter&#8221;</b> pour le last sector (pour utiliser la valeur proposée)</li>
<li>À la question <b>Do you want to remove the signature?</b>, répondre <b>&#8220;N&#8221;</b></li>
<li>On écrit la table de partition avec <b>&#8220;w&#8221;</b></li>
<li>Puis on reboot avec <code>sudo shutdown -r now</code></li>
<li>Après le reboot on va terminer par : <code>sudo resize2fs /dev/sda2</code></li>
</ul>
</li>
<li>Maintenant on va augmenter la taille du swap : <code>sudo nano /etc/dphys-swapfile</code> où on va remplacer <b>CONF_SWAPSIZE=100</b> par <b>CONF_SWAPSIZE=1024</b></li>
<li>On redémarre le service avec : <code>sudo /etc/init.d/dphys-swapfile stop</code> puis <code>sudo /etc/init.d/dphys-swapfile start</code></li>
</ol>
<style>
#steps-rpi > li { margin-bottom:20px }
</style>
<p>Maintenant l&#8217;émulateur est prêt à être utilisé. Se reporter aux deux sources fournies en début d&#8217;article pour plus de détails et des options supplémentaires !</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2018/01/04/emuler-raspberry-pi-sous-windows/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 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>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 fetchpriority="high" 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="(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>Execute an action before saving a form but after the form validation [Sharepoint]</title>
		<link>https://blog.kodono.info/wordpress/2016/11/18/execute-action-before-saving-a-form-and-after-form-validation-sharepoint/</link>
					<comments>https://blog.kodono.info/wordpress/2016/11/18/execute-action-before-saving-a-form-and-after-form-validation-sharepoint/#comments</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Fri, 18 Nov 2016 14:44:22 +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=1721</guid>

					<description><![CDATA[Let&#8217;s say you want to do an asynchronous request just before saving a Sharepoint form, but after Sharepoint verified all the fields in your form (for mandatory ones, or for format, &#8230;). Here is my solution to do it (using jQuery.Deferred): // this function will do our asynchronous check function beforeSaving() { var deferred=jQuery.Deferred(); setTimeout(function() [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Let&#8217;s say you want to do an asynchronous request just before saving a Sharepoint form, but after Sharepoint verified all the fields in your form (for mandatory ones, or for format, &#8230;). Here is my solution to do it (using jQuery.Deferred):</p>
<pre class="brush:javascript">
// this function will do our asynchronous check
function beforeSaving() {
  var deferred=jQuery.Deferred();
  setTimeout(function() {
    alert("Test Complete!")
    deferred.reject(); // if the test failed
    // or deferred.resolve() to valid the test
  }, 2000)
  return deferred;
}
// force PostBackRequired to true in the context, otherwise it won't work if you open it into a modal
WPQ2FormCtx.PostBackRequired=true;
// we override SPClientForms.ClientFormManager.SubmitClientForm
SPClientForms.ClientFormManager.SubmitClientForm=function(b){
  var a=SPClientForms.ClientFormManager.GetClientForm(b);
  var res = (a!=null&#038;&a.SubmitClientForm());
  // if the form is not valid, then res===true
  if (res === true) return true;
  else {
    // at this stage, all fields' value have been saved into a hidden input
    // e.g. document.querySelector('input[type="hidden"][id$="Field_x0020_Name"]')
    // all these saved values will be sent back to the server when "WebForm_DoPostBackWithOptions" is executed

    // if the form is valid we now want to do our asynchronous check
    beforeSaving().done(function() {
      // our test is valid too so we can send the form to the server
      WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions($get(WPQ2FormCtx.SubmitButtonID).name, "", true, "", "", false, true))
    }).fail(function() {
      // if it fails we just unblock the save button
      $get(WPQ2FormCtx.SubmitButtonID).disabled=false;
    })
  }
  // to make sure the form won't be submitted yet
  return true;
};
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/11/18/execute-action-before-saving-a-form-and-after-form-validation-sharepoint/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Disable X-Frame-Options on Sharepoint</title>
		<link>https://blog.kodono.info/wordpress/2016/11/08/disable-x-frame-options-on-sharepoint/</link>
					<comments>https://blog.kodono.info/wordpress/2016/11/08/disable-x-frame-options-on-sharepoint/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 08 Nov 2016 17:34:18 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1716</guid>

					<description><![CDATA[I needed to communicate with an iframe on Sharepoint, however Sharepoint returned Load denied by X-Frame-Options &#8230; To override this limitation you have to create a Webpart page where you&#8217;ll add the code &#60;WebPartPages:AllowFraming runat="server" /> into the &#60;asp:Content> section (that might work somewhere else, but I did this way). You can also add it [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I needed to communicate with an iframe on Sharepoint, however Sharepoint returned <code>Load denied by X-Frame-Options</code> &#8230; To override this limitation you have to create a Webpart page where you&#8217;ll add the code <code>&lt;WebPartPages:AllowFraming runat="server" /></code> into the <code>&lt;asp:Content></code> section (that might work somewhere else, but I did this way).</p>
<p>You can also add it into your masterpage to allow it everywhere on your website. Add it into your <code>&lt;head></code> block:<br />
<a href="https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram.png" title="See full size image"><img decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram-1024x319.png" alt="" width="1024" height="319" class="aligncenter size-large wp-image-1836" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram-1024x319.png 1024w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram-300x93.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram-768x239.png 768w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/11/masterpage_allow_ifram.png 1672w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now you can use <code>postMessage()</code> to communicate with your iframe.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/11/08/disable-x-frame-options-on-sharepoint/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Bypass a lookup field not displayed because of threshold on NewForm and EditForm [Sharepoint 2013]</title>
		<link>https://blog.kodono.info/wordpress/2016/08/25/bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/</link>
					<comments>https://blog.kodono.info/wordpress/2016/08/25/bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/#comments</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 25 Aug 2016 16:15:48 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[sharepoint]]></category>
		<category><![CDATA[Sharepoint 2013]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1687</guid>

					<description><![CDATA[EDIT 22/Dec/2016: there is s a new version of this article at https://blog.kodono.info/wordpress/2016/12/22/2-bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/ Sharepoint is really annoying to limit the access to the list with more than 5,000 items&#8230; It causes many troubles, and one of them is when you use a lookup field into a form that is tied to a big list. Sharepoint [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><strong>EDIT 22/Dec/2016</strong>: there is s a new version of this article at <a href="https://blog.kodono.info/wordpress/2016/12/22/2-bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/">https://blog.kodono.info/wordpress/2016/12/22/2-bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/</a></p>
<p>Sharepoint is really annoying to limit the access to the list with more than 5,000 items&#8230; It causes many troubles, and one of them is when you use a lookup field into a form that is tied to a big list. Sharepoint will not display the field/dropdown but will show the message:</p>
<blockquote><p>This is a lookup column that displays data from another list that currently exceeds the List View Threshold defined by the administrator</p></blockquote>
<p>There is a solution to bypass this problem and show our lookup dropdowns.</p>
<p>You need:</p>
<ul>
<li><a href="http://jquery.com/">jQuery</a></li>
<li><a href="http://aymkdn.github.io/SharepointPlus/">Sharepoint</a></li>
<li>And I use <a href="https://harvesthq.github.io/chosen/">Chosen</a> to have a better dropdown</li>
</ul>
<p>I&#8217;ll show how I did it for the <strong>EditForm</strong>.</p>
<p>First, <strong>copy/paste the below JavaScript code</strong> into a file that you&#8217;ll store somewhere on your Sharepoint:</p>
<pre class="brush:javascript">
// load jQuery, SharepointPlus and Chosen
var toLoad = '&lt;script src="/Toolbox/Documents/js/jQuery/jquery-1.12.3.min.js">&lt;/script>'
           + '&lt;script src="/Toolbox/Documents/js/SharepointPlus/3.13/sharepointplus-3.13.min.js">&lt;/script>'
           + '&lt;link href="/Toolbox/Documents/js/Chosen/1.5.0/chosen.min.css" rel="stylesheet" type="text/css">'
           + '&lt;script src="/Toolbox/Documents/js/Chosen/1.5.0/chosen.jquery.min.js">&lt;/script>'
document.write(toLoad);

(function() {
  var aDeferred=[];
  var modal;
  // list the fields we want to fix
  // /!\ Add here the Field ID of the fields that need to be fixed
  var lookupFieldsToFix = ["Voucher_x0020_Code", "User_x0020_Name"];
  // /!\ Specify the name of the related list, as well as the Column to retrieve
  var configurationsLookup = [{list:"Vouchers", field:"Title"}, {list:"Users", field:"Name"}];

  // this function is triggered once the form is loaded
  function allLoaded(ctx) {
    // delete all existing localStorage
    localStorage.removeItem('RequestsLookup')
    // check if our call to lists are done
    $.when.apply(this, aDeferred).done(function() {
      var save={}, count=0, i;
      for (i=arguments.length; i--;) {
        if (arguments[i]) {
          save[arguments[i].field] = arguments[i].choices; // save it as {fieldName:choices}
          count++;
        }
      }
      if (count > 0) {
        // we use localStorage
        localStorage.setItem('RequestsLookup', JSON.stringify(save));
        // now reload the page
        $SP().closeModalDialog();
        $('#aspnetForm').hide().after('&lt;h1>Reloading...&lt;/h1>');
        window.location.reload();
      } else {
        // we use Chosen
        for (i=lookupFieldsToFix.length; i--;) {
          var e=WPQ2FormCtx.ListSchema[lookupFieldsToFix[i]];
          $(document.getElementById(e.Name+"_"+e.Id+"_$"+e.FieldType+"Field")).chosen({search_contains:true});
        }
        // and on Exam Name
        $SP().formfields("Exam Name").elem().chosen({search_contains:true});
      }
    })
  }
  
  /**
   * Fix the broken lookup fields
   * @param  {String} field Name of the field to fix
   * @return {Deferred}
   */  
  function fixLookup(field) {
    var deferred = jQuery.Deferred();
    var saved, choices=[], config;

    // we check if there is a Throttled
    if (WPQ2FormCtx.ListSchema[field].Throttled) {
      WPQ2FormCtx.ListSchema[field].Throttled=false;
      // check if we have a localStorage, if yes it means we are after the reload
      saved = localStorage.getItem("RequestsLookup");
      if (saved !== null) {
        saved = JSON.parse(saved);
        // we use the stored data to create our dropdown
        WPQ2FormCtx.ListSchema[field].ChoiceCount=saved[field].length;
        WPQ2FormCtx.ListSchema[field].Choices=saved[field];
        deferred.resolve();
      } else {
        WPQ2FormCtx.ListSchema[field].ChoiceCount=0;
        WPQ2FormCtx.ListSchema[field].Choices=[];
        // then we show a Waiting message
        if (!modal) {
          modal=true;
          $SP().waitModalDialog("Loading some data...");
        }
        // and we get data from the list
        config = configurationsLookup[SPArrayIndexOf(lookupFieldsToFix, field)];
        if (config.list) {
          $SP().list(config.list).get({fields:config.field, paging:true}, function(data) {
            var res=[];
            for (var i=data.length; i--;) {
              res.push({LookupId:data[i].getAttribute("ID"), LookupValue:data[i].getAttribute(config.field)});
            }
            deferred.resolve({field:field, choices:res});
          });
        } else deferred.resolve([]);
      }

    } else deferred.resolve();
    return deferred;
  }

  // do some actions as soon as the fields are shown
  var changeForm = {
    Templates: {
      OnPreRender:function(ctx) {
        // we want to show Voucher Code and User Name even if there are more than 5000 items in those lists
        if (SPArrayIndexOf(lookupFieldsToFix, ctx.ListSchema.Field[0].Name) > -1) {
          aDeferred.push(fixLookup(ctx.ListSchema.Field[0].Name));
        }
      },
      OnPostRender:function(ctx) {
        // only trigger when everything is loaded
        if (ctx.ListSchema.Field[0].Name === "Attachments") {
          allLoaded(ctx)
        }
      }
    }
  }
  // don't do it when editing the page
  if (GetUrlKeyValue("PageView") !== "Shared") SPClientTemplates.TemplateManager.RegisterTemplateOverrides(changeForm);
})();
</pre>
<p>Please refer to the <strong>/!\</strong> symbol to configure two variables: only <code>lookupFieldsToFix</code> and <code>configurationsLookup</code> need to be set by you.<br />
Note that the above code is compatible for IE8+, and all modern browsers.</p>
<p>Now go to the <strong>EditForm.aspx</strong> of your list. Then <strong>edit the page</strong>:<br />
<img decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture1.png" alt="showing how to edit the EditForm thru Settings" width="1091" height="313" class="aligncenter size-full wp-image-1691" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture1.png 1091w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture1-300x86.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture1-768x220.png 768w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture1-1024x294.png 1024w" sizes="(max-width: 1091px) 100vw, 1091px" /></p>
<p>Next, <strong>edit the webpart settings</strong>:<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture2.png" alt="show how to edit webpart settings" width="840" height="432" class="aligncenter size-full wp-image-1690" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture2.png 840w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture2-300x154.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture2-768x395.png 768w" sizes="auto, (max-width: 840px) 100vw, 840px" /></p>
<p>Go to the <strong>Miscellaneous section</strong> and enter the path to your JavaScript file (created before) in the <strong>JS Link</strong> field – you can use <code>~site</code> in the path:<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture3.png" alt="show where to input the path to the JS file" width="346" height="385" class="aligncenter size-full wp-image-1692" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture3.png 346w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture3-270x300.png 270w" sizes="auto, (max-width: 346px) 100vw, 346px" /></p>
<p>Finally click ON, and then on <strong>Stop Editing</strong> in the ribbon.</p>
<p>You can now try to edit an item and the lookup fields should be fixed. Example:<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture4.png" alt="" width="869" height="217" class="aligncenter size-full wp-image-1694" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture4.png 869w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture4-300x75.png 300w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/capture4-768x192.png 768w" sizes="auto, (max-width: 869px) 100vw, 869px" /></p>
<p><strong>NOTE</strong></p>
<p>The <code>document.write()</code> is not really a good practice because it will delay the page load. It would be better to load asyn the JS using <a href="https://gist.github.com/Aymkdn/98acfbb46fbe7c1f00cdd3c753520ea8">this tiny function</a>. In that case you need to make sure to have only Vanilla JS in your <code>changeForm</code>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/08/25/bypass-a-lookup-field-not-displayed-because-of-threshold-on-newform-and-editform-sharepoint-2013/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Incruster des sous-titres dans une vidéo</title>
		<link>https://blog.kodono.info/wordpress/2016/08/16/incruster-des-sous-titres-dans-une-video/</link>
					<comments>https://blog.kodono.info/wordpress/2016/08/16/incruster-des-sous-titres-dans-une-video/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 16 Aug 2016 14:33:02 +0000</pubDate>
				<category><![CDATA[Application]]></category>
		<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Français]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Vidéo]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[vidéo]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1676</guid>

					<description><![CDATA[Voilà une opération qui pourrait paraitre simple et qui pourtant est difficile à trouver sur le Net&#8230; Pour cela on va utiliser le logiciel HandBrake. Commencer par le télécharger puis l&#8217;installer. On choisit notre fichier vidéo d&#8217;origine (ici un .mp4) en cliquant sur &#8220;Source&#8221; : On choisit la destination, c&#8217;est-à-dire là où notre nouveau fichier [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Voilà une opération qui pourrait paraitre simple et qui pourtant est difficile à trouver sur le Net&#8230;</p>
<p>Pour cela on va utiliser le logiciel <a href="https://handbrake.fr/">HandBrake</a>. Commencer par le télécharger puis l&#8217;installer.</p>
<ol>
<li>On choisit notre fichier vidéo d&#8217;origine (ici un .mp4) en cliquant sur &#8220;Source&#8221; :<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step1.png" alt="step1" width="234" height="147" class="aligncenter size-full wp-image-1677" /><br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step1_b.png" alt="step1_b" width="304" height="323" class="aligncenter size-full wp-image-1678" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step1_b.png 304w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step1_b-282x300.png 282w" sizes="auto, (max-width: 304px) 100vw, 304px" />
</li>
<li>On choisit la destination, c&#8217;est-à-dire là où notre nouveau fichier sera sauvegardé :<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step2.png" alt="step2" width="745" height="266" class="aligncenter size-full wp-image-1679" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step2.png 745w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step2-300x107.png 300w" sizes="auto, (max-width: 745px) 100vw, 745px" /></li>
<li>On clique ensuite sur l&#8217;onglet &#8220;Subtitles&#8221; puis sur &#8220;Import SRT&#8221; et on choisit notre fichier avec l&#8217;extension &#8220;.srt&#8221; :<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step3.png" alt="step3" width="731" height="232" class="aligncenter size-full wp-image-1680" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step3.png 731w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step3-300x95.png 300w" sizes="auto, (max-width: 731px) 100vw, 731px" /></li>
<li>On choisit la langue et on coche la case &#8220;Burn In&#8221; :<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step4.png" alt="step4" width="730" height="229" class="aligncenter size-full wp-image-1681" srcset="https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step4.png 730w, https://blog.kodono.info/wordpress/wp-content/uploads/2016/08/step4-300x94.png 300w" sizes="auto, (max-width: 730px) 100vw, 730px" /></li>
<li>Et enfin on clique sur le bouton &#8220;Start&#8221; dans la barre d&#8217;outil.</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/08/16/incruster-des-sous-titres-dans-une-video/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Send an email to several recipients from a String in a workflow [Sharepoint 2013]</title>
		<link>https://blog.kodono.info/wordpress/2016/06/28/send-an-email-to-several-recipients-from-a-string-in-a-workflow-sharepoint-2013/</link>
					<comments>https://blog.kodono.info/wordpress/2016/06/28/send-an-email-to-several-recipients-from-a-string-in-a-workflow-sharepoint-2013/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 28 Jun 2016 07:22:44 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Anglais]]></category>
		<category><![CDATA[Sharepoint 2013]]></category>
		<category><![CDATA[workflow]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1665</guid>

					<description><![CDATA[I found the case in which I have to send 1 email to several recipients. I have the names stored into a Sharepoint list. Using REST API and a call into my Workflow I&#8217;ve been able to get a list of login names (using $expand=MyUserField and $select=MyUserField/Name), then you just need to concatenate them separate [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I found the case in which I have to send 1 email to several recipients. I have the names stored into a Sharepoint list.</p>
<p>Using REST API and a call into my Workflow I&#8217;ve been able to get a list of login names (using <code>$expand=MyUserField</code> and <code>$select=MyUserField/Name</code>), then you just need to concatenate them separate by <code>;</code>.</p>
<p>At the end you should have a string that looks like <code>domain\login_name1;domain\login_name2;domain\login_name3;</code> into yout <em>To</em> field for the email.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/06/28/send-an-email-to-several-recipients-from-a-string-in-a-workflow-sharepoint-2013/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Load a script once a DispForm is fully shown in Sharepoint 2013</title>
		<link>https://blog.kodono.info/wordpress/2016/05/30/load-a-script-once-a-dispform-is-fully-shown-in-sharepoint-2013/</link>
					<comments>https://blog.kodono.info/wordpress/2016/05/30/load-a-script-once-a-dispform-is-fully-shown-in-sharepoint-2013/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 30 May 2016 10:48:54 +0000</pubDate>
				<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<category><![CDATA[Sharepoint 2013]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1654</guid>

					<description><![CDATA[Sharepoint 2013 introduced the JSLink. This is very useful to play with forms and views. My attempt here is to remove some rows from the DispForm. To do so I needed to trigger an action as soon as the fields rendering has been done. After different tries, I finally came up with the PostRender option. [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Sharepoint 2013 introduced the <a href="http://jsuhail.blogspot.fr/2014/09/client-side-rendering-using-jslink-post_30.html">JSLink</a>. This is very useful to play with forms and views.</p>
<p>My attempt here is to remove some rows from the DispForm. To do so I needed to trigger an action as soon as the fields rendering has been done. After different tries, I finally came up with the <code>PostRender</code> option.</p>
<pre class="brush:javascript">
// https://gist.github.com/Aymkdn/98acfbb46fbe7c1f00cdd3c753520ea8
function loadExt(e,t){var s=this;s.files=e,s.js=[],s.head=document.getElementsByTagName("head")[0],s.after=t||function(){},s.loadStyle=function(e){var t=document.createElement("link");t.rel="stylesheet",t.type="text/css",t.href=e,s.head.appendChild(t)},s.loadScript=function(e){var t=document.createElement("script");t.type="text/javascript",t.src=s.js[e];var a=function(){++e&lt;s.js.length?s.loadScript(e):s.after()};t.onload=function(){a()},s.head.appendChild(t)};for(var a=0;a&lt;s.files.length;a++)/\.js$|\.js\?/.test(s.files[a])&#038;&s.js.push(s.files[a]),/\.css$|\.css\?/.test(s.files[a])&#038;&s.loadStyle(s.files[a]);s.js.length>0?s.loadScript(0):s.after()}

// verify when all scripts have been loaded
var loadExtLoaded = false;
function checkExt(ctx) {
  if (loadExtLoaded) {
    // here you can call a function that is in one of the called script
  } else {
    setTimeout(function() { checkExt(ctx) }, 50);
  }
}
loadExt([
  'file_you_want_to_load.js',
  'style_you_want_to_load.css',
  'no_cache_file.js?timestamp='+(Date.now())
], function() {
  loadExtLoaded=true;
});

(function() {
  function onLoad(ctx) {
    checkExt(ctx);
  }

  // do some actions as soon as the fields are shown
  var loadAfterForm = {
    Templates: {
      OnPostRender:function(ctx) {
         // only trigger when everything is loaded
        // --> ctx.ListData.Items[0] all the fields
        if (ctx.ListSchema.Field[0].Name === "Attachments") {
          onLoad(ctx)
        }
      }
    }
  }
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(loadAfterForm);
})();
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/05/30/load-a-script-once-a-dispform-is-fully-shown-in-sharepoint-2013/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Add a SharePointWebControls into a HTML version of a MasterPage [Sharepoint 2013]</title>
		<link>https://blog.kodono.info/wordpress/2016/05/03/add-a-sharepointwebcontrols-into-a-html-version-of-a-masterpage-sharepoint-2013/</link>
					<comments>https://blog.kodono.info/wordpress/2016/05/03/add-a-sharepointwebcontrols-into-a-html-version-of-a-masterpage-sharepoint-2013/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Tue, 03 May 2016 16:52:57 +0000</pubDate>
				<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=1647</guid>

					<description><![CDATA[In Sharepoint 2013 it&#8217;s now possible to create the MasterPage based on an HTML file. Here is the snippet you need to add into your HTML page to get a SharePointWebControls: &#60;!--SPM&#60;%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>--> &#60;!--CS: Start Create Snippets From Custom ASP.NET Markup Snippet--> &#60;!--SPM:&#60;SharePointWebControls:TextField runat="server" FieldName="Title" />--> &#60;!--CE: End [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In Sharepoint 2013 it&#8217;s now possible to create the MasterPage based on an HTML file.</p>
<p>Here is <a href="https://amtopmblog.azurewebsites.net/2013/02/05/sp2013-adding-custom-control-to-a-master-page-with-design-manager/">the snippet</a> you need to add into your HTML page to get a SharePointWebControls:</p>
<pre class="brush:html">
&lt;!--SPM&lt;%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>-->
&lt;!--CS: Start Create Snippets From Custom ASP.NET Markup Snippet-->
&lt;!--SPM:&lt;SharePointWebControls:TextField runat="server" FieldName="Title" />-->
&lt;!--CE: End Create Snippets From Custom ASP.NET Markup Snippet-->
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/05/03/add-a-sharepointwebcontrols-into-a-html-version-of-a-masterpage-sharepoint-2013/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Illegal use of $_SERVER. You must use the request class or request_var() to access input data. [phpBB]</title>
		<link>https://blog.kodono.info/wordpress/2016/04/21/illegal-use-of-_server-you-must-use-the-request-class-or-request_var-to-access-input-data-phpbb/</link>
					<comments>https://blog.kodono.info/wordpress/2016/04/21/illegal-use-of-_server-you-must-use-the-request-class-or-request_var-to-access-input-data-phpbb/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 21 Apr 2016 15:15:59 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[english]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1645</guid>

					<description><![CDATA[When I want to update my phpBB forum I get this annoying message because I&#8217;m using a homemade auth file where $_SERVER is used. I found the solution on the phpBB forum: Modified /forums/config/parameters.yml. Set core.disable_super_globals to false and delete the cache]]></description>
										<content:encoded><![CDATA[<p>When I want to update my phpBB forum I get this annoying message because I&#8217;m using a homemade auth file where <code>$_SERVER</code> is used.</p>
<p>I found the solution on <a href="https://www.phpbb.com/community/viewtopic.php?p=14202666#p14202666">the phpBB forum</a>: </p>
<blockquote><p>Modified /forums/config/parameters.yml. Set core.disable_super_globals to false and delete the cache</p></blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/04/21/illegal-use-of-_server-you-must-use-the-request-class-or-request_var-to-access-input-data-phpbb/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Get color_id from a Google Calendar using API [PHP]</title>
		<link>https://blog.kodono.info/wordpress/2016/04/18/get-color_id-from-a-google-calendar-using-api-php/</link>
					<comments>https://blog.kodono.info/wordpress/2016/04/18/get-color_id-from-a-google-calendar-using-api-php/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Mon, 18 Apr 2016 07:50:13 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[Web Design]]></category>
		<category><![CDATA[english]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://blog.kodono.info/wordpress/?p=1637</guid>

					<description><![CDATA[For a project I needed to get the events from a Google Calendar, as well as the colors from it. It&#8217;s been a pain, but after a couple of days I&#8217;ve been able to create a PHP page to do so. It will use the server-to-server auth mechanism. I&#8217;ll try to provide the different steps [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>For a project I needed to get the events from a Google Calendar, as well as the colors from it.</p>
<p>It&#8217;s been a pain, but after a couple of days I&#8217;ve been able to create a PHP page to do so. It will use the <a href="http://www.riskcompletefailure.com/2015/03/understanding-service-accounts.html">server-to-server auth mechanism</a>.</p>
<p>I&#8217;ll try to provide the different steps (please note that my Google Console is in French so I tried to translate) :</p>
<ol>
<li>Go to <a href="https://console.developers.google.com/apis/api/calendar/overview">https://console.developers.google.com/apis/api/calendar/overview</a> and <strong>Activate the Calendar API</strong> (or create first a project if required)</li>
<li>Once the API is activated you should be invited to go to the Identification part ; make sure you choose <strong>&#8220;Account Service Key&#8221;</strong> for the identification mode</li>
<li>Then pick <strong>&#8220;New Service&#8221;</strong> and complete the fields (choose JSON for the file format)</li>
<li>Download the JSON file and save it where your PHP file will stand on your web server</li>
<li>Open the JSON file and search for the <strong>client_email</strong></li>
<li>Go to <a href="https://calendar.google.com/">https://calendar.google.com/</a> and in the sharing parameters : make sure that you share your calendar in editing with the <strong>client_email</strong> address found in the previous step (the editing mode is required to get the Colors)</li>
<li>Now you need to install the <a href="https://developers.google.com/api-client-library/php/start/installation">PHP library from Google</a> &#8230; in my case I don&#8217;t have a console access on the server, so I transfered the files from Github to the web server, in the same directory as our PHP file will be (so I got a folder called <em>google-api-php-client-1.1.7</em>)</li>
<li>Create your PHP file with the below content :
<pre class="brush:php">
&lt;?php
// make sure the include path got the Google API (please refer to https://developers.google.com/api-client-library/php/start/installation)
set_include_path(get_include_path() . PATH_SEPARATOR . '/full/path/WordPress/wp-content/agenda/google-api-php-client-1.1.7/src/Google');
require_once "autoload.php";

// Connect to the Google Calendar Service
$client = new Google_Client();
$client->setApplicationName("Google Calendar");
$data = json_decode(file_get_contents('YourKeyFile-xxxxx.json'));
$client_id = $data->client_id;
$client_email = $data->client_email;
$cred = new Google_Auth_AssertionCredentials(
  $client_email,
  array(Google_Service_Calendar::CALENDAR),
  $data->private_key
);

// Remember to cache the access token locally if making multiple calls
// and don't just use this function for each request!
$client->getAuth()->refreshTokenWithAssertion($cred);
$service = new Google_Service_Calendar($client);
$optParams = array(
  "calendarId"   => "TheGoogleAccountForTheCalendar@gmail.com",
  "singleEvents" => true,
  "timeZone"     => "Europe/Paris",
  "maxResults"   => 250,
  "timeMin"      => date("c", strtotime("midnight")), /* to get events from today... */
  "timeMax"      => date("c",strtotime('+3 day')), /* ...to the 3 next days */
  "orderBy"      => "startTime"
);
$events = $service->events->listEvents('TheGoogleAccountForTheCalendar@gmail.com', $optParams);
?>
&lt;!DOCTYPE html>
&lt;html>
  &lt;head>
    &lt;meta charset="UTF-8">
    &lt;meta http-equiv="Content-Language" content="fr" />
    &lt;meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
  &lt;/head>
  &lt;body>
&lt;?php
  while(true) {
    foreach ($events->getItems() as $event) {
      $endTime = new DateTime($event->getEnd()->getDateTime());
      echo $event->getSummary() ." [".$event->getColorId()."] (".$endTime->format('Y-m-d').")&lt;br>";
    }
    $pageToken = $events->getNextPageToken();
    if ($pageToken) {
      $optParams['pageToken'] = $pageToken;
      $events = $service->events->listEvents('lgpmontpellier@gmail.com', $optParams);
    } else {
      break;
    }
  }
?>
  &lt;/body>
&lt;/html>
</pre>
<p>Finally you can refer to the <a href="https://developers.google.com/google-apps/calendar/?csw=1">Google Calendar API</a>.</p>
<p>FYI I retrieved the below colorId for the below available colors:<br />
<img loading="lazy" decoding="async" src="https://blog.kodono.info/wordpress/wp-content/uploads/2016/04/colors_google_calendar.png" alt="" width="288" height="41" class="aligncenter size-full wp-image-1685" /></p>
<pre class="brush:php">
    // same order as the image above
    switch ($event->getColorId()) {
      case 9: $color="#5484ED"; break;
      case 1: $color="#A4BDFC"; break;
      case 7: $color="#46D6DB"; break;
      case 2: $color="#7AE7BF"; break;
      case 10: $color="#51B749"; break;
      case 5: $color="#FBD75B"; break;
      case 6: $color="#FFB878"; break;
      case 4: $color="#FF887C"; break;
      case 11: $color="#DC2127"; break;
      case 3: $color="#DBADFF"; break;
      case 8: $color="#E1E1E1"; break;
      default: $color="#AC725E"; // the first one in the picture, the one that is checked
    }
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/04/18/get-color_id-from-a-google-calendar-using-api-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Play with ribbon on Sharepoint</title>
		<link>https://blog.kodono.info/wordpress/2016/03/17/play-with-ribbon-on-sharepoint/</link>
					<comments>https://blog.kodono.info/wordpress/2016/03/17/play-with-ribbon-on-sharepoint/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Thu, 17 Mar 2016 15:49:50 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Programmation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[sharepoint]]></category>
		<guid isPermaLink="false">http://blog.kodono.info/wordpress/?p=1604</guid>

					<description><![CDATA[In Sharepoint 2010 and 2013, there are some existing functions to deal with the ribbon. Below an example of what we can do: // we need the file "sp.ribbon.js" SP.SOD.executeOrDelayUntilScriptLoaded(function () { // use PageManager var pm = SP.Ribbon.PageManager.get_instance(); // define a function to call when the ribbon is loaded var DoSomethingWithRibbon=function(ribbon) { // For [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In Sharepoint 2010 and 2013, there are some existing functions to deal with the ribbon.</p>
<p>Below an example of what we can do:</p>
<pre class="brush:javascript">
// we need the file "sp.ribbon.js"
SP.SOD.executeOrDelayUntilScriptLoaded(function () {
  // use PageManager
  var pm = SP.Ribbon.PageManager.get_instance();

  // define a function to call when the ribbon is loaded
  var DoSomethingWithRibbon=function(ribbon) {
    // For example, we can select the "Browse" tab
    ribbon.selectTabById("Ribbon.ListForm.Display", true);
    // Note: You can explore the DOM to find the related IDs
    // other example "Edit" tab is "Ribbon.ListForm.Edit"
  
    // We can now remove the "Edit" tab
    ribbon.removeChild("Ribbon.ListForm.Edit");
  }

  // perform an action when the ribbon has been inited
  pm.add_ribbonInited(function () {
    DoSomethingWithRibbon(pm.get_ribbon())
  });

  // if the ribbon is already loaded
  var ribbon = null;
  try {
    // get an instance of the ribbon
    ribbon = pm.get_ribbon();
  } catch (e) {}
  if (!ribbon) {
    if (typeof(_ribbonStartInit) == "function")
      _ribbonStartInit(_ribbon.initialTabId, false, null);
  } else {
    DoSomethingWithRibbon(ribbon);
  }

}, "sp.ribbon.js");
</pre>
<p>And there are also solutions to add stuff to the ribbon. I have to dig into these solutions&#8230; In the meantime you can try <a href="https://dbremes.wordpress.com/2011/01/16/theres-a-javascript-api-for-creating-ribbons/">this blog post</a>, or <a href="http://www.umtsoftware.com/blog/creating-sharepoint-ribbon-elements-in-javascript/">this one</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/03/17/play-with-ribbon-on-sharepoint/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to change the default logon name on Windows 7</title>
		<link>https://blog.kodono.info/wordpress/2016/01/06/how-to-change-the-default-logon-name-on-windows-7/</link>
					<comments>https://blog.kodono.info/wordpress/2016/01/06/how-to-change-the-default-logon-name-on-windows-7/#respond</comments>
		
		<dc:creator><![CDATA[Aymeric]]></dc:creator>
		<pubDate>Wed, 06 Jan 2016 08:51:25 +0000</pubDate>
				<category><![CDATA[Astuce]]></category>
		<category><![CDATA[Niveau intermédiaire]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">http://blog.kodono.info/wordpress/?p=1595</guid>

					<description><![CDATA[On a remote PC it was another logon name that appeared by default&#8230; In that case I had to click on &#8220;Switch User&#8221;, then &#8220;Other User&#8221;, and finally enter my username and password. Very frustrating. After a few searches I found we can change the default name using the registry and with the below commands [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>On a remote PC it was another logon name that appeared by default&#8230; In that case I had to click on &#8220;Switch User&#8221;, then &#8220;Other User&#8221;, and finally enter my username and password. Very frustrating.</p>
<p>After a few searches <a href="http://answers.microsoft.com/en-us/windows/forum/windows_7-security/set-default-username-how-to/fea276d1-9845-41c8-9621-50f1738500c7?db=5&#038;auth=1">I found</a> we can change the default name using the registry and with the below commands (to enter into a <code>cmd</code> console in admin mode) :<br />
<code>call reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI" /v LastLoggedOnSAMUser /t REG_SZ /d "The_Default_Domain\The_Default_Username" /f<br />
call reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI" /v LastLoggedOnUser /t REG_SZ /d "The_Default_Domain\The_Default_Username" /f </code></p>
<p>Log off and <code>The_Default_Domain\The_Default_Username</code> should prompt!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.kodono.info/wordpress/2016/01/06/how-to-change-the-default-logon-name-on-windows-7/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
