tag:blogger.com,1999:blog-7520948595663720982023-10-12T11:42:26.506+02:00St. on ITNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.comBlogger127125tag:blogger.com,1999:blog-752094859566372098.post-52960833104940803472012-04-06T13:46:00.002+03:002012-04-06T13:50:04.251+03:00Moving onHey folks.<br /><br />After more than 10 years of being a web developer, I finally decided to make my very own place in the great web<br /><br />So I'm moving to <a href="http://nikolay.theosom.com">http://nikolay.theosom.com</a>, all my new posts will be published in there, meanwhile thanks for reading and I'll hope to see you there some day!<br /><br />Cheers,<br />NikolayNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-20280120774704613082011-08-07T16:07:00.001+03:002011-08-07T16:09:25.436+03:00The Lovely Future Of RightJSOkay, let's make it official, shall we?<br /><br />Folks, I'm forking RightJS. And before you start screaming like "omg, we all gonna die in here!", calm down, RightJS ain't no going nowhere. The thing I do is future oriented and quite different from RightJS itself. So RightJS will stay where it is, I'm using all the same servers for the fork, so RightJS will be available as long as people use it. And I certainly will apply patches as much as I can.<br /><br />Just, there will be no RightJS 3.0, RightJS 3.0 will be called <a href="http://lovely.io">lovely.io</a><br /><br /><br /><b>So, What's That All Aboot?</b><br /><br />Folks, it's not a secret, that monolithic frameworks are dead. Dead as Java. The future is in small, agile and modular libraries and this is where <a href="http://lovely.io">lovely.io</a> starts.<br /><br />In RightJS we already had kinda modular structure, you could go to the building page and switch off things that you don't need. The problem with this approach is that it is not suitable for the nova-days CDN hosting, all the permutations of a dozen options were blowing the 15k small library into a huge collection of files that weighted several hundreds megabytes and was almost uncacheable. You could host it by uself, but on CDN even if we host it, the chances that another user has the same configurations are slim and it would be pretty much the same as if you host it on your own domain.<br /><br /><a href="http://lovely.io">Lovely.IO</a> is not really a framework as you might think of a normal javascript framework. It is more like a CDN based package management system. In <a href="http://lovely.io">lovely.io</a> all the RightJS core got split apart on several packages.<br /><br /> * 'core' - basically RigihtJS Class, Events (former Observer), utility functions + some new stuff<br /> * 'dom' - the dom manipulations from RightJS + new jQuery like collections handler<br /> * 'ajax' - new XHR2 based ajax module<br /> * 'cookie' - the cookie module<br /> * 'lang' - JavaScript core extensions<br /> * 'sugar' - syntax sugar for the 'dom' module, things like "something".something() and so on.<br /><br />Every package is pretty much independent and you can choose what you want. If all you want is 'dom' you just hook it up and it will be just that. If you also like some JavaScript core extensions, then you hook the 'lang' module. Need to do some ajax? Include the ajax module. It's completely up to you what load and what not.<br /><br />A generic example would look like that<br /><br /><pre class="brush: html"><html><br /> <head><br /> <script src="http://cdn.lovely.io/core.js"></script><br /> <script type="text/javascript"><br /> Lovely(["dom", "ajax", "fx"], function($, ajax) {<br /> ajax.load("/some.url", {<br /> success: function() {<br /> $('#some-element').html(this.text).highlight();<br /> }<br /> });<br /> });<br /> </script><br /> </head><br /></html></pre><br />Basically wha happening in there is that you firstly include the <a href="http://lovely.io/packages/core">lovely.io core package</a> which just 3k of code and provides the modules handling. After that, you can specify the modules you need and once they're loaded (happens asynchronously) your callback function will be called where you can do whatever is it you need to do.<br /><br />The example above is a bit simplistic. In reality it also automatically handles all internal dependencies, versions and so on. Check out <a href="http://lovely.io/packages/mines-game/demo">this example</a>, it's a little game, it uses 'dom' and 'cookies', but it also uses another packages like 'timer' and 'hiscore' to function.<br /><br />This way we are going to have a rubygems like system where anyone can create and share modules, which can relay and reuse each other. All modules including the standard ones will be more or less equal and independent.<br /><br /><br /><b>Automatic Packages Hosting</b><br /><br />Another thing that I'm solving with lovely.io is automatic packages hosting. No more mangling with CDN, demos, documentation and so on. Once you create a package it will be automatically hosted at <tt>cdn.lovely.io</tt> which sits on Amazon's CloudFront. And it's not just scripts, all your asset images also will be there, automatically and free.<br /><br />The basic idea is to completely eliminate the process of modules installation. All your package users will have to do is to specify the package name and version in the dependencies, all the reset will be automatically served from the super fast amazon hosting.<br /><br />Check the <a href="http://lovely.io/packages/mines-game/demo">mines game</a> I mentioned above. Take a look into the HTML code of the page. It is fairly complex widget, it has some styles and depends on some images, more of that it is a compound widget, the hiscore block is provided by a completely different package. Yet all you have to do to make it working is this<br /><br /><pre class="brush: html"><script type='text/javascript'><br /> Lovely(["mines-game-1.0.1"], function(Game) {<br /> new Game().insertTo('#game-container');<br /> });<br /></script></pre><br />And it's not all. The micro-modular structure also will provide a big deal of caching optimization. As all the modules are hosted at the same CDN domain, they all will be cached one by one in the user browsers. And because of that the most frequently used packages will be always in cache.<br /><br />Say a user opens up a page that uses packages A and B, then he goes to a page that uses A, B and C. All he really downloads on the second page is C.<br /><br /><br /><b>About The Packages</b><br /><br />The cool stuff is not over people. Concentrate, because there is more of awesome news!<br /><br />The other thing is how you actually make the packages. By default there is no JavaScript. Yup, you've heard me. The actual packages code is written in CoffeeScript and SASS (though you can use JavaScript + CSS if you like). Check for example <a href="https://github.com/MadRabbit/lovely.io-games/tree/master/mines">the source code of the mines game</a> from the above. It is all nice and clean now.<br /><br />How it works? Quite simple. Lovely.IO is not just a hosting. It also has a CLI tool called `lovely` which is much like ruby-on-rails thingy. You can create a project, you can launch a development server and so on.<br /><br />Then you write your code in whatever you like, and once you're ready do share it with the public, the tool will compile everything in JavaScript, minify using Ugly and push to the lovely.io server. More of that it will automatically use your README and index.html files as landing and demo pages on the server.<br /><br />You can structure your project as you like, you can have as many files as you like. You can use CoffeeScript or JavaScript, SASS or CSS, or even Stylus. It all doesn't matter for the end result.<br /><br />Finally you can do the front-side development in a clean and civilized way.<br /><br /><br /><br /><b>Other Stuff</b><br /><br />There is one thing among this awesomeness though. Lovely.IO is an HTML5 oriented thingy, there is no IE < 9 support, not like I couldn't, just it's thankless job to support those old browsers. I don't wanna do that, you don't wanna do that, and the guy next to you don't wanna do that either.<br /><br />So, in lovely.io there will be no old IE browsers support in the standard packages, plus there is a good chance that I'll be nuking any other packages that will try to provide the old browsers support explicitly.<br /><br />Basically, this is where I'd like to draw the line between RightJS and LovelyIO. If you need something well tested with old browsers support, use RightJS, it will be around as long as you want it. But, if you're building a modern HTML5/CSS3 application then you might want to consider LovelyIO, this is where all new stuff will go.<br /><br /><br /><b>Current Status and Future Plans</b><br /><br />At the moment Lovely.IO has all the modules from RightJS core + RubyOnRails support module + I've made a bunch of demo projects <a href="https://github.com/MadRabbit/lovely.io-games">over here</a>. It appears to be more or less stable (it's based on RightJS after all), but there is no UI yet.<br /><br />There is also not much of documentation either. I've just opened the registration for early adopters. So if you wanna play with it, please check <a href="https://github.com/MadRabbit/lovely.io/tree/master/stl">the main repository</a>, this is where the STL packages live. It's mostly the good old RightJS with a bit of lean towards more standard jQuery behavior for the <tt>$</tt> function.<br /><br />The next step in the project will be automatic documentation hosting for the packages and then I'll start to port UI modules from RightJS, so if you want me to port something specific from RightJS UI, let me know I'll try to make it a priority.<br /><br /><br />--<br />Okay, I think that's the whole introduction for now. I'll give you more when I get to the documentation.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-39644187462727834872011-05-28T17:30:00.004+03:002011-05-28T17:43:29.716+03:00Calculating Cubic Bezier FunctionIf you ever played with the CSS3 native css-transitions, you know that they use <tt>cubic-bezier</tt> notation to define the transition formula. <a href="http://en.wikipedia.org/wiki/Bézier_curve">Cubic Bezier</a> is a parametric function that allows you to define all sorts of smooth curvatures that looks kinda like that<br /><br /><center><img src="http://upload.wikimedia.org/wikipedia/commons/f/ff/Bezier_3_big.gif" /></center><br /><br />The reason why it's used instead of sinuses and exponents, is that it allows you to define all sorts of shapes with just a few more or less intuitively understandable parameters. Plus, unlike other mathematical functions it can be computed very fast, because it's a simple parametric function, no sequences no nothing.<br /><br />In <a href="http://rightjs.org">RightJS</a> we support native css3 transitions, but it also has a pure JavaScript fx-engine to handle old browsers. And the thing is that native CSS3 transitions use the cubic-bezier functions, while the pure JavaScript engine uses a bit of mumbo-jumbo with <tt>Math.sin()</tt> and <tt>Math.log()</tt>, and what I wanted is to allow the developers to use cubic-bezier notation with the old engine.<br /><br />The problem is that it's not that simple. The cubic-bezier function itself is pretty much straightforward and you can calculate a set of X and Y coordinates in no time, but it won't make you any good because both x-s and y-s will be related to the third <tt>t</tt> parameter and therefore unevenly distributed agains the <tt>t</tt> parameter. What you really need is a straight <tt>Y = B(x)</tt> function.<br /><br />And here it gets tricky. <a href="http://gamedev.stackexchange.com/questions/5373/moving-ships-between-two-planets-along-a-bezier-missing-some-equations-for-accel">That much tricky</a>. But, luckily for us, there is always a better way to do it. All you need is to recall a bit of kindergarden math.<br /><br />Originally, the cubic bezier function is used in a parametric form, but it also can be converted into a polynomial form, in which case it will look like that (you can google it and find say <a href="http://www.algorithmist.net/bezier3.html">this document</a>)<br /><br /><pre class="brush:">a = 3 P0<br />b = 3 P1<br />c = 3 P2<br />c0 = P0<br />c1 = b - a<br />c2 = a - 2b + c<br />c3 = P3 - P0 + b - c<br /><br />B(t) = c0 + t(c1 + t(c2 + tc3))</pre><br />In case of CSS3 cubic-bezier definitions, <tt>P0</tt> is always <tt>0</tt> and <tt>P3</tt> is always <tt>1</tt>, in which case the formula gets even simpler<br /><br /><pre class="brush:">c3 = 3 * P1<br />c2 = 3 * (P2 - P1) - c3<br />c1 = 1 - c3 - c2<br /><br />B(t) = t * (c1 + t * (c2 + t * c3))</pre><br />Which, in case of of CSS3 <tt>x1,y1,x2,y2</tt> parameters, can be written in javascript with two functions, for example this way<br /><br /><pre class="brush: js">var Cx = 3 * x1;<br />var Bx = 3 * (x2 - x1) - Cx;<br />var Ax = 1 - Cx - Bx;<br /><br />var Cy = 3 * y1;<br />var By = 3 * (y2 - y1) - Cy;<br />var Ay = 1 - Cy - By;<br /><br />function bezier_x(t) {<br /> return t * (Cx + t * (Bx + t * Ax));<br />}<br /><br />function bezier_y(t) {<br /> return t * (Cy + t * (By + t * Ay));<br />}</pre><br />There are two reasons why we use the polynomial form of the equation. Firstly, it has less operations and therefore will work faster. Secondly, we are going to use Newton's method to approximate the values and will need a first derivative of one of the functions, which in case of polynomial functions is pretty simple.<br /><br />Now, to the fun part. We converted the function from one form to another, but the question remains the same, how are we going to get the <tt>y = B(x)</tt> from <tt>x = B(t) and y = B(t)</tt>? Quite simple my friends, we will use the kindergarden math, or more exactly the Newton's method to approximate a parametric <tt>x</tt> value for every <tt>t</tt> value so that we could get an evenly distributed set of <tt>x</tt> values and then get a set of <tt>y</tt> for them using the same <tt>bezier_y(t)</tt> function.<br /><br /><a href="http://en.wikipedia.org/wiki/Newton's_method">Newton's method</a> might look a bit scary for those who are not familiar with it, but it is actually very simple. <a href="http://www.youtube.com/watch?v=1uN8cBGVpfs">Check this video</a> the guy explains it nicely.<br /><br />All you need to make it work is to have a derivative to your function, which in our case will look like that<br /><br /><pre class="brush: js">function bezier_x_der(x) {<br /> return Cx + t * (2*Bx + t * 3*Ax);<br />}</pre><br />And after that, we just define a little function that will make several iterations trying to find an <tt>x</tt> value which came from the current <tt>t</tt> value. We don't have to be very precise in our case, we just make 5 iterations tops and limit the precision by the 3 digits after the pointer.<br /><br /><pre class="brush: js">function find_x_for(t) {<br /> var x = t, i = 0, z;<br /><br /> while (i < 5) {<br /> z = bezier_x(x) - t;<br /> if (Math.abs(z) < 1e-3) break;<br /><br /> x = x - z / bezier_x_der(x);<br /> i++;<br /> }<br /> <br /> return x;<br />}</pre><br />Now you can create a loop and calculate a set of evenly distributed values, just like that:<br /><br /><pre class="brush: js">var result = [];<br />for (var i=0; i < 1.001; i+=0.1) {<br /> result.push(bezier_y(find_x_for(i)));<br />}<br />console.log(result);</pre><br /><br /><br />That's basically all of it. You can find the full version of this script <a href="https://gist.github.com/996893">in this gist</a>.<br /><br />Enjoy!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-86989125774031559612011-05-08T18:29:00.002+03:002011-05-08T18:58:03.231+03:00How To Read User Input With NodeJSI think it's time for me to join the NodeJS hysteria. So, I'd like to share a bit of things I was tackling today because there is not really much of docs on that matter right now.<br /><br />Short things short. If you're writing a little console script in NodeJS that supposed to ask the user this and that, here's how you can get it done.<br /><br />Node's global object <tt>process</tt> has two properties called <tt>.stdin</tt> and <tt>.stdout</tt>, which are essentially streams. You can write things into the <tt>stdout</tt> and listen to the <tt>'data'</tt> event in the <tt>stdin</tt> stream. A simple example from the api-docs looks like that<br /><br /><pre class="brush:js">process.stdin.resume();<br />process.stdin.setEncoding('utf8');<br /><br />process.stdin.on('data', function (chunk) {<br /> process.stdout.write('data: ' + chunk);<br />});</pre><br />You need to call that <tt>.resume()</tt> method first, it initializes the STDIN reading process.<br /><br />It is pretty straightforward, but it's almost useless when you need to ask the user several questions, more of that validate the input data and re-ask questions when something was entered wrong.<br /><br />The basic trouble here is that <tt>.on('data'</tt> handler that will fire every time the user hits the <tt>Enter</tt>, so you'll have to figure out which question is currently asked an where to put the data. Given the fact that everything is happening asynchronously, it pretty quickly gets really messy.<br /><br />Fortunately for us, there is another events handler in NodeJS called <tt>.once(..</tt> it's basically same as <tt>.on(</tt> but it detaches the listener after the first event received. Knowing that, we can write a little helper function like that<br /><br /><pre class="brush: js">function ask(question, format, callback) {<br /> var stdin = process.stdin, stdout = process.stdout;<br /><br /> stdin.resume();<br /> stdout.write(question + ": ");<br /><br /> stdin.once('data', function(data) {<br /> data = data.toString().trim();<br /><br /> if (format.test(data)) {<br /> callback(data);<br /> } else {<br /> stdout.write("It should match: "+ format +"\n");<br /> ask(question, format, callback);<br /> }<br /> });<br />}</pre><br />There are two important moments. First of all, don't use <tt>console.log</tt> to ask the user the question, otherwise it will print a new line at the end, which is kinda sucks. Secondly note that you should call <tt>.toString()</tt> and <tt>.trim()</tt> on your data, the first one to convert the data from a stream into an actual string, the second one is needed because the string will have a trailing new line symbol at the end after the user hits the <tt>Enter</tt> key.<br /><br />After that, you can ask the user all sorts of questions. For example like that<br /><br /><pre class="brush: js">ask("Name", /.+/, function(name) {<br /> ask("Email", /^.+@.+$/, function(email) {<br /> console.log("Your name is: ", name);<br /> console.log("Your email is:", email);<br /><br /> process.exit();<br /> });<br />});</pre><br />And don't forget to call the <tt>process.exit()</tt> when you done, otherwise the script will just hung in there.<br /><br />That's basically all of it. Enjoy!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-64825647555922560602011-04-28T17:20:00.003+03:002011-04-28T17:55:24.166+03:00Why Make A Run For ItIt has been almost two years since I decided to go public with RightJS and on this occasion I'd like to post some reflections on it.<br /><br />Those days, thanks to github, it's pretty simple to start an open-source project. You just make a repo, write some awesome stuff and push it under the "I don't owe you shit" license. And I like it, in most cases that's all you really need. But, as fun as it is, there is actually another level to open-source projects. The level, where you decide to get serious about it and go public with your project. With promotions, users, official site, docs, tutorials and so on.<br /><br />It is not completely necessary to make your project kinda "officially public", in many cases it might be even a bad idea, because that will distract you from the actual programming, but there are several important things in this process, which can be pretty valuable as well. And that's what I'd like to write about today.<br /><br /><br /><br /><b>It Will Make You A Better Programmer</b><br /><br />The trouble with programmers is that we work in this area where most people don't really understand anything. And because of that, at some level, programmers tend to start thinking that they are pretty darn smart and kick ass.<br /><br />A healthy portion of self-esteem is not a bad thing, it might help you to overcome some small obstacles on your way, but for a programmer as a knowledge worker it is crucial to stay hungry for new information.<br /><br />And running your project for real, will give you exactly that. If you do something interesting enough, people will respond, they will throw all sorts of ideas at you, they will criticize and they will like (hopefully :)) some parts of your work, which will give you all sorts of new information.<br /><br />With new information you'll face new problems and discover new ways to solve them, and that will make you better at what you do.<br /><br /><br /><br /><b>It Will Make You More Organized</b><br /><br />It is not a secret that many developers don't like TDD and Tickets. Even the ones that do, often cheat and don't cover everything, don't document bugs and so on.<br /><br />But, when you start an open project for real, you will have to deal with those things. You will have to handle tickets, document bugs and cover everything you can with tests so that folks who use your code had a hight quality experience.<br /><br />More of that, most open-source projects, especially individual ones, are just about "scratching your own itch". It is highly doubtful that you will make any real money directly from your project, and as much as you might enjoy the creative process of writing code, at some point, you will have to get pragmatic about what you do.<br /><br />You will need to start thinking strategically, where is it worth to invest your time and where it's not. And that is a highly valuable skill, not just for developing a software project, but genuinely in life.<br /><br /><br /><br /><b>It Will Make You Better With People</b><br /><br />Well, you know what they say "all programmers are bad with people" :). The thing is, that people are irrational, even the smart ones. And there is only one way to learn how to deal with irrational - by accumulating experience.<br /><br />One of the hazards of the trade is that programmers spend most of their time with computers, and that's certainly not a good thing for your social skills.<br /><br />When you run an open-source project you will have to handle contributors and do that nicely. Because contributors are privilege. But as all people have different coding styles, different ways to approach issues and just different personalities, you will learn how to find common grounds with different folks, how to work together and how to coordinate the changes.<br /><br /><br /><br /><b>Conclusion</b><br /><br />I don't want to sound like an open-source project is the most awesome thing that might happen to you. By the end of the day, if you're vicious bastard then all that will help you is an old-fashioned kick in the ass.<br /><br />But, if you're interested in software-development, if you want to learn why and how the things done, running your own project for real might be very insightful and teach you quite a few things.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-76488240410423269432011-04-04T16:12:00.010+03:002011-05-06T17:31:59.726+03:00Making Tags With Rails And RightJSAs the <a href="http://rightjs.org/ui/tags">tags widget</a> appeared recently on the <a href="http://rightjs.org/ui">RightJS UI</a> list, I'd like to write a simple how-to about tags in case of using RubyOnRails.<br /><br />You can see the tags widget in action on <a href="http://rightjs.org/ui/tags/demo">this demo page</a>, and <a href="https://github.com/MadRabbit/right-rails-demo">over here</a> you can find a demo rails application that has the tags feature implemented, along with some other <a href="https://github.com/MadRabbit/right-rails">right-rails</a> features.<br /><br />Let's start<br /><br /><b>The Initial Model</b><br /><br />When you need to add a tags feature in a ruby-on-rails project, a standard model would look kinda like that<br /><br /><pre class="brush: ruby">class Article < ActiveRecord::Base<br /> has_and_belongs_to_many :tags, :uniq => true<br />end<br /><br />class Tag < ActiveRecord::Base<br /> has_and_belongs_to_many :articles, :uniq => true<br /><br /> validates_presence_of :name<br /> validates_uniqueness_of :name<br />end</pre><br />As you can see, it's a pretty much straightforward m2m association, articles have many tags and tags have many articles.<br /><br /><br /><b>Tags To Strings Conversion</b><br /><br />The next standard step is usually to add a couple of methods to convert the list of tags into a coma separated string back and forth. The basic reason is that tags are data-base records and it's not much of user-friendly to use integer ids<br /><br /><pre class="brush: ruby">class Article < ActiveRecord::Base<br /> has_and_belong_to_many :tags, :uniq => true<br /><br /> def tags_string<br /> tags.map(&:name).join(', ')<br /> end<br /><br /> def tags_string=(string)<br /> self.tags = string.split(',').map do |tag|<br /> unless tag.blank?<br /> Tag.find_or_create_by_name(tag.strip)<br /> end<br /> end.compact<br /> end<br />end</pre><br />After that you can use this proxy property in forms directly, like that<br /><br /><pre class="brush: html"><%= form_for @article do |f| %><br /> <p><br /> <%= f.label :tags_string %><br /> <%= f.text_field :tags_string %><br /> </p><br /><% end %></pre><br />This way the user will always manipulate the tags list as a simple string and your app will automatically create the tag records and associations on fly<br /><br /><br /><b>Hooking Up RightJS</b><br /><br />At this point your rails app will present a kind of a standard and simple case of tags handling. Time to make it look nice and friendly with a bit of javascript.<br /><br />To hook up RightJS into your Rails application all you need is just add the <tt>right-rails</tt> gem into your Gemfile<br /><br /><pre class="brush: ruby">gem 'right-rails'</pre><br />And run the following code generator<br /><br /><pre>rails g right_rails</pre><br />Don't worry when you see a tall list of scripts it copies into your <tt>public/javascripts</tt> directory, right-rails handles most of them automatically, so you won't really need to look inside of those.<br /><br /><br /><b>Adding The Tags Widget</b><br /><br />Ironically, the actual RightJS part of this enterprise is the shortest one. Once you added <tt>right-rails</tt> into your application, all you need to do is replace <tt>'f.text_field'</tt> with <tt>'f.tags_field'</tt> in your form<br /><br /><pre class="brush: html"><%= form_for @article do |f| %><br /> <p><br /> <%= f.label :tags_string %><br /> <%= f.tags_field :tags_string %><br /> </p><br /><% end %></pre><br />RightRails handles everything else automatically, it generates all necessary html, includes javascript/css modules, it even switches between minified and source builds of javascript libraries depending on the working environment.<br /><br />More of that, it can automatically use the google hosted <a href="http://cdn.rightjs.org">rightjs cdn-server</a> for a superfast, shared scripts delivery.<br /><br /><br /><b>Adding Autocompletion</b><br /><br />By default the <tt>f.tags_field</tt> will make you a pretty looking tags-field, if you want to add the tags autocompletion feature to it, all you need is to specify a list of known tags in it<br /><br /><pre class="brush: html">....<br /> <%= f.tags_field :tags_string, :tags => Tag.all.map(&:name) %><br />....</pre><br /><br />There is also a few additional options you can use with tags widgets, you can find them at the <a href="http://rightjs.org/ui/tags#options">rightjs.org documentation</a><br /><br /><br /><b>Conclusion</b><br /><br />This is a good example to show how <tt>RightJS</tt> is build with server-side developers in mind. As you have noticed we didn't write a single line of javascript in our little exercise, not like we couldn't, just we don't have to bother with those routine things every time we need a simple form with a bunch of standard widgets.<br /><br />More of that, if you take a look into your HTML code, you'll see that <tt>RightRails</tt> didn't write a single line of script either, all it did is added the <tt>data-tags</tt> attribute to your input field.<br /><br /><pre class="brush: html"><input data-tags="{tags: ['one','two','three'}" value="one, two"<br /> id="article_tags_string" name="article[tags_string]" /></pre><br />This way, even if something will go wrong, the user will still see the standard input field with coma separated tags. All your styles and content will remain were it was.<br /><br /><br />--<br />Well, this is pretty much the whole story. If you're interested, go check the <a href="http://rightjs.org/ui">RightJS UI</a> collection, it has many more useful widgets that you can use in your applications.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-19363296569275184922011-03-24T15:38:00.016+02:002011-04-05T09:47:34.237+03:00Why ==null, Not ===nullSometimes in <a href="http://rightjs.org">RightJS</a> source code you might see a thing like this<br /><br /><pre class="brush: js">if (value == null) {<br /> // ...<br />}</pre><br />And as every JavaScript optimization tutorial tells you to use <tt>'===null'</tt> instead of <tt>'==null'</tt> and JSLint yells at you when do otherwise, people immediately try to change it to the "right" way.<br /><br />Meanwhile there is a pretty good case when it is much better to use <tt>'==null'</tt> than <tt>'===null'</tt>.<br /><br />The thing is, that in JavaScript we have this ugly thing called <tt>'undefined'</tt>, which is quite clunky and often weird in use. Like say you might have a piece of code like that<br /><br /><pre class="brush: js">var hash = {a: undefined};<br />console.log(hash.a); // -> undefined<br />console.log(hash.b); // -> undefined<br /><br />console.log('a' in hash); // -> true<br />console.log('b' in hash); // -> false</pre><br />Which is a bit strange. So, it is quite often, people use <tt>'null'</tt> to predefine keys in hashes and then need to check whether a certain value is not <tt>'null'</tt> or <tt>'undefined'</tt>, kinda like this<br /><br /><pre class="brush: js">if (value !== null && value !== undefined) {<br /> // ...<br />}</pre><br />Another case is that the <tt>'null'</tt> thing is an object in JavaScript and sometimes you might need to check if a variable is a plain type value, you go with things like that<br /><br /><pre class="brush: js">if (<br /> typeof(value) !== 'object' &&<br /> value !== null && value !== undefined<br />) {<br /> // ..<br />}</pre><br />There are lots of cases where you need this double check. You also should keep in mind the fact that <tt>'undefined'</tt> is a variable in JavaScript and someone actually can define a variable named <tt>'undefined'</tt>, and in general case you'll need to handle that too. Well, you get the ugly picture.<br /><br /><br />So, what about that <tt>'==null'</tt> business anyways?<br /><br />The trick is that <tt>'==null'</tt>, unlike other boolean comparisons (for example <tt>'==true'</tt>), returns <tt>'true'</tt> only for <tt>'null'</tt> and <tt>'undefined'</tt> values.<br /><br /><pre class="brush: js">null == null; // -> true<br />null == undefined; // -> true<br /><br />null == false; // -> false<br />null == ''; // -> false<br />null == 0; // -> false</pre><br />Which basically means that you can use <tt>value == null</tt> instead of<br /><br /><pre class="brush: js">value === null || value === unefined</pre><br />More of that, except being more compact, <tt>'value == null'</tt> also will be protected from <tt>'undefined'</tt> replacements, and the browser also won't perform a variable name lookup, because <tt>null</tt> is a keyword and there is nothing besides it. Which will make the things faster.<br /><br />How much faster? Let's see. I cranked this little script and run it in FF4<br /><br /><pre class="brush: js">function test1() {<br /> var i=0, t = new Date(), v1 = null, v2 = undefined, r;<br /> for (; i < 100000; i++) {<br /> r = v1 === null && v1 === undefined;<br /> r = v2 === null && v2 === undefined;<br /> }<br /> console.log(new Date() - t);<br />}<br /><br />function test2() {<br /> var i=0, t = new Date(), v1 = null, v2 = undefined, r;<br /> for (; i < 100000; i++) {<br /> r = v1 == null;<br /> r = v2 == null;<br /> }<br /> console.log(new Date() - t);<br />}<br /><br />console.log('--');<br />10..times(test1);<br />console.log('--');<br />10..times(test2);</pre><br />And here is the result<br /><br /><pre class="brush:">--<br />22<br />24<br />23<br />23<br />23<br />23<br />23<br />23<br />24<br />23<br />--<br />2<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1</pre><br /><br />Well, that's the whole story. Think you can put it in a good use :)Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-40672439721023174962011-03-15T18:36:00.009+02:002011-03-15T19:06:21.629+02:00Ruby + Gosu = Fun<a href="https://github.com/jlnr/gosu">Gosu</a> is a nice simple 2D games engine for Ruby, which I used to work on this little game called <a href="https://github.com/MadRabbit/pentix.rb">pentix.rb</a>. And I'd like to put in some good words for the folks who maintain the project.<br /><br />What's particularly cool about Gosu is that it doesn't try to jump over its head and do everything by themselves. Gosu is a very small framework specifically made for 2D games, it will help you make things like windows, handle graphics, fonts, sounds and some basic animations. But it also easily integrates with <a href="http://code.google.com/p/chipmunk-physics/">Chipmunk</a> to handle physics and with ImageMagic/OpenGL modules if you need some seriously looking graphics.<br /><br />If you think about it, Gosu is a very cool thing, you leave all the rendering and heavy stuff to the native modules and use Ruby for what it's good for, for describing logic, units, interactions and so on. And Gosu does it right, it doesn't force you to inherit it's classes all the time, quite on contrary actually. Gosu itself has just a few basic classes to handle media things, like fonts and images, and for the actual units you can write plain Ruby classes, which certainly makes it much easier to implement, test and maintain.<br /><br />And one more thing. Gosu is not just a Ruby toy. It also has all the C++ bindings, which kinda makes it a pretty interesting choice. You can use the power of Ruby to prototype and do all the R&D things. And later, if you actually make it to the investors, it will be relatively simple for you to port everything to C++ and make it running anywhere. Yup, iPhone is on the list :)<br /><br />This is basically it. If you ever wanted to write some simple 2D games, but didn't want to deal with C++ check out Gosu, it's pretty awesome!<br /><br />UPD: Check out also <a href="http://code.google.com/p/gosu/wiki/RubyTutorial">this simple ruby tutorial</a> they haveNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-40458238538678695162011-03-03T14:02:00.004+02:002011-03-03T14:41:27.816+02:00Super Simple LayoutI'd like to show you a little css-trickery thing I use on pages where you have a super simple content, like a documentation or a demo page, and all you want is just to make it look kinda decent without bothering with additional HTML scaffolding.<br /><br />Say you have the following HTML page<br /><br /><pre class="brush:html"><html><br /> <body><br /> <h1>The Main Title</h1><br /> <br /> <h2>Chapter Title</h2><br /> <p><br /> bla bla bla<br /> </p><br /> .......<br /> <div id="footer">Copyright ...</div><br /> </body><br /></html></pre><br />It is super-simple, you've got an <tt>H1</tt> for the page head title, you've got a bunch of <tt>H2</tt> and <tt>P</tt> tags with the content and kind of a footer at the end.<br /><br />And say, you want your page to have some sort of header/footer areas and a bit of paddings on the left and on there right.<br /><br />Here is how you can do that with pure CSS, without bothering with additional tags<br /><br /><pre class="brush:css">html, body {<br /> margin: 0;<br /> padding: 0;<br />}<br />html {<br /> padding-top: 8em;<br /> padding-bottom: 4em;<br /> background: gray; /* header and footer background */<br />}<br />body {<br /> padding: 1em 10em;<br /> padding-bottom: 5em;<br /> background: white; /* the main area background */<br />}<br />h1 {<br /> position: absolute;<br /> top: -.6em;<br /> font-size: 4em;<br /> color: white;<br /> margin: 0;<br /> padding: 0;<br />}<br />div#footer {<br /> position: absolute;<br /> bottom: 1.5em;<br /> color: white;<br />}</pre><br />As you can see the trick is very simple, you use top and bottom paddings on the <tt>HTML</tt> tag to create the header and the footer, and left/right paddings on the <tt>BODY</tt> tag to create, well left and right paddings. After that just move the header and footer elements in their place with absolute positioning and you're done!<br /><br />That's the whole trick. An example is <a href="http://cdn.rightjs.org">over here</a><br />Enjoy!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-54142725032119279752011-02-18T12:41:00.007+02:002011-02-18T12:59:38.088+02:00If I Would Design A Simple FormatThere is an idea I wanted to spit out for quite a while now. It is about simple formats and to keep the short story short, here is a simple spec I cooked up.<br /><br />Basically it is a mix of RDoc, Markdown and Maruku, plus some stuff I miss in all of them. The main goal in this one is readability mixed with abilities to handle everyday things, like images, tables, API references and stuff. HTML might be allowed as a fallback.<br /><br />That's all, let me know what you think about it.<br /><br /><pre><br />= Head 1<br />== Head 2<br />=== Head 3<br />==== Head 4<br /><br /># Head 1<br />## Head 2<br />### Head 3<br />#### Head 4<br /><br />= Head 1 #anchor1<br />## Head 2 #anchor2<br /><br /><br />*bold*<br />~italic~<br />_underline_<br />-strike through-<br />`type text`<br /><br /><br />http://some.url<br /></some.url><br /><http://some.url><br /><Some text:/some.url><br /><br />some@email.com<br /><some@email.com><br /><Some email:some@email.com><br /><br /><br />API Links<br /><br />{ClassName#instanceMethod}<br />{ClassName.classMethod}<br /><br />Defining a default scope<br />{-ClassName} after that<br />{#instanceMethod}<br />{.classMethod}<br /><br /><br /><img:/some.url><br /><swf:/some.url><br /><br /><img:123x234:/some.url><br /><swf:123x234:/some.url><br /><br /><img:Some title text:/some.url><br /><swf:Some title text:/some.url><br /><br /><img:Some title text:123x234:/some.url><br /><swf:Some title text:123x234:/some.url><br /><br /><br />Code formatting<br /><br /><br /> Just a genuine piece of code<br /> That is pre formatted<br /><br /><br />Ruby piece of code<br /><br /> :ruby<br /> this.is_a?(Ruby)<br /> code.which_we do<br /> paint in some do<br /> nice(colors)<br /> end<br /> end<br /><br />Javascript code<br /><br /> :javascript<br /> this.isA(JavaScript).code();<br /> that.we(Paint).accordingly();<br /><br /><br />> This is a quote text<br />> It will be converted to a block-quote<br />> > This is and internal quote<br />> > it will be nested into the original one<br /><br /><br /> * List item 1<br /> * List item 2<br /><br /> - List item 1<br /> - List item 2<br /><br /><br />1. Num list item 1<br />2. Num list item 2<br /><br /><br />a. Letter list item 1<br />b. Letter list item 2<br /><br /><br />I. Roman number list item 1<br />II. Roman number list item 2<br />III. Roman number list item 3<br /><br /><br /> * Mixed list 1<br /> * Mixed list 2<br /><br /> - Mixed List 3<br /> - Mixed List 4<br /><br /> 1. Mixed List 5<br /> 2. Mixed List 6<br /><br /> a. Mixed List 7<br /> b. Mixed List 8<br /><br /> I. Mixed List 9<br /> II. Mixed List 10<br /><br /><br />Head | Head | Head<br />-----|------|-------------------<br />Cell | Cell | Cell<br />Cell | Cell | Cell<br />-----|------|-------------------<br />Foot | Foot | Foot<br /><br /><br />Head | Head | Head<br /> | Head | Head |<br />-----|------|------|------------<br />Cell | Cell | Cell | Cell<br />Cell | Cell | Cell<br />Cell | Cell | Cell | Cell<br /> | Cell | Cell |<br />-----|-------------|------------<br />Foot | Foot | Foot<br /><br /><br />Right | Left | Center |<br />----->|<-----------|------x------|<br /> 1 | 1 | 1 |<br /> 11 | 11 | 111 |<br /> 111 | 111 | 11111 |<br /> 1111 | 1111 | 1111111 |<br /><br /></pre>Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-17413126576011602712011-01-09T16:52:00.008+02:002011-01-09T17:50:46.142+02:00RightJS 2.2 RC Public TestMy dear fellas rightjslings (or whatever the hell we are) I've got some good news for our species! I took a bit of a break from RRTE those holidays and packed ourselves the next major update in the RightJS core, which will go by the number <tt>2.2.0</tt>. And I would really like you to play with the thing. Bring some joy and magic in the routine, and start the year with the new shiny toys!<br /><br />Awrighty, now to the business. You can <a href="http://stcamp.net/share/rightjs-220-rc.zip">download the thing from over here</a> (NOTE: there are updates for all the plugins as well).<br /><br />And as for the changes, there are quite a few of them actually, so let's get through them one by one<br /><br /><br /><b>Native Fx Support</b><br /><br />The first thing that RightJS 2.2 brings is the support of native css-transitions in the visual effects engine. There is not much of changes in the actual API, RightJS will automatically figure everything out and use native features when available.<br /><br />Currently it runs on Safari, Chrome and FF4. Opera also supports them but I have disabled it for Opera by default, because first of all their thing is buggy (doesn't support say font-size and background-position) and secondly our own, javascript based engine works faster than their native feature :)<br /><br />Anyhow, if you insist to switch it on in Opera or disable in Webkit/FF4, use the new <tt>engine</tt> option with your effects, it can be either <tt>'javascript'</tt> or <tt>'native'</tt><br /><br /><br /><b>Class and Wrapper merge</b><br /><br />The second biggest change is that the <tt>Class</tt> and <tt>Wrapper</tt> units were merged to make an uniformed classes structure where the <tt>Class</tt> unit is the top parent of everything.<br /><br />The <tt>new Wrapper</tt> construction won't work anymore, use the standard <tt>new Class</tt> calls as you do when you define any other class.<br /><br /><br /><b>Supercalls On Modules</b><br /><br />The other outcome of the <tt>Class</tt> unit update is that now you can call the <tt>$super</tt> method not only on inherited classes but with injected modules as well. It kinda looks like that<br /><br /><pre class="brush: js"><br />var Klass = new Class({<br /> method: function() {<br /> return "original";<br /> }<br />});<br /><br />Klass.include({<br /> method: function() {<br /> return this.$super() + "+module1";<br /> }<br />});<br /><br />Klass.include({<br /> method: function() {<br /> return this.$super() + "+module2";<br /> }<br />});<br /><br />new Klass().method(); // -> "original+module1+module2"</pre><br />This comes very handy when you need to overload some certain methods without using the actual inheritance. Before, we used to use all sorts of <tt>old_method</tt> hacks, now it's all nice and civilized.<br /><br /><br /><b>Builtin Mouseenter/Mouseleave Handling</b><br /><br />RightJS 2.2 will come with built in mouseenter/mouseleave events handler. As usual it all handled automagically, just use the <tt>'mouseenter'</tt> and <tt>'mouseleave'</tt> event names and be happy. Works both ways, directly with elements and via UJS.<br /><br /><pre class="brush: js"><br />$('element').onMouseenter('addClass', 'hovered');<br />$('element').on('mouseleave', 'removeClass', 'hovered');<br /><br />"div.something".onMouseenter('addClass', 'hovered');</pre><br /><br /><br /><b>Better UJS</b><br /><br />Another major update is that now UJS handlers got triggered by nested elements as well, just like with the normal dom-events. Basically it means that if you say have a structure like that<br /><br /><pre class="brush: html"><br /><div class="something"><br /> Some text in here<br /> <div>some inner element</div><br /></div></pre><br />If you attach your UJS listener like that<br /><br /><pre class="brush: js"><br />"div.something".onClick('toggleClass', 'clicked');</pre><br />Then it will get triggered no matter if the user has clicked the <tt>div.something</tt> element itself or any of its internal elements. No more hacking this stuff around.<br /><br /><br /><b>Pretty Collections Handling</b><br /><br />And one more sweet thing the RightJS 2.2 release will bring. I know you all love the <tt>String#on</tt> method to handle the UJS features, so I had extended it a bit further. Now you can run basically any <tt>Element</tt> methods from strings, just like that.<br /><br /><pre class="brush: js"><br />"div.something".addClass('red');<br />"div.something".removeClass('red');<br />"div.important".highlight();<br />"div#some-crap".remove('fade');<br />....</pre><br />Those basically shortcuts for <tt>$$(css_rule).each('method', args);</tt> it finds all the elements matching the rule and calls the method on them.<br /><br /><br />----<br /><br />There are more fancy things in there, like various performance optimizations, IE8 was kicked out in the olds module, all CSS3 selectors now work everywhere, and so one and so one. I'll describe everything with the actual release.<br /><br />For now you just have fun with the new sweet features and come back if you have any troubles.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-31196258874121855382010-12-22T19:47:00.003+02:002010-12-22T20:11:18.124+02:00RRTE Public AlphaHey people, sorry for being quiet recently, been busy with work and stuff. I don't have a pretty picture for you today, but Santa didn't come up giftless today, not at all :)<br /><br /><a href="https://github.com/rightjs/rightjs-ui/blob/master/test/demos/rte.html">I've got a cute little link for you!</a><br /><br />I just pushed RRTE alpha to github, so you could have a sneak pick on what's going on.<br /><br />It's still an alpha, it doesn't work under IE yet and you might stumble upon some bugs here and there, but generally, generally it all shapes up and should give you some basic overview of the thing.<br /><br />Anyhow, you know the drill. Checkout, enjoy and come back with feedback! :)Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-84853652331765613542010-12-01T18:38:00.005+02:002010-12-01T19:27:35.886+02:00RRTE Status UpdateHey folks! It's been couple of weeks and some of you started to wonder, where's Nik with his RRTE and the world domination, so here is the status update.<br /><br /><center><img src="http://stcamp.net/images/rightjs/rrte-2.png" /></center><br /><br />As you can see, we are having some serious progress. Most of the things you see on the picture are already working, but I'm trying to explore some possibilities and features.<br /><br /><br /><b>What's Wrong With the World?</b><br /><br />It seems that the design-mode support in browsers is utterly broken. It's ugly, limited, uncomfortable to use and behaves differently in different browsers. Well, just like the whole JavaScript business :)<br /><br />There is basically two modes how the design-mode works in browsers, the tags mode and the css-mode, in the first one the browser tries to use tags to style the content, in the other one it tries to use styles. The trouble is that IE supports the tags-mode only and FF supports both, but in any case both of them do that wrong.<br /><br />You see, in the tag mode say they use obsolete <tt>FONT</tt> tag to style fonts, but in this case FF doesn't support for example proper selections highlighting, they also for example use <tt>STRIKE</tt> instead of <tt>S</tt> tag and there is no way specify it. In the css-mode, the browsers try to use things like <tt>style="font-weight:bold"</tt> instead of the <tt><B></tt> tag pair, which is quite inflexible if not to say idiotic in terms of CSS. It also incorrectly reacts on all sorts of things, like say it will show the <tt>U</tt> tool "on" when you put your cursor on a link, and you won't be able to switch it off because it's styled with css.<br /><br />And so one and so one. There is are lots of small and big fuckups like that, and honestly it is quite a mess.<br /><br /><br /><b>Time To Fix It!</b><br /><br />Being an arrogant idiot, I couldn't just pass by this mess, so now I'm building my own engine, which will do precisely what we need on any browser. Basically there are two sets of tools, one of them allows you to work with the <tt>style</tt> attribute, the other one allows you to format anything with any tag you want, and, what's more important, with any attribute you need, which means that you can use ids and classes as well.<br /><br />The formatting setting is not limited to the H1-H6, PRE and ADDRESS tags anymore. You can easily specify say things like that<br /><br /><pre class="brush: js">Rte.Formats = {<br /> 'h2': "Header 2",<br /> 'tt': "Typetext",<br /> 'blockquote': "Block quote",<br /> 'div.blue': "Blue block",<br /> 'div.green': "Green block"<br />};</pre><br />Etc, etc. The basic plan is to create some sort of a mixed, truly css-oriented mode. We will use <tt>SPAN</tt> + <tt>style</tt> attribute for things like custom colors and fonts, but for everything else use normal tags and classes, so that the editor produced a nice and easy to process and support content.<br /><br />It's a bit tricky, but we will get through it.<br /><br /><br /><b>Advanced Tools</b><br /><br />The other thing which I'm trying to figure out is how small an RTE can be, or how much features can we squeeze in 10k? Advanced OOP features of RightJS are really helpful in this case, because all the inheritance and functionality injection features allow us to create really compact and flexible code. As you can see I already added the color tools, font name and size tools, formatting options and some other things. At the moment all of that weights about 8k of gzipped code (and that includes all the css).<br /><br />So I'm trying to add more features in the standard package than I originally planed and see where it will lead us. We might drop some of them into the extensions pack later on, or, if everything will go smoothly, we might not need one and all the standard functionality will be available in the basic build, so that we will have just a core and plugins. Or something like that. Will see.<br /><br /><br />--<br />Well, this is basically it for the moment.<br />To be continued...Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-90649571087589975872010-11-12T18:45:00.009+02:002010-11-14T12:29:09.798+02:00RightJS RTE ConceptIn case you were wondering why it was quiet around here for last couple of weeks, I'd like to share some stuff I've been secretly working on and what are the future plans.<br /><br />Basically we are taking a little pause until Mozilla guys sort their stuff out and release FF4 or at least 3.7, which we need to execute our <a href="http://st-on-it.blogspot.com/2010/10/rightjs-22-notes.html">evil plan for RightJS 2.2</a>.<br /><br />Meanwhile I've been working on this puppy<br /><br /><center><img src="http://stcamp.net/images/rightjs/rrte.png" /></center><br /><br />Yup, it's a RightJS based RTE that will most definitely take over the world, and so you started to want it for xmas, I'd like to put some words in about what's what and stuff.<br /><br /><br /><b>Meet RRTE The Frameless</b><br /><br />One of the major differences from usual RTEs is that our RTE (which goes under the codename <tt>RRTE</tt>) does not use any frakking frames. Instead, it uses an inlined <tt>DIV</tt> with <tt>contenteditable="true"</tt> property.<br /><br />If now you're wondering what it gives you, then this is what:<br /><br />Because it's an inlined div, all the content inside of it will follow all the styles on the page, which means no more headache with transferring and applying your styles to some iframe. If you take a look at the picture, you'll see that the header text inside of the editor has exactly the same font and size as the header on the main page. The <tt>blockquote</tt> and <tt>pre</tt> tags are also painted through usual CSS right on the page.<br /><br />Secondly, because it's just a small inlined piece of page, RRTE works and feels much faster than any IFRAME based editors. It is super fast, practically it feels almost like a plain textarea element.<br /><br />Thirdly, because all widgets in RightJS UI are plain elements, you will be allowed to easily access and manipulate any content right inside of the editor via standard API.<br /><br /><br /><b>Modular</b><br /><br />The second most important feature of RRTE is that it will be modular. Unlike all the other heavy duty RTEs, our RTE, by default will be mainly social networks oriented. It's main purpose will be to work as a lightweight embeddable RTE for all sorts of things like comments and blog posts where you already have all styles in place and just need some nice and shiny thing instead of textareas.<br /><br />For this reason the default package will contain the main core/engine and provide basic editing tools which you can see on the picture above. Currently it weights just <b>4k</b> of gzipped code (including stylesheets) and my intention is to keep it under 10k size.<br /><br />And for all the advanced functionality, like file-pickers, fonts, tables, etc. we will have a separated package, which will turn the editor in a normal heavy duty RTE.<br /><br /><br /><b>Extendable</b><br /><br />As you can see, my plan for RRTE is to extend it via plugins. I don't have any intention to implement everything in it, instead of that RRTE will have a proper OOP design in best RightJS traditions, so that you could make your own tools and extensions, using classes and inheritance. In case if you're wondering how it's gonna look like, here is an example how the <tt>Save</tt> button is implemented<br /><br /><pre class="brush: js"><br />Rte.Tool.Save = new Class(Rte.Tool, {<br /> shortcut: 'S',<br /><br /> initialize: function(rte) {<br /> this.$super(rte);<br /> if (!rte.textarea.form()) {<br /> this.disable();<br /> }<br /> },<br /><br /> exec: function() {<br /> if (!this.disabled) {<br /> this.rte.textarea.form().submit();<br /> }<br /> }<br />});</pre><br />RRTE will provide you with basic tools and open API, so I expect it to be pretty civilized and easy to extend.<br /><br /><br /><b>What and When</b><br /><br />Currently I keep all the fun for myself. This thing is not on github yet, basically because I hack and refactor it alot. Some parts are still quite flimsy and as I don't want you to have a wrong impression about it I'm going to keep it locally for the next week or two.<br /><br />At the moment it appears to me that I'm done on about 40-50%, but as I'm a bit busy those days it is hard to estimate the exact schedule. Judging by my guts I should push something worth of seeing on github in about couple of weeks and probably will have the first release by the end of November/beginning of December.<br /><br /><br />This is basically it. Enjoy the news!<br /><br />--<br />Oh, and one more thing. I could use some help with a default iconset for this widget. Currently I use some free stuff that I found over the internet, but if you can and willing to draw some particularly cool uber-iconset, that would be much appreciated!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-4615373308518701192010-10-25T18:32:00.009+03:002010-10-29T13:48:58.447+03:00RightJS 2.2 NotesI'm cooking a new evil plan for RightJS 2.2 release and would like to share some thoughts and notes, so you knew what's going on and where are we heading.<br /><br /><br /><b>Native Fx</b><br /><br />We are living in an interesting moment. Native CSS transitions are finally becoming reality. Safari does it, Chrome does it, Opera does it, FF4 does it (they promised they will include the feature into the 3.7 release). IE9b does not. Rumors has it, the feature will be in the final release, but I have my doubts it will happen.<br /><br />Anyways, now, when the majority of sane browsers support the feature, I think it's the right time to start using native CSS transitions as a default option for our dom-morph effects. It is faster, simpler and more reliable.<br /><br /><br /><b>Better UJS</b><br /><br />The current implementation of UJS in RightJS works with an event <tt>target</tt> property only. The trouble with this solution is that when you have something like<br /><br /><pre class="brush: html"><div id="one">first<br /> <div id="two">second<br /> <div id="three">third</div><br /> </div><br /></div></pre><br />and you attach an event listener to say the top one<br /><br /><pre class="brush: js">"div#one".onClick(function() {<br /> ...<br />});</pre><br />it will reacts only if the user clicks on the <tt>div#one</tt> itself and will successfully ignoring clicks on the inner element. Sometimes that's what you need, but in majority of the cases it creates more confusion than helping.<br /><br />I'm still thinking about this one, but there is a good chance that the logic will be changed and our UJS will mimic the normal event listeners behavior and react on inner elements as well.<br /><br />Hey! You will be able to make UJS stuff within UJS stuff! :)<br /><br /><br /><b>Cookie plugin</b><br /><br />At the beginning it seemed like a good idea to have a basic Cookie wrapper out of the box, but later I realized that on majority of my projects I don't use it. Well I assume you have pretty much the same experience.<br /><br />So I think the cookie module will be kicked out of the core into an officially supported plugin. it's not much, just half a KB of gzipped code, but I guess we can fill this half a K with something more useful in everyday life.<br /><br /><br /><b>IE8 And Pals</b><br /><br />IE8, or as it known in some circles "IE7 on steroids" is kinda of troubling browser. The problem is that on a good half of the pages this darn things automatically falls into IE7 mode and therefore downloads the "olds" module, on the other half, it still has some troubles with native css selectors because some of CSS3 constructions are not supported, which consequentially makes some wonder-people to wonder how "right" right.js exactly is?<br /><br />Furthermore the <tt>change</tt>/<tt>submit</tt> events still don't bubble and we carry quite large chunk of code in the core, to work this thing around.<br /><br />So I was having that wild thought in my head, that we could ditch IE8 and pals support into the olds module so we could fix those things in there and not bother the core.<br /><br />Currently, I'm considering the idea of making the line between the old and new browsers right where the CSS transitions support starts, which will effectively drop the whole IE support into the olds module.<br /><br />That probably will make some jquery folks to moan that we are unfair towards them, but I'm looking into my glass ball and it says that after all the cutting and stitching, RightJS core size could drop below 12k.<br /><br />Well, at least that the target. Besides there is still a tiny chance that IE9 folks will hear the voice of sanity and add css-transitions into it, then this distinction will be perfectly justified.<br /><br /><br />---<br /><br />Anyhow, those are the notes and thoughts. Let me know if you have something on your mind about thatNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-45959835216559341912010-10-14T17:42:00.008+03:002010-10-14T18:57:31.471+03:00Cloned SELECT elements in IEWhat I love about IE browsers is that genuine feeling of moral superiority that you unavoidable accumulate inside yourself when you're dealing with its features. Found one more "treasure" that killed half of my day.<br /><br />The story goes like that. Say I have a <tt>SELECT</tt> element and then you clone it a bunch of times and populate with new content, kinda like that<br /><br /><pre class="brush: js">var original = document.createElement('select');<br />clone = original.cloneNode(false);<br />document.body.appendChild(clone);<br /><br />$(clone).html('<option>boo hoo!</option>');</pre><br />And that all works fine, but now say you update the content in another function, say an ajax callback or something<br /><br /><pre class="brush: js">var original = document.createElement('select');<br />clone = original.cloneNode(false);<br />document.body.appendChild(clone);<br /><br />setTimeout(function() {<br /> $(clone).html('<option>boo hoo!</option>');<br />}, 0);</pre><br />You would expect that this is no different from the first example and here is where they will get ya. Not only it does not update the options list (it will be empty), but it also somehow manages to show you that the <tt>innerHTML</tt> property was actually updated and contains all the new data.<br /><br /><pre class="brush: js"><br />// .....<br /><br />setTimeout(function() {<br /> $(clone).html('<option>boo hoo!</option>');<br /> alert(clone.innerHTML); // -> '<option>boo hoo!</option>'<br />}, 0);</pre><br />All versions affected 6,7 and 8 (didn't test in 9 though)<br /><br />In case you really really need to update a cloned SELECT element in an async callback, here is a hack how you can do that<br /><br /><pre class="brush: js"><br />// ....<br />setTimeout(function() {<br /> $(clone).html('<option>boo hoo!</option>');<br /><br /> var dummy = document.createElement('option');<br /> dummy.text = 'dummy'; // DON'T use innerHTML in here!<br /> clone.add(dummy);<br /> clone.removeChild(dummy);<br />}, 0);</pre><br />It will fix the problem, but you'll need to add some checks in there to ensure it's actually IE you're dealing with.<br /><br />That's the whole gotcha. Hope will save someone's dayNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-28559859462132190352010-10-02T18:46:00.007+03:002010-10-02T20:19:48.728+03:00Making Pretty CLI Applications In RubySometimes we need to process large amount of data in Ruby, convert things from one format to another, process a large database, etc. And when you start implementing those things as rake tasks or something like that you need some feedback, say to see the progress and so one. Normally people would use <tt>puts</tt> <br /><br /><pre class="brush: ruby">index = 0<br />count = things.size<br />things.each do |thing|<br /> do_something_about thing<br /><br /> puts "#{index +=1} of #{count}"<br />end</pre><br />But when you have several thousands or millions things to process this approach doesn't work, because it will just blow into the console, which is ugly and well... there are ways to do it much better, prettier and more professionally looking.<br /><br />There are gems and libs that will help you to do it properly, but in this article I'd like to show how it actually works internally. <br /><br /><br /><b>Strings Rewriting</b><br /><br />One of the first things you might want to learn in order to make seriously looking CLI app is how to rewrite strings all over. It is a bit tricky in Ruby so here how it looks like. First of all you need to learn the "\r" symbol, which is called "caret return" and well it returns the caret. A simple example will demonstrate. Say you have a line of code like that<br /><br /><pre class="brush: ruby">puts "one\ranother"</pre><br />when you run it, you will see in the console a string like <tt>"another"</tt> and what's happening is that ruby will print <tt>"one"</tt> then return the caret and print <tt>"another"</tt> over it, so that you see the last one only. But the trouble is that if you'll write something like that<br /><br /><pre class="brush: ruby">puts "one"<br />puts "\ranother"</pre><br />It won't work and you'll see two strings in the console <tt>"one"</tt> and <tt>"another"</tt>, and because of that if you'll put into your loop something like that<br /><br /><pre class="brush: ruby">puts "\r#{index += 1} of #{count}"</pre><br />it won't work either and you will see the same ugly roll of strings. To make it working you have to use the a combination of the <tt>print</tt> and <tt>STDOUT.flush</tt> calls, kida like that<br /><br /><pre class="brush: ruby">8.times do |i|<br /> print "\r#{i}"<br /> STDOUT.flush<br /> sleep 0.1<br />end</pre><br />In this case it will print a string and stay on it. <tt>STDOUT.flush</tt> dumps the current stdout into the console, and on the next iteration, it will normally go to the beginning of the string and write it over as you needed.<br /><br />But it is still not everything. If you run a piece of code like this one<br /><br /><pre class="brush: ruby">%w{looooong short}.each do |str|<br /> print "\r#{str}"<br /> STDOUT.flush<br /> sleep 0.5<br />end</pre><br />You will see that on the second iteration, the previous line won't be entirely overwritten and instead of <tt>"short"</tt> you will see <tt>"shortong"</tt>, to make it work properly you need to write a long enough string that contains spaces at the end, for example<br /><br /><pre class="brush: ruby">%w{looooong short}.each do |str|<br /> print "\r#{str.ljust(80)}"<br /> STDOUT.flush<br /> sleep 0.5<br />end</pre><br /><tt>String#ljust</tt> makes a string of the given length by filling the remaining places with spaces. This way you will always overwrite 80 symbols of the line in the console.<br /><br />To wrap it up nicely you might create a simple function and your loop will look like that <br /><br /><pre class="brush: ruby">def print_r(text, size=80)<br /> print "\r#{text.ljust(size)}"<br /> STDOUT.flush<br />end<br /><br />index = 0<br />count = things.size<br />things.each do |thing|<br /> do_something_about thing<br /><br /> print_r "#{index +=1} of #{count}"<br />end<br />puts "\n" # <- a final new line</pre><br /><br /><br /><b>Displaying the progress</b><br /><br />With the trick above you will be able to show a constantly updating status line, but there are still some meat on this bone. Showing the user things like <tt>"345 of 87654"</tt> is not particularly user friendly, because it might be a bit annoying to calculate the actual progress in your head all the time. Would be nice to show the progress in percents as well. Happily it is very simple to do using placeholders<br /><br /><pre class="brush: ruby">print_r(<br /> "%d of %d (%d%%)" %<br /> [index+=1, count, (index.to_f/count * 100)]<br />)</pre><br />The other usual problem with status reports is that you might have particularly large set of things, say several millions of them and your script might process several thousands of them per second. In this case hitting your console several thousands times per second will seriously slow the process down, so you might need a way to skip some steps and print reports in some periods of time. You can do that the following way<br /><br /><pre class="brush: ruby">index = 0<br />count = things.size<br />step = count / 1000 # 1/10th of a percent<br /><br />things.each do |thing|<br /> if (index += 1) % step == 0<br /> print_r "....."<br /> end<br />end</pre><br />As you can see we defined the <tt>step</tt> variable and then skip all the non-round iterations. In this particular case it will make the script to update the report every <tt>1/10th</tt> of a percent of the job done. Which is in most cases is not a big drawback and still provides the user with progress updates.<br /><br />You also might think of <tt>ETA</tt> calculations, but you probably can figure it out on your own now, it's very simple.<br /><br /><br /><b>Add Some Colors</b><br /><br />And the last thing I'd like to show is how to make colors in the console, which might make your application look even cooler. Some developers already know how to do that, but some don't. So here it is.<br /><br />Basically it is very simple and in some ways similar to HTML tags. You use things called <tt>escape sequences</tt> which are just some markers like tags, you have an opening one, and you have a closing one, like that<br /><br /><pre class="brush: ruby">puts "\e[32mGREEN TEXT\e[0m"<br />puts "\e[31mRED TEXT\e[0m"<br />puts "\e[36mBLUE TEXT\e[0m"</pre><br />As you can see, the closing sequence is always the same and the opening one differs only by a number, and this number is basically describes the properties of the following text. It might be a color, or a blinking effect, you can nest them just like normal HTML tags and so one. You can find full list of options <a href="http://en.wikipedia.org/wiki/ANSI_escape_code">on wikipedia</a><br /><br />The only trouble with those things is that the format of escape sequences differs from a platform to platform. The example above is for OSX terminal. How to make those things working in DOS and Linux you can find that on the same wikipedia page.<br /><br /><br />This is about it. Now go and make the world prettier!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-9393587498741098502010-09-23T15:47:00.008+03:002010-09-23T16:18:10.067+03:00Easy Way Out of The STI HellI like the idea of STI (single table inheritance), it is cheap, dodgy but it works and allows you to play with all sorts of sub-types in a civilized way. For example you can redefine things in subclasses, use strategies and so one.<br /><br />But when you try STI with Rails, you immediately fall into the polymorphic routes hell. Because you have new types, Rails tries to find routes for them, and it doesn't want to use the base model as a fallback. And here, people start to do all kinds of things (I did), define controller level helpers, generators, modules and so one. But then, someone adds a new custom method or a new subtype and it all falls down like a house of cards.<br /><br />Well, you know what they say, the exit from a hell lays at the very bottom of it. And in Rails it will be routes. Say I want to handle all sorts of <tt>User</tt> model subclasses, like <tt>User::Admin</tt>, <tt>User::Manager</tt>, <tt>User::Blocked</tt>.<br /><br /><pre class="brush: ruby">Trololo::Application.routes.draw do<br /> # here I collect all the User subtypes<br /> user_types = Dir["#{Rails.root}/app/models/user/*.rb"].map do |name|<br /> "user_" + File.basename(name).gsub('.rb', '').pluralize<br /> end<br /><br /> # and then I put all of them one by one<br /> (['users'] + user_types).each do |name|<br /> resources name, :controller => 'users', :path => '/users' do<br /> member do<br /> get 'stats'<br /> end<br /><br /> resources :comments # we can define nested resources too<br /> end<br /> end<br />end</pre><br />I use the <tt>Rails 3</tt> notation in this case, but I suppose you can figure how to make it work under Rails 2 as well.<br /><br />It is still a bit dodgy, but it is better and more stable than defining those type-specific routes manually in controllers, you also can automatically handle all the nested routes as well.<br /><br />That's it, hope that will helpNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-85424830129009975042010-09-09T15:44:00.005+03:002010-09-09T16:00:29.119+03:00RightJS 2 jQuerysh PluginHey folks. I had couple of minutes of free time and cooked a fancy plugin for RightJS 2.<br /><br />It's called 'jQuerysh' and provides the jquery-like behavior for the <tt>$()</tt> function. You can copypast or build it from over here <a href="http://github.com/rightjs/rightjs-plugins/blob/2.0.0/src/jquerysh/jquerysh.js">jquerysh on github</a><br /><br />Basically it does three things with the <tt>$()</tt> function. You can navigate in jquery-style<br /><br /><pre class="brush: js">$('#element-id').onClick('addClass', 'marked');<br /><br />$('div.class').each('addClass', 'marked');</pre><br />And you can call the <tt>onReady</tt> via it, same way as in jQuery<br /><br /><pre class="brush: js">$(function() {<br /> // will be executed when on ready<br />});</pre><br />This is pretty much it, might be useful for people who need to work with both jQuery and RightJS.<br /><br />And yes, it works with RightJS 2 only. Not like I want to make you switch to RJS2 (which I actually want), RJS1 is simply not built for that.<br /><br />CheersNikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-7616987595159219122010-09-09T08:30:00.006+03:002010-09-09T09:56:43.608+03:00RightJS 1 Chrome IssuesAs much as I like to think about webkit as the world's savior, it constantly produces all sorts of weird stuff in Google Chrome, the last update of which had killed some important feature in RightJS 1 (do those folks even think before they make such changes? because I guess it won't be a problem of RightJS only)<br /><br />In any case, the shorts and longs of the story is that they screwed the <tt>Element#hidden()</tt> method, which broke down several UI units, Autocompleter, Calendar, Lightbox, Selectable and Tooltips.<br /><br />I've published a package for you over here <a href="http://rightjs.lighthouseapp.com/projects/31989/tickets/343/a/665444/rui-fixes.zip">RightJS 1 UI Fixes</a>. It has patched builds of all those widgets, plus a fresh RightJS 1 build with backports from RightJS 2.<br /><br />If this core-build will cause you troubles, you can patch your own by a simple line of code like that<br /><br /><pre class="brush: js">Element.insert({<br /> visible: function() {<br /> return this.getStyle('display') !== 'none';<br /> }<br />});</pre><br />And don't use the <tt>Element#hidden()</tt> method in your code, use <tt>Element#visible()</tt> instead.<br /><br />Also think about moving to RightJS2, it works with wrappers and therefore doesn't have such issues by design.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-85179112101399301142010-08-27T18:27:00.003+03:002010-08-27T18:56:05.955+03:00RightJS 2 Release Plan UpdatesMy dear fellas, this lovely Friday's evening I'd like to share with you some updates on the RightJS 2.0 release plan. And yes, by "updates" I mean delays.<br /><br />No need for dirty swears, because there are two good reasons for that. 1) Rails 3 which should come out any moment now, and 2) upcoming IE 9 beta which is scheduled to September 15th. And as we all know well those funny MS folks, I think you'll agree that it's better to wait couple of weeks rather than pull your hair off later.<br /><br />And it's not all that bad, there are good news too. I'm almost finished porting the UI modules to RJS 2, which means there well be the RC2 release in about couple of days I think. RC2 will include the core with all the latest updates and all the plugins and widgets ported to the new system. Generally this will be the final version and unless someone find a bug it will go to the actual release as is.<br /><br />You'll have couple of weeks to play with it until the IE 9 release, and I'll have couple of weeks to brush up the docs, update rightjs.org and rework right-rails. Thinks that should give as a good runaway for a nice and smooth release.<br /><br />This is about it. Take care!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-14174070248872952932010-08-17T10:20:00.003+03:002010-08-17T11:06:31.840+03:00RightJS UI 2 The Battle PlanHello people. As I'm currently elbow deep in porting rightjs-ui modules to RightJS 2, I'd like to share some ideas and thoughts behind the changes so you knew what to expect.<br /><br /><br /><b>RightJS 2 With New UI System</b><br /><br />First of all the RightJS 2 release will be not just the core release, there are lots of cool new features and some dramatic changes, so I'm porting all the plugins and ui widgets to the new development approach, and with the RightJS 2 release I'll release updates for all the plugins as well.<br /><br />This way we will have some sort of a clean slate, and you'll be able to start with all new tools right away.<br /><br /><br /><b>Widgets === Elements</b><br /><br />One of the biggest change in RightJS 2 is those <a href="http://st-on-it.blogspot.com/2010/08/dom-wrappers-in-rightjs-2.html">really cool object-oriented dom-wrappers feature</a>, and in the RightJS UI 2 we will take full advantage of it. If in the current system all the widgets are classes with some limited interface, in RightJS UI 2, all the widgets will be inherited from the dom-wrappers, so you will be able to manipulate with them as if they were normal elements.<br /><br /><pre class="brush: js">// say you have a calendar unit<br />var calendar = new Calendar({<br /> // some options<br />});<br /><br />// now you can do anything you want as if it was a normal Element<br />calendar.insertTo('my-element', 'top');<br />calendar.addClass('my-calendar');<br />calendar.set('id', 'my-calendar-id');<br />calendar.onChange(function() {<br /> // do something about it<br />});<br /><br />// you also will be able to access it through the standard navigation methods<br />$('my-calendar-id'); // -> the 'calendar'<br />$('my-element').first('div.my-calendar'); // -> the same calendar<br /><br />// it will be also follow the general inheritance structure<br />calendar instanceof Calendar; // -> true<br />calendar instanceof Element; // -> true</pre><br />You've got the picture, everything you can do with any element on the page you will be able to do with the widgets and do that directly.<br /><br /><br /><b>Unified Initialization</b><br /><br />RightJS UI were growing a bit chaotically during the last year and we have some diverse ways to initialize units. With the new release all of them will work via the same initialization process with the same principles. The <tt>rel</tt> hacks are gone, instead of that we will use the HTML5 <tt>data-widget-name</tt> attributes.<br /><br /><pre class="brush: html"><input data-autocompleter="{url: '/some.url'}" /><br /><br /><input data-calendar="{format: 'US', hideOnClick: true}" /></pre><br /><br /><b>Meta-framework and Modularity</b><br /><br />In current incarnation all the RightJS UI widgets are pretty much independent, which means that we have some duplications here and there, same things work slightly different, not really clean styles and so one.<br /><br />It's time to refactor the mess, with RightJS UI 2 there will be a meta framework which will provide common bits of elements and styles, like say buttons, panels, spinners, various common functionality and so one. This way we will have a consistent elements behavior over the widgets, plus it will be easier to create new widgets with the common blocks of code already existing.<br /><br /><br /><b>Unified Stylesheets</b><br /><br />The stylesheets also will be cleaned up and unified. There will be common classes for buttons, panels, spinners and so one. One of the reasons is that now we will be able to create skins in a civilized way.<br /><br />There will be no actual skins with the release, we simply do the preparation work, but the skins constructor is one of the first things to do right after the release.<br /><br /><br /><br /><b>Summary</b><br /><br />As you can see with RightJS 2 release we will bring to the next level not just the core, but the ui modules as well.<br /><br />I've already ported the <tt>Autocompleter</tt> and <tt>Calendar</tt> widgets, you can check it out at the <a href="http://github.com/rightjs/rightjs-ui/tree/2.0.0">2.0.0 branch</a> on github. I estimate it will take about a week to port the rest of them to RightJS 2.<br /><br />After that there will be RC2 release where I'll publish RightJS core and all the modules for tests. And in about a week after that (by the end of August) we shall release.<br /><br />This is about it.<br /><br />And btw, if you have thoughts about new features for some of the existing rightjs-ui widgets, that's a really good moment to let me know.<br /><br />Now that's it.<br />Take care!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-747045206301305612010-08-07T14:21:00.003+03:002010-08-07T15:31:32.723+03:00DOM-Wrappers In RightJS 2Put your tin-foil hats on people, because it's your next brainwashing session about upcoming RightJS 2.<br /><br />When you heard that RightJS 2 is going to have dom-wrappers instead of direct dom-units access you might think "oh, that's not a big deal, jQuery has dom-wrappers from the very beginning!". And you will be dead wrong! I already touched it a bit in one of my previous articles, now let me show this beauty in details.<br /><br /><br /><b>DOM-Wrappers == Classes</b><br /><br />First of all, dom-wrappers in RightJS are not just a bunch of functions behind a namespace, dom-wrappers in RightJS essentially are normal classes, with inheritance and functionality-injection support. For example you have the basic class <tt>Element</tt> and two subclasses <tt>Form</tt> and <tt>Input</tt>, which means you can say normally call <tt>instanceof</tt> on them.<br /><br /><pre class="brush: js">$('div') instanceof Element; // true<br />$('div') instanceof Input; // false<br />$('div') instanceof Form; // false<br /><br />$('form') instanceof Element; // true<br />$('form') instanceof Input; // false<br />$('form') instanceof Form; // true<br /><br />$('input') instanceof Element; // true<br />$('input') instanceof Input; // true<br />$('input') instanceof Form; // false</pre><br />You also can extend them separately and all the methods will follow the inheritance structure principles<br /><br /><pre class="brush: js">Element.include({<br /> global_method: function() {<br /> // this method will appear on all elements<br /> }<br />});<br /><br />Input.include({<br /> inputs_only: function() {<br /> // this method will appear on Input elements only<br /> }<br />});</pre><br />You can use polymorphism, redefine the meaning of methods, etc. For example the <tt>Element#select</tt> will search for matching elements by a css-rule, but <tt>Input#select</tt> will put the focus on the input element and select its content. No problem, you can do that easily.<br /><br /><br /><b>Define Your Own Wrappers</b><br /><br />The usual extending methods like <tt>Element#include</tt>, <tt>Form#include</tt> are fine, but in RightJS you are also allowed to define your own wrappers for certain types of elements. For example you can define a tables-sepecific wrapper<br /><br /><pre class="brush: js">Element.Wrappers.TABLE = new Wrapper(Element, {<br /> sortBy: function(column) {<br /> // sort the table body<br /> }<br />});</pre><br />Or you could create a textareas wrapper the same way<br /><br /><pre class="brush: js">Element.Wrappers.TEXTAREA = new Wrapper(Input, {<br /> spellcheck: function() {<br /> // spellcheck the content<br /> }<br />});</pre><br />NOTE: we inherited the <tt>Element</tt> and <tt>Input</tt> classes as you would normally do with any other classes in RigthJS.<br /><br />Once you've done that, anytime you access a table or a textarea you'll have those new methods available<br /><br /><pre class="brush: js">$('my-table').sortBy('name');<br /><br />$('my-textarea').spellcheck();</pre><br />This feature will let you to adjust and completely redefine the framework itself for the needs of your application.<br /><br />But this is not the most kick-ass thing yet. Because we have much more!<br /><br /><br /><b>Private DOM-Wrappers</b><br /><br />With RightJS 2 you are not limited to the actual dom-nodes and tags. You can define your very own private dom-wrappers that won't be tied to the framework structure in any way. Why would you need that? The answer is simple - widgets.<br /><br />How do you normally write a widget? You create some class which aggregates some main element and then you have all the headaches with different contexts and bindings, because half of your logic is in your class and half is in your elements<br /><br /><pre class="brush: js">var MyWidget = new Class(Observer, {<br /> initialize: function() {<br /> this.element = $E('div')<br /> .onClick(this.clicked.bind(this));<br /> },<br /><br /> clicked: function() {<br /> // do something about it.<br /> }<br />});</pre><br />Then more, you'll have to create several proxy methods to delegate the methods to actually insert the widget on the page and do other normal dom-manipulations and so one and so one. In more or less complicated case those things tend to get quite messy.<br /><br />Well my friends, you don't have to suffer anymore, because now you can define your widget as a private wrapper and inherit any existing dom-wrapper directly just like that<br /><br /><pre class="brush: js">var MyWidget = new Wrapper(Element, {<br /> initialize: function(widget_id) {<br /> this.$super('div', {<br /> 'id': widget_id,<br /> 'class': 'my-widget'<br /> });<br /> this.onClick('doSomething');<br /><br /> // build your entire widget over here<br /> },<br /><br /> doSomething: function() {<br /> // do something about the click<br /> }<br />});</pre><br />NOTE: now you never leave the actual element context, don't need to worry about bindings, and then, can manipulate with your widget as a usual element on your page.<br /><br /><pre class="brush: js">var widget = new MyWidget('widget-id');<br />widget.insertTo('some-element', 'after');<br />widget.addClass('custom-class');<br /><br />// more of that!<br />$('widget-id') instanceof MyWidget; // true!</pre><br />And there is more! You can inherit your private wrappers as any other and create different versions of your widget!<br /><br /><pre class="brush: js">var MySuperWidget = new Wrapper(MyWidget, {<br /> initialize: function(widget_id) {<br /> this.$super(widget_id);<br /><br /> this.onClick('doSuperThing');<br /> },<br /><br /> doSuperThing: function() {<br /> // do the super thing over here!<br /> }<br />});</pre><br />You can create abstract widgets, share modules between them, do any sorts of crazy things, the possibilities are endless! And at the end, you still have an <tt>Element</tt>, which you can toss around the page in the usual way.<br /><br />---<br /><br />Oh yes my dear fellas, RightJS 2 will help you to kick some serious ass! The right way!<br /><br />And this is about it. Come over for the next session, it will be fun!Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-1170412808884063472010-08-05T15:55:00.005+03:002010-08-05T16:18:13.971+03:00Prepare Your Project For RightJS 2Some notes for those lucky of you who already is hooked to RightJS and the ones who think about giving it a try, but afraid that when RightJS 2 will start saving the world, the ones code will go south.<br /><br /><b>Rule #1</b> <tt>don't panic</tt>, despite of all the massive changes in the dom-stack and all the new finest kickassery, the actual API almost didn't change, just instead of real dom-nodes/events/etc you will receive some proxy objects, which have the same exact API. The difference is that you will have no direct access to the dom-unit attributes, so if you want your code to be working both in RightJS 1 and RightJS 2, use the <tt>Element#get</tt>, <tt>#set</tt> and <tt>#has</tt> methods instead.<br /><br /><pre class="brush: js">// instead of this<br />$(element).id = 'boo-hoo';<br />var id = $(element).id ? $(element).id : 'default';<br /> <br />// write it like that<br />$(element).set('id', 'boo-hoo');<br />var id = $(element).has('id') ? $(element).get('id') : 'default';</pre><br />If you need to access an element <tt>innerHTML</tt> use a simple patch like that<br /><br /><pre class="brush: js">Element.include({<br /> html: function() {<br /> return this.innerHTML;<br /> }<br />});</pre><br />Later, when you will migrate to the actual RightJS 2, just remove it, RightJS 2 will have this method out of box.<br /><br /><br /><b>Rule #2</b> <tt>don't access `window` and `document` directly</tt>, when you need to access some of the RightJS methods, put them through the same <tt>`$()`</tt> function first as you do with the dom elements<br /><br /><pre class="brush: js">// instead of those<br />document.onReady(function() { ... });<br />window.sizes();<br /><br />// call it like this<br />$(document).onReady(function() { ... });<br />$(window).sizes();</pre><br /><br /><b>Rule #3</b> <tt>don't use `Form.Element`</tt> this unit will be renamed to <tt>Input</tt> in RightJS 2, so don't touch it or create a simple reference like that<br /><br /><pre class="brush: js">var Input = Form.Element;</pre><br />and work with the <tt>Input</tt> object instead.<br /><br /><br />This is about it. If you follow those three simple rules, all your code should be in working condition when you switch to RightJS 2.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0tag:blogger.com,1999:blog-752094859566372098.post-33352492777428660502010-08-01T09:09:00.002+03:002010-08-01T09:27:04.102+03:00The Circus of Web DevelopmentYou might think of the web-development area (or sphere if you will) as some sort of a circus. For example.<br /><br />Say there is an elephants show of Java developers, they big, slow, but precise. Then there is a exotic pet show of Python developers. Fearless camel riders with the perl guys. JavaScript people will be magicians, weird fellas who make things appear and disappear by some flimsy tricks.<br /><br />Then there are a bunch of trained monkeys of Ruby kids (yes my agile friends we are :)). ASP.NET folks will be gipsy fortune-tellers, barely connected with the reality and no-one listen to them. And there are bears on monocycles in silly turkish hats, those are the PHP people (you are comrades, you are).<br /><br />Clowns! Those will be the web-architects. Just like the real clowns, they barely can do a thing properly, and yet, they think they own the circus.Nikolay V. Nemshilovhttp://www.blogger.com/profile/11826995023912878683noreply@blogger.com0