Blog
One of the first things I wanted to get working with YUI's Rich Text Editor was to make the editor area styled appropriately. There is an example out there that basically waits for the editor to finish loading and then dynamically adds a link tag to the head of the iframe. It works, but there's a moment where you can see the un-styled content then it switches. Then I found that you can set the initial HTML that's loaded into the iframe, so I figured why not just load it there?
var html = "<html>\n<head>\n<title>{TITLE}</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" +
"<base href=\"http://" + document.domain + "/\">\n" +
"<style>\n{CSS}\n</style>\n" +
"<style>\n{HIDDEN_CSS}\n</style>\n" +
"<style>\n {EXTRA_CSS}\n</style>\n" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/assets/editor_css\">\n" +
"</head>\n" +
"<body onload=\"document.body._rteLoaded = true;\">\n{CONTENT}\n</body>\n</html>\n";
editor = new YAHOO.widget.Editor(container, {
animate: true,
collapse: false,
markup: 'xhtml',
css: '',
html: html,
toolbar: {
buttons: button_config
}
});
Working great so far. In the meantime (ie. while I get my ass caught up) I wrote a simple plugin to make it super easy to add properties to your ActiveRecord models without needing table columns for all of them.
Nothing earth-shattering, just a cool little plugin I wanted to share.
I call it Bitchin.
There are two parts to it, Bitchin and Hashed. The only difference is that Bitchin uses a Bit Field so it can only store boolean fields which means it's much faster. As long as you have an Integer called bit_flag in your table you just need to do this...
class User < ActiveRecord::Base
bitchin :active, :banned, :stupid
And the accessors are automatically created for you...
user.stupid = true
user.stupid? #=> true
user.stupid #=> true
Hashed works the same way but it relies on ActiveRecord's built-in hash serialization so you can basically store any scalar value.More about configuration options and how to use in the README.
This plugin is under the Do Whatever The Fuck You Want With It License (WTFYWL)
Rails
First you'll need to install Raspell and it's dependencies. Next you'll need an action to call this. I already had an Editor controller for other stuff like image browsing, so I just added this action.
def spellcheck
spell = Aspell.new
spell.set_option("mode", "html")
words = spell.list_misspelled([params[:text]])
checked = { :check => :spelling,
:data => words.map { |word|
{
:word => word,
:suggestions => spell.suggest(word)
}
}
}
render :json => checked.to_json
end
Fairly straightforward. It looks for misspelled words and returns a JSON object with the results. The set_option("mode", "html") is important because it makes Aspell ignore text that's part of an HTML tag.
JavaScript
I modified Dav's script slightly, you can grab my version here. There are three main differences. First I made the script a function of the Editor object, so that it could be initialized on command. I'll show how to do that later.Then I changed the Ajax request to POST the HTML back to the action for checking.
this._conn = YAHOO.util.Connect.asyncRequest('POST', '/editor/spellcheck', {
success: this._checkSpelling,
failure: function() {},
scope: this
}, 'text=' + escape(this.getEditorHTML()));
Finally I changed the replacement regular expression to ingore text inside HTML tags and to look for word boundaries.
html = html.replace(new RegExp('\\b' + data.data[i].word + '(?![^<]*>)\\b', 'g'), '<span class="yui-spellcheck">' + data.data[i].word + '</span>');So to get the Javascript side working just copy my script into a .js file and load that in the HTML. Some time after the editor is initialized call...
editor.initSpellChecker();
Make sure to add a button...
{ type: 'push', label: 'Check Spelling', value: 'spellcheck' } ... and add the Highlight CSS to your main editor config ....
extracss: '.yui-spellcheck { background-color: yellow; }' I've been feeling a lot of anxiety about the Web recently and I just figured out why. The iPad, Facebook and the aging platform that is web development are all pointing to big changes for the Internet. Read on for my semi-coherent ramblings.
The iPad has been hugely successful in just a few weeks. I'm holding out for a 3g but I knew from the keynote that it is a "Magical" device. However to me as a web developer the iPad, iPhone and the App Store represent a shift away from technologies I've been specializing in for over a decade. Yes it still has a browser and you can make awesome web apps for the iPhone platform, but in reality the native apps are so much better. This presents a dilemma for me. The notion of developing a app that works on only one platform seems so limiting and constraining to me, but it's so hot right now.
Last night my wife and I were chatting. I was telling her about the Facebook hubub and how I think everyone is blowing it out of proportion. People like Jeffery Zeldman are saying "But most of us, if we think about it, have seen Big Things like this come and go on the web". That's how I want to feel, but as I was talking I could tell that I really felt like this time is different. The fact is that that Facebook has almost 500 million users. There are only 230 million Internet users in the US, and 1.6 billion on the planet. That's 30% of the Net. You can keep saying "I've seen this come and go" but that at some point something is going to stick.
If it does stick it represents a fundamental change in how we interact with the Web. If everyone thinks they need a Facebook account to get around on the Web that means you do too. As a business you need to make sure you're Facebook compatible, just like we bend over for Google Page Rank. Google has been a discovery engine to an existing web of sites. Facebook wants to be the web. This sort of corporate controlled web, however you feel about it, will be rejected by large amounts of Internet users. It already has been.
This left me thinking what's next? What comes after the Web? Until now I couldn't imagine the Web not being the go-to platform for information sharing, communication and entertainment.
When I learned HTML I read HTML4, A Visual Quickstart Guide from the Peachpit Press. HTML4, 13 years ago. HTML5 is only just now looking like we may get to use it sometime soon. IE9 is the big question, and it's still being developed. In other words the fundamental tools we use as web developers are stagnant. Every once in a while we find a gem that's supported by all like Ajax, dragndrop, etc. By and large I feel like the solutions we're coming up with to take it to the next level, while extremely clever, are hackish. We now have 5 browsers to contend with, Firefox, Safari, IE, Chrome and Opera. I can imagine how much of a relief it must be to go to a single platform like iPhone or Android.
All of these things, the Facebook Web, the success of App Stores and the stagnation of web development represent a split in the way people will use the Internet in the future. Computing in general is moving away from a single desktop sitting under your desk to a multitude of devices that have their own specific purpose. Cars are getting Net connections, appliances have WiFi, hell my treadmill has an Ethernet port. As beautiful and elegant as the Web Browser as a single platform is, it's holding us back.
As this story unfolds more segments will be created. More devices, more platforms, more markets. This is a good thing. Niche markets will thrive and individuals will be able to create profitable businesses. But it does mean that I'm probably going to have to learn Objective-C.
For awhile I had a Javascript bot blocker that did a good job keeping spammers from flinging crap at our blogs, but apparently they got smarter. Go Figure. Even though I hate them, I figured the best option would be to add a Captcha system. I looked into systems like Snook and Askimet and really didn't think they were right for our customers at this point. At least not for a first line of defense.
Before you get much further, this is not a plugin, and I'm not even going to provide full examples. One of the chief benefits of a custom system is the obscurity. However, I do think the general approach is sound and worth sharing. IMO, creating a captcha plugin is kind of like selling every lock with the same key.
I looked at hosted solutions like Re-Captcha, but didn't want to be reliant on a third party. I also looked at the Simple Captcha Rails plugin. The problem I had with it is that it generated the images on the fly, which seemed like it could turn into a resource nightmare with all the requests we get.
I wanted to create a system that used static pre-generated images so it would be super fast.
The Gist of It
I generated a set of images using ImageMagick. Here's an example of the code I used to do that...
words = %w{ sack river space }
for word in words
`convert xc:#FFF -resize 110x35! -frame '1x1' -family Helvetica -pointsize 13 -gravity "Center" -draw "text 0,0 '#{word}'" #{word}.jpg`
end
Notice the text is the name of the file. I put those images in a directory in my app. Then I created a table with a key, filename, and created date.
Here's some psuedo code.
image = getRandomCaptchaFile() captcha = findCaptcha(filename = image, createdDate > expireInterval)
if captcha == nil
captcha = new Captcha
captcha.filename = image
captcha.key = getRandomKey()
captcha.created_date = now()
captcha.save
end deleteAllCaptchas(created_date < 1.day.ago) return captcha
This is the crux of the system. Basically I get a random image file, check to see if a captcha record has been created within a set interval, if not create a new one with a new key (such as a GUID), and delete all the old captchas. For doodlekit I also have some code to take into account the multi-site environment.
Once you have this you can create a controller or action to accept the random key. This will look up the image from the captcha table and return the image data. The random key breaks the link between the URL and the actual image.

