/ Published in: JavaScript
The annotaion framework provides access to client side comment based DOM annotations. The framework does not imply any specific usage and is essentially useless on it's own. It merely provides another way to offer metadata for elements.
An annotated DOM Element is any element in the DOM preceeded by one or many comments of the form below. NB. The payload ({...}) is optional.
An annotated DOM Element is any element in the DOM preceeded by one or many comments of the form below. NB. The payload ({...}) is optional.
Expand |
Embed | Plain Text
Copy this code and paste it in your HTML
/*--------------------------------------------------------------------------------- * * Annotations jQuery Plugin * *--------------------------------------------------------------------------------- * * The annotaion framework provides access to client side comment based DOM * annotations. The framework does not imply any specific usage and is * essentially useless on it's own. It merely provides another way to offer * metadata for elements. * * An annotated DOM Element is any element in the DOM preceeded by one or many * comments of the form below. NB. The payload ({...}) is optional. * * <!--@Contraints({blank:true})--> * <input type="text" value="test" id="textbox"/> * * <!--@ReadOnly-->; * <input type="text" value="test" id="textbox"/> * * ------------------------------------------------------------------------------- * 24/10/2008 - Initial Version * ------------------------------------------------------------------------------- * *///------------------------------------------------------------------------------ /* * ------------------------------------------------------------------------------- * W A R N I N G W A R N I N G W A R N I N G W A R N I N G W A R N I N G * ------------------------------------------------------------------------------- * * XML Standards dictate that XML parsers are permitted to silently remove HTML * comments before rendering the output. It cannot be guarenteed that comments * will make it into the final version of the HTML document. All major browsers * do not exhibit this behaviour. It is simply a caveat! * */ (function($) { /*----------------------------------------------------------------------------- * * Annotate Function * *----------------------------------------------------------------------------- * * Adds comment based annotations to the scoped elements. * * @param Annotations variable number of annotations to apply * *///-------------------------------------------------------------------------- $.fn.annotate = function(){ var args = arguments; if(args && args.length > 0){ this.each(function(){ $el = $(this); var a = $el.data("annotations") || []; $.each(args, function(){ $el.before("<"+"!-"+"-"+this+"-"+"-"+">"); var ann = parse(this, prev($el[0])); $el.trigger("annotation:added", [$el, ann]); a.push(ann); }); $el.data("annotations",a); }); return this; } } /*----------------------------------------------------------------------------- * * Unannotate Function * *----------------------------------------------------------------------------- * * Removes some or all of the elements annotations depending on the input * * @param Filter representing the annotaion types to remove. Optional * *///-------------------------------------------------------------------------- $.fn.unannotate = function(){ var $args = arguments; var filter = $args && $args.length > 0; return this.each(function(){ var $el = $(this); var filteredAnnotations = []; $.each($el.data("annotations"), function(){ if(!filter || (filter && $inArray(this.name, $args) != -1)){ $(this.source).remove(); $el.trigger("annotation:removed", [this]); }else{ filteredAnnotations.push(this); } }); $el.data("annotations", (filteredAnnotations.length > 0)?filteredAnnotations:null); }); } /*----------------------------------------------------------------------------- * * Annotations Function * *----------------------------------------------------------------------------- * * Returns a list of annotations for this first object only. Can be filtered * by annotation types. * * @param Filter representing the annotaion types to collect. Optional * *///-------------------------------------------------------------------------- $.fn.annotations = function(){ if(this.length === 0) return null; // attempt to load annotations from cache var annotations = this.data("annotations"); if(!annotations){ annotations = []; var p = prev(this[0]); while(isAnnotation(p)){ annotations.push( parse($.trim(p.nodeValue), p) ); p = prev(p); } this.data("annotations", annotations); } if(arguments.length > 0){ var args = arguments; annotations = $.map(annotations, function(el){ var found = false; $.each(args, function(){ return !(found = (el.name==this)); }); return found ? el : null; }); } return annotations; } /*----------------------------------------------------------------------------- * * Annotated Utility Function * *----------------------------------------------------------------------------- * * Returns a list of all annotated elements from the root specified or the * document * * @param Filter representing the annotaion types to collect * @param Root element to look for annotations, defaults to document element * *///-------------------------------------------------------------------------- $.annotated = function(filter, root){ var n = $(root || document)[0]; var v = $.trim(n.nodeValue); if (isAnnotation(n)){ if(filter){ if(filter.constructor == String && (parse(v).name === filter)){ return [next(n,true)]; }else if(filter.constructor == Array){ var found = false; $.each(filter, function(){ return !(found = (parse(v).name === this)); }); return found?[next(n,true)]:[]; }else{ return []; } }else{ return [next(n,true)]; } } var children = []; for(var m = n.firstChild; m != null; m = m.nextSibling) { $.each($.annotated(filter,m), function(){children.push(this)}); } return $(jQuery.unique(children)); } /*----------------------------------------------------------------------------- * * Private Functions * *----------------------------------------------------------------------------- * * Helper functions used through out the public API of the plugins * *///-------------------------------------------------------------------------- var NODE_COMMENT = 8; var NODE_TEXT = 3; function prev(root, skipComments){ var ps = root ? root.previousSibling : null; return (ps && (ps.nodeType === NODE_TEXT || (ps.nodeType === NODE_COMMENT && skipComments)))?prev(ps,skipComments):ps; } function next(root, skipComments){ var ns = root ? root.nextSibling : null; return (ns && (ns.nodeType === NODE_TEXT || (ns.nodeType === NODE_COMMENT && skipComments)))?next(ns,skipComments):ns; } function parse(annotation, src){ var payload = (annotation.match(/\(.*\)/)||[""])[0]; var name = (annotation.match(/^@[A-Z,a-z]*/)||[""])[0]; return {name:name, data:eval(payload), source:src}; } function isAnnotation(node){ return node && (node.nodeType === NODE_COMMENT && $.trim(node.nodeValue).substring(0,1) === "@"); } function remove(idx, array){ var rest = array.slice(idx + 1 || array.length); array.length = idx < 0 ? array.length + idx : idx; return array.push.apply(array, rest); } })(jQuery);