New Clientside Scripts, 3rd Party Scripts added
So in the last week or so I’ve been working on a bunch of CMS related tasks. I’ve added some new stuff and, for the first time, 3rd party scripts are now in our repository. Why? Well, why re-invent the wheel, right? In some cases I’ve implemented a few changes in these libraries, while in others I’ve rewritten them a LOT. You’ll find working examples and details in the wikitorials and I’ll be updating our docs shortly.
simple.editor.js
As much as I’d like to implement a wysiwyg editor or use one of the 3rd party ones out there like TinyMCE or FCKeditor, or even the Mootools wysiwyg by Inviz, it doesn’t suit my needs right now. This annoys me, but the fact is that wysiwyg editors built in browsers are fraught with peril. Creating one with flash is an option, but I’m not a flash expert.
So what I’ve created is an html editor that just helps you wrap your content with custom tags. I need to add tag support and that sort of thing like posteditor (or I might just integrate posteditor).
Anyway, basically this works kinda the way my form validator works. You create commands (like “bold” or “underline”) and add them to the editor’s list of commands. You can add commands to an instance or to the global set. Then you add buttons to your editor that reference the command and you’re set.
Here’s an example of what it takes to add a command to the editor:
/* Default commands: */
SimpleEditor.addCommands({
/* bold - <b></b> */
bold: {
shortcut: 'b',
command: function(input){
input.insertAroundCursor({before:'<b>',after:'</b>'});
}
},
/* underline - <u></u> */
underline: {
shortcut: 'u',
command: function(input){
input.insertAroundCursor({before:'<u>',after:'</u>'});
}
}
});
And then to make these work, you add a link or image or whatever to your editor like so:
<img src="bold.gif" width="20" height="20" alt="Bold (ctrl+b)" title="Bold (ctrl+b)" rel="bold"/> <img src="underline.gif" width="20" height="20" alt="Underline (ctrl+u)" title="Underline (ctrl+u)" rel="underline"/>
In this case I use images and pass those along when I create a new instance of the editor. It uses the rel attribute to map to the command.
See a working example in the wikitorial.
Autocompleter
I needed an Autocompleter and once again digitarald has beat me to it. I liked this script a whole hell of a lot but it was missing one big thing: multiple values. Now, the right way to implement multivalues with autocomplete is that the user starts typing, valid options show up in the drop down, they click one, and it ads this value to a different dom element, presenting the user with a now empty input. This is how tagging works on flickr and just about every where else. But for our common library I wanted to implement a simple solution for this for others that might want to use it, so I rewrote most of the whole thing. I sent these changes back to digitarald, and he’s going to incorporate them into his release (probably).
Autocompleter.JsonP
I also integrated our JsonP class into the script so that we could use this against the API. Here’s a working example; type in “ipod”.
Execute the block below and then type something into the input above.
new Autocompleter.JsonP($('jsonp'), 'http://api.cnet.com/restApi/v1.0/techProductSearch',
{
jsonpOptions: {
//this data gets added to the query string using JsonP's options
data: {
viewType: 'json',
partKey: '19926949750937665684988687810562', //this is my code, user your own!
iod:'none',
start:0,
results:10
}
},
inheritWidth: false,
dropDownWidth: 600,
//require at least a key stroke from the user
minLength: 1,
//this function filters the results based on the input
filterResponse: function(resp) {
//test it
if(!choices || choices.length == 0) return [];
//filter it and return it
var regex = new RegExp('^' + (this.queryValue || '').escapeRegExp(), 'i');
return choices.filter(function(choice){
return (regex.test(choice.Name.$) || regex.test(choice['@id']));
});
},
useSelection: false,
//because the data returned has a unique structure, we must manage the parsing ourselves
filterResponse: function(resp) {
try {
//this structure is unique to the CNET API
choices = resp.CNETResponse.TechProducts.TechProduct;
//test it
if(!choices || choices.length == 0) return [];
//filter it and return it
return choices.filter(function(choice){
return (choice.Name.$.test(this.getQueryValue(), 'i') || choice['@id'].test(this.getQueryValue()), 'i');
}.bind(this));
} catch(e){'filterResponse error: ', dbug.log(e)}
},
injectChoice: function(choice) {
//again, the structure of these items is unique to the CNET API
if(! choice.Name.$)return;
var el = new Element('li')
.setHTML(this.markQueryValue(choice.Name.$))
.adopt(new Element('span', {'class': 'example-info'}).setHTML(this.markQueryValue(choice['@id'])));
el.inputValue = choice.Name.$+' ('+choice['@id']+')';
this.addChoiceEvents(el).injectInside(this.choices);
}
});
Expect more in the next week or so.

July 9th, 2007 at 6:12 am
Hello Aron, this comment is connected both with the autocompleter and with the IE Problem (’operation aborted’). I have the problem with MF IE 7 generated by the Autocompleter script, and i don’t seem to figure out what to update in the Autocompleter.js so that i obtain the same result as you did with the IFrameShim. And btw, i don’t want to be rude but, if you stressed yourself with the IFrameShim, why is the OverlayFix in Autocompleter necessary - wich basicaly provides the same functionality ?
July 16th, 2007 at 8:04 am
Autocompleter was written by the very talented Harald Kirschner (http://www.digitarald.de). I added it to our library because we wanted to start using it on our tools. I did make a few changes to it (and sent them back to Harald to consider), but he is the principle author. The Overlay solution in this script was authored by him and I didn’t want to mess with it.
The problem you are having is because you are instantiating the class before the dom has loaded. Wrap your javascript in a domready function and you shouldn’t see the error anymore.