Alexander Ulizko2017-02-14T11:00:32+00:00http://ulizko.com/Alexander Ulizkoalexander@ulizko.comMongoDB-based Backend::Store implementation for I18n gem2010-12-28T00:00:00+00:00http://ulizko.com/2010/12/28/408<p>Currently I’m working on a web project on top of rails 3 and mongodb.</p>
<p>Recently we faced the necessity of changing I18n backend from simple to something more dynamic (in fact, we wanted to allow the non-geeks from our team to participate in the internationalization process via web interface).</p>
<p>I googled for “mongodb i18n”, “mongo_mapper i18n”, “mongodb i18n backend”, etc. and found nothing, so I wrote my own implementation of mongodb backend for I18n, called <a href="https://github.com/aulizko/mongo-i18n">mongo-i18n</a> (in fact, «wrote» is too strong a word — all that I needed to do was to implement three methods of the store interface:)</p>
<p>You can grab the sources <a href="https://github.com/aulizko/mongo-i18n">here</a> or you can install the gem via command line:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gem install mongo-i18n</code></pre></figure>
<h4 id="usage">Usage:</h4>
<p>I recommend to start with <a href="https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/chain.rb">Chain</a> backend while mongodb collection is empty, and move to entirely mongodb-based backend when you populate your database with all I18n messages.</p>
<p>Begin with:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">collection</span> <span class="o">=</span> <span class="no">Mongo</span><span class="o">::</span><span class="no">Connection</span><span class="p">.</span><span class="nf">new</span><span class="p">[</span><span class="s1">'my_app_related_db'</span><span class="p">].</span><span class="nf">collection</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">)</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span> <span class="o">=</span> <span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">Chain</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">KeyValue</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">MongoI18n</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">collection</span><span class="p">)),</span> <span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span><span class="p">)</span></code></pre></figure>
<p>And finish with:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">collection</span> <span class="o">=</span> <span class="no">Mongo</span><span class="o">::</span><span class="no">Connection</span><span class="p">.</span><span class="nf">new</span><span class="p">[</span><span class="s1">'my_app_related_db'</span><span class="p">].</span><span class="nf">collection</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">)</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span> <span class="o">=</span> <span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">KeyValue</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">MongoI18n</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">collection</span><span class="p">)</span></code></pre></figure>
<p>If you are already using a mongodb ORM in your project (and I suppose you are, why else would you be reading this article? :), I recommend using the existing database connection.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">collection</span> <span class="o">=</span> <span class="no">MongoMapper</span><span class="p">.</span><span class="nf">database</span><span class="p">.</span><span class="nf">collection</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">)</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span> <span class="o">=</span> <span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">KeyValue</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">MongoI18n</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">collection</span><span class="p">))</span></code></pre></figure>
<p>Free Christmas gift, the rake file to import en.yml into mongodb:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44</pre></td><td class="code"><pre><span class="c1"># usage:</span>
<span class="c1"># bundle exec rake locale:file RAILS_ENV=production</span>
<span class="c1"># if you want to export a different locale (not en.yml), provide locale option, as follows:</span>
<span class="c1"># bundle exec rake locale:file RAILS_ENV=production locale=ru</span>
<span class="nb">require</span> <span class="s1">'mongo-i18n'</span>
<span class="k">def</span> <span class="nf">write_to_database</span><span class="p">(</span><span class="n">sc</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">path</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span>
<span class="n">sc</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">to_json</span>
<span class="k">end</span>
<span class="c1"># traverse through hash</span>
<span class="k">def</span> <span class="nf">traverse</span><span class="p">(</span><span class="n">sc</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
<span class="k">case</span> <span class="n">obj</span>
<span class="k">when</span> <span class="no">Hash</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">k</span><span class="p">,</span><span class="n">v</span><span class="o">|</span>
<span class="n">traverse</span><span class="p">(</span><span class="n">sc</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">path</span> <span class="o">+</span> <span class="p">[</span><span class="n">k</span><span class="p">])</span>
<span class="k">end</span>
<span class="k">when</span> <span class="no">Array</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span><span class="o">|</span><span class="n">v</span><span class="o">|</span> <span class="n">traverse</span><span class="p">(</span><span class="n">sc</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="p">}</span>
<span class="k">else</span> <span class="c1"># end values</span>
<span class="n">write_to_database</span><span class="p">(</span><span class="n">sc</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">namespace</span> <span class="ss">:locale</span> <span class="k">do</span>
<span class="n">desc</span> <span class="o"><<-</span><span class="no">eos</span><span class="sh">
Exports $app/config/locale/$locale.yml contents to mongodb database.
If locale is not specified, default (en) locale file will be exported.
</span><span class="no"> eos</span>
<span class="n">task</span> <span class="ss">:file</span> <span class="k">do</span>
<span class="n">locale</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'locale'</span><span class="p">]</span> <span class="o">||</span> <span class="s2">"en"</span>
<span class="n">environment</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'RAILS_ENV'</span><span class="p">]</span> <span class="o">||</span> <span class="s2">"development"</span>
<span class="c1"># I keep mongodb connection descriptor in config/mongodb.yml</span>
<span class="n">config</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">::</span><span class="nb">load</span><span class="p">(</span><span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="no">Rails</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'config/mongodb.yml'</span><span class="p">)))</span>
<span class="n">collection</span> <span class="o">=</span> <span class="no">Mongo</span><span class="o">::</span><span class="no">Connection</span><span class="p">.</span><span class="nf">new</span><span class="p">[</span><span class="n">config</span><span class="p">[</span><span class="s2">"development"</span><span class="p">][</span><span class="s2">"database"</span><span class="p">]].</span><span class="nf">collection</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">)</span>
<span class="n">store</span> <span class="o">=</span> <span class="no">MongoI18n</span><span class="o">::</span><span class="no">Store</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">collection</span><span class="p">)</span>
<span class="n">dump</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">::</span><span class="nb">load</span><span class="p">(</span><span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="no">Rails</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"config"</span><span class="p">,</span><span class="s2">"locales"</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">locale</span><span class="si">}</span><span class="s2">.yml"</span><span class="p">)))</span>
<span class="n">traverse</span><span class="p">(</span><span class="n">store</span><span class="p">,</span> <span class="n">dump</span><span class="p">,</span> <span class="p">[])</span>
<span class="k">end</span>
<span class="k">end</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Any feedback would be welcome.</p>
Quick tip for Intellij Idea users: manage your dependencies order2010-12-01T00:00:00+00:00http://ulizko.com/2010/12/01/379<p>Recently I was developing project on top of Servlet API 3.0 and GWT 2.1 and faced the following problem:
When I wanted to use async support from Servlet 3.0, <a href="http://www.jetbrains.com/idea/">Idea</a> was unable to resolve method startAsync for HttpServletRequest.</p>
<p>Like this:</p>
<p><img title="Resolving method failure" src="/images/idea_dependencies/resolving_method_failure.png" alt="Resolving method failure" width="344" height="31" /></p>
<p>It turns out that gwt-dev-2.1.0.jar contains Servlet API 2.4 (looks like it comes with jetty or tomcat gwt dependencies) and <a href="http://www.jetbrains.com/idea/">Idea</a> uses it for inspections and autocomplete.</p>
<p>Solution is simple:
Check if servlet api 3.0 jar comes after gwt-dev-2.1.0.jar in yout project module dependencies (meta+; shortcut), like this:</p>
<p><img title="Wrong dependency order" src="/images/idea_dependencies/wrong_dependency_order.png" alt="Wrong dependency order" width="481" height="34" /></p>
<p>And swap them using “Move Up”|”Move Down” keys, than hit OK button.
After that Idea will resolve Servlet API as expected:</p>
<p><img title="Resolving method success" src="/images/idea_dependencies/resolving_method_success.png" alt="Resolving method success" width="619" height="169" /></p>
Strip firebug console api calls2009-10-05T00:00:00+00:00http://ulizko.com/2009/10/05/371<p><strong>Update</strong>: После <a href="http://habrahabr.ru/blogs/webdev/71586/">обсуждения</a> на хабре и продолжительных размышлений на тему, решил отказаться от подобного метода. Думаю пересесть на <a href="http://code.google.com/closure/compiler/">Google Closure Compiler</a> и с его помощью обрезать debug-код, как расписано в <a href="http://javascript.ru/optimize/google-closure-compiler/define">статье</a> у Ильи Кантора. Так что этот пост подустарел и оставляю я его чисто для истории.</p>
<p>На днях надо было сходить показать представителю заказчика, как пользоваться одной свежевстроенной в проект фичей.
За полчаса до выхода подготовил новый билд, протестировал.</p>
<p>По приезду оказалось, что у заказчика фича не работает. Неприятно получилось, в общем.</p>
<p>Но радость ваша, мои дорогие читатели, была бы не полной, если бы я не сообщил вам, что там случилось и что я по этому поводу предпринял.</p>
<p>Оказалось, что я забыл удалить в функции-обработчике события вызов firebug'овской консоли (<code>console.log</code>… и т.п.) Со мной вообще часто бывает такое, что я то какой-то символ, случайно ткнув на клавиатуру, допишу, то, наоборот, удалю - короче, использование редакторов без подсветки синтакса и (желательно) анализа структуры кода мне противопоказаны.</p>
<p>Так как я использую apache ant для развертывания приложения на боевой сервер, я дописал маленький скриптик, который уберет все вызовы <code lang="javascript">console.log(/* something */)</code> или <code lang="javascript">console.dir(/* something */)</code> из вашего кода.</p>
<p>Собственно, вот он:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23</pre></td><td class="code"><pre><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="nt"><project</span> <span class="na">name=</span><span class="s">"deploy"</span> <span class="na">default=</span><span class="s">"stripFirebugConsoleCalls"</span> <span class="na">basedir=</span><span class="s">"."</span><span class="nt">></span>
<span class="c"><!-- место, где сложены наши еще не сжатые и не слитые в один js-скрипты --></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"js"</span> <span class="na">value=</span><span class="s">"js/"</span><span class="nt">/></span>
<span class="c"><!-- регулярка для отлова нездоровых элементов (беззастенчиво утянута с yui builder'a, и слегка доведена напильником)
http://github.com/yui/builder/blob/master/componentbuild/shared/properties.xml 79-я строка --></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"firebug.console.regex"</span> <span class="na">value=</span><span class="s">"^.*?(?:console.log|console.dir).*?(?:;|\).*;|(?:\r?\n.*?)*?\).*;).*;?.*?\r?\n"</span> <span class="nt">/></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"firebug.console.regex.flags"</span> <span class="na">value=</span><span class="s">"mg"</span> <span class="nt">/></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"firebug.console.regex.byline"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"firebug.console.regex.replace"</span> <span class="na">value=</span><span class="s">""</span> <span class="nt">/></span>
<span class="c"><!-- Сам таргет тоже без затей "вдохновен" YUI Builder'ом, оригинал тут:
http://github.com/yui/builder/blob/master/componentbuild/3.x/module.xml 19-я строка --></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"stripFirebugConsoleCalls"</span> <span class="na">description=</span><span class="s">"Replace firebug console calls"</span><span class="nt">></span>
<span class="nt"><replaceregexp</span> <span class="na">byline=</span><span class="s">"${firebug.console.regex.byline}"</span>
<span class="na">match=</span><span class="s">"${firebug.console.regex}"</span>
<span class="na">replace=</span><span class="s">"${firebug.console.regex.replace}"</span>
<span class="na">flags=</span><span class="s">"${firebug.console.regex.flags}"</span><span class="nt">></span>
<span class="nt"><fileset</span> <span class="na">dir=</span><span class="s">"${js}"</span> <span class="na">includes=</span><span class="s">"*.js"</span> <span class="nt">/></span>
<span class="nt"></replaceregexp></span>
<span class="nt"></target></span>
<span class="nt"></project></span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Использовать так: создать xml-файл с удобным вам именем (например, boom.xml) и скопипастить в него этот код. Разумеется, стоит поправить значение переменной js, которая указывает на папку с еще не сжатыми js-скриптами. После этого запускаем адскую машину такой командой (для *nix):</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">ant stripFirebugConsoleCalls -buildfile /path/to/boom.xml</code></pre></figure>
<p>Вот и все. Засим я откланиваюсь до следующего ЧП или конца проекта.</p>
Перестановки2009-03-17T00:00:00+00:00http://ulizko.com/2009/03/17/351<p>Дорогие мои марсиане. Сограждане. Я принял решение, и оно далось мне нелегко.</p>
<p>Перед тем, как его огласить, я позволю себе небольшой экскурс в историю, с тем, чтобы как можно полнее представить вам причины, которые вынудили поступить меня именно так, и никак иначе.</p>
<p>Во-первых, уже достаточно давно меня раздражает движок wordpress, на котором имеет несчастие крутиться этот несчастный блог. Долго полнилась чаша моего терпения, и наконец переполнилась.</p>
<p>Во-вторых, от многих из вас до меня доходят сигналы, что было бы неплохо как-то разделить статьи технического плана и посты “про остальное”. И слова ваши доходили до моего сердца и наконец нашли в нем отклик.</p>
<p>В-третьих, меня уже давно не устраивает низкая посещаемость - почти все программисты (и особенно java/javascript программисты) общаются на англоязычных ресурсах. К слову сказать, все средства для ведения мультиязычного блога на wordpress откровенно убоги. Это, так сказать, еще одно “фи” в сторону wrordpress’a.</p>
<p>В общем, исходя из всего вышенаписанного, я думаю, что правильнее всего будет сделать следующее:</p>
<ul>
<li> Разделить блог на две части: лытдыбр (под которую уже выделен отдельный блог по адресу <a href="http://ulizko.name">http://ulizko.name</a>) и т.н. "технические статьи", которые останутся по этому адресу.</li>
<li> Весь блог будет вестись на английском языке. Тому есть две причины: первая это та, что англоговорящих программистов (т.е. людей, которым интересен этот контент) в разы больше, чем русскоговорящих, а значит, я смогу делиться мыслями с гораздо большим количеством народа, что, откровенно говоря, меня заводит. И вторая - я смогу поднять свой уровень английского языка, что также лишним не будет. Будут ли доступны в том или ином виде тексты статей на русском - пока не знаю, сообщу дополнительно.</li>
<li> Будет проведен редизайн блога. Просто так, потому что мне того хочется.</li>
<li> Блог будет переведен на другую, самописную платформу. Как говорится, сделанное своими руками колесо - самое круглое колесо в мире! Опять же, есть несколько интересных задумок, которые очень и очень сложно реализовать на базе wordpress'a.</li>
</ul>
<p>Что же требуется от вас, читателей?</p>
<ul>
<li>Если вы читаете блог ради технических статей - стэй, как говорится, тюнд. Между постами будет нехилый перерыв, думаю, с месяц, но потом все наладится. Правда, будет уже на английском языке. И rss будет тот же.</li>
<li> А вот если вам нравятся все остальные посты, то вам нужно подписываться на <a href="http://ulizko.name/rss.xml">rss</a> от ulizko.name. Напоминаю, все посты, не относящиеся к IT, будут перенесены в <a href="http://ulizko.name">http://ulizko.name</a>.</li>
</ul>
Невпопад2009-03-16T00:00:00+00:00http://ulizko.com/2009/03/16/360<p>Хочу в отпуск. Так хочу, что меня все раздражает.</p>
<p>GC в ruby в сто раз примитивнее того, что используется в jvm. Ц-ц-ц.</p>
<p>И еще меня начинает раздражать “мусорность” javascript. Я имею ввиду, что, в целом, многие ништяки из ФЯП можно реализовать и в javascript, но на java-подобный синтакс такие штуки не очень хорошо ложатся:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59</pre></td><td class="code"><pre><span class="c1">// пусть ArrayUtils - это специальная утилита для работы с массивами, </span>
<span class="c1">// реализующая for…each, map/reduce для всех браузеров, включая ie6. </span>
<span class="c1">// Что-то наподобие YUI.Array</span>
<span class="kd">var</span> <span class="nx">A</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">ArrayUtils</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">map</span> <span class="p">:</span> <span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">map</span><span class="p">)</span> <span class="p">?</span>
<span class="kd">function</span> <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">fn</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">a</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">fn</span><span class="p">,</span> <span class="nx">c</span> <span class="o">||</span> <span class="nb">window</span><span class="p">);</span>
<span class="p">}</span> <span class="p">:</span>
<span class="kd">function</span> <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">fn</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="p">[],</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">a</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
<span class="k">while</span><span class="p">(</span><span class="nx">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">result</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">fn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">c</span> <span class="o">||</span> <span class="nb">window</span><span class="p">,</span> <span class="nx">a</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">},</span>
<span class="na">filter</span> <span class="p">:</span> <span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">filter</span><span class="p">)</span> <span class="p">?</span>
<span class="kd">function</span> <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">fn</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">a</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">fn</span><span class="p">,</span> <span class="nx">c</span> <span class="o">||</span> <span class="nb">window</span><span class="p">);</span>
<span class="p">}</span> <span class="p">:</span>
<span class="kd">function</span> <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">func</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="p">[],</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">a</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
<span class="k">while</span><span class="p">(</span><span class="nx">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="k">in</span> <span class="nx">a</span> <span class="o">&&</span> <span class="nx">fn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">c</span> <span class="o">||</span> <span class="nb">window</span><span class="p">,</span> <span class="nx">a</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">a</span><span class="p">))</span> <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">a</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="c1">// получим новый массив, получаемый из исходного путем умножения каждого элемента на два.</span>
<span class="c1">// уже немножко "weird", не так ли?</span>
<span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">];</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">item</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> <span class="p">});</span> <span class="c1">// 2, 4, 6, 8</span>
<span class="c1">// а теперь пример повеселее:</span>
<span class="kd">var</span> <span class="nx">persons</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span>
<span class="na">name</span> <span class="p">:</span> <span class="s1">'John'</span><span class="p">,</span>
<span class="na">lastName</span> <span class="p">:</span> <span class="s1">'Doe'</span><span class="p">,</span>
<span class="na">address</span> <span class="p">:</span> <span class="s1">'California, Los Angeles'</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="na">name</span> <span class="p">:</span> <span class="s1">'Ivan'</span><span class="p">,</span>
<span class="na">lastName</span> <span class="p">:</span> <span class="s1">'Ivanov'</span><span class="p">,</span>
<span class="na">address</span> <span class="p">:</span> <span class="s1">'Moscow'</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="na">name</span> <span class="p">:</span> <span class="s1">'Abraham'</span><span class="p">,</span>
<span class="na">lastName</span> <span class="p">:</span> <span class="s1">'Smith'</span><span class="p">,</span>
<span class="na">address</span> <span class="p">:</span> <span class="s1">'California, San Francisco'</span>
<span class="p">}</span>
<span class="p">];</span>
<span class="c1">// Получим массив, состоящий только из полных имен пользователей, проживающих в калифорнии</span>
<span class="kd">var</span> <span class="nx">townRegex</span> <span class="o">=</span> <span class="sr">/california/i</span><span class="p">;</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">A</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">persons</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">person</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">townRegex</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">address</span><span class="p">);</span>
<span class="p">}),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">person</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">person</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">person</span><span class="p">.</span><span class="nx">lastName</span><span class="p">;</span>
<span class="p">});</span> <span class="c1">// John Doe, Abraham Smith</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Чрезвычайно избыточный и непонятный с непривычки код, особенно в сравнении с аналогичным в ruby или python.</p>
manual written if2009-03-15T00:00:00+00:00http://ulizko.com/2009/03/15/346<p>Как многие из вас в курсе, на днях на хабре промелькнул топик «<a href="http://habrahabr.ru/blogs/i_am_clever/54210/">Как я гонял на клаве</a>», от хабраюзера <a href="http://jahson.habrahabr.ru/">jahson</a>. Примечателен этот топик вовсе не своим скриптом, а тем, что дал старт достаточно неприятной сваре, в ходе которой владелец и автор «<a href="http://klavogonki.ru/">Клавогонок</a>», известный на хабре как <a href="http://artch.habrahabr.ru/">artch</a>, повел себя, на мой взгляд, не вполне адекватно. Это не говоря уж о том, что решать такие вопросы принято в личке, не привлекая общественное мнение (которое, к слову, катком прошлось по карме artch).</p>
<p>По мере того, как я читал обсуждение, мне все больше становилось жаль jahson’a, по мере сил отбивавшегося от нападок автора и присных. И в процессе этого сочуствования решил я поднять jahson’у карму, зайдя в его личку. Где увидел не только то, что он не особо нуждается в помощи, но и то, что он член «Российского крыла Web Standards Group».</p>
<p>Тут надо сделать отступление — я, вообще говоря, не знал о существовании такой организации, точнее, о существовании ее российского крыла, и немедленно заинтересовался. Набрав в гугле известное сочетание слов, я попал на страничку «<a href="http://web-standards.ru/">Веб-стандарты — WSG-Россия</a>». Интересно, можно ли еще попасть в ряды, или лавочка уже прикрыта? Судя по тому, что последние встречи проводились в 2007 году, то уже нет, но, если кто-то владеет более актуальной информацией, призываю его поделиться.</p>
<p>Внизу главной странички есть калейдоскоп ссылок под названием «список контактных лиц», и, если пройти по ним, то выяснится, что за ними скрываются очень знакомые и авторитетные люди и ресурсы. Люди, в той или иной степени определяющие сегодняшний облик рунета. Например, по тому же webmascon лично я учился верстке.</p>
<p>Отдельно хотелось бы упомянуть Дмитрия Барановского, который, к слову, присутствует и на хабре под псевдонимом… <a href="http://DmitryBaranovskiy.habrahabr.ru/">DmitryBaranovskiy</a> (сюрприз!) и, по совместительству, является разработчиком <a href="http://raphaeljs.com/">Raphaël—JavaScript Library</a>.</p>
<p>Читая его <a href="http://dmitry.baranovskiy.com/">блог</a>, я наткнулся на его пост «<a href="http://dmitry.baranovskiy.com/post/40514291">JavaScript Without „if“</a>», и вспомнил, что у меня валяется в загашниках очень похожая штука:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12</pre></td><td class="code"><pre><span class="nx">IF</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'true'</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'true'</span><span class="p">);</span>
<span class="p">},</span>
<span class="s1">'false'</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'false'</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="nx">IF</span><span class="p">[(</span><span class="mi">5</span> <span class="o"><</span> <span class="mi">4</span><span class="p">)]();</span> <span class="c1">// should be false</span>
<span class="nx">IF</span><span class="p">[(</span><span class="k">typeof</span> <span class="nb">window</span><span class="p">.</span><span class="nx">UnusualAndStrangeProperty</span> <span class="o">===</span> <span class="s1">'undefined'</span><span class="p">)]();</span> <span class="c1">// should be true</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Думаю, как это работает, очевидно, поэтому я хочу заострить внимание на другом: такая конструкция, по идее, должна работать достаточно быстро, так как доступ к свойствам объекта в javascript очень быстр. Правда, в таком случае мы платим памятью за скорость. И действительно, тесты в safari показывают, что этот код лишь чуть-чуть медленнее классической конструкции if… else. Про остальные браузеры ничего не могу сказать, так как всесторонним тестированием не занимался — да и не стоит оно того, это же чисто proof of concept.</p>
<p>В общем, как обычно, гибкость javascript достойна всяческих похвал. Если в этом языке чего-то не хватает, то это что-то легко может быть дописано руками.</p>
По горячим следам: запись скринкаста2009-02-22T00:00:00+00:00http://ulizko.com/2009/02/22/338<p>Вчера я потратил вечер, записывая скринкаст. Нервов было израсходовано много, и в этом посте я собираюсь поделиться с вами своими впечатлениями от процесса и размышлениями на тему.</p>
<p>Итак. Что касается виновника торжества, то вот он:</p>
<object width="400" height="251" data="http://vimeo.com/moogaloop.swf?clip_id=3310996&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1" type="application/x-shockwave-flash"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=3310996&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1" /></object>
<p><a href="http://vimeo.com/3310996">TweetDeck screencast (rus)</a> от <a href="http://vimeo.com/user1053824">Александра Улизько</a> на <a href="http://vimeo.com">Vimeo</a>.</p>
<p>На мой взгляд, получилось гораздо лучше, нежели в <a href="http://ulizko.com/posts/210/index.html">прошлый раз</a>, но до сколько-нибудь нормального уровня скринкаст все еще не дотягивает. Из замеченных недостатков:</p>
<p><em>ВНЕЗАПНО</em> прорезавшийся вологодский акцент - абсолютно непонятно, откуда он взялся, но, тем не менее, в отдельных местах я отчетливо окаю.</p>
<p>Язык убегает вперед головы — иногда не согласованы рода и числа, предложения остаются оборваны. Вы бы видели, как хохотал <a href="http://proxiper.livejournal.com">proxiper</a>, когда, я пять раз подряд записывал фразу «зарегистрировался в сервисе», потому что с языка упорно слетало слово «сервер». Как с этим бороться, я не знаю, если честно — заучивать текст мне кажется глупым, но иного способа говорить четко и без оговорок я не знаю. Может быть, кто-нибудь из более опытных товарищей поделится?</p>
<p>Откровенно странное качество записи — писалось все на встроенный в макбук микрофон в течении достаточно длительного времени, от этого голос время от времени меняется, что вы наверняка заметили. Думаю, при наличии нормального микрофона и сокращении времени записи конкретно этот недостаток можно изжить.</p>
<p><a href="/images/tweetdeck_screencast/tweetdeck_screencast_plan.png"><img title="План скринкаста о tweetdeck'e" src="images/tweetdeck_screencast/tweetdeck_screencast_plan-150x150.png" alt="План скринкаста о tweetdeck'e" width="150" height="150" /></a></p>
<p>Сделав выводы из прошлого скринкаста, я решил, что записывать одновременно видео, звуки клавиатуры и речь — не комильфо, по крайней мере, мне еще далеко до такого уровня мастерства, так что я сделал себе такой вот план и решил сначала по нему записать видео, а потом поверх наложить звук. Собственно, результат действительно оказался гораздо лучше, чем в прошлый раз, но тоже изобилует недостатками. Короче, это было правильное решение, надо и дальше действовать так.</p>
<p><img class="size-thumbnail wp-image-340" title="Монтаж скринкаста" src="/images/tweetdeck_screencast/dhcdhndhdhndhnn-3.png" alt="Монтаж скринкаста" width="150" height="150" /></p>
<p>Неправильный выбор программы для записи и редактирования — я записывал все в программу <a href="http://www.varasoftware.com/products/screenflow/">screenflow</a>. Точнее даже, записывает-то она вполне прилично, но вот редактирование в ней совершенно не предусмотренно. Например, совершенно невозможно взять отдельный кадр из видео и показывать только его, а звук пускай идет дальше — иногда это полезно, так как не успеваешь проговорить все, что собирался. Также, совершенно дико реализован процесс дозаписи кусочков звука — чем-то процесс мне напоминает далекую молодость, когда я мышкой накликивал в cakewalk 9 <nobr>midi-партии.</nobr> Возникают точно такие же ощущения бессмысленной и лишней работы — но, черт возьми, уже сколько лет-то прошло? Должен же прогресс уйти вперед не?</p>
<p>В общем, выводы из всего этого такие:</p>
<ul>
<li>Скринкасты делать весело и интересно</li>
<li>Нужна какая-то более удобная программа для редактирования видео</li>
<li>Нужно что-то сделать с речью - перед зеркалом тренироваться, что ли</li>
</ul>
<p>Хотелось бы, разумеется, услышать ваши отзывы и критику. Ну и если кто знает решение одной из перечисленный проблем — поделитесь, пожалуйста.</p>
Букмарклеты2009-02-16T00:00:00+00:00http://ulizko.com/2009/02/16/334<p>Всем привет, сегодня речь пойдет про использование букмарклета, или закладки для браузера.</p>
<p>Кто не знает, это такая штука, которую можно добавить в закладки (да, я сегодня дебютирую в роли Капитана Очевидность :) и, при нажатии на нее, произвести какой-нибудь эффект.</p>
<p>Примером может служить герой сегодняшней заметки, который расположен по адресу <a href="http://ulizko.com/demo/allthat/">http://ulizko. com/demo/allthat/</a>. Инструкция по применению:</p>
<ul>
<li>Перетащите ссылку «link» на панель закладок или щелкните по ней правой кнопкой мыши и выберите пункт меню «добавить в избранное».</li>
<li>Зайдите на какой-нибудь сайт, вроде <a href="http://twitter.com">http://twitter.com</a>, и нажмите на эту закладку (ну или на избранное).</li>
</ul>
<p>Появится окошко, в которое можно ввести данные. Вообще, предполагается, что это будет интерфейс добавления желаний в вишлисты (предварительно созданные на каком-то сайте), настроить триггеры оповещений, и прочее. Есть даже какая-то валидация начального уровня. И налажен обмен данными с сервером — то есть, на любом домене к вам приходит список ваших вишлистов, а ваше новое желание с любого домена долетит на крыльях любви к вишлисту и уютно устроится в его объятьях<sup><a href="#footnotes_wtf">1</a></sup>.</p>
<p>Но. Мы сегодня не об этом, а о том, как делать такие штуки в принципе.</p>
<p>Прежде чем перейти непосредственно к разбору кода, хотелось бы ответить на вопрос (который мне никто не задавал :), а именно, "Какие возможности дает букмарклет?". Правильный ответ — любые. Так как мы получаем возможность подгрузить любой скрипт, мы можем сделать с клиентской страничкой все, что угодно. Например — сделать «выносной» виджет, в котором на любой страничке можно будет добавить запись в блокнот или таскменджер. Или вообще сделать весь таскменеджер выносным. Что тоже важно, они будут работать практически везде — это не плагины к firefox’у и не виджеты к opera. Букмарклетам не важно (ну, почти :), какая у вас ОС или браузер. В общем, есть простор для фантазии.</p>
<p>Итак, как же делать эти самые букмарклеты?</p>
<p>Очень просто: надо создать на страничке элемент anchor с атрибутом href, содержащим javascript-код. Если перевести на русский, то надо сделать вот такую ссылку, адрес которой, по большому счету, и будет букмарклетом:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><a</span> <span class="na">href=</span><span class="s">"javascript:alert('I am bookmarklet'); void 0;"</span><span class="nt">></span>Bookmarklet<span class="nt"></a></span></code></pre></figure>
<p>Демо:</p>
<p><a href="javascript:alert('I am bookmarklet'); void 0;">Демо вышеописанного кода</a></p>
<p>Для того, чтобы javascript код в адресе ссылки заработал, надо добавить перед ним слово <code>javascript:</code>. По умному это называется «указание псевдопротокола javascript». Еще одна важная деталь — если ваш код вернет какое-то значение, то браузер воспримет его в качестве адреса, по которому нужно перейти, и уйдет с текущей страницы. Чтобы избежать этого, не возвращайте значения, то есть допишите в конец скрипта <code>void 0;</code>, либо оберните весь код в анонимную функцию, невозвращающую значения — <code>(function(){... ваш код мог бы быть здесь...})()</code>.</p>
<p>В любом случае, все эти вопросы подробно рассмотрены у Ильи Кантора в его заметке <a href="http://javascript.ru/unsorted/bookmarklet">Букмарклеты и правила их написания</a>, к которой я вас и отсылаю за подробностями.</p>
<p>Единственную вещь, которую нам еще нужно знать — это то, что все браузеры ограничивают максимальную длину кода букмарклета. И, подобно тому, как скорость каравана равна скорости самого медленного верблюда, так и максимальный размер кроссбраузерного букмарклета равен ограничению, наложенному IE 6 SP2, то есть, 488 символам.</p>
<p>Таким образом, вряд ли мы сможем закодить какую-то комплексную логику в неполных пятистах символах, так что чаще всего букмарклеты просто создают новый тэг script, в который уже сгружают код приложения.</p>
<p>Так поступил и я. Вот код моего букмарклета в человекоадаптированном виде:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre></td><td class="code"><pre><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// создаем новую внутреннюю переменную a (лучше в данном случае использовать короткие идентификаторы)</span>
<span class="c1">// и сразу же добавляем свой объект в глобальный объект window, и записываем в него данные, которые уникальны</span>
<span class="c1">// для каждого пользователя (ведь они сгенерированы сервером для пользователя перед тем, как он добавил этот букмарклет к себе)</span>
<span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">allThat</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">userId</span> <span class="p">:</span> <span class="s1">'123345456'</span><span class="p">,</span>
<span class="na">server</span> <span class="p">:</span> <span class="s1">'http://mysite.com/'</span><span class="p">,</span>
<span class="na">script</span> <span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'script'</span><span class="p">),</span> <span class="c1">// создадим и запомним тэг скрипт, </span>
<span class="c1">// который сгрузит нам код нашего приложения - мы его потом удалим, если пользователь нажмет кнопку "закрыть"</span>
<span class="na">css</span> <span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'link'</span><span class="p">)</span>
<span class="p">},</span>
<span class="cm">/* динамически создаем элементы: */</span>
<span class="nx">h</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'head'</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
<span class="nx">a</span><span class="p">.</span><span class="nx">css</span><span class="p">.</span><span class="nx">rel</span> <span class="o">=</span> <span class="s1">'stylesheet'</span><span class="p">;</span>
<span class="nx">a</span><span class="p">.</span><span class="nx">css</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="nx">a</span><span class="p">.</span><span class="nx">server</span> <span class="o">+</span> <span class="s1">'css/bookmarklet.2.css'</span><span class="p">;</span>
<span class="nx">h</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">css</span><span class="p">);</span>
<span class="nx">a</span><span class="p">.</span><span class="nx">script</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">a</span><span class="p">.</span><span class="nx">server</span> <span class="o">+</span> <span class="s1">'js/bookmarklet.7.js'</span><span class="p">;</span>
<span class="nx">h</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">script</span><span class="p">);</span>
<span class="nx">h</span><span class="o">=</span><span class="kc">null</span><span class="p">;</span>
<span class="p">})();</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Потом подгружается непосредственно код самого окошка. Думаю, он может представлять некий интерес сам по себе, так что и его я сюда запощу (все комментарии идут на английском, так как заказчик американец):</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318</pre></td><td class="code"><pre><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">Dom</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">get</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">el</span> <span class="o">&&</span> <span class="nx">el</span><span class="p">.</span><span class="nx">nodeType</span><span class="p">)</span> <span class="p">?</span> <span class="nx">el</span> <span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">el</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">addListener</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
<span class="p">};</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">attachEvent</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">attachEvent</span><span class="p">(</span><span class="s1">'on'</span> <span class="o">+</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">);</span>
<span class="p">};</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">[</span><span class="s1">'on'</span> <span class="o">+</span> <span class="nx">type</span><span class="p">]</span> <span class="o">=</span> <span class="nx">fn</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="p">}(),</span>
<span class="na">removeListener</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">removeEventListener</span><span class="p">){</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">removeEventListener</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
<span class="p">};</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">detachEvent</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">detachEvent</span><span class="p">(</span><span class="s1">'on'</span> <span class="o">+</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">);</span>
<span class="p">};</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">[</span><span class="s1">'on'</span> <span class="o">+</span> <span class="nx">type</span><span class="p">]</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span> <span class="p">};</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="p">}(),</span>
<span class="na">hide</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="s1">'none'</span><span class="p">;</span>
<span class="p">},</span>
<span class="na">show</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="nx">allThat</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">allThat</span><span class="p">;</span>
<span class="nx">allThat</span><span class="p">.</span><span class="nx">Bookmarklet</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// where to send user data and where from take wishlists list</span>
<span class="kd">var</span> <span class="nx">wishlistsLocation</span> <span class="o">=</span> <span class="nx">allThat</span><span class="p">.</span><span class="nx">server</span> <span class="o">+</span> <span class="s1">'wishlists/'</span><span class="p">,</span>
<span class="nx">sendTo</span> <span class="o">=</span> <span class="nx">allThat</span><span class="p">.</span><span class="nx">server</span> <span class="o">+</span> <span class="s1">'wishes/'</span><span class="p">,</span>
<span class="c1">// bookmarklet window html code</span>
<span class="nx">innerHTML</span> <span class="o">=</span> <span class="s1">'<div id="allthat-wish"><div class="allthat-saving" id="allthat-throbber">saving...</div><div id="allthat-logo"><span>AllThat</span></div><button title="close" id="allthat-close"><span>close</span></button><h1><span>Add To Wishlist</span></h1><form action=""><div class="allthat-field"><label for="allthat-product">Product Name:</label><br /><input type="text" name="product" value="(Ex: Black iPhone Adapter)" class="allthat-sample-value" id="allthat-product" /></div> <div class="allthat-field"><label for="allthat-wishlist">Add to List:</label><br /><select name="wishlist" id="allthat-wishlist"></select></div><fieldset id="allthat-low-price"> <h2>Low Price Alerts!</h2> <div class="allthat-field" id="allthat-range"><label for="allthat-minprice">How much would you like to pay?</label><br /><input type="text" name="minprice" value="(min)" class="allthat-sample-value" id="allthat-minprice" />to<input type="text" name="maxprice" value="(max)" class="allthat-sample-value" id="allthat-maxprice" /></div><h3>Alert me via:</h3><fieldset id="allthat-alerts"><input type="checkbox" name="email" id="allthat-email" /><label for="allthat-email" id="allthat-email-label">Email</label><br /><input type="checkbox" name="sms" id="allthat-sms" /><label for="allthat-sms" id="allthat-sms-label">SMS</label><br /><input type="checkbox" name="twitter" id="allthat-twitter" /><label for="allthat-twitter" id="allthat-twitter-label">Twitter</label><br /><select name="frequency" id="allthat-frequency"><option value="0" selected="selected">-- Alert Frequency --</option><option value="1">Daily</option><option value="7">Weekly</option><option value="30">Monthly</option></select></fieldset></fieldset><button title="Add" id="allthat-add"><span>Add</span></button></form><div id="allthat-errors" style="color:red;"/></div>'</span><span class="p">,</span>
<span class="c1">// dom elements:</span>
<span class="nx">container</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'div'</span><span class="p">),</span>
<span class="nx">errorDiv</span><span class="p">,</span>
<span class="nx">alertFrequencyDropdown</span><span class="p">,</span>
<span class="nx">wishlistsDropdown</span><span class="p">,</span>
<span class="nx">wishlistsWrapper</span><span class="p">,</span>
<span class="nx">savingThrobber</span><span class="p">,</span>
<span class="nx">closeButton</span><span class="p">,</span>
<span class="nx">titleInput</span><span class="p">,</span>
<span class="nx">minPriceInput</span><span class="p">,</span>
<span class="nx">maxPriceInput</span><span class="p">,</span>
<span class="nx">sendButton</span><span class="p">,</span>
<span class="nx">alerts</span> <span class="o">=</span> <span class="p">{},</span>
<span class="nx">scripts</span> <span class="o">=</span> <span class="p">[],</span>
<span class="c1">// input default values:</span>
<span class="nx">titleDefaultValue</span> <span class="o">=</span> <span class="s1">'(Ex: Black iPhone Adapter)'</span><span class="p">,</span>
<span class="nx">minPriceDefaultValue</span> <span class="o">=</span> <span class="s1">'(min)'</span><span class="p">,</span>
<span class="nx">maxPriceDefaultValue</span> <span class="o">=</span> <span class="s1">'(max)'</span><span class="p">,</span>
<span class="c1">// errors array - used for validation</span>
<span class="nx">errors</span> <span class="o">=</span> <span class="p">[],</span>
<span class="nx">errorMessages</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">titleEmpty</span> <span class="p">:</span> <span class="s1">'Please enter product name'</span><span class="p">,</span>
<span class="na">wishlistNotSelected</span> <span class="p">:</span> <span class="s1">'Please chose list'</span><span class="p">,</span>
<span class="na">frequencyNonSelected</span> <span class="p">:</span> <span class="s1">'Please chose alert frequency'</span>
<span class="p">};</span>
<span class="c1">// append bookmarklet window html to the target page</span>
<span class="kd">function</span> <span class="nx">createTemplate</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">container</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">innerHTML</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">container</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">// initialize javascript references to the Dom elements</span>
<span class="kd">function</span> <span class="nx">initializeDomElementsReferences</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">errorDiv</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-errors'</span><span class="p">);</span>
<span class="nx">alertFrequencyDropdown</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-frequency'</span><span class="p">);</span>
<span class="nx">wishlistsDropdown</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-wishlist'</span><span class="p">);</span>
<span class="nx">wishlistsWrapper</span> <span class="o">=</span> <span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
<span class="nx">savingThrobber</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-throbber'</span><span class="p">);</span>
<span class="nx">closeButton</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-close'</span><span class="p">);</span>
<span class="nx">titleInput</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-product'</span><span class="p">);</span>
<span class="nx">minPriceInput</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-minprice'</span><span class="p">);</span>
<span class="nx">maxPriceInput</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-maxprice'</span><span class="p">);</span>
<span class="nx">sendButton</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-add'</span><span class="p">);</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">email</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-email'</span><span class="p">);</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">sms</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-sms'</span><span class="p">);</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">twitter</span> <span class="o">=</span> <span class="nx">Dom</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'allthat-twitter'</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">// disable wishlist dropdown before server response with wishlists array doesn't arrive</span>
<span class="kd">function</span> <span class="nx">initializeGUI</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="s1">'disabled'</span><span class="p">;</span>
<span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="s1">'90%'</span><span class="p">;</span>
<span class="nx">wishlistsWrapper</span> <span class="o">=</span> <span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
<span class="nx">wishlistsWrapper</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">background</span> <span class="o">=</span> <span class="s1">'transparent url('</span> <span class="o">+</span> <span class="nx">allThat</span><span class="p">.</span><span class="nx">server</span> <span class="o">+</span> <span class="s1">'images/bookmarklet/ajax-loader-blue.gif) no-repeat right'</span><span class="p">;</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">hide</span><span class="p">(</span><span class="nx">savingThrobber</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">// bind event listeners to the controls</span>
<span class="kd">function</span> <span class="nx">attachListeners</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nx">closeButton</span><span class="p">,</span> <span class="s1">'click'</span><span class="p">,</span> <span class="nx">destroy</span><span class="p">);</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nx">titleInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">titleInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">titleDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">titleInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nx">minPriceInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">minPriceInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">minPriceDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">minPriceInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">maxPriceDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nx">sendButton</span><span class="p">,</span> <span class="s1">'click'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">e</span> <span class="o">||</span> <span class="nb">window</span><span class="p">.</span><span class="nx">event</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">)</span> <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span> <span class="nx">addItemToList</span><span class="p">();</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;});</span>
<span class="p">};</span>
<span class="c1">// validators</span>
<span class="kd">function</span> <span class="nx">validateItemTitlePresence</span> <span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">titleInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^s+|s+$/</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">t</span> <span class="o">==</span> <span class="nx">titleDefaultValue</span><span class="p">)</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">errorMessages</span><span class="p">.</span><span class="nx">titleEmpty</span><span class="p">);</span>
<span class="p">};</span>
<span class="kd">function</span> <span class="nx">validateWishlistPresence</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">value</span> <span class="o">===</span> <span class="s1">'undefined'</span><span class="p">)</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">errorMessages</span><span class="p">.</span><span class="nx">wishlistNotSelected</span><span class="p">);</span>
<span class="p">};</span>
<span class="kd">function</span> <span class="nx">validateFrequencyPresence</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">alert</span> <span class="k">in</span> <span class="nx">alerts</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">alerts</span><span class="p">[</span><span class="nx">alert</span><span class="p">].</span><span class="nx">checked</span> <span class="o">&&</span> <span class="nx">alertFrequencyDropdown</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">errors</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">errorMessages</span><span class="p">.</span><span class="nx">frequencyNonSelected</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="kd">function</span> <span class="nx">validate</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">errors</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">validateItemTitlePresence</span><span class="p">();</span>
<span class="nx">validateWishlistPresence</span><span class="p">();</span>
<span class="nx">validateFrequencyPresence</span><span class="p">();</span>
<span class="k">return</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>
<span class="kd">function</span> <span class="nx">displayErrors</span> <span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">output</span> <span class="o">=</span> <span class="s1">''</span><span class="p">,</span> <span class="nx">error</span><span class="p">,</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="nx">error</span> <span class="o">=</span> <span class="nx">errors</span><span class="p">[</span><span class="nx">i</span><span class="o">++</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">output</span> <span class="o">+=</span> <span class="nx">error</span> <span class="o">+</span> <span class="s1">'<br/>'</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">errorDiv</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">output</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// this function called if user clicks on the 'send' button</span>
<span class="c1">// so that we need to validate data, and, if it's all ok,</span>
<span class="c1">// send request to server. Also, we show throbber and setup callback which would stop it</span>
<span class="kd">function</span> <span class="nx">addItemToList</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">validate</span><span class="p">())</span> <span class="p">{</span>
<span class="nx">sendItemOnServer</span><span class="p">();</span>
<span class="p">}</span>
<span class="nx">displayErrors</span><span class="p">();</span>
<span class="p">};</span>
<span class="c1">// serialize data into string, show loader and call sendRequest method</span>
<span class="kd">function</span> <span class="nx">sendItemOnServer</span> <span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="s1">'title='</span> <span class="o">+</span> <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">titleInput</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'&wishlist='</span> <span class="o">+</span> <span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">temp</span> <span class="o">=</span> <span class="nx">minPriceInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">temp</span> <span class="o">==</span> <span class="s1">''</span> <span class="o">||</span> <span class="nx">temp</span> <span class="o">==</span> <span class="nx">minPriceDefaultValue</span><span class="p">)</span> <span class="p">?</span> <span class="s1">''</span> <span class="p">:</span> <span class="p">(</span><span class="s1">'&minPrice='</span> <span class="o">+</span> <span class="nx">temp</span><span class="p">);</span>
<span class="nx">temp</span> <span class="o">=</span> <span class="nx">maxPriceInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">temp</span> <span class="o">==</span> <span class="s1">''</span> <span class="o">||</span> <span class="nx">temp</span> <span class="o">==</span> <span class="nx">maxPriceDefaultValue</span><span class="p">)</span> <span class="p">?</span> <span class="s1">''</span> <span class="p">:</span> <span class="p">(</span><span class="s1">'&maxPrice='</span> <span class="o">+</span> <span class="nx">temp</span><span class="p">);</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="s1">'&alerts=['</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">alert</span> <span class="k">in</span> <span class="nx">alerts</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">alerts</span><span class="p">[</span><span class="nx">alert</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">checked</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="s1">']'</span><span class="p">;</span>
<span class="nx">data</span> <span class="o">+=</span> <span class="s1">'&alertFrequency='</span> <span class="o">+</span> <span class="nx">alertFrequencyDropdown</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="nx">showLoader</span><span class="p">();</span>
<span class="nx">sendRequest</span><span class="p">(</span><span class="nx">sendTo</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="s1">'itemAdded'</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">// clear inputs</span>
<span class="kd">function</span> <span class="nx">clearFields</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">hideLoader</span><span class="p">();</span>
<span class="nx">activateInput</span> <span class="p">(</span><span class="nx">titleInput</span><span class="p">);</span>
<span class="nx">activateInput</span> <span class="p">(</span><span class="nx">minPriceInput</span><span class="p">);</span>
<span class="nx">activateInput</span> <span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">alert</span> <span class="k">in</span> <span class="nx">alerts</span><span class="p">)</span> <span class="nx">alerts</span><span class="p">[</span><span class="nx">alert</span><span class="p">].</span><span class="nx">checked</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// misc - remove default value and make font color black</span>
<span class="kd">function</span> <span class="nx">activateInput</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// feed wishlists dropdown with data and enable it</span>
<span class="kd">function</span> <span class="nx">activateWhishlistsDropdown</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">w</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">wishlists</span><span class="p">,</span>
<span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="nx">wishlist</span><span class="p">,</span>
<span class="nx">opt</span><span class="p">;</span>
<span class="k">while</span><span class="p">(</span><span class="nx">wishlist</span> <span class="o">=</span> <span class="nx">w</span><span class="p">[</span><span class="nx">i</span><span class="o">++</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">opt</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"option"</span><span class="p">);</span>
<span class="nx">opt</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">createTextNode</span><span class="p">(</span><span class="nx">wishlist</span><span class="p">.</span><span class="nx">title</span><span class="p">));</span>
<span class="nx">opt</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">"value"</span><span class="p">,</span> <span class="nx">wishlist</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">opt</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">wishlistsDropdown</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="s1">'100%'</span><span class="p">;</span>
<span class="nx">wishlistsWrapper</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">background</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// remove every track of bookmarklet from the page</span>
<span class="kd">function</span> <span class="nx">destroy</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">removeEventListeners</span><span class="p">();</span>
<span class="nx">removeDOMReferences</span><span class="p">();</span>
<span class="nx">container</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">container</span><span class="p">);</span>
<span class="nx">container</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">allThat</span><span class="p">.</span><span class="nx">css</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">allThat</span><span class="p">.</span><span class="nx">css</span><span class="p">);</span>
<span class="nx">allThat</span><span class="p">.</span><span class="nx">script</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">allThat</span><span class="p">.</span><span class="nx">script</span><span class="p">);</span>
<span class="nx">allThat</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// to prevent memory leaks on ie6 - remove all js to dom references</span>
<span class="kd">function</span> <span class="nx">removeDOMReferences</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">errorDiv</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">alertFrequencyDropdown</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">wishlistsDropdown</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">wishlistsWrapper</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">savingThrobber</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">closeButton</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">titleInput</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">minPriceInput</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">maxPriceInput</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">sendButton</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">email</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">sms</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">alerts</span><span class="p">.</span><span class="nx">twitter</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">scripts</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">script</span><span class="p">,</span> <span class="nx">head</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'head'</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
<span class="k">while</span> <span class="p">(</span><span class="nx">script</span> <span class="o">=</span> <span class="nx">scripts</span><span class="p">[</span><span class="nx">i</span><span class="o">--</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">head</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="nx">script</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">scripts</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">scripts</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// to prevent memory leaks - remove all event listeners</span>
<span class="kd">function</span> <span class="nx">removeEventListeners</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">closeButton</span><span class="p">,</span> <span class="s1">'click'</span><span class="p">,</span> <span class="nx">destroy</span><span class="p">);</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">titleInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">titleInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">titleDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">titleInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">minPriceInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">minPriceInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">minPriceDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">minPriceInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">,</span> <span class="s1">'focus'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><span class="k">if</span> <span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">.</span><span class="nx">value</span> <span class="o">==</span> <span class="nx">maxPriceDefaultValue</span><span class="p">)</span> <span class="nx">activateInput</span><span class="p">(</span><span class="nx">maxPriceInput</span><span class="p">);});</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">sendButton</span><span class="p">,</span> <span class="s1">'click'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">e</span> <span class="o">||</span> <span class="nb">window</span><span class="p">.</span><span class="nx">event</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">)</span> <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span> <span class="nx">addItemToList</span><span class="p">();</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;});</span>
<span class="p">};</span>
<span class="c1">// create dynamic script element and remove it immediately after it load</span>
<span class="kd">function</span> <span class="nx">sendRequest</span> <span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">head</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'head'</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'script'</span><span class="p">),</span>
<span class="nx">noCacheIE</span> <span class="o">=</span> <span class="s1">'&noCacheIE='</span> <span class="o">+</span> <span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">()).</span><span class="nx">getTime</span><span class="p">(),</span>
<span class="nx">fullUrl</span> <span class="o">=</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">'?callback='</span> <span class="o">+</span> <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'&userId='</span> <span class="o">+</span> <span class="nx">allThat</span><span class="p">.</span><span class="nx">userId</span><span class="o">+</span> <span class="p">((</span><span class="nx">data</span><span class="p">)</span> <span class="p">?</span> <span class="p">(</span><span class="s1">'&'</span> <span class="o">+</span> <span class="nx">data</span><span class="p">)</span> <span class="p">:</span> <span class="s1">''</span><span class="p">)</span> <span class="o">+</span> <span class="nx">noCacheIE</span><span class="p">;</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s1">'type'</span><span class="p">,</span> <span class="s1">'text/javascript'</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s1">'src'</span><span class="p">,</span> <span class="nx">fullUrl</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s1">'charset'</span><span class="p">,</span> <span class="s1">'utf-8'</span><span class="p">);</span>
<span class="nx">head</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="nx">scripts</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="nx">head</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// misc - hide send button and show saving throbber instead</span>
<span class="kd">function</span> <span class="nx">showLoader</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">show</span><span class="p">(</span><span class="nx">savingThrobber</span><span class="p">);</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">hide</span><span class="p">(</span><span class="nx">sendButton</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">// misc - hide saving throbber and show send button instead</span>
<span class="kd">function</span> <span class="nx">hideLoader</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">hide</span><span class="p">(</span><span class="nx">savingThrobber</span><span class="p">);</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">show</span><span class="p">(</span><span class="nx">sendButton</span><span class="p">);</span>
<span class="p">};</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">initialize</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">createTemplate</span><span class="p">();</span>
<span class="nx">initializeDomElementsReferences</span><span class="p">();</span>
<span class="nx">initializeGUI</span><span class="p">();</span>
<span class="nx">attachListeners</span><span class="p">();</span>
<span class="nx">sendRequest</span><span class="p">(</span><span class="nx">wishlistsLocation</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="s1">'loadWishlists'</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">destroy</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">destroy</span><span class="p">();</span>
<span class="p">},</span>
<span class="na">loadWishlists</span> <span class="p">:</span> <span class="nx">activateWhishlistsDropdown</span><span class="p">,</span>
<span class="na">itemAdded</span> <span class="p">:</span> <span class="nx">clearFields</span>
<span class="p">};</span>
<span class="p">}();</span>
<span class="c1">// to prevent memory leaks, remove all js <-> dom references, including dom elements references and event listeners</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="s1">'unload'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">allThat</span><span class="p">)</span> <span class="nx">allThat</span><span class="p">.</span><span class="nx">Bookmarklet</span><span class="p">.</span><span class="nx">destroy</span><span class="p">();</span>
<span class="nx">Dom</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="s1">'unload'</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">.</span><span class="nx">callee</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">allThat</span><span class="p">.</span><span class="nx">Bookmarklet</span><span class="p">.</span><span class="nx">initialize</span><span class="p">();</span> <span class="c1">// show bookmarklet - this is visual start of the application</span>
<span class="p">})();</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p><strong>Примечания</strong>:</p>
<ul class="footnotes">
<li id="footnotes_wtf">Вообще скрипт выполнен мной на заказ в рамках моей фрилансерской деятельности, так что не удивляйтесь идее, логотипам и дизайну. </li>
</ul>
Перевод нормальных слов в код2009-02-06T00:00:00+00:00http://ulizko.com/2009/02/06/329<p>Так, сегодня пришло в голову, решил записать. Не то, чтобы это очень уж смешная штука была, но забавная. Особенно в конце плодотворного рабочего дня :)</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">mate</span> <span class="k">in</span> <span class="nx">addressBook</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">mate</span><span class="p">.</span><span class="nx">blacklisted</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Ко всем неприятным знакомым:</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">calculateDistance</span><span class="p">(</span><span class="nx">Home</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">().</span><span class="nx">getLatitude</span><span class="p">(),</span>
<span class="nx">mate</span><span class="p">.</span><span class="nx">getLatitude</span><span class="p">())</span> <span class="o"><</span> <span class="mi">100</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// будете проходить мимо -</span>
<span class="k">continue</span><span class="p">;</span> <span class="c1">// проходите</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
И еще про синтаксис JavaScript2009-02-06T00:00:00+00:00http://ulizko.com/2009/02/06/323<p>Кто о чем, а <span style="text-decoration: line-through;">вшивый о бане</span> я о синтаксе в javascript.</p>
<p>Дело в том, что часто внутри функции нужно проверить, переданы ли правильные параметры и переданы ли вообще. Ну и вот один из самых коротких способов это сделать. Ничего фантастического тут нет, старый и проверенный способ. Кто может что сказать о достоинствах и недостатках этого метода?</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3</pre></td><td class="code"><pre><span class="kd">function</span> <span class="nx">destroyTheWorld</span> <span class="p">(</span><span class="nx">when</span><span class="p">,</span> <span class="nx">byWhom</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">when</span><span class="o">||!</span><span class="nx">byWhom</span><span class="p">)</span> <span class="k">return</span> <span class="s1">'fuck off'</span><span class="p">;</span>
<span class="p">};</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>Если кто не знает, оператор логического отрицания <code>!</code> в JavaScript вернет <code>true</code> если ему передан <code>false</code>, <code>''</code> (пустая строка), <code>0</code>, <code>null</code>, <code>undefined</code>. Во всех остальных случаях оператор логического отрицания вернет false. На всякий случай, проиллюстрирую:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">!</span><span class="mi">0</span> <span class="o">===</span> <span class="o">!</span><span class="s1">''</span> <span class="o">===</span> <span class="o">!</span><span class="kc">null</span> <span class="o">===</span> <span class="o">!</span><span class="kc">undefined</span> <span class="o">===</span> <span class="o">!</span><span class="kc">false</span> <span class="o">===</span> <span class="kc">true</span><span class="p">;</span></code></pre></figure>
<p>Таким образом, если мы не передали никакого объекта или передали <code>null</code>, то функция завершит свою работу и вернет в качестве результата нехорошее слово. </p>
<p>Внимательные люди могут спросить — а что, если передать <code>true</code>? Функция завершит работу при вполне валидном параметре? <br />
Я могу на это ответить примерно так: если вы передаете в функцию булевую переменную, то почти наверняка эта переменная — рычаг, т.е. в зависимости от нее меняется поведение функции. И обработка аргументов, таким образом, будет вестить несколько другая. Скажем, такая:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8</pre></td><td class="code"><pre><span class="kd">function</span> <span class="nx">shouldWeDestroyTheWorld</span> <span class="p">(</span><span class="nx">acceptance</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">acceptance</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">World</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">().</span><span class="nx">destroy</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">World</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">().</span><span class="nx">armageddon</span> <span class="o">=</span> <span class="s1">'stopped'</span><span class="p">;</span>
<span class="nx">World</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">().</span><span class="nx">destructionTimer</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></figure>
<p>И если вы опустите этот аргумент, то по эффекту это будет равнозначно передачи <code>false</code>.</p>
Обзор книги: Том Питерс. «Основы. Тренды.»2009-01-27T00:00:00+00:00http://ulizko.com/2009/01/27/287<p>Выполняя данное самому себе обещание — а именно, читать в день не меньше 50 страниц полезной книги, я вчера я дочитал книгу <a href="http://www.tompeters.com/">Тома Питерса</a> «Основы. Тренды».</p>
<p>Если вы читали мою предыдущую рецензию одной из его книг, то вы наверное в курсе, что я являюсь его яростным поклонником, поэтому при чтении этой рецензии стоит иметь это ввиду.</p>
<p>Как известно, немалую долю в арсенале фирменных приемчиков Тома Питерса занимает такая штука, как эпатаж — в данном случае под этим словом я понимаю манеру выкопать какой-нибудь неизвестный факт или неизвестную трактовку факта и сунуть ее под нос читателю. У читателя, который никогда и не слышал про такое, произойдет слом шаблона, и он станет гораздо податливее для убеждения и для усвоения того, что говорит сверх-гуру<sup><a href="#footnotes_super_guru">1</a></sup>.</p>
<p>К сожалению, а может быть и к счастью, я уже достаточно давно прочитал замечательную книгу Алана и Барбары Пиз «Язык взаимоотношений», поэтому информация о том, что мужчины и женщины — разные, для меня не оказалась новостью. Я и так в курсе, что половинки человечества по разному живут, стареют, воспринимают окружающую действительность, по разному думают, говорят и слушают. Ну и, что важно знать всем людям, так или иначе завязанным на бизнес (то есть всем людям :), они по разному покупают. Так как я все это уже знал и, более того, с этим уже смирился и, можно сказать, «грокнул<sup><a href="#footnotes_grokh">2</a></sup>» это знание, то главы, написанные Мартой Барлетта<sup><a href="#footnotes_marta_barletta">3</a></sup>, для меня оказались довольно-таки скучным повторением пройденного. Поэтому всех интересующихся почему женщины поступают вот так, а не иначе, как с ними разговаривать и как они покупают, я отсылаю на озон за книгой «<a href="http://www.ozon.ru/context/detail/id/126499/?partner=aulizko">Язык взаимоотношений</a>».</p>
<p>Остальные же главы обращают внимание читателя на достаточно интересные тенденции, изменяющие облик рынков в развитых странах. К моему большому сожалению, еще далеко не всегда то, о чем старина Том пишет, работает для нашей страны, так что чтение скорее даст представление о том, что надо <em>будет</em> делать, а не о том, что надо делать <em>сейчас</em>.</p>
<p>Ну и по устоявшейся традиции выкладываю те выписки, которые я сделал, читая эту книгу. Как обычно, мысли — автора, формат — мой:</p>
<ul>
<li>Мы (мужчины) подшучиваем над склонностью женщин покупать, при этом мы ведем себя (строим маркетинговую политику, рекламируем, упаковываем, продаем товар) так, будто покупатель — мужчина.</li>
<li>Очень часто, даже если женщина не присутствует лично при покупке какой-либо вещи (автомобиля, к примеру), она все равно незримо присутствует — (она подбивала мужа сходить именно в эти выходные, обсуждала с ним цвет, марку, количество мест и прочее). Так что очень и очень глупо пытаться игнорировать женщин даже в очень и очень «мужских» товарах. А уж в остальных товарах прежде всего надо ориентироваться на то, чтобы они понравились женщине. И, кстати, это касается не только товаров, но и услуг, и всего прочего.</li>
<li>Население в развитых странах стареет. В развитых странах средний возраст непрерывно увеличивается. При этом, эти «новые старики», в отличии от предыдущих поколений, вовсе не настроены пассивно доживать последние годы своей жизни — напротив, выйдя на пенсию, они только начинают жить и тратить. Следует помнить, что их все больше, что у них активная жизненная позиция, и у них дохрена денег (и их будет все больше). Кстати, женщин среди них тоже больше (мужчины живут меньше), причем богатых женщин (эти женщины как сами заработали состояния, так и унаследовали состояния мужей).</li>
</ul>
<p><a href="http://www.ozon.ru/context/detail/id/2752879/?partner=aulizko"><img title="книга Тома Питерса & Марты Барлетта «Основы. Тренды»" src="http://www.ozon.ru/multimedia/books_covers/1000369660.jpg" alt="купить на Озоне книгу Тома Питерса & Марты Барлетта «Основы. Тренды»" width="200" height="376" /></a></p>
<p><a href="http://www.ozon.ru/context/detail/id/126499/?partner=aulizko"><img title="книга Аллана и Барбары Пиз «Язык взаимоотношений мужчина-женщина»" src="http://www.ozon.ru/multimedia/books_covers/sd148_05_09_01.jpg" alt="купить на Озоне книгу Аллана и Барбары Пиз «Язык взаимоотношений мужчина-женщина»" width="200" height="374" /></a></p>
<p><strong>Примечания</strong>:</p>
<ul class="footnotes">
<li id="footnotes_super_guru">сверх-гуру — это Том Питерс. По крайней мере его так называют некоторые издания и критики.</li>
<li id="footnotes_grokh">грокинг — термин, придуманный Робертом Хайнлайном. Означает что-то вроде «впитать знание». Подробнее можно прочитать здесь: <a href="http://alternativereality-alias.blogspot.com/2008/01/blog-post_26.html">http://alternativereality-alias.blogspot.com/2008/01/blog-post_26.html</a></li>
<li id="footnotes_marta_barletta">Марта Барлетта — соавтор книги, о которой я тут распинаюсь. Часть глав написана ею.</li>
</ul>
В программисты бы пошел, пусть меня научат2009-01-26T00:00:00+00:00http://ulizko.com/2009/01/26/267<p>Думаю, я стал программистом в основном потому, что в Нерюнгринской гимназии, в которой я учился, был компьютерный класс. И учительница по информатике разрешала ребятам оставаться после уроков и играть в Duke Nukem 3D, WarCraft 2 и прочие времяубивалки. Но разрешалось посещать кабинет информатики (и оставаться после уроков) только тем, кто посещал факультет информатики и решал на basic’e разные задачки — например, вывести числа от 1 до 256, раскрашенные в разные цвета спектра, и прочие чудовищно сложные и безумно полезные штуки.</p>
<p>Разумеется, это далеко не единственная причина и даже не причина вовсе — это первый толчок в направлении IT, и кто знает, возможно, не будь его, я бы стал экономистом, юристом, пекарем, токарем, военным или еще кем-нибудь.</p>
<p>А у вас, дорогие читатели, что повлияло на выбор будущей профессии?</p>
Камасутра для оратора. Заметки. Глава 1.2009-01-23T00:00:00+00:00http://ulizko.com/2009/01/23/242<p>Вроде бы я еще не писал о том, что я был на конференции Google Developers Day 2008. Про саму конференцию я как-нибудь в другой раз напишу (если напишу вообще, все ж таки информационный повод не первой свежести).</p>
<p>Сегодняшняя же заметка будет вот о чем: на этом самом дне разработчиков посчастливилось мне побывать на выступлении талантливого оратора <a href="http://codinginparadise.org/">Brad’a Neuberg</a>’a. И очень сильно мне запало в душу его умение ладить с аудиторией и объяснять простым языком достаточно сложные вещи. На мой взгляд, он вообще один из лучших ораторов, которых я когда либо видел.</p>
<p>Ну и захотелось мне тоже так уметь — и потому, что и перед аудиторией выступать приходится, и хочется делать это классно, и потому, что испытываю я некий внутренний дискомфорт при общении с большим количеством народа, что, конечно, неприемлемо. От такого недостатка надо непременно избавляться.</p>
<p>По здравому размышлению я понял, что делать надо вот что: так как никакой возможности получить какие-либо курсы ораторского мастерства в нашем городе я не нашел (да и не припомню я хоть сколько-нибудь сравнимых с Нойбергом<sup><a href="#note_spell">1</a></sup> местных ораторов), то самое правильное в моей ситуации — это прочитать всяких умных книжек и практиковаться на <a href="http://javapoint.ru">кроликах</a> (благо возможность появляется регулярно — всякие там обучающие лекции и тому подобное).</p>
<p>Ну, и скачал я аудиокнигу «Камасутра для оратора» от Радислава Гандапаса (надеюсь, его фамилия склоняется). И неторопливо начал слушать. Ну и как водится, для лучшего усвоения материала стал выписывать в отдельный файлик те пассажи, которые мне чем-то приглянулись или показались интересными и(ли) новыми. Как обычно, содержание иногда прямиком от автора, иногда в моей обработке, мысли же от автора без искажений (по крайней мере, я надеюсь). Собственно, вот они:</p>
<ul>
<li>Страх публичного выступления соперничает по «силе» со страхом смерти. Может быть ,потому, что человек — стадное животное, и воспринимает каждое публичное выступление как своеобразный экзамен на то, что он останется с этой стаей. В этом случае, неудачное выступление означает изгнание из стада, что автоматически означает для стадного животного (в том числе и для человека) смерть — от холода, голода и хищников.</li>
<li>Субъективное время волнующегося (выступающего) человека идет быстрее обычного. Таким образом, все процессы в его организме будут идти быстрее. Из-за этого такой человек начнет тараторить (с точки зрения слушателя) хотя ему его быстрая речь будет казаться нормальной. Чтобы поправить это, можно попробовать перед началом выступления час говорить медленнее, примерно как мальчик с дефектами умственного развития. Это замедлит темп речи, и, таким образом, во время же выступления, с учетом ускорения темпа речи от волнения, получится нормальный темп речи.</li>
<li>Зайки. Если в зале сидят люди, чье мнение значимо для вас (и в связи с чем вы испытываете излишнее волнение) или вы ожидаете от них каверзных вопросов, попробуйте упражнение от спецслужб «Зайки». Суть в том, за пять минут до выступления представить, что вы будете выступать не перед людьми, а перед зайками (очень важно представить их во всех деталях — белые, пушистые такие зайки, с розовыми губами и носами, вплоть до вен, просвечивающих в ушах). Также представьте, что, если какие-то зайки будут мешать вашему выступлению, вы отшлепаете его по розовой попке, и он после этого будет сидеть в зале и горько плакать, а остальные зайки притихнут и не будут больше вам мешать. По идее, должно помочь.</li>
<li>Неплохо бы побывать минимум за сутки на месте выступления (даже если вы выступаете не на «своем» месте, а едете куда-то). Походите по залу, посидите в зале, посмотрите, как смотрится сцена, попробуйте, как работает оборудование, микрофон, проектер и прочее. Типа это должно успокоить. Прийти лучше всего первым, раньше любого слушателя — это создаст у вас подсознательное ощущение, что слушатели — гости, что сильно поможет во время выступление.</li>
<li>Привлеките союзников. Очень неплохо, чтобы в зале сидели ваши союзники — люди, которые вас будут поддерживать и в безусловном одобрении которых вы будете стопроцентно уверены. Если вы негативно относитесь к тому, чтобы это были родственники или друзья (скажем, их присутствие наоборот влияет на вашу готовность отрицательно), или по чисто физическим причинам это невозможно (ну, например, вы выступаете где-нибудь на конференции, а они с вами не полетели), то пускай это будет кто-то из слушателей. Походите перед началом мероприятия/выступления среди людей, пообщайтесь, поинтервьюируйте (привет, Нойберг! :) объясните, что вы сейчас будете выступать, попросите задать вам вопрос, обменяйтесь визитками. Люди обычно легко идут на контакт. Особенно хорошо будет, если вы попросите кого-нибудь помочь вам — например, что-нибудь поправить или что-нибудь в таком духе. После этого, в зале вы будете видеть людей, которые смотрят на вас с одобрением, зададут вопрос/другой. Это сильно вам поможет. И вообще, никогда не знаешь, чем аукнется новое знакомство — новым контрактом, женитьбой или просто визиткой, по номеру на которой вы никогда не позвоните.</li>
<li>Профессиональный оратор спокойно воспринимает любые итоги своего выступления. После самого провального выступления не закончится жизнь — ни ваша, ни на планете Земля. Просто проанализируйте сегодняшнее выступление. Отметьте, что получилось, что не получилось, и почему. Отметьте удачные места, и то, что вам не удалось.</li>
<li>Насчет страха перед выступлением: практически перед всем, что нам сегодня приносит удовольствие, мы когда-то использовали страх. Управление автомобилем, прыжок с парашютом, секс и т.д. и т.п.</li>
</ul>
<p> </p>
<p><a href="http://www.ozon.ru/context/detail/id/2415920/?partner=aulizko"><img title="аудиокнига Радислава Гандапаса «Камасутра для оратора»" src="http://www.ozon.ru/multimedia/books_covers/1000264080.jpg" alt="Купить на озоне аудиокнигу Радислава Гандапаса «Камасутра для оратора»" width="200" height="275" /></a></p>
<p><strong>Примечания</strong>:</p>
<ul class="notes"><li id="note_spell">Брэд Нойберг (Brad Neuberg) — надеюсь, я правильно транскрибировал его имя.</li></ul>
jQuery 1.3.1 вышел2009-01-22T00:00:00+00:00http://ulizko.com/2009/01/22/241<p><a href="http://blog.jquery.com/2009/01/21/jquery-131-released/">Сабж</a>. Не прошло и года, как они догадались, что в итоге <a href="http://dean.edwards.name/packer/">packer</a> замедляет общую скорость работы JS на клиенте. Причем, замедление происходит в двух местах:</p>
<ul>
<li>Распаковка скрипта. Да, eval медленная штука, а eval таких объемов данных — очень медленная штука. В итоге получается, что «полезный» код начинает работать позже, чем если бы он был minified, даже с учетом того, что уpackованный скрипт загружается быстрее.</li>
<li>После того, как была такая нагрузка на движок JS, и было занято столько памяти под распаковку, некоторое время движок не сможет работать в полную скорость — пока не отработает сборщик мусора, да и некоторое количество памяти все равно будет занято под изначальный код скрипта. И в итоге и работать скрипт будет медленнее, если браузер получит его упакованным в packer.</li>
</ul>
<p>О таких «мелочах», что уpackованный скрипт в разы труднее дебажить, и упоминать не будем.</p>
<p>Короче, хорошо, что ребята перешли на использование моего любимого <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>‘a. Вообще, мне полагается сейчас скакать до потолка с криками “А я ведь говорил, я знал, я ЗНАЛ!”. Но, так как письменных свидетельств того, что я уже неоднократно негативно высказывался об упаковке JS packer’ом не осталось (кроме как в асечных логах), то придется скромно промолчать :)</p>
Обзор книги: Том Питерс. «Основы. Талант.»2008-12-19T00:00:00+00:00http://ulizko.com/2008/12/19/221<p><a href="http://www.ozon.ru/context/detail/id/2752868/?partner=aulizko"><img title="Том Питерс. Основы. Талант" src="http://www.ozon.ru/multimedia/books_covers/1000369659.jpg" alt="Купить на Озоне книгу Тома Питерса «Основы. Талант»." width="200" height="372" /></a></p>
<p>Прочитал сегодня маленькую, но очень и очень классную книжку от «сверх-гуру» <a href="http://tompeters.com">Тома Питерса</a>, называется «Основы. Талант».</p>
<p>Это <em>правильная</em> книга. Книга, которую стоит читать. Она изменила меня — во время чтения я прямо чувствовал, как что-то во мне сдвигается, меняется, выпрямляется.</p>
<p>Ну и помимо мозговпрямляющего эффекта, Том нехило мотивирует — после чтения так и хочется вскочить и побежать что-нибудь делать. Делать <em>великое</em>.</p>
<p>Отдельной строкой надо отметить дизайн — книгу интересно читать, разглядывать, держать в руках.</p>
<p>Чтение даже побудило меня выписать самые ценные (на мой, разумеется, взгляд) мысли в отдельную заметку (мысли — Питерса, стиль и изложение зачастую мои):</p>
<ul>
<li>Стоит делать что-то, заведомо обреченное на неудачу. И убедить всех (и коллег) в том, что вы обречены на успех. Почему это работает? Потому что если вы собираетесь сделать что-то, нацеленное на успех, значит, вы будете ориентироваться на успешных игроков. А значит, повторять то, что уже и без вас делают. А значит, ни на какой оглушительный успех вы рассчитывать не можете.</li>
<li>Идиоты продают Ролекс. Гении продают образ жизни с Ролексом.</li>
<li>В конечном итоге, только продажа определяет, успешен или нет проект. А значит, каждый в наше время на полную ставку работает в отделе продаж. Продавайте «изнутри» (проект — своим коллегам, начальству), продавайте «снаружи» (ощущения — клиенту), продавайте себя (вы — бренд).</li>
<li>Нанимайте людей, которые смотрят на мир иначе, чем вы. Зачастую они вам будут неприятны, у вас не будет к ним симпатии, но именно они, их странности, приведут ваш проект к успеху. Вам нужны люди, которые смотрят на вещи с другой стороны.</li>
<li>Будете водиться с чудаками — станете чудаком. Будете водиться с занудами — станете занудами…</li>
<li>Вещи, которые изменяют мир, всегда появляются с черного входа.</li>
<li>Тупые конкуренты — тупой вы. Классные конкуренты — классный вы.</li>
<li>Почтенные компании отторгают энтузиастов.</li>
<li>Классная метафора — «Гигансткие поглощения (имеется ввиду приобретения одной корпорацией другой) == спаривание динозавров».</li>
</ul>