<?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: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-1176484787338693227</id><updated>2011-09-15T16:36:46.311+04:00</updated><title type='text'>Music of Code</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-6701470715389874083</id><published>2009-11-15T19:01:00.005+03:00</published><updated>2009-11-15T19:40:47.125+03:00</updated><title type='text'>Never ever reinstall a Linux box</title><content type='html'>&lt;p&gt;Recently I had a weird problem. My Firefox was producing a segmentation fault on random pages, svn dropped messages like
&lt;pre&gt;
svn: /usr/lib/liblber-2.4.so.2: no version information available (required by /usr/lib/libldap_r-2.4.so.2)
svn: relocation error: /usr/lib/libldap_r-2.4.so.2: symbol ber_sockbuf_io_tcp, version OPENLDAP_2.4_2 not defined in file liblber-2.4.so.2 with link time reference
&lt;/pre&gt;
and refused to work. When I tried to reinstall Firefox, Synaptic urged me to run "sudo dpkg --configure -a", which in turn produced some totally cryptic errors. Reinstallation attempt of libldap ended in an epic fail bringing my whole system down.
&lt;/p&gt;
&lt;p&gt;
I was going to reinstall the Ubuntu 9.04, but decided to call Dmitry Stolyarov of &lt;a href="http://www.trueoffice.ru/" target="_blank"&gt;TrueOffice&lt;/a&gt; fame. At first, he asked me if I had tried reinstalling libldap.
&lt;/p&gt;
&lt;p&gt;
 — Sure. — I replied. — I did that through Synaptic, but it froze my system.&lt;br /&gt;
 — Synaptic, you say... Run "sudo apt-get install libldap-2.4-2 --reinstall"&lt;br /&gt;
 — But, hey, I've already done it!&lt;br /&gt;
 — Give it another try.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
Damn! This time it worked. From now on, I won't trust GUI tools when things don't work the way they should.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-6701470715389874083?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/6701470715389874083/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=6701470715389874083' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6701470715389874083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6701470715389874083'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/11/never-ever-reinstall-linux-box.html' title='Never ever reinstall a Linux box'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-3645573957804468197</id><published>2009-06-12T14:47:00.002+04:00</published><updated>2009-06-12T14:48:00.244+04:00</updated><title type='text'>Display a symfony form without labels</title><content type='html'>Paste this in configure():
&lt;pre&gt;
$format = $this-&gt;widgetSchema-&gt;getFormFormatter()-&gt;getRowFormat();
$format = str_replace('%label%', '', $format);
$this-&gt;widgetSchema-&gt;getFormFormatter()-&gt;setRowFormat($format);
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-3645573957804468197?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/3645573957804468197/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=3645573957804468197' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3645573957804468197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3645573957804468197'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/06/display-symfony-form-without-labels.html' title='Display a symfony form without labels'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-2792170620758853780</id><published>2009-06-07T16:12:00.004+04:00</published><updated>2009-06-07T16:27:34.533+04:00</updated><title type='text'>Change color of all links in a page on click without JS</title><content type='html'>This should've been an April Fools's post :)&lt;br&gt;&lt;br&gt;

To accomplish the above, place this in your css:
&lt;pre&gt;
a:visited {
  color: #777777;
}
&lt;/pre&gt;
and change all &lt;i&gt;hrefs&lt;/i&gt; to "&lt;tt&gt;#777777&lt;/tt&gt;".

Then load the page, click on a link and - Whoa!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-2792170620758853780?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/2792170620758853780/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=2792170620758853780' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2792170620758853780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2792170620758853780'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/06/change-color-of-all-links-in-page-on.html' title='Change color of all links in a page on click without JS'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-761079493739518039</id><published>2009-04-25T12:59:00.001+04:00</published><updated>2009-04-25T13:00:42.586+04:00</updated><title type='text'>Get is_secure of current action</title><content type='html'>Ever wondered if a currently running action is secure? 

Try 
&lt;pre&gt;
$sf_context-&gt;getActionStack()-&gt;getLastEntry()-&gt;getActionInstance()-&gt;isSecure()
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-761079493739518039?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/761079493739518039/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=761079493739518039' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/761079493739518039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/761079493739518039'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/04/get-issecure-of-current-action.html' title='Get is_secure of current action'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-828397352637157031</id><published>2009-04-21T21:53:00.004+04:00</published><updated>2009-04-21T22:04:35.463+04:00</updated><title type='text'>Calling submit method doesn't trigger onsubmit event</title><content type='html'>&lt;p&gt;First, this is the proper behavior, as David Flanagan writes in his book.&lt;/p&gt;
&lt;p&gt;Second, how to overcome this?&lt;/p&gt;
&lt;p&gt;Suppose you have TinyMCE control embedded in a form. It sets his callback on a form's &lt;span style="font-style: italic;"&gt;onsubmit&lt;/span&gt; to clean himself up and write all the stuff back to parent textarea. If you have a link that triggers&lt;span style="font-style: italic;"&gt; submit()&lt;/span&gt;, just create a hidden &lt;span style="font-style: italic;"&gt;&amp;lt;input type="submit"&amp;gt;&lt;/span&gt; and call &lt;span style="font-style: italic;"&gt;click()&lt;/span&gt; on it.&lt;/p&gt;
&lt;p&gt;Click on submit button does trigger the &lt;span style="font-style:italic;"&gt;onsubmit&lt;/span&gt; event of a form, giving TinyMCE a chance to properly save his contents.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-828397352637157031?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/828397352637157031/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=828397352637157031' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/828397352637157031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/828397352637157031'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/04/calling-submit-method-doesnt-trigger.html' title='Calling submit method doesn&apos;t trigger onsubmit event'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-7620457552013324304</id><published>2009-03-03T19:10:00.001+03:00</published><updated>2009-03-03T19:11:25.715+03:00</updated><title type='text'>Dev controllers in the wild</title><content type='html'>Funny how many people &lt;a href="http://www.google.ru/search?hl=ru&amp;amp;newwindow=1&amp;amp;client=firefox-a&amp;amp;rls=org.mozilla%3Aru%3Aofficial&amp;amp;hs=bmC&amp;amp;q=frontend_dev.php+Match+route&amp;amp;btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA&amp;amp;lr=&amp;amp;aq=f&amp;amp;oq="&gt;forget&lt;/a&gt; to hide their dev controllers after deployment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-7620457552013324304?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/7620457552013324304/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=7620457552013324304' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/7620457552013324304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/7620457552013324304'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/03/dev-controllers-in-wild.html' title='Dev controllers in the wild'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-3852804956544438424</id><published>2009-03-02T23:17:00.002+03:00</published><updated>2009-03-02T23:19:58.656+03:00</updated><title type='text'>Handy Eclipse shortcut</title><content type='html'>There is a hotkey in Eclipse which behavior is close to Alt+Tab: press Alt+[left arrow]/[right arrow] to jump between your opened editors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-3852804956544438424?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/3852804956544438424/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=3852804956544438424' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3852804956544438424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3852804956544438424'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/03/handy-eclipse-shortcut.html' title='Handy Eclipse shortcut'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-2807685890738403310</id><published>2009-02-26T11:56:00.004+03:00</published><updated>2009-02-26T12:08:09.391+03:00</updated><title type='text'>Proper Propel behavior registration</title><content type='html'>Suppose you add a propel behavior using this code:
&lt;pre&gt;
sfPropelBehavior::add('Article', array(
 'positioned'
));
&lt;/pre&gt;
Now, where to put it? The &lt;a href="http://www.symfony-project.org/cookbook/1_2/en/"&gt;cookbook&lt;/a&gt; suggests it should be put "in lib/model/Article.php". But what if your behavior includes hooks for peer classes, and in a certain action you call peer methods before using model classes (which is rather common)? In this case you might end up without any behavior attached before the first call of any peer method.
&lt;br /&gt;
&lt;br /&gt;
This happens because of symfony autoloading mechanism:
&lt;ol&gt;
  &lt;li&gt;Peer class method is called&lt;/li&gt;
  &lt;li&gt;It is not found, so autoloading steps in&lt;/li&gt;
  &lt;li&gt;Peer class is loaded&lt;/li&gt;
  &lt;li&gt;Peer class method is executed&lt;/li&gt;
  &lt;li&gt;Model class is loaded&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Propel behavior is added&lt;/b&gt;&lt;/li&gt;
  &lt;li&gt;Result set is hyrdated&lt;/li&gt;
  &lt;li&gt;...&lt;/li&gt;
&lt;/ol&gt;

You see: because model class is loaded after the peer class' method executes, there is no behavior attached to peer class at the time of method execution.
&lt;br /&gt;
&lt;br /&gt;
Registering behaviors in projectConfiguration doesn't work.
&lt;br /&gt;
&lt;br /&gt;
The only solution I found is to register them in plugin's config.php.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-2807685890738403310?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/2807685890738403310/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=2807685890738403310' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2807685890738403310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2807685890738403310'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/02/proper-propel-behavior-registration.html' title='Proper Propel behavior registration'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-216046952739854729</id><published>2009-02-26T11:32:00.005+03:00</published><updated>2009-02-26T11:56:37.136+03:00</updated><title type='text'>Propel Behaviors: registering hooks for doSelectRS</title><content type='html'>If you read the chapter of symfony &lt;a href="http://www.symfony-project.org/cookbook/1_2/"&gt;cookbook&lt;/a&gt; which talks about &lt;a href="http://www.symfony-project.org/cookbook/1_2/en/behaviors"&gt;Propel behaviors&lt;/a&gt;, and tried to register a hook for &lt;i&gt;doSelectRS&lt;/i&gt;, you'd find out it doesn't work.
&lt;br /&gt;
&lt;br /&gt;
In fact, &lt;i&gt;doSelectRS&lt;/i&gt; was removed as of symfony 1.2. &lt;i&gt;doSelectStmt&lt;/i&gt; took its place, so if you want to add a hook to selecting records, you should write something like this:
&lt;pre&gt;
sfPropelBehavior::registerHooks('positioned', array(
 'Peer:doSelectStmt:doSelectStmt' =&gt; array('wgPropelPositionedBehavior', 'addAscendingOrderByPosition'),
));
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-216046952739854729?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/216046952739854729/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=216046952739854729' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/216046952739854729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/216046952739854729'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/02/using-propel-behaviors.html' title='Propel Behaviors: registering hooks for doSelectRS'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-3930581099237772987</id><published>2009-02-25T21:28:00.007+03:00</published><updated>2009-02-25T21:35:22.306+03:00</updated><title type='text'>How to get all action variables</title><content type='html'>For my programming work, I use &lt;a href="http://www.symfony-project.org/"&gt;symfony&lt;/a&gt; framework. It has a funny system of passing variables from actions to templates: you just set the variable as a property of your action object and it automatically becomes available in template that is used to render results. So, there is a bunch of variables you can use, but no way of getting the whole array of them. This line will do the trick:
&lt;div style="overflow: auto;"&gt;
$vars = $sf_context-&gt;getActionStack()-&gt;getLastEntry()-&gt;getActionInstance()-&gt;getVarHolder()-&gt;getAll();
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-3930581099237772987?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/3930581099237772987/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=3930581099237772987' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3930581099237772987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3930581099237772987'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/02/how-to-get-all-action-variables.html' title='How to get all action variables'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-6908322553270136725</id><published>2009-02-01T20:18:00.002+03:00</published><updated>2009-02-01T20:38:50.748+03:00</updated><title type='text'>Mouse wheel handling with Prototype</title><content type='html'>There is a bug wandering the web.

If you google for "prototype mouse wheel", you'll find some snippets of code. They are rather good, except for their age. Those are '06-'07 oldies, and we have '09 around.

Since the time that code was written, there has been a release of Firefox 3, in which they fixed one tiny wee peculiarity: the value of event &lt;span style="font-style: italic;"&gt;detail&lt;/span&gt; property&lt;span style="font-style: italic;"&gt;, &lt;/span&gt;which holds the "amount" of scroll. Before the new version of FF it was +-3 for single wheel turn, which is reflected in the old code as the division of &lt;span style="font-style: italic;"&gt;detail&lt;/span&gt; by 3, which gives "normalized" wheel move data.

FF3 guys thought it was a shame to have 3 as value of &lt;span style="font-style: italic;"&gt;detail&lt;/span&gt; property while in fact it represents only one wheel turn. So they adjusted it to be nice +-1. The problem is, old code returns zero now, because 1/3 equals 0.

I will post my fix for &lt;a href="http://www.ogonek.net/mousewheel/demo.html"&gt;this solution&lt;/a&gt;, although it's easy as heck to port it to other one.
&lt;pre&gt;
delta = !!event.detail*(event.detail&gt;0? 1 : -1);
&lt;/pre&gt;
Now this behaves good both in FF2 and FF3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-6908322553270136725?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/6908322553270136725/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=6908322553270136725' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6908322553270136725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6908322553270136725'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/02/mouse-wheel-handling-with-prototype.html' title='Mouse wheel handling with Prototype'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-1411640842566993264</id><published>2009-01-19T18:58:00.003+03:00</published><updated>2009-01-19T19:11:24.216+03:00</updated><title type='text'>semicolon keyCode</title><content type='html'>When you press semicolon on Firefox and poke in the event object for its key code, the result is 59. The funny thing is, other browsers give you 186. So, if you want to execute some action when user presses semicolon, you have to check for both values.
&lt;pre&gt;
if (event.keyCode == 186 || event.keyCode == 59) {
   // some stuff
}
&lt;/pre&gt;
Developers often choose to use semicolon in conjunction with CTRL or ALT keys to issue commands to application in a normal "desktop way". For example, CTRL+; activates other keyboard shortcuts in &lt;a href="http://www.fogcreek.com/FogBUGZ/"&gt;FogBugz&lt;/a&gt;. If you are a clean code maniac (as I am), the alternative for semicolon is &lt;b&gt;'&lt;/b&gt; (an apostrophe), which has a nice key code of 222.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-1411640842566993264?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/1411640842566993264/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=1411640842566993264' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1411640842566993264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1411640842566993264'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/semicolon-keycode.html' title='semicolon keyCode'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-6737188174631612403</id><published>2009-01-14T13:23:00.015+03:00</published><updated>2009-09-25T14:14:12.575+04:00</updated><title type='text'>Prototype with TinyMCE: adventures in iframe space</title><content type='html'>If you use TinyMCE on a fairly large site with a narrow target auditence, there always comes a day when you have to sit down and develop some custom plugins for the rich text editor. For example, if your site is all about Linux and Open Source (like &lt;a href="http://www.nixp.ru/"&gt;nixp.ru&lt;/a&gt;), your users would want to insert code snippets in their posts. This requires some special behavior, which is not provided by default. You have to code it yourself as a custom plugin.
&lt;br /&gt;
&lt;br /&gt;
Plugin creation is very closely related to DOM manipulation. TinyMCE has its &lt;a href="http://wiki.moxiecode.com/index.php/TinyMCE:API"&gt;own DOM API&lt;/a&gt;, but it is not nearly as comprehensive as the one provided by Prototype. Being used to walk the DOM with convenient methods like &lt;a href="http://www.prototypejs.org/api/element/up"&gt;up&lt;/a&gt; and &lt;a href="http://www.prototypejs.org/api/element/down"&gt;down&lt;/a&gt;, I hated TinyMCE for the lack of those.
&lt;br /&gt;
&lt;br /&gt;
As it turned out, you can't use Prototype methods while developing plugins for TinyMCE. Prototype correctly detects that Firefox 3 has implemented ElementExtensions and SpecificElementExtensions: that means &lt;a href="http://www.prototypejs.org/api/element/extend"&gt;Element.extend&lt;/a&gt;, used internally by &lt;a href="http://www.prototypejs.org/api/utility/dollar"&gt;dollar function&lt;/a&gt;, just returns the element, passing the stage of augmenting it with handy methods. The magic happens when designMode of document is set to 'On': Firefox doesn't apply these extensions to elements of such document. This results in awful behavior: you can't use Prototype methods on elements because Element.extend won't copy it to element thinking they are present (hey, Firefox already implemented them!), but the browser returns the elements untouched, just old plain HTMLElements.
&lt;br /&gt;
&lt;br /&gt;
My solution to this is a slightly different implementation of dollar function:
&lt;pre&gt;
$t = (function() {

  var Methods = { }, ByTag = Element.Methods.ByTag;
  Object.extend(Methods, Element.Methods);
  Object.extend(Methods, Element.Methods.Simulated);

  var extend = function(element, force) {
    if (!element || (element._extendedByPrototype &amp;&amp; !force) ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
      tagName = element.tagName, property, value;

    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    for (property in methods) {
      value = methods[property];
      if (Object.isFunction(value) &amp;&amp; !(property in element))
        element[property] = value.methodize();
    }

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;
  }
  
  return extend;
})();
&lt;/pre&gt;I gave it a different name because there is no need to &lt;span style="font-style:italic;"&gt;override&lt;/span&gt; the dollar function: since the parent document of an iframe is not in designMode, it does the job properly most of the time. But in plugin development, usage of $t ensures the elements are extended with all the Prototype sugar.

Sometimes (particularly, when you insert an extended element into another) the element loses its extended functions. I don't know why it happens. The workaround is the second parameter to &lt;span style="font-style:italic;"&gt;$t&lt;/span&gt;, called &lt;span style="font-style:italic;"&gt;force&lt;/span&gt;. This will force reaugmentation of an element disregarding the _extendedByPrototype property.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-6737188174631612403?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/6737188174631612403/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=6737188174631612403' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6737188174631612403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6737188174631612403'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/prototype-with-tinymce-adventures-in.html' title='Prototype with TinyMCE: adventures in iframe space'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-3783249720203898843</id><published>2009-01-13T20:23:00.004+03:00</published><updated>2009-11-06T00:10:56.685+03:00</updated><title type='text'>Verbose boolean parameters</title><content type='html'>Suppose we program in &lt;a href="http://en.wikipedia.org/wiki/Javascript"&gt;Javascript&lt;/a&gt;. There is a function &lt;i&gt;updatePost&lt;/i&gt; that takes a boolean parameter indicating whether it should highlight the updated post or not.
&lt;pre&gt;updatePost: function(highlight) {
  // ...code to update post...
  if (highlight) {
      post.highlight()
  }
}
&lt;/pre&gt;One would definitely call it like this:
&lt;pre&gt;this.updatePost(true);
&lt;/pre&gt;The problem is, that's not very explanatory. In other words, you can't tell straight from the line what this &lt;i&gt;true&lt;/i&gt; does.
I propose a solution that takes advantage of &lt;a href="http://en.wikipedia.org/wiki/Loose_typing"&gt;loose typing&lt;/a&gt;: just pass a string containing a parameter meaning as an argument.
&lt;pre&gt;
this.updatePost('and highlight');
&lt;/pre&gt;Now, this is definitily more verbose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-3783249720203898843?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/3783249720203898843/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=3783249720203898843' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3783249720203898843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/3783249720203898843'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/verbose-boolean-parameters.html' title='Verbose boolean parameters'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-1696673364236204463</id><published>2009-01-05T15:04:00.003+03:00</published><updated>2009-01-05T15:12:51.980+03:00</updated><title type='text'>Form Ajax upload with Opera</title><content type='html'>It looks like Opera hates having its forms disabled.

Suppose you have a form with onSubmit handler attached to it using HTML.
&lt;pre&gt;
&amp;lt;form action="..." onSubmit="return myHandler(this);"&amp;gt;
&lt;/pre&gt;

and myHandler looks like that:
&lt;pre&gt;
/*
form is the first argument to handler
the very form being submitted
*/
form.disable();
new Ajax.Request(form.action,{
 method: 'post',
 parameters: {
  username: $('loginFormUsername').value,
  password: $('loginFormPassword').value
 },
 onSuccess: this.loginSuccess.bind(this)
});
return false;
&lt;/pre&gt;

The code works fine in FF, Chrome ans Safari, but breaks in Opera. It seems that disabling the form in onSubmit handler somehow triggers its normal submission, although handler returns false. The only solution I found is to conditionalize the disabling of form:
&lt;pre&gt;
if (!Prototype.Browser.Opera) {
 form.disable();
}
&lt;/pre&gt;

How do you manage such a problem?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-1696673364236204463?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/1696673364236204463/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=1696673364236204463' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1696673364236204463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1696673364236204463'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/form-ajax-upload-with-opera.html' title='Form Ajax upload with Opera'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-1153210880955152790</id><published>2009-01-05T14:57:00.003+03:00</published><updated>2009-01-05T15:03:24.608+03:00</updated><title type='text'>Revert to default styles</title><content type='html'>For example, you've changed the default colors of a link using &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt;'s &lt;a href="http://www.prototypejs.org/api/element/setStyle"&gt;setStyle&lt;/a&gt;.
&lt;pre&gt;
$('answer-link').setStyle({
 color: '#000000',
 borderBottomColor: '#000000'
});
&lt;/pre&gt;

Then, after some action, you want to change the styles back to the original ones. You have an option of specifying them again:
&lt;pre&gt;
$('answer-link').setStyle({
 color: '#B2B2B2',
 borderBottomColor: '#B2B2B2'
});
&lt;/pre&gt;

...but that means you'll have to change your JS if designer changes his CSS. This kind of dependency is bad and, in fact, could be avoided
&lt;pre&gt;
$('answer-link').setStyle({
 color: '',
 borderBottomColor: ''
});
&lt;/pre&gt;

...by using empty strings as style property values.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-1153210880955152790?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/1153210880955152790/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=1153210880955152790' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1153210880955152790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/1153210880955152790'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/revert-to-default-styles.html' title='Revert to default styles'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-6367352528719064175</id><published>2009-01-03T17:41:00.002+03:00</published><updated>2009-01-03T17:43:50.855+03:00</updated><title type='text'>How to preload tinyMCE theme and language scripts</title><content type='html'>These three commands seem to do the job for me:
&lt;pre&gt;
tinymce.ScriptLoader.add(tinymce.baseURL+'/langs/ru.js');
tinymce.ThemeManager.load('advanced', '/js/tiny_mce/themes/advanced/editor_template.js');
tinymce.ScriptLoader.loadQueue();
&lt;/pre&gt;

Of course, they should be called after main tinymce script is loaded.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-6367352528719064175?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/6367352528719064175/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=6367352528719064175' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6367352528719064175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/6367352528719064175'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2009/01/how-to-preload-tinymce-theme-and.html' title='How to preload tinyMCE theme and language scripts'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-2491044422038469212</id><published>2008-12-18T14:33:00.003+03:00</published><updated>2008-12-18T14:39:06.294+03:00</updated><title type='text'>More on masterhost</title><content type='html'>I use &lt;a href="http://www.symfony-project.org/"&gt;symfony&lt;/a&gt; framework for my web development. I'm very glad that this one doesn't enforce you to use the directory structure it creates by default. So, if your shared host public directory is not "web" (symfony default), but something like "www" or "public_html", just call &lt;span style="font-style:italic;"&gt;setWebDir&lt;/span&gt; method from your project confirugation's &lt;span style="font-style:italic;"&gt;setup&lt;/span&gt; method, just like this:
&lt;pre&gt;
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this-&gt;setWebDir(sfConfig::get('sf_root_dir').'/www');
    // Change "www" to your public directory name
  }
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-2491044422038469212?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/2491044422038469212/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=2491044422038469212' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2491044422038469212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/2491044422038469212'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2008/12/more-on-masterhost.html' title='More on masterhost'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-7315823910706777067</id><published>2008-12-18T13:37:00.004+03:00</published><updated>2008-12-18T13:44:06.717+03:00</updated><title type='text'>Masterhost and 411 Content Length required</title><content type='html'>Hey, guys, I just discovered a glitch on Masterhost servers. If you get 411 from their nginx, try looking up your error_log. That might be not the problem of your client not setting Content-Length while sending chunked content.
&lt;br&gt;&lt;br&gt;
If your error_log says something like "Failed to create file upload directory "/var/tmp"", look for tempnam() function in your code. This thingie is trying to create temporary file in masterhost's server own /tmp, not your virtual host's one. The only solution is to avoid using tempnam().&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-7315823910706777067?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/7315823910706777067/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=7315823910706777067' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/7315823910706777067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/7315823910706777067'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2008/12/masterhost-and-411-content-length.html' title='Masterhost and 411 Content Length required'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1176484787338693227.post-8804522445799572941</id><published>2008-07-23T00:28:00.023+04:00</published><updated>2008-07-23T13:04:01.015+04:00</updated><title type='text'>It’s all about interface, baby</title><content type='html'>What’s a program, really?
&lt;br /&gt;
&lt;br /&gt;
A bunch of programming language statements? - Certainly &lt;a href="http://en.wikibooks.org/wiki/List_of_hello_world_programs"&gt;not&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Some screens for user to type in their data and have it processed? - That’s warmer.
&lt;br /&gt;
&lt;br /&gt;
A paper prospect with a couple of sentences blaming current government and a long passage on how it all could be done better? - Get out of here, you nose-thrusting politician!
&lt;br /&gt;
&lt;br /&gt;
Ok, so what is it, now? – A crutch. Well, just like every technical object you have on the desk. Some time ago when word processing and e-mail still wasn’t invented, people needed to clip papers. And they did it pretty nicely, wasting on it about five minutes. You see, in 1800, five minutes were a blah. Five mins here, five mins there, people in 1800 had plenty of time. Not that they had more than 24 hours in a day, it has something to do with the feeling of time flow. Now, as year marks on calendar came closer to 1860s, time shrank. The first five mins you help your boss write a note, the second five mins you speak to somebody that desperately needs attention, and you have no time to do paper-clipping! So well, smart people invented a stapler (which, of course, wasn’t called so in 1860s and was larger and didn’t have any preinstalled RAM). The stapler is a “crutch”, a prosthetic device that helps people who have a kind of “time disability” to do a simple thing like paper-clipping quickly.
&lt;br /&gt;
&lt;br /&gt;
Nowadays, all businesses have their websites. Certainly, a website could be just a number of HTML pages hyperlinked together, and having it this way has some advantages like decreased time for page generation (there’s simply no page generation), no need for complicated power-consuming webserver software, etc. But businesses wanted their customers to buy things on websites, which led to invention of cart concept, which meant to serve different pages to different customers, and good businessmen just couldn’t place 5000 people making HTML pages on the fly, so good programmers invented web programming languages and wrote content management software implementing the aforementioned cart concept and much more. Now, top-management bosses don’t know HTML and couldn’t care less about learning it. But they like fancy markup like &lt;span style="font-weight: bold;"&gt;bold&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;italics&lt;/span&gt; and &lt;span style=""&gt;underline (those without aesthetic sense even use &lt;span id="blink"&gt;blink&lt;/span&gt; | &lt;span id="disable"&gt;&lt;a href="javascript:disabler();"&gt;disable it now&lt;/a&gt;&lt;/span&gt;). Smart creators of CMS thingies are aware of this situation and include web-based rich text editors (again, a crutch!) in their products. After playing around with brand-new yesterday-bought system, businessmen realize that they really have neither time nor skills for writing and they need a content manager. Imagine you are a guru in HTML doing on-demand content management for a couple of firms. You hate those RTE because they generate w3c-incompatible HTML and mess the things up, so you turn them off. But nobody told you about a secretary whose knowledge of HTML consists of a statement that it’s a "web programming language". While you perform relatively complex operations like building tables, this poor girl posts company news on the first page, and those news include the markup the boss likes, and she can’t make it without an RTE disabled by you. From a programmer’s point of view, this situation has an obvious solution: let user have a checkbox in his settings that says “Enable rich text editor”, which defaults to be set to true and could be unchecked by arrogant HTML-wise content managers.
This tiny feature requires creating a checkbox in user settings HTML code, adding a place for this setting in some kind of user settings storage you use, and wrapping code for transforming a textarea to RTE with an &lt;code&gt;If&lt;/code&gt; checking whether user prefers it to be RTE or not.
&lt;br /&gt;
In five minutes, your program, your CMS, a crutch created by your team for businessmen and secretaries and even content managers is easier to use by more than one man at a time.
&lt;br /&gt;
Not so fast! - you say. With all those tiny features we’ll soon have a user settings page which is four screens long and has checkboxes organized in three columns, it just &lt;span style="font-weight: bold;"&gt;won’t&lt;/span&gt; be easier to use. Now, it’s your choice how to design your software. The way of checkboxes is not that bad, dive into Word (Writer) options and you’ll see it’s populated by little squares with ticks. &lt;a href="http://www.joelonsoftware.com/articles/fog0000000020.html"&gt;And don’t think you can get away having only 20% checkboxes the Word has&lt;/a&gt;. So, creating software is all about creating an interface which acts like a crutch that is easy to use and fits people needs.
&lt;/span&gt;
&lt;script type="text/javascript"&gt;
var t = true;
var f = function() {
if (t = !t) {
document.getElementById("blink").style.visibility = "hidden";
} else {
document.getElementById("blink").style.visibility = "visible";
}
}
var myInterval = setInterval(f,1000);
var disabler = function() {
window.clearInterval(myInterval);
document.getElementById("blink").style.visibility = "visible";
document.getElementById("disable").innerHTML = "Thanks! You saved a kitten."
}
&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1176484787338693227-8804522445799572941?l=musicofcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://musicofcode.blogspot.com/feeds/8804522445799572941/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1176484787338693227&amp;postID=8804522445799572941' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/8804522445799572941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1176484787338693227/posts/default/8804522445799572941'/><link rel='alternate' type='text/html' href='http://musicofcode.blogspot.com/2008/07/its-all-about-interface-baby.html' title='It’s all about interface, baby'/><author><name>Denis Gorbachev</name><uri>http://www.blogger.com/profile/13960421711089496300</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
