Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://weblogs.asp.net/soever/rss.aspx

  1. <?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Serge van den Oever [Macaw]</title><link>https://weblogs.asp.net:443/soever/</link><description>SharePoint RIP. Azure, Node.js, hybrid mobile apps</description><item><title>sitecore - one click publish for web projects</title><link>https://weblogs.asp.net:443/soever/sitecore-one-click-publish-for-web-projects</link><description>&lt;p&gt;With the Helix application structure of sitecore projects there are a lot of web projects. If you follow the Habitat tooling there is a set of convenient gulp tasks for publishing changes like the "do it all" &lt;code&gt;gulp default&lt;/code&gt; task. In most cases publishing the web project you made your changes in is enough. In most cases this is a feature or foundation project. You can do this by right-clicking on the web project, select&amp;nbsp;&lt;strong&gt;Publish...&lt;/strong&gt;, and press the&amp;nbsp;&lt;strong&gt;Publish&lt;/strong&gt; button in the resulting screen. A faster way is to enable the &lt;strong&gt;Views &amp;gt; Toolbars &amp;gt; Web One Click Publish&lt;/strong&gt; option so you get a button on your toolbar for fast publication.&lt;/p&gt;
  2. </description><pubDate>Thu, 08 Jun 2017 13:25:37 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/sitecore-one-click-publish-for-web-projects</guid><category>sitecore</category><category>helix</category><category>habitat</category></item><item><title>sitecore Helix - pdf, epub, mobi</title><link>https://weblogs.asp.net:443/soever/sitecore-helix-pdf-epub-mobi</link><description>&lt;p&gt;Sitecore Helix documentation is available at http://helix.sitecore.net. But if you want the documentation as PDF, epub or mobi file you can download them at &lt;a href="https://chorpoblog.wordpress.com/2017/03/19/sitecore-helix-documentation-1-1/"&gt;https://chorpoblog.wordpress.com/2017/03/19/sitecore-helix-documentation-1-1/&lt;/a&gt;&amp;nbsp;thanks to the great work of Peter Prochazka.&lt;/p&gt;
  3. </description><pubDate>Tue, 06 Jun 2017 12:16:14 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/sitecore-helix-pdf-epub-mobi</guid><category>sitecore</category><category>helix</category></item><item><title>sitecore Habitat - TypeError: Cannot read property '0' of undefined</title><link>https://weblogs.asp.net:443/soever/sitecore-habitat-typeerror-cannot-read-property-0-of-undefined</link><description>&lt;p&gt;When you get the error&amp;nbsp;&lt;strong&gt;TypeError: Cannot read property '0' of undefined&lt;/strong&gt; in the Gulp task&amp;nbsp;'05-Sync-Unicorn' you probably&amp;nbsp;don't have a&amp;nbsp;&lt;strong&gt;SharedSecret&lt;/strong&gt; configured in the file&amp;nbsp;&lt;strong&gt;C:\Projects\Habitat\src\Project\Habitat\code\App_Config\Include\Unicorn\Unicorn.UI.config&lt;/strong&gt;.&lt;/p&gt;
  4. &lt;p&gt;In my project the&amp;nbsp;&lt;strong&gt;SharedSecret&lt;/strong&gt; wat commented out, i.e.:&lt;/p&gt;
  5. &lt;p&gt;&lt;code&gt;&amp;lt;!--&amp;lt;SharedSecret&amp;gt;&amp;lt;/SharedSecret&amp;gt; Uncomment this line and provide a strong randomized shared secret here. At least 64 characters is recommended, for example https://www.grc.com/passwords.htm --&amp;gt;&lt;/code&gt;&lt;/p&gt;
  6. &lt;p&gt;I followed the instructions, uncommented it, grabbed a 64 characters password from&amp;nbsp;&lt;a href=" https://www.grc.com/passwords.htm" target="_blank"&gt; https://www.grc.com/passwords.htm&lt;/a&gt;&amp;nbsp;so my line read:&lt;/p&gt;
  7. &lt;p&gt;&lt;code&gt;&amp;lt;SharedSecret&amp;gt;06A3203AA36C84D499D9BF6F79852B61EF2992465C2160FE09263E1AB5B882E2&amp;lt;/SharedSecret&amp;gt;&lt;/code&gt;&lt;/p&gt;
  8. &lt;p&gt;I did run &lt;code&gt;gulp 05-Sync-Unicorn&lt;/code&gt; again, but still the same error.&amp;nbsp;&lt;/p&gt;
  9. &lt;p&gt;After adding a line to the script C:\Projects\Habitat\scripts\unicorn.js:&lt;/p&gt;
  10. &lt;div&gt;
  11. &lt;div&gt;&lt;span&gt; &lt;/span&gt;&lt;strong&gt;&lt;code&gt;console.log("Reading Unicorn configuration file " + unicornConfigFile);&lt;/code&gt;&lt;/strong&gt;&lt;/div&gt;
  12. &lt;div&gt;&lt;code&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readFileSync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unicornConfigFile&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
  13. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  14. &lt;div&gt;&lt;span&gt;I saw my problem:&lt;/span&gt;&lt;/div&gt;
  15. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  16. &lt;div&gt;&lt;span&gt;The script is reading from the deployed website location (&amp;nbsp;C:\websites\Habitat.dev.local\Website/App_config/Include/Unicorn/Unicorn.UI.config), not the project location (C:\Projects\Habitat\src\Project\Habitat\code\App_Config\Include\Unicorn\Unicorn.UI.config).&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
  17. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  18. &lt;div&gt;&lt;span&gt;I could run the complete &lt;code&gt;gulp default&lt;/code&gt; task again, but doing a &lt;strong&gt;Publish...&lt;/strong&gt; on the &lt;strong&gt;Sitecore.Habitat.Website&lt;/strong&gt; project (right-click on the project) does the job much quicker.&lt;/span&gt;&lt;/div&gt;
  19. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  20. &lt;div&gt;&lt;span&gt;After publishing, re-execute step 5 again:&amp;nbsp;gulp 05-Sync-Unicorn&lt;/span&gt;&lt;/div&gt;
  21. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  22. &lt;div&gt;&lt;span&gt;&lt;span&gt;Hint for the sitecore team: reading a configuration setting using the line:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
  23. &lt;div&gt;
  24. &lt;div&gt;
  25. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  26. &lt;div&gt;&lt;code&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;configuration&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sitecore&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].&lt;/span&gt;&lt;span&gt;unicorn&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].&lt;/span&gt;&lt;span&gt;authenticationProvider&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].&lt;/span&gt;&lt;span&gt;SharedSecret&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
  27. &lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
  28. &lt;div&gt;&lt;span&gt;from a configuration file where this setting is commented out will lead to issues that take people a lot of time to find out, especially because I couldn't find anything on this on the &lt;a href="https://github.com/Sitecore/Habitat/wiki" target="_blank"&gt;Wiki documentation&lt;/a&gt;&amp;nbsp;of the Habitat project.&lt;/span&gt;&lt;/div&gt;
  29. &lt;/div&gt;
  30. &lt;/div&gt;
  31. &lt;/div&gt;
  32. </description><pubDate>Mon, 05 Jun 2017 10:55:39 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/sitecore-habitat-typeerror-cannot-read-property-0-of-undefined</guid><category>sitecore</category><category>habitat</category></item><item><title>sitecore SIM - backup installation as restore point</title><link>https://weblogs.asp.net:443/soever/sitecore-sim-backup-installation-as-restore-point</link><description>&lt;p&gt;After doing a fresh install of a sitecore site through the &lt;a href="https://github.com/Sitecore/Sitecore-Instance-Manager" target="_blank"&gt;sitecore instance manager&lt;/a&gt;&amp;nbsp;(SIM) including packages like &lt;a href="https://marketplace.sitecore.net/en/Modules/Sitecore_PowerShell_console.aspx" target="_blank"&gt;Sitecore PowerShell Extensions&lt;/a&gt;&amp;nbsp;and other stuff you want to have installed you can make a backup (right-click on your site &amp;gt; Backup) as a fresh restore point in case things get terribly wrong.&amp;nbsp;&lt;/p&gt;
  33. &lt;p&gt;Note that the backups are made in the folder&amp;nbsp;C:\websites\&lt;em&gt;mysite.dev.local&lt;/em&gt;\Backups.&lt;/p&gt;
  34. &lt;p&gt;&lt;/p&gt;
  35. &lt;p&gt;Install the latest version of SIM from &lt;a href="http://dl.sitecore.net/updater/sim/" target="_blank"&gt;http://dl.sitecore.net/updater/sim/&lt;/a&gt;.&lt;/p&gt;
  36. </description><pubDate>Fri, 02 Jun 2017 14:22:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/sitecore-sim-backup-installation-as-restore-point</guid><category>sitecore</category><category>SIM</category></item><item><title>sitecore SIM - succesful install but no databases</title><link>https://weblogs.asp.net:443/soever/sitecore-sim-succesful-install-but-no-databases</link><description>&lt;p&gt;I was busy with an installation of sitecore through the &lt;a href="https://github.com/Sitecore/Sitecore-Instance-Manager" target="_blank"&gt;sitecore instance manager&lt;/a&gt;&amp;nbsp;(SIM), asnd everything seemed to be ok, but I had no databases.&lt;/p&gt;
  37. &lt;p&gt;I gave Network Service read/write access on my c:\websites folder, but when I looked the SIM logs (Home &amp;gt; Bundled tools &amp;gt; SIM logs) I saw the error:&lt;/p&gt;
  38. &lt;p&gt;System.Data.SqlClient.SqlException (0x80131904): Unable to open the physical file "C:\websites\mysite.dev.local\Databases\Sitecore.core.mdf". Operating system error 5: "5(Access denied.)".&lt;/p&gt;
  39. &lt;p&gt;When I gave Network Service full control on the folder c:\websites it worked.&lt;/p&gt;
  40. &lt;p&gt;&lt;span&gt;Install the latest version of SIM from&amp;nbsp;&lt;a href="http://dl.sitecore.net/updater/sim/" target="_blank"&gt;http://dl.sitecore.net/updater/sim/&lt;/a&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
  41. </description><pubDate>Fri, 02 Jun 2017 14:03:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/sitecore-sim-succesful-install-but-no-databases</guid><category>sitecore</category><category>SIM</category></item><item><title>Wappalyzer + PageXray Chrome plugins combined change PUT to GET</title><link>https://weblogs.asp.net:443/soever/wappalyzer-pagexray-chrome-plugins-combined-change-put-to-get</link><description>&lt;p&gt;I installed at home two Chrome plugins on my Mac to analyze technology used on websites: Wappalyzer and PageXray. When I got on my work this morning and turned on my Windows PC &amp;nbsp;I started using the application we are developing, but it behaved weird. After a lot of debugging I found that an Ajax PUT request was changed into a GET request! Then I remembered that I installed some plugins at home, and that on startup of Chrome these plugins were installed at work as well! When I disable one of the plugins it started working again as expected. So beware of this deadly combination!!&lt;/p&gt;
  42. </description><pubDate>Fri, 21 Apr 2017 09:46:25 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/wappalyzer-pagexray-chrome-plugins-combined-change-put-to-get</guid></item><item><title>Zipkin with docker startup script</title><link>https://weblogs.asp.net:443/soever/zipkin-with-docker-startup-script</link><description>&lt;p&gt;In a project we use &lt;a href="http://zipkin.io/" target="_blank"&gt;http://zipkin.io/&lt;/a&gt;&amp;nbsp;for distributed tracing. During development is is very handy to trace to Zipkin running in a Docker image. The following PowerShell script will help with (re)starting the Docker image on WIndows and open Zipkin in Chrome when it is running.&lt;/p&gt;
  43. &lt;p&gt;&lt;code&gt;$runningZipkin = &amp;amp; docker ps -q --filter ancestor=openzipkin/zipkin&lt;/code&gt;&lt;br /&gt;&lt;code&gt;if ($runningZipkin) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt; "Running Zipkin with id $runningZipkin - will be killed"&lt;/code&gt;&lt;br /&gt;&lt;code&gt; &amp;amp; docker stop $runningZipkin&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;br /&gt;&lt;code&gt;"Starting Zipkin docker image"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;amp; docker run -d -p 9411:9411 openzipkin/zipkin&lt;/code&gt;&lt;/p&gt;
  44. &lt;p&gt;&lt;code&gt;$ErrorActionPreference = "SilentlyContinue" # We don't want to see failing requests&lt;/code&gt;&lt;br /&gt;&lt;code&gt;do {&lt;/code&gt;&lt;br /&gt;&lt;code&gt; Start-Sleep -Seconds 1&lt;/code&gt;&lt;br /&gt;&lt;code&gt; "Waiting for starting of Zipkin..."&lt;/code&gt;&lt;br /&gt;&lt;code&gt; $up = Invoke-WebRequest -Uri http://localhost:9411&lt;/code&gt;&lt;br /&gt;&lt;code&gt;} while (!$up)&lt;/code&gt;&lt;/p&gt;
  45. &lt;p&gt;&lt;code&gt;&amp;amp; "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" http://localhost:9411&lt;/code&gt;&lt;/p&gt;
  46. </description><pubDate>Mon, 10 Apr 2017 15:17:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/zipkin-with-docker-startup-script</guid></item><item><title>SPA Series: Turn our ShowTitle app into a Progressive Web App</title><link>https://weblogs.asp.net:443/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app</link><description>&lt;p&gt;In this post we turn our great web app into a Progressive Web App (PWA). "&lt;span&gt;A progressive web app provides an app-like user experience that is low friction and is built using modern web capabilities and hosted on the web and can become an app on the user's system over time."&amp;nbsp;&lt;/span&gt;To learn more about the great promises of Progressive Web Apps read Addy Osmani's great overview article&amp;nbsp;&lt;a href="https://addyosmani.com/blog/getting-started-with-progressive-web-apps/" target="_blank"&gt;Getting started with Progressive Web Apps&lt;/a&gt;. Google also has a great entry point to the required information at&amp;nbsp;&lt;a href="https://developers.google.com/web/progressive-web-apps/"&gt;https://developers.google.com/web/progressive-web-apps/&lt;/a&gt;.&lt;/p&gt;
  47. &lt;h3&gt;Getting up to speed with Progressive Web Apps&lt;/h3&gt;
  48. &lt;p&gt;Progressive Web Apps are cool, and in my opinion the future of a whole category of mobile apps. An inspiring introduction to this vision is &lt;a href="https://youtu.be/MSldc28Hvp0" target="_blank"&gt;this presentation by Bruce Lawson&lt;/a&gt;. See also&amp;nbsp;&lt;a href="https://dev.opera.com/blog/pwa-taipei/"&gt;https://dev.opera.com/blog/pwa-taipei/&lt;/a&gt;. For a great overview of other material available on Progressive Web Apps have a look at&amp;nbsp;&lt;a href="https://github.com/hemanth/awesome-pwa"&gt;https://github.com/hemanth/awesome-pwa&lt;/a&gt;.&lt;/p&gt;
  49. &lt;h3&gt;What do I want to achieve in this blog post&lt;/h3&gt;
  50. &lt;p&gt;In this article we explore how to get the following functionality working in our PWA:&lt;/p&gt;
  51. &lt;ul&gt;
  52. &lt;li&gt;&lt;strong&gt;Hosting in a SharePoint document library&lt;/strong&gt; - for authentication, access to data within your company, and freedom of distribution&lt;/li&gt;
  53. &lt;li&gt;&lt;strong&gt;Add to homescreen&lt;/strong&gt; - so we get an icon between the other apps on your mobile device or between the apps in your browser&lt;/li&gt;
  54. &lt;li&gt;&lt;strong&gt;Splash screen&lt;/strong&gt; - for direct visual feedback on start of our application&lt;/li&gt;
  55. &lt;li&gt;&lt;strong&gt;Offline support&lt;/strong&gt; - so we can use our app even if we are not connected to the network&lt;/li&gt;
  56. &lt;/ul&gt;
  57. &lt;p&gt;The code for our sample Progressive Web App can be found at &lt;a href="https://github.com/svdoever/sharepoint-progressive-web-apps/tree/master/ShowTitleProgressiveWebApp" target="_blank"&gt;https://github.com/svdoever/sharepoint-progressive-web-apps/tree/master/ShowTitleProgressiveWebApp&lt;/a&gt;.&lt;/p&gt;
  58. &lt;h3&gt;Generating artifacts&lt;/h3&gt;
  59. &lt;p&gt;For the PWA we need things like a favicon, icons for the different (mobile) platforms, html code to include these icons, and configuration directives for platforms to provide us with PWA functionality. The site&amp;nbsp;&lt;a href="http://realfavicongenerator.net/%20" target="_blank" title="http://realfavicongenerator.net/ "&gt;http://realfavicongenerator.net/&amp;nbsp;&lt;/a&gt;can help us out with some of these steps. It generates a zip file with icons and other artifacts based on a single uploaded icon. Because we are creating the amazing "Show Title" app that shows the title of SharePoint site hosting our app, I downloaded an &lt;a href="http://www.clipartpanda.com/clipart_images/nycs-bull-trans-t-clip-art-29088807" target="_blank"&gt;icon&lt;/a&gt;&amp;nbsp;of the letter &lt;strong&gt;T&amp;nbsp;&lt;/strong&gt;and used that for the generation. The generator created a zip file with artifacts and the following HTML lines for inclusion in the head of our app page:&lt;/p&gt;
  60. &lt;p&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="manifest" href="/manifest.json"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;meta name="theme-color" content="#ffffff"&amp;gt;&lt;/code&gt;&lt;/p&gt;
  61. &lt;p&gt;&lt;span class="tag"&gt;Because we are hosting in a subfolder of a SharePoint document library and not in the root of a website we need to remove the leading slashes as in:&lt;/span&gt;&lt;/p&gt;
  62. &lt;p&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="manifest" href="manifest.json"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="mask-icon" href="safari-pinned-tab.svg" color="#5bbad5"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;meta name="theme-color" content="#ffffff"&amp;gt;&lt;/code&gt;&lt;/p&gt;
  63. &lt;p&gt;Besides a set of icons it generated a &lt;a href="https://msdn.microsoft.com/en-us/library/dn320426" target="_blank"&gt;browserconfig.xml&lt;/a&gt;&amp;nbsp;file for Internet Explorer with the following contents (leading slashes removed):&lt;/p&gt;
  64. &lt;p&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;browserconfig&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;lt;msapplication&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;lt;tile&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;square70x70logo src="mstile-70x70.png"/&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;square150x150logo src="mstile-150x150.png"/&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;square310x310logo src="mstile-310x310.png"/&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;wide310x150logo src="mstile-310x150.png"/&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;TileColor&amp;gt;#da532c&amp;lt;/TileColor&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;lt;/tile&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;lt;/msapplication&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;/browserconfig&amp;gt;&lt;/code&gt;&lt;/p&gt;
  65. &lt;h3&gt;The web manifest file&lt;/h3&gt;
  66. &lt;p&gt;Now we need to add a manifest&amp;nbsp;file that drives our Progressive Web App. The specifications for the app manifest can be found at &lt;a href="https://www.w3.org/TR/appmanifest/" target="_blank"&gt;https://www.w3.org/TR/appmanifest/&lt;/a&gt;, but a better readable reference can be found at&amp;nbsp;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" target="_blank"&gt;https://developer.mozilla.org/en-US/docs/Web/Manifest&lt;/a&gt;. In most examples, and in the generated zip file by the generator, the manifest file is named&amp;nbsp;&lt;strong&gt;manifest.json&lt;/strong&gt;. When hosting in SharePoint files ending in&amp;nbsp;&lt;strong&gt;.json&lt;/strong&gt; are not allowed. We will rename the file to&amp;nbsp;&lt;strong&gt;manifest.webmanifest&lt;/strong&gt;.&lt;/p&gt;
  67. &lt;p&gt;I made some small changes to the generated manifest, like adding a &lt;strong&gt;short_name&lt;/strong&gt; and &lt;strong&gt;description &lt;/strong&gt;and&amp;nbsp;&lt;strong&gt;background_color&lt;/strong&gt;&amp;nbsp;(used as background color for the splash screen), and I added 128x128 and 144x144 version of the icon (I resized the 256x256 icon using a paint program) as that seems to be required by Firefox (128x128) and for the splash screen support (144x144). The &lt;strong&gt;start_url&lt;/strong&gt;&amp;nbsp;we set to index.html?home=true so that when we add the app to homescreen&amp;nbsp;we can identify that it is an app lounched from the homescreen.&lt;/p&gt;
  68. &lt;p&gt;The manifest file &lt;strong&gt;manifest.webmanifest&lt;/strong&gt;:&lt;/p&gt;
  69. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleProgressiveWebApp/static/manifest.webmanifest"&gt;&lt;/script&gt;
  70. &lt;p&gt;End of file &lt;strong&gt;manifest.webmanifest&lt;/strong&gt;.&lt;/p&gt;
  71. &lt;p&gt;If we look into the descriptions about add to homescreen requirements (&lt;a href="https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/" target="_blank"&gt;https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/&lt;/a&gt;) we find that the site:&lt;/p&gt;
  72. &lt;ul&gt;
  73. &lt;li&gt;Has a &lt;a href="https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/" target="_blank"&gt;web app manifest&lt;/a&gt; file with:
  74. &lt;ul&gt;
  75. &lt;li&gt;a &lt;code&gt;short_name&lt;/code&gt; (used on the home screen)&lt;/li&gt;
  76. &lt;li&gt;a &lt;code&gt;name&lt;/code&gt; (used in the banner when showing the splash screen)&lt;/li&gt;
  77. &lt;li&gt;a 144x144 png icon used on the splash screen, (the icon declarations must include a mime type of &lt;code&gt;image/png&lt;/code&gt;)&lt;/li&gt;
  78. &lt;li&gt;a &lt;code&gt;start_url&lt;/code&gt; that loads&lt;/li&gt;
  79. &lt;/ul&gt;
  80. &lt;/li&gt;
  81. &lt;li&gt;Has a &lt;a href="https://developers.google.com/web/fundamentals/getting-started/primers/service-workers" target="_blank"&gt;service worker&lt;/a&gt; registered on your site (service worker may be empty)&lt;/li&gt;
  82. &lt;li&gt;Is served over HTTPS (a requirement for using service worker).&lt;/li&gt;
  83. &lt;li&gt;Is visited at least twice, with at least five minutes between visits.&lt;/li&gt;
  84. &lt;/ul&gt;
  85. &lt;h3&gt;The app page index.html&lt;/h3&gt;
  86. &lt;p&gt;In the&amp;nbsp;&lt;strong&gt;index.html&lt;/strong&gt; file we see the registration of the service worker. Besides the service worker registration there is one really important thing: the link to the web manifest. When specifying the link to the manifest file as found in all examples as&amp;nbsp;&lt;code&gt;&amp;lt;link rel="manifest" href="manifest.webmanifest"&amp;gt;&lt;/code&gt; it works perfectly locally, but does not work when deployed to SharePoint because authentication headers are not passed through on requesting the manifest. I tried everything. Providing the manifest content from a page&amp;nbsp;&lt;strong&gt;manifest.aspx&lt;/strong&gt; so I could set the correct content type (made no difference). Embedding the manifest as base64 in the href on the link (seems not supported on Chrome, see&amp;nbsp;&lt;a href="https://github.com/w3c/manifest/issues/534" target="_blank"&gt;https://github.com/w3c/manifest/issues/534&lt;/a&gt;). The answer came on a question I posted on&amp;nbsp;&lt;a href="https://github.com/w3c/manifest/issues/535:" target="_blank"&gt;https://github.com/w3c/manifest/issues/535:&lt;/a&gt;&amp;nbsp;we need to use the attribute&amp;nbsp;&lt;strong&gt;&lt;span&gt;crossOrigin="use-credentials"&lt;/span&gt;&lt;/strong&gt;, now the authentication headers are passed as required. So the manifest should be referenced as: &lt;code&gt;&amp;lt;link rel="manifest" href="manifest.webmanifest" crossOrigin="use-credentials"&amp;gt;&lt;/code&gt;. I think this is a bug, because on access of resources on the same origin&amp;nbsp;the security context&amp;nbsp;should be inherited (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" target="_blank"&gt;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&lt;/a&gt;).&lt;/p&gt;
  87. &lt;p&gt;The file &lt;strong&gt;index.html&lt;/strong&gt;:&lt;/p&gt;
  88. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleProgressiveWebApp/static/index.html"&gt;&lt;/script&gt;
  89. &lt;p&gt;End of file &lt;strong&gt;index.html&lt;/strong&gt;.&lt;/p&gt;
  90. &lt;h3&gt;Testing the app from a browser and from a device&lt;/h3&gt;
  91. &lt;p&gt;During development we use the &lt;a href="https://github.com/koltyakov/sp-rest-proxy" target="_blank"&gt;sp-rest-proxy&lt;/a&gt;&amp;nbsp;and can access the site on &lt;a href="http://localhost:8081" target="_blank"&gt;http://localhost:8081&lt;/a&gt;. We can now test the app from for example Chrome. Testing the app in Chrome is interesting because Chrome has support for web app manifests in the developer tools on the application tab. From this tab it is possible to see if the manifest is correctly parsed and we can test the Add to homescreen functionality:&lt;/p&gt;
  92. &lt;p&gt;&lt;img width="1708" height="1652" alt="" src="https://aspblogs.blob.core.windows.net:443/media/soever/Media/Application%20manifest%20in%20Chrome.png" /&gt;&lt;/p&gt;
  93. &lt;p&gt;&lt;/p&gt;
  94. &lt;p&gt;But what if we want to test the app on another device like a mobile phone while developing on &lt;a href="http://localhost:8081?"&gt;http://localhost:8081?&lt;/a&gt;&amp;nbsp;&lt;a href="https://ngrok.com/" target="_blank"&gt;Ngrok&lt;/a&gt; to the rescue! Install ngrok on you system and run &lt;code&gt;ngrok http 8081&lt;/code&gt;.&lt;/p&gt;
  95. &lt;p&gt;&lt;img width="1334" height="840" alt="" src="https://aspblogs.blob.core.windows.net:443/media/soever/Media/ngrok-1.png" /&gt;&lt;/p&gt;
  96. &lt;p&gt;We now have an outside https endpoint to access our app. Now open&amp;nbsp;https://471e3571.ngrok.io/index.html&amp;nbsp;to open the app from another device like your mobile.&lt;/p&gt;
  97. &lt;h3&gt;Deploying to SharePoint&lt;/h3&gt;
  98. &lt;p&gt;Building on the SharePoint configuration described in the previous blog posts we can now deploy our app to SharePoint. The custom deployment script &lt;strong&gt;deploy.js&lt;/strong&gt; will work for our current situation.&lt;/p&gt;
  99. &lt;p&gt;The file &lt;strong&gt;deploy.js&lt;/strong&gt;:&lt;/p&gt;
  100. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleProgressiveWebApp/deploy.js"&gt;&lt;/script&gt;
  101. &lt;p&gt;End of file &lt;strong&gt;deploy.js&lt;/strong&gt;.&lt;/p&gt;
  102. &lt;p&gt;On deployment we rename the &lt;strong&gt;index.html&lt;/strong&gt; page to &lt;strong&gt;index.aspx&lt;/strong&gt;. But we also need to do rewrites on the&amp;nbsp;&lt;strong&gt;index.html&lt;/strong&gt; and&amp;nbsp;&lt;strong&gt;manifest.webmanifest&lt;/strong&gt; files.&lt;/p&gt;
  103. &lt;p&gt;Because we need to deploy more artifacta to SharePoint, the&amp;nbsp;&lt;strong&gt;deploy.js&lt;/strong&gt; command got an optional parameter. If you give no parameter only the&amp;nbsp;&lt;strong&gt;index.html&amp;nbsp;&lt;/strong&gt;and&amp;nbsp;&lt;strong&gt;manifest.webmanifest&lt;/strong&gt; files are deployed. If the parameter&amp;nbsp;&lt;strong&gt;assets&lt;/strong&gt; is given, also all other artifacts are deployed.&lt;/p&gt;
  104. &lt;p&gt;For deployment we no support the following npm commands:&lt;/p&gt;
  105. &lt;ul&gt;
  106. &lt;li&gt;&lt;strong&gt;npm start codedeploy&lt;/strong&gt; - only deploy the &lt;strong&gt;index.html&lt;/strong&gt; and &lt;strong&gt;manifest.webmanifest&lt;/strong&gt; files&lt;/li&gt;
  107. &lt;li&gt;&lt;strong&gt;npm start deploy&lt;/strong&gt; - deploy all files (makes the call &lt;b&gt;node deploy.js assets&lt;/b&gt;)&lt;/li&gt;
  108. &lt;/ul&gt;
  109. &lt;p&gt;When no offline support is required we can get away with an empty &lt;strong&gt;service-worker.js&lt;/strong&gt; file. When we want offline support we need to implement caching functionality like the first approach below. In this first approach I don't remove old caches, and when cached I don't load newer versions. Not even of /_api/ calls. When creating a new version of the app we can increase the version number of the cache to cache the latest versions again. For api call we need another strategy. For more information on caching strategies see Jake Archibalds blog post&amp;nbsp;&lt;a href="https://jakearchibald.com/2016/caching-best-practices/" target="_blank"&gt;https://jakearchibald.com/2016/caching-best-practices/&lt;/a&gt;. There is also agreat service workers cookbook at&amp;nbsp;&lt;a href="https://serviceworke.rs/" target="_blank"&gt;https://serviceworke.rs/&lt;/a&gt;&amp;nbsp;describing different caching strategies. In an upcoming blog post I will describe what I think would be the optimal caching strategy for SharePoint hosted apps and /_api service calls.&lt;/p&gt;
  110. &lt;p&gt;The file &lt;strong&gt;service-worker.js&lt;/strong&gt;:&lt;/p&gt;
  111. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleProgressiveWebApp/static/service-worker.js"&gt;&lt;/script&gt;
  112. &lt;p&gt;End of file &lt;strong&gt;service-worker.js&lt;/strong&gt;.&lt;/p&gt;
  113. &lt;h3&gt;Easy access to your SharePoint hosted PWA&lt;/h3&gt;
  114. &lt;p&gt;The links into SharePoint for your Progressive Web App can become quite large, and not easy to share with others. For easy access on devices I registered a short link &lt;a href="https://bit.ly/sptitle,"&gt;https://bit.ly/sptitle&lt;/a&gt;&amp;nbsp;to my app using the &lt;a href="https://bit.ly" target="_blank"&gt;https://bit.ly&lt;/a&gt;&amp;nbsp;shortening service.&lt;/p&gt;
  115. &lt;h3&gt;SharePoint SPA Series blog posts&lt;/h3&gt;
  116. &lt;ul&gt;
  117. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;SPA Series: Building full screen single page web applications on SharePoint&lt;/a&gt;&lt;/li&gt;
  118. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-sharepoint-rest-versus-sharepoint-csom" target="_blank"&gt;SPA Series: SharePoint REST versus SharePoint CSOM&lt;/a&gt;&lt;/li&gt;
  119. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data" target="_blank"&gt;SPA Series: Using sp-rest-proxy for local web development against real SharePoint data&lt;/a&gt;&lt;/li&gt;
  120. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app" target="_blank"&gt;SPA Series: Turn our ShowTitle app into a Progressive Web App&lt;/a&gt;&lt;/li&gt;
  121. &lt;/ul&gt;
  122. </description><pubDate>Sun, 11 Dec 2016 18:43:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app</guid><category>SPA-Series</category><category>SharePoint</category><category>SPA</category><category>PWA</category></item><item><title>SPA Series: Using sp-rest-proxy for local web development against real SharePoint data</title><link>https://weblogs.asp.net:443/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data</link><description>&lt;p&gt;A very interesting tool called&amp;nbsp;&lt;a href="https://github.com/koltyakov/sp-rest-proxy" target="_blank"&gt;sp-rest-proxy&lt;/a&gt;&amp;nbsp;enables us to do local web development against real SharePoint data. All REST api requests are proxied to the real SharePoint in the context of a configured site under the credentials of a configured username and password.&lt;/p&gt;
  123. &lt;p&gt;Install sp-rest-proxy using: &lt;code&gt;npm install sp-rest-proxy --save-dev&lt;/code&gt;. See&amp;nbsp;&lt;a href="https://github.com/koltyakov/sp-rest-proxy" target="_blank"&gt;sp-rest-proxy&lt;/a&gt;&amp;nbsp;for the documentation.&lt;/p&gt;
  124. &lt;p&gt;As described in the documentation create a file &lt;strong&gt;server.js&lt;/strong&gt; with the following contents:&lt;/p&gt;
  125. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleRestWithProxy/server.js"&gt;&lt;/script&gt;
  126. &lt;p&gt;Note that instead of using port 8080 as described in the documentation we used port 8081... with a reason: the sp-rest-proxy tool contains a UI to test our api REST requests, and that tool runs under port 8080.&lt;/p&gt;
  127. &lt;p&gt;The app under development lives in &lt;strong&gt;static/index.html&lt;/strong&gt;:&lt;/p&gt;
  128. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleRestWithProxy/static/index.html"&gt;&lt;/script&gt;
  129. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;/span&gt;&lt;strong&gt;static/index.html&lt;/strong&gt;.&lt;/p&gt;
  130. &lt;p&gt;The code is written in a way that it will work for local development and for hosting within a document library in SharePoint as described in&amp;nbsp;&lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;SPA Series: Building full screen single page web applications on SharePoint&lt;/a&gt;.&lt;/p&gt;
  131. &lt;p&gt;We also added a new and improved &lt;strong&gt;deploy.js&lt;/strong&gt; script:&lt;/p&gt;
  132. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleRestWithProxy/deploy.js"&gt;&lt;/script&gt;
  133. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;strong&gt;deploy.js&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
  134. &lt;p&gt;Note that the deploy script loads a configuration file from config/_private.conf.json which contains the site to deploy to and the credentials to use for deployment. This file is excluded from sourcecontrol (through .gitignore) because it contains personal settings, but the file (which is generated through a set of questions when starting the local website) contains something like:&lt;/p&gt;
  135. &lt;p style="padding-left: 30px;"&gt;&lt;code&gt;{&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; "siteUrl":"https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps",&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; "username":"serge@macaw.nl",&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; "password":"&amp;lt;my password&amp;gt;"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;/p&gt;
  136. &lt;p&gt;The password is encrypted on creation of the site, but a plain password works as well.&lt;/p&gt;
  137. &lt;p&gt;During the deployment two things are done:&lt;/p&gt;
  138. &lt;ol&gt;
  139. &lt;li&gt;the contents of the file static/index.html is loaded and all occurences of &lt;a href="http://localhost:8081"&gt;http://localhost:8081&lt;/a&gt;&amp;nbsp;are replaced with the url of the SharePoint site we will deploy to.&lt;/li&gt;
  140. &lt;li&gt;the contents of the file is uploaded in the document library &lt;strong&gt;apppages&lt;/strong&gt; in the folder &lt;strong&gt;showtitlerest&lt;/strong&gt; with the name i&lt;strong&gt;ndex.aspx&lt;/strong&gt;.&lt;/li&gt;
  141. &lt;/ol&gt;
  142. &lt;p&gt;We extend the npm &lt;strong&gt;package.json&lt;/strong&gt; script with some commands:&lt;/p&gt;
  143. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleRestWithProxy/deploy.js"&gt;&lt;/script&gt;
  144. &lt;p&gt;End&amp;nbsp;&lt;span&gt; of file&amp;nbsp;&lt;/span&gt;&lt;strong&gt;package.json&lt;/strong&gt;.&lt;/p&gt;
  145. &lt;p&gt;We can now execute the following commands:&lt;/p&gt;
  146. &lt;ol&gt;
  147. &lt;li&gt;&lt;code&gt;npm run serve&lt;/code&gt; - start a local website with our app on &lt;a href="http://localhost:8081/index.html"&gt;http://localhost:8081/index.html&lt;/a&gt;. On first run it asks for the url to the SharePoint site sp-rest-proxy makes a proxy for, a domain (leave empty for SharePoint Online), a username (in the format &lt;a href="mailto:name@mycompany.com"&gt;name@mycompany.com&lt;/a&gt;&amp;nbsp;for SharePoiint Online) and a password. Persist the configuration so the settings can be used by the deploy script as well.&lt;/li&gt;
  148. &lt;li&gt;&lt;code&gt;npm run api&lt;/code&gt; - start a test site at &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; that is part of sp-rest-proxy to test api requests.&lt;/li&gt;
  149. &lt;li&gt;&lt;code&gt;npm run deploy&lt;/code&gt; - deploy our app to the &lt;strong&gt;apppages&lt;/strong&gt; document library in a folder &lt;strong&gt;showtitlerest&lt;/strong&gt;. The app is available under the url &lt;a href="https://&amp;lt;yoursharepointsite&amp;gt;/apppages/showtitlerest/index.aspx"&gt;https://&amp;lt;yoursharepointsite&amp;gt;/apppages/showtitlerest/index.aspx&lt;/a&gt;. For me this url is&amp;nbsp;&lt;a href="https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages/showtitlerest/index.aspx"&gt;https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages/showtitlerest/index.aspx&lt;/a&gt;.&lt;/li&gt;
  150. &lt;/ol&gt;
  151. &lt;h3&gt;Conclusion&lt;/h3&gt;
  152. &lt;p&gt;this concludes this blog post. What did we accomplish:&lt;/p&gt;
  153. &lt;ul&gt;
  154. &lt;li&gt;We can do local web development against the content of a live SharePoint site. Api calls can be made through the url &lt;a href="http://localhost:8081/_api/.."&gt;http://localhost:8081/_api/..&lt;/a&gt;. On deployment this url is replaced by the correct site url we deploy to.&lt;/li&gt;
  155. &lt;li&gt;We can test api calls in a test page available on &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt;.&lt;/li&gt;
  156. &lt;li&gt;We can deploy our resulting app page to the SharePoint site.&lt;/li&gt;
  157. &lt;/ul&gt;
  158. &lt;p&gt;&lt;span&gt;The sample code can be found in the GitHub repository &lt;/span&gt;&lt;a href="https://github.com/svdoever/sharepoint-progressive-web-apps" target="_blank"&gt;https://github.com/svdoever/sharepoint-progressive-web-apps&lt;/a&gt;&lt;span&gt; in the folder &lt;/span&gt;&lt;strong&gt;ShowTitleRestWithProxy&lt;/strong&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
  159. &lt;h3&gt;SharePoint SPA Series blog posts&lt;/h3&gt;
  160. &lt;ul&gt;
  161. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;SPA Series: Building full screen single page web applications on SharePoint&lt;/a&gt;&lt;/li&gt;
  162. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-sharepoint-rest-versus-sharepoint-csom" target="_blank"&gt;SPA Series: SharePoint REST versus SharePoint CSOM&lt;/a&gt;&lt;/li&gt;
  163. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data" target="_blank"&gt;SPA Series: Using sp-rest-proxy for local web development against real SharePoint data&lt;/a&gt;&lt;/li&gt;
  164. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app" target="_blank"&gt;SPA Series: Turn our ShowTitle app into a Progressive Web App&lt;/a&gt;&lt;/li&gt;
  165. &lt;/ul&gt;
  166. </description><pubDate>Thu, 01 Dec 2016 22:38:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data</guid><category>SPA-Series</category><category>SharePoint</category><category>SPA</category><category>PWA</category></item><item><title>SPA Series: SharePoint REST versus SharePoint CSOM</title><link>https://weblogs.asp.net:443/soever/spa-series-sharepoint-rest-versus-sharepoint-csom</link><description>&lt;p&gt;Using REST to access data within SharePoint has advantages over&amp;nbsp;using CSOM, the Client-side SharePoint Object Model.&amp;nbsp;One important reason for me is a way smaller footprint in required libraries. For CSOM we need to use a bulky set of proprietary libraries provided by SharePoint. With REST we can use any library to do http requests. A good &lt;a href="http://www.andrewconnell.com/blog/sharepoint-2013-csom-vs.-rest-...-my-preference-and-why" target="_blank" title="SharePoint CSOM versus REST"&gt;must read blog post on SharePoint CSOM versus REST&lt;/a&gt;&amp;nbsp;is written by Andrew Connell, and he has a lot of good reasons in favor of&amp;nbsp;REST. Another reason is that with REST we can use&amp;nbsp;&lt;a href="https://github.com/koltyakov/sp-rest-proxy" target="_blank"&gt;sp-rest-proxy&lt;/a&gt;, but that will be the topic of the next blog post.&lt;/p&gt;
  167. &lt;p&gt;In the &lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;first post&lt;/a&gt;&amp;nbsp;of our SPA Series we described a simple web app that displayed the title of the hosting SharePoint site using CSOM.&lt;/p&gt;
  168. &lt;p&gt;The file &lt;strong&gt;index.aspx&lt;/strong&gt; using CSOM has the following content:&lt;/p&gt;
  169. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleCsom/index.aspx"&gt;&lt;/script&gt;
  170. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;/span&gt;&lt;strong&gt;index.aspx&lt;/strong&gt; using CSOM.&lt;/p&gt;
  171. &lt;p&gt;We can also use REST to display the title of the hosting SharePoint site. When using SharePoint REST almost all &lt;a href="https://msdn.microsoft.com/en-us/library/office/dn499819.aspx" target="_blank"&gt;examples&lt;/a&gt;&amp;nbsp;use the jQuery Ajax functions. I prefer to use the new web standards like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch" target="_blank"&gt;fetch()&lt;/a&gt;&amp;nbsp;in combination with ES6 promises. Because not all browsers support fetch() and promises yet I included polyfills for these web standards. In the future we do not even have to include these polyfills anymore.&lt;/p&gt;
  172. &lt;p&gt;The file &lt;strong&gt;index.aspx&lt;/strong&gt; using REST&amp;nbsp;has the following content:&lt;/p&gt;
  173. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleRestWithProxy/static/index.html"&gt;&lt;/script&gt;
  174. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;/span&gt;&lt;strong&gt;index.aspx&lt;/strong&gt; using REST.&lt;/p&gt;
  175. &lt;p&gt;There are a few interesting things to notice in the above REST example:&lt;/p&gt;
  176. &lt;ol&gt;
  177. &lt;li&gt;The code is hard-coding the API on path &lt;a href="http://localhost:8081"&gt;http://localhost:8081&lt;/a&gt;. This is the url I configured for sp-rest-proxy, a proxy tool I use for local development while accessing real SharePoint data. more on this in the next blog post.&lt;/li&gt;
  178. &lt;li&gt;We need to configure a header &lt;strong&gt;Accept&lt;/strong&gt;&amp;nbsp;with the value &lt;strong&gt;application/json; odata=verbose&lt;/strong&gt;. This was the only json output format that gave (almost) the same results through sp-rest-proxy and on the real SharePoint.&lt;/li&gt;
  179. &lt;li&gt;In the point above I said "almost" the same value... the proxy returns a json containing an extra level &lt;strong&gt;body&lt;/strong&gt;. See the &lt;a href="https://github.com/koltyakov/sp-rest-proxy/issues/9" target="_blank" title="sp-rest-proxy issue on returned formats"&gt;issue&lt;/a&gt;&amp;nbsp;I posted on the sp-rest-proxy repository.&lt;/li&gt;
  180. &lt;li&gt;I included a helper function sp_api_get_json() that return the correct json content in a promise.&lt;/li&gt;
  181. &lt;li&gt;In the fetch call we need to configure to include credentials, otherwise we get an authentication error on real SharePoint. It works without it on the sp-rest-proxy, because sp-rest-proxy handles the proxy and authentication.&amp;nbsp;&lt;/li&gt;
  182. &lt;/ol&gt;
  183. &lt;h3&gt;SharePoint SPA Series blog posts&lt;/h3&gt;
  184. &lt;ul&gt;
  185. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;SPA Series: Building full screen single page web applications on SharePoint&lt;/a&gt;&lt;/li&gt;
  186. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-sharepoint-rest-versus-sharepoint-csom" target="_blank"&gt;SPA Series: SharePoint REST versus SharePoint CSOM&lt;/a&gt;&lt;/li&gt;
  187. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data" target="_blank"&gt;SPA Series: Using sp-rest-proxy for local web development against real SharePoint data&lt;/a&gt;&lt;/li&gt;
  188. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app" target="_blank"&gt;SPA Series: Turn our ShowTitle app into a Progressive Web App&lt;/a&gt;&lt;/li&gt;
  189. &lt;/ul&gt;
  190. </description><pubDate>Wed, 23 Nov 2016 00:06:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/spa-series-sharepoint-rest-versus-sharepoint-csom</guid><category>SPA-Series</category><category>SharePoint</category><category>SPA</category><category>PWA</category></item><item><title>SPA Series: Building full screen single page web applications on SharePoint </title><link>https://weblogs.asp.net:443/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom</link><description>&lt;h3&gt;Introduction&lt;/h3&gt;
  191. &lt;p&gt;I have the intention to write a series of blog posts on how to write full screen single page web applications that are hosted on SharePoint and have access to Sharepoint data. There are a few good reasons why hosting a web app on SharePoint is handy:&lt;/p&gt;
  192. &lt;ul&gt;
  193. &lt;li&gt;When you access the url of the web app page hosted in SharePoint, the default SharePoint login page will be shown. There is nothing that you have to do to handle authentication in your app.&lt;/li&gt;
  194. &lt;li&gt;The SharePoint rights system is taken into account for authentication and authorization. You can specify who has access to the web app and to the content the web app is displaying.&lt;/li&gt;
  195. &lt;li&gt;It is easy to access SharePoint data.&lt;/li&gt;
  196. &lt;li&gt;You don't need a separate hosting platform for your web app like a web server when working on premise, or an Azure website if your are working in the cloud. Just upload the artifacts that are part of your web app in a SharePoint document library and you are done. SharePoint can serve your web app to the desktop or mobile web browser.&lt;/li&gt;
  197. &lt;/ul&gt;
  198. &lt;p&gt;In this first blog post I will show how to get the most simple web app possible up and running on SharePoint: a web app that displays the title of the SharePoint site it resides in.&lt;/p&gt;
  199. &lt;h3&gt;Front-end toolbelt&lt;/h3&gt;
  200. &lt;p&gt;In the world of front-end development Node.js is your friend. If you don't have it running on your machine yet, head over to &lt;a href="https://nodejs.org" target="_blank"&gt;https://nodejs.org&lt;/a&gt;&amp;nbsp;and install the LTS version.&lt;/p&gt;
  201. &lt;p&gt;There is no need for big Visual Studio projects, any editor will be sufficient. But if you have to choose one that is free and cool, have a look at &lt;a href="https://code.visualstudio.com" target="_blank"&gt;Visual Studio Code&lt;/a&gt;. Works on Windows and OSX (I develop on OSX), is fast and has great support for front-end development.&lt;/p&gt;
  202. &lt;h3&gt;Getting started&lt;/h3&gt;
  203. &lt;p&gt;To get started first create a project folder, I called mine SPOnlinePWA, and run &lt;code&gt;npm init&lt;/code&gt; on it to initialize a new project:&lt;/p&gt;
  204. &lt;div&gt;&lt;code&gt;~/projects/serge&lt;/code&gt;&lt;/div&gt;
  205. &lt;div&gt;&lt;code&gt;▶ mkdir SPOnlinePWA&lt;/code&gt;&lt;/div&gt;
  206. &lt;div&gt;&lt;/div&gt;
  207. &lt;div&gt;&lt;code&gt;~/projects/serge&lt;/code&gt;&lt;/div&gt;
  208. &lt;div&gt;&lt;code&gt;▶ cd SPOnlinePWA&lt;/code&gt;&lt;/div&gt;
  209. &lt;div&gt;&lt;/div&gt;
  210. &lt;div&gt;&lt;code&gt;projects/serge/SPOnlinePWA&lt;/code&gt;&lt;/div&gt;
  211. &lt;div&gt;&lt;code&gt;▶ npm init&lt;/code&gt;&lt;/div&gt;
  212. &lt;div&gt;&lt;code&gt;This utility will walk you through creating a package.json file.&lt;/code&gt;&lt;/div&gt;
  213. &lt;div&gt;&lt;code&gt;It only covers the most common items, and tries to guess sensible defaults.&lt;/code&gt;&lt;/div&gt;
  214. &lt;div&gt;&lt;/div&gt;
  215. &lt;div&gt;&lt;code&gt;See `npm help json` for definitive documentation on these fields&lt;/code&gt;&lt;/div&gt;
  216. &lt;div&gt;&lt;code&gt;and exactly what they do.&lt;/code&gt;&lt;/div&gt;
  217. &lt;div&gt;&lt;/div&gt;
  218. &lt;div&gt;&lt;code&gt;Use `npm install &amp;lt;pkg&amp;gt; --save` afterwards to install a package and&lt;/code&gt;&lt;/div&gt;
  219. &lt;div&gt;&lt;code&gt;save it as a dependency in the package.json file.&lt;/code&gt;&lt;/div&gt;
  220. &lt;div&gt;&lt;/div&gt;
  221. &lt;div&gt;&lt;code&gt;Press ^C at any time to quit.&lt;/code&gt;&lt;/div&gt;
  222. &lt;div&gt;&lt;code&gt;name: (SPOnlinePWA) sponlinepwa&lt;/code&gt;&lt;/div&gt;
  223. &lt;div&gt;&lt;code&gt;version: (1.0.0)&lt;/code&gt;&lt;/div&gt;
  224. &lt;div&gt;&lt;code&gt;description: A progressive web app on SharePoint Online&lt;/code&gt;&lt;/div&gt;
  225. &lt;div&gt;&lt;code&gt;entry point: (index.js)&lt;/code&gt;&lt;/div&gt;
  226. &lt;div&gt;&lt;code&gt;test command:&lt;/code&gt;&lt;/div&gt;
  227. &lt;div&gt;&lt;code&gt;git repository:&lt;/code&gt;&lt;/div&gt;
  228. &lt;div&gt;&lt;code&gt;keywords: pwa sponline&lt;/code&gt;&lt;/div&gt;
  229. &lt;div&gt;&lt;code&gt;author: Serge van den Oever&lt;/code&gt;&lt;/div&gt;
  230. &lt;div&gt;&lt;code&gt;license: (ISC) MIT&lt;/code&gt;&lt;/div&gt;
  231. &lt;div&gt;&lt;code&gt;About to write to /Users/Serge/projects/serge/SPOnlinePWA/package.json:&lt;/code&gt;&lt;/div&gt;
  232. &lt;div&gt;&lt;/div&gt;
  233. &lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
  234. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"name": "sponlinepwa",&lt;/code&gt;&lt;/div&gt;
  235. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"version": "1.0.0",&lt;/code&gt;&lt;/div&gt;
  236. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"description": "A progressive web app on SharePoint Online",&lt;/code&gt;&lt;/div&gt;
  237. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"main": "index.js",&lt;/code&gt;&lt;/div&gt;
  238. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"scripts": {&lt;/code&gt;&lt;/div&gt;
  239. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"&lt;/code&gt;&lt;/div&gt;
  240. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;},&lt;/code&gt;&lt;/div&gt;
  241. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"keywords": [&lt;/code&gt;&lt;/div&gt;
  242. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"pwa",&lt;/code&gt;&lt;/div&gt;
  243. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"sponline"&lt;/code&gt;&lt;/div&gt;
  244. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;],&lt;/code&gt;&lt;/div&gt;
  245. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"author": "Serge van den Oever",&lt;/code&gt;&lt;/div&gt;
  246. &lt;div&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;"license": "MIT"&lt;/code&gt;&lt;/div&gt;
  247. &lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
  248. &lt;div&gt;&lt;/div&gt;
  249. &lt;div&gt;&lt;/div&gt;
  250. &lt;div&gt;&lt;code&gt;Is this ok? (yes) yes&lt;/code&gt;&lt;/div&gt;
  251. &lt;div&gt;&lt;/div&gt;
  252. &lt;p&gt;We now have a simple project to get us started. First thing to do is install tooling that we need. And we need tooling.... to get our page into SharePoint. We do this using the great tool&amp;nbsp;&lt;a href="https://www.npmjs.com/package/spsave" target="_blank"&gt;spsave&lt;/a&gt;&amp;nbsp;- advertised as&amp;nbsp;&lt;em&gt;"&lt;span&gt;Save files in SharePoint using node.js easily"&lt;/span&gt;&lt;/em&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
  253. &lt;div&gt;&lt;code&gt;projects/serge/SPOnlinePWA&lt;/code&gt;&lt;/div&gt;
  254. &lt;div&gt;&lt;code&gt;▶ npm install spsave --save-dev&lt;/code&gt;&lt;/div&gt;
  255. &lt;div&gt;&lt;/div&gt;
  256. &lt;h3&gt;Configure SharePoint Online&lt;/h3&gt;
  257. &lt;p&gt;Another thing that we need is a SharePoint site with a document library where we have write access. In this blog post we assume the use of On SharePoint Online where you can go to the url &lt;a href="https://tenant-my.sharepoint.com,"&gt;https://&lt;em&gt;tenant&lt;/em&gt;-my.sharepoint.com,&lt;/a&gt;&amp;nbsp;where &lt;em&gt;tenant&lt;/em&gt; is the name of your company. After authentication you will end up in OneDrive with the url&amp;nbsp;&lt;a href="https://tenant-my.sharepoint.com/personal/serge_macaw_nl/_layouts/15/onedrive.aspx,"&gt;https://&lt;em&gt;tenant&lt;/em&gt;-my.sharepoint.com/personal/serge_macaw_nl/_layouts/15/&lt;strong&gt;onedrive&lt;/strong&gt;.aspx,&lt;/a&gt;&amp;nbsp;if you replace the &lt;strong&gt;onedrive&lt;/strong&gt; into &lt;strong&gt;viewlsts&lt;/strong&gt; like this&amp;nbsp;&lt;a href="https://tenant-my.sharepoint.com/personal/serge_macaw_nl/_layouts/15/viewlsts.aspx,"&gt;https://&lt;em&gt;tenant&lt;/em&gt;-my.sharepoint.com/personal/serge_macaw_nl/_layouts/15/viewlsts.aspx,&lt;/a&gt;&amp;nbsp;you will get to the content living on your personal site. With the &lt;strong&gt;new&lt;/strong&gt; link you can add a subsite:&lt;/p&gt;
  258. &lt;p&gt;&lt;img width="720" height="714" alt="" src="https://aspblogs.blob.core.windows.net:443/media/soever/Media/NewSharePointSite.png" /&gt;&lt;/p&gt;
  259. &lt;p&gt;Because we selected "Use unique permissions" we can now give everyone read access to our new site so we can share our web apps hosted on this site within our&amp;nbsp;company:&lt;/p&gt;
  260. &lt;p&gt;&lt;img width="720" height="643" alt="" src="https://aspblogs.blob.core.windows.net:443/media/soever/Media/Screen%20Shot%202016-11-19%20at%2016.38.39.png" /&gt;&lt;/p&gt;
  261. &lt;p&gt;In our newly created "apps" site create a document library called "apppages". In this document library we will host our apps. For each app we will create a sub-folder, so we can host multiple apps in this document library. In my case this document library has the url:&amp;nbsp;&lt;a href="https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages" target="_blank"&gt;https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages&lt;/a&gt;.&lt;/p&gt;
  262. &lt;p&gt;Note that you can take a similar approach with a SharePoint site on-premise.&lt;/p&gt;
  263. &lt;h3&gt;The simplest app&lt;/h3&gt;
  264. &lt;p&gt;We now create our simplest app, showing the title of the SharePoint site the app resides in using CSOM, the Client-side SharePoint Object Model.&lt;/p&gt;
  265. &lt;p&gt;Create a file &lt;strong&gt;index.aspx&lt;/strong&gt; with the following content:&lt;/p&gt;
  266. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleCsom/index.aspx"&gt;&lt;/script&gt;
  267. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;/span&gt;&lt;strong&gt;index.aspx&lt;/strong&gt;.&lt;/p&gt;
  268. &lt;h3&gt;Configuration for deployment&lt;/h3&gt;
  269. &lt;p&gt;To deploy to SharePoint Online we need the following environment variables (I saved this in my .zshrc file on OSX because I use zsh, add to .bshrc if you use bash):&lt;/p&gt;
  270. &lt;p&gt;&lt;code&gt;# For SharePoint Online App Development we need the following environment variables&lt;/code&gt;&lt;br /&gt;&lt;code&gt;export SPONLINE_SITE_APPS="https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;export SPONLINE_USERNAME="&amp;lt;my username&amp;gt;"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;export SPONLINE_PASSWORD="&amp;lt;my password&amp;gt;"&lt;/code&gt;&amp;nbsp;&lt;/p&gt;
  271. &lt;p&gt;On Windows set the environment variables with the method as described &lt;a href="http://www.computerhope.com/issues/ch000549.htm" target="_blank" title="Setting environment variables on Windows"&gt;here&lt;/a&gt;.&lt;/p&gt;
  272. &lt;h3&gt;Deploy to SharePoint&lt;/h3&gt;
  273. &lt;p&gt;To deploy to SharePoint we use the &lt;a href="https://www.npmjs.com/package/spsave" target="_blank" title="spsave npm package"&gt;spsave npm package&lt;/a&gt;&amp;nbsp;as already installed above.&lt;/p&gt;
  274. &lt;p&gt;Create a file &lt;strong&gt;deploy.js&lt;/strong&gt;&amp;nbsp;with the following content:&lt;/p&gt;
  275. &lt;script src="https://gist-it.appspot.com/github/svdoever/sharepoint-progressive-web-apps/blob/master/ShowTitleCsom/deploy.js"&gt;&lt;/script&gt;
  276. &lt;p&gt;End&amp;nbsp;&lt;span&gt;code of file&amp;nbsp;&lt;strong&gt;deploy.js&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
  277. &lt;p&gt;We can now run the command &lt;code&gt;node deploy.js&lt;/code&gt; to deploy the file &lt;strong&gt;index.aspx&lt;/strong&gt; to the document library &lt;strong&gt;apppages&lt;/strong&gt;. In my case the url of the uploaded app is&amp;nbsp;&lt;a href="https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages/showtitlecsom/index.aspx" target="_blank"&gt;https://macaw-my.sharepoint.com/personal/serge_macaw_nl/apps/apppages/showtitlecsom/index.aspx&lt;/a&gt;.&lt;/p&gt;
  278. &lt;p&gt;If you open this url in a browser you would see a blank page with the SharePoint site title &lt;strong&gt;apps&lt;/strong&gt;. If you open this url from an anonymous browser or your phone you would get the SharePoint login screen, and after authentication you will see the interesting app content.&lt;/p&gt;
  279. &lt;h3&gt;Conclusion&lt;/h3&gt;
  280. &lt;p&gt;Although very simple, these are the first steps to get a web app hosted on SharePoint with access to SharePoint content. In following blog posts we build on the above knowledge to improve our development process for building SharePoint hosted full screen single page applications.&lt;/p&gt;
  281. &lt;p&gt;The sample code can be found in the GitHub repository &lt;a href="https://github.com/svdoever/sharepoint-progressive-web-apps" target="_blank"&gt;https://github.com/svdoever/sharepoint-progressive-web-apps&lt;/a&gt; in the folder &lt;strong&gt;ShowTitleCsom&lt;/strong&gt;.&lt;/p&gt;
  282. &lt;h3&gt;SharePoint SPA Series blog posts&lt;/h3&gt;
  283. &lt;ul&gt;
  284. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom" target="_blank"&gt;SPA Series: Building full screen single page web applications on SharePoint&lt;/a&gt;&lt;/li&gt;
  285. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-sharepoint-rest-versus-sharepoint-csom" target="_blank"&gt;SPA Series: SharePoint REST versus SharePoint CSOM&lt;/a&gt;&lt;/li&gt;
  286. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-using-sp-rest-proxy-for-local-web-development-against-real-sharepoint-data" target="_blank"&gt;SPA Series: Using sp-rest-proxy for local web development against real SharePoint data&lt;/a&gt;&lt;/li&gt;
  287. &lt;li&gt;&lt;a href="https://weblogs.asp.net/soever/spa-series-turn-our-showtitle-app-into-a-progressive-web-app" target="_blank"&gt;SPA Series: Turn our ShowTitle app into a Progressive Web App&lt;/a&gt;&lt;/li&gt;
  288. &lt;/ul&gt;
  289. </description><pubDate>Mon, 21 Nov 2016 22:25:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/spa-series-full-screen-spa-on-sharepoint-showtitle-csom</guid><category>SPA-Series</category><category>SharePoint</category><category>SPA</category><category>PWA</category></item><item><title>Working example of MassTransit 3 request/response conversation</title><link>https://weblogs.asp.net:443/soever/working-example-of-masstransit-3-request-response-conversation</link><description>&lt;p&gt;&lt;a href="http://docs.masstransit-project.com/en/latest/usage/request_response.html" target="_blank"&gt;Chapter 3.5 of the MassTransit documentation&lt;/a&gt; contains a non-complete example of a request/response conversation using MassTransit. After some fiddling I got an example working using an in-memory MassTransit queue with multple request types. See the code below, implemented as an xunit test.&lt;/p&gt;
  290. &lt;script src="https://gist.github.com/svdoever/5bbf9a08c309b3a935f24671eaeb3e3c.js"&gt;&lt;/script&gt;
  291. </description><pubDate>Mon, 29 Aug 2016 15:46:27 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/working-example-of-masstransit-3-request-response-conversation</guid></item><item><title>Consuming Javascript libraries from TypeScript without type definition files</title><link>https://weblogs.asp.net:443/soever/consuming-javascript-libraries-from-typescrip-without-type-definition-files</link><description>&lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;There are cases where you need to consume Javascript libraries or, for example, ReactJS components written in Javascript from your TypeScript code. Possible reasons:&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  292. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;&lt;/span&gt;&lt;/div&gt;
  293. &lt;ul&gt;
  294. &lt;li class="cledit-section"&gt;&lt;span class="token li"&gt;You find a great library or component "out in the wild" written in Javascript&lt;/span&gt;&lt;/li&gt;
  295. &lt;li class="cledit-section"&gt;&lt;span class="token li"&gt;One of your team-members does not know/does not want to write TypeScript&lt;/span&gt;&lt;/li&gt;
  296. &lt;li class="cledit-section"&gt;&lt;span class="token li"&gt;You want to consume components from an existing library or component set writen in Javascript&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
  297. &lt;/ul&gt;
  298. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;&lt;/span&gt;&lt;/div&gt;
  299. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;Assume the situation where a ReactJS component &lt;strong&gt;&lt;span class="token code" spellcheck="false"&gt;MyComponent.jsx&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;written in Javascript must be consumed from a component &lt;strong&gt;&lt;span class="token code" spellcheck="false"&gt;Home.tsx&lt;/span&gt;&lt;/strong&gt;:&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  300. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;The file &lt;strong&gt;&lt;span class="token code" spellcheck="false"&gt;MyComponent.jsx&lt;/span&gt;&lt;/strong&gt;:&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  301. &lt;pre class="cledit-section"&gt;&lt;span class="token pre gfm" spellcheck="false"&gt;&lt;span class="token language-javascript"&gt;&lt;code&gt;&lt;span class="token keyword"&gt;import&lt;/span&gt; &lt;span class="token operator"&gt;*&lt;/span&gt; as React from &lt;span class="token string"&gt;'react'&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="token keyword"&gt;export&lt;/span&gt; &lt;span class="token keyword"&gt;class&lt;/span&gt; &lt;span class="token class-name"&gt;MyComponent&lt;/span&gt; &lt;span class="token keyword"&gt;extends&lt;/span&gt; &lt;span class="token class-name"&gt;React&lt;span class="token punctuation"&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="token function"&gt;&amp;nbsp; constructor&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;props&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt; &lt;span class="token keyword"&gt;super&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;props&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="token function"&gt;&amp;nbsp; render&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt; &lt;span class="token keyword"&gt;return&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt;h1&lt;span class="token operator"&gt;&amp;gt;&lt;/span&gt;Hello from MyComponent&lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token operator"&gt;/&lt;/span&gt;h1&lt;span class="token operator"&gt;&amp;gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
  302. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;We could import this component in different ways:&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  303. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;&lt;/span&gt;&lt;/div&gt;
  304. &lt;pre class="cledit-section"&gt;&lt;span class="token pre gfm" spellcheck="false"&gt;&lt;code&gt;&lt;em&gt;import {MyComponent} from './MyComponent'; // ERROR: Cannot find module './MyComponent'&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const MyComponent = require('./MyComponent'); // Warning if used as &amp;lt;MyComponent/&amp;gt;&lt;/em&gt;&lt;br /&gt;            // see https://codereviewvideos.com/blog/warning-react-createelement/&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const X = require('./MyComponent'); // OK if used as &amp;lt;X.MyComponent/&amp;gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const MyComponent = require('./MyComponent').MyComponent; // OK&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const MyComponent = require('./MyComponent').default;// OK if defined as export default class MyComponent&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const {MyComponent} = require('./MyComponent'); // OK, it's possible to destructure multiple components&lt;/code&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
  305. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;For details on how to specify types for desctructured object parameters see &lt;a href="https://blog.mariusschulz.com/2015/11/13/typing-destructured-object-parameters-in-typescript" target="_blank"&gt;destructured object parameters in TypeScript&lt;/a&gt;.&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  306. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;So if we want to consume the above JavaScript component from TypeScript in the component&amp;nbsp;&lt;strong&gt;&lt;span class="token code" spellcheck="false"&gt;Home.tsx&lt;/span&gt;&lt;/strong&gt;:&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
  307. &lt;div class="cledit-section"&gt;&lt;span class="token p"&gt;&lt;/span&gt;&lt;/div&gt;
  308. &lt;pre class="cledit-section"&gt;&lt;span class="token pre gfm" spellcheck="false"&gt;import * as React from 'react';&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;const MyComponent = require('./MyComponent').MyComponent;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;export class Home extends React.Component&amp;lt;any, any&amp;gt; {&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;  render() { return (&amp;lt;div&amp;gt;&amp;lt;MyComponent /&amp;gt;&amp;lt;/div&amp;gt;); }&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/span&gt;&lt;span class="lf"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
  309. &lt;p&gt;&lt;/p&gt;
  310. </description><pubDate>Sat, 09 Jul 2016 09:16:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/consuming-javascript-libraries-from-typescrip-without-type-definition-files</guid><category>Javascript</category><category>TypeScript</category><category>ReactJS</category></item><item><title>Polymer 1.0 - Polylint - use on project instead of component</title><link>https://weblogs.asp.net:443/soever/polymer-1-0-polylint-use-on-project-instead-of-component</link><description>&lt;p&gt;The Polymer team just release Polylint, a tool to c&lt;span&gt;atch errors in your polymer project before even running your code.&lt;/span&gt;&lt;/p&gt;
  311. &lt;p&gt;&lt;span&gt;The tool seems to be designed to work in a component, but it faisl in a project that follows the project structure as used in the&lt;a href="https://developers.google.com/web/tools/polymer-starter-kit/index" target="_blank"&gt; Polymer Starter Kit&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
  312. &lt;p&gt;You can see this structure at&amp;nbsp;&lt;a href="https://github.com/polymerelements/polymer-starter-kit"&gt;https://github.com/polymerelements/polymer-starter-kit&lt;/a&gt;.&lt;/p&gt;
  313. &lt;p&gt;In this structure the folder&amp;nbsp;bower_components folder is located &lt;span style="text-decoration: underline;"&gt;next&lt;/span&gt; to the &lt;strong&gt;app&lt;/strong&gt; folder, instead of &lt;span style="text-decoration: underline;"&gt;in&lt;/span&gt; the &lt;strong&gt;app&lt;/strong&gt; folder.&lt;/p&gt;
  314. &lt;p&gt;To get started:&lt;/p&gt;
  315. &lt;p&gt;&lt;strong&gt;git clone&amp;nbsp;&lt;a href="https://github.com/polymerelements/polymer-starter-kit"&gt;https://github.com/polymerelements/polymer-starter-kit&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
  316. &lt;p&gt;&lt;strong&gt;cd &amp;nbsp;polymer-starter-kit&lt;/strong&gt;&lt;/p&gt;
  317. &lt;p&gt;&lt;strong&gt;bower install&lt;/strong&gt;&lt;/p&gt;
  318. &lt;p&gt;Now if you run the command &lt;strong&gt;polylint --root app --input index.html&lt;/strong&gt; you will get the following errors:&lt;/p&gt;
  319. &lt;p&gt;ERROR finding app\bower_components\webcomponentsjs\webcomponents-lite.js&lt;br /&gt;Error: ENOENT, open 'C:\p\serge\polymer-starter-kit\app\bower_components\webcomponentsjs\webcomponents-lite.js'&lt;br /&gt; at Error (native)&lt;br /&gt;ERROR finding app\bower_components\iron-flex-layout\classes\iron-flex-layout.html&lt;br /&gt;ERROR finding app\bower_components\iron-icons\iron-icons.html&lt;br /&gt;ERROR finding app\bower_components\iron-pages\iron-pages.html&lt;br /&gt;ERROR finding app\bower_components\iron-selector\iron-selector.html&lt;br /&gt;ERROR finding app\bower_components\paper-drawer-panel\paper-drawer-panel.html&lt;br /&gt;ERROR finding app\bower_components\paper-icon-button\paper-icon-button.html&lt;br /&gt;ERROR finding app\bower_components\paper-item\paper-item.html&lt;br /&gt;ERROR finding app\bower_components\paper-material\paper-material.html&lt;br /&gt;ERROR finding app\bower_components\paper-menu\paper-menu.html&lt;br /&gt;ERROR finding app\bower_components\paper-scroll-header-panel\paper-scroll-header-panel.html&lt;br /&gt;ERROR finding app\bower_components\paper-styles\paper-styles-classes.html&lt;br /&gt;ERROR finding app\bower_components\paper-toast\paper-toast.html&lt;br /&gt;ERROR finding app\bower_components\paper-toolbar\paper-toolbar.html&lt;br /&gt;ERROR finding app\bower_components\page\page.js&lt;br /&gt;ERROR finding app\bower_components\polymer\polymer.html&lt;/p&gt;
  320. &lt;p&gt;This can be solved by creating a symbolic link &lt;strong&gt;bower_components&lt;/strong&gt; in the app folder to &lt;strong&gt;..\bower_components&lt;/strong&gt;.&lt;/p&gt;
  321. &lt;p&gt;The following script &lt;strong&gt;RunPolylint.bat&amp;nbsp;&lt;/strong&gt;will do this, place it in the root of your project (next to the &lt;b&gt;app&lt;/b&gt; folder.&lt;/p&gt;
  322. &lt;pre&gt;:: RunPolylint.bat - by Serge van den Oever, http://weblogs.asp.net/soever&lt;br /&gt;:: This script assumes that polylint in installed&lt;br /&gt;:: globally through the following command:&lt;br /&gt;::    npm install -g polylint&lt;br /&gt;:: Polylint assumes that the bower_components folder is located&lt;br /&gt;:: in the same folder as the entry point file as specified with --input.&lt;br /&gt;:: This is the case for a Polymer component, but not for an application&lt;br /&gt;:: that follows the structure of the Polymer Starter Kit.&lt;br /&gt;:: This script solves this issue by creating a temporary symbolic link&lt;br /&gt;:: to the folder bower_components in the folder app&lt;br /&gt;@cd %~dp0&lt;br /&gt;set root=app&lt;br /&gt;set input=index.html&lt;br /&gt;pushd %root%&lt;br /&gt;mklink bower_components ..\bower_components&lt;br /&gt;popd&lt;br /&gt;polylint --root %root% --input %input%&lt;br /&gt;del %root\bower_components&lt;/pre&gt;
  323. </description><pubDate>Fri, 18 Sep 2015 16:33:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/polymer-1-0-polylint-use-on-project-instead-of-component</guid><category>Polymer</category></item><item><title>Intel AppFramework create and use your choice of IcoMoon icons </title><link>https://weblogs.asp.net:443/soever/intel-appframework-create-and-use-your-choice-of-icomoon-icons</link><description>&lt;p style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: normal;"&gt;The Intel AppFramework uses a small subset of the I&lt;a href="https://icomoon.io/" target="_blank"&gt;coMoon&lt;/a&gt;&amp;nbsp;icons. This post describes how to make your own selection of IcoMoon icons and use it in your app.&lt;/p&gt;
  324. &lt;p style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: normal;"&gt;There is a&amp;nbsp;&lt;a href="https://icomoon.io/#icons-icomoon" target="_blank"&gt;free IcoMoon icon set with 490 icons&lt;/a&gt;&amp;nbsp;available that we will use to make our selection from.&lt;/p&gt;
  325. &lt;ol style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: normal;"&gt;
  326. &lt;li&gt;Open the url&amp;nbsp;&lt;a href="https://icomoon.io/app/#/select"&gt;https://icomoon.io/app/#/select&lt;br /&gt;&lt;/a&gt;&lt;a href="https://icomoon.io/app/#/select"&gt;&lt;/a&gt;&lt;/li&gt;
  327. &lt;li&gt;Open the&amp;nbsp;&lt;strong&gt;IcoMoon - Free&lt;/strong&gt;&amp;nbsp;icon set and select the icons you want to use in your app&lt;/li&gt;
  328. &lt;li&gt;It is also possible to select all icons (we will do that for now)&lt;/li&gt;
  329. &lt;li&gt;Select the&amp;nbsp;&lt;strong&gt;Generate Font&lt;/strong&gt;&amp;nbsp;option at the bottom&lt;/li&gt;
  330. &lt;li&gt;Press settings and select Font Name&amp;nbsp;&lt;strong&gt;IcoMoon&lt;/strong&gt;, select as Class Prefix&amp;nbsp;&lt;strong&gt;icon.&lt;/strong&gt;&amp;nbsp;and select the option&amp;nbsp;&lt;strong&gt;Encode &amp;amp; Embed Font in CSS&lt;/strong&gt;&lt;/li&gt;
  331. &lt;li&gt;Now click the download button&lt;/li&gt;
  332. &lt;li&gt;Open the downloaded&amp;nbsp;&lt;strong&gt;IcoMoon.zip&amp;nbsp;&lt;/strong&gt;file and copy the file&amp;nbsp;&lt;strong&gt;style.css&lt;/strong&gt;to your styles folder as&amp;nbsp;&lt;strong&gt;customicons.css&lt;/strong&gt;&lt;/li&gt;
  333. &lt;li&gt;Open de&amp;nbsp;&lt;strong&gt;customicons.css&lt;/strong&gt;&amp;nbsp;file and compare with the file&amp;nbsp;&lt;a href="https://github.com/01org/appframework/blob/master/build/icons.css" target="_blank"&gt;&lt;strong&gt;appframework/build/icons.css&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;(we need to copy over the appframework specific styles)&lt;/li&gt;
  334. &lt;li&gt;Remove the first four lines with a file-based&amp;nbsp;&lt;strong&gt;@font-face&lt;/strong&gt;definition, we will use the embeded one&lt;br /&gt;
  335. &lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;@font-face &lt;/span&gt;{
  336.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-family&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;'IcoMoon'&lt;/span&gt;;
  337.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;src&lt;/span&gt;: &lt;span style="color: #000080; font-weight: bold;"&gt;url&lt;/span&gt;(&lt;span style="color: #008000; font-weight: bold;"&gt;'fonts/IcoMoon.eot'&lt;/span&gt;);
  338. }
  339. &lt;/pre&gt;
  340. &lt;/li&gt;
  341. &lt;li&gt;Replace:&lt;br /&gt;
  342. &lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;.&lt;span style="color: #000080; font-weight: bold;"&gt;icon &lt;/span&gt;{
  343.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-family&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;'IcoMoon'&lt;/span&gt;;
  344.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;speak&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;none&lt;/span&gt;;
  345.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-style&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;normal&lt;/span&gt;;
  346.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-weight&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;normal&lt;/span&gt;;
  347.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-variant&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;normal&lt;/span&gt;;
  348.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;text-transform&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;none&lt;/span&gt;;
  349.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;line-height&lt;/span&gt;: &lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;;
  350. &lt;p&gt;&lt;span style="color: #808080; font-style: italic;"&gt;/* Better Font Rendering =========== */
  351. &lt;/span&gt;&lt;span style="color: #0000ff; font-weight: bold;"&gt;-webkit-font-smoothing&lt;/span&gt;: &lt;span style="color: #008000; font-weight: bold;"&gt;antialiased&lt;/span&gt;;
  352. &lt;span style="color: #0000ff; font-weight: bold;"&gt;-moz-osx-font-smoothing&lt;/span&gt;: &lt;span style="color: #000080; font-weight: bold;"&gt;grayscale&lt;/span&gt;;
  353. }
  354. &lt;span style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; white-space: normal;"&gt;with (check &lt;/span&gt;&lt;strong style="font-family: Helvetica, Arial, sans-serif; font-size: 14px;"&gt;&lt;a href="https://github.com/01org/appframework/blob/master/build/icons.css" target="_blank"&gt;appframework/build/icons.css&lt;/a&gt;&lt;/strong&gt;&lt;span style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; white-space: normal;"&gt; for changes):&lt;/span&gt;
  355. &lt;/pre&gt;&lt;/p&gt;
  356. &lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;.&lt;span style="color: #000080; font-weight: bold;"&gt;icon&lt;/span&gt;:&lt;span style="color: #000080; font-weight: bold;"&gt;before &lt;/span&gt;{
  357.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-family&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;'IcoMoon'&lt;/span&gt;;
  358.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;speak&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;none&lt;/span&gt;;
  359.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-style&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;normal&lt;/span&gt;;
  360.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-weight&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;normal &lt;/span&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;!important&lt;/span&gt;;
  361.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-variant&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;normal&lt;/span&gt;;
  362.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;text-transform&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;none&lt;/span&gt;;
  363.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;line-height&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;;
  364.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;color&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;inherit&lt;/span&gt;;
  365.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;position&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;relative&lt;/span&gt;;
  366.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-size&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;em&lt;/span&gt;;
  367.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;left&lt;/span&gt;:-&lt;span style="color: #0000ff;"&gt;3&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;px&lt;/span&gt;; &lt;span style="color: #0000ff; font-weight: bold;"&gt;top&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;px&lt;/span&gt;;
  368. }
  369. &lt;span style="color: #000080; font-weight: bold;"&gt;li &lt;/span&gt;.&lt;span style="color: #000080; font-weight: bold;"&gt;icon&lt;/span&gt;:&lt;span style="color: #000080; font-weight: bold;"&gt;before &lt;/span&gt;{
  370.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;position&lt;/span&gt;:&lt;span style="color: #008000; font-weight: bold;"&gt;relative&lt;/span&gt;;
  371.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;width&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;24&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;px&lt;/span&gt;; &lt;span style="color: #0000ff; font-weight: bold;"&gt;height&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;100&lt;/span&gt;%;
  372.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;top&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;px&lt;/span&gt;;
  373.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;line-height&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;0 &lt;/span&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;!important&lt;/span&gt;;
  374.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;margin-right&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;4&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;px&lt;/span&gt;;
  375. }
  376.  
  377. .&lt;span style="color: #000080; font-weight: bold;"&gt;icon&lt;/span&gt;.&lt;span style="color: #000080; font-weight: bold;"&gt;mini&lt;/span&gt;:&lt;span style="color: #000080; font-weight: bold;"&gt;before &lt;/span&gt;{
  378.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-size&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;.7&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;em&lt;/span&gt;;
  379. }
  380. .&lt;span style="color: #000080; font-weight: bold;"&gt;icon&lt;/span&gt;.&lt;span style="color: #000080; font-weight: bold;"&gt;big&lt;/span&gt;:&lt;span style="color: #000080; font-weight: bold;"&gt;before &lt;/span&gt;{
  381.   &lt;span style="color: #0000ff; font-weight: bold;"&gt;font-size&lt;/span&gt;:&lt;span style="color: #0000ff;"&gt;1.5&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;em&lt;/span&gt;;
  382. }
  383. &lt;/pre&gt;
  384. &lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;&lt;span style="font-family: Helvetica, Arial, sans-serif; font-size: 14px; white-space: normal;"&gt;and we are done!&amp;nbsp;&lt;/span&gt;
  385. &lt;/pre&gt;
  386. &lt;/li&gt;
  387. &lt;li&gt;In your main.css file include the appframework css files and your customicons.css file (or include directly in html):&lt;br /&gt;
  388. &lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;@import url&lt;/span&gt;(&lt;span style="color: #008000; font-weight: bold;"&gt;../appframework/build/af.ui.base.css&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;@import url&lt;/span&gt;(&lt;span style="color: #008000; font-weight: bold;"&gt;../appframework/build/af.ui.css&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;@import url&lt;/span&gt;(&lt;span style="color: #008000; font-weight: bold;"&gt;customicons.css&lt;/span&gt;);&lt;/pre&gt;
  389. &lt;/li&gt;
  390. &lt;/ol&gt;
  391. </description><pubDate>Sun, 19 Jul 2015 23:14:53 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/intel-appframework-create-and-use-your-choice-of-icomoon-icons</guid><category>appframework</category><category>Mobile Development</category></item><item><title>Intel AppFramework installation and documentation</title><link>https://weblogs.asp.net:443/soever/intel-appframework-installation-and-documentation</link><description>&lt;p&gt;I have written a&amp;nbsp;&lt;a href="https://itunes.apple.com/nl/app/elsevier-nextens/id902737411?mt=8" target="_blank"&gt;mobile app&lt;/a&gt;&amp;nbsp;with&amp;nbsp;&lt;a href="http://www.ionicframework.com" target="_blank"&gt;Ionic Framework&lt;/a&gt;&amp;nbsp;but I must say that I'm not really font of the AngularJS framework, especially now that you know that version 1.3 as used in Ionic at the time of writing (version 1.0.1) is a dead end and version 2 is on the horizon.&amp;nbsp;For a new mobile app I needed a&amp;nbsp;&lt;a href="http://noeticforce.com/best-hybrid-mobile-app-ui-frameworks-html5-js-css" target="_blank"&gt;mobile app UI framework&lt;/a&gt;&amp;nbsp;that I can use in combination with ReactJS and that would work on an as wide range of mobile devices as possible.&amp;nbsp;&lt;a href="http://reapp.io" target="_blank"&gt;Reapp&lt;/a&gt;&amp;nbsp;looks promising, but is still alpha and not very cross platform (for example Windows Phone). I ended up with&amp;nbsp;&lt;a href="http://app-framework-software.intel.com/" target="_blank"&gt;Intel App Framework&lt;/a&gt;&amp;nbsp;version 3, a simple framework with great support for multiple devices. It event tries to mimic the native style on each type of device, I'm not sure yet if i'm that happy about that, but it is also possible to override the ui time to a fixed ui (for example ios) for all devices.&lt;/p&gt;
  392. &lt;p&gt;&lt;strong&gt;Installing Intel App Framework&lt;/strong&gt;&lt;/p&gt;
  393. &lt;p&gt;For client framework I normally use Bower. The Intel App Framework in available on Bower as the "&lt;a href="https://github.com/ayman-alkom/intel-bower" target="_blank"&gt;intel-bower&lt;/a&gt;" package, but that package is not maintained and out of date, so don't use it. There is another reason why you shouldn't use it, it only contains the js and css files, not the samples which you really need due to a lack of documentation. More on that later. My approach is that I add the original&amp;nbsp;&lt;a href="https://github.com/01org/appframework.git" target="_blank"&gt;appframework Git repository&lt;/a&gt;&amp;nbsp;ito my project's Git repository a a submodule:&lt;/p&gt;
  394. &lt;blockquote&gt;
  395. &lt;p&gt;&lt;code&gt;git submodule add https://github.com/01org/appframework.git&amp;nbsp; appframework&lt;/code&gt;&lt;/p&gt;
  396. &lt;/blockquote&gt;
  397. &lt;p&gt;And to update this (an possibly other) submodules in your repository, just execute:&lt;/p&gt;
  398. &lt;blockquote&gt;
  399. &lt;p&gt;&lt;code&gt;git submodule foreach git pull&lt;/code&gt;&lt;/p&gt;
  400. &lt;/blockquote&gt;
  401. &lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/p&gt;
  402. &lt;p&gt;The documentation available for the Intel App Framework is ... minimal.&lt;/p&gt;
  403. &lt;ul&gt;
  404. &lt;li&gt;Your main entry point is at&amp;nbsp;&lt;a href="http://app-framework-software.intel.com/"&gt;http://app-framework-software.intel.com/&lt;/a&gt;&lt;/li&gt;
  405. &lt;li&gt;The most important entry in the documentation is&amp;nbsp;&lt;a href="http://app-framework-software.intel.com/documentation.php#afui/afui_about" target="_blank"&gt;http://app-framework-software.intel.com/documentation.php#afui/afui_about&lt;/a&gt;, in this list you find some interesting things like:&lt;/li&gt;
  406. &lt;li&gt;- UI Quickstart &amp;nbsp;- gives a nice initial introduction on using the Intel App Framework&lt;/li&gt;
  407. &lt;li&gt;- OS Themes - how to disable custom os themes and specify the one you want to use on all devices (still mentions version 2.1?!)&lt;/li&gt;
  408. &lt;li&gt;For all JavaScript api's and plugins see&amp;nbsp;&lt;a href="http://app-framework-software.intel.com/api.php"&gt;http://app-framework-software.intel.com/api.php&lt;/a&gt;&lt;/li&gt;
  409. &lt;/ul&gt;
  410. &lt;p&gt;The documentation is very minimal (to say the least) about a lot of things. Good example: the section&amp;nbsp;&lt;a href="http://app-framework-software.intel.com/documentation.php#afui/afui_icons" target="_blank"&gt;Vector Icons&lt;/a&gt;&amp;nbsp;does not mention the available icons, and does not explain how to add your custom icons (I will write about that in a next blog post).&lt;/p&gt;
  411. &lt;p&gt;One of the most important pages is the appframework/index.html kitchensink example. It is possible to run this page directly within the github repository by translating it's url from:&amp;nbsp;&lt;a href="https://github.com/01org/appframework/blob/master/index.html"&gt;https://github.com/01org/appframework/blob/master/index.html&lt;/a&gt;&amp;nbsp;to&amp;nbsp;&lt;a href="http://rawgit.com/01org/appframework/master/index.html"&gt;http://rawgit.com/01org/appframework/master/index.html&lt;/a&gt;&amp;nbsp;(see&amp;nbsp;&lt;a href="http://stackoverflow.com/questions/6551446/can-i-run-html-files-directly-from-github-instead-of-just-viewing-their-source" target="_blank"&gt;this stackoverflow page&lt;/a&gt;&amp;nbsp;for more information on this translation)&lt;/p&gt;
  412. &lt;p&gt;This is a list of all example pages in the&amp;nbsp;&lt;a href="https://github.com/01org/appframework" target="_blank"&gt;appframework github repository&lt;/a&gt;. They&amp;nbsp;are interesting to check out and its source code is one of the best sources of documentation:&lt;/p&gt;
  413. &lt;ul&gt;
  414. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/index.html" target="_blank"&gt;Kitchensink index.html&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/index.html" target="_blank"&gt;github source code&lt;/a&gt;)&lt;br /&gt; note: sample gives overview of all available vector fonts&lt;/li&gt;
  415. &lt;li&gt;&lt;a href="http://rawgit.com/svdoever/appframework/master/animbase.html" target="_blank"&gt;Kitchensink animbase.html&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/svdoever/appframework/blob/master/index.html" target="_blank"&gt;github source code&lt;/a&gt;)&lt;br /&gt; note: had to fork the appframework repository and make some changed because JQuery and FastClick were not referenced correctly&lt;/li&gt;
  416. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/samples/angular/index.html#main" target="_blank"&gt;Angular todo example&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/samples/angular/index.html" target="_blank"&gt;github source code&lt;/a&gt;)&lt;/li&gt;
  417. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/samples/backbone/index.html" target="_blank"&gt;Backbone todo example&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/samples/backbone/index.html" target="_blank"&gt;github source code&lt;/a&gt;)&lt;/li&gt;
  418. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/samples/react/index.html" target="_blank"&gt;React todo example&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/samples/react/index.html" target="_blank"&gt;github source &amp;nbsp;code&lt;/a&gt;)&lt;br /&gt; note: this is a very simplistic React example, I had some more trouble to get multiple panels provided by React rendering working&lt;/li&gt;
  419. &lt;li&gt;&lt;a href="http://rawgit.com/svdoever/appframework/master/lancaster/index.html" target="_blank"&gt;Lancaster demo&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/svdoever/appframework/blob/master/lancaster/index.html" target="_blank"&gt;github source code&lt;/a&gt;)&lt;br /&gt; note: had to fork the appframework repository and make some changed because JQuery and FastClick were not referenced correctly&lt;/li&gt;
  420. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/drawer.html" target="_blank"&gt;Template drawer&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/drawer.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  421. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/form.html" target="_blank"&gt;Template form&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/form.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  422. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/gridview.html" target="_blank"&gt;Template gridview&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/gridview.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  423. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/listview.html" target="_blank"&gt;Template listview&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/listview.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  424. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/loginview.html" target="_blank"&gt;Template loginview&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/loginview.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  425. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/swipedelete.html" target="_blank"&gt;Template swipedelete&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/swipedelete.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  426. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/templates/tabview.html" target="_blank"&gt;Template tabview&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/templates/tabview.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  427. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/jquery-widgets/af.lockscreen.html" target="_blank"&gt;Widget lockscreen&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/jquery-widgets/af.lockscreen.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  428. &lt;li&gt;&lt;a href="http://rawgit.com/01org/appframework/master/jquery-widgets/af.popup.html" target="_blank"&gt;Widget popup&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/01org/appframework/blob/master/jquery-widgets/af.popup.html" target="_blank"&gt;github source code)&lt;/a&gt;&lt;/li&gt;
  429. &lt;/ul&gt;
  430. &lt;p&gt;I think it might be a good idea if the intel team would give the appframework documentation some more love, and include the links as described above.&lt;/p&gt;
  431. </description><pubDate>Fri, 17 Jul 2015 22:19:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/intel-appframework-installation-and-documentation</guid><category>appframework</category><category>Mobile Development</category></item><item><title>AngularJS 2 and TypeScript... some work to do...</title><link>https://weblogs.asp.net:443/soever/angularjs-2-and-typescript-some-work-to-do</link><description>&lt;p&gt;After reading a great "First impressions" post on AngularJS 2 (&lt;a href="http://blog.mgechev.com/2015/04/06/angular2-first-impressions/"&gt;http://blog.mgechev.com/2015/04/06/angular2-first-impressions/&lt;/a&gt;) I headed over to the code repository of AngularJS 2 to see how they write their code now in my favorite front-end language: TypeScript. After looking at some of the code it is clear that the team has still some TypeScript to learn. A little example of something you find in most of the code: for example in the file &lt;a href="https://github.com/angular/angular/blob/master/modules/angular2/src/render/api.ts:"&gt;https://github.com/angular/angular/blob/master/modules/angular2/src/render/api.ts:&lt;/a&gt;&lt;/p&gt;&lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;export class &lt;/span&gt;EventBinding {&lt;br /&gt;    &lt;span style="color: #660e7a; font-weight: bold;"&gt;fullName&lt;/span&gt;: &lt;span style="color: #000080; font-weight: bold;"&gt;string&lt;/span&gt;;  &lt;span style="color: #808080; font-style: italic;"&gt;// name/target:name, e.g "click", "window:resize"&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #660e7a; font-weight: bold;"&gt;source&lt;/span&gt;: ASTWithSource;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #000080; font-weight: bold;"&gt;constructor&lt;/span&gt;(fullName: &lt;span style="color: #000080; font-weight: bold;"&gt;string&lt;/span&gt;, source: ASTWithSource) {&lt;br /&gt;        &lt;span style="color: #000080; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #660e7a; font-weight: bold;"&gt;fullName &lt;/span&gt;= fullName;&lt;br /&gt;        &lt;span style="color: #000080; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #660e7a; font-weight: bold;"&gt;source &lt;/span&gt;= source;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;But one of the features of TypeScript is parameter property declaration and is shorthand for declaring a property with the same name as the parameter and initializing it with the value of the parameter. This would reduce the above code to:&lt;/p&gt;&lt;pre style="font-family: Menlo; font-size: 10pt;"&gt;&lt;span style="color: #000080; font-weight: bold;"&gt;export class &lt;/span&gt;EventBinding {&lt;br /&gt;    &lt;span style="color: #000080; font-weight: bold;"&gt;constructor&lt;/span&gt;(private fullName: &lt;span style="color: #000080; font-weight: bold;"&gt;string&lt;/span&gt;, private source: ASTWithSource) {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;See chapter 8.3.1. of the &lt;a href="http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf" target="_blank"&gt;TypeScript language specification.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And this is a really simple example. The code is full of this kind of initialization code.&lt;/p&gt;
  432. </description><pubDate>Sat, 23 May 2015 22:36:09 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/angularjs-2-and-typescript-some-work-to-do</guid></item><item><title>Building an Ionic hybrid mobile app with TypeScript</title><link>https://weblogs.asp.net:443/soever/ionictypescript</link><description>&lt;p&gt;Presentation based on experiences of building a hybrid mobile app using the Ionic framework, Cordova, AngularJS and TypeScript.&lt;/p&gt;
  433. &lt;p&gt;The app we have built is for &lt;a href="https://play.google.com/store/apps/details?id=com.elsevier.nextens&amp;amp;hl=en" title="Android" target="_blank"&gt;Android&lt;/a&gt; and &lt;a href="https://itunes.apple.com/nl/app/elsevier-nextens/id902737411?mt=8" title="iOS" target="_blank"&gt;iOS&lt;/a&gt;.&lt;/p&gt;
  434. &lt;p&gt;&lt;iframe src="//www.slideshare.net/slideshow/embed_code/43898307" width="476" height="400" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;
  435. </description><pubDate>Mon, 26 Jan 2015 13:00:11 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/ionictypescript</guid><category>angularjs</category><category>ionic</category><category>mobile</category><category>cordova</category><category>hybrid</category><category>typescript</category></item><item><title>Cordova – file-transfer, unzip and present adventures</title><link>https://weblogs.asp.net:443/soever/cordova-file-transfer-unzip-and-present-adventures</link><description>&lt;p&gt;For a hybrid project I have a very simple requirement: download zip file, unzip it, serve content on a page from artifacts (html text, images).&lt;/p&gt;
  436. &lt;p&gt;I started with &lt;a href="http://xdk-software.intel.com/" target="_blank"&gt;Intel XDK&lt;/a&gt;, an environment I did some other work with. A great integrated development environment, but some of its big problems: lagging behind in version of Cordova, fixed set of selected plugins, no possibility to include other plugins. Because I wanted to unzip, I tried it with a Javascript only solution &lt;a href="http://gildas-lormeau.github.io/zip.js/" target="_blank"&gt;zip.js&lt;/a&gt;. The problem I had was that it worked if I downloaded the zip file over http using &lt;em&gt;importHttpContent()&lt;/em&gt;, but I could&amp;rsquo;t get it working with loading from the local file system. Another problem I had was with where files ended up on different devices: in &lt;strong&gt;/&lt;/strong&gt; on wp8, on &lt;strong&gt;/storage/sdcard0&lt;/strong&gt; on Android, and on iOS in even another location.&lt;/p&gt;
  437. &lt;p&gt;I decided to go with plain &lt;a href="http://cordova.apache.org/" target="_blank"&gt;Cordova&lt;/a&gt;, with the command-line commands. That was a good decision. It was now possible to use the latest version (3.4 at time of writing), and use the new &lt;a href="https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md" target="_blank"&gt;file&lt;/a&gt; and &lt;a href="https://github.com/apache/cordova-plugin-file-transfer/blob/master/doc/index.md" target="_blank"&gt;file-transfer&lt;/a&gt; plugins that now support a huge improvement to hybrid development: the &lt;strong&gt;cdvfile &lt;/strong&gt;protocol. Files can now be addressed with respect to one multi-platform root: cdvfile://, rather than through device-specific paths. There is also a great plugin available to &lt;a href="https://github.com/MobileChromeApps/zip" target="_blank"&gt;unzip&lt;/a&gt; that understands the new cdvfile:// notation as well. I ended up with a simple example to showcase the download, unzip and present case. To get it working execute the following commands with a &lt;a href="http://phonegap-tips.com/articles/the-nodejs-command-line-interface-for-phonegap.html" target="_blank"&gt;Cordova 3.4 installation&lt;/a&gt;:&lt;/p&gt;
  438. &lt;ol&gt;
  439. &lt;li&gt;cordova create Cordova-TransferUnzipPresent com.svdoever.tranferunzippresent TransferUnzipPresent&lt;/li&gt;
  440. &lt;li&gt;cd Cordova-TransferUnzipPresent&lt;/li&gt;
  441. &lt;li&gt;cordova platform add android&lt;/li&gt;
  442. &lt;li&gt;cordova plugin add org.apache.cordova.file&lt;/li&gt;
  443. &lt;li&gt;cordova plugin add org.apache.cordova.file-transfer&lt;/li&gt;
  444. &lt;li&gt;cordova plugin add org.chromium.zip&lt;/li&gt;
  445. &lt;li&gt;&lt;em&gt;Replace code in &lt;strong&gt;www\index.html&lt;/strong&gt; with the code below&lt;/em&gt;&lt;/li&gt;
  446. &lt;li&gt;cordova emulate android&lt;/li&gt;
  447. &lt;/ol&gt;
  448. &lt;p&gt;Works with iOS platform as well. The zip plugin does not work on wp8 (yet).&lt;/p&gt;
  449. &lt;p&gt;The code:&lt;/p&gt;
  450. &lt;pre class="code"&gt;&lt;span style="background: white; color: #006400;"&gt;&amp;lt;!-- Code by Serge van den Oever, http://weblogs.asp.net/soever --&amp;gt;
  451. &amp;lt;!-- Using Cordova 3.4 with the following plugins: --&amp;gt;
  452. &amp;lt;!-- 'org.apache.cordova.file' (version 1.0.1), 'org.apache.cordova.file-transfer' (0.4.2), 'org.chromium.zip' (2.0.0)  --&amp;gt;
  453. &lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;!DOCTYPE &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;html&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  454. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;html&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  455. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;head&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  456.    &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;title&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: white; color: black;"&gt;Cordova Download Unzip Display Sample&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;title&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  457.    &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;meta &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;http-equiv&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;="Content-type" &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;content&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;="text/html; charset=utf-8"&amp;gt;
  458.    &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;meta &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;name&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;="viewport" &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;content&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"&amp;gt;
  459.    &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;script &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;src&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;="cordova.js"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;script&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  460. &amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;head&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  461. &lt;p&gt;&amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;body&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  462. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;button &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;id&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;btnLoad&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background: white; color: black;"&gt;Load&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;button&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  463. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;button &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;id&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;btnUnzip&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background: white; color: black;"&gt;Unzip&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;button&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  464. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;hr&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;/&amp;gt;
  465. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;div &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;id&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;statusPlace&amp;quot;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;div&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  466. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;hr&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;/&amp;gt;
  467. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;img &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;id&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;imgPlace&amp;quot; &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;src&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;http://lorempixel.com/320/200&amp;quot;&amp;gt;
  468. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;br&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;/&amp;gt;
  469. &amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;div &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;id&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;txtPlace&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background: white; color: black;"&gt;TEXT COMES HERE&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;div&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;&lt;/p&gt;
  470. &lt;p&gt;&amp;lt;&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;script &lt;/span&gt;&lt;span style="background: white; color: red;"&gt;type&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;=&amp;quot;application/javascript&amp;quot;&amp;gt;
  471. &lt;/span&gt;&lt;span style="background: white; color: black;"&gt;document.addEventListener(&amp;quot;deviceready&amp;quot;, onDeviceReady, false);&lt;/p&gt;
  472. &lt;pre&gt;&lt;code&gt;function registerHandlers() {
  473.    document.getElementById(&amp;quot;btnLoad&amp;quot;).onclick = function() {
  474.        var that = this,
  475.                App = new DownloadApp(),
  476.                fileName = &amp;quot;ft-p.zip&amp;quot;,
  477.                uri = encodeURI(&amp;quot;https://dl.dropboxusercontent.com/u/7197720/ftpack.zip&amp;quot;),
  478.                folderName = &amp;quot;content&amp;quot;;
  479.        console.log(&amp;quot;load button clicked&amp;quot;);
  480.        document.getElementById(&amp;quot;statusPlace&amp;quot;).innerHTML += &amp;quot;&amp;amp;lt;br/&amp;amp;gt;Loading: &amp;quot; + uri;
  481.        App.load(uri, folderName, fileName,
  482.                /*progress*/function(percentage) { document.getElementById(&amp;quot;statusPlace&amp;quot;).innerHTML += &amp;quot;&amp;amp;lt;br/&amp;amp;gt;&amp;quot; + percentage + &amp;quot;%&amp;quot;; },
  483.                /*success*/function(entry) { document.getElementById(&amp;quot;statusPlace&amp;quot;).innerHTML += &amp;quot;&amp;amp;lt;br/&amp;amp;gt;Zip saved to: &amp;quot; + entry.toURL(); },
  484.                /*fail*/function() { document.getElementById(&amp;quot;statusPlace&amp;quot;).innerHTML += &amp;quot;&amp;amp;lt;br/&amp;amp;gt;Failed load zip: &amp;quot; + that.uri; }
  485.        );
  486.    };
  487.    document.getElementById(&amp;quot;btnUnzip&amp;quot;).onclick = function() {
  488.        var that = this,
  489.                App = new DownloadApp(),
  490.                fileName = &amp;quot;ft-p.zip&amp;quot;,
  491.                folderName = &amp;quot;content&amp;quot;;
  492.        console.log(&amp;quot;zip button clicked&amp;quot;);
  493.        App.unzip(folderName, fileName,
  494.                /*success*/function() { alert(&amp;quot;Unzipped and assigned&amp;quot;); },
  495.                /*fail*/function(error) { alert(&amp;quot;Unzip failed: &amp;quot; + error.code); }
  496.        );
  497.    };
  498. }
  499.  
  500. function onDeviceReady() {
  501.    // navigator.splashscreen.hide();
  502.    document.getElementById(&amp;quot;statusPlace&amp;quot;).innerHTML += &amp;quot;&amp;amp;lt;br/&amp;amp;gt;deviceready event received&amp;quot;;
  503.    registerHandlers();
  504. }
  505.  
  506. var DownloadApp = function() {
  507. }
  508.  
  509. DownloadApp.prototype = {
  510.    load: function(uri, folderName, fileName, progress, success, fail) {
  511.        var that = this;
  512.        that.progress = progress;
  513.        that.success = success;
  514.        that.fail = fail;
  515.        filePath = &amp;quot;&amp;quot;;
  516.  
  517.        that.getFilesystem(
  518.                function(fileSystem) {
  519.                    console.log(&amp;quot;GotFS&amp;quot;);
  520.                    that.getFolder(fileSystem, folderName, function(folder) {
  521.                        filePath = folder.toURL() + &amp;quot;/&amp;quot; + fileName;
  522.                        that.transferFile(uri, filePath, progress, success, fail);
  523.                    }, function(error) {
  524.                        console.log(&amp;quot;Failed to get folder: &amp;quot; + error.code);
  525.                        typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  526.                    });
  527.                },
  528.                function(error) {
  529.                    console.log(&amp;quot;Failed to get filesystem: &amp;quot; + error.code);
  530.                    typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  531.                }
  532.        );
  533.    },
  534.  
  535.    getFilesystem:function (success, fail) {
  536.        window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
  537.        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, success, fail);
  538.    },
  539.  
  540.    getFolder: function (fileSystem, folderName, success, fail) {
  541.        fileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, success, fail)
  542.    },
  543.  
  544.    transferFile: function (uri, filePath, progress, success, fail) {
  545.        var that = this;
  546.        that.progress = progress;
  547.        that.success = success;
  548.        that.fail = fail;
  549.  
  550.        var transfer = new FileTransfer();
  551.        transfer.onprogress = function(progressEvent) {
  552.            if (progressEvent.lengthComputable) {
  553.                var perc = Math.floor(progressEvent.loaded / progressEvent.total * 100);
  554.                typeof that.progress === 'function' &amp;amp;amp;&amp;amp;amp; that.progress(perc); // progression on scale 0..100 (percentage) as number
  555.            } else {
  556.            }
  557.        };
  558.  
  559.        transfer.download(
  560.                uri,
  561.                filePath,
  562.                function(entry) {
  563.                    console.log(&amp;quot;File saved to: &amp;quot; + entry.toURL());
  564.                    typeof that.success === 'function' &amp;amp;amp;&amp;amp;amp; that.success(entry);
  565.                },
  566.                function(error) {
  567.                    console.log(&amp;quot;An error has occurred: Code = &amp;quot; + error.code);
  568.                    console.log(&amp;quot;download error source &amp;quot; + error.source);
  569.                    console.log(&amp;quot;download error target &amp;quot; + error.target);
  570.                    console.log(&amp;quot;download error code &amp;quot; + error.code);
  571.                    typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  572.                }
  573.        );
  574.    },
  575.  
  576.    unzip: function(folderName, fileName, success, fail) {
  577.        var that = this;
  578.        that.success = success;
  579.        that.fail = fail;
  580.  
  581.        zip.unzip(&amp;quot;cdvfile://localhost/persistent/&amp;quot; + folderName + &amp;quot;/&amp;quot; + fileName,
  582.                  &amp;quot;cdvfile://localhost/persistent/&amp;quot; + folderName,
  583.                function(code) {
  584.                    console.log(&amp;quot;result: &amp;quot; + code);
  585.                    that.getFilesystem(
  586.                            function(fileSystem) {
  587.                                console.log(&amp;quot;gotFS&amp;quot;);
  588.                                that.getFolder(fileSystem, folderName + &amp;quot;/ftpack&amp;quot;, function (folder) {
  589.                                    document.getElementById(&amp;quot;imgPlace&amp;quot;).src = folder.nativeURL + &amp;quot;/img.jpg&amp;quot;;
  590.                                    folder.getFile(&amp;quot;text.html&amp;quot;, {create: false}, function (fileEntry) {
  591.                                        fileEntry.file(function(file) {
  592.                                            var reader = new FileReader();
  593.                                            reader.onloadend = function (evt) {
  594.                                                console.log(&amp;quot;Read as text&amp;quot;);
  595.                                                console.log(evt.target.result);
  596.                                                document.getElementById(&amp;quot;txtPlace&amp;quot;).innerHTML = evt.target.result;
  597.                                                typeof that.success === ' function &amp;amp;amp;&amp;amp;amp; that.success();'
  598.                                            };
  599.                                            reader.readAsText(file);
  600.                                        }, function(error) {
  601.                                            console.log(&amp;quot;Failed to get file&amp;quot;);
  602.                                            typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  603.                                        });
  604.                                    }, function (error) {
  605.                                        console.log(&amp;quot;failed to get file: &amp;quot; + error.code);
  606.                                        typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  607.                                    });
  608.                                }, function (error) {
  609.                                    console.log(&amp;quot;failed to get folder: &amp;quot; + error.code);
  610.                                    typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  611.                                });
  612.                            }, function(error) {
  613.                                console.log(&amp;quot;failed to get filesystem: &amp;quot; + error.code);
  614.                                typeof that.fail === 'function' &amp;amp;amp;&amp;amp;amp; that.fail(error);
  615.                            });
  616.                }
  617.        );
  618.    }
  619. }
  620. &lt;/code&gt;&lt;/pre&gt;
  621. &lt;p&gt;&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;script&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  622. &amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;body&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  623. &amp;lt;/&lt;/span&gt;&lt;span style="background: white; color: maroon;"&gt;html&lt;/span&gt;&lt;span style="background: white; color: blue;"&gt;&amp;gt;
  624. &lt;/span&gt;&lt;/pre&gt;&lt;/p&gt;
  625. </description><pubDate>Fri, 21 Mar 2014 11:40:00 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/cordova-file-transfer-unzip-and-present-adventures</guid><category>Cordova</category><category>Phonegap</category></item><item><title>AngularJS–don’t use self-closing div tags</title><link>https://weblogs.asp.net:443/soever/angularjs-don-t-use-self-closing-div-tags</link><description>&lt;p&gt;I had a piece of code that gave strange results in AngularJS. The issue was that I used a self closing &amp;lt;div /&amp;gt; tag instead of &amp;lt;div&amp;gt;…&amp;lt;/div&amp;gt;. Self closing div tags are not supported in HTML5. The complete code can be found at &lt;a title="http://stackoverflow.com/questions/21552560/angularjs-bug-in-ng-include-when-not-using-jquery" href="http://stackoverflow.com/questions/21552560/angularjs-bug-in-ng-include-when-not-using-jquery"&gt;http://stackoverflow.com/questions/21552560/angularjs-bug-in-ng-include-when-not-using-jquery&lt;/a&gt; and the plunker &lt;a href="http://plnkr.co/edit/O3NSb2VEwAEDrkmtoKZ6?p=preview"&gt;http://plnkr.co/edit/O3NSb2VEwAEDrkmtoKZ6?p=preview&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;My wrong code was written as:&lt;/p&gt;  &lt;pre&gt;&lt;code&gt;&amp;lt;script id=&amp;quot;paragraphTmpl.html&amp;quot; type=&amp;quot;text/ng-template&amp;quot;&amp;gt;
  626.    &amp;lt;h4&amp;gt;{{paragraph.Title}}&amp;lt;/h4&amp;gt;
  627.    &amp;lt;!-- comment line below to have the paragraphs render correctly --&amp;gt;
  628.    &amp;lt;div ng-bind-html=&amp;quot;trustAsHtml(paragraph.Content)&amp;quot;/&amp;gt;
  629.    &amp;lt;ng-include ng-repeat=&amp;quot;paragraph in paragraph.Paragraphs&amp;quot;
  630.                src=&amp;quot;'paragraphTmpl.html'&amp;quot;&amp;gt;
  631. &amp;lt;/script&amp;gt;
  632. &lt;p&gt;&amp;lt;div&amp;gt;
  633. &amp;lt;h3&amp;gt;{{chaptercontent.Title}}&amp;lt;/h3&amp;gt;&lt;/p&gt;
  634. &lt;pre&gt;&lt;code&gt;&amp;amp;lt;div ng-bind-html=&amp;amp;quot;trustAsHtml(chaptercontent.Content)&amp;amp;quot;/&amp;amp;gt;
  635. &amp;amp;lt;ng-include ng-repeat=&amp;amp;quot;paragraph in chaptercontent.Paragraphs&amp;amp;quot;
  636.            src=&amp;amp;quot;'paragraphTmpl.html'&amp;amp;quot;/&amp;amp;gt;
  637. &lt;/code&gt;&lt;/pre&gt;
  638. &lt;p&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
  639. &lt;pre&gt;&lt;code&gt;&lt;font face="Verdana"&gt;It works fine when jQuery is included, but not when you use the AngularJS JQLite implementation.&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;
  640. &lt;pre&gt;&lt;code&gt;&lt;font face="Verdana"&gt;When &amp;lt;div ng-bind-html=&amp;quot;trustAsHtml(chaptercontent.Content)&amp;quot;&amp;gt;&amp;lt;/div&amp;gt; is used, the code works correctly.&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;
  641. </description><pubDate>Tue, 04 Feb 2014 15:18:24 GMT</pubDate><guid isPermaLink="true">https://weblogs.asp.net:443/soever/angularjs-don-t-use-self-closing-div-tags</guid><category>AngularJS</category></item></channel></rss>

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//weblogs.asp.net/soever/rss.aspx

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda