<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8886165919970940400</id><updated>2020-02-28T14:15:08.655+01:00</updated><category term="lotus"/><category term="domino"/><category term="development"/><category term="xpages"/><category term="administration"/><category term="ibm"/><category term="OffTopic"/><category term="notes"/><category term="quickr"/><category term="LotusScript"/><category term="deployment"/><category term="troubleshooting"/><category term="JavaScript"/><category term="symphony"/><category term="ApplicationIsBorn"/><category term="REST"/><category term="dnd-series"/><category term="java"/><category term="jquery"/><category term="linux"/><category term="installation"/><category term="sametime"/><category term="dms"/><category term="document management"/><category term="scrum"/><category term="configuration"/><category term="events"/><category term="exchange"/><category term="microsoft"/><category term="red hat"/><category term="requirement management"/><category term="windows 7"/><category term="BlackBerry"/><category term="Firefox"/><category term="Internet"/><category term="apache"/><category term="aws"/><category term="book"/><category term="bootstrap"/><category term="chart"/><category term="errata"/><category term="framework"/><category term="mercurial"/><category term="oo"/><category term="programming"/><category term="sharepoint"/><category term="smb"/><category term="vmware"/><category term="web services"/><category term="BES"/><category term="PowerShell"/><category term="calendar"/><category term="certification"/><category term="connections"/><category term="css"/><category term="gtd"/><category term="ldap"/><category term="rational"/><category term="teamstudio"/><category term="traveler"/><category term="ui"/><title type='text'>Lotus Shade of Yellow</title><subtitle type='html'>some things IBM - many things Lotus - work - life - family</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.squareone.ba/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>90</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-2004798623679383041</id><published>2014-10-23T11:01:00.000+02:00</published><updated>2014-10-23T11:10:00.076+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="apache"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="web services"/><title type='text'>How to use TLS and SHA-2 certificates in Domino Web Service Consumer</title><content type='html'>We have a solution that is used by thousands of public sector workers.&lt;br /&gt;The solution relies heavily on interacting with various web services provided by the tax authority, social welfare and health authorities and others.&lt;br /&gt;So we have a lots of Domino web service consumers and providers that require both SSL and authentication using certificates.&lt;br /&gt;Like many others we were aware of Domino&#39;s lack of support for TLS and SHA-2, but the web services providers were not insisting on them, so everything worked fine. Until last Friday, when one after the other turned off support for SSL v3. We could just watch as all our consumers stopped working.&lt;br /&gt;Despite the recent technotes (&lt;a href=&quot;http://www-01.ibm.com/support/docview.wss?uid=swg21418982&quot; target=&quot;_blank&quot;&gt;1418982&lt;/a&gt; and &lt;a href=&quot;http://www-01.ibm.com/support/docview.wss?uid=swg21687167&quot; target=&quot;_blank&quot;&gt;1687167&lt;/a&gt;) stating that the fix will be available in &quot;the next several weeks&quot;, we needed a working solution immediately.&lt;br /&gt;We are familiar and have been using reverse proxies before. But it didn&#39;t seem they could be used in our case. A reverse proxy is often positioned in front of a server (provider), but in this case our Domino servers were clients (consumers).&lt;br /&gt;But, it turns out that you actually can use reverse proxy even in this use case.&lt;br /&gt;What happens is that our Domino web service consumers first contact the Apache reverse proxy using SSL, but without any authentication. Then Apache contacts the web service provider using the certificate that Domino used previously. Since Apache supports SHA-2, we can use new certificates to authenticate ourselves.&lt;br /&gt;After Apache and web service provider finished handshake (using TLS) and authentication, it is free for the web service consumer in Domino to do its stuff.&lt;br /&gt;This means that Domino doesn&#39;t need to do any of the SHA-2 and TLS stuff. It only needs to communicate with the Apache proxy using SSL v3, which it supports.&lt;br /&gt;The setup is easy. You&#39;ll need an Apache server (obviously), we installed our in a CentOS virtual machine:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;yum install httpd mod_ssl&lt;/pre&gt;&lt;br /&gt;Once you have Apache installed, open the configuration file in a text editor:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;vim /etc/httpd/conf/httpd.conf&lt;/pre&gt;&lt;br /&gt;Scroll down to the end of file and enter the following:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;&amp;lt;VirtualHost&amp;nbsp;*:8443&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Turn&amp;nbsp;off&amp;nbsp;forward&amp;nbsp;proxy&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProxyRequests&amp;nbsp;Off&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Communication&amp;nbsp;with&amp;nbsp;Domino&amp;nbsp;is&amp;nbsp;using&amp;nbsp;SSL,&amp;nbsp;so&amp;nbsp;we&amp;nbsp;need&amp;nbsp;SSL&amp;nbsp;support&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLEngine&amp;nbsp;On&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLCertificateFile&amp;nbsp;/etc/pki/tls/certs/localhost.crt&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLCertificateKeyFile&amp;nbsp;/etc/pki/tls/private/localhost.key&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;This&amp;nbsp;is&amp;nbsp;necessary&amp;nbsp;for&amp;nbsp;authentication&amp;nbsp;to&amp;nbsp;work.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLProxyEngine&amp;nbsp;On&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;This&amp;nbsp;is&amp;nbsp;Domino&amp;nbsp;certificate&amp;nbsp;including&amp;nbsp;private&amp;nbsp;key&amp;nbsp;saved&amp;nbsp;as&amp;nbsp;unecrypted&amp;nbsp;pem&amp;nbsp;file.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLProxyMachineCertificateFile&amp;nbsp;/etc/httpd/certs/domino-cert.pem&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;This&amp;nbsp;is&amp;nbsp;list&amp;nbsp;of&amp;nbsp;CA&amp;nbsp;certificates&amp;nbsp;necessary&amp;nbsp;to&amp;nbsp;authenticate&amp;nbsp;the&amp;nbsp;provider.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSLProxyCACertificateFile&amp;nbsp;/etc/httpd/certs/provider-cert.pem&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Redirection&amp;nbsp;rules&amp;nbsp;are&amp;nbsp;in&amp;nbsp;this&amp;nbsp;case&amp;nbsp;very&amp;nbsp;simple&amp;nbsp;-&amp;nbsp;redirect&amp;nbsp;everything&amp;nbsp;that&amp;nbsp;comes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;to&amp;nbsp;the&amp;nbsp;proxy&amp;nbsp;to&amp;nbsp;the&amp;nbsp;web&amp;nbsp;service&amp;nbsp;provider&amp;nbsp;address.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProxyPass&amp;nbsp;/&amp;nbsp;https://ws.provider.com/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProxyPassReverse&amp;nbsp;/&amp;nbsp;https://ws.provider.com/&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Allow&amp;nbsp;only&amp;nbsp;connections&amp;nbsp;from&amp;nbsp;Intranet.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Proxy&amp;nbsp;*&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Order&amp;nbsp;deny,allow&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Deny&amp;nbsp;from&amp;nbsp;all&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Allow&amp;nbsp;from&amp;nbsp;172.20.20.0/24&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/Proxy&amp;gt;&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Just a few things to mention here:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You should be able to use certificate and key installed by default with Apache, as they are only used to secure communication between the Domino and the proxy.&lt;/li&gt;&lt;li&gt;Domino key and certificate must be in unencrypted pem format. Use openssl to convert if necessary. If you should get error message about missing or encrypted private key, open your pem certificate and confirm that it includes &lt;code&gt;&lt;b&gt;RSA&lt;/b&gt;&lt;/code&gt; in lines &lt;code&gt;-----BEGIN RSA PRIVATE KEY-----&lt;/code&gt; and &lt;code&gt;-----END RSA PRIVATE KEY-----&lt;/code&gt;.&lt;br /&gt;openssl sometimes generates certificate without the word RSA and then Apache won&#39;t be able to use it.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That concludes the Apache configuration. The only thing that remains is to modify the web service consumer - find in your code the line where you set endpoint address, something like&lt;br /&gt;&lt;code&gt;https://ws.provider.com/ws/getTemperature&lt;/code&gt;&lt;br /&gt;and change it to&lt;br /&gt;&lt;code&gt;https://proxy.mycompany.com:8443/ws/getTemperature&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And that&#39;s it. We now have working solution for using Domino web services together with TLS and SHA-2 certificates. And we can calmly wait for IBM to implement support for this in Domino.&lt;br /&gt;&lt;br /&gt;A few parting thoughts - the above configuration is using Apache version 2.2.15 and CentOS 6.5. If you are using Debian-based or Red Hat 7 based distribution, the configuration will be somewhat different, but this should put you in the right direction.&lt;br /&gt;I also posted &lt;a href=&quot;http://stackoverflow.com/questions/26468208/how-to-use-tls-and-sha-2-certificates-in-domino-web-service-consumer&quot; target=&quot;_blank&quot;&gt;this question on Stack Overflow&lt;/a&gt;, you might want to keep an eye on it, maybe there is some even easier and better solution. &lt;style type=&quot;text/css&quot;&gt;   .syntaxhighlighter {         overflow-y: hidden !important;         overflow-x: auto !important;      } &lt;/style&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/2004798623679383041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2014/10/how-to-use-tls-and-sha-2-certificates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2004798623679383041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2004798623679383041'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2014/10/how-to-use-tls-and-sha-2-certificates.html' title='How to use TLS and SHA-2 certificates in Domino Web Service Consumer'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-7897320925168471153</id><published>2014-01-05T20:37:00.002+01:00</published><updated>2014-01-05T20:41:36.357+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in XPages - Part 6: Data Attributes</title><content type='html'>&lt;div style=&quot;-moz-border-radius: 4px; -webkit-border-radius: 4px; background-color: #d9edf7; border-radius: 4px; border: 1px solid #bce8f1; color: #3a87ad; margin-bottom: 20px; padding: 8px 35px 8px 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;Enabling the key | label functionality&lt;/h3&gt;This is the first blog post in this year — and it is the last part of this drag-and-drop series.&lt;br /&gt;So far, we have learned how to create fairly advanced drag-and-drop controls. In this last part we&#39;ll learn another technique, which, while not directly related to drag-and-drop, can help in developing applications.&lt;br /&gt;It is often necessary to display one, often more verbose, information to application users, while in the back-end we work with other, more terse and precise, information. For example, we might display a product name to the user, while we prefer to work with the SKU of the product (because it is unique). Or, we display a contact&#39;s name and address, but we work with UNID in the background — because UNID makes it easy to get that contact&#39;s document from the database.&lt;br /&gt;In other words, we work with key | label pairs.&lt;br /&gt;If you are familiar with the &quot;classic&quot; Notes development, you have probably used key | label pairs for Combobox, Listbox, Dialog list, Checkbox or Radio button fields. Some of the XPages controls, such as Combo Box and List Box, also allow for the use of key | label pairs.&lt;br /&gt;So, how do we use key | label pairs with our drag-and-drop controls? The answer is by using HTML5 data attributes. The HTML5 data attributes allow you to specify application specific attributes that you can assign to HTML tags, while maintaining validity of the HTML markup.&lt;br /&gt;Let&#39;s take an example. Assume you are creating an application that allows users to follow stock price of their favourite car manufacturers. You can use a drag-and-drop control for that, but instead of sending the name of the car manufacturers back to the server, you want to send their stock symbols. Something like this:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ZdDvJyTXxAU/UsmuNjswZCI/AAAAAAAACzU/vpb7zPVrK8E/s1600/dnd6-data_attributes.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ZdDvJyTXxAU/UsmuNjswZCI/AAAAAAAACzU/vpb7zPVrK8E/s1600/dnd6-data_attributes.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Here is the basic HTML code: &lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;div class=&amp;quot;sideBySide&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ul class=&amp;quot;source connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;BMW&amp;quot;&amp;gt;BMW&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;DDFAIF&amp;quot;&amp;gt;Daimler&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;FIADF&amp;quot;&amp;gt;Fiat&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;F&amp;quot;&amp;gt;Ford&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;POAHF&amp;quot;&amp;gt;Porsche&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;TSLA&amp;quot;&amp;gt;Tesla&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li data-stock-symbol=&amp;quot;VLKAF&amp;quot;&amp;gt;Volkswagen&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ul class=&amp;quot;target connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The majority of the code should be familiar by now. The only new thing is the&amp;#160;&lt;code&gt;data-stock-symbol&lt;/code&gt;&amp;#160;attribute, which, in fact is an HTML5 data attribute.&lt;/p&gt;&lt;p&gt;The data attributes consist of a mandatory prefix&amp;#160;&lt;code&gt;data-&lt;/code&gt;&amp;#160;and a lowercase name. By convention, hyphens are used instead of spaces. The content of a data attribute can be anything that can be represented as a string (such as JSON).&lt;/p&gt;&lt;p&gt;The content can be read and set using three different techniques. For the sake of simplicity, let&#39;s take the following example:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;manufacturer&amp;quot; data-stock-symbol=&amp;quot;DDFAIF&amp;quot;&amp;gt;Daimler&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The most natural way would be to use the native HTML5 dataset API. You would use it like this:&lt;/p&gt;&lt;pre class=&quot;brush: javascript&quot;&gt;&lt;br /&gt;var manufacturer = document.getElementById(&quot;manufacturer&quot;);&lt;br /&gt;// get value&lt;br /&gt;var stock = manufacturer.dataset.stockSymbol;&lt;br /&gt;// set value&lt;br /&gt;manufacturer.dataset.stockSymbol = &amp;quot;DDFAIF&amp;quot;;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;As you can see, you access the data attribute by stripping the&amp;#160;&lt;code&gt;data-&lt;/code&gt;&amp;#160;prefix, removing hyphens from the attribute name and converting it to camel case, so that&amp;#160;&lt;code&gt;data-stock-symbol&lt;/code&gt;&amp;#160;becomes&amp;#160;&lt;code&gt;stockSymbol&lt;/code&gt;&amp;#160;as in the example above.&lt;/p&gt;&lt;p&gt;Unfortunately, Internet Explorer 10 and below do not support the HTML5 dataset API, so you&#39;ll probably want to use one of the other two techniques.&lt;/p&gt;&lt;p&gt;The jQuery data() method will be the best option for the most uses. It is used like this:&lt;/p&gt;&lt;pre class=&quot;brush: javascript&quot;&gt;&lt;br /&gt;var manufacturer = $(&quot;#manufacturer&quot;);&lt;br /&gt;// get value&lt;br /&gt;var stock = manufacturer.data(&amp;quot;stock-symbol&amp;quot;);&lt;br /&gt;// set value&lt;br /&gt;manufacturer.data(&amp;quot;stock-symbol&amp;quot;, &amp;quot;DDFAIF&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Finally, there are the standard JavaScript &amp;#160;&lt;code&gt;getAttribute()&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;setAttribute()&lt;/code&gt;&amp;#160;methods, that you could use in case you don&#39;t have jQuery available:&lt;/p&gt;&lt;pre class=&quot;brush: javascript&quot;&gt;&lt;br /&gt;var manufacturer = document.getElementById(&quot;manufacturer&quot;);&lt;br /&gt;// get value&lt;br /&gt;var stock = manufacturer.getAttribute(&amp;quot;data-stock-symbol&amp;quot;);&lt;br /&gt;// set value&lt;br /&gt;manufacturer.setAttribute(&amp;quot;data-stock-symbol&amp;quot;, &amp;quot;DDFAIF&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you want to learn more about the HTML5 data attributes, I recommend you start with this&amp;#160;&lt;a href=&quot;http://www.sitepoint.com/use-html5-data-attributes/&quot; target=&quot;new&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Applying it to XPages&lt;/h3&gt;&lt;p&gt;Now, let&#39;s take a look at how to apply data attributes in an XPages application. Once again, let&#39;s use the stock-choosing drag-and-drop control.&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;ul class=&amp;quot;source connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xp:repeat id=&amp;quot;repeat2&amp;quot; rows=&amp;quot;30&amp;quot; var=&amp;quot;manufacturer&amp;quot; removeRepeat=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:this.value&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;![CDATA[${javascript:&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;return [[&amp;quot;BMW&amp;quot;, &amp;quot;BMW&amp;quot;], [&amp;quot;Daimler&amp;quot;, &amp;quot;DDFAIF&amp;quot;], [&amp;quot;Fiat&amp;quot;, &amp;quot;FIADF&amp;quot;], [&amp;quot;Ford&amp;quot;, &amp;quot;F&amp;quot;], [&amp;quot;Porsche&amp;quot;, &amp;quot;POAHF&amp;quot;], [&amp;quot;Tesla&amp;quot;, &amp;quot;TSLA&amp;quot;], [&amp;quot;Volkswagen&amp;quot;, &amp;quot;VLKAF&amp;quot;]];&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}]]&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xp:this.value&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:text escape=&amp;quot;true&amp;quot; id=&amp;quot;sourceLI&amp;quot; value=&amp;quot;#{manufacturer[0]}&amp;quot; tagName=&amp;quot;li&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:this.attrs&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:attr name=&amp;quot;data-stock-symbol&amp;quot; value=&amp;quot;#{manufacturer[1]}&amp;quot;&amp;gt;&amp;lt;/xp:attr&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xp:this.attrs&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xp:text&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/xp:repeat&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The code is very similar to the code we used in our&amp;#160;&lt;a href=&quot;http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_29.html#dnd&quot;&gt;first example&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You should note the following changes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Once again, a static array is used as a data source for the repeat control. This time, it is a two-dimensional array containing manufacturer&#39;s name and stock symbol. In a real application, you would probably use a view and itterate over documents containing necessary data.&lt;/li&gt;&lt;li&gt;Computed text control has been extended with&amp;#160;&lt;code&gt;&amp;lt;xp:this.attrs&amp;gt;...&amp;lt;/xp:this.attrs&amp;gt;&lt;/code&gt;&amp;#160;which allows us to define data attributes and set them programmatically.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The JavaScript code for reading data attributes is also very similar to the code we have already used. This is the adjusted code:&lt;/p&gt;&lt;pre class=&quot;brush: javascript&quot;&gt;&lt;br /&gt;var items = [];&lt;br /&gt;$(&amp;quot;ul.target&amp;quot;).children().each(function() {&lt;br /&gt;&amp;#160;&amp;#160;var item = {manufacturer: $(this).data(&amp;quot;stock-symbol&amp;quot;)};&lt;br /&gt;&amp;#160;&amp;#160;items.push(item);&lt;br /&gt;});&lt;br /&gt;var jsonData = JSON.stringify(items);      &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Instead of reading the text of each&amp;#160;&lt;code&gt;li&lt;/code&gt;&amp;#160;element, we read the value of the data attribute. The rest of the implementation is the same as already described above.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Epilogue&lt;/h3&gt;&lt;p&gt;I hope that you have found this blog series useful and that it will help you use drag-and-drop in your applications.&lt;/p&gt;&lt;p&gt;Please let me know if you should have any questions, comments or suggestions.&lt;/p&gt;&lt;style type=&quot;text/css&quot;&gt;   .syntaxhighlighter {         overflow-y: hidden !important;         overflow-x: auto !important;      } &lt;/style&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/7897320925168471153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2014/01/making-drag-and-drop-work-in-xpages.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7897320925168471153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7897320925168471153'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2014/01/making-drag-and-drop-work-in-xpages.html' title='Making drag and drop work in XPages - Part 6: Data Attributes'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ZdDvJyTXxAU/UsmuNjswZCI/AAAAAAAACzU/vpb7zPVrK8E/s72-c/dnd6-data_attributes.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-7215836681452679065</id><published>2013-12-26T12:17:00.002+01:00</published><updated>2013-12-26T12:21:05.573+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="mercurial"/><title type='text'>How to backup your Mercurial server to Amazon S3</title><content type='html'>In the last couple of years, I&#39;ve seen a clear trend towards using established software development methods and techniques when developing Domino applications, such as the use of revision control systems like SVN, Git and Mercurial.&lt;br /&gt;&lt;br /&gt;It seems that majority of developers is using distributed revision control systems like Git or Mercurial. When working in a team, developers use a central repository (i.e. server) to share the code. The services like Bitbucket and GitHub can be used for that purpose, but they cost and, when working on a commercial product, there are always privacy and security concerns.&lt;br /&gt;&lt;br /&gt;A better solution is to setup your own server. And it is fairly easy to do: a while ago I wrote instructions on how to set up a &lt;a href=&quot;http://blog.squareone.ba/2012/01/guide-installing-mercurial-server-on_11.html&quot;&gt;Mercurial server running on a Red Hat Linux server&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One issue that you have to deal with when running your own server is backup.&lt;br /&gt;&lt;br /&gt;One of the simplest, cheapest and most reliable solutions is to use Amazon S3 storage for backups. I have already shown how to use it to &lt;a href=&quot;http://blog.squareone.ba/2012/11/backup-domino-to-amazon-s3-cloud-storage_30.html&quot;&gt;back up Domino server&lt;/a&gt;, and now I want to show you how to backup your Mercurial server.&lt;br /&gt;&lt;br /&gt;First of all, you&#39;ll need two things:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the backup script &lt;code&gt;s3backup.sh&lt;/code&gt;,&lt;/li&gt;&lt;li&gt;&lt;code&gt;s3cmd&lt;/code&gt; utility for uploading files to Amazon S3.&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;-moz-border-radius: 4px; -webkit-border-radius: 4px; background-color: #d9edf7; border-radius: 4px; border: 1px solid #bce8f1; color: #3a87ad; margin-bottom: 20px; padding: 8px 35px 8px 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; The script currently works only on Red Hat-based distributions. If you are running a Debian-based distribution (e.g. Ubuntu) and are interested in the script, let me know and I&#39;ll make necessary modifications.&lt;/div&gt;You can get the script from either the &lt;a href=&quot;https://bitbucket.org/sasabrkic/s3backup&quot;&gt;Bitbucket&lt;/a&gt; (Mercurial) or &lt;a href=&quot;https://github.com/sasabrkic/s3backup-git&quot;&gt;GitHub&lt;/a&gt; repositories.&lt;br /&gt;&lt;br /&gt;You&#39;ll find the s3cmd utility at the &lt;a href=&quot;http://s3tools.org/s3cmd&quot;&gt;S3 Tools site&lt;/a&gt;, together with installation instructions. Once you have installed the utility, run the configuration by executing:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;# s3cmd --configure&lt;/pre&gt;&lt;br /&gt;Enter your access key and secret key when requested. If you do not plan on encrypting the backups, leave the encryption password blank and accept the default path to GPG. Choose whether you want to use HTTPS (I recommend you answer Yes here). Let the utility test the settings and if everything is OK, save the configuration when asked.&lt;br /&gt;&lt;br /&gt;With that out of way, let&#39;s configure the script.&lt;br /&gt;&lt;br /&gt;First of all: you&#39;ll need to run the script as &lt;code&gt;root&lt;/code&gt; user, because the script needs permissions to stop and start the HTTP server service.&lt;br /&gt;&lt;br /&gt;Put the script in a suitable directory — I keep mine in &lt;code&gt;/root/bin&lt;/code&gt;. Make sure the script is executable:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;# chmod u+x s3backup.sh&lt;br /&gt;# ll s3backup.sh&lt;br /&gt;-rwxr--r--. 1 root root 4774 Dec 25 15:47 s3backup.sh&lt;/pre&gt;&lt;br /&gt;Now, open the script in your favourite text editor and set these variables:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;SOURCEDIR&lt;/code&gt;: path to the directory on the Apache server containing your repositories. In my case it is &lt;code&gt;/var/www/vhosts/hg.cs-computing.com/repos&lt;/code&gt; — you specified this location when you installed the Mercurial server, check your installation in case you forgot it. The script will backup everything it finds in this directory.&lt;/li&gt;&lt;li&gt;&lt;code&gt;BACKUPDIR&lt;/code&gt;: path to a directory where backup archives will be created and from where they will be uploaded to Amazon S3. Use whatever location you want (providing you have full access to it). You don&#39;t need to create this directory, it will be created automatically.&lt;/li&gt;&lt;li&gt;&lt;code&gt;LOGDIR&lt;/code&gt;: path to a directory where you want to keep the log files. I keep mine in &lt;code&gt;/var/log/s3backup&lt;/code&gt;, but again, use whatever suits you best. This directory will be created automatically as well.&lt;/li&gt;&lt;li&gt;&lt;code&gt;DAYSTOKEEP&lt;/code&gt;: number of days to keep the log files. The log files older than &lt;code&gt;DAYSTOKEEP&lt;/code&gt; days will be deleted. 14 by default.&lt;/li&gt;&lt;li&gt;&lt;code&gt;HTTPSERVER&lt;/code&gt;: name of your HTTP server service. If you are using Apache on Red Hat this will be &lt;code&gt;httpd&lt;/code&gt;, which is also the default value.&lt;/li&gt;&lt;li&gt;&lt;code&gt;S3DEST&lt;/code&gt;: name of the bucket on Amazon S3 where you want to store backups. You can specify the bucket name like this: &lt;code&gt;s3://your-bucket-name/&lt;/code&gt;. If you have and want to use a folder inside the bucket, specify it like this: &lt;code&gt;s3://your-bucket-name/folder-name/&lt;/code&gt;. Make sure not to forget the trailing slash. It is mandatory in this case!&lt;/li&gt;&lt;/ul&gt;To run the script simply execute it:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;# cd /root/bin&lt;br /&gt;# ./s3backup.sh&lt;/pre&gt;&lt;br /&gt;The script works like this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If the HTTP server is running, it is stopped. I don&#39;t know if this step is necessary: it feels safer to first stop the server and then copy the files (in order to avoid copying files being modified by someone else). On the other hand, stopping the server in the middle of a changeset upload may corrupt the repository as well. I am open for any suggestion on this.&lt;/li&gt;&lt;li&gt;Once the HTTP server is stopped, all files (repositories) from the &lt;code&gt;SOURCEDIR&lt;/code&gt; are copied to the &lt;code&gt;BACKUPDIR&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;As soon as the copy operation is finished, the HTTP server is started again.&lt;/li&gt;&lt;li&gt;The copied repositories are packaged and compressed in a &lt;code&gt;.tar.gz&lt;/code&gt; archive. When the archive is created, the copied repositories are deleted.&lt;/li&gt;&lt;li&gt;The archive is uploaded to the specified Amazon S3 bucket. If the upload is successful, the archive is deleted. Otherwise, it is left in the directory and the script will try to upload it again the next time.&lt;/li&gt;&lt;li&gt;The script checks if some of the log files are older than &lt;code&gt;DAYSTOKEEP&lt;/code&gt; days and deletes them.&lt;/li&gt;&lt;/ol&gt;If you specify &lt;code&gt;-v&lt;/code&gt; (or &lt;code&gt;--verbose&lt;/code&gt;) option, the script will output all log entries to the console as well, which is useful when you run the script manually:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;# ./s3backup.sh -v&lt;/pre&gt;&lt;br /&gt;The recommended way to run the script is by scheduling its execution using &lt;code&gt;cron&lt;/code&gt;. To schedule the execution, run the following command:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;# crontab -e&lt;/pre&gt;&lt;br /&gt;This will open (possibly empty) list of cronjobs in your default text editor. Add the following line:&lt;br /&gt;&lt;pre class=&quot;brush: shell&quot;&gt;15 1 * * * /path/to/script/s3backup.sh &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/pre&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;15 1 * * *&lt;/code&gt; means that this cronjob runs daily at 01:15. Then, the path to the script follows. Finally, you may choose to log the output of the cronjob to a file, or simply trash it like I did in the above line.&lt;br /&gt;&lt;br /&gt;If you want to learn more about the cron, here is a &lt;a href=&quot;http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/&quot;&gt;nice introduction&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I plan on updating the script so it can be used more generally—for example, I plan to add option to skip stopping / starting the web server. Then you can use it to backup any folder to Amazon S3. Let me know if you have comments or suggestions.&lt;br /&gt;&lt;style type=&quot;text/css&quot;&gt;   .syntaxhighlighter {         overflow-y: hidden !important;         overflow-x: auto !important;      } &lt;/style&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/7215836681452679065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/12/how-to-backup-your-mercurial-server-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7215836681452679065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7215836681452679065'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/12/how-to-backup-your-mercurial-server-to.html' title='How to backup your Mercurial server to Amazon S3'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-8259080800448907559</id><published>2013-08-12T22:12:00.000+02:00</published><updated>2014-01-05T20:40:27.402+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in Xpages - Part 5: Advanced example</title><content type='html'>&lt;div style=&quot;-moz-border-radius: 4px; -webkit-border-radius: 4px; background-color: #d9edf7; border-radius: 4px; border: 1px solid #bce8f1; color: #3a87ad; margin-bottom: 20px; padding: 8px 35px 8px 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;Controlling output&lt;/h3&gt;&lt;p&gt;If HTML5 Sortable satisfies your needs, you are good to go. But what if you need better control of your drag and drop?&lt;/p&gt;&lt;p&gt;Let&#39;s consider the&amp;#160;&lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#result&quot;&gt;first example&lt;/a&gt;. It has two features that are impossible to implement in HTML5 Sortable&amp;#160;&lt;span class=&quot;muted&quot;&gt;(without changing its source code)&lt;/span&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;notice how elements are copied between the lists, instead of moved as in HTML5 Sortable;&lt;/li&gt;&lt;li&gt;notice how you can delete an item from the target list &amp;#8212; this is implemented by writing custom code for dropped elements.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And for that you&#39;ll need&amp;#160;&lt;a href =&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#plugins&quot;&gt;jQuery UI widgets&lt;/a&gt;. But, let&#39;s start by examining the HTML code for the&amp;#160;&lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#result&quot;&gt;first example&lt;/a&gt;:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;div class=&amp;quot;sideBySide&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ul class=&amp;quot;source&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Alfa Romeo&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Audi&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;BMW&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Ford&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Jaguar&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Mercedes&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Porsche&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Tesla&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Volkswagen&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Volvo&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ol class=&amp;quot;target&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li class=&amp;quot;placeholder&amp;quot;&amp;gt;Drop your favourites here&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ol&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;     &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;As you can see, the code is almost identical to the code we used for the HTML5 Sortable example &amp;#8212; we no longer use the class&amp;#160;&lt;code&gt;connected&lt;/code&gt;, we use an ordered instead of an unordered list for the target list and we have a single item in the target list with class&amp;#160;&lt;code&gt;placeholder&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;As expected, it is the JavaScript code that makes all of the difference:&lt;/p&gt;&lt;pre class=&quot;brush: javascript&quot;&gt;&lt;br /&gt;$(&amp;quot;.source li&amp;quot;).draggable({&lt;br /&gt;&amp;#160;&amp;#160;addClasses: false,&lt;br /&gt;&amp;#160;&amp;#160;appendTo: &amp;quot;body&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;helper: &amp;quot;clone&amp;quot;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;$(&amp;quot;.target&amp;quot;).droppable({&lt;br /&gt;&amp;#160;&amp;#160;addClasses: false,&lt;br /&gt;&amp;#160;&amp;#160;activeClass: &amp;quot;listActive&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;accept: &amp;quot;:not(.ui-sortable-helper)&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;drop: function(event, ui) {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(this).find(&amp;quot;.placeholder&amp;quot;).remove();&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var link = $(&amp;quot;&amp;lt;a href=&#39;#&#39; class=&#39;dismiss&#39;&amp;gt;x&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var list = $(&amp;quot;&amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;).text(ui.draggable.text());&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(list).append(link);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(list).appendTo(this);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;updateValues();&lt;br /&gt;&amp;#160;&amp;#160;}&lt;br /&gt;}).sortable({&lt;br /&gt;&amp;#160;&amp;#160;items: &amp;quot;li:not(.placeholder)&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;sort: function() {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(this).removeClass(&amp;quot;listActive&amp;quot;);&lt;br /&gt;&amp;#160;&amp;#160;},&lt;br /&gt;&amp;#160;&amp;#160;update: function() {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;updateValues();&lt;br /&gt;&amp;#160;&amp;#160;}&lt;br /&gt;}).on(&amp;quot;click&amp;quot;, &amp;quot;.dismiss&amp;quot;, function(event) {&lt;br /&gt;&amp;#160;&amp;#160;event.preventDefault();&lt;br /&gt;&amp;#160;&amp;#160;$(this).parent().remove();&lt;br /&gt;&amp;#160;&amp;#160;updateValues();&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;div style=&quot;-moz-border-radius: 4px; -webkit-border-radius: 4px; background-color: #d9edf7; border-radius: 4px; border: 1px solid #bce8f1; color: #3a87ad; margin-bottom: 20px; padding: 8px 35px 8px 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&quot;&gt;I use only a small subset of options and attributes that are available for each widget. Consult the&amp;#160;&lt;a href=&quot;http://api.jqueryui.com/category/interactions/&quot; target=&quot;new&quot;&gt;official documentation&lt;/a&gt;&amp;#160;for the full list. &lt;/div&gt;&lt;p&gt;The first thing&amp;#160;&lt;span class=&quot;muted&quot;&gt;(lines 1&amp;#8211;5)&lt;/span&gt;&amp;#160;we need to do is to make list items draggable. We select all line items&amp;#160;&lt;code&gt;li&lt;/code&gt;&amp;#160;having the class of&amp;#160;&lt;code&gt;.source&lt;/code&gt;&amp;#160;and attach&amp;#160;&lt;code&gt;draggable()&lt;/code&gt;. We then set some options to make&amp;#160;&lt;code&gt;draggable()&lt;/code&gt;&amp;#160;work to our liking:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;addClasses&lt;/strong&gt; We use our own CSS classes, so we set this to&amp;#160;&lt;code&gt;false&lt;/code&gt;. Set it to&amp;#160;&lt;code&gt;true&lt;/code&gt;&amp;#160;if you want to use jQuery UI CSS styles.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;appendTo&lt;/strong&gt; This defines the bounding box for the control. Most often, you&#39;ll leave this at the default setting of&amp;#160;&lt;code&gt;body&lt;/code&gt;. However, there might be times when you want to limit the area inside which a user can drag elements. Simply set the attribute to &amp;#160;&lt;code&gt;#myContainerName&lt;/code&gt;&amp;#160;or similar.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;helper&lt;/strong&gt; Tells the widget to create a clone&amp;#160;&lt;span class=&quot;muted&quot;&gt;(copy)&lt;/span&gt;&amp;#160;of the element to use in drag and drop operations.&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;-moz-border-radius: 4px; background-color: #fcf8e3; border-radius: 4px; border: 1px solid #fbeed5; margin-bottom: 20px; padding: 8px 35px 8px 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); webkit-border-radius: 4px;&quot;&gt;Sometimes, you might encounter issues with overlap/z-index when you set&amp;#160;&lt;code&gt;appendTo: &amp;quot;body&amp;quot;&lt;/code&gt;. If that happens, try to downsize the bounding box by changing the selector to something else, as described above.&lt;/div&gt;&lt;p&gt;Thereafter we have a long code that starts by selecting the target container&amp;#160;&lt;span class=&quot;muted&quot;&gt;(in our case an ordered list&amp;#160;&lt;code&gt;ol&lt;/code&gt;)&lt;/span&gt;&amp;#160;by using the class selector&amp;#160;&lt;code&gt;.target&lt;/code&gt;. Then we chain&amp;#160;&lt;code&gt;droppable()&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;sortable()&lt;/code&gt;&amp;#160;to it.&amp;#160;&lt;code&gt;on(&amp;quot;click&amp;quot;&amp;#8230;)&lt;/code&gt;&amp;#160;has nothing to do directly with drag and drop and we&#39;ll come to it later.&lt;/p&gt;&lt;p&gt;We set the following options for&amp;#160;&lt;code&gt;droppable()&lt;/code&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;addClasses&lt;/strong&gt; We use our own CSS classes, so we set this to&amp;#160;&lt;code&gt;false&lt;/code&gt;. Set it to&amp;#160;&lt;code&gt;true&lt;/code&gt;&amp;#160;if you want to use jQuery UI CSS styles.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;activeClass&lt;/strong&gt; This is the class that gets added to your target container, each time you start dragging an element. In our example, it makes the target border extend downwards to highlight the drop zone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;accept&lt;/strong&gt; This option defines what elements are accepted by the target control. This could be useful if you have multiple drag and drop controls and want to prohibit mixing of elements. At any case, don&#39;t remove the value&amp;#160;&lt;code&gt;&amp;quot;:not(.ui-sortable-helper)&amp;quot;&lt;/code&gt;, since it prevents helper elements generated by&amp;#160;&lt;code&gt;sortable()&lt;/code&gt;&amp;#160;from appearing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;drop&lt;/strong&gt; This function is called when you release the dragged item on the target control. It is here that we create an element to be displayed within the target control. But, first of all&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 12)&lt;/span&gt;&amp;#160;we remove any element with class&amp;#160;&lt;code&gt;.placeholder&lt;/code&gt;. In our example, this is the class responsible for showing the list item with the text &amp;quot;Drop your favourites here&amp;quot;.&lt;xp:br&gt;&lt;/xp:br&gt;Then, we create a variable that holds HTML code for a link that we use to remove a list item&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 13)&lt;/span&gt;. After that, on line 14, we create another variable to hold HTML code for a list item and attach to it the text from the dragged item (&lt;code&gt;draggable&lt;/code&gt;&amp;#160;is a jQuery object representing the element being dragged).&lt;xp:br&gt;&lt;/xp:br&gt;Finally, we append the link to the list item&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 15)&lt;/span&gt;&amp;#160;and then append the list item to the parent &amp;#8212; our sorted list&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 16)&lt;/span&gt;. This results in HTML code similar to this:&lt;xp:br&gt;&lt;/xp:br&gt;&lt;xp:br&gt;&lt;/xp:br&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;Volvo&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;a class=&amp;quot;dismiss&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;x&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&lt;/pre&gt;Line 17 calls the function&amp;#160;&lt;code&gt;updateValues()&lt;/code&gt;&amp;#160;that we&amp;#160;&lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#rest&quot;&gt;that we created in an earlier post&lt;/a&gt;. This function will update the backend each time you drop an element onto the target control. Depending on your design&amp;#160;&lt;span class=&quot;muted&quot;&gt;(e.g. you prefer to manually update the backend by clicking a button)&lt;/span&gt;&amp;#160;you may want to remove this function call.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And this is how we set&amp;#160;&lt;code&gt;sortable()&lt;/code&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;items&lt;/strong&gt; Allows us to specify which elements inside the target control will be sortable. We only want to exclude the placeholder.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;sort&lt;/strong&gt; This function is called during sorting. The only thing we do here is to remove the class&amp;#160;&lt;code&gt;listActive&lt;/code&gt;&amp;#160;from the sorted element. This class gets unintentionally added because of the interaction with&amp;#160;&lt;code&gt;droppable()&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;update&lt;/strong&gt; This is the function that get called when the sort order is updated. Here we call the function&amp;#160;&lt;code&gt;updateValues()&lt;/code&gt;, but once again, it is up to you whether you want to update the backend with each change.&lt;/dd&gt;&lt;/ul&gt;&lt;p&gt;And finally, the&amp;#160;&lt;code&gt;on(&amp;quot;click&amp;quot;&amp;#8230;)&lt;/code&gt;&amp;#160;function. We append this function to each link in the list item in order to make it possible to remove the list item. We target the links by using the class selector&amp;#160;&lt;code&gt;.dismiss&lt;/code&gt;&amp;#160;&lt;span class=&quot;muted&quot;&gt;(see generated HTML code above)&lt;/span&gt;&amp;#160;and we override the&amp;#160;&lt;code&gt;click&lt;/code&gt;&amp;#160;behaviour: when user clicks on the link, we first prevent normal link behaviour&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 28)&lt;/span&gt;&amp;#160;and then we remove the link&#39;s parent, i.e. the list item element&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 29)&lt;/span&gt;. Since we want to send all of the sort changes to the backend immediately, we end the function by calling&amp;#160;&lt;code&gt;updateValues()&lt;/code&gt;&amp;#160;&lt;span class=&quot;muted&quot;&gt;(line 30)&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;These are the CSS styles specific to this implementation&amp;#160;&lt;span class=&quot;muted&quot;&gt;(the others, such as&amp;#160;&lt;code&gt;source&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;target&lt;/code&gt;&amp;#160;are the same as in the HTML5&amp;#160;Sortable example)&lt;/span&gt;:&lt;/p&gt;&lt;pre class=&quot;brush: css&quot;&gt;&lt;br /&gt;body &amp;gt; li {&lt;br /&gt;&amp;#160;&amp;#160;width: 177px;&lt;br /&gt;&amp;#160;&amp;#160;margin: 5px;&lt;br /&gt;&amp;#160;&amp;#160;padding: 5px;&lt;br /&gt;&amp;#160;&amp;#160;-webkit-border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;-moz-border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&lt;br /&gt;&amp;#160;&amp;#160;list-style-type: none;&lt;br /&gt;&amp;#160;&amp;#160;list-style-position: inside;&lt;br /&gt;&amp;#160;&amp;#160;border-width: 1px;&lt;br /&gt;&amp;#160;&amp;#160;border-style: solid;&lt;br /&gt;&amp;#160;&amp;#160;border-color: #ccc !important;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fafafa !important;&lt;br /&gt;&amp;#160;&amp;#160;color: #bbb !important;&lt;br /&gt;}&lt;br /&gt;.listActive {&lt;br /&gt;&amp;#160;&amp;#160;border: 1px solid #ccc;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fcfcfc;&lt;br /&gt;&amp;#160;&amp;#160;padding: 0.5em 0 3em 0 !important;&lt;br /&gt;}&lt;br /&gt;.placeholder {&lt;br /&gt;&amp;#160;&amp;#160;list-style-type: none;&lt;br /&gt;&amp;#160;&amp;#160;text-align: center;&lt;br /&gt;&amp;#160;&amp;#160;font-style: italic;&lt;br /&gt;&amp;#160;&amp;#160;border: 1px dashed #ddd !important;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fff !important;&lt;br /&gt;&amp;#160;&amp;#160;color: #aaa !important;&lt;br /&gt;}&lt;br /&gt;.dismiss {&lt;br /&gt;&amp;#160;&amp;#160;float: right;&lt;br /&gt;&amp;#160;&amp;#160;position: relative;&lt;br /&gt;&amp;#160;&amp;#160;top: -8px;&lt;br /&gt;&amp;#160;&amp;#160;line-height: 20px;&lt;br /&gt;&amp;#160;&amp;#160;font-size: 12px;&lt;br /&gt;&amp;#160;&amp;#160;font-weight: bold;&lt;br /&gt;&amp;#160;&amp;#160;text-decoration: none !important;&lt;br /&gt;&amp;#160;&amp;#160;color: #468847;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The only really interesting thing here is the first style,&amp;#160;&lt;code&gt;body &amp;gt; li&lt;/code&gt;. It is used to style the element that is being dragged. While being dragged, this element&amp;#160;&lt;span class=&quot;muted&quot;&gt;(&lt;code&gt;li&lt;/code&gt;&amp;#160;in our case)&lt;/span&gt;&amp;#160;is a child of the element&amp;#160;&lt;span class=&quot;muted&quot;&gt;(&lt;code&gt;body&lt;/code&gt;&amp;#160;in our case)&lt;/span&gt;&amp;#160;we stated in the&amp;#160;&lt;code&gt;appendTo&lt;/code&gt;&amp;#160;option&amp;#160;&lt;span class=&quot;muted&quot;&gt;(see&amp;#160;&lt;code&gt;draggable()&lt;/code&gt;&amp;#160;above)&lt;/span&gt;&amp;#160;and this is the only way to target and style it.&lt;/p&gt;&lt;h3&gt;Next time&lt;/h3&gt;Next time - using data attributes for key | label functionality. &lt;p&gt;&amp;#160;&lt;/p&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/8259080800448907559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/08/making-drag-and-drop-work-in-xpages.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8259080800448907559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8259080800448907559'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/08/making-drag-and-drop-work-in-xpages.html' title='Making drag and drop work in Xpages - Part 5: Advanced example'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-6430225852455566996</id><published>2013-08-06T21:29:00.000+02:00</published><updated>2013-08-06T21:31:22.761+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="certification"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>LOT-408 Assessment Test (Notes and Domino 9.0 Application Development Update)</title><content type='html'>I have recently taken assessment test LOT-408 IBM Notes and Domino 9.0 Social Edition Application Development Update, just to see what I can expect in the real certification.&lt;br /&gt;&lt;br /&gt;I would say that the assessment was as difficult as the 8.5 Application Development Update certification. The focus in the assessment test was heavily on the Extension Library, going into very fine details of the various controls.&lt;br /&gt;&lt;br /&gt;There were far too many (for my taste) questions of the type &quot;What menu item do you need to navigate to in order to do this or that?&quot; I hate those kind of questions and I never can answer them. I really see no point in them. I like questions where there is a part of code and I need to find an error in it or complete it.&lt;br /&gt;&lt;br /&gt;As I plan to do my update certification by the end of September, I guess I&#39;ll have to start browsing those Extension Library controls immediately.&lt;br /&gt;&lt;br /&gt;As a side note, I am preparing for Red Hat Certified System Administrator (RHCSA) as well. That exam is completely performance-based, meaning that you perform a variety of tasks on a live system, instead of answering scripted questions. You have access to all help resources that come with the system, but there is no Internet access.&lt;br /&gt;&lt;br /&gt;Imagine if the Domino development certification involved writing a CRUD application with some set parameters or controls that you had to use. Much more difficult to grade, but much more fun for us to attend and much more telling about an individual&#39;s knowledge.</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/6430225852455566996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/08/lot-408-assessment-test-notes-and.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6430225852455566996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6430225852455566996'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/08/lot-408-assessment-test-notes-and.html' title='LOT-408 Assessment Test (Notes and Domino 9.0 Application Development Update)'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-1912820143882970367</id><published>2013-07-30T15:42:00.000+02:00</published><updated>2014-01-05T20:42:58.476+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in XPages - Part 4: Ajax and REST</title><content type='html'>&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;Sending sorted list back to server&lt;/h3&gt;&lt;p&gt;Once we have a working drag and drop control, it is time to think about sending the sorted list back to server. In order to do that, we need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;few lines of JavaScript code to read the sorted list and prepare values for sending;&lt;/li&gt;&lt;li&gt;a call to jQuery.ajax() to send the prepared values;&lt;/li&gt;&lt;li&gt;a REST control with PUT method that receives the values and stores them.&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;I use JSON as content type both for sending request and receiving response from the server. These are simple examples and I could have used plain text as well, but JSON is much more robust and flexible (as you will see when we come to the advanced examples). &lt;/div&gt;&lt;h4&gt;Reading list and preparing values&lt;/h4&gt;&lt;p&gt;We use jQuery to find our sorted list, read values and prepare them for sending. The code looks like this:&lt;/p&gt;&lt;pre class=&quot;brush: js&quot;&gt;&lt;br /&gt;var items = [];&lt;br /&gt;$(&amp;quot;ul.target&amp;quot;).children().each(function() {&lt;br /&gt;&amp;#160;&amp;#160;var item = {manufacturer: $(this).text()};&lt;br /&gt;&amp;#160;&amp;#160;items.push(item);&lt;br /&gt;});&lt;br /&gt;var jsonData = JSON.stringify(items);      &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;On line 1, we create an empty array to hold our values.&lt;br /&gt;Then on the line 2, we first find our target list by specifying tag and class (&lt;code&gt;ul.target&lt;/code&gt;) and then for each child (that would be our&amp;#160;&lt;code&gt;li&lt;/code&gt;&amp;#160;items) we run a function.&lt;br /&gt;In the function, we create a key/value item by specifying key&amp;#160;&lt;code&gt;manufacturer&lt;/code&gt;&amp;#160;and reading text value of the current&amp;#160;&lt;code&gt;li&lt;/code&gt;&amp;#160;item (line 3). Then we add the item to the items array (line 4).&lt;br /&gt;Lastly, on line 6, we call&amp;#160;&lt;code&gt;JSON.stringify()&lt;/code&gt;&amp;#160;on the array in order to get a valid JSON structure.&lt;/p&gt;&lt;h4&gt;Ajax call&lt;/h4&gt;&lt;p&gt;We use&amp;#160;&lt;code&gt;jQuery.ajax()&lt;/code&gt;&amp;#160;method to send request with sorted list values to the server and receive response:&lt;/p&gt;&lt;pre class=&quot;brush: js&quot;&gt;&lt;br /&gt;$.ajax ({&lt;br /&gt;&amp;#160;&amp;#160;url: &amp;quot;dnd.xsp/setfavourites&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;type: &amp;quot;PUT&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;data: jsonData,&lt;br /&gt;&amp;#160;&amp;#160;dataType: &amp;quot;json&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;contentType: &amp;quot;application/json; charset=utf-8&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;success: function(){},&lt;br /&gt;&amp;#160;&amp;#160;error: function(){}&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Let&#39;s analyze the call:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;url&lt;/strong&gt;: The url of your REST control. In 99.9% of cases, the REST control will be on the same page as your drag and drop controls, in this case dnd.xsp. The remaining part is the name of the PUT method, setfavourites.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;type&lt;/strong&gt;: Type of the REST method, we use PUT (we could have used POST as well, but I think PUT is more appropriate for this kind of updates).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;data&lt;/strong&gt;:Data to be sent in the call - we prepared it earlier and saved in the jsonData variable.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;dataType&lt;/strong&gt;: Type of data that&amp;#160;&lt;i&gt;server returns&lt;/i&gt;. Our PUT method returns JSON. Note that server must return valid JSON (can be an empty element), otherwise&amp;#160;&lt;code&gt;jQuery.ajax()&lt;/code&gt;&amp;#160;raises error.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;contentType&lt;/strong&gt;: Content type to use when sending request to server. Our PUT method expects JSON.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;success&lt;/strong&gt;: Function to execute if Ajax request complets successfully. During development, you can insert&amp;#160;&lt;code&gt;alert()&lt;/code&gt;&amp;#160;call here to monitor what happens. It is here that calls to Pines notification are made in the first example.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;error&lt;/strong&gt;: Function to call if Ajax request fails. During development, you can insert&amp;#160;&lt;code&gt;alert()&lt;/code&gt;&amp;#160;call here to monitor what happens. It is here that calls to Pines notification are made in the first example.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You&#39;ll find detailed information on&amp;#160;&lt;code&gt;jQuery.ajax()&lt;/code&gt;&amp;#160;method and additional parameters on&amp;#160;&lt;a href=&quot;http://api.jquery.com/jQuery.ajax/&quot; target=&quot;new&quot;&gt;the official site&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;REST control&lt;/h4&gt;&lt;p&gt;Let&#39;s begin by dragging REST Service (Controls &amp;gt; Data Access &amp;gt; REST Service) control to the XPage - I usually insert it towards the end of the page.&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;xe:restService id=&amp;quot;setfavourites&amp;quot; pathInfo=&amp;quot;setfavourites&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xe:this.service&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xe:customRestService contentType=&amp;quot;application/json&amp;quot; requestContentType=&amp;quot;application/json&amp;quot; requestVar=&amp;quot;rqst&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xe:this.doPut&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;![CDATA[#{javascript:&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;if (rqst.length == 0) {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sessionScope.put(&amp;quot;myFavourites&amp;quot;, &amp;quot;(empty)&amp;quot;);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;} else {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var favourites:java.util.ArrayList = new java.util.ArrayList;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;for (var i = 0; i &amp;lt; rqst.length; i++) {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;favourites.add(rqst[i].manufacturer);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sessionScope.put(&amp;quot;myFavourites&amp;quot;, favourites);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;return {};&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}]]&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xe:this.doPut&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xe:customRestService&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/xe:this.service&amp;gt;&lt;br /&gt;&amp;lt;/xe:restService&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The first thing to note is the&amp;#160;&lt;code&gt;pathInfo&lt;/code&gt;&amp;#160;attribute. Its value must be the same as the last part (after /) of the url in the&amp;#160;&lt;code&gt;jQuery.ajax()&lt;/code&gt;&amp;#160;call.&lt;/p&gt;&lt;p&gt;The REST Service control comes with some predefined methods, but we use custom REST service so that we can freely specify how it should work. We specify that we want to use JSON both as request and response type and we set&amp;#160;&lt;code&gt;requestVar&lt;/code&gt;&amp;#160;attribute. This attribute will hold the content of the request, i.e. our sorted list values.&lt;/p&gt;&lt;p&gt;Since we want to use PUT method, we write all of the code in the doPut.&lt;/p&gt;&lt;p&gt;The first thing we do in the code is to check the length of the request. If it is empty, we&#39;ll put value of&amp;#160;&lt;i&gt;(empty)&lt;/i&gt;&amp;#160;in the&amp;#160;&lt;code&gt;sessionScope&lt;/code&gt;&amp;#160;variable.&lt;/p&gt;&lt;p&gt;If the request is not empty, we first create an empty ArrayList to hold decoded values.&lt;/p&gt;&lt;p&gt;Then, we loop through all elements in the request array. The values in the&amp;#160;&lt;code&gt;requestVar&lt;/code&gt;&amp;#160;attribute are stored in an array of&amp;#160;&lt;code&gt;com.ibm.jscript.std.ObjectObject&lt;/code&gt;&amp;#160;elements, thus the somewhat unusual way of getting its value, as shown on line 11. You&#39;ll see its usefullness when we come to the advanced examples.&lt;/p&gt;&lt;p&gt;Do note that the key name (manufacturer) in&amp;#160;&lt;code&gt;rqst[i].&lt;strong&gt;manufacturer&lt;/strong&gt;&lt;/code&gt;&amp;#160;must be the same as the key name we used when creating JSON data:&amp;#160;&lt;code&gt;var item = {&lt;strong&gt;manufacturer&lt;/strong&gt;: $(this).text()};&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;After we looped through all of the elements, we put the ArrayList in the&amp;#160;&lt;code&gt;sessionScope&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Finally, we return en empty JSON element&amp;#160;&lt;code&gt;{}&lt;/code&gt;&amp;#160;since the calling&amp;#160;&lt;code&gt;jQuery.ajax()&lt;/code&gt;&amp;#160;method expects it.&lt;/p&gt;&lt;h5&gt;Configuring Domino server&lt;/h5&gt;&lt;p&gt;In order to use REST services, you will need to enable Domino Access Services on your Domino server.&lt;/p&gt;&lt;p&gt;Start IBM Domino Administrator and access the server that hosts your XPages application. Click the Configuration tab, then Internet Protocols... &amp;gt; Domino Web Engine:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-7DtqQW4dk0I/Uff0DaWJwNI/AAAAAAAABO0/gdSUZDRlgEY/s1600/bootstrap_004.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-7DtqQW4dk0I/Uff0DaWJwNI/AAAAAAAABO0/gdSUZDRlgEY/s400/bootstrap_004.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Scroll to the bottom of the page and find the section Domino Access Services. Under Enables services choose Data. Restart the HTTP task.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-nQSjHz9gWmE/Uff0DTQNxZI/AAAAAAAABO4/vvhO59EASBE/s1600/bootstrap_005.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-nQSjHz9gWmE/Uff0DTQNxZI/AAAAAAAABO4/vvhO59EASBE/s1600/bootstrap_005.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Putting it all together&lt;/h4&gt;&lt;p&gt;Now we have all elements needed to send sorted list values to the server and use them. But, how do we put everything together?&lt;/p&gt;&lt;p&gt;The REST service is self-sufficient, so simply put it on your XPage.&lt;/p&gt;&lt;p&gt;The client side requires a bit more thought. First of all, it would be beneficial to create a function to hold code for reading list values and creating Ajax calls. You could put this function in a JavaScript library or in the same script block as the code to initialize HTML5 Sortable:&lt;/p&gt;&lt;pre class=&quot;brush: js&quot;&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;$(function () {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(&amp;quot;.source, .target&amp;quot;).sortable({&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;connectWith: &amp;quot;.connected&amp;quot;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;function updateValues() {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var items = [];&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(&amp;quot;ul.target&amp;quot;).children().each(function() {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var item = {manufacturer: $(this).text()};&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;items.push(item);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;var jsonData = JSON.stringify(items);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$.ajax ({&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;url: &amp;quot;dnd.xsp/setfavourites&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;type: &amp;quot;PUT&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;data: jsonData,&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;dataType: &amp;quot;json&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;contentType: &amp;quot;application/json; charset=utf-8&amp;quot;,&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;success: function(){},&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;error: function(){}&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;};&lt;br /&gt;&amp;lt;/script&amp;gt;   &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The second point to ponder is how often to update the server. There are two alternatives - automatically, each time a drag-drop-sort operation is performed or manually, by clicking a button or link once you finished sorting.&lt;/p&gt;&lt;p&gt;If you want automatic updates, you simply add a function call, like this:&lt;/p&gt;&lt;pre class=&quot;brush: js&quot;&gt;&lt;br /&gt;$(function () {&lt;br /&gt;&amp;#160;&amp;#160;$(&amp;quot;.source, .target&amp;quot;).sortable({&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;connectWith: &amp;quot;.connected&amp;quot;&lt;br /&gt;&amp;#160;&amp;#160;}).bind(&amp;quot;sortupdate&amp;quot;, function() {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;updateValues();&lt;br /&gt;&amp;#160;&amp;#160;});&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This way, each time you change sort order of the elements, the&amp;#160;&lt;code&gt;updateValues()&lt;/code&gt;&amp;#160;function is called and the server receives new sorted list. Depending on your server, available bandwidth, number of users and other requirements, this could be a totally acceptable way.&lt;/p&gt;&lt;p&gt;On the other hand, if you want to keep server load on minimum and only send values to the server when you are finished dragging, dropping and sorting, you can add a button that calls the&amp;#160;&lt;code&gt;updateValues()&lt;/code&gt;&amp;#160;function:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;xp:button value=&amp;quot;Update values&amp;quot; id=&amp;quot;updateButton&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xp:eventHandler event=&amp;quot;onclick&amp;quot; submit=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:this.script&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;![CDATA[&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;updateValues();&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;]]&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xp:this.script&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/xp:eventHandler&amp;gt;&lt;br /&gt;&amp;lt;/xp:button&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;So, now we know how to create a simple, yet fully functional, drag and drop control. We&#39;ll add a bit more features in the advanced examples.&lt;/p&gt;&lt;h3&gt;Next time&lt;/h3&gt;&lt;p&gt;Next time - advanced examples.&lt;/p&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/1912820143882970367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_30.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1912820143882970367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1912820143882970367'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_30.html' title='Making drag and drop work in XPages - Part 4: Ajax and REST'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-7DtqQW4dk0I/Uff0DaWJwNI/AAAAAAAABO0/gdSUZDRlgEY/s72-c/bootstrap_004.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-6895376410608401470</id><published>2013-07-30T08:46:00.000+02:00</published><updated>2013-07-30T08:46:16.505+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="scrum"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>XPages the Scrum way</title><content type='html'>A picture of our Scrum working area. Still early in the sprint...&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-Vao7lt_M81U/UfdgIDqGHXI/AAAAAAAABOg/9UZq4YDqCsM/s1600/DSC01771.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-Vao7lt_M81U/UfdgIDqGHXI/AAAAAAAABOg/9UZq4YDqCsM/s1600/DSC01771.JPG&quot; height=&quot;480&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Via&amp;nbsp;&lt;a class=&quot;g-profile&quot; href=&quot;https://plus.google.com/113547515373394696068&quot; target=&quot;_blank&quot;&gt;+Boris Paukovic&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/6895376410608401470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/07/xpages-scrum-way.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6895376410608401470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6895376410608401470'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/07/xpages-scrum-way.html' title='XPages the Scrum way'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-Vao7lt_M81U/UfdgIDqGHXI/AAAAAAAABOg/9UZq4YDqCsM/s72-c/DSC01771.JPG" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-7656009005311579877</id><published>2013-07-29T10:09:00.001+02:00</published><updated>2014-01-05T20:43:57.307+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in XPages - Part 3: Coding drag-and-drop</title><content type='html'>&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;Coding drag and drop&lt;/h3&gt;&lt;p&gt;The basic examples use HTML5 Sortable as it is easier to use. We&#39;ll deal with jQuery UI widgets when we get to more advanced examples.&lt;/p&gt;&lt;p&gt;Implementation of drag and drop is usually done using unordered lists,&amp;#160;&lt;code&gt;ul&lt;/code&gt;, but you could use almost any other HTML element.&lt;/p&gt;&lt;p&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#dnd&quot; target=&quot;new&quot;&gt;a simple example&lt;/a&gt; on the demo site, with two unordered lists. You simply grab one of the elements from the left-hand side list and drop it on the placeholder on the right-hand side.&lt;/p&gt;&lt;p&gt;Once the element is on the right-hand side, you can change its position relative to the other elements. You can also grab it and drop it back onto the source list on the left-hand side, thus effectively removing it from the target list.&lt;/p&gt;&lt;p&gt;Let&#39;s take a look at the code. The HTML code is nothing special:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;div class=&amp;quot;sideBySide&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ul class=&amp;quot;source connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Alfa Romeo&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Audi&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;BMW&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Ford&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Jaguar&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Mercedes&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Porsche&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Tesla&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Volkswagen&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;li&amp;gt;Volvo&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;ul class=&amp;quot;target connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;We can ignore&amp;#160;&lt;code&gt;div&lt;/code&gt;&amp;#160;tags as they are only used to position lists. We then have two unordered lists, one with some items, and the other empty. The important thing to note here are the classes attached to these lists:&amp;#160;&lt;code&gt;source&lt;/code&gt;,&amp;#160;&lt;code&gt;target&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;connected&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;JavaScript code required to make this example work is extremely simple:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;$(function () {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(&amp;quot;.source, .target&amp;quot;).sortable({&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;connectWith: &amp;quot;.connected&amp;quot;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;On line 3 we select all HTML elements with class&amp;#160;&lt;code&gt;source&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;target&lt;/code&gt;&amp;#160;(i.e. our unordered lists) and attach&amp;#160;&lt;code&gt;sortable()&lt;/code&gt;&amp;#160;to them which enables drag, drop and sort functionality.&lt;/p&gt;&lt;p&gt;On line 4, we also pass&amp;#160;&lt;code&gt;connectWith: &amp;quot;.connected&amp;quot;&lt;/code&gt;&amp;#160;option to the&amp;#160;&lt;code&gt;sortable()&lt;/code&gt;&amp;#160;which enables dragging and dropping between elements of class&amp;#160;&lt;code&gt;connected&lt;/code&gt;&amp;#160;.&lt;/p&gt;&lt;p&gt;Finally, this is the CSS used to style lists in the above example:&lt;/p&gt;&lt;pre class=&quot;brush: css&quot;&gt;&lt;br /&gt;ul.source, ul.target {&lt;br /&gt;&amp;#160;&amp;#160;min-height: 50px;&lt;br /&gt;&amp;#160;&amp;#160;margin: 0px 25px 10px 0px;&lt;br /&gt;&amp;#160;&amp;#160;padding: 2px;&lt;br /&gt;&amp;#160;&amp;#160;border-width: 1px;&lt;br /&gt;&amp;#160;&amp;#160;border-style: solid;&lt;br /&gt;&amp;#160;&amp;#160;-webkit-border-radius: 3px;&lt;br /&gt;&amp;#160;&amp;#160;-moz-border-radius: 3px;&lt;br /&gt;&amp;#160;&amp;#160;border-radius: 3px;&lt;br /&gt;&amp;#160;&amp;#160;list-style-type: none;&lt;br /&gt;&amp;#160;&amp;#160;list-style-position: inside;&lt;br /&gt;}&lt;br /&gt;ul.source {&lt;br /&gt;&amp;#160;&amp;#160;border-color: #f8e0b1;&lt;br /&gt;}&lt;br /&gt;ul.target {&lt;br /&gt;&amp;#160;&amp;#160;border-color: #add38d;&lt;br /&gt;}&lt;br /&gt;.source li, .target li {&lt;br /&gt;&amp;#160;&amp;#160;margin: 5px;&lt;br /&gt;&amp;#160;&amp;#160;padding: 5px;&lt;br /&gt;&amp;#160;&amp;#160;-webkit-border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;-moz-border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;border-radius: 4px;&lt;br /&gt;&amp;#160;&amp;#160;text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);&lt;br /&gt;}&lt;br /&gt;.source li {&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fcf8e3;&lt;br /&gt;&amp;#160;&amp;#160;border: 1px solid #fbeed5;&lt;br /&gt;&amp;#160;&amp;#160;color: #c09853;&lt;br /&gt;}&lt;br /&gt;.target li {&lt;br /&gt;&amp;#160;&amp;#160;background-color: #ebf5e6;&lt;br /&gt;&amp;#160;&amp;#160;border: 1px solid #d6e9c6;&lt;br /&gt;&amp;#160;&amp;#160;color: #468847;&lt;br /&gt;}&lt;br /&gt;.sortable-dragging {&lt;br /&gt;&amp;#160;&amp;#160;border-color: #ccc !important;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fafafa !important;&lt;br /&gt;&amp;#160;&amp;#160;color: #bbb !important;&lt;br /&gt;}&lt;br /&gt;.sortable-placeholder {&lt;br /&gt;&amp;#160;&amp;#160;height: 40px;&lt;br /&gt;}&lt;br /&gt;.source .sortable-placeholder {&lt;br /&gt;&amp;#160;&amp;#160;border: 2px dashed #f8e0b1 !important;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fefcf5 !important;&lt;br /&gt;}&lt;br /&gt;.target .sortable-placeholder {&lt;br /&gt;&amp;#160;&amp;#160;border: 2px dashed #add38d !important;&lt;br /&gt;&amp;#160;&amp;#160;background-color: #fefcf5 !important;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You can choose your own class names instead of&amp;#160;&lt;code&gt;source&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;target&lt;/code&gt;, simply replace them in the HTML and the JavaScript code.&lt;/p&gt;&lt;p&gt;As you can see, there are no styles defined for the&amp;#160;&lt;code&gt;connected&lt;/code&gt;&amp;#160;class, as it is only used to tell the HTML5 Sortable code which lists to connect.&lt;/p&gt;&lt;p&gt;There are also two class names,&amp;#160;&lt;code&gt;sortable-dragging&lt;/code&gt;&amp;#160;and&amp;#160;&lt;code&gt;sortable-placeholder&lt;/code&gt;, which are hard-coded in the HTML5 Sortable. These two classes are used for styling items in dragging state and drop placeholders.&lt;/p&gt;&lt;h4&gt;Making it XPages friendly&lt;/h4&gt;&lt;p&gt;Static lists are great for examples, but I doubt you&#39;ll find them useful in your XPages application.&lt;/p&gt;&lt;p&gt;You would probably want to read list items from a view or perhaps some field. The easiest way to implement it is by using the Repeat control, similar to this:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;ul class=&amp;quot;source connected&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xp:repeat id=&amp;quot;repeat1&amp;quot; rows=&amp;quot;30&amp;quot; var=&amp;quot;manufacturer&amp;quot; removeRepeat=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:this.value&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;![CDATA[${javascript:&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;return [&amp;quot;Alfa Romeo&amp;quot;, &amp;quot;Audi&amp;quot;, &amp;quot;BMW&amp;quot;, &amp;quot;Jaguar&amp;quot;, &amp;quot;Mercedes&amp;quot;, &amp;quot;Porsche&amp;quot;, &amp;quot;Tesla&amp;quot;, &amp;quot;Volkswagen&amp;quot;, &amp;quot;Volvo&amp;quot;];&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}]]&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;/xp:this.value&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;xp:text escape=&amp;quot;true&amp;quot; id=&amp;quot;sourceLI&amp;quot; value=&amp;quot;#{manufacturer}&amp;quot; tagName=&amp;quot;li&amp;quot;&amp;gt;&amp;lt;/xp:text&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/xp:repeat&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;I am using a static array as data source for the repeat - obviously, you would use your application specific code instead.&lt;/div&gt;&lt;p&gt;Two things to note here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use&amp;#160;&lt;code&gt;removeRepeat=&amp;quot;true&amp;quot;&lt;/code&gt;&amp;#160;in the repeat control in order to remove&amp;#160;&lt;code&gt;div&lt;/code&gt;&amp;#160;tag that the repeat control generates.&lt;/li&gt;&lt;li&gt;Use&amp;#160;&lt;code&gt;tagName=&amp;quot;li&amp;quot;&lt;/code&gt;&amp;#160;in the computed text control to make it output&amp;#160;&lt;code&gt;li&lt;/code&gt;&amp;#160;tag, instead of the usual&amp;#160;&lt;code&gt;span&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;All of the JavaScript code should be at the end of your XPage, like this:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;xp:view&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;!-- rest of the code --&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery-1.9.1.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery.sortable.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(function () {&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;$(&amp;quot;.source, .target&amp;quot;).sortable({&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;connectWith: &amp;quot;.connected&amp;quot;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;});&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/xp:view&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Next time&lt;/h3&gt;&lt;p&gt;Next time - REST and Ajax.&lt;/p&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/7656009005311579877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_29.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7656009005311579877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7656009005311579877'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_29.html' title='Making drag and drop work in XPages - Part 3: Coding drag-and-drop'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-5513364600984235356</id><published>2013-07-29T10:09:00.000+02:00</published><updated>2014-01-05T20:44:36.361+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in XPages - Part 2: Prerequisites</title><content type='html'>&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;Prerequisites&lt;/h3&gt;&lt;h4&gt;jQuery&lt;/h4&gt;&lt;p&gt;Regardless of what plugin you choose, you will need jQuery. In case that you are using Twitter Bootstrap, you already have it. Otherwise, go and&amp;#160;&lt;a href=&quot;http://jquery.com/download/&quot; target=&quot;new&quot;&gt;download it&lt;/a&gt;. Unless you plan to do jQuery development, download the compressed (production) version.&lt;/p&gt;&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;The fact that you are using jQuery does not prevent you from using OneUI or any other Dojo-based framework. In fact, my wellness center application is a OneUI-based application.&lt;/div&gt;&lt;p&gt;I usually put my resources in the WebContent folder. If you want to do the same, simply create a new folder under the WebContent folder and put (drag and drop works fine) the downloaded jQuery library there.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/--_2ADjESB1g/UfQGRwZBmSI/AAAAAAAABN4/lQY3TdJcObs/s1600/bootstrap_002.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/--_2ADjESB1g/UfQGRwZBmSI/AAAAAAAABN4/lQY3TdJcObs/s1600/bootstrap_002.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Before you use the jQuery library, you need to include it in your XPages. How you do that depends on whether you plan to use it on one (few) pages or in a whole application. To include it in a single page, simply use the&amp;#160;&lt;code&gt;script&lt;/code&gt;&amp;#160;tag:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery-1.9.1.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Alternatively, for using it application-wide, add it to your theme file:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;resource&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;content-type&amp;gt;application/x-javascript&amp;lt;/content-type&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;href&amp;gt;js/jquery-1.9.1.min.js&amp;lt;/href&amp;gt;&lt;br /&gt;&amp;lt;/resource&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Plug-ins&lt;/h4&gt;&lt;p&gt;The plug-ins provide drag and drop, as well as sort functionality. I have tested two different approaches here, which both work very well and can fulfill all imaginable requirements.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;HTML5 Sortable&lt;/strong&gt; The first plug-in is&amp;#160;&lt;a href=&quot;http://farhadi.ir/projects/html5sortable/&quot; target=&quot;new&quot;&gt;HTML5 Sortable&lt;/a&gt;. This is a very small (less than 2 kB minimized) and fast plug-in that utilizes the native HTML5 drag and drop API.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;jQuery UI&lt;/strong&gt; The second plug-in is actually a collection of three different jQuery UI widgets:&amp;#160;&lt;a href=&quot;http://api.jqueryui.com/category/interactions/&quot; target=&quot;new&quot;&gt;Draggable, Dropable and Sortable&lt;/a&gt;. These widgets provide considerable configurability and extensibility, but come at the price of being significantly larger than the HTML5 Sortable.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Which plug-in you choose will depend on your exact needs - I&#39;ll explain the main differences when we come to practical examples.&lt;/p&gt;&lt;h5&gt;Installation&lt;/h5&gt;&lt;p&gt;First of all, you need to download the plug-ins.&lt;/p&gt;&lt;p&gt;It is easy for HTML5 Sortable:&amp;#160;&lt;a href=&quot;http://farhadi.ir/downloads/html5sortable.tar.gz&quot; target=&quot;new&quot;&gt;download it&lt;/a&gt;, extract it and put the minimized version (jquery.sortable.min.js) in your WebContent/js (or whatever you named it) folder - just like you did with the jQuery library.&lt;/p&gt;&lt;p&gt;It is a bit more work for jQuery UI widgets. jQuery UI is huge and you&#39;ll want to choose only the parts that you need. So, head over to&amp;#160;&lt;a href=&quot;http://jqueryui.com/download/&quot; target=&quot;new&quot;&gt;the download page&lt;/a&gt;. Then select as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Under Version: select 1.10.3 (latest version)&lt;/li&gt;&lt;li&gt;Under UI Core: select Core, Widget and Mouse&lt;/li&gt;&lt;li&gt;Under Interactions: select Draggable, Dropable and Sortable&lt;/li&gt;&lt;li&gt;Under Widgets: deselect all&lt;/li&gt;&lt;li&gt;Under Effects: deselect all&lt;/li&gt;&lt;li&gt;Under Theme: select No Theme&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;I have chosen not to include CSS styles, as I will provide my own. If you want to choose default jQuery UI styles, make appropriate selection under Theme.&lt;/div&gt;&lt;p&gt;Click the Download button to save your customized library. Extract the files and navigate to the jquery-ui-1.10.3.custom\js folder and then drag and drop the minimized version (jquery-ui-1.10.3.custom.min.js) onto your WebContent/js folder.&lt;/p&gt;&lt;p&gt;Finally, you need to include the plug-ins in your XPage. Presumably, you will use this functionality on a limited number of XPages, so it is best to include them using the&amp;#160;&lt;code&gt;script&lt;/code&gt;&amp;#160;tag, similar to this:&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery-ui-1.10.3.custom.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;&quot;&gt;&lt;strong&gt;Heads up!&lt;/strong&gt;&amp;#160;Depending on how you import libraries (using script tag or via themes) and whether you checked&amp;#160;&lt;i&gt;Use runtime optimized JavaScript and CSS resources&lt;/i&gt;&amp;#160;in the XPage Properties Editor, you might encounter problems running your JavaScript, which (I guess) happen because of namespace collisions. Should this happen to you, try changing the way you import libraries and/or toggling the runtime optimization option.&lt;/div&gt;&lt;h4&gt;Extension library&lt;/h4&gt;&lt;p&gt;You will also need the Extension Library in order to use the REST Service control. I guess that mostly everyone has the Extension Library installed and configured by now, but in case that you don&#39;t, you can download it at&amp;#160;&lt;a href=&quot;http://extlib.openntf.org/&quot; target=&quot;new&quot;&gt;the OpenNTF.org site&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Finally, in order to make everything work as it should, you&#39;ll have to write some client and server JavaScript code of your own. It is nothing difficult and I&#39;ll try to explain as much as possible using practical examples. Hopefully, that will be enough to get you started.&lt;/p&gt;&lt;h3&gt;Next time&lt;/h3&gt;&lt;p&gt;Next time - coding drag and drop.&lt;/p&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/5513364600984235356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_6377.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/5513364600984235356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/5513364600984235356'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages_6377.html' title='Making drag and drop work in XPages - Part 2: Prerequisites'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/--_2ADjESB1g/UfQGRwZBmSI/AAAAAAAABN4/lQY3TdJcObs/s72-c/bootstrap_002.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-45983615576274341</id><published>2013-07-29T10:07:00.000+02:00</published><updated>2014-01-05T20:44:50.461+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="dnd-series"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Making drag and drop work in XPages - Part 1: Introduction</title><content type='html'>&lt;div style=&quot;padding: 8px 35px 8px 14px; margin-bottom: 20px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); border: 1px solid #bce8f1; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #3a87ad; background-color: #d9edf7;&quot;&gt;There is &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp&quot; target=&quot;new&quot;&gt;a demo site&lt;/a&gt; accompanying this series of posts on drag and drop. The text is mostly the same, but you get working examples on the demo site.&lt;/div&gt;&lt;h3&gt;A bit of introduction&lt;/h3&gt;&lt;p&gt;Drag &amp;amp; drop and related sort function have been around since the web became dynamic. I have seen them used to solve some tricky UI problems, but also misused to the point of making me cry.&lt;/p&gt;&lt;p&gt;My first serious encounter with drag &amp;amp; drop was last year when I was working on an application for a wellness center.&lt;/p&gt;&lt;p&gt;As a part of her individual programme, each client would receive customized list of exercises. A trainer would choose from hundreds of available exercises: first sorting them by category (1), then picking an individual exercise and adding it to the list (2) where it could be sorted (3), as shown in this screenshot of the old application written in Delphi.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-oBYlgS6-XbM/UfYhxyeNcYI/AAAAAAAABOM/jr-dMG1qmdI/s1600/bootstrap_003.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-oBYlgS6-XbM/UfYhxyeNcYI/AAAAAAAABOM/jr-dMG1qmdI/s1600/bootstrap_003.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;At that time, my first idea was to use a value picker and a Dojo List Text Box. The value picker would allow me to search and select exercises&amp;#160;&lt;a href=&quot;http://blog.squareone.ba/2012/02/vertically-stacking-members-in-dojo_9.html&quot; target=&quot;new&quot;&gt;to be displayed in the List Text Box&lt;/a&gt;. However, that approach was rejected because the value picker would output exercises in alphabetic order and there was no possibility to sort the exercises in the List Text Box.&lt;/p&gt;&lt;p&gt;Next in the line was drag and drop, which I felt could solve the problem. But, despite the fact that some XPages resources related to drag and drop existed (like&amp;#160;&lt;a href=&quot;http://www.keithstric.com/A55BAC/keithstric.nsf/default.xsp?documentId=E459925411F502CF85257920000494D5&quot; target=&quot;new&quot;&gt;Keith&#39;s&lt;/a&gt;&amp;#160;and&amp;#160;&lt;a href=&quot;http://www.critical-masses.com/category/tags/xpages-drag-and-drop-tutorial&quot; target=&quot;new&quot;&gt;Jake&#39;s&lt;/a&gt;&amp;#160;series), my XPages and JavaScript knowledge (as well as the release schedule) at that time made this a no-go.&lt;/p&gt;&lt;p&gt;So, I ended up implementing a half-baked solution using a name picker (because it outputs the values in the order they were selected) and a List Text Box. It was hardly an elegant solution, but it was good enough.&lt;/p&gt;&lt;p&gt;A year later, it was time to revisit this part of the application and finally make it work as it should have been from the beginning. Drag and drop was still my favourite solution, so I wanted to check what had happened since our last encounter.&lt;/p&gt;&lt;p&gt;One new resource that caught my attention was this&amp;#160;&lt;a href=&quot;http://xomino.com/2012/03/27/html5-drag-and-drop-demonstration-in-an-xpage/&quot; target=&quot;new&quot;&gt;Marky Roden&#39;s post&lt;/a&gt;&amp;#160;on implementing native HTML5 drag and drop. That article put me in a general direction and after some additional work I ended up with a fully working solution.&lt;/p&gt;&lt;p&gt;This is a screenshot of the new implementation. On the left-hand side, a Dojo Accordion is used to allow the trainer to choose a category and display exercises in that category. Selected exercise is simply drag-and-dropped onto the right-hand side. Once there, the exercises can be sorted or removed.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-TXP5lb-2LFY/UfP6LA4UXNI/AAAAAAAABNo/Ive7M5iEhRE/s1600/bootstrap_001.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-TXP5lb-2LFY/UfP6LA4UXNI/AAAAAAAABNo/Ive7M5iEhRE/s1600/bootstrap_001.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Result&lt;/h3&gt;&lt;p&gt;Instead of writing my own drag and drop function, I decided to use two different, already existing, jQuery plugins. One is small, efficient and fast, albeit a bit restricted. The other one offers all bells and whistles, but is larger and slower. Depending on my needs, I can choose one or the other. As I am increasingly using Twitter Bootstrap in my XPages applications, jQuery represents no additional overhead.&lt;/p&gt;&lt;p&gt;The communication between the drag and drop control and the XPages application on the server is done using Ajax and REST. jQuery has built-in Ajax method and the REST Service from the Extension Library takes care of the server side.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/dnd.xsp#result&quot; target=&quot;new&quot;&gt;Head over to the demo site&lt;/a&gt; to see an example of a finished drag and drop control.&lt;/p&gt;&lt;p&gt;That is an elaborate example that uses&amp;#160;&lt;a href=&quot;http://api.jqueryui.com/category/interactions/&quot; target=&quot;new&quot;&gt;jQuery UI Draggable, Dropable and Sortable&lt;/a&gt;&amp;#160;widgets. It also uses&amp;#160; &lt;a href=&quot;http://pinesframework.org/pnotify/&quot; target=&quot;new&quot;&gt;Pines notifications&lt;/a&gt;&amp;#160;to display status of Ajax calls.&lt;/p&gt;&lt;p&gt;Each time you drop, sort or delete an item, an Ajax call is generated containing the current list values. The REST PUT method on the server reads the values and sets a&amp;#160;&lt;code&gt;sessionScope&lt;/code&gt;&amp;#160;variable. If the&amp;#160;&lt;code&gt;PUT&lt;/code&gt;&amp;#160;call is successful, the Ajax method automatically refreshes a computed field that displays the&amp;#160;&lt;code&gt;sessionScope&lt;/code&gt;&amp;#160;variable. Should the&amp;#160;&lt;code&gt;PUT&lt;/code&gt;&amp;#160;call fail, the Ajax method generates an error notification.&lt;/p&gt;&lt;h3&gt;Next time&lt;/h3&gt;&lt;p&gt;Next time - prerequisites.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/45983615576274341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/45983615576274341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/45983615576274341'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/07/making-drag-and-drop-work-in-xpages.html' title='Making drag and drop work in XPages - Part 1: Introduction'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-oBYlgS6-XbM/UfYhxyeNcYI/AAAAAAAABOM/jr-dMG1qmdI/s72-c/bootstrap_003.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-111399529032033228</id><published>2013-05-06T12:27:00.000+02:00</published><updated>2013-05-06T12:48:24.486+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bootstrap"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>XPages, Bootstrap and links pretending to be buttons</title><content type='html'>In &lt;a href=&quot;http://blog.squareone.ba/2013/05/xpages-twitter-bootstrap-and-button.html&quot;&gt;a recent post&lt;/a&gt;, I wrote about how I used Twitter Bootstrap to style an XPages application and what challenges I faced when using &lt;code&gt;Button&lt;/code&gt; core control. &lt;br /&gt;Twitter Bootstrap is very flexible and it allows you to visually turn a link into a button. All you need to do is to apply the same style classes to a link, as you would do with a button. For example, this:&lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;a class=&quot;btn&quot; href=&quot;#&quot;&amp;gt;Approve&amp;lt;/a&amp;gt;&lt;/pre&gt;will be rendered as this:&lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHI/bC-MLZ1WviE/s1600/bootstrap_button_1.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHI/bC-MLZ1WviE/s1600/bootstrap_button_1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;And, just as easily as with the buttons, you can add additional styles or icons: &lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;a class=&quot;btn btn-primary&quot; href=&quot;#&quot;&amp;gt;&amp;lt;i class=&quot;icon-upload-alt&quot;&amp;gt;&amp;lt;/i&amp;gt; Upload&amp;lt;/a&amp;gt;&lt;/pre&gt;The result is this button:&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-VpOHEsGQAEc/UYd8HJJcmeI/AAAAAAAABII/zhgpQdnADng/s1600/link_button1.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-VpOHEsGQAEc/UYd8HJJcmeI/AAAAAAAABII/zhgpQdnADng/s320/link_button1.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;The basic styling can be easily applied using the XPages &lt;code&gt;Link&lt;/code&gt; core control. The code corresponding to the first example looks like this: &lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:link text=&quot;Approve&quot; id=&quot;buttonLink1&quot; styleClass=&quot;btn&quot;&amp;gt;&amp;lt;/xp:link&amp;gt;&lt;/pre&gt;When it comes to adding icons, there are two choices. The first is to use an approach similar to the one we used with buttons: use the &lt;code&gt;Computed Field&lt;/code&gt; core control to inject the necessary &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag: &lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:link text=&quot; Upload&quot; id=&quot;buttonLink2&quot; styleClass=&quot;btn btn-primary&quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xp:text id=&quot;uploadIcon&quot; tagName=&quot;i&quot; styleClass=&quot;icon-upload-alt&quot;&amp;gt;&amp;lt;/xp:text&amp;gt;&lt;br /&gt;&amp;lt;/xp:link&amp;gt;&lt;br /&gt;&lt;/pre&gt;But, there is also another approach that, depending on your preferences and requirement, you might find easier. The &lt;code&gt;Link&lt;/code&gt; core control contains &lt;code&gt;escape&lt;/code&gt; property which, when set to &lt;code&gt;false&lt;/code&gt; enables us to output the necessary &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag as a part of the link&#39;s &lt;code&gt;text&lt;/code&gt; property: &lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:link escape=&quot;false&quot; id=&quot;link1&quot; styleClass=&quot;btn btn-danger&quot;&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;xp:this.text&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;![CDATA[&amp;lt;i class=&#39;icon-remove&#39;&amp;gt;&amp;lt;/i&amp;gt; Delete]]&amp;gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;lt;/xp:this.text&amp;gt;&lt;br /&gt;&amp;lt;/xp:link&amp;gt;&lt;br /&gt;&lt;/pre&gt;The second approach might be especially handy if you want to dynamically change the look of the button, as it will require less code. &lt;br /&gt;&lt;br /&gt;You can see both approaches in &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/links.xsp&quot; target=&quot;_blank&quot;&gt;the demo application&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/111399529032033228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/05/xpages-bootstrap-and-links-pretending.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/111399529032033228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/111399529032033228'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/05/xpages-bootstrap-and-links-pretending.html' title='XPages, Bootstrap and links pretending to be buttons'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHI/bC-MLZ1WviE/s72-c/bootstrap_button_1.PNG" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-6781693267188684492</id><published>2013-05-04T16:39:00.002+02:00</published><updated>2013-05-04T16:39:21.392+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OffTopic"/><title type='text'>Google+ Comments now turned off on this blog</title><content type='html'>&lt;br /&gt;For some time I had Google+ comments enabled on this blog. I thought it would be a good idea, having both blog and Google+ conversation collected in one place. However, I failed to understand that only those with Google+ accounts would be allowed to comment.&lt;br /&gt;&lt;br /&gt;This mistake has now been fixed - I switched back to the old comments system that allows for anonymous comments as well.&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/6781693267188684492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/05/google-comments-now-turned-off-on-this.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6781693267188684492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6781693267188684492'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/05/google-comments-now-turned-off-on-this.html' title='Google+ Comments now turned off on this blog'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-378639641057335335</id><published>2013-05-03T12:52:00.000+02:00</published><updated>2013-05-06T11:31:33.558+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bootstrap"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>XPages, Twitter Bootstrap and button decorations</title><content type='html'>This is a follow-up post to &lt;a href=&quot;http://stackoverflow.com/q/16245230/1510606&quot; target=&quot;_blank&quot;&gt;my question&lt;/a&gt; at the Stack Overflow.&lt;br /&gt;&lt;br /&gt;I am trying to switch completely to &lt;a href=&quot;http://twitter.github.io/bootstrap/index.html&quot; target=&quot;_blank&quot;&gt;Twitter Bootstrap&lt;/a&gt; for our XPages applications. I find it easy to work with, with lean and understandable CSS that is easy to modify should the need arise. There are so many different resources on the Internet dedicated to Bootstrap, including the marvelous &lt;a href=&quot;https://wrapbootstrap.com/&quot; target=&quot;_blank&quot;&gt;{wrap}bootstrap&lt;/a&gt; with ready-to-use themes.&lt;br /&gt;&lt;br /&gt;Using the Boostrap is easy as long as you use static elements, like &lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt; or &lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt;. It gets a little tougher when you start using XPages core controls, like Button and Link.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;I&#39;ll show you on an example. This is the static code you would use when defining a button:&lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;button class=&quot;btn&quot; type=&quot;button&quot;&amp;gt;Approve&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/pre&gt;This code results in a button similar to this:&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHE/b0sy4rB1oYo/s1600/bootstrap_button_1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHE/b0sy4rB1oYo/s1600/bootstrap_button_1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The button can easily be styled by adding additional classes like this:&lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;button class=&quot;btn btn-success btn-large&quot; type=&quot;button&quot;&amp;gt;Approve&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/pre&gt;which turns into:&lt;br /&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-Iy7_efffcrI/UYOcxqE1BEI/AAAAAAAABHM/czk085TdwZk/s1600/bootstrap_button_2.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-Iy7_efffcrI/UYOcxqE1BEI/AAAAAAAABHM/czk085TdwZk/s1600/bootstrap_button_2.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;These styles are easily repeatable using the XPages Button core control. You simply specify the necessary class(es), like this:&lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:button value=&quot;Approve&quot; id=&quot;button1&quot; styleClass=&quot;btn btn-success btn-large&quot;&amp;gt;&lt;br /&gt;&amp;lt;/xp:button&amp;gt;&lt;br /&gt;&lt;/pre&gt;Now, the really neat feature is the easy way of adding decorations (icons) to buttons. So for example, if you want to add a tick mark to your button you use the following code: &lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;button class=&quot;btn&quot; type=&quot;button&quot;&amp;gt;&amp;lt;i class=&quot;icon-ok&quot;&amp;gt;&amp;lt;/i&amp;gt; Approve&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/pre&gt;resulting in this:&lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-SPWWdsrXOfo/UYOjcVgvl2I/AAAAAAAABHg/o75WF7xX-Vo/s1600/bootstrap_button_3.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-SPWWdsrXOfo/UYOjcVgvl2I/AAAAAAAABHg/o75WF7xX-Vo/s320/bootstrap_button_3.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;But, when I tried using this technique with the button core control, I realized that I didn&#39;t know how to inject the necessary &lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag inside the generated button code. At first, I tried all possible and impossible ways of calculating the value of the button. But it wouldn&#39;t work as the html code would always get escaped.&lt;br /&gt;I then came up with a client-side script that would execute on page load, find the button and inject the necessary tags (see my &lt;a href=&quot;http://stackoverflow.com/q/16245230/1510606&quot; target=&quot;_blank&quot;&gt;Stack Overflow question&lt;/a&gt;). But this was not an elegant solution and it would be difficult to programatically change the icon. &lt;br /&gt;Thankfully,&amp;nbsp;&lt;a class=&quot;g-profile&quot; href=&quot;https://plus.google.com/103119335037606490151&quot; target=&quot;_blank&quot;&gt;+Stephan Wissel&lt;/a&gt; showed that I could easily include html tags in the XPages markup. So, the solution to the icon problem was as easy as this: &lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:button value=&quot;Approve&quot; id=&quot;button1&quot; styleClass=&quot;btn&quot;&amp;gt;&lt;br /&gt;    &amp;lt;i class=&quot;icon-ok&quot;&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;&amp;lt;/xp:button&amp;gt;&lt;br /&gt;&lt;/pre&gt;But wait, there is more! In XPages you can use property &lt;code class=&quot;prettyprint&quot;&gt;tagName&lt;/code&gt; to control what html tag is output when the control is rendered. So, I used the Computed Field core control and told it to output the &lt;code class=&quot;prettyprint&quot;&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag: &lt;br /&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;xp:button value=&quot;Approve&quot; id=&quot;button1&quot; styleClass=&quot;btn&quot;&amp;gt;&lt;br /&gt;    &amp;lt;xp:text id=&quot;buttonIcon1&quot; tagName=&quot;i&quot; styleClass=&quot;icon-ok&quot;&amp;gt;&amp;lt;/xp:text&amp;gt;&lt;br /&gt;&amp;lt;/xp:button&amp;gt;&lt;br /&gt;&lt;/pre&gt;Why would you do that? Well, now you can easily change the value of the &lt;code class=&quot;prettyprint&quot;&gt;styleClass&lt;/code&gt; property and thus the icon. Which means that you can completely change the look of the button, based on some condition in the application. &lt;br /&gt;&lt;br /&gt;This approach is easy to use and completely controllable using the server-side script. I created a small demo application where you can &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/buttons.xsp&quot; target=&quot;_blank&quot;&gt;see this technique in action&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Instead of the default Glyphicons, I use &lt;a href=&quot;http://fortawesome.github.io/Font-Awesome/&quot; target=&quot;_blank&quot;&gt;Font Awesome&lt;/a&gt; for displaying icons. Font Awesome has more symbols, is smaller and easier to use. And it uses exactly the same style names as Bootstrap, so you won&#39;t need to change your existing code. Warmly recommended! &lt;br /&gt;&lt;br /&gt;And lastly, to demonstrate why I needed this in first place: we are planning an event and I wanted to ask our customers and partners where we should organize it. So I created a simple XPage and provided four alternatives that they can choose from. It is made using Twitter Bootstrap and the techniques described in this blog post. I haven&#39;t translated it, but you&#39;ll get the idea. Feel free to &lt;a href=&quot;http://web1.cs-computing.com/apps/demo/bootstrap/bootstrap_demo.nsf/survey.xsp&quot; target=&quot;_blank&quot;&gt;submit your choices&lt;/a&gt;!&lt;br /&gt;&lt;h3&gt;Update&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;I just found another way to display icons using the &lt;code&gt;Link&lt;/code&gt; core control. When you set &lt;code&gt;escape=&quot;false&quot;&lt;/code&gt; you can inject the &lt;code&gt;i&lt;/code&gt; tag directly into the &lt;code&gt;text&lt;/code&gt; property. Depending on your needs, this could be easier than using computed fields. But, there are caveats. I&#39;ll update the demo database and write a blog post about this.&lt;/div&gt;&lt;style type=&#39;text/css&#39;&gt;   .syntaxhighlighter {         overflow-y: hidden !important;         overflow-x: auto !important;      } &lt;/style&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/378639641057335335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/05/xpages-twitter-bootstrap-and-button.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/378639641057335335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/378639641057335335'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/05/xpages-twitter-bootstrap-and-button.html' title='XPages, Twitter Bootstrap and button decorations'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-Uzcuf0yI30A/UYOcYHmf43I/AAAAAAAABHE/b0sy4rB1oYo/s72-c/bootstrap_button_1.PNG" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-2809063242352549448</id><published>2013-04-24T23:09:00.002+02:00</published><updated>2013-04-24T23:24:16.924+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="ldap"/><category scheme="http://www.blogger.com/atom/ns#" term="sametime"/><category scheme="http://www.blogger.com/atom/ns#" term="troubleshooting"/><title type='text'>User&#39;s login ID, LDAP and Sametime</title><content type='html'>&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;Or, when too much RTFM is not a good thing.&lt;br /&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Each time we perform a new installation, we try to make it better than the one before. We tighten security, we make it more robust and scalable. We read manuals and check best practices an extra time.&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;When we were installing Sametime at a new customer some time ago, we did just that - we read the documentation one extra time.&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;And we noticed that the documentation recommended use of a unique, non-changing, identifier as the user&#39;s login ID. For example, the section &lt;a href=&quot;http://www-10.lotus.com/ldd/stwiki.nsf/xpDocViewer.xsp?lookupName=Administering+Sametime+Standard+8.5.2+documentation#action=openDocument&amp;amp;res_title=Specifying_a_users_login_ID_st852&amp;amp;content=pdcontent&quot; target=&quot;_blank&quot;&gt;Specifying a user&#39;s login ID&lt;/a&gt; states:&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;i&gt;To avoid running the name change tool in the future, you can select an LDAP attribute that is not likely to change when users change their name or relocate. Here are examples of stable attributes in some well-known LDAP servers:&amp;nbsp;&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;i&gt;IBM Directory Server: ibm-entryUUID&lt;/i&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;i&gt;Domino® LDAP: dominounid&lt;/i&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;i&gt;Novell Directory Server (NDS): guid&lt;/i&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;i&gt;SunOne: nsuniqueid&lt;/i&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;i&gt;Active Directory: objectGUID&amp;nbsp;&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/div&gt;So, we did exactly as recommended and changed the login ID to dominounid. And everything was fine with the Sametime client (both embedded and standalone), but we could no longer log in using the web client (e.g. via ST Proxy). Attempts to log in using the web client would time out, but the funny thing was that if the user first logged in to the iNotes and then opened the web client, it would work.&lt;br /&gt;&lt;br /&gt;So, we contacted the IBM support and started checking all the standard things - SSO configuration in both WAS and Domino, LDAP settings, trusted IPs... And everything was fine. The PMR got escalated all the way until it reached the SWAT (cool name, isn&#39;t it?). And then, after going through a massive amount of logs, they found the cause - it was our change of the login ID to dominounid.&lt;br /&gt;&lt;br /&gt;The thing is, if you change the login ID, you also need to change the search filter used when resolving a user name to a distinguished name. This can be changed in STSC or directly in stconfig.nsf. So instead of &lt;br /&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;(&amp;amp;(objectclass=inetOrgPerson)(|(mail=%s)(cn=%s)(uid=%s))) &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;it should be: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;(&amp;amp;(objectclass=inetOrgPerson)(|(mail=%s)(cn=%s)(uid=%s)(dominounid=%s)))&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After this change, everything started working as it should. Such a small change, so difficult to find (it took over a month to get this sorted!), so big an impact. I felt quite dumb after this was over: &quot;Did I miss this in the manual?&quot; I double checked, but I couldn&#39;t find a reference to the search filter change anywhere.&lt;br /&gt;&lt;br /&gt;The moral of this story is thus: reading too much manual is sometimes as bad as not reading it at all. Especially if the manual is missing some very important information. :-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/2809063242352549448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/04/users-login-id-ldap-and-sametime.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2809063242352549448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2809063242352549448'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/04/users-login-id-ldap-and-sametime.html' title='User&#39;s login ID, LDAP and Sametime'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total><georss:featurename>Banja Luka, Bosnia and Herzegovina</georss:featurename><georss:point>44.766666699999988 17.183333299999958</georss:point><georss:box>44.406377199999987 16.537886299999958 45.126956199999988 17.828780299999959</georss:box></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-7938785405408108829</id><published>2013-04-23T23:24:00.001+02:00</published><updated>2013-04-23T23:24:34.615+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="connections"/><category scheme="http://www.blogger.com/atom/ns#" term="notes"/><title type='text'>Connections Business Cards in Notes 9.0</title><content type='html'>I really don&#39;t know how old this is - I only noticed it yesterday.  &lt;br /&gt;&lt;br /&gt;When one hovers over a name in Notes 9.0, a Connections business card appears:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-pxCKffYqV2g/UXb6mZgMeOI/AAAAAAAABF8/1LAWjEZqluw/s1600/notes.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-pxCKffYqV2g/UXb6mZgMeOI/AAAAAAAABF8/1LAWjEZqluw/s1600/notes.png&quot; height=&quot;152&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;We haven&#39;t done any integration between our Domino / Connections environments, apart for installing Connections plug-ins for Notes. So I guess that this function is a part of the plug-ins.&lt;br /&gt;&lt;br /&gt;Really nice touch, it simply works out of box. No manual configuration of any sort. I wish I could say the same for other aspects of Domino / Connections interaction, such as Embedded Experience and Activity Streams.</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/7938785405408108829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/04/connections-business-cards-in-notes-90.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7938785405408108829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/7938785405408108829'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/04/connections-business-cards-in-notes-90.html' title='Connections Business Cards in Notes 9.0'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-pxCKffYqV2g/UXb6mZgMeOI/AAAAAAAABF8/1LAWjEZqluw/s72-c/notes.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-6449855635180729878</id><published>2013-04-23T21:29:00.002+02:00</published><updated>2013-04-23T22:41:08.801+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="traveler"/><category scheme="http://www.blogger.com/atom/ns#" term="troubleshooting"/><title type='text'>Installing Traveler 9.0 on Linux - watch out for this inconsistency</title><content type='html'>&lt;style type=&#39;text/css&#39;&gt;   .syntaxhighlighter {         overflow-y: hidden !important;         overflow-x: auto !important;      } &lt;/style&gt;I don&#39;t know if I am the only one to encounter this. I&#39;ll share it, maybe it saves some headache.&lt;br /&gt;&lt;br /&gt;Prior to Domino 9.0, the default program directory on Linux was:&lt;br /&gt;&lt;pre class=&quot;brush: bash&quot;&gt;/opt/ibm/lotus&lt;/pre&gt;With version 9.0, it has been changed, as seen in this excerpt from the installation procedure:&lt;br /&gt;&lt;pre class=&quot;brush: plain&quot;&gt;Please specify a directory or press Enter to accept the default directory.&lt;br /&gt;Program Files Directory Name [/opt/ibm/domino]&lt;/pre&gt;However, it seems that Traveler 9.0 is not completely aware of this change. It will install just fine, but when you try to run it, it will crash with all sorts of nasty errors, such as:&lt;br /&gt;&lt;pre class=&quot;brush: plain&quot;&gt;&lt;br /&gt;HTTP JVM: IBM Notes Traveler: cannot load allpackages - could not find /local/data/web1/../../../traveler.jar&lt;br /&gt;HTTP JVM: Unable to load /opt/ibm/lotus/notes/90000/linux/travelerca. For more detailed information, please consult error-log-0.xml located in /local/data/web1/domino/workspace/logs&lt;br /&gt;HTTP JVM: java.lang.UnsatisfiedLinkError: com/lotus/sync/dca/access/NativeAccess.jniInitThread()I&lt;br /&gt;HTTP JVM:  at com.lotus.sync.dca.access.NativeAccess.initThread(NativeAccess.java:1133)&lt;br /&gt;HTTP JVM:  at com.lotus.sync.dca.dispatch.DispatchThreadData.ensureJNIThreadInited(DispatchThreadData.java:478)&lt;br /&gt;&lt;/pre&gt;The second error is actually the clue to the cause and to the solution - for some reason, the Traveler is looking for travelerca (actually&amp;nbsp;libtravelerca.so) in &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/opt/ibm/lotus&lt;/span&gt; - the pre-9.0 installation location.&lt;br /&gt;&lt;br /&gt;It is an easy one to fix though, one just needs to make a symbolic link (as root), like this :&lt;br /&gt;&lt;pre class=&quot;brush: bash&quot;&gt;# cd /opt/ibm&lt;br /&gt;# ln -s domino lotus&lt;br /&gt;# ll&lt;br /&gt;total 4&lt;br /&gt;drwxr-xr-x 4 root root 4096 Mar 27 00:34 domino&lt;br /&gt;lrwxrwxrwx 1 root root &amp;nbsp; &amp;nbsp;6 Apr 23 20:56 lotus -&amp;gt; domino&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;I think this problem only occurs in new Domino 9.0 installations. If you upgrade from 8.5.x, the program directory is &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/opt/ibm/lotus&lt;/span&gt; and this error does not happen.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As a side note, if you are using&amp;nbsp;&lt;a class=&quot;g-profile&quot; href=&quot;https://plus.google.com/100379994261840402776&quot; target=&quot;_blank&quot;&gt;+Daniel Nashed&lt;/a&gt;&#39;s &lt;a href=&quot;http://www.nashcom.de/nshweb/pages/startscript.htm&quot; target=&quot;_blank&quot;&gt;start/stop scripts&lt;/a&gt;, you&#39;ll also need to edit them as they have &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/opt/ibm/lotus&lt;/span&gt; hard-coded in few places.&lt;/div&gt;&lt;br /&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/6449855635180729878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/04/installing-traveler-90-on-linux-watch.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6449855635180729878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6449855635180729878'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/04/installing-traveler-90-on-linux-watch.html' title='Installing Traveler 9.0 on Linux - watch out for this inconsistency'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-8513081718106446408</id><published>2013-01-15T10:15:00.000+01:00</published><updated>2013-01-15T22:08:39.152+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="ibm"/><category scheme="http://www.blogger.com/atom/ns#" term="red hat"/><title type='text'>A Success Story - IBM, Red Hat (and Domino)</title><content type='html'>&lt;img alt=&quot;COMPUTING systems d.o.o.&quot; border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-oOHbNDKaz-A/UPUaVabAMpI/AAAAAAAABBA/Bmz_N4bqa3k/s1600/cs_h.png&quot; height=&quot;50&quot; style=&quot;border: 0; box-shadow: none;&quot; title=&quot;COMPUTING systems d.o.o.&quot; width=&quot;400&quot; /&gt;&lt;br /&gt;&lt;br /&gt;I feel proud to share with you &lt;a href=&quot;http://www-01.ibm.com/software/success/cssdb.nsf/CS/KFIN-93KQ8V?OpenDocument&amp;amp;Site=corp&amp;amp;cty=en_us&quot; target=&quot;_blank&quot;&gt;this success story&lt;/a&gt; that IBM has recently published. It details the work that we (&lt;a href=&quot;http://www.cs-computing.com/&quot; target=&quot;_blank&quot;&gt;COMPUTING systems d.o.o.&lt;/a&gt;) did on a complete infrastructure overhaul for one of our customers.&lt;br /&gt;&lt;br /&gt;While it focuses on IBM System x servers, System Storage and Red Hat Enterprise Virtualization, it does mention Domino / Notes as well.&lt;br /&gt;&lt;br /&gt;Sometime this year, when the complete collaboration infrastructure - including Notes / Domino, Sametime and Connections - is in place and operational, I hope that we shall be able to write a success story about it as well.&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-XcAA0uSQFhM/UPUbGd0bBAI/AAAAAAAABBQ/4a5yR9_Oieg/s1600/sasabrkic_BPMark_web_list.jpg&quot; style=&quot;border: 0; box-shadow: none;&quot; /&gt;&amp;nbsp;&amp;nbsp;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-5VFrDDLm8O4/UPUayMeEefI/AAAAAAAABBI/4-C7PtvdUvM/s1600/RHBusReadyLogo_RGB.png&quot; style=&quot;border: 0; box-shadow: none;&quot; /&gt;&lt;/div&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/8513081718106446408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/01/a-success-story-ibm-red-hat-and-domino.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8513081718106446408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8513081718106446408'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/01/a-success-story-ibm-red-hat-and-domino.html' title='A Success Story - IBM, Red Hat (and Domino)'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-oOHbNDKaz-A/UPUaVabAMpI/AAAAAAAABBA/Bmz_N4bqa3k/s72-c/cs_h.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-1079063508789363949</id><published>2013-01-08T14:39:00.000+01:00</published><updated>2013-01-19T09:01:42.140+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="notes"/><category scheme="http://www.blogger.com/atom/ns#" term="symphony"/><title type='text'>IBM Notes / Domino 9.0 Beta - initial impressions</title><content type='html'>I&#39;ve spent the last few weeks playing with and testing Notes / Domino 9 Social Edition Beta. In &lt;a href=&quot;http://lotusshadeofyellow.blogspot.com/2012/12/notes-domino-90-linux-64-bit-symphony_18.html&quot;&gt;the last post&lt;/a&gt;, I highlighted a few issues that I saw as possibly being problematic. I am glad to say that my fears have been unfounded. This is what I have discovered so far:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Domino 64-bit on Linux&lt;/b&gt; - works like a charm. I installed one Domino 64-bit server from the scratch and I even upgraded an existing 32-bit 8.5.3 FP3 server. I don&#39;t know what official recommendations will be regarding upgrading 32-bit servers, but everything seems to work perfectly. Even though the Domino is 64-bit, you&#39;ll still need a few 32-bit libraries (I think they are for GUI installer). The good thing is that installer is very kind and will list all of the missing dependencies.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Symphony&lt;/b&gt; - I haven&#39;t played with the widget that&#39;s supposed to enable Notes applications to use stand-alone Symphony, but judging by the comments elsewhere it doesn&#39;t work very well (yet). I have gone through our applications and only one uses the LotusScript&amp;nbsp;Symphony API and is therefore affected by the removal of the embedded Symphony. The rest uses the UNO API and works perfectly with the latest version of the OpenOffice. Some templates will need minor adjustments, but no code change will be necessary. Which is very positive.&lt;/li&gt;&lt;li&gt;&lt;b&gt;XPages Extension Library&lt;/b&gt; is integrated in the product and it works flawlessly. I disabled OSGi bundles that I set up previously on the 8.5.3 server and everything just worked. The Domino Designer works properly and recognizes and builds all code written in the previous versions.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Activity Stream and Embedded Experience&lt;/b&gt; - this is the most exciting part. In a way, it embeds a part of Connections in the Notes client. You get to see updates from your network and you can interact with some posts directly - I assume that third-party applications will be able to post to the activity stream as well. (I already envision our support application posting tickets or our time tracker posting leave requests to the stream. And users acting on them directly from the stream.)&lt;br /&gt;At the moment, the integration is complicated and hard to get working. I hope that some parts of the integration will be simplified and the rest properly described in the documentation by the time version 9 is released.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Upgrading &lt;/b&gt;- I upgraded few servers from 8.5.3 and there is no need to waste words: it just works, without a single problem. Pure excellence!&lt;/li&gt;&lt;/ul&gt;Those were the initial findings, more testing to come...&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/1079063508789363949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2013/01/ibm-notes-domino-90-beta-initial.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1079063508789363949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1079063508789363949'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2013/01/ibm-notes-domino-90-beta-initial.html' title='IBM Notes / Domino 9.0 Beta - initial impressions'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total><georss:featurename>Banja Luka, Bosnia and Herzegovina</georss:featurename><georss:point>44.766666699999988 17.183333299999958</georss:point><georss:box>44.40637619999999 16.537886299999958 45.126957199999985 17.828780299999959</georss:box></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-4835931809034714616</id><published>2012-12-18T10:08:00.001+01:00</published><updated>2013-01-04T14:49:12.572+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="notes"/><category scheme="http://www.blogger.com/atom/ns#" term="sametime"/><category scheme="http://www.blogger.com/atom/ns#" term="symphony"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Notes / Domino 9.0, Linux 64-bit, Symphony and other stuff</title><content type='html'>So, the first ever public beta of a Lotus Notes / Domino release is upon us. Like many others, I rushed to download and install it.&lt;br /&gt;&lt;br /&gt; It became obvious immediately that this update will require much more thought, planning and testing than the previous ones. Here are some of the reasons:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Domino 64-bit on Linux&lt;/b&gt; - Linux users now have access to a 64-bit version of the Domino server. That is good - no more installing 32-bit libraries, fiddling with memory settings and the like. But, can we do an in-place upgrade of existing 32-bit Domino servers? Are there any restriction to the 64-bit version, which seems to be the case with other OSes?&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Supported Linux releases&lt;/b&gt; - I tried upgrading one of our Domino servers running on Red Hat 5.7. The installation went smoothly, but the Domino wouldn&#39;t run. It requires glibc version 2.7 and RHEL 5.7 ships with glibc 2.5. Which means that I must upgrade to RHEL 6.x that ships with glibc 2.12. Which, in turn, means that when the 9.0 is released there will be quite a lot Linux servers needing upgrade, which may or may not be possible.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Symphony&lt;/b&gt; - Symphony is no longer included with the Notes client. As a matter of fact, IBM no longer does any new development of the Symphony, the efforts are instead switched to fully supporting the Apache OpenOffice. We, like many others, have invested in the Symphony: we are using it as the only office suite and we are counting on it in numerous applications for creating reports and outputting (nicely) formatted PDFs. According to &lt;a href=&quot;http://www.johndavidhead.com/jhead/johnhead.nsf/dx/ibm-notes-9-embedded-lotus-symphony-is-gone-but-application-developers-should-not-fret&quot;&gt;a blog post by John Head&lt;/a&gt;, there will be a plug-in that will enable applications to seamlessly use the stand-alone version of the Symphony. However, at this moment it it unclear whether this plug-in will be officially supported by IBM and how well it will work. And we&#39;ll still need to use the Symphony, which no longer is being developed.&lt;br /&gt;So, for our part, we will bid farewell to the Symphony when Notes / Domino 9.0 is released. We&#39;ll switch to either OpenOffice or LibreOffice. And, during this next few months we&#39;ll perform a major overhaul of our applications and get rid of the Symphony-related code. Instead of it we plan to use the &lt;a href=&quot;http://incubator.apache.org/odftoolkit/simple/index.html&quot;&gt;Apache ODF Toolkit&lt;/a&gt; and the &lt;a href=&quot;http://poi.apache.org/&quot;&gt;Apache POI&lt;/a&gt;, which will allow us to create documents on server (adding an additional bonus of being reusable in our XPages applications).&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Sametime&lt;/b&gt; - at this point it is still unclear how Sametime, Quickr and other products will be affected by upgrade to version 9.0. Judging by the beta forums, the Sametime seems to work. But, the question is whether it is going to be supported and on which platforms: e.g. Sametime Community Server 8.5.2 IFR1 is officially supported on RHEL 5.4, but not on RHEL 6.x that is required for Domino 9.0.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;XPages Extension Library&lt;/b&gt; - the Extension Library is now included with the Notes / Domino. So far, we used the &quot;stand-alone&quot; version of the Extension Library. The switch to the integrated version will probably be painless, but there is still need to clean the servers and remove the OSGi bundles. As a side note - how and how often is this integrated version updated? Can it be updated independently or must we wait for fix packs for updates?&lt;/li&gt;&lt;/ul&gt;So, at the moment there are lot of questions. Some of them could be answered immediately if IBM had produced any kind of documentation. I know this is a beta, but I still expect (draft) documentation to be available. In this way, there will be more job for us - but in the end, I am sure, we&#39;ll all end up running version 9.0 :-)&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/4835931809034714616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/12/notes-domino-90-linux-64-bit-symphony_18.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/4835931809034714616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/4835931809034714616'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/12/notes-domino-90-linux-64-bit-symphony_18.html' title='Notes / Domino 9.0, Linux 64-bit, Symphony and other stuff'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-4513692860847127970</id><published>2012-11-30T09:26:00.001+01:00</published><updated>2013-01-04T14:47:04.280+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="administration"/><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="ibm"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerShell"/><title type='text'>Backup Domino to Amazon S3 Cloud Storage</title><content type='html'>I can&#39;t believe it&#39;s been 9 months since the last post!&lt;br /&gt;&lt;br /&gt;A lot has happened during that time: there has been a lot of XPages programming, great time time with Scrum, frustration with source code management and administration of some old (Sametime) and some new (Connections) applications. More about thatt some other time.&lt;br /&gt;&lt;br /&gt;What I wanted to share with you this time is a way to cheaply and reliably backup your Domino server(s) to cloud.&lt;br /&gt;&lt;h3&gt; The Need&lt;/h3&gt;We have a few small customers running Domino. They run it on Microsoft Windows servers, use it for mail and a custom application or two. The hardware is often redundant and reliable, but they still want to backup their Domino environment. For, no matter how your hardware is reliable, it won&#39;t help when you delete that important e-mail (and it expires from the Trash).&lt;br /&gt;&lt;br /&gt;Backup solutions that are able to backup Domino online are expensive and require expensive supporting hardware (dedicated backup servers, tape libraries). Nothing a small customer is ready to purchase.&lt;br /&gt;&lt;br /&gt;In the past, we used to write batch files to shut-down server, wait predefined time for a server to stop, than copy files from the Domino data directory to a network share or external disk and then start server again. It worked, but there is a better solution.&lt;br /&gt;&lt;h3&gt; The Solution&lt;/h3&gt;The solution we are using now involves using Windows PowerShell and Amazon S3 Storage.&lt;br /&gt;&lt;br /&gt;PowerShell is an extremely powerful administration tool and makes tasks such as starting and stopping services (such as Domino server) and invoking other applications reliable and easy.&lt;br /&gt;&lt;br /&gt;Backup to Amazon S3 has always been an option, but here in Bosnia until recently, the cost of obtaining sufficient upload speeds precluded any practical use of this service.&lt;br /&gt;&lt;br /&gt;Thankfully, our ISPs have shown some mercy and, while still snail-paced comparing to the developed countries, the upload speeds are high enough to finish majority of backup uploads during a nightly backup window.&lt;br /&gt;&lt;br /&gt;Another important development is the introduction of the Amazon Glacier storage, costing next to nothing. The catch with the Glacier is that your files are not immediately available for download / restore as is the case with the standard S3 storage. Instead, you need to wait some 3 - 5 hours for your data to get ready. The data is still covered by the astonishing 99.999999999% durability guarantee, just like the standard S3 storage.&lt;br /&gt;&lt;br /&gt;Amazon has provided seamless integration between S3 and Glacier, so you can simply and completely transparently move data from S3 to Glacier. We usually recommend our customers to keep 1 - 2 weeks of backups in the S3 (for quick and easy restores) and move older backups to Glacier. It is also easy to configure automatic data expiration, so you don&#39;t end up paying for obsolete data.&lt;br /&gt;&lt;br /&gt;All of our customers fall in the first 1 TB tier, so according to &lt;a href=&quot;http://aws.amazon.com/s3/pricing-effective-december-2012/&quot;&gt;the just reduced prices&lt;/a&gt;, they pay only $0.095 per GB per month for standard S3 storage and $0.010 per GB per month for Glacier storage (there is also the Reduced Redundancy Storage at $0.076 per GB per month, which is similar to the standard S3 storage but with &quot;only&quot; 99.99% durability). So a customer with some 100 GB of backup will pay no more than $10 per month. And that is cheap!&lt;br /&gt;&lt;br /&gt;I have written a PowerShell script that automates the whole process: it stops the Domino server, copies predefined files from the Domino data directory to a temporary directory, starts the Domino server, zips the files and uploads them to the S3 storage.&lt;br /&gt;&lt;br /&gt;By using the PowerShell we can precisely detect when Domino server shuts down so file copy operation can commence immediately afterwards. As soon as files are copied, the Domino server is started again. This means that the downtime is minimal, usually less than 2 minutes.&lt;br /&gt;&lt;br /&gt;Once the Domino server is started, the script proceeds with zipping (we use 7-Zip at maximum compression setting) and uploading the data.&lt;br /&gt;&lt;h3&gt; The Implementation&lt;/h3&gt;If you are interested in this solution, you will need the script, which you can get from the &lt;a href=&quot;https://github.com/sasabrkic/domino-backup-to-s3&quot;&gt;GitHub&lt;/a&gt; (I would think that the script is too big for &lt;a href=&quot;http://openntf.org/XSnippets.nsf/home.xsp&quot;&gt;XSnippets&lt;/a&gt;, what do you think?). I have also attached the current version to this post.&lt;br /&gt;&lt;br /&gt;Apart from the script, you will also need: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;PowerShell 2.0 environment. If you are using Windows 7 or Windows Server 2008 R2 you already have it. For older systems &lt;a href=&quot;http://support.microsoft.com/kb/968929&quot;&gt;head over to Microsoft&lt;/a&gt; and download the Windows Management Framework Core for your platform.&amp;nbsp;&lt;/li&gt;&lt;li&gt;7-Zip, which is used for compressing the backup files. The free download is available at &lt;a href=&quot;http://7-zip.org/&quot;&gt;7-Zip.org&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;&lt;li&gt;S3Sync, which is used to upload files to Amazon S3 Storage service. S3Sync is available for free download at &lt;a href=&quot;http://sprightlysoft.com/S3Sync/&quot;&gt;SprightlySoft&#39;s website&lt;/a&gt;. No installation is necessary, simply extract it to a suitable location (remember the location, you will need to enter it into the script).&amp;nbsp;&lt;/li&gt;&lt;li&gt;Amazon S3 account, if you don&#39;t have one. Simply head to the &lt;a href=&quot;http://aws.amazon.com/&quot;&gt;Amazon AWS&lt;/a&gt; site and sign up for the account.There is a &lt;a href=&quot;http://aws.amazon.com/free/&quot;&gt;Free Usage Tier&lt;/a&gt; that will give you 5 GB of free S3 storage, so you can test it for free.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;Once you have created your account and logged in into the &lt;a href=&quot;https://console.aws.amazon.com/console/home&quot;&gt;AWS console&lt;/a&gt;, choose to manage S3 storage and create a bucket. The bucket is a place where your files will go. You can create multiple buckets if they are used for different things (you can serve a web site directly from a bucket) or if you want them to have different lifecycle policy.&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-NhzYnDHZvIk/UOac6kBtjAI/AAAAAAAAA2Y/jYS-28TPziw/s1600/s3backup_1.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;219&quot; src=&quot;http://2.bp.blogspot.com/-NhzYnDHZvIk/UOac6kBtjAI/AAAAAAAAA2Y/jYS-28TPziw/s400/s3backup_1.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;In the bucket, you can create folders to further organize things.&lt;br /&gt;&lt;br /&gt;If you select a bucket and click Actions &amp;gt; Properties you will see properties for that bucket and be able to set, among other things, lifecycle policies:&lt;br /&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-7Y9ER073TZ8/UOac6gwZTPI/AAAAAAAAA2c/0vmsEGxe17E/s1600/s3backup_2.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;210&quot; src=&quot;http://1.bp.blogspot.com/-7Y9ER073TZ8/UOac6gwZTPI/AAAAAAAAA2c/0vmsEGxe17E/s400/s3backup_2.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Click Add rule and you will be able to specify when the data is to be moved to Glacier and if and when it is going to be removed. You can specify the time as either an exact date or as number of days since the creation of an object. The rule can apply to the entire bucket or a single folder:&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-lnKJq8MBEMI/UOac6qdFPzI/AAAAAAAAA2U/8WbB7HIXkDY/s1600/s3backup_3.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;293&quot; src=&quot;http://4.bp.blogspot.com/-lnKJq8MBEMI/UOac6qdFPzI/AAAAAAAAA2U/8WbB7HIXkDY/s400/s3backup_3.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Lastly, you will need your security credentials for accessing your S3 storage. Click on your name in the upper right corner and choose Security Credentials:&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-COE0z2fk_PU/UOac7PiYFaI/AAAAAAAAA2g/uSPWGEhogbI/s1600/s3backup_4.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;290&quot; src=&quot;http://2.bp.blogspot.com/-COE0z2fk_PU/UOac7PiYFaI/AAAAAAAAA2g/uSPWGEhogbI/s400/s3backup_4.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;You will be presented with a page where you can manage all sorts of security credentials for accessing AWS. You are interested in Access Keys - copy your Access Key ID and Secret Access Key, you will need them in the script.&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-vIXvu5YdwVQ/UOac7WIBdQI/AAAAAAAAA2k/FqRS5XdJsw0/s1600/s3backup_5.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;http://2.bp.blogspot.com/-vIXvu5YdwVQ/UOac7WIBdQI/AAAAAAAAA2k/FqRS5XdJsw0/s400/s3backup_5.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;You can use AWS console for managing and accessing your files, or you can use dedicated a application like CloudBerry&#39;s free &lt;a href=&quot;http://www.cloudberrylab.com/free-amazon-s3-explorer-cloudfront-IAM.aspx&quot;&gt;Explorer for Amazon S3&lt;/a&gt;, that will let you do more things easily.&lt;br /&gt;&lt;br /&gt;And that is all that you need to know about the Amazon S3 for this purpose. Refer to the online help (it is good) if you want to know more, or let me know in the comments and I&#39;ll try to help.&lt;br /&gt;&lt;h3&gt; The script&lt;/h3&gt;The script is actually fairly easy. The whole work is done by some ten lines of code. The rest of the code is there to provide meaningful logging - it will let you know how long it took to shut down your Domino server, what files have been copied and how long it took to upload the files. It will also let you know about eventual problems.&lt;br /&gt;&lt;br /&gt;Before you start using the script, you will need to set some variables, they are all located at the beginning of the script. Among other things you will need to set Domino server service name, location of the data folder and what files to back-up. You will also need to set your Amazon S3 details. Check also that the default locations for 7-Zip and S3Sync are valid for your environment.&lt;br /&gt;&lt;br /&gt;Please make sure to end all Windows directory paths with a backslash (). Also, if you are specifying an S3 folder, it needs to end with a forward slash (/).&lt;br /&gt;&lt;br /&gt;Currently, the script compresses the files with 7-Zip algorithm and uses the strongest compression. If that is not suitable for your needs, let me know and I&#39;ll let you know what to change to set one of the supported algorithms.&lt;br /&gt;&lt;br /&gt;The upload to S3 is secured by SSL, but the 7-Zip file is not encrypted. 7-Zip has support for strong encryption - once again, let me know if you need that and I&#39;ll help you fix it.&lt;br /&gt;&lt;h3&gt; Running the script&lt;/h3&gt;Once you downloaded the script open it in a text editor or PowerShell ISE , which is a PowerShell script editor. (If you plan to spend more time with PowerShell, &lt;a href=&quot;http://www.powergui.org/index.jspa&quot;&gt;PowerGUI&lt;/a&gt; might be a good alternative. Then you might also find this book interesting: &lt;a href=&quot;http://powershell.com/Mastering-PowerShell.pdf&quot;&gt;Mastering PowerShell by Tobias Weltner&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Edit the script variables as described in the file and save the script.&lt;br /&gt;&lt;br /&gt;By default, Windows will not allow you to run scripts. To change this, you need to open a PowerShell console (with alleviated privileges (Run as Administrator) if you are on Vista / 7 / 2008) and enter following:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: ps&quot;&gt;Set-ExecutionPolicy RemoteSigned&lt;/pre&gt;&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-E_ezDcPr0gg/UOac7qLClKI/AAAAAAAAA2o/9S2PZL7oBmY/s1600/s3backup_6.gif&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;75&quot; src=&quot;http://4.bp.blogspot.com/-E_ezDcPr0gg/UOac7qLClKI/AAAAAAAAA2o/9S2PZL7oBmY/s400/s3backup_6.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;This will change the execution policy to allow local scripts. You can check if it applied correctly by issuing command:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: ps&quot;&gt;Get-ExecutionPolicy&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can now simply navigate to the directory where you saved the script and execute it by entering:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: ps&quot;&gt;.domino_backup.ps1&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can run the script manually or you can schedule it using Windows Task Manager.&lt;br /&gt;&lt;br /&gt;That&#39;s it, I hope you find it useful. Let me know if you use the script - how it works, what would you like to improve or what needs to be fixed.&lt;/div&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/4513692860847127970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/11/backup-domino-to-amazon-s3-cloud-storage_30.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/4513692860847127970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/4513692860847127970'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/11/backup-domino-to-amazon-s3-cloud-storage_30.html' title='Backup Domino to Amazon S3 Cloud Storage'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-NhzYnDHZvIk/UOac6kBtjAI/AAAAAAAAA2Y/jYS-28TPziw/s72-c/s3backup_1.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-8251778405842522653</id><published>2012-03-01T13:15:00.001+01:00</published><updated>2013-01-04T14:57:25.525+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="errata"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Update: XPages, Directory Assistance and context.getUser()</title><content type='html'>A few days ago &lt;a href=&quot;http://lsoy.posterous.com/xpages-directory-assistance-and-contextgetuse&quot;&gt;I wrote about my problems&lt;/a&gt;&amp;nbsp;with the Directory Assistance and getting user roles with context.getUser().&lt;br /&gt;Prompted by Mark Leusink&#39;s comment, I decided to take a look at our Directory Assistance settings. I started changing settings and... context.getUser().getRoles() started to work!&lt;br /&gt;The setting that made all the difference was &quot;Use exclusively for group authorization or credential authentication&quot;.&lt;br /&gt;&lt;div class=&quot;p_embed p_image_embed&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-SuSwXH-z3Cc/UObfmtr2l2I/AAAAAAAAA3Y/YanlN2Ctjq8/s1600/da_4.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;208&quot; src=&quot;http://1.bp.blogspot.com/-SuSwXH-z3Cc/UObfmtr2l2I/AAAAAAAAA3Y/YanlN2Ctjq8/s320/da_4.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;If you set this to Yes, as it was originally set in our case, context.getUser().getRoles() will not work. Setting this to No makes it work. No other settings have any influence on context.getUser().&lt;/div&gt;So, whether you have access to Directory Assistance settings and / or are allowed to change them will decide what implementation you choose. context.getUser().getRoles() is shorter and more elegant, session.getCurrentDatabase().getACL().getEntry(session.getEffectiveUserName()).getRoles() seems to be safer in the long run. The choice is yours.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/8251778405842522653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/03/update-xpages-directory-assistance-and_1.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8251778405842522653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8251778405842522653'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/03/update-xpages-directory-assistance-and_1.html' title='Update: XPages, Directory Assistance and context.getUser()'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-SuSwXH-z3Cc/UObfmtr2l2I/AAAAAAAAA3Y/YanlN2Ctjq8/s72-c/da_4.gif" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-2237275921142172376</id><published>2012-03-01T12:01:00.001+01:00</published><updated>2013-01-04T15:12:38.259+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Formatting dates in XPages links - the Java way</title><content type='html'>As many of you have experienced, date and number formatting of the link text in xp:link does not work. Sure, you can assign a data converter, just as you would for a field or a computed text, but it won&#39;t work. &lt;a href=&quot;http://www.intec.co.uk/formatting-dates-on-link/&quot;&gt;Paul Withers&lt;/a&gt; and &lt;a href=&quot;http://www.fdehedin.ch/168/format-a-number-in-xplink&quot;&gt;Frédéric Dehédin&lt;/a&gt;, among others, have offered nice SSJS solutions to this problem.&lt;br /&gt;&lt;br /&gt;When I encountered the same problem, I took a somewhat different approach. I didn&#39;t like the idea of creating SSJS libraries for something that is essentially a hack and which can be easily solved with a single line (albeit long) of Java code.&lt;br /&gt;&lt;br /&gt;So here is your one-liner that will let you format dates in xp:links:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance().format(yourDateValue);&lt;/pre&gt;&lt;br /&gt;What happens here is that you use the DateFormat class (you must call it by its full name java.text.DateFormat) which knows how to format dates. Using DateFormat, you first get dateInstance which knows everything about dates and their formatting and then you call format with the date value that you want to format.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Let&#39;s first take a look at the date value. This value needs to be of type java.util.Date.&lt;/div&gt;&lt;div&gt;If you already have this value in a field on your xpage, you simply need to call&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;getComponent(&quot;elementID&quot;).getValue()&lt;/pre&gt;&lt;br /&gt;The complete code would look something like this:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance().format(getComponent(&quot;elementID&quot;).getValue());&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;You can also read a date value from the Notes back-end, a Notes document for example. Say you have a Notes document as the data source and you call it doc. You&#39;ll get your date value by calling:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;doc.getItemValueDate(&quot;fieldName&quot;)&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;which translates to:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance().format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;The method getItemValueDate returns java.util.Date, so you are OK there. If you, however, have a Notes DateTime item, you need to convert it to Java Date first. You do so by calling the method toJavaDate(). For example:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;doc.getItemValueDateTime(&quot;fieldName&quot;).toJavaDate()&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;getItemValueDateTime returns Notes DateTime and by calling toJavaDate you transform it to Java Date that you can use.&lt;br /&gt;&lt;br /&gt;That was the date value. Now, let&#39;s look at the format options. Calling:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance().format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;br /&gt;will return you a string formatted using the default date format and the default locale for the JVM running your application. Most likely, this is not what you want. Fortunately, you can change this easily. getDateInstance accepts arguments that tell it what date format and what locale you want to use in the form of getDateInstance(int style, Locale aLocale). For example, you could do something like this:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT, Locale.US).format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG, Locale.GERMANY).format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;br /&gt;As you can see, you can use predefined constants for format and locale. The format constants are: FULL, LONG, MEDIUM and SHORT. Just don&#39;t forget you need to call them by the full name, e.g. java.text.DateFormat.FULL.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;There are many predefined locales as well, you should check &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/java/util/Locale.html&quot;&gt;Java API documentation&lt;/a&gt; (look under Field Summary) to find out more. If your locale is not predefined, don&#39;t despair - it is easy to define it. What you would need to know are the &lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes&quot;&gt;lowercase two-letter ISO-639 code&lt;/a&gt; for the language and the &lt;a href=&quot;http://en.wikipedia.org/wiki/ISO_3166-1&quot;&gt;uppercase two-letter ISO-3166 code&lt;/a&gt; for the country. So, if you want to specify locale for the Italian speaking part of Switzerland, you would use:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;new Locale(&quot;it&quot;, &quot;CH&quot;)&lt;/pre&gt;&lt;br /&gt;which in turn would give something like this:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG, new Locale(&quot;it&quot;, &quot;CH&quot;)).format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;br /&gt;Of course, you could read language and country from some sort of settings document, making your display fully customizable.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Finally, you can also read the locale from the user&#39;s browser by calling:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;context.getLocale()&lt;/pre&gt;&lt;br /&gt;resulting in:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;brush: java&quot;&gt;java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM, context.getLocale()).format(doc.getItemValueDate(&quot;fieldName&quot;));&lt;/pre&gt;&lt;br /&gt;And that&#39;s all. Let me know if something is unclear. And for your homework you do similar conversion for numbers using either the &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/java/text/NumberFormat.html&quot;&gt;NumberFormat&lt;/a&gt; class or the &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#format(java.util.Locale,%20java.lang.String,%20java.lang.Object...)&quot;&gt;String.format&lt;/a&gt; method.&lt;/div&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/2237275921142172376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/03/formatting-dates-in-xpages-links-java_1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2237275921142172376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/2237275921142172376'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/03/formatting-dates-in-xpages-links-java_1.html' title='Formatting dates in XPages links - the Java way'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-1254190525382663042</id><published>2012-02-28T14:42:00.001+01:00</published><updated>2013-01-04T15:19:21.100+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>XPages, Directory Assistance and context.getUser()</title><content type='html'>It often happens that some parts of the GUI should be hidden, based on the current users authorizations. For that purpose, we have been using ACL roles and a short line of code to evaluate whether the current user is assigned to a specific role:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: java&quot;&gt;context.getUser().getRoles().contains(&quot;[RoleName]&quot;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And this had worked very well until we recently introduced Directory Assistance and allowed users from the secondary directory to log in and use the application. For users from the secondary directory, the above procedure did not work - they could never see parts of the GUI requiring a role membership, i.e. the above line of code never evaluated to true. At the same time, users from the primary directory had no problem at all.&lt;br /&gt;&lt;br /&gt;I have recently read &lt;a href=&quot;http://xmage.gbs.com/blog.nsf/d6plinks/TTRY-8QWBBU&quot;&gt;Tim Tripcony&#39;s post&lt;/a&gt; on problems with page ACL and Directory Assistance and suspected a similar problem here.&lt;br /&gt;&lt;br /&gt;This is what a simple test reveals. If a user from the primary directory logs in, context.getUser() will return a wealth of information:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-GY4U0LesOus/UObfl_c9gtI/AAAAAAAAA3U/FS0Khddojsw/s1600/da_1.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;http://2.bp.blogspot.com/-GY4U0LesOus/UObfl_c9gtI/AAAAAAAAA3U/FS0Khddojsw/s400/da_1.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;context.getUser().getRoles() returns all roles assigned to the user and hence checking for a specific role works as expected.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But, this is what happens when a user from a secondary  directory logs in:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-jPYL8UuY42U/UObfl8u8ugI/AAAAAAAAA3M/tyfHzKhnI_8/s1600/da_2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;111&quot; src=&quot;http://3.bp.blogspot.com/-jPYL8UuY42U/UObfl8u8ugI/AAAAAAAAA3M/tyfHzKhnI_8/s400/da_2.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The context.getUser() is all by empty, no roles are returned and check for a role name will always return false.&lt;br /&gt;&lt;br /&gt;And that is not good. I don&#39;t know if this is intended or not (feature or bug), but I needed to fix it. The first idea that occurred to me was to define roles for each user in a settings document, but that was too much of a hack for my liking. So I tested different ways to get the information about a user&#39;s roles and found that this one works:&lt;br /&gt;&lt;br /&gt;session.getCurrentDatabase().getACL().getEntry(session.getEffectiveUserName()).getRoles()&lt;br /&gt;&lt;br /&gt;This is how it looks if a user from the secondary directory logs in now:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-TVY5mzqdKDk/UObfmMUtIjI/AAAAAAAAA3Q/aieaXMeHEkM/s1600/da_3.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;98&quot; src=&quot;http://3.bp.blogspot.com/-TVY5mzqdKDk/UObfmMUtIjI/AAAAAAAAA3Q/aieaXMeHEkM/s400/da_3.gif&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The assigned roles are correctly recognized and it is easy to check for them by calling the isRoleEnabled() method. It also works correctly with users from the primary directory.&lt;br /&gt;&lt;br /&gt;So, if you are using or planning to use Directory Assistance and need to check assigned roles, this is the code that you can use.&lt;/div&gt;&lt;/div&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/1254190525382663042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/02/xpages-directory-assistance-and_28.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1254190525382663042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/1254190525382663042'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/02/xpages-directory-assistance-and_28.html' title='XPages, Directory Assistance and context.getUser()'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-GY4U0LesOus/UObfl_c9gtI/AAAAAAAAA3U/FS0Khddojsw/s72-c/da_1.gif" height="72" width="72"/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-6027194985898961400</id><published>2012-02-09T22:05:00.001+01:00</published><updated>2013-01-04T19:15:37.559+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>Vertically stacking members in Dojo List Text Box</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;The extension library provides the Dojo List Text Box (djextListTextBox) control that, connected to a value picker, makes it possible to create a list whose members are easy to remove. Using the oneUI v2.1, the default display is similar to this:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-YoSV85NZn2o/UOcZjIOhhxI/AAAAAAAAA30/X0v0WKI5lvo/s1600/dojoTextBox_1.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-YoSV85NZn2o/UOcZjIOhhxI/AAAAAAAAA30/X0v0WKI5lvo/s1600/dojoTextBox_1.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;But, what if you instead wanted list members to be stacked vertically? Something like this:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-cKwmdDZQ6QU/UOcZjKJQr4I/AAAAAAAAA34/w-ArPpVh-IA/s1600/dojoTextBox_2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-cKwmdDZQ6QU/UOcZjKJQr4I/AAAAAAAAA34/w-ArPpVh-IA/s1600/dojoTextBox_2.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;With some CSS, it is actually quite easy to accomplish. First, put your djextListTextBox inside a panel and give it a style class, let&#39;s call it verticalStack. Then, edit your existing or create a new style sheet and add following:&lt;/div&gt;&lt;br /&gt;&lt;pre class=&quot;brush: css&quot;&gt;.verticalStack span {&lt;br /&gt; display: block;&lt;br /&gt; margin-left: 0px !important;&lt;br /&gt; }&lt;br /&gt; .verticalStack a span {&lt;br /&gt; display: inline;&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;What does it all mean? If you take a look at the HTML code that the Dojo List Text Box control generates, you&#39;ll see that each list member is actually a &amp;lt;span&amp;gt; tag, which in turn contains an &amp;lt;a&amp;gt; tag that contains a &amp;lt;span&amp;gt; tag.&lt;br /&gt;&lt;br /&gt;So, the CSS says that each &amp;lt;span&amp;gt; in the &amp;lt;div&amp;gt;  with class verticalStack should have block display style. &amp;lt;span&amp;gt; tags usually have inline display style, which means that multiple &amp;lt;span&amp;gt; tags are displayed in a row, one after the other. display: block will force them to behave like &amp;lt;p&amp;gt; or &amp;lt;div&amp;gt; tags and display one beneath the other.&lt;br /&gt;&lt;br /&gt;Now, there is a &amp;lt;span&amp;gt; within the &amp;lt;a&amp;gt; tag. And it is also affected by the block display. And that makes the close button (little x) to be displayed beneath the rest of the list member. This is taken care of by the .verticalStack a span style, which returns normal, inline, display style to all &amp;lt;span&amp;gt; tags that are within a &amp;lt;a&amp;gt; tag that is within an element with .verticalStack class applied.&lt;br /&gt;&lt;br /&gt;Finally, using the original style, each list member has applied left margin of 5 pixels to make separetion between consecutive members.We use margin-left: 0px !important to remove that margin and make our members nicely align. The CSS is hierarchical and there are styles higher in the hierarchy that would take precedence, so we need to use !important.&lt;br /&gt;&lt;br /&gt;That&#39;s all that is needed. Have in mind that this works if you are using oneUI, but it should point you in the right direction even if you are using other layout. And, by applying some more CSS you can easily make it look even better:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-UpdwtpEC2jQ/UOcZjT13u6I/AAAAAAAAA38/4OrhDaquC5Y/s1600/dojoTextBox_3.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-UpdwtpEC2jQ/UOcZjT13u6I/AAAAAAAAA38/4OrhDaquC5Y/s1600/dojoTextBox_3.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script type=&quot;text/javascript&quot;&gt;SyntaxHighlighter.highlight();&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/6027194985898961400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/02/vertically-stacking-members-in-dojo_9.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6027194985898961400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/6027194985898961400'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/02/vertically-stacking-members-in-dojo_9.html' title='Vertically stacking members in Dojo List Text Box'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-YoSV85NZn2o/UOcZjIOhhxI/AAAAAAAAA30/X0v0WKI5lvo/s72-c/dojoTextBox_1.gif" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8886165919970940400.post-8784978132009396218</id><published>2012-02-06T08:41:00.001+01:00</published><updated>2013-01-04T19:19:09.515+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ApplicationIsBorn"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="domino"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="lotus"/><category scheme="http://www.blogger.com/atom/ns#" term="xpages"/><title type='text'>How expensive is view.getColumnValues()?</title><content type='html'>I need expert help and advice.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the &lt;a href=&quot;http://lsoy.posterous.com/tag/applicationisborn&quot;&gt;application we are building&lt;/a&gt;, among other things, we keep record of all payments. One of the resources is an XPage that shows all payments due within certain number of days from &#39;today&#39;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is how we did it: we already have a Domino view that displays all unpaid payments. We don&#39;t like creating a Domino view for each new requirement, so we decided to reuse this one. I wrote some Java code to go through all of these payments, find those that fall within the given time period and then extract interesting data (i.e. client name, due amount, due date) into a hash map. This hash map is saved in the view scope and used as data source for a repeat control on the XPage.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We also evaluated a solution with full-text database search, but one of the requirements is that when a new payment is added or a payment is paid, the XPage must display those changes immediately. Which means that delay between payment change and full-text index update is unacceptable. And we didn&#39;t think that constantly forcing index update was a good idea either.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Our current solution works well, but I don&#39;t like to go through all documents each time I reload the XPage. Now, the view is small and lean (only one sorted column) and it will hardly ever have more than a hundred documents, so the computation is quick. Still, I would like to perform the computation only when the view has changed. One of the solutions that&amp;nbsp;occurred&amp;nbsp;to me is this:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Get view.&lt;/li&gt;&lt;li&gt;Get all column values for the first column (view.getColumnValues(0);).&lt;/li&gt;&lt;li&gt;Calculate the hash value of the column values.&lt;/li&gt;&lt;li&gt;Get previously calculated hash value from the session/application scope and compare the two.&lt;/li&gt;&lt;li&gt;If the hash values are the same, do nothing - the existing hash map with payment details is still valid.&lt;/li&gt;&lt;li&gt;If the hash values are different, perform full computation, update the hash map with payment details and update the hash value.&lt;/li&gt;&lt;/ol&gt;Is this a sound approach? It should be less intensive than the current solution, but is there a better way to do this? How expensive is the view.getColumnValues() call?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Any comments would  be greatly appreciated.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.squareone.ba/feeds/8784978132009396218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.squareone.ba/2012/02/how-expensive-is-viewgetcolumnvalues_6.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8784978132009396218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8886165919970940400/posts/default/8784978132009396218'/><link rel='alternate' type='text/html' href='http://blog.squareone.ba/2012/02/how-expensive-is-viewgetcolumnvalues_6.html' title='How expensive is view.getColumnValues()?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04300515654696659160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry></feed>