Friday, November 12, 2010

RightJS RTE Concept

In 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.

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 evil plan for RightJS 2.2.

Meanwhile I've been working on this puppy



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.


Meet RRTE The Frameless

One of the major differences from usual RTEs is that our RTE (which goes under the codename RRTE) does not use any frakking frames. Instead, it uses an inlined DIV with contenteditable="true" property.

If now you're wondering what it gives you, then this is what:

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 blockquote and pre tags are also painted through usual CSS right on the page.

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.

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.


Modular

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.

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 4k of gzipped code (including stylesheets) and my intention is to keep it under 10k size.

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.


Extendable

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 Save button is implemented


Rte.Tool.Save = new Class(Rte.Tool, {
shortcut: 'S',

initialize: function(rte) {
this.$super(rte);
if (!rte.textarea.form()) {
this.disable();
}
},

exec: function() {
if (!this.disabled) {
this.rte.textarea.form().submit();
}
}
});

RRTE will provide you with basic tools and open API, so I expect it to be pretty civilized and easy to extend.


What and When

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.

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.


This is basically it. Enjoy the news!

--
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!

Monday, October 25, 2010

RightJS 2.2 Notes

I'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.


Native Fx

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.

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.


Better UJS

The current implementation of UJS in RightJS works with an event target property only. The trouble with this solution is that when you have something like

<div id="one">first
<div id="two">second
<div id="three">third</div>
</div>
</div>

and you attach an event listener to say the top one

"div#one".onClick(function() {
...
});

it will reacts only if the user clicks on the div#one 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.

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.

Hey! You will be able to make UJS stuff within UJS stuff! :)


Cookie plugin

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.

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.


IE8 And Pals

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?

Furthermore the change/submit events still don't bubble and we carry quite large chunk of code in the core, to work this thing around.

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.

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.

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.

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.


---

Anyhow, those are the notes and thoughts. Let me know if you have something on your mind about that

Thursday, October 14, 2010

Cloned SELECT elements in IE

What 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.

The story goes like that. Say I have a SELECT element and then you clone it a bunch of times and populate with new content, kinda like that

var original = document.createElement('select');
clone = original.cloneNode(false);
document.body.appendChild(clone);

$(clone).html('<option>boo hoo!</option>');

And that all works fine, but now say you update the content in another function, say an ajax callback or something

var original = document.createElement('select');
clone = original.cloneNode(false);
document.body.appendChild(clone);

setTimeout(function() {
$(clone).html('<option>boo hoo!</option>');
}, 0);

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 innerHTML property was actually updated and contains all the new data.


// .....

setTimeout(function() {
$(clone).html('<option>boo hoo!</option>');
alert(clone.innerHTML); // -> '<option>boo hoo!</option>'
}, 0);

All versions affected 6,7 and 8 (didn't test in 9 though)

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


// ....
setTimeout(function() {
$(clone).html('<option>boo hoo!</option>');

var dummy = document.createElement('option');
dummy.text = 'dummy'; // DON'T use innerHTML in here!
clone.add(dummy);
clone.removeChild(dummy);
}, 0);

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.

That's the whole gotcha. Hope will save someone's day

Saturday, October 2, 2010

Making Pretty CLI Applications In Ruby

Sometimes 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 puts

index = 0
count = things.size
things.each do |thing|
do_something_about thing

puts "#{index +=1} of #{count}"
end

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.

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.


Strings Rewriting

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

puts "one\ranother"

when you run it, you will see in the console a string like "another" and what's happening is that ruby will print "one" then return the caret and print "another" over it, so that you see the last one only. But the trouble is that if you'll write something like that

puts "one"
puts "\ranother"

It won't work and you'll see two strings in the console "one" and "another", and because of that if you'll put into your loop something like that

puts "\r#{index += 1} of #{count}"

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 print and STDOUT.flush calls, kida like that

8.times do |i|
print "\r#{i}"
STDOUT.flush
sleep 0.1
end

In this case it will print a string and stay on it. STDOUT.flush 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.

But it is still not everything. If you run a piece of code like this one

%w{looooong short}.each do |str|
print "\r#{str}"
STDOUT.flush
sleep 0.5
end

You will see that on the second iteration, the previous line won't be entirely overwritten and instead of "short" you will see "shortong", to make it work properly you need to write a long enough string that contains spaces at the end, for example

%w{looooong short}.each do |str|
print "\r#{str.ljust(80)}"
STDOUT.flush
sleep 0.5
end

String#ljust 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.

To wrap it up nicely you might create a simple function and your loop will look like that

def print_r(text, size=80)
print "\r#{text.ljust(size)}"
STDOUT.flush
end

index = 0
count = things.size
things.each do |thing|
do_something_about thing

print_r "#{index +=1} of #{count}"
end
puts "\n" # <- a final new line



Displaying the progress

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 "345 of 87654" 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

print_r(
"%d of %d (%d%%)" %
[index+=1, count, (index.to_f/count * 100)]
)

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

index = 0
count = things.size
step = count / 1000 # 1/10th of a percent

things.each do |thing|
if (index += 1) % step == 0
print_r "....."
end
end

As you can see we defined the step variable and then skip all the non-round iterations. In this particular case it will make the script to update the report every 1/10th 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.

You also might think of ETA calculations, but you probably can figure it out on your own now, it's very simple.


Add Some Colors

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.

Basically it is very simple and in some ways similar to HTML tags. You use things called escape sequences which are just some markers like tags, you have an opening one, and you have a closing one, like that

puts "\e[32mGREEN TEXT\e[0m"
puts "\e[31mRED TEXT\e[0m"
puts "\e[36mBLUE TEXT\e[0m"

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 on wikipedia

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.


This is about it. Now go and make the world prettier!

Thursday, September 23, 2010

Easy Way Out of The STI Hell

I 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.

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.

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 User model subclasses, like User::Admin, User::Manager, User::Blocked.

Trololo::Application.routes.draw do
# here I collect all the User subtypes
user_types = Dir["#{Rails.root}/app/models/user/*.rb"].map do |name|
"user_" + File.basename(name).gsub('.rb', '').pluralize
end

# and then I put all of them one by one
(['users'] + user_types).each do |name|
resources name, :controller => 'users', :path => '/users' do
member do
get 'stats'
end

resources :comments # we can define nested resources too
end
end
end

I use the Rails 3 notation in this case, but I suppose you can figure how to make it work under Rails 2 as well.

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.

That's it, hope that will help

Thursday, September 9, 2010

RightJS 2 jQuerysh Plugin

Hey folks. I had couple of minutes of free time and cooked a fancy plugin for RightJS 2.

It's called 'jQuerysh' and provides the jquery-like behavior for the $() function. You can copypast or build it from over here jquerysh on github

Basically it does three things with the $() function. You can navigate in jquery-style

$('#element-id').onClick('addClass', 'marked');

$('div.class').each('addClass', 'marked');

And you can call the onReady via it, same way as in jQuery

$(function() {
// will be executed when on ready
});

This is pretty much it, might be useful for people who need to work with both jQuery and RightJS.

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.

Cheers

RightJS 1 Chrome Issues

As 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)

In any case, the shorts and longs of the story is that they screwed the Element#hidden() method, which broke down several UI units, Autocompleter, Calendar, Lightbox, Selectable and Tooltips.

I've published a package for you over here RightJS 1 UI Fixes. It has patched builds of all those widgets, plus a fresh RightJS 1 build with backports from RightJS 2.

If this core-build will cause you troubles, you can patch your own by a simple line of code like that

Element.insert({
visible: function() {
return this.getStyle('display') !== 'none';
}
});

And don't use the Element#hidden() method in your code, use Element#visible() instead.

Also think about moving to RightJS2, it works with wrappers and therefore doesn't have such issues by design.