# HG changeset patch # User hamidouk # Date 1324636906 -3600 # Node ID df716b99c5bb611f013471c870486cea69e4a1f1 # Parent 97599ff4307210c2635e216ab9150654dc5156b0# Parent fe008e95a716c7990117f980740042954d2fd1e1 Merge with jsdoc diff -r 97599ff43072 -r df716b99c5bb .hgignore --- a/.hgignore Fri Dec 23 10:46:07 2011 +0100 +++ b/.hgignore Fri Dec 23 11:41:46 2011 +0100 @@ -7,3 +7,4 @@ *.swp *.orig src/js/site.js +doc/jsdoc/* diff -r 97599ff43072 -r df716b99c5bb sbin/build/gendoc.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/build/gendoc.bat Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,1 @@ +java -jar ../res/jsdoc/jsrun.jar ../res/jsdoc/app/run.js -a -t=../res/jsdoc/templates/jsdoc/ ../../build/LdtPlayer-release.js -d=../../doc/jsdoc/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/build/gendoc.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/build/gendoc.sh Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +java -jar ../res/jsdoc/jsrun.jar ../res/jsdoc/app/run.js -a -t=../res/jsdoc/templates/jsdoc/ ../../build/LdtPlayer-release.js -d=../../doc/jsdoc/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/LdtPlayer-release.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/LdtPlayer-release.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,3541 @@ +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +/*! LAB.js (LABjs :: Loading And Blocking JavaScript) + v2.0.3 (c) Kyle Simpson + MIT License +*/ + +(function(global){ + var _$LAB = global.$LAB, + + // constants for the valid keys of the options object + _UseLocalXHR = "UseLocalXHR", + _AlwaysPreserveOrder = "AlwaysPreserveOrder", + _AllowDuplicates = "AllowDuplicates", + _CacheBust = "CacheBust", + /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/ + _BasePath = "BasePath", + + // stateless variables used across all $LAB instances + root_page = /^[^?#]*\//.exec(location.href)[0], + root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0], + append_to = document.head || document.getElementsByTagName("head"), + + // inferences... ick, but still necessary + opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style), + +/*!START_DEBUG*/ + // console.log() and console.error() wrappers + log_msg = function(){}, + log_error = log_msg, +/*!END_DEBUG*/ + + // feature sniffs (yay!) + test_script_elem = document.createElement("script"), + explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29 + real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append? + script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order + + // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers) + xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko + ; + +/*!START_DEBUG*/ + // define console wrapper functions if applicable + if (global.console && global.console.log) { + if (!global.console.error) global.console.error = global.console.log; + log_msg = function(msg) { global.console.log(msg); }; + log_error = function(msg,err) { global.console.error(msg,err); }; + } +/*!END_DEBUG*/ + + // test for function + function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; } + + // test for array + function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; } + + // make script URL absolute/canonical + function canonical_uri(src,base_path) { + var absolute_regex = /^\w+\:\/\//; + + // is `src` is protocol-relative (begins with // or ///), prepend protocol + if (/^\/\/\/?/.test(src)) { + src = location.protocol + src; + } + // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /) + else if (!absolute_regex.test(src) && src.charAt(0) != "/") { + // prepend `base_path`, if any + src = (base_path || "") + src; + } + // make sure to return `src` as absolute + return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src); + } + + // merge `source` into `target` + function merge_objs(source,target) { + for (var k in source) { if (source.hasOwnProperty(k)) { + target[k] = source[k]; // TODO: does this need to be recursive for our purposes? + }} + return target; + } + + // does the chain group have any ready-to-execute scripts? + function check_chain_group_scripts_ready(chain_group) { + var any_scripts_ready = false; + for (var i=0; i 0) { + for (var i=0; i=0;) { + val = queue.shift(); + $L = $L[val.type].apply(null,val.args); + } + return $L; + }, + + // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB + noConflict:function(){ + global.$LAB = _$LAB; + return instanceAPI; + }, + + // create another clean instance of $LAB + sandbox:function(){ + return create_sandbox(); + } + }; + + return instanceAPI; + } + + // create the main instance of $LAB + global.$LAB = create_sandbox(); + + + /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?). + + The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does + proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked + document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready. + For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or + fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs. + */ + (function(addEvent,domLoaded,handler){ + if (document.readyState == null && document[addEvent]){ + document.readyState = "loading"; + document[addEvent](domLoaded,handler = function(){ + document.removeEventListener(domLoaded,handler,false); + document.readyState = "complete"; + },false); + } + })("addEventListener","DOMContentLoaded"); + +})(this);/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function() { + var Renderer = function() {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function(template, context, partials, in_recursion) { + // reset buffer & set context + if(!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if(!this.includes("", template)) { + if(in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + template = this.render_pragmas(template); + var html = this.render_section(template, context, partials); + if(in_recursion) { + return this.render_tags(html, context, partials, in_recursion); + } + + this.render_tags(html, context, partials, in_recursion); + }, + + /* + Sends parsed lines + */ + send: function(line) { + if(line !== "") { + this.buffer.push(line); + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function(template) { + // no pragmas + if(!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + + this.ctag, "g"); + return template.replace(regex, function(match, pragma, options) { + if(!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if(options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function(name, context, partials) { + name = this.trim(name); + if(!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if(typeof(context[name]) != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function(template, context, partials) { + if(!this.includes("#", template) && !this.includes("^", template)) { + return template; + } + + var that = this; + // CSW - Added "+?" so it finds the tighest bound, not the widest + var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag + + "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag + + "\\s*", "mg"); + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function(match, type, name, content) { + var value = that.find(name, context); + if(type == "^") { // inverted section + if(!value || that.is_array(value) && value.length === 0) { + // false or empty list, render it + return that.render(content, context, partials, true); + } else { + return ""; + } + } else if(type == "#") { // normal section + if(that.is_array(value)) { // Enumerable, Let's loop! + return that.map(value, function(row) { + return that.render(content, that.create_context(row), + partials, true); + }).join(""); + } else if(that.is_object(value)) { // Object, Use it as subcontext! + return that.render(content, that.create_context(value), + partials, true); + } else if(typeof value === "function") { + // higher order section + return value.call(context, content, function(text) { + return that.render(text, context, partials, true); + }); + } else if(value) { // boolean section + return that.render(content, context, partials, true); + } else { + return ""; + } + } + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function(template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function() { + return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + + that.ctag + "+", "g"); + }; + + var regex = new_regex(); + var tag_replace_callback = function(match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + return that.find(name, context); + default: // escape the value + return that.escape(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if(!in_recursion) { + this.send(lines[i]); + } + } + + if(in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function(delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function(text) { + // thank you Simon Willison + if(!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function(name, context) { + name = this.trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + if(is_kinda_truthy(context[name])) { + value = context[name]; + } else if(is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + + if(typeof value === "function") { + return value.apply(context); + } + if(value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + // Utility methods + + /* includes tag */ + includes: function(needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + /* + Does away with nasty characters + */ + escape: function(s) { + s = String(s === null ? "" : s); + return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) { + switch(s) { + case "&": return "&"; + case "\\": return "\\\\"; + case '"': return '"'; + case "'": return '''; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); + }, + + // by @langalex, support for arrays of strings + create_context: function(_context) { + if(this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if(this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function(a) { + return a && typeof a == "object"; + }, + + is_array: function(a) { + return Object.prototype.toString.call(a) === '[object Array]'; + }, + + /* + Gets rid of leading and trailing whitespace + */ + trim: function(s) { + return s.replace(/^\s*|\s*$/g, ""); + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function(array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + } + }; + + return({ + name: "mustache.js", + version: "0.3.1-dev", + + /* + Turns a template and view into HTML + */ + to_html: function(template, view, partials, send_fun) { + var renderer = new Renderer(); + if(send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view, partials); + if(!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +// Underscore.js 1.2.3 +// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c, +h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.concat,H=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&& +define.amd?define("underscore",function(){return b}):s._=b;b.VERSION="1.2.3";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g, +c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c, +b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});return e};var D=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a, +d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex= +function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after= +function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a=== +Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)== +"[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){J(c, +b[c]=a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g, +"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b, +a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this); +/* main file */ + +if ( window.IriSP === undefined && window.__IriSP === undefined ) { + var IriSP = {}; + var __IriSP = IriSP; /* for backward compatibility */ +} + +IriSP.loadLibs = function( libs, config, metadata_url, callback ) { + // Localize jQuery variable + IriSP.jQuery = null; + var $L = $LAB.script(libs.jQuery).script(libs.swfObject) + .script(libs.jQueryUI) + + if (config.player.type === "jwplayer") { + // load our popcorn.js lookalike + $L = $L.script(libs.jwplayer); + } else { + // load the real popcorn + $L = $L.script(libs.popcorn).script(libs["popcorn.code"]); + if (config.player.type === "youtube") { + $L = $L.script(libs["popcorn.youtube"]); + } + if (config.player.type === "vimeo") + $L = $L.script(libs["popcorn.vimeo"]); + + /* do nothing for html5 */ + } + + /* widget specific requirements */ + for (var idx in config.gui.widgets) { + if (config.gui.widgets[idx].type === "PolemicWidget") { + $L.script(libs.raphael); + } + } + + // same for modules + /* + for (var idx in config.modules) { + if (config.modules[idx].type === "PolemicWidget") + $L.script(libs.raphaelJs); + } + */ + + $L.wait(function() { + IriSP.jQuery = window.jQuery.noConflict( true ); + IriSP._ = window._.noConflict(); + IriSP.underscore = IriSP._; + + var css_link_jquery = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: libs.cssjQueryUI, + 'class': "dynamic_css" + } ); + var css_link_custom = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: config.gui.css, + 'class': "dynamic_css" + } ); + + css_link_jquery.appendTo('head'); + css_link_custom.appendTo('head'); + + IriSP.setupDataLoader(); + IriSP.__dataloader.get(metadata_url, + function(data) { + /* save the data so that we could re-use it to + configure the video + */ + IriSP.__jsonMetadata = data; + callback.call(window) }); + }); +}; +IriSP.annotation_template = "{{! template for an annotation displayed in a segmentWidget }}
"; +IriSP.annotationWidget_template = "{{! template for the annotation widget }}
share on facebook share on twitter share on google+
"; +IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}
 
Chargement...
"; +IriSP.arrowWidget_template = "
"; +IriSP.overlay_marker_template = "{{! the template for the small bars which is z-indexed over our segment widget }}
"; +IriSP.player_template = "{{! template for the radio player }}
/
"; +IriSP.search_template = "{{! template for the search container }}
"; +IriSP.share_template = "{{! social network sharing template }} "; +IriSP.sliderWidget_template = "{{! template for the slider widget - it's composed of two divs we one overlayed on top of the other }}
"; +IriSP.tooltip_template = "{{! template used by the jquery ui tooltip }}
{{title}}
{{begin}} : {{end}}
{{description}}
"; +IriSP.tooltipWidget_template = "{{! template for the tooltip widget }}
"; +IriSP.tweetWidget_template = "{{! template for the tweet widget }}";/* wrapper that simulates popcorn.js because + popcorn is a bit unstable at the time */ + +IriSP.PopcornReplacement = { + msgPump : {} /* used by jquery to receive and send messages */ +}; + +IriSP.PopcornReplacement.media = { + "paused": true, + "muted": false +}; + +IriSP.PopcornReplacement.listen = function(msg, callback) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).bind(msg, function(event, rest) { callback(rest); }); + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + IriSP.PopcornReplacement.msgPump[msg] = []; + + IriSP.PopcornReplacement.msgPump[msg].push(callback); +}; + +IriSP.PopcornReplacement.trigger = function(msg, params) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).trigger(msg, params); + + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + return; + + var d = IriSP.PopcornReplacement.msgPump[msg]; + for(var entry in d) { + d[entry].call(window, params); + } + +}; + +IriSP.PopcornReplacement.guid = function(prefix) { + var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); + + return prefix + str; +}; + +IriSP.PopcornReplacement.__initApi = function() { + IriSP.PopcornReplacement.trigger("loadedmetadata"); // we've done more than loading metadata of course, + // but popcorn doesn't need to know more. + IriSP.PopcornReplacement.media.muted = jwplayer(IriSP.PopcornReplacement._container).getMute(); +}; + +IriSP.PopcornReplacement.jwplayer = function(container, options) { + IriSP.PopcornReplacement._container = container.slice(1); //eschew the '#' + options.events = { + onReady: IriSP.PopcornReplacement.__initApi, + onTime: IriSP.PopcornReplacement.__timeHandler, + onPlay: IriSP.PopcornReplacement.__playHandler, + onPause: IriSP.PopcornReplacement.__pauseHandler, + onSeek: IriSP.PopcornReplacement.__seekHandler + } + + jwplayer(IriSP.PopcornReplacement._container).setup(options); + IriSP.PopcornReplacement.media.duration = options.duration; + return IriSP.PopcornReplacement; +}; + +IriSP.PopcornReplacement.currentTime = function(time) { + if (typeof(time) === "undefined") { + return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + } else { + var currentTime = +time; + jwplayer( IriSP.PopcornReplacement._container ).seek( currentTime ); + IriSP.PopcornReplacement.trigger("seeked"); + return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + } +}; + +IriSP.PopcornReplacement.play = function() { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +// IriSP.PopcornReplacement.trigger("playing"); + jwplayer( IriSP.PopcornReplacement._container ).play(); +}; + +IriSP.PopcornReplacement.pause = function() { + if ( !IriSP.PopcornReplacement.media.paused ) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger( "pause" ); + jwplayer( IriSP.PopcornReplacement._container ).pause(); + } +}; + +IriSP.PopcornReplacement.muted = function(val) { + if (typeof(val) !== "undefined") { + + if (jwplayer(IriSP.PopcornReplacement._container).getMute() !== val) { + if (val) { + jwplayer(IriSP.PopcornReplacement._container).setMute(true); + IriSP.PopcornReplacement.media.muted = true; + } else { + jwplayer( IriSP.PopcornReplacement._container ).setMute(false); + IriSP.PopcornReplacement.media.muted = false; + } + + IriSP.PopcornReplacement.trigger( "volumechange" ); + } + + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } else { + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } +}; + +IriSP.PopcornReplacement.mute = IriSP.PopcornReplacement.muted; + +IriSP.PopcornReplacement.__codes = []; +IriSP.PopcornReplacement.code = function(options) { + IriSP.PopcornReplacement.__codes.push(options); + return IriSP.PopcornReplacement; +}; + +IriSP.PopcornReplacement.__runCode = function() { + var currentTime = jwplayer(IriSP.PopcornReplacement._container).getPosition(); + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + if (currentTime == c.start) { + c.onStart(); + } + + if (currentTime == c.end) { + c.onEnd(); + } + + } +}; + +/* called everytime the player updates itself + (onTime event) + */ + +IriSP.PopcornReplacement.__timeHandler = function(event) { + var pos = event.position; + + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (pos >= c.start && pos < c.end && + pos - 0.1 <= c.start) { + c.onStart(); + } + + if (pos > c.start && pos > c.end && + pos - 0.1 <= c.end) { + console.log("eonedn"); + c.onEnd(); + } + + } + + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + +IriSP.PopcornReplacement.__seekHandler = function(event) { + var i = 0; + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (event.position >= c.start && event.position < c.end) { + c.onEnd(); + } + } + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (typeof(event.offset) === "undefined") + event.offset = 0; + + if (event.offset >= c.start && event.offset < c.end) { + c.onStart(); + } + + } + + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + + +IriSP.PopcornReplacement.__playHandler = function(event) { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +}; + +IriSP.PopcornReplacement.__pauseHandler = function(event) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger("pause"); +}; + +IriSP.PopcornReplacement.roundTime = function() { + var currentTime = IriSP.PopcornReplacement.currentTime(); + return Math.round(currentTime); +}; +/* utils.js - various utils that don't belong anywhere else */ + +/* trace function, for debugging */ + +IriSP.traceNum = 0; +IriSP.trace = function( msg, value ) { +/* + if( IriSP.config.gui.debug === true ) { + IriSP.traceNum += 1; + IriSP.jQuery( "
"+IriSP.traceNum+" - "+msg+" : "+value+"
" ).appendTo( "#Ldt-output" ); + } +*/ +}; + +/* used in callbacks - because in callbacks we lose "this", + we need to have a special function which wraps "this" in + a closure. This way, the +*/ +IriSP.wrap = function (obj, fn) { + return function() { + var args = Array.prototype.slice.call(arguments, 0); + return fn.apply(obj, args); + } +} + +/* convert a time to a percentage in the media */ +IriSP.timeToPourcent = function(time, timetotal){ + var time = Math.abs(time); + var timetotal = Math.abs(timetotal); + + return Math.floor((time/timetotal) * 100); +}; + +IriSP.padWithZeros = function(num) { + if (Math.abs(num) < 10) { + return "0" + num.toString(); + } else { + return num.toString(); + } +}; +/* convert a number of seconds to a tuple of the form + [hours, minutes, seconds] +*/ +IriSP.secondsToTime = function(secs) { + var hours = Math.abs(parseInt( secs / 3600 ) % 24); + var minutes = Math.abs(parseInt( secs / 60 ) % 60); + var seconds = parseFloat(Math.abs(secs % 60).toFixed(0)); + + var toString_fn = function() { + var ret = ""; + if (hours > 0) + ret = IriSP.padWithZeros(this.hours) + ":"; + ret += IriSP.padWithZeros(this.minutes) + ":" + IriSP.padWithZeros(this.seconds); + + return ret; + } + return {"hours" : hours, "minutes" : minutes, "seconds" : seconds, toString: toString_fn}; +}; + +IriSP.secondsToString + +/* format a tweet - replaces @name by a link to the profile, #hashtag, etc. */ +IriSP.formatTweet = function(tweet) { + /* + an array of arrays which hold a regexp and its replacement. + */ + var regExps = [ + /* copied from http://codegolf.stackexchange.com/questions/464/shortest-url-regex-match-in-javascript/480#480 */ + [/((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/gi, "$1"], + [/@(\w+)/gi, "@$1"], // matches a @handle + [/#(\w+)/gi, "#$1"],// matches a hashtag + [/(\+\+)/gi, "$1"], + [/(--)/gi, "$1"], + [/(==)/gi, "$1"], + [/(\?\?)/gi, "$1"] + ]; + + var i = 0; + for(i = 0; i < regExps.length; i++) { + tweet = tweet.replace(regExps[i][0], regExps[i][1]); + } + + return tweet; +}; + +IriSP.countProperties = function(obj) { + var count = 0; + + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) + ++count; + } + + return count; +}; + +// conversion de couleur Decimal vers HexaDecimal || 000 si fff +IriSP.DEC_HEXA_COLOR = function (dec) { + var hexa='0123456789ABCDEF'; + var hex=''; + var tmp; + while (dec>15){ + tmp = dec-(Math.floor(dec/16))*16; + hex = hexa.charAt(tmp)+hex; + dec = Math.floor(dec/16); + } + hex = hexa.charAt(dec)+hex; + return(hex); +}; + +/* shortcut to have global variables in templates */ +IriSP.templToHTML = function(template, values) { + var params = IriSP.jQuery.extend(IriSP.default_templates_vars, values); + return Mustache.to_html(template, params); +}; + +/* we need to be stricter than encodeURIComponent, + because of twitter +*/ +IriSP.encodeURI = function(str) { + return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28'). + replace(/\)/g, '%29').replace(/\*/g, '%2A'); +} + +IriSP.__guidCounter = 0; +IriSP.guid = function(prefix) { + IriSP.__guidCounter += 1; + return prefix + IriSP.__guidCounter; +}; +/* for ie compatibility +if (Object.prototype.__defineGetter__&&!Object.defineProperty) { + Object.defineProperty=function(obj,prop,desc) { + if ("get" in desc) obj.__defineGetter__(prop,desc.get); + if ("set" in desc) obj.__defineSetter__(prop,desc.set); + } +} +*/ +/* data.js - this file deals with how the players gets and sends data */ + +IriSP.DataLoader = function() { + this._cache = {}; + + /* + A structure to hold callbacks for specific urls. We need it because + ajax calls are asynchronous, so it means that sometimes we ask + multiple times for a ressource because the first call hasn't been + received yet. + */ + this._callbacks = {}; +}; + +IriSP.DataLoader.prototype.get = function(url, callback) { + + var base_url = url.split("&")[0] + if (this._cache.hasOwnProperty(base_url)) { + callback(this._cache[base_url]); + } else { + if (!this._callbacks.hasOwnProperty(base_url)) { + this._callbacks[base_url] = []; + this._callbacks[base_url].push(callback); + /* we need a closure because this gets lost when it's called back */ + + // uncomment you don't want to use caching. + // IriSP.jQuery.get(url, callback); + + var func = function(data) { + this._cache[base_url] = data; + var i = 0; + + for (i = 0; i < this._callbacks[base_url].length; i++) { + this._callbacks[base_url][i](this._cache[base_url]); + } + }; + + /* automagically choose between json and jsonp */ + if (url.indexOf(document.location.hostname) === -1 && + url.indexOf("http://") !== -1 /* not a relative url */ ) { + // we contacting a foreign domain, use JSONP + + IriSP.jQuery.get(url, {}, IriSP.wrap(this, func), "jsonp"); + } else { + + // otherwise, hey, whatever rows your boat + IriSP.jQuery.get(url, IriSP.wrap(this, func)); + } + + } else { + /* simply push the callback - it'll get called when the ressource + has been received */ + + this._callbacks[base_url].push(callback); + + } + } +} + +/* the base abstract "class" */ +IriSP.Serializer = function(DataLoader, url) { + this._DataLoader = DataLoader; + this._url = url; + this._data = []; +}; + +IriSP.Serializer.prototype.serialize = function(data) { }; +IriSP.Serializer.prototype.deserialize = function(data) {}; + +IriSP.Serializer.prototype.currentMedia = function() { +}; + +IriSP.Serializer.prototype.sync = function(callback) { + callback.call(this, this._data); +}; + +IriSP.SerializerFactory = function(DataLoader) { + this._dataloader = DataLoader; +}; + +IriSP.SerializerFactory.prototype.getSerializer = function(metadataOptions) { + /* This function returns serializer set-up with the correct + configuration - takes a metadata struct describing the metadata source + */ + + if (metadataOptions === undefined) + /* return an empty serializer */ + return IriSP.Serializer("", ""); + + switch(metadataOptions.type) { + case "json": + return new IriSP.JSONSerializer(this._dataloader, metadataOptions.src); + break; + + case "dummy": /* only used for unit testing - not defined in production */ + return new IriSP.MockSerializer(this._dataloader, metadataOptions.src); + break; + + case "empty": + return new IriSP.Serializer("", "empty"); + break; + + default: + return undefined; + } +}; +/* site.js - all our site-dependent config : player chrome, cdn locations, etc...*/ + +IriSP.lib = { + jQuery : "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js", + jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js", + jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js", + swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", + cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css", + popcorn : "/mdp/src/js/libs/popcorn.js", + jwplayer : "/mdp/src/js/libs/jwplayer.js", + popcornReplacement: "/mdp/src/js/libs/pop.js", + raphael: "/mdp/src/js/libs/raphael.js", + "popcorn.mediafragment" : "/mdp/src/js/libs/popcorn.mediafragment.js", + "popcorn.code" : "/mdp/src/js/libs/popcorn.code.js", + "popcorn.jwplayer": "/mdp/src/js/libs/popcorn.jwplayer.js", + "popcorn.youtube": "/mdp/src/js/libs/popcorn.youtube.js" +}; + +//Player Configuration +IriSP.config = undefined; + +IriSP.widgetsDefaults = { + "LayoutManager" : {spacer_div_height : "0px" }, + "PlayerWidget" : {}, + "AnnotationsWidget": { + "share_text" : "I'm watching ", + "fb_link" : "http://www.facebook.com/share.php?u=", + "tw_link" : "http://twitter.com/home?status=", + "gplus_link" : "" + }, + "TweetsWidget" : { + default_profile_picture : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png", + tweet_display_period: 10000 // how long do we show a tweet ? + }, + "SliderWidget" : { + minimize_period: 850 // how long does the slider stays maximized after the user leaves the zone ? + }, + "Main" : { + autoplay: true + } + +}; + +IriSP.paths = { +// "imgs": "/tweetlive/res/metadataplayer/src/css/imgs" + "imgs": "/mdp/src/css/imgs" +}; +IriSP.default_templates_vars = { + "img_dir" : IriSP.paths.imgs +}; + +/* ui.js - ui related functions */ + +/* FIXME: use an sharing library */ +IriSP.LdtShareTool = IriSP.share_template; /* the contents come from share.html */ + +IriSP.createPlayerChrome = function(){ + var width = IriSP.config.gui.width; + var height = IriSP.config.gui.height; + var heightS = IriSP.config.gui.height-20; + + // AUDIO */ + // PB dans le html : ; + IriSP.trace( "__IriSP.createMyHtml",IriSP.config.gui.container ); + + + /* FIXME : factor this in another file */ + if( IriSP.config.gui.mode=="radio" ){ + + IriSP.jQuery( "#"+IriSP.config.gui.container ).before(IriSP.search_template); + var radioPlayer = Mustache.to_html(IriSP.radio_template, {"share_template" : IriSP.share_template}); + IriSP.jQuery(radioPlayer).appendTo("#"+IriSP.config.gui.container); + + // special tricks for IE 7 + if (IriSP.jQuery.browser.msie==true && IriSP.jQuery.browser.version=="7.0"){ + //LdtSearchContainer + //__IriSP.jQuery("#LdtPlayer").attr("margin-top","50px"); + IriSP.jQuery("#Ldt-Root").css("padding-top","25px"); + IriSP.trace("__IriSP.createHtml","IE7 SPECIAL "); + } + } else if(IriSP.config.gui.mode=="video") { + + var videoPlayer = Mustache.to_html(IriSP.video_template, {"share_template" : IriSP.share_template, "heightS" : heightS}); + IriSP.jQuery(videoPlayer).appendTo("#"+IriSP.config.gui.container); + } + + IriSP.jQuery("#Ldt-Annotations").width(width-(75*2)); + IriSP.jQuery("#Ldt-Show-Arrow-container").width(width-(75*2)); + IriSP.jQuery("#Ldt-ShowAnnotation-audio").width(width-10); + IriSP.jQuery("#Ldt-ShowAnnotation-video").width(width-10); + IriSP.jQuery("#Ldt-SaKeyword").width(width-10); + IriSP.jQuery("#Ldt-controler").width(width-10); + IriSP.jQuery("#Ldt-Control").attr("z-index","100"); + IriSP.jQuery("#Ldt-controler").hide(); + + IriSP.jQuery(IriSP.annotation_loading_template).appendTo("#Ldt-ShowAnnotation-audio"); + + if(IriSP.config.gui.mode=='radio'){ + IriSP.jQuery("#Ldt-load-container").attr("width",IriSP.config.gui.width); + } + // Show or not the output + if(IriSP.config.gui.debug===true){ + IriSP.jQuery("#Ldt-output").show(); + } else { + IriSP.jQuery("#Ldt-output").hide(); + } + +}; + + +/* create the buttons and the slider */ +IriSP.createInterface = function( width, height, duration ) { + + IriSP.jQuery( "#Ldt-controler" ).show(); + //__IriSP.jQuery("#Ldt-Root").css('display','visible'); + IriSP.trace( "__IriSP.createInterface" , width+","+height+","+duration+"," ); + + IriSP.jQuery( "#Ldt-ShowAnnotation").click( function () { + //__IriSP.jQuery(this).slideUp(); + } ); + + var LdtpPlayerY = IriSP.jQuery("#Ldt-PlaceHolder").attr("top"); + var LdtpPlayerX = IriSP.jQuery("#Ldt-PlaceHolder").attr("left"); + + IriSP.jQuery( "#slider-range-min" ).slider( { //range: "min", + value: 0, + min: 1, + max: duration/1000,//1:54:52.66 = 3600+3240+ + step: 0.1, + slide: function(event, ui) { + + //__IriSP.jQuery("#amount").val(ui.value+" s"); + //player.sendEvent('SEEK', ui.value) + IriSP.MyApiPlayer.seek(ui.value); + //changePageUrlOffset(ui.value); + //player.sendEvent('PAUSE') + } + } ); + + IriSP.trace("__IriSP.createInterface","ICI"); + IriSP.jQuery("#amount").val(IriSP.jQuery("#slider-range-min").slider("value")+" s"); + IriSP.jQuery(".Ldt-Control1 button:first").button({ + icons: { + primary: 'ui-icon-play' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-seek-next' + }, + text: false + }); + IriSP.jQuery(".Ldt-Control2 button:first").button({ + icons: { + primary: 'ui-icon-search'//, + //secondary: 'ui-icon-volume-off' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-volume-on' + }, + text: false + }); + + // /!\ PB A MODIFIER + //__IriSP.MyTags.draw(); + IriSP.trace("__IriSP.createInterface","ICI2"); + IriSP.jQuery( "#ldt-CtrlPlay" ).attr( "style", "background-color:#CD21C24;" ); + + IriSP.jQuery( "#Ldt-load-container" ).hide(); + + if( IriSP.config.gui.mode=="radio" & IriSP.jQuery.browser.msie != true ) { + IriSP.jQuery( "#Ldtplayer1" ).attr( "height", "0" ); + } + IriSP.trace( "__IriSP.createInterface" , "3" ); + + IriSP.trace( "__IriSP.createInterface", "END" ); + + }; +/* the widget classes and definitions */ + +IriSP.Widget = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; + + if (config.hasOwnProperty("container")) { + this._id = config.container; + this.selector = IriSP.jQuery("#" + this._id); + } + + if (config.hasOwnProperty("spacer")) { + this._spacerId = config.spacer; + this.spacer = IriSP.jQuery("#" + this._spacerId); + } + + + if (config.hasOwnProperty("width")) { + // this.width and not this._width because we consider it public. + this.width = config.width; + } + + if (config.hasOwnProperty("height")) { + this.height = config.height; + } + + if (config.hasOwnProperty("heightmax")) { + this.heightmax = config.heightmax; + } + + if (config.hasOwnProperty("widthmax")) { + this.widthmax = config.widthmax; + } + +}; + +IriSP.Widget.prototype.draw = function() { + /* implemented by "sub-classes" */ +}; + +IriSP.Widget.prototype.redraw = function() { + /* implemented by "sub-classes" */ +}; +/* modules are non-graphical entities, similar to widgets */ + +IriSP.Module = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; +}; +/* layout.js - very basic layout management */ + +/* + a layout manager manages a div and the layout of objects + inside it. +*/ + +IriSP.LayoutManager = function(options) { + this._Popcorn = null; + this._widgets = []; + + this._div = "LdtPlayer"; + this._width = 640; + + if (options === undefined) { + options = {}; + }; + + if (options.hasOwnProperty('container')) { + this._div = options.container; + } + + if (options.hasOwnProperty('width')) { + this._width = options.width; + } + + if (options.hasOwnProperty('height')) { + this._height = options.height; + } + + /* this is a shortcut */ + this.selector = IriSP.jQuery("#" + this._div); + + this.selector.css("width", this._width); + + if (this._height !== undefined) + this.selector.css("height", this._height); +}; + +/* we need this special setter because of a chicken and egg problem : + we want the manager to use popcorn but the popcorn div will be managed + by the manager. So we need a way to set the instance the manager uses +*/ + +IriSP.LayoutManager.prototype.setPopcornInstance = function(popcorn) { + this._Popcorn = popcorn; +} + +/* stem is a string to append to the id of the widget */ +IriSP.LayoutManager.prototype.createDiv = function(stem) { + if (typeof(stem) === "undefined") + stem = ""; + + var newDiv = IriSP.guid(this._div + "_widget_" + stem + "_"); + var spacerDiv = IriSP.guid("LdtPlayer_spacer_"); + this._widgets.push(newDiv); + + var divTempl = "
"); + + if (options.hasOwnProperty("width")) + IriSP.jQuery("#" + containerDiv).css("width", options.width); + + if (options.hasOwnProperty("height")) + IriSP.jQuery("#" + containerDiv).css("height", options.height); + + pop = Popcorn("#" + tmpId); + break; + + case "jwplayer": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + + if (options.provider === "rtmp") { + /* exit if we can't access the metadata */ + if (typeof(IriSP.__jsonMetadata) === "undefined") { + break; + }; + + + // the json format is totally illogical + opts.streamer = IriSP.__jsonMetadata["medias"][0]["meta"]["item"]["value"]; + var source = IriSP.__jsonMetadata["medias"][0]["href"]; + + // the source if a full url but jwplayer wants an url relative to the + // streamer url, so we've got to remove the common part. + opts.file = source.slice(opts.streamer.length); + } else { + /* other providers type, video for instance - + pass everything as is */ + } + + pop = IriSP.PopcornReplacement.jwplayer("#" + containerDiv, opts); + break; + + case "youtube": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + opts.controls = 0; + opts.autostart = false; + templ = "width: {{width}}px; height: {{height}}px;"; + var str = Mustache.to_html(templ, {width: opts.width, height: opts.height}); + // Popcorn.youtube wants us to specify the size of the player in the style attribute of its container div. + IriSP.jQuery("#" + containerDiv).attr("style", str); + + pop = Popcorn.youtube("#" + containerDiv, opts.video, opts); + break; + + default: + pop = undefined; + }; + + return pop; +}; + +IriSP.configureWidgets = function (popcornInstance, layoutManager, guiOptions) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var params = {width: guiOptions.width, height: guiOptions.height}; + + var ret_widgets = []; + var index; + + for (index = 0; index < guiOptions.widgets.length; index++) { + var widgetConfig = guiOptions.widgets[index]; + var widget = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig); + ret_widgets.push(widget); + + }; + + return ret_widgets; +}; + +IriSP.configureModules = function (popcornInstance, modulesList) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var ret_modules = []; + var index; + + for (index = 0; index < modulesList.length; index++) { + var moduleConfig = modulesList[index]; + + var serializer = serialFactory.getSerializer(moduleConfig.metadata); + var module = new IriSP[moduleConfig.type](popcornInstance, moduleConfig, serializer); + ret_modules.push(module); + }; + + return ret_modules; +}; + +IriSP.instantiateWidget = function(popcornInstance, serialFactory, layoutManager, widgetConfig) { + /* create div returns us a container for the widget and a spacer */ + var ret = layoutManager.createDiv(widgetConfig.type); + var container = ret[0]; + var spacer = ret[1]; + + var arr = IriSP.jQuery.extend({}, widgetConfig); + arr.container = container; + arr.spacer = spacer; + + var serializer = serialFactory.getSerializer(widgetConfig.metadata); + + if (typeof serializer == "undefined") + debugger; + + // instantiate the object passed as a string + var widget = new IriSP[widgetConfig.type](popcornInstance, arr, serializer); + + if (widgetConfig.hasOwnProperty("requires")) { + // also create the widgets this one depends on. + // the dependency widget is available in the parent widget context as + // this.WidgetName (for instance, this.TipWidget); + + var i = 0; + for(i = 0; i < widgetConfig.requires.length; i++) { + var widgetName = widgetConfig.requires[i]["type"]; + widget[widgetName] = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig.requires[i]); + } + } + + serializer.sync(IriSP.wrap(widget, function() { this.draw(); })); + return widget; +}; +/* mediafragment module */ + +IriSP.MediaFragment = function(Popcorn, config, Serializer) { + IriSP.Module.call(this, Popcorn, config, Serializer); + + this.mutex = false; /* a mutex because we access the url from two different functions */ + + this._Popcorn.listen( "loadedmetadata", IriSP.wrap(this, IriSP.MediaFragment.advanceTime)); + this._Popcorn.listen( "pause", IriSP.wrap(this, IriSP.MediaFragment.updateTime)); + this._Popcorn.listen( "seeked", IriSP.wrap(this, IriSP.MediaFragment.updateTime)); + this._Popcorn.listen( "IriSP.PolemicTweet.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation)); + this._Popcorn.listen( "IriSP.SegmentsWidget.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation)); +}; + +IriSP.MediaFragment.advanceTime = function() { + var url = window.location.href; + + if ( url.split( "#" )[ 1 ] != null ) { + pageoffset = url.split( "#" )[1]; + + if ( pageoffset.substring(0, 2) === "t=") { + // timecode + if ( pageoffset.substring( 2 ) != null ) { + var offsettime = pageoffset.substring( 2 ); + this._Popcorn.currentTime( parseFloat( offsettime ) ); + } + } else if ( pageoffset.substring(0, 2) === "a=") { + // annotation + var annotationId = pageoffset.substring( 2 ); + + // there's no better way than that because + // of possible race conditions + this._serializer.sync(IriSP.wrap(this, function() { + IriSP.MediaFragment.lookupAnnotation.call(this, annotationId); + })); + } + } +}; + +IriSP.MediaFragment.updateTime = function() { + if (this.mutex === true) { + return; + } + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#t=" + this._Popcorn.currentTime().toFixed( 2 ) ); +}; + + +IriSP.MediaFragment.updateAnnotation = function(annotationId) { + var _this = this; + this.mutex = true; + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#a=" + annotationId); + + window.setTimeout(function() { _this.mutex = false }, 50); +}; + +// lookup and seek to the beginning of an annotation +IriSP.MediaFragment.lookupAnnotation = function(annotationId) { + var annotation = undefined; + var annotations = this._serializer._data.annotations; + + var i; + for (i = 0; i < annotations.length; i++) { + if (annotations[i].id === annotationId) { + annotation = annotations[i]; + break; + } + } + + if (typeof(annotation) !== "undefined") { + this._Popcorn.currentTime(annotation.begin / 1000); + } +}; +IriSP.AnnotationsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + +}; + + +IriSP.AnnotationsWidget.prototype = new IriSP.Widget(); + +IriSP.AnnotationsWidget.prototype.clear = function() { + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").text(""); +}; + +IriSP.AnnotationsWidget.prototype.displayAnnotation = function(annotation) { + + var title = annotation.content.title; + var description = annotation.content.description; + var keywords = "" // FIXME; + var begin = +annotation.begin / 1000; + var end = +annotation.end / 1000; + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + var title_templ = "{{title}} - ( {{begin}} - {{end}} )"; + var endstr = Mustache.to_html(title_templ, {title: title, begin: IriSP.secondsToTime(begin), end: IriSP.secondsToTime(end)}); + + this.selector.find(".Ldt-SaTitle").text(endstr); + this.selector.find(".Ldt-SaDescription").text(description); + + // update sharing buttons + var defaults = IriSP.widgetsDefaults.AnnotationsWidget; + var text = defaults.share_text; + var fb_link = defaults.fb_link; + var tw_link = defaults.tw_link; + var gplus_link = defaults.gplus_link; + var url = document.location.href + "#a=" + annotation.id; + this.selector.find(".Ldt-fbShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-TwShare").attr("href", tw_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-GplusShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); +}; + +IriSP.AnnotationsWidget.prototype.clearWidget = function() { + + + /* retract the pane between two annotations */ + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").html(""); + this.selector.find(".Ldt-ShowAnnotation").slideUp(); +}; + +IriSP.AnnotationsWidget.prototype.draw = function() { + var _this = this; + + var annotationMarkup = IriSP.templToHTML(IriSP.annotationWidget_template); + this.selector.append(annotationMarkup); + var view; + + if (typeof(this._serializer._data.views) !== "undefined" && this._serializer._data.views !== null) + view = this._serializer._data.views[0]; + + var view_type = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + view_type = view.annotation_types[0]; + } + + var annotations = this._serializer._data.annotations; + var i; + + for (i in annotations) { + var annotation = annotations[i]; + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + + if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + + var conf = {start: begin, end: end, + onStart: + function(annotation) { + return function() { + _this.displayAnnotation(annotation); + + } }(annotation), + onEnd: + function() { _this.clearWidget.call(_this); } + }; + this._Popcorn = this._Popcorn.code(conf); + } + +}; +IriSP.ArrowWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._oldAnnotation = null; + +}; + + +IriSP.ArrowWidget.prototype = new IriSP.Widget(); + +IriSP.ArrowWidget.prototype.clear = function() { + +}; + +IriSP.ArrowWidget.prototype.clearWidget = function() { +}; + +IriSP.ArrowWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.arrowWidget_template, {}); + this.selector.append(templ); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler)); +}; + +IriSP.ArrowWidget.prototype.timeUpdateHandler = function(percents) { + var currentTime = this._Popcorn.currentTime(); + var currentAnnotation = this._serializer.currentAnnotations(currentTime)[0]; // FIXME : use the others ? + + /* move the arrow only if the current annotation changes */ + if (currentAnnotation != this._oldAnnotation) { + var begin = (+ currentAnnotation.begin) / 1000; + var end = (+ currentAnnotation.end) / 1000; + + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var middle_time = (begin + end) / 2; + var percents = Math.floor((middle_time / duration) * 100); + + // we need to apply a fix because the arrow has a certain length + // it's half the length of the arrow (27 / 2). We need to convert + // it in percents though. + var totalWidth = this.selector.width(); + var correction = ((27 / 2) / totalWidth) * 100; + var corrected_percents = percents - correction; + + /* don't move out of the screen */ + if (corrected_percents <= 0) + corrected_percents = 0; + + this.selector.children(".Ldt-arrowWidget").animate({"left" : corrected_percents + "%"}); + + this._oldAnnotation = currentAnnotation; + } +} +IriSP.PlayerWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._searchBlockOpen = false; + this._searchLastValue = ""; +}; + +IriSP.PlayerWidget.prototype = new IriSP.Widget(); + +IriSP.PlayerWidget.prototype.draw = function() { + var self = this; + var width = this.width; + var height = this.height; + var heightS = this.height-20; + + var Player_templ = Mustache.to_html(IriSP.player_template, {"share_template" : IriSP.share_template}); + this.selector.append(Player_templ); + + this.selector.children(".Ldt-controler").show(); + + // handle clicks by the user on the video. + this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater)); + this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater)); + + this._Popcorn.listen("volumechange", IriSP.wrap(this, this.muteButtonUpdater)); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater)); + this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch)); + this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch)); + + + this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); }); + this.selector.find(".Ldt-CtrlNext").click(function() { }); + this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); }); + + this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } ); + + this.selector.find(".Ldt-CtrlPlay").attr( "style", "background-color:#CD21C24;" ); + + var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position(); + var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"}); + this.selector.append(searchBox); + + // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget) + this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, + function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); }); + + this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */ +}; + +/* Update the elasped time div */ +IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() { + + if (this._previousSecond === undefined) + this._previousSecond = this._Popcorn.roundTime(); + + else { + /* we're still in the same second, so it's not necessary to update time */ + if (this._Popcorn.roundTime() == this._previousSecond) + return; + + } + + // we get it at each call because it may change. + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var totalTime = IriSP.secondsToTime(duration); + var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime()); + + this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString()); + this.selector.find(".Ldt-TotalTime").html(totalTime.toString()); + this._previousSecond = this._Popcorn.roundTime(); +}; + +/* update the icon of the button - separate function from playHandler + because in some cases (for instance, when the user directly clicks on + the jwplayer window) we have to change the icon without playing/pausing +*/ +IriSP.PlayerWidget.prototype.playButtonUpdater = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlPlay").attr("title", "Play"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/play_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlPlay").attr("title", "Pause"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/pause_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.playHandler = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this._Popcorn.play(); + } else { + this._Popcorn.pause(); + } +}; + +IriSP.PlayerWidget.prototype.muteHandler = function() { + if (!this._Popcorn.muted()) { + this._Popcorn.mute(true); + } else { + this._Popcorn.mute(false); + } +}; + +IriSP.PlayerWidget.prototype.muteButtonUpdater = function() { + var status = this._Popcorn.media.muted; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlSound").attr("title", "Unmute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/sound_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlSound").attr("title", "Mute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/mute_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.searchButtonHandler = function() { + var self = this; + + /* show the search field if it is not shown */ + if ( this._searchBlockOpen == false ) { + this.selector.find(".LdtSearch").show(100); + + this.selector.find(".LdtSearchInput").css('background-color','#fff'); + this.selector.find(".LdtSearchInput").focus(); + this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue); + this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural. + + this._searchBlockOpen = true; + this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } ); + + // we need this variable because some widget can find a match in + // their data while at the same time other's don't. As we want the + // search field to become green when there's a match, we need a + // variable to remember that we had one. + this._positiveMatch = false; + + // tell the world the field is open + this._Popcorn.trigger("IriSP.search.open"); + + } else { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this.selector.find(".LdtSearchInput").attr('value',''); + this.selector.find(".LdtSearch").hide(100); + + // unbind the watcher event. + this.selector.find(".LdtSearchInput").unbind('keypress set'); + this._searchBlockOpen = false; + + this._positiveMatch = false; + + this._Popcorn.trigger("IriSP.search.closed"); + } +}; + +/* this handler is called whenever the content of the search + field changes */ +IriSP.PlayerWidget.prototype.searchHandler = function() { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this._positiveMatch = false; + + // do nothing if the search field is empty, instead of highlighting everything. + if (this._searchLastValue == "") { + this._Popcorn.trigger("IriSP.search.cleared"); + this.selector.find(".LdtSearchInput").css('background-color',''); + } else { + this._Popcorn.trigger("IriSP.search", this._searchLastValue); + } +}; + +/* + handler for the IriSP.search.found message, which is sent by some views when they + highlight a match. +*/ +IriSP.PlayerWidget.prototype.searchMatch = function() { + this._positiveMatch = true; + this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1'); +} + +/* the same, except that no value could be found */ +IriSP.PlayerWidget.prototype.searchNoMatch = function() { + if (this._positiveMatch !== true) + this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a"); +} + +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +// CHART TIMELINE / VERSION PROTOTYPE :: + +IriSP.PolemicWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this.userPol = new Array(); + this.userNoPol = new Array(); + this.userst = new Array(); + this.numberOfTweet = 0; + this.Users; + this.TweetPolemic; + this.yMax = this.height; + this.PaperSlider; + this.heightOfChart; + this.tweets = new Array(); + this.svgElements = {}; + + // Make and define the Raphael area + this.paper = Raphael(document.getElementById(this._id), config.width, config.height); + + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); })); + this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler)); + this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler)); + +}; + +IriSP.PolemicWidget.prototype = new IriSP.Widget(); + +IriSP.PolemicWidget.prototype.draw = function() { + + // variable + // yMax + + var self = this; + var yCoef = 2; // coef for height of 1 tweet + var frameSize = 5; // frame size + var margin = 1; // marge between frame + var lineSize = this.width; // timeline pixel width + var nbrframes = lineSize/frameSize; // frame numbers + var numberOfTweet = 0; // number of tweet overide later + var duration = +this._serializer.currentMedia().meta["dc:duration"]; // timescale width + var frameLength = lineSize / frameSize; // frame timescale + var timeline; + var colors = new Array("","#1D973D","#C5A62D","#CE0A15","#036AAE","#585858"); + + // array + //var tweets = new Array(); + var element = new Array(); + var cluster = new Array(); + var frames = new Array(frameLength); + var slices = new Array(); + + + // Classes ======================================================================= + var Frames = function(){ + + var Myclusters; + var x; + var y; + var width; + var height; + }; + Frames = function(json){ + // make my clusters + // ou Frame vide + }; + Frames.prototype.draw = function(){ + }; + Frames.prototype.zoom = function(){ + }; + Frames.prototype.inside = function(){ + }; + var Clusters = function(){ + var Object; + var yDist; + var x; + var y; + var width; + var height; + }; + Clusters = function(json){ + // make my object + }; + var Tweet = function(){ + }; + // Classes ======================================================================= + + // Refactoring (parametere) ************************************************************ + // color translastion + var qTweet_0 =0; + var qTweet_Q =0; + var qTweet_REF=0; + var qTweet_OK =0; + var qTweet_KO =0; + function colorTranslation(value){ + if(value == "Q"){ + qTweet_Q+=1; + return 2; + }else if(value =="REF"){ + qTweet_REF+=1; + return 4; + }else if(value =="OK"){ + qTweet_OK+=1; + return 1; + }else if(value =="KO"){ + qTweet_KO+=1; + return 3; + }else if(value ==""){ + qTweet_0+=1; + return 5; + } + } + + + this._serializer.sync(function(data) { loaded_callback.call(self, data) }); + + function loaded_callback (json) { + + // get current view (the first ???) + view = json.views[0]; + + // the tweets are by definition of the second annotation type FIXME ? + tweet_annot_type = null; + if(typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + tweet_annot_type = view.annotation_types[1]; + } + + for(var i = 0; i < json.annotations.length; i++) { + var item = json.annotations[i]; + var MyTime = Math.floor(item.begin/duration*lineSize); + var Myframe = Math.floor(MyTime/lineSize*frameLength); + + if (typeof(item.meta) !== "undefined" + && typeof(item.meta["id-ref"]) !== "undefined" + && item.meta["id-ref"] === tweet_annot_type) { + + var MyTJson = JSON.parse(item.meta['dc:source']['content']); + + if (item.content['polemics'] != undefined + && item.content['polemics'][0] != null) { + + // a tweet can have many polemics at the same time. + for(var j=0; j max) { + max = moy; + } + } + + var tweetDrawed = new Array(); + var TweetHeight = 5; + + // DRAW TWEETS ============================================ + for(var i = 0; i < nbrframes; i++) { + var addEheight = 5; + if (frames[i] != undefined){ + // by type + + for (var j = 6; j > -1; j--) { + if (frames[i].qualifVol[j] != undefined) { + // show tweet by type + for (var k = 0; k < frames[i].mytweetsID.length; k++) { + + if (frames[i].mytweetsID[k].qualification == j) { + var x = i * frameSize; + var y = this.heightmax - addEheight; + + if (this.yMax > y) { + this.yMax = y; + } + + var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */) + .attr({stroke:"#00","stroke-width":0.1, fill: colors[j]}); + + addEheight += TweetHeight; + + e.color = colors[j]; + e.time = frames[i].mytweetsID[k].timeframe; + e.title = frames[i].mytweetsID[k].title; + e.id = frames[i].mytweetsID[k].cinecast_id; + + this.svgElements[e.id] = e; + + /* + e.mouseover(function(element) { return function (event) { + // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. + self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.clientX - 106, event.clientY - 160); + element.displayed = true; + }}(e)).mouseout(function(element) { return function () { + self.TooltipWidget.hide.call(self.TooltipWidget); + }}(e)).mousedown(function () { + self._Popcorn.currentTime(this.time/1000); + self._Popcorn.trigger("IriSP.PolemicTweet.click", this.id); + }); + */ + + IriSP.jQuery(e.node).mouseenter(function(element) { return function (event) { + // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. + self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.pageX - 106, event.pageY - 160); + element.displayed = true; + }}(e)).mousedown(function(element) { return function () { + self._Popcorn.currentTime(element.time/1000); + self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); + } + }(e)); + + IriSP.jQuery(e.node).attr('id', 't' + k + ''); + IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title); + IriSP.jQuery(e.node).attr('begin', frames[i].mytweetsID[k].timeframe); + } + } + } + } + } + + } + // DRAW UI :: resize border and bgd + this.paperBackground = this.paper.rect(0, 0, this.width, this.heightmax).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1}); + + // outer borders + this.outerBorders = []; + this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + + // inner borders + this.innerBorders = []; + this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8})); + this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1})); + + + + this.paperSlider = this.paper.rect(0, 0, 0, this.heightmax).attr({fill:"#D4D5D5", stroke: "none", opacity: 1}); + + // the small white line displayed over the slider. + this.sliderTip = this.paper.rect(0, 0, 1, this.heightmax).attr({fill:"#fc00ff", stroke: "none", opacity: 1}); + // decalage + // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1}); + + + this.paperSlider.toBack(); + this.paperBackground.toBack(); + this.sliderTip.toFront(); + } + + this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); })); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); +} + +IriSP.PolemicWidget.prototype.sliderUpdater = function() { + + var time = +this._Popcorn.currentTime(); + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + this.paperSlider.attr("width", time * (this.width / (duration / 1000))); + + this.sliderTip.attr("x", time * (this.width / (duration / 1000))); +}; + +IriSP.PolemicWidget.prototype.searchHandler = function(searchString) { + if (searchString == "") + return; + + var matches = this._serializer.searchTweetsOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + for (var id in matches) { + if (this.svgElements.hasOwnProperty(id)) { + var e = this.svgElements[id]; + this.svgElements[id].attr({fill: "#fc00ff"}); + } + } + + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + if (!matches.hasOwnProperty(id)) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + } + + this.oldSearchMatches = matches; +}; + +IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; + +IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; + +IriSP.SegmentsWidget = function(Popcorn, config, Serializer) { + + var self = this; + IriSP.Widget.call(this, Popcorn, config, Serializer); + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", function(searchString) { self.searchHandler.call(self, searchString); }); + this._Popcorn.listen("IriSP.search.closed", function() { self.searchFieldClosedHandler.call(self); }); + this._Popcorn.listen("IriSP.search.cleared", function() { self.searchFieldClearedHandler.call(self); }); +}; + +IriSP.SegmentsWidget.prototype = new IriSP.Widget(); + +/* Get the width of a segment, in pixels. */ +IriSP.SegmentsWidget.prototype.segmentToPixel = function(annotation) { + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + + var startPourcent = IriSP.timeToPourcent(begin, duration); + var startPixel = Math.floor(this.selector.parent().width() * (startPourcent / 100)); + + var endPourcent = Math.floor(IriSP.timeToPourcent(end, duration) - startPourcent); + var endPixel = Math.floor(this.selector.parent().width() * (endPourcent / 100)); + + return endPixel; +}; + +/* compute the total length of a group of segments */ +IriSP.SegmentsWidget.prototype.segmentsLength = function(segmentsList) { + var self = this; + var total = 0; + + for (var i = 0; i < segmentsList.length; i++) + total += self.segmentToPixel(segmentsList[i].annotation); + + return total; +}; + +IriSP.SegmentsWidget.prototype.draw = function() { + + var self = this; + var annotations = this._serializer._data.annotations; + + this.selector.addClass("Ldt-SegmentsWidget"); + this.selector.append(Mustache.to_html(IriSP.overlay_marker_template)); + + var view_type = this._serializer.getNonTweetIds()[0]; + + this.positionMarker = this.selector.children(":first"); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.positionUpdater)); + + + var i = 0; + + var segments_annotations = []; + + for (i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + segments_annotations.push(annotation); + } + + var totalWidth = this.selector.width() - segments_annotations.length; + var lastSegment = IriSP.underscore.max(segments_annotations, function(annotation) { return annotation.end; }); + + for (i = 0; i < segments_annotations.length; i++) { + + var annotation = segments_annotations[i]; + var begin = (+ annotation.begin); + var end = (+ annotation.end); + var duration = this._serializer.currentMedia().meta["dc:duration"]; + var id = annotation.id; + + var startPixel = Math.floor(this.selector.parent().width() * (begin / duration)); + + var endPixel = Math.floor(this.selector.parent().width() * (end / duration)); + + if (annotation.id !== lastSegment.id) + var pxWidth = endPixel - startPixel -1; + else + /* the last segment has no segment following it */ + var pxWidth = endPixel - startPixel; + + var divTitle = (annotation.content.title + " - " + annotation.content.description).substr(0,55); + + if (typeof(annotation.content.color) !== "undefined") + var color = annotation.content.color; + else + var color = annotation.color; + + var hexa_color = IriSP.DEC_HEXA_COLOR(color); + + if (hexa_color === "FFCC00") + hexa_color = "333"; + if (hexa_color.length == 4) + hexa_color = hexa_color + '00'; + + var annotationTemplate = Mustache.to_html(IriSP.annotation_template, + {"divTitle" : divTitle, "id" : id, "startPixel" : startPixel, + "pxWidth" : pxWidth, "hexa_color" : hexa_color, + "seekPlace" : Math.round(begin/1000)}); + + + this.selector.append(annotationTemplate); + + /* add a special class to the last segment and change its border */ + if (annotation.id === lastSegment.id) { + this.selector.find("#" + id).addClass("Ldt-lastSegment"); + this.selector.find(".Ldt-lastSegment").css("border-color", "#" + hexa_color); + } + + IriSP.jQuery("#" + id).fadeTo(0, 0.3); + + IriSP.jQuery("#" + id).mouseover( + /* we wrap the handler in another function because js's scoping + rules are function-based - otherwise, the internal vars like + divTitle are preserved but they are looked-up from the draw + method scope, so after that the loop is run, so they're not + preserved */ + (function(divTitle) { + return function(event) { + IriSP.jQuery(this).animate({opacity: 0.6}, 5); + var offset = IriSP.jQuery(this).offset(); + var correction = IriSP.jQuery(this).outerWidth() / 2; + + var offset_x = offset.left + correction - 106; + if (offset_x < 0) + offset_x = 0; + + self.TooltipWidget.show(divTitle, color, offset_x, event.pageY - 160); + } })(divTitle)).mouseout(function(){ + IriSP.jQuery(this).animate({opacity: 0.3}, 5); + self.TooltipWidget.hide(); + }); + + IriSP.jQuery("#" + id).click(function(_this, annotation) { + return function() { _this.clickHandler(annotation)}; + }(this, annotation)); + } +}; + +/* restores the view after a search */ +IriSP.SegmentsWidget.prototype.clear = function() { + this.selector.children(".Ldt-iri-chapter").animate({opacity:0.3}, 100); +}; + +IriSP.SegmentsWidget.prototype.clickHandler = function(annotation) { + this._Popcorn.trigger("IriSP.SegmentsWidget.click", annotation.id); + var begin = (+ annotation.begin) / 1000; + this._Popcorn.currentTime(Math.round(begin)); +}; + +IriSP.SegmentsWidget.prototype.searchHandler = function(searchString) { + + if (searchString == "") + return; + + var matches = this._serializer.searchOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + // un-highlight all the blocks + this.selector.children(".Ldt-iri-chapter").css("opacity", 0.1); + + // then highlight the ones with matches. + for (var id in matches) { + var factor = 0.5 + matches[id] * 0.2; + this.selector.find("#"+id).dequeue(); + this.selector.find("#"+id).animate({opacity:factor}, 200); + } + + + this.oldSearchMatches = matches; +}; + +IriSP.SegmentsWidget.prototype.searchFieldClearedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.searchFieldClosedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.positionUpdater = function() { + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var time = this._Popcorn.currentTime(); + //var position = ((time / duration) * 100).toFixed(2); + var position = ((time / duration) * 100).toFixed(2); + + this.positionMarker.css("left", position + "%"); +}; +IriSP.SliderWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); +}; + +IriSP.SliderWidget.prototype = new IriSP.Widget(); + +IriSP.SliderWidget.prototype.draw = function() { + var self = this; + + this.selector.append(Mustache.to_html(IriSP.sliderWidget_template, {})); + this.selector.addClass("Ldt-SliderMinimized"); + + this.sliderBackground = this.selector.find(".Ldt-sliderBackground"); + this.sliderForeground = this.selector.find(".Ldt-sliderForeground"); + this.positionMarker = this.selector.find(".Ldt-sliderPositionMarker"); + + + // a special variable to stop methods from tinkering + // with the positionMarker when the user is dragging it + this.draggingOngoing = false; + + // another special variable used by the timeout handler to + // open or close the slider. + this.sliderMaximized = false; + this.timeOutId = null; + + + this.positionMarker.draggable({axis: "x", + start: IriSP.wrap(this, this.positionMarkerDraggingStartedHandler), + stop: IriSP.wrap(this, this.positionMarkerDraggedHandler), + containment: "parent" + }); + this.positionMarker.css("position", "absolute"); + + this.sliderBackground.click(function(event) { self.backgroundClickHandler.call(self, event); }); + this.sliderForeground.click(function(event) { self.foregroundClickHandler.call(self, event); }); + + this.selector.hover(IriSP.wrap(this, this.mouseOverHandler), IriSP.wrap(this, this.mouseOutHandler)); + + // update the positions + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); + + // special messages : + this._Popcorn.listen("IriSP.PlayerWidget.MouseOver", IriSP.wrap(this, this.mouseOverHandler)); + this._Popcorn.listen("IriSP.PlayerWidget.MouseOut", IriSP.wrap(this, this.mouseOutHandler)); +}; + +/* update the slider and the position marker as time passes */ +IriSP.SliderWidget.prototype.sliderUpdater = function() { + if(this.draggingOngoing || this._disableUpdate) + return; + + var time = this._Popcorn.currentTime(); + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var percent = ((time / duration) * 100).toFixed(2); + + /* we do these complicated calculations to center exactly + the position Marker */ + var pixels_to_percents = 100 / this.selector.width(); /* how much is a pixel in percents */ + var positionMarker_width = this.positionMarker.width(); + var correction = (pixels_to_percents * positionMarker_width) / 2; + + var newPos = percent - correction; + if (newPos <= 0) + newPos = 0; + + this.sliderForeground.css("width", percent + "%"); + this.positionMarker.css("left", newPos + "%"); + +}; + +IriSP.SliderWidget.prototype.backgroundClickHandler = function(event) { + /* this piece of code is a little bit convoluted - here's how it works : + we want to handle clicks on the progress bar and convert those to seeks in the media. + However, jquery only gives us a global position, and we want a number of pixels relative + to our container div, so we get the parent position, and compute an offset to this position, + and finally compute the progress ratio in the media. + Finally we multiply this ratio with the duration to get the correct time + */ + + var parentOffset = this.sliderBackground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* same function as the previous one, except that it handles clicks + on the foreground element */ +IriSP.SliderWidget.prototype.foregroundClickHandler = function(event) { + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* handles mouse over the slider */ +IriSP.SliderWidget.prototype.mouseOverHandler = function(event) { + + if (this.timeOutId !== null) { + window.clearTimeout(this.timeOutId); + } + + this.sliderMaximized = true; + + this.sliderBackground.animate({"height": "9px"}, 100); + this.sliderForeground.animate({"height": "9px"}, 100); + this.positionMarker.animate({"height": "9px", "width": "9px"}, 100); + //this.positionMarker.css("margin-top", "-4px"); + +// this.selector.removeClass("Ldt-SliderMinimized"); +// this.selector.addClass("Ldt-SliderMaximized"); +}; + +/* handles when the mouse leaves the slider */ +IriSP.SliderWidget.prototype.mouseOutHandler = function(event) { + + this.timeOutId = window.setTimeout(IriSP.wrap(this, this.minimizeOnTimeout), + IriSP.widgetsDefaults.SliderWidget.minimize_period); +}; + +IriSP.SliderWidget.prototype.minimizeOnTimeout = function(event) { + this.sliderBackground.animate({"height": "5px"}, 100); + this.sliderForeground.animate({"height": "5px"}, 100); + this.positionMarker.animate({"height": "5px", "width": "5px"}, 100); + this.positionMarker.css("margin-top", "0px"); + this.sliderMinimized = true; + +// this.selector.removeClass("Ldt-SliderMaximized"); +// this.selector.addClass("Ldt-SliderMinimized"); + +}; + +// called when the user starts dragging the position indicator +IriSP.SliderWidget.prototype.positionMarkerDraggingStartedHandler = function(event, ui) { + this.draggingOngoing = true; +}; + +IriSP.SliderWidget.prototype.positionMarkerDraggedHandler = function(event, ui) { + this._disableUpdate = true; // disable slider position updates while dragging is ongoing. + window.setTimeout(IriSP.wrap(this, function() { this._disableUpdate = false; }), 500); + + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); + + this.draggingOngoing = false; +}; + +/* this widget displays a small tooltip */ +IriSP.TooltipWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + this._shown = false; + this._displayedText = ""; + this._hideTimeout = -1; +}; + + +IriSP.TooltipWidget.prototype = new IriSP.Widget(); + +IriSP.TooltipWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.tooltipWidget_template); + + this.selector.append(templ); + this.hide(); + +}; + +IriSP.TooltipWidget.prototype.clear = function() { + this.selector.find(".tiptext").text(""); +}; + +IriSP.TooltipWidget.prototype.show = function(text, color, x, y) { + + if (this._displayedText == text) + return; + + this.selector.find(".tipcolor").css("background-color", color); + this._displayedText = text; + this.selector.find(".tiptext").text(text); + //this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").show(); + this._shown = true; +}; + +IriSP.TooltipWidget.prototype.hide = function() { + this.selector.find(".tip").hide(); + this._shown = false; +};/* a widget that displays tweet - used in conjunction with the polemicWidget */ + +IriSP.TweetsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._displayingTweet = false; + this._timeoutId = undefined; +}; + + +IriSP.TweetsWidget.prototype = new IriSP.Widget(); + + +IriSP.TweetsWidget.prototype.drawTweet = function(annotation) { + + var title = IriSP.formatTweet(annotation.content.title); + var img = annotation.content.img.src; + if (typeof(img) === "undefined" || img === "" || img === "None") { + img = IriSP.widgetsDefaults.TweetsWidget.default_profile_picture; + } + + var imageMarkup = IriSP.templToHTML("user image", + {src : img}); + + if (typeof(annotation.meta["dc:source"].content) !== "undefined") { + var tweetContents = JSON.parse(annotation.meta["dc:source"].content); + var creator = tweetContents.user.screen_name; + var real_name = tweetContents.user.name; + + imageMarkup = IriSP.templToHTML("user image", + {src : img, creator: creator}); + + var formatted_date = new Date(tweetContents.created_at).toLocaleDateString(); + title = IriSP.templToHTML("@{{creator}} - " + + "
{{real_name}}
" + + "
{{{ contents }}}
" + + "
{{ date }}
", + {creator: creator, real_name: real_name, contents : title, date : formatted_date}); + + this.selector.find(".Ldt-TweetReply").attr("href", "http://twitter.com/home?status=@" + creator + ":%20"); + + + var rtText = Mustache.to_html("http://twitter.com/home?status=RT @{{creator}}: {{text}}", + {creator: creator, text: IriSP.encodeURI(annotation.content.title)}); + this.selector.find(".Ldt-Retweet").attr("href", rtText); + } + + this.selector.find(".Ldt-tweetContents").html(title); + this.selector.find(".Ldt-tweetAvatar").html(imageMarkup); + this.selector.show("blind", 250); +}; + +IriSP.TweetsWidget.prototype.displayTweet = function(annotation) { + if (this._displayingTweet === false) { + this._displayingTweet = true; + } else { + window.clearTimeout(this._timeoutId); + } + + this.drawTweet(annotation); + + var time = this._Popcorn.currentTime(); + this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), IriSP.widgetsDefaults.TweetsWidget.tweet_display_period); +}; + + +IriSP.TweetsWidget.prototype.clearPanel = function() { + this._displayingTweet = false; + this._timeoutId = undefined; + this.closePanel(); + +}; + +IriSP.TweetsWidget.prototype.closePanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } + + this.selector.hide("blind", 400); + +}; + +/* cancel the timeout if the user clicks on the keep panel open button */ +IriSP.TweetsWidget.prototype.keepPanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } +}; + +IriSP.TweetsWidget.prototype.draw = function() { + var _this = this; + + var tweetMarkup = IriSP.templToHTML(IriSP.tweetWidget_template, {"share_template" : IriSP.share_template}); + this.selector.append(tweetMarkup); + this.selector.hide(); + this.selector.find(".Ldt-tweetWidgetMinimize").click(IriSP.wrap(this, this.closePanel)); + this.selector.find(".Ldt-tweetWidgetKeepOpen").click(IriSP.wrap(this, this.keepPanel)); + + this._Popcorn.listen("IriSP.PolemicTweet.click", IriSP.wrap(this, this.PolemicTweetClickHandler)); +}; + +IriSP.TweetsWidget.prototype.PolemicTweetClickHandler = function(tweet_id) { + var index, annotation; + for (index in this._serializer._data.annotations) { + annotation = this._serializer._data.annotations[index]; + + if (annotation.id === tweet_id) + break; + } + + if (annotation.id !== tweet_id) + /* we haven't found it */ + return; + + this.displayTweet(annotation); + return; +}; + +IriSP.JSONSerializer = function(DataLoader, url) { + IriSP.Serializer.call(this, DataLoader, url); +}; + +IriSP.JSONSerializer.prototype = new IriSP.Serializer(); + +IriSP.JSONSerializer.prototype.serialize = function(data) { + return JSON.stringify(data); +}; + +IriSP.JSONSerializer.prototype.deserialize = function(data) { + return JSON.parse(data); +}; + +IriSP.JSONSerializer.prototype.sync = function(callback) { + /* we don't have to do much because jQuery handles json for us */ + + var self = this; + + var fn = function(data) { + self._data = data; + // sort the data too + self._data["annotations"].sort(function(a, b) + { var a_begin = +a.begin; + var b_begin = +b.begin; + return a_begin - b_begin; + }); + + callback(data); + }; + + this._DataLoader.get(this._url, fn); +}; + +IriSP.JSONSerializer.prototype.currentMedia = function() { + return this._data.medias[0]; /* FIXME: don't hardcode it */ +}; + +/* this function searches for an annotation which matches title, description and keyword + "" matches any field. + Note: it ignores tweets. +*/ +IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return true; // don't pass + } else { + return false; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* only look for tweets */ +IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return false; // pass + } else { + return true; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* + the previous function call this one, which is more general: + */ +IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) { + + var rTitle; + var rDescription; + var rKeyword; + /* match anything if given the empty string */ + if (title == "") + title = ".*"; + if (description == "") + description = ".*"; + if (keyword == "") + keyword = ".*"; + + rTitle = new RegExp(title, "i"); + rDescription = new RegExp(description, "i"); + rKeyword = new RegExp(keyword, "i"); + + var ret_array = []; + + var i; + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (filter(annotation)) { + continue; + } + + if (rTitle.test(annotation.content.title) && + rDescription.test(annotation.content.description)) { + /* FIXME : implement keyword support */ + ret_array.push(annotation); + } + } + + return ret_array; +}; + +/* breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/* breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchTweets(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchTweets("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/* takes the currentTime and returns all the annotations that are displayable at the moment + NB: only takes account the first type of annotations - ignores tweets + currentTime is in seconds. + */ + +IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime) { + var view; + var currentTimeMs = 1000 * currentTime; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var view_type = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length >= 1) { + view_type = view.annotation_types[0]; + } + + var ret_array = []; + + var i; + + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + if (annotation.meta["id-ref"] === view_type && annotation.begin <= currentTimeMs && annotation.end >= currentTimeMs) + ret_array.push(annotation); + } + + return ret_array; +}; + + +/* this function returns a list of ids of tweet lines */ +IriSP.JSONSerializer.prototype.getTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + var tweetsId = []; + + /* first get the list containing the tweets */ + var tweets = IriSP.underscore.filter(this._data.lists, function(entry) { return entry.id.indexOf("tweet") !== -1 }); + + // FIXME: collect tweets from multiple sources ? + tweetsId = IriSP.underscore.pluck(tweets[0].items, "id-ref"); + + return tweetsId; +}; + +/* this function returns a list of lines which are not tweet lines */ +IriSP.JSONSerializer.prototype.getNonTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + /* get all the ids */ + var ids = IriSP.underscore.map(this._data.lists, function(entry) { + return IriSP.underscore.pluck(entry.items, "id-ref"); }); + + var illegal_values = this.getTweetIds(); + return IriSP.underscore.difference(ids, illegal_values); + +}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/README.txt Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,183 @@ +====================================================================== + +DESCRIPTION: + +This is the source code for JsDoc Toolkit, an automatic documentation +generation tool for JavaScript. It is written in JavaScript and is run +from a command line (or terminal) using Java and Mozilla's Rhino +JavaScript runtime engine. + +Using this tool you can automatically turn JavaDoc-like comments in +your JavaScript source code into published output files, such as HTML +or XML. + +For more information, to report a bug, or to browse the technical +documentation for this tool please visit the official JsDoc Toolkit +project homepage at http://code.google.com/p/jsdoc-toolkit/ + +For the most up-to-date documentation on JsDoc Toolkit see the +official wiki at http://code.google.com/p/jsdoc-toolkit/w/list + +====================================================================== + +REQUIREMENTS: + +JsDoc Toolkit is known to work with: +java version "1.6.0_03" +Java(TM) SE Runtime Environment (build 1.6.0_03-b05) +on Windows XP, +and java version "1.5.0_19" +Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_19-b02-304) +on Mac OS X 10.5. + +Other versions of java may or may not work with JsDoc Toolkit. + +====================================================================== + +USAGE: + +Running JsDoc Toolkit requires you to have Java installed on your +computer. For more information see http://www.java.com/getjava/ + +Before running the JsDoc Toolkit app you should change your current +working directory to the jsdoc-toolkit folder. Then follow the +examples below, or as shown on the project wiki. + +On a computer running Windows a valid command line to run JsDoc +Toolkit might look like this: + +> java -jar jsrun.jar app\run.js -a -t=templates\jsdoc mycode.js + +On Mac OS X or Linux the same command would look like this: + +$ java -jar jsrun.jar app/run.js -a -t=templates/jsdoc mycode.js + +The above assumes your current working directory contains jsrun.jar, +the "app" and "templates" subdirectories from the standard JsDoc +Toolkit distribution and that the relative path to the code you wish +to document is "mycode.js". + +The output documentation files will be saved to a new directory named +"out" (by default) in the current directory, or if you specify a +-d=somewhere_else option, to the somewhere_else directory. + +For help (usage notes) enter this on the command line: + +$ java -jar jsrun.jar app/run.js --help + +More information about the various command line options used by JsDoc +Toolkit are available on the project wiki. + +====================================================================== + +RUNNING VIA SHELL SCRIPT + +Avi Deitcher has contributed the file jsrun.sh with the following usage notes: + +A script to simplify running jsdoc from the command-line, especially when +running from within a development or build environment such as ant. + +Normally, to run jsdoc, you need a command-line as the following: +java -Djsdoc.dir=/some/long/dir/path/to/jsdoc -jar +/some/long/dir/path/to/jsdoc/jsrun.jar /some/long/dir/path/to/jsdoc/app/run.js +-t=template -r=4 /some/long/dir/path/to/my/src/code + +This can get tedious to redo time and again, and difficult to use from within a build environment. + +To simplify the process, jsrun.sh will automatically run this path, as well as passing through any arguments. + +Usage: jsrun.sh + +All will be passed through. +Additionally, jsrun.sh will take the following actions: +1) If the environment variable JSDOCDIR is set, it will add +"-Djsdoc.dir=$JSDOCDIR" to the command-line +2) If the environment variable JSDOCTEMPLATEDIR is set, it will add +"-Djsdoc.template.dir=$JSDOCTEMPLATEDIR" to the command-line +3) java with the appropriate path to jsrun.jar and run.js will be instantiated + +If not variables are set, it is assumed that the path to jsrun.jar and app/ is in the current working directory. + +Example: +# jsrun.sh ./src/ +Assuming JSDOCDIR=/some/path/to/my/jsdoc will cause the following command to +execute: +java -Djsdoc.dir=/some/path/to/my/jsdoc -jar /some/path/to/my/jsdoc/jsrun.jar +/some/path/to/my/jsdoc/app/run.js ./src/ + +====================================================================== + +TESTING: + +To run the suite of unit tests included with JsDoc Toolkit enter this +on the command line: + +$ java -jar jsrun.jar app/run.js -T + +To see a dump of the internal data structure that JsDoc Toolkit has +built from your source files use this command: + +$ java -jar jsrun.jar app/run.js mycode.js -Z + +====================================================================== + +LICENSE: + +JSDoc.pm + +This project is based on the JSDoc.pm tool, created by Michael +Mathews and Gabriel Reid. More information on JsDoc.pm can +be found on the JSDoc.pm homepage: http://jsdoc.sourceforge.net/ + +Complete documentation on JsDoc Toolkit can be found on the project +wiki at http://code.google.com/p/jsdoc-toolkit/w/list + +Rhino + +Rhino (JavaScript in Java) is open source and licensed by Mozilla +under the MPL 1.1 or later/GPL 2.0 or later licenses, the text of +which is available at http://www.mozilla.org/MPL/ + +You can obtain the source code for Rhino from the Mozilla web site at +http://www.mozilla.org/rhino/download.html + +JsDoc Toolkit is a larger work that uses the Rhino JavaScript engine +but is not derived from it in any way. The Rhino library is used +without modification and without any claims whatsoever. + +The Rhino Debugger + +You can obtain more information about the Rhino Debugger from the +Mozilla web site at http://www.mozilla.org/rhino/debugger.html + +JsDoc Toolkit is a larger work that uses the Rhino Debugger but +is not derived from it in any way. The Rhino Debugger is used +without modification and without any claims whatsoever. + +JsDoc Toolkit + +All code specific to JsDoc Toolkit are free, open source and licensed +for use under the X11/MIT License. + +JsDoc Toolkit is Copyright (c)2009 Michael Mathews + +This program is free software; you can redistribute it and/or +modify it under the terms below. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: The above copyright notice and this +permission notice must be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,33 @@ +IO.include("frame/Opt.js"); +IO.include("frame/Chain.js"); +IO.include("frame/Link.js"); +IO.include("frame/String.js"); +IO.include("frame/Hash.js"); +IO.include("frame/Namespace.js"); +//IO.include("frame/Reflection.js"); + +/** A few helper functions to make life a little easier. */ + +function defined(o) { + return (o !== undefined); +} + +function copy(o) { // todo check for circular refs + if (o == null || typeof(o) != 'object') return o; + var c = new o.constructor(); + for(var p in o) c[p] = copy(o[p]); + return c; +} + +function isUnique(arr) { + var l = arr.length; + for(var i = 0; i < l; i++ ) { + if (arr.lastIndexOf(arr[i]) > i) return false; + } + return true; +} + +/** Returns the given string with all regex meta characters backslashed. */ +RegExp.escapeMeta = function(str) { + return str.replace(/([$^\\\/()|?+*\[\]{}.-])/g, "\\$1"); +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Chain.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Chain.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,102 @@ +/**@constructor*/ +function ChainNode(object, link) { + this.value = object; + this.link = link; // describes this node's relationship to the previous node +} + +/**@constructor*/ +function Chain(valueLinks) { + this.nodes = []; + this.cursor = -1; + + if (valueLinks && valueLinks.length > 0) { + this.push(valueLinks[0], "//"); + for (var i = 1, l = valueLinks.length; i < l; i+=2) { + this.push(valueLinks[i+1], valueLinks[i]); + } + } +} + +Chain.prototype.push = function(o, link) { + if (this.nodes.length > 0 && link) this.nodes.push(new ChainNode(o, link)); + else this.nodes.push(new ChainNode(o)); +} + +Chain.prototype.unshift = function(o, link) { + if (this.nodes.length > 0 && link) this.nodes[0].link = link; + this.nodes.unshift(new ChainNode(o)); + this.cursor++; +} + +Chain.prototype.get = function() { + if (this.cursor < 0 || this.cursor > this.nodes.length-1) return null; + return this.nodes[this.cursor]; +} + +Chain.prototype.first = function() { + this.cursor = 0; + return this.get(); +} + +Chain.prototype.last = function() { + this.cursor = this.nodes.length-1; + return this.get(); +} + +Chain.prototype.next = function() { + this.cursor++; + return this.get(); +} + +Chain.prototype.prev = function() { + this.cursor--; + return this.get(); +} + +Chain.prototype.toString = function() { + var string = ""; + for (var i = 0, l = this.nodes.length; i < l; i++) { + if (this.nodes[i].link) string += " -("+this.nodes[i].link+")-> "; + string += this.nodes[i].value.toString(); + } + return string; +} + +Chain.prototype.joinLeft = function() { + var result = ""; + for (var i = 0, l = this.cursor; i < l; i++) { + if (result && this.nodes[i].link) result += this.nodes[i].link; + result += this.nodes[i].value.toString(); + } + return result; +} + + +/* USAGE: + +var path = "one/two/three.four/five-six"; +var pathChain = new Chain(path.split(/([\/.-])/)); +print(pathChain); + +var lineage = new Chain(); +lineage.push("Port"); +lineage.push("Les", "son"); +lineage.push("Dawn", "daughter"); +lineage.unshift("Purdie", "son"); + +print(lineage); + +// walk left +for (var node = lineage.last(); node !== null; node = lineage.prev()) { + print("< "+node.value); +} + +// walk right +var node = lineage.first() +while (node !== null) { + print(node.value); + node = lineage.next(); + if (node && node.link) print("had a "+node.link+" named"); +} + +*/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Dumper.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Dumper.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,144 @@ +/** + * @class +
+This is a lightly modified version of Kevin Jones' JavaScript
+library Data.Dump. To download the original visit:
+    http://openjsan.org/doc/k/ke/kevinj/Data/Dump/
+
+AUTHORS
+
+The Data.Dump JavaScript module is written by Kevin Jones 
+(kevinj@cpan.org), based on Data::Dump by Gisle Aas (gisle@aas.no),
+based on Data::Dumper by Gurusamy Sarathy (gsar@umich.edu).
+
+COPYRIGHT
+
+Copyright 2007 Kevin Jones. Copyright 1998-2000,2003-2004 Gisle Aas.
+Copyright 1996-1998 Gurusamy Sarathy.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the Perl Artistic License
+
+See http://www.perl.com/perl/misc/Artistic.html
+
+ * @static + */ +Dumper = { + /** @param [...] The objects to dump. */ + dump: function () { + if (arguments.length > 1) + return this._dump(arguments); + else if (arguments.length == 1) + return this._dump(arguments[0]); + else + return "()"; + }, + + _dump: function (obj) { + if (typeof obj == 'undefined') return 'undefined'; + var out; + if (obj.serialize) { return obj.serialize(); } + var type = this._typeof(obj); + if (obj.circularReference) obj.circularReference++; + switch (type) { + case 'circular': + out = "{ //circularReference\n}"; + break; + case 'object': + var pairs = new Array; + + for (var prop in obj) { + if (prop != "circularReference" && obj.hasOwnProperty(prop)) { //hide inherited properties + pairs.push(prop + ': ' + this._dump(obj[prop])); + } + } + + out = '{' + this._format_list(pairs) + '}'; + break; + + case 'string': + for (var prop in Dumper.ESC) { + if (Dumper.ESC.hasOwnProperty(prop)) { + obj = obj.replace(prop, Dumper.ESC[prop]); + } + } + + // Escape UTF-8 Strings + if (obj.match(/^[\x00-\x7f]*$/)) { + out = '"' + obj.replace(/\"/g, "\\\"").replace(/([\n\r]+)/g, "\\$1") + '"'; + } + else { + out = "unescape('"+escape(obj)+"')"; + } + break; + + case 'array': + var elems = new Array; + + for (var i=0; i 60 ? '\n' : ' '; + return nl + list.join(',' + nl) + nl; + }, + + _typeof: function (obj) { + if (obj && obj.circularReference && obj.circularReference > 1) return 'circular'; + if (Array.prototype.isPrototypeOf(obj)) return 'array'; + if (Date.prototype.isPrototypeOf(obj)) return 'date'; + if (typeof obj.nodeType != 'undefined') return 'element'; + return typeof(obj); + }, + + _dump_dom: function (obj) { + return '"' + Dumper.nodeTypes[obj.nodeType] + '"'; + } +}; + +Dumper.ESC = { + "\t": "\\t", + "\n": "\\n", + "\f": "\\f" +}; + +Dumper.nodeTypes = { + 1: "ELEMENT_NODE", + 2: "ATTRIBUTE_NODE", + 3: "TEXT_NODE", + 4: "CDATA_SECTION_NODE", + 5: "ENTITY_REFERENCE_NODE", + 6: "ENTITY_NODE", + 7: "PROCESSING_INSTRUCTION_NODE", + 8: "COMMENT_NODE", + 9: "DOCUMENT_NODE", + 10: "DOCUMENT_TYPE_NODE", + 11: "DOCUMENT_FRAGMENT_NODE", + 12: "NOTATION_NODE" +}; \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Hash.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Hash.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,84 @@ +/** + @constructor + @example + var _index = new Hash(); + _index.set("a", "apple"); + _index.set("b", "blue"); + _index.set("c", "coffee"); + + for (var p = _index.first(); p; p = _index.next()) { + print(p.key+" is for "+p.value); + } + + */ +var Hash = function() { + this._map = {}; + this._keys = []; + this._vals = []; + this.reset(); +} + +Hash.prototype.set = function(k, v) { + if (k != "") { + this._keys.push(k); + this._map["="+k] = this._vals.length; + this._vals.push(v); + } +} + +Hash.prototype.replace = function(k, k2, v) { + if (k == k2) return; + + var offset = this._map["="+k]; + this._keys[offset] = k2; + if (typeof v != "undefined") this._vals[offset] = v; + this._map["="+k2] = offset; + delete(this._map["="+k]); +} + +Hash.prototype.drop = function(k) { + if (k != "") { + var offset = this._map["="+k]; + this._keys.splice(offset, 1); + this._vals.splice(offset, 1); + delete(this._map["="+k]); + for (var p in this._map) { + if (this._map[p] >= offset) this._map[p]--; + } + if (this._cursor >= offset && this._cursor > 0) this._cursor--; + } +} + +Hash.prototype.get = function(k) { + if (k != "") { + return this._vals[this._map["="+k]]; + } +} + +Hash.prototype.keys = function() { + return this._keys; +} + +Hash.prototype.hasKey = function(k) { + if (k != "") { + return (typeof this._map["="+k] != "undefined"); + } +} + +Hash.prototype.values = function() { + return this._vals; +} + +Hash.prototype.reset = function() { + this._cursor = 0; +} + +Hash.prototype.first = function() { + this.reset(); + return this.next(); +} + +Hash.prototype.next = function() { + if (this._cursor++ < this._keys.length) + return {key: this._keys[this._cursor-1], value: this._vals[this._cursor-1]}; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Link.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Link.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,173 @@ +/** Handle the creation of HTML links to documented symbols. + @constructor +*/ +function Link() { + this.alias = ""; + this.src = ""; + this.file = ""; + this.text = ""; + this.innerName = ""; + this.classLink = false; + this.targetName = ""; + + this.target = function(targetName) { + if (defined(targetName)) this.targetName = targetName; + return this; + } + this.inner = function(inner) { + if (defined(inner)) this.innerName = inner; + return this; + } + this.withText = function(text) { + if (defined(text)) this.text = text; + return this; + } + this.toSrc = function(filename) { + if (defined(filename)) this.src = filename; + return this; + } + this.toSymbol = function(alias) { + if (defined(alias)) this.alias = new String(alias); + return this; + } + this.toClass = function(alias) { + this.classLink = true; + return this.toSymbol(alias); + } + this.toFile = function(file) { + if (defined(file)) this.file = file; + return this; + } + + this.toString = function() { + var linkString; + var thisLink = this; + + if (this.alias) { + linkString = this.alias.replace(/(^|[^a-z$0-9_#.:^-])([|a-z$0-9_#.:^-]+)($|[^a-z$0-9_#.:^-])/i, + function(match, prematch, symbolName, postmatch) { + var symbolNames = symbolName.split("|"); + var links = []; + for (var i = 0, l = symbolNames.length; i < l; i++) { + thisLink.alias = symbolNames[i]; + links.push(thisLink._makeSymbolLink(symbolNames[i])); + } + return prematch+links.join("|")+postmatch; + } + ); + } + else if (this.src) { + linkString = thisLink._makeSrcLink(this.src); + } + else if (this.file) { + linkString = thisLink._makeFileLink(this.file); + } + + return linkString; + } +} + +/** prefixed for hashes */ +Link.hashPrefix = ""; + +/** Appended to the front of relative link paths. */ +Link.base = ""; + +Link.symbolNameToLinkName = function(symbol) { + var linker = "", + ns = ""; + + if (symbol.isStatic) linker = "."; + else if (symbol.isInner) linker = "-"; + + if (symbol.isEvent && !/^event:/.test(symbol.name)) { + ns = "event:"; + } + return Link.hashPrefix+linker+ns+symbol.name; +} + +Link.getSymbol= function(alias) { + var symbol= Link.symbolSet.getSymbol(alias); + + if (symbol) + return symbol; + + if ('#'!==alias.charAt(0) || !Link.currentSymbol) + return null; + + // resolve relative name + var container= Link.currentSymbol; + + while (container) + { + symbol= Link.symbolSet.getSymbol(container.alias + alias); + if (symbol) + return symbol; + + // No superclass + if (!container.augments.length) + return null; + + container= Link.symbolSet.getSymbol(container.augments[0].desc); + } + + return null; +} + +/** Create a link to another symbol. */ +Link.prototype._makeSymbolLink = function(alias) { + var linkBase = Link.base+publish.conf.symbolsDir; + var linkTo = Link.getSymbol(alias); + var linkPath; + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + // if there is no symbol by that name just return the name unaltered + if (!linkTo) + return this.text || alias; + + // it's a symbol in another file + else { + if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property + linkPath= (Link.filemap) ? Link.filemap[linkTo.memberOf] : + escape(linkTo.memberOf) || "_global_"; + linkPath += publish.conf.ext + "#" + Link.symbolNameToLinkName(linkTo); + } + else { + linkPath = (Link.filemap)? Link.filemap[linkTo.alias] : escape(linkTo.alias); + linkPath += publish.conf.ext;// + (this.classLink? "":"#" + Link.hashPrefix + "constructor"); + } + linkPath = linkBase + linkPath + } + + var linkText= this.text || alias; + + var link = {linkPath: linkPath, linkText: linkText, linkInner: (this.innerName? "#"+this.innerName : "")}; + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onSymbolLink", link); + } + + return ""+link.linkText+""; +} + +/** Create a link to a source file. */ +Link.prototype._makeSrcLink = function(srcFilePath) { + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + // transform filepath into a filename + var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "_"); + var outFilePath = Link.base + publish.conf.srcDir + srcFile + publish.conf.ext; + + if (!this.text) this.text = FilePath.fileName(srcFilePath); + return ""+this.text+""; +} + +/** Create a link to a source file. */ +Link.prototype._makeFileLink = function(filePath) { + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + var outFilePath = Link.base + filePath; + + if (!this.text) this.text = filePath; + return ""+this.text+""; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Namespace.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Namespace.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ +_global_ = this; + +function Namespace(name, f) { + var n = name.split("."); + for (var o = _global_, i = 0, l = n.length; i < l; i++) { + o = o[n[i]] = o[n[i]] || {}; + } + + if (f) f(); +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Opt.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Opt.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,134 @@ +/** @namespace */ +Opt = { + /** + * Get commandline option values. + * @param {Array} args Commandline arguments. Like ["-a=xml", "-b", "--class=new", "--debug"] + * @param {object} optNames Map short names to long names. Like {a:"accept", b:"backtrace", c:"class", d:"debug"}. + * @return {object} Short names and values. Like {a:"xml", b:true, c:"new", d:true} + */ + get: function(args, optNames) { + var opt = {"_": []}; // the unnamed option allows multiple values + for (var i = 0; i < args.length; i++) { + var arg = new String(args[i]); + var name; + var value; + if (arg.charAt(0) == "-") { + if (arg.charAt(1) == "-") { // it's a longname like --foo + arg = arg.substring(2); + var m = arg.split("="); + name = m.shift(); + value = m.shift(); + if (typeof value == "undefined") value = true; + + for (var n in optNames) { // convert it to a shortname + if (name == optNames[n]) { + name = n; + } + } + } + else { // it's a shortname like -f + arg = arg.substring(1); + var m = arg.split("="); + name = m.shift(); + value = m.shift(); + if (typeof value == "undefined") value = true; + + for (var n in optNames) { // find the matching key + if (name == n || name+'[]' == n) { + name = n; + break; + } + } + } + if (name.match(/(.+)\[\]$/)) { // it's an array type like n[] + name = RegExp.$1; + if (!opt[name]) opt[name] = []; + } + + if (opt[name] && opt[name].push) { + opt[name].push(value); + } + else { + opt[name] = value; + } + } + else { // not associated with any optname + opt._.push(args[i]); + } + } + return opt; + } +} + +/*t: + plan(11, "Testing Opt."); + + is( + typeof Opt, + "object", + "Opt is an object." + ); + + is( + typeof Opt.get, + "function", + "Opt.get is a function." + ); + + var optNames = {a:"accept", b:"backtrace", c:"class", d:"debug", "e[]":"exceptions"}; + var t_options = Opt.get(["-a=xml", "-b", "--class=new", "--debug", "-e=one", "-e=two", "foo", "bar"], optNames); + + is( + t_options.a, + "xml", + "an option defined with a short name can be accessed by its short name." + ); + + is( + t_options.b, + true, + "an option defined with a short name and no value are true." + ); + + is( + t_options.c, + "new", + "an option defined with a long name can be accessed by its short name." + ); + + is( + t_options.d, + true, + "an option defined with a long name and no value are true." + ); + + is( + typeof t_options.e, + "object", + "an option that can accept multiple values is defined." + ); + + is( + t_options.e.length, + 2, + "an option that can accept multiple values can have more than one value." + ); + + is( + t_options.e[1], + "two", + "an option that can accept multiple values can be accessed as an array." + ); + + is( + typeof t_options._, + "object", + "the property '_' is defined for unnamed options." + ); + + is( + t_options._[0], + "foo", + "the property '_' can be accessed as an array." + ); + */ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/Reflection.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/Reflection.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,26 @@ +/**@constructor*/ +function Reflection(obj) { + this.obj = obj; +} + +Reflection.prototype.getConstructorName = function() { + if (this.obj.constructor.name) return this.obj.constructor.name; + var src = this.obj.constructor.toSource(); + var name = src.substring(name.indexOf("function")+8, src.indexOf('(')).replace(/ /g,''); + return name; +} + +Reflection.prototype.getMethod = function(name) { + for (var p in this.obj) { + if (p == name && typeof(this.obj[p]) == "function") return this.obj[p]; + } + return null; +} + +Reflection.prototype.getParameterNames = function() { + var src = this.obj.toSource(); + src = src.substring( + src.indexOf("(", 8)+1, src.indexOf(")") + ); + return src.split(/, ?/); +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/frame/String.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/frame/String.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,93 @@ +/** + @name String + @class Additions to the core string object. +*/ + +/** @author Steven Levithan, released as public domain. */ +String.prototype.trim = function() { + var str = this.replace(/^\s+/, ''); + for (var i = str.length - 1; i >= 0; i--) { + if (/\S/.test(str.charAt(i))) { + str = str.substring(0, i + 1); + break; + } + } + return str; +} +/*t: + plan(6, "Testing String.prototype.trim."); + + var s = " a bc ".trim(); + is(s, "a bc", "multiple spaces front and back are trimmed."); + + s = "a bc\n\n".trim(); + is(s, "a bc", "newlines only in back are trimmed."); + + s = "\ta bc".trim(); + is(s, "a bc", "tabs only in front are trimmed."); + + s = "\n \t".trim(); + is(s, "", "an all-space string is trimmed to empty."); + + s = "a b\nc".trim(); + is(s, "a b\nc", "a string with no spaces in front or back is trimmed to itself."); + + s = "".trim(); + is(s, "", "an empty string is trimmed to empty."); + +*/ + +String.prototype.balance = function(open, close) { + var i = 0; + while (this.charAt(i) != open) { + if (i == this.length) return [-1, -1]; + i++; + } + + var j = i+1; + var balance = 1; + while (j < this.length) { + if (this.charAt(j) == open) balance++; + if (this.charAt(j) == close) balance--; + if (balance == 0) break; + j++; + if (j == this.length) return [-1, -1]; + } + + return [i, j]; +} +/*t: + plan(16, "Testing String.prototype.balance."); + + var s = "{abc}".balance("{","}"); + is(s[0], 0, "opener in first is found."); + is(s[1], 4, "closer in last is found."); + + s = "ab{c}de".balance("{","}"); + is(s[0], 2, "opener in middle is found."); + is(s[1], 4, "closer in middle is found."); + + s = "a{b{c}de}f".balance("{","}"); + is(s[0], 1, "nested opener is found."); + is(s[1], 8, "nested closer is found."); + + s = "{}".balance("{","}"); + is(s[0], 0, "opener with no content is found."); + is(s[1], 1, "closer with no content is found."); + + s = "".balance("{","}"); + is(s[0], -1, "empty string opener is -1."); + is(s[1], -1, "empty string closer is -1."); + + s = "{abc".balance("{","}"); + is(s[0], -1, "opener with no closer returns -1."); + is(s[1], -1, "no closer returns -1."); + + s = "abc".balance("{","}"); + is(s[0], -1, "no opener or closer returns -1 for opener."); + is(s[1], -1, "no opener or closer returns -1 for closer."); + + s = "aX11/MIT License + * (See the accompanying README file for full details.) + */ + +/** + Yet another unit testing tool for JavaScript. + @author Michael Mathews micmath@gmail.com + @param {object} testCases Properties are testcase names, values are functions to execute as tests. +*/ +function testrun(testCases) { + var ran = 0; + for (t in testCases) { + var result = testCases[t](); + ran++; + } + + return testrun.reportOut+"-------------------------------\n"+((testrun.fails>0)? ":( Failed "+testrun.fails+"/" : ":) Passed all ")+testrun.count+" test"+((testrun.count == 1)? "":"s")+".\n"; +} + + +testrun.count = 0; +testrun.current = null; +testrun.passes = 0; +testrun.fails = 0; +testrun.reportOut = ""; + +/** @private */ +testrun.report = function(text) { + testrun.reportOut += text+"\n"; +} + +/** + Check if test evaluates to true. + @param {string} test To be evaluated. + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if the string test evaluates to true. +*/ +ok = function(test, message) { + testrun.count++; + + var result; + try { + result = eval(test); + + if (result) { + testrun.passes++; + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++; + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + + } +} + +/** + Check if test is same as expected. + @param {string} test To be evaluated. + @param {string} expected + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if (test == expected). Note that the comparison is not a strict equality check. +*/ +is = function(test, expected, message) { + testrun.count++; + + var result; + try { + result = eval(test); + + if (result == expected) { + testrun.passes++ + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report("expected: "+expected); + testrun.report(" got: "+result); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report("expected: "+expected); + testrun.report(" got: "+result);} +} + +/** + Check if test matches pattern. + @param {string} test To be evaluated. + @param {string} pattern Used to create a RegExp. + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if test matches pattern. +*/ +like = function(test, pattern, message) { + testrun.count++; + + var result; + try { + result = eval(test); + var rgx = new RegExp(pattern); + + if (rgx.test(result)) { + testrun.passes++ + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report(" this: "+result); + testrun.report("is not like: "+pattern); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/handlers/FOODOC.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/handlers/FOODOC.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,26 @@ +/** + This is the main container for the FOODOC handler. + @namespace +*/ +FOODOC = { +}; + +/** The current version string of this application. */ +FOODOC.VERSION = "1.0"; + +FOODOC.handle = function(srcFile, src) { + LOG.inform("Handling file '" + srcFile + "'"); + + return [ + new JSDOC.Symbol( + "foo", + [], + "VIRTUAL", + new JSDOC.DocComment("/** This is a foo. */") + ) + ]; +}; + +FOODOC.publish = function(symbolgroup) { + LOG.inform("Publishing symbolgroup."); +}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/handlers/XMLDOC.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/handlers/XMLDOC.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,26 @@ +/** + * This is the main container for the XMLDOC handler. + * @namespace + * @author Brett Fattori (bfattori@fry.com) + * @version $Revision: 498 $ + */ +XMLDOC = { + +}; + +/** The current version string of this application. */ +XMLDOC.VERSION = "1.0"; + +/** Include the library necessary to handle XML files */ +IO.includeDir("handlers/XMLDOC/"); + +/** + * @type Symbol[] + */ +XMLDOC.handle = function(srcFile, src) { + +}; + +XMLDOC.publish = function(symbolgroup) { + +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/handlers/XMLDOC/DomReader.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/handlers/XMLDOC/DomReader.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,159 @@ +LOG.inform("XMLDOC.DomReader loaded"); + +XMLDOC.DomReader = function(root) { + + this.dom = root; + + /** + * The current node the reader is on + */ + this.node = root; + + /** + * Get the current node the reader is on + * @type XMLDOC.Parser.node + */ + XMLDOC.DomReader.prototype.getNode = function() { + return this.node; + }; + + /** + * Set the node the reader should be positioned on. + * @param node {XMLDOC.Parser.node} + */ + XMLDOC.DomReader.prototype.setNode = function(node) { + this.node = node; + }; + + /** + * A helper method to make sure the current node will + * never return null, unless null is passed as the root. + * @param step {String} An expression to evaluate - should return a node or null + */ + XMLDOC.DomReader.prototype.navigate = function(step) { + var n; + if ((n = step) != null) + { + this.node = n; + return this.node; + } + return null; + }; + + /** + * Get the root node of the current node's document. + */ + XMLDOC.DomReader.prototype.root = function() { + this.navigate(this.dom); + }; + + /** + * Get the parent of the current node. + */ + XMLDOC.DomReader.prototype.parent = function() { + return this.navigate(this.node.parentNode()); + }; + + /** + * Get the first child of the current node. + */ + XMLDOC.DomReader.prototype.firstChild = function() { + return this.navigate(this.node.firstChild()); + }; + + /** + * Get the last child of the current node. + */ + XMLDOC.DomReader.prototype.lastChild = function() { + return this.navigate(this.node.lastChild()); + }; + + /** + * Get the next sibling of the current node. + */ + XMLDOC.DomReader.prototype.nextSibling = function() { + return this.navigate(this.node.nextSibling()); + }; + + /** + * Get the previous sibling of the current node. + */ + XMLDOC.DomReader.prototype.prevSibling = function() { + return this.navigate(this.node.prevSibling()); + }; + + //=============================================================================================== + // Support methods + + /** + * Walk the tree starting with the current node, calling the plug-in for + * each node visited. Each time the plug-in is called, the DomReader + * is passed as the only parameter. Use the {@link XMLDOC.DomReader#getNode} method + * to access the current node. This method uses a depth first traversal pattern. + * + * @param srcFile {String} The source file being evaluated + */ + XMLDOC.DomReader.prototype.getSymbols = function(srcFile) + { + XMLDOC.DomReader.symbols = []; + XMLDOC.DomReader.currentFile = srcFile; + JSDOC.Symbol.srcFile = (srcFile || ""); + + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onDomGetSymbols", this); + } + + return XMLDOC.DomReader.symbols; + }; + + /** + * Find the node with the given name using a depth first traversal. + * Does not modify the DomReader's current node. + * + * @param name {String} The name of the node to find + * @return the node that was found, or null if not found + */ + XMLDOC.DomReader.prototype.findNode = function(name) + { + var findNode = null; + + // Start at the current node and move into the subtree, + // looking for the node with the given name + function deeper(node, find) + { + var look = null; + + if (node) { + if (node.name == find) + { + return node; + } + + if (node.firstChild()) + { + look = deeper(node.firstChild(), find); + } + + if (!look && node.nextSibling()) + { + look = deeper(node.nextSibling(), find); + } + } + + return look; + } + + return deeper(this.getNode().firstChild(), name); + }; + + /** + * Find the next node with the given name using a depth first traversal. + * + * @param name {String} The name of the node to find + */ + XMLDOC.DomReader.prototype.findPreviousNode = function(name) + { + }; + +}; + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/handlers/XMLDOC/XMLDoc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/handlers/XMLDOC/XMLDoc.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,16 @@ +LOG.inform("XMLDOC.symbolize loaded"); + +/** + * Convert the source file to a set of symbols + */ +XMLDOC.symbolize = function(srcFile, src) { + + LOG.inform("Symbolizing file '" + srcFile + "'"); + + // XML files already have a defined structure, so we don't need to + // do anything but parse them. The DOM reader can create a symbol + // table from the parsed XML. + var dr = new XMLDOC.DomReader(XMLDOC.Parser.parse(src)); + return dr.getSymbols(srcFile); + +}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/handlers/XMLDOC/XMLParse.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/handlers/XMLDOC/XMLParse.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,292 @@ +LOG.inform("XMLDOC.Parser loaded"); + +/** + * XML Parser object. Returns an {@link #XMLDOC.Parser.node} which is + * the root element of the parsed document. + *

+ * By default, this parser will only handle well formed XML. To + * allow the parser to handle HTML, set the XMLDOC.Parser.strictMode + * variable to false before calling XMLDOC.Parser.parse(). + *

+ * Note: If you pass poorly formed XML, it will cause the parser to throw + * an exception. + * + * @author Brett Fattori (bfattori@fry.com) + * @author $Author: micmath $ + * @version $Revision: 497 $ + */ +XMLDOC.Parser = {}; + +/** + * Strict mode setting. Setting this to false allows HTML-style source to + * be parsed. Normally, well formed XML has defined end tags, or empty tags + * are properly formed. Default: true + * @type Boolean + */ +XMLDOC.Parser.strictMode = true; + +/** + * A node in an XML Document. Node types are ROOT, ELEMENT, COMMENT, PI, and TEXT. + * @param parent {XMLDOC.Parser.node} The parent node + * @param name {String} The node name + * @param type {String} One of the types + */ +XMLDOC.Parser.node = function(parent, name, type) +{ + this.name = name; + this.type = type || "ELEMENT"; + this.parent = parent; + this.charData = ""; + this.attrs = {}; + this.nodes = []; + this.cPtr = 0; + + XMLDOC.Parser.node.prototype.getAttributeNames = function() { + var a = []; + for (var o in this.attrs) + { + a.push(o); + } + + return a; + }; + + XMLDOC.Parser.node.prototype.getAttribute = function(attr) { + return this.attrs[attr]; + }; + + XMLDOC.Parser.node.prototype.setAttribute = function(attr, val) { + this.attrs[attr] = val; + }; + + XMLDOC.Parser.node.prototype.getChild = function(idx) { + return this.nodes[idx]; + }; + + XMLDOC.Parser.node.prototype.parentNode = function() { + return this.parent; + }; + + XMLDOC.Parser.node.prototype.firstChild = function() { + return this.nodes[0]; + }; + + XMLDOC.Parser.node.prototype.lastChild = function() { + return this.nodes[this.nodes.length - 1]; + }; + + XMLDOC.Parser.node.prototype.nextSibling = function() { + var p = this.parent; + if (p && (p.nodes.indexOf(this) + 1 != p.nodes.length)) + { + return p.getChild(p.nodes.indexOf(this) + 1); + } + return null; + }; + + XMLDOC.Parser.node.prototype.prevSibling = function() { + var p = this.parent; + if (p && (p.nodes.indexOf(this) - 1 >= 0)) + { + return p.getChild(p.nodes.indexOf(this) - 1); + } + return null; + }; +}; + +/** + * Parse an XML Document from the specified source. The XML should be + * well formed, unless strict mode is disabled, then the parser will + * handle HTML-style XML documents. + * @param src {String} The source to parse + */ +XMLDOC.Parser.parse = function(src) +{ + var A = []; + + // Normailize whitespace + A = src.split("\r\n"); + src = A.join("\n"); + A = src.split("\r"); + src = A.join("\n"); + + // Remove XML and DOCTYPE specifier + src.replace(/<\?XML .*\?>/i, ""); + src.replace(//i, ""); + + // The document is the root node and cannot be modified or removed + var doc = new XMLDOC.Parser.node(null, "ROOT", "DOCUMENT"); + + // Let's break it down + XMLDOC.Parser.eat(doc, src); + + return doc; +}; + +/** + * The XML fragment processing routine. This method is private and should not be called + * directly. + * @param parentNode {XMLDOC.Parser.node} The node which is the parent of this fragment + * @param src {String} The source within the fragment to process + * @private + */ +XMLDOC.Parser.eat = function(parentNode, src) +{ + // A simple tag def + var reTag = new RegExp("<(!|)(\\?|--|)((.|\\s)*?)\\2>","g"); + + // Special tag types + var reCommentTag = //; + var rePITag = /<\?((.|\s)*?)\?>/; + + // A start tag (with potential empty marker) + var reStartTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*(\/)?>/; + + // An empty HTML style tag (not proper XML, but we'll accept it so we can process HTML) + var reHTMLEmptyTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*>/; + + // Fully enclosing tag with nested tags + var reEnclosingTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*?)\4)*>((.|\s)*?)<\/\1>/; + + // Breaks down attributes + var reAttributes = new RegExp(" +([\\w_\\-]*)=(\"|')(.*?)\\2","g"); + + // Find us a tag + var tag; + while ((tag = reTag.exec(src)) != null) + { + if (tag.index > 0) + { + // The next tag has some text before it + var text = src.substring(0, tag.index).replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); + + if (text.length > 0 && (text != "\n")) + { + var txtnode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); + txtnode.charData = text; + + // Append the new text node + parentNode.nodes.push(txtnode); + } + + // Reset the lastIndex of reTag + reTag.lastIndex -= src.substring(0, tag.index).length; + + // Eat the text + src = src.substring(tag.index); + } + + if (reCommentTag.test(tag[0])) + { + // Is this a comment? + var comment = new XMLDOC.Parser.node(parentNode, "", "COMMENT"); + comment.charData = reCommentTag.exec(tag[0])[1]; + + // Append the comment + parentNode.nodes.push(comment); + + // Move the lastIndex of reTag + reTag.lastIndex -= tag[0].length; + + // Eat the tag + src = src.replace(reCommentTag, ""); + } + else if (rePITag.test(tag[0])) + { + // Is this a processing instruction? + var pi = new XMLDOC.Parser.node(parentNode, "", "PI"); + pi.charData = rePITag.exec(tag[0])[1]; + + // Append the processing instruction + parentNode.nodes.push(pi); + + // Move the lastIndex of reTag + reTag.lastIndex -= tag[0].length; + + // Eat the tag + src = src.replace(rePITag, ""); + } + else if (reStartTag.test(tag[0])) + { + // Break it down + var e = reStartTag.exec(tag[0]); + var elem = new XMLDOC.Parser.node(parentNode, e[1], "ELEMENT"); + + // Get attributes from the tag + var a; + while ((a = reAttributes.exec(e[2])) != null ) + { + elem.attrs[a[1]] = a[3]; + } + + // Is this an empty XML-style tag? + if (e[6] == "/") + { + // Append the empty element + parentNode.nodes.push(elem); + + // Move the lastIndex of reTag (include the start tag length) + reTag.lastIndex -= e[0].length; + + // Eat the tag + src = src.replace(reStartTag, ""); + } + else + { + // Check for malformed XML tags + var htmlParsed = false; + var htmlStartTag = reHTMLEmptyTag.exec(src); + + // See if there isn't an end tag within this block + var reHTMLEndTag = new RegExp(""); + var htmlEndTag = reHTMLEndTag.exec(src); + + if (XMLDOC.Parser.strictMode && htmlEndTag == null) + { + // Poorly formed XML fails in strict mode + var err = new Error("Malformed XML passed to XMLDOC.Parser... Error contains malformed 'src'"); + err.src = src; + throw err; + } + else if (htmlEndTag == null) + { + // This is an HTML-style empty tag, store the element for it in non-strict mode + parentNode.nodes.push(elem); + + // Eat the tag + src = src.replace(reHTMLEmptyTag, ""); + htmlParsed = true; + } + + // If we didn't parse HTML-style, it must be an enclosing tag + if (!htmlParsed) + { + var enc = reEnclosingTag.exec(src); + + // Go deeper into the document + XMLDOC.Parser.eat(elem, enc[6]); + + // Append the new element node + parentNode.nodes.push(elem); + + // Eat the tag + src = src.replace(reEnclosingTag, ""); + } + } + + // Reset the lastIndex of reTag + reTag.lastIndex = 0; + } + } + + // No tag was found... append the text if there is any + src = src.replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); + if (src.length > 0 && (src != "\n")) + { + var txtNode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); + txtNode.charData = src; + + // Append the new text node + parentNode.nodes.push(txtNode); + } +}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,106 @@ +/** + @overview + @date $Date: 2010-06-13 22:02:44 +0100 (Sun, 13 Jun 2010) $ + @version $Revision: 837 $ + @location $HeadURL: https://jsdoc-toolkit.googlecode.com/svn/tags/jsdoc_toolkit-2.4.0/jsdoc-toolkit/app/lib/JSDOC.js $ + @name JSDOC.js + */ + +/** + This is the main container for the JSDOC application. + @namespace +*/ +JSDOC = { +}; + +/** + @requires Opt + */ +if (typeof arguments == "undefined") arguments = []; +JSDOC.opt = Opt.get( + arguments, + { + a: "allfunctions", + c: "conf", + d: "directory", + "D[]": "define", + e: "encoding", + "E[]": "exclude", + h: "help", + m: "multiple", + n: "nocode", + o: "out", + p: "private", + q: "quiet", + r: "recurse", + S: "securemodules", + s: "suppress", + t: "template", + T: "testmode", + u: "unique", + v: "verbose", + x: "ext" + } +); + +/** The current version string of this application. */ +JSDOC.VERSION = "2.4.0"; + +/** Print out usage information and quit. */ +JSDOC.usage = function() { + print("USAGE: java -jar jsrun.jar app/run.js [OPTIONS] ..."); + print(""); + print("OPTIONS:"); + print(" -a or --allfunctions\n Include all functions, even undocumented ones.\n"); + print(" -c or --conf\n Load a configuration file.\n"); + print(" -d= or --directory=\n Output to this directory (defaults to \"out\").\n"); + print(" -D=\"myVar:My value\" or --define=\"myVar:My value\"\n Multiple. Define a variable, available in JsDoc as JSDOC.opt.D.myVar.\n"); + print(" -e= or --encoding=\n Use this encoding to read and write files.\n"); + print(" -E=\"REGEX\" or --exclude=\"REGEX\"\n Multiple. Exclude files based on the supplied regex.\n"); + print(" -h or --help\n Show this message and exit.\n"); + print(" -m or --multiples\n Don't warn about symbols being documented more than once.\n"); + print(" -n or --nocode\n Ignore all code, only document comments with @name tags.\n"); + print(" -o= or --out=\n Print log messages to a file (defaults to stdout).\n"); + print(" -p or --private\n Include symbols tagged as private, underscored and inner symbols.\n"); + print(" -q or --quiet\n Do not output any messages, not even warnings.\n"); + print(" -r= or --recurse=\n Descend into src directories.\n"); + print(" -s or --suppress\n Suppress source code output.\n"); + print(" -S or --securemodules\n Use Secure Modules mode to parse source code.\n"); + print(" -t= or --template=\n Required. Use this template to format the output.\n"); + print(" -T or --test\n Run all unit tests and exit.\n"); + print(" -u or --unique\n Force file names to be unique, but not based on symbol names.\n"); + print(" -v or --verbose\n Provide verbose feedback about what is happening.\n"); + print(" -x=[,EXT]... or --ext=[,EXT]...\n Scan source files with the given extension/s (defaults to js).\n"); + + quit(); +} + +/*t: + plan(4, "Testing JSDOC namespace."); + + is( + typeof JSDOC, + "object", + "JSDOC.usage is a function." + ); + + is( + typeof JSDOC.VERSION, + "string", + "JSDOC.VERSION is a string." + ); + + is( + typeof JSDOC.usage, + "function", + "JSDOC.usage is a function." + ); + + is( + typeof JSDOC.opt, + "object", + "JSDOC.opt is a object." + ); + */ + +if (this.IO) IO.includeDir("lib/JSDOC/"); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/DocComment.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/DocComment.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,204 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + Create a new DocComment. This takes a raw documentation comment, + and wraps it in useful accessors. + @class Represents a documentation comment object. + */ +JSDOC.DocComment = function(/**String*/comment) { + this.init(); + if (typeof comment != "undefined") { + this.parse(comment); + } +} + +JSDOC.DocComment.prototype.init = function() { + this.isUserComment = true; + this.src = ""; + this.meta = ""; + this.tagTexts = []; + this.tags = []; +} + +/** + @requires JSDOC.DocTag + */ +JSDOC.DocComment.prototype.parse = function(/**String*/comment) { + if (comment == "") { + comment = "/** @desc */"; + this.isUserComment = false; + } + + this.src = JSDOC.DocComment.unwrapComment(comment); + + this.meta = ""; + if (this.src.indexOf("#") == 0) { + this.src.match(/#(.+[+-])([\s\S]*)$/); + if (RegExp.$1) this.meta = RegExp.$1; + if (RegExp.$2) this.src = RegExp.$2; + } + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onDocCommentSrc", this); + } + + this.fixDesc(); + + this.src = JSDOC.DocComment.shared+"\n"+this.src; + + this.tagTexts = + this.src + .split(/(^|[\r\n])\s*@/) + .filter(function($){return $.match(/\S/)}); + + /** + The tags found in the comment. + @type JSDOC.DocTag[] + */ + this.tags = this.tagTexts.map(function($){return new JSDOC.DocTag($)}); + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onDocCommentTags", this); + } +} + +/*t: + plan(5, "testing JSDOC.DocComment"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/"); + is(com.tagTexts[0], "foo some\ncomment here", "first tag text is found."); + is(com.tags[0].title, "foo", "the title is found in a comment with one tag."); + + var com = new JSDOC.DocComment("/** @foo first\n* @bar second*"+"/"); + is(com.getTag("bar").length, 1, "getTag() returns one tag by that title."); + + JSDOC.DocComment.shared = "@author John Smith"; + var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/"); + is(com.tags[0].title, "author", "shared comment is added."); + is(com.tags[1].title, "foo", "shared comment is added to existing tag."); +*/ + +/** + If no @desc tag is provided, this function will add it. + */ +JSDOC.DocComment.prototype.fixDesc = function() { + if (this.meta && this.meta != "@+") return; + if (/^\s*[^@\s]/.test(this.src)) { + this.src = "@desc "+this.src; + } +} + +/*t: + plan(5, "testing JSDOC.DocComment#fixDesc"); + + var com = new JSDOC.DocComment(); + + com.src = "this is a desc\n@author foo"; + com.fixDesc(); + is(com.src, "@desc this is a desc\n@author foo", "if no @desc tag is provided one is added."); + + com.src = "x"; + com.fixDesc(); + is(com.src, "@desc x", "if no @desc tag is provided one is added to a single character."); + + com.src = "\nx"; + com.fixDesc(); + is(com.src, "@desc \nx", "if no @desc tag is provided one is added to return and character."); + + com.src = " "; + com.fixDesc(); + is(com.src, " ", "if no @desc tag is provided one is not added to just whitespace."); + + com.src = ""; + com.fixDesc(); + is(com.src, "", "if no @desc tag is provided one is not added to empty."); +*/ + +/** + Remove slash-star comment wrapper from a raw comment string. + @type String + */ +JSDOC.DocComment.unwrapComment = function(/**String*/comment) { + if (!comment) return ""; + var unwrapped = comment.replace(/(^\/\*\*|\*\/$)/g, "").replace(/^\s*\* ?/gm, ""); + return unwrapped; +} + +/*t: + plan(5, "testing JSDOC.DocComment.unwrapComment"); + + var com = "/**x*"+"/"; + var unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x", "a single character jsdoc is found."); + + com = "/***x*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x", "three stars are allowed in the opener."); + + com = "/****x*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "*x", "fourth star in the opener is kept."); + + com = "/**x\n * y\n*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x\ny\n", "leading stars and spaces are trimmed."); + + com = "/**x\n * y\n*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x\n y\n", "only first space after leading stars are trimmed."); +*/ + +/** + Provides a printable version of the comment. + @type String + */ +JSDOC.DocComment.prototype.toString = function() { + return this.src; +} + +/*t: + plan(1, "testing JSDOC.DocComment#fixDesc"); + var com = new JSDOC.DocComment(); + com.src = "foo"; + is(""+com, "foo", "stringifying a comment returns the unwrapped src."); +*/ + +/** + Given the title of a tag, returns all tags that have that title. + @type JSDOC.DocTag[] + */ +JSDOC.DocComment.prototype.getTag = function(/**String*/tagTitle) { + return this.tags.filter(function($){return $.title == tagTitle}); +} + +JSDOC.DocComment.prototype.deleteTag = function(/**String*/tagTitle) { + this.tags = this.tags.filter(function($){return $.title != tagTitle}) +} + +/*t: + plan(1, "testing JSDOC.DocComment#getTag"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var com = new JSDOC.DocComment("/**@foo some\n* @bar\n* @bar*"+"/"); + is(com.getTag("bar").length, 2, "getTag returns expected number of tags."); +*/ + +/** + Used to store the currently shared tag text. +*/ +JSDOC.DocComment.shared = ""; + +/*t: + plan(2, "testing JSDOC.DocComment.shared"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + JSDOC.DocComment.shared = "@author Michael"; + + var com = new JSDOC.DocComment("/**@foo\n* @foo*"+"/"); + is(com.getTag("author").length, 1, "getTag returns shared tag."); + is(com.getTag("foo").length, 2, "getTag returns unshared tags too."); +*/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/DocTag.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/DocTag.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,294 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor + */ +JSDOC.DocTag = function(src) { + this.init(); + if (typeof src != "undefined") { + this.parse(src); + } +} + +/** + Create and initialize the properties of this. + */ +JSDOC.DocTag.prototype.init = function() { + this.title = ""; + this.type = ""; + this.name = ""; + this.isOptional = false; + this.defaultValue = ""; + this.desc = ""; + + return this; +} + +/** + Populate the properties of this from the given tag src. + @param {string} src + */ +JSDOC.DocTag.prototype.parse = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + try { + src = this.nibbleTitle(src); + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onDocTagSynonym", this); + } + + src = this.nibbleType(src); + + // only some tags are allowed to have names. + if (this.title == "param" || this.title == "property" || this.title == "config") { // @config is deprecated + src = this.nibbleName(src); + } + } + catch(e) { + if (LOG) LOG.warn(e); + else throw e; + } + this.desc = src; // whatever is left + + // example tags need to have whitespace preserved + if (this.title != "example") this.desc = this.desc.trim(); + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onDocTag", this); + } +} + +/** + Automatically called when this is stringified. + */ +JSDOC.DocTag.prototype.toString = function() { + return this.desc; +} + +/*t: + plan(1, "testing JSDOC.DocTag#toString"); + + var tag = new JSDOC.DocTag("param {object} date A valid date."); + is(""+tag, "A valid date.", "stringifying a tag returns the desc."); + */ + +/** + Find and shift off the title of a tag. + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleTitle = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/); + + if (parts && parts[1]) this.title = parts[1]; + if (parts && parts[2]) src = parts[2]; + else src = ""; + + return src; +} + +/*t: + plan(8, "testing JSDOC.DocTag#nibbleTitle"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleTitle("aTitleGoesHere"); + is(tag.title, "aTitleGoesHere", "a title can be found in a single-word string."); + + var src = tag.init().nibbleTitle("aTitleGoesHere and the rest"); + is(tag.title, "aTitleGoesHere", "a title can be found in a multi-word string."); + is(src, "and the rest", "the rest is returned when the title is nibbled off."); + + src = tag.init().nibbleTitle(""); + is(tag.title, "", "given an empty string the title is empty."); + is(src, "", "the rest is empty when the tag is empty."); + + var src = tag.init().nibbleTitle(" aTitleGoesHere\n a description"); + is(tag.title, "aTitleGoesHere", "leading and trailing spaces are not part of the title."); + is(src, " a description", "leading spaces (less one) are part of the description."); + + tag.init().nibbleTitle("a.Title::Goes_Here foo"); + is(tag.title, "a.Title::Goes_Here", "titles with punctuation are allowed."); + */ + +/** + Find and shift off the type of a tag. + @requires frame/String.js + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleType = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + if (src.match(/^\s*\{/)) { + var typeRange = src.balance("{", "}"); + if (typeRange[1] == -1) { + throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src; + } + this.type = src.substring(typeRange[0]+1, typeRange[1]).trim(); + this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or | + src = src.substring(typeRange[1]+1); + } + + return src; +} + +/*t: + plan(5, "testing JSDOC.DocTag.parser.nibbleType"); + requires("../frame/String.js"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleType("{String[]} aliases"); + is(tag.type, "String[]", "type can have non-alpha characters."); + + tag.init().nibbleType("{ aTypeGoesHere } etc etc"); + is(tag.type, "aTypeGoesHere", "type is trimmed."); + + tag.init().nibbleType("{ oneType, twoType ,\n threeType } etc etc"); + is(tag.type, "oneType|twoType|threeType", "multiple types can be separated by commas."); + + var error; + try { tag.init().nibbleType("{widget foo"); } + catch(e) { error = e; } + is(typeof error, "string", "malformed tag type throws error."); + isnt(error.indexOf("Malformed"), -1, "error message tells tag is malformed."); + */ + +/** + Find and shift off the name of a tag. + @requires frame/String.js + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleName = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + src = src.trim(); + + // is optional? + if (src.charAt(0) == "[") { + var nameRange = src.balance("[", "]"); + if (nameRange[1] == -1) { + throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src; + } + this.name = src.substring(nameRange[0]+1, nameRange[1]).trim(); + this.isOptional = true; + + src = src.substring(nameRange[1]+1); + + // has default value? + var nameAndValue = this.name.split("="); + if (nameAndValue.length) { + this.name = nameAndValue.shift().trim(); + this.defaultValue = nameAndValue.join("="); + } + } + else { + var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/); + if (parts) { + if (parts[1]) this.name = parts[1]; + if (parts[2]) src = parts[2].trim(); + else src = ""; + } + } + + return src; +} + +/*t: + requires("../frame/String.js"); + plan(9, "testing JSDOC.DocTag.parser.nibbleName"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleName("[foo] This is a description."); + is(tag.isOptional, true, "isOptional syntax is detected."); + is(tag.name, "foo", "optional param name is found."); + + tag.init().nibbleName("[foo] This is a description."); + is(tag.isOptional, true, "isOptional syntax is detected when no type."); + is(tag.name, "foo", "optional param name is found when no type."); + + tag.init().nibbleName("[foo=7] This is a description."); + is(tag.name, "foo", "optional param name is found when default value."); + is(tag.defaultValue, 7, "optional param default value is found when default value."); + + //tag.init().nibbleName("[foo= a value] This is a description."); + //is(tag.defaultValue, " a value", "optional param default value is found when default value has spaces (issue #112)."); + + tag.init().nibbleName("[foo=[]] This is a description."); + is(tag.defaultValue, "[]", "optional param default value is found when default value is [] (issue #95)."); + + tag.init().nibbleName("[foo=a=b] This is a description."); + is(tag.name, "foo", "optional param name is found when default value is a=b."); + is(tag.defaultValue, "a=b", "optional param default value is found when default value is a=b.") + */ + +/*t: + plan(32, "Testing JSDOC.DocTag.parser."); + requires("../frame/String.js"); + + var tag = new JSDOC.DocTag(); + + is(typeof tag, "object", "JSDOC.DocTag.parser with an empty string returns an object."); + is(typeof tag.title, "string", "returned object has a string property 'title'."); + is(typeof tag.type, "string", "returned object has a string property 'type'."); + is(typeof tag.name, "string", "returned object has a string property 'name'."); + is(typeof tag.defaultValue, "string", "returned object has a string property 'defaultValue'."); + is(typeof tag.isOptional, "boolean", "returned object has a boolean property 'isOptional'."); + is(typeof tag.desc, "string", "returned object has a string property 'desc'."); + + tag = new JSDOC.DocTag("param {widget} foo"); + is(tag.title, "param", "param title is found."); + is(tag.name, "foo", "param name is found when desc is missing."); + is(tag.desc, "", "param desc is empty when missing."); + + tag = new JSDOC.DocTag("param {object} date A valid date."); + is(tag.name, "date", "param name is found with a type."); + is(tag.type, "object", "param type is found."); + is(tag.desc, "A valid date.", "param desc is found with a type."); + + tag = new JSDOC.DocTag("param aName a description goes\n here."); + is(tag.name, "aName", "param name is found without a type."); + is(tag.desc, "a description goes\n here.", "param desc is found without a type."); + + tag = new JSDOC.DocTag("param {widget}"); + is(tag.name, "", "param name is empty when it is not given."); + + tag = new JSDOC.DocTag("param {widget} [foo] This is a description."); + is(tag.name, "foo", "optional param name is found."); + + tag = new JSDOC.DocTag("return {aType} This is a description."); + is(tag.type, "aType", "when return tag has no name, type is found."); + is(tag.desc, "This is a description.", "when return tag has no name, desc is found."); + + tag = new JSDOC.DocTag("author Joe Coder "); + is(tag.title, "author", "author tag has a title."); + is(tag.type, "", "the author tag has no type."); + is(tag.name, "", "the author tag has no name."); + is(tag.desc, "Joe Coder ", "author tag has desc."); + + tag = new JSDOC.DocTag("private \t\n "); + is(tag.title, "private", "private tag has a title."); + is(tag.type, "", "the private tag has no type."); + is(tag.name, "", "the private tag has no name."); + is(tag.desc, "", "private tag has no desc."); + + tag = new JSDOC.DocTag("example\n example(code);\n more();"); + is(tag.desc, " example(code);\n more();", "leading whitespace (less one) in examples code is preserved."); + + tag = new JSDOC.DocTag("param theName \n"); + is(tag.name, "theName", "name only is found."); + + tag = new JSDOC.DocTag("type theDesc \n"); + is(tag.desc, "theDesc", "desc only is found."); + + tag = new JSDOC.DocTag("type {theType} \n"); + is(tag.type, "theType", "type only is found."); + + tag = new JSDOC.DocTag(""); + is(tag.title, "", "title is empty when tag is empty."); + */ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/JsDoc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/JsDoc.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,140 @@ +/** + @constructor + @param [opt] Used to override the commandline options. Useful for testing. + @version $Id: JsDoc.js 831 2010-03-09 14:24:56Z micmath $ +*/ +JSDOC.JsDoc = function(/**object*/ opt) { + if (opt) { + JSDOC.opt = opt; + } + + if (JSDOC.opt.h) { + JSDOC.usage(); + quit(); + } + + // defend against options that are not sane + if (JSDOC.opt._.length == 0) { + LOG.warn("No source files to work on. Nothing to do."); + quit(); + } + if (JSDOC.opt.t === true || JSDOC.opt.d === true) { + JSDOC.usage(); + } + + if (typeof JSDOC.opt.d == "string") { + if (!JSDOC.opt.d.charAt(JSDOC.opt.d.length-1).match(/[\\\/]/)) { + JSDOC.opt.d = JSDOC.opt.d+"/"; + } + LOG.inform("Output directory set to '"+JSDOC.opt.d+"'."); + IO.mkPath(JSDOC.opt.d); + } + if (JSDOC.opt.e) IO.setEncoding(JSDOC.opt.e); + + // the -r option: scan source directories recursively + if (typeof JSDOC.opt.r == "boolean") JSDOC.opt.r = 10; + else if (!isNaN(parseInt(JSDOC.opt.r))) JSDOC.opt.r = parseInt(JSDOC.opt.r); + else JSDOC.opt.r = 1; + + // the -D option: define user variables + var D = {}; + if (JSDOC.opt.D) { + for (var i = 0; i < JSDOC.opt.D.length; i++) { + var param = JSDOC.opt.D[i]; + // remove first and last character if both == " + if ( + param.length > 1 + && param.charAt(0) == '"' + && param.charAt(param.length-1) == '"' + ) { + param = param.substr(1, param.length-2); + } + var defineParts = param.split(":"); + if (defineParts && defineParts.length > 1) { + for ( var dpIdx = 2; dpIdx < defineParts.length; dpIdx++ ) { + defineParts[1] += ':' + defineParts[dpIdx]; + } + D[defineParts[0]] = defineParts[1]; + } + } + } + JSDOC.opt.D = D; + // combine any conf file D options with the commandline D options + if (defined(JSDOC.conf)) for (var c in JSDOC.conf.D) { + if (!defined(JSDOC.opt.D[c])) { + JSDOC.opt.D[c] = JSDOC.conf.D[c]; + } + } + + // Give plugins a chance to initialize + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onInit", JSDOC.opt); + } + + JSDOC.opt.srcFiles = JSDOC.JsDoc._getSrcFiles(); + JSDOC.JsDoc._parseSrcFiles(); + JSDOC.JsDoc.symbolSet = JSDOC.Parser.symbols; +} + +/** + Retrieve source file list. + @returns {String[]} The pathnames of the files to be parsed. + */ +JSDOC.JsDoc._getSrcFiles = function() { + JSDOC.JsDoc.srcFiles = []; + + var ext = ["js"]; + if (JSDOC.opt.x) { + ext = JSDOC.opt.x.split(",").map(function($) {return $.toLowerCase()}); + } + + for (var i = 0; i < JSDOC.opt._.length; i++) { + JSDOC.JsDoc.srcFiles = JSDOC.JsDoc.srcFiles.concat( + IO.ls(JSDOC.opt._[i], JSDOC.opt.r).filter( + function($) { + var thisExt = $.split(".").pop().toLowerCase(); + + if (JSDOC.opt.E) { + for(var n = 0; n < JSDOC.opt.E.length; n++) { + if ($.match(new RegExp(JSDOC.opt.E[n]))) { + LOG.inform("Excluding " + $); + return false; // if the file matches the regex then it's excluded. + } + } + } + + return (ext.indexOf(thisExt) > -1); // we're only interested in files with certain extensions + } + ) + ); + } + + return JSDOC.JsDoc.srcFiles; +} + +JSDOC.JsDoc._parseSrcFiles = function() { + JSDOC.Parser.init(); + for (var i = 0, l = JSDOC.JsDoc.srcFiles.length; i < l; i++) { + var srcFile = JSDOC.JsDoc.srcFiles[i]; + + if (JSDOC.opt.v) LOG.inform("Parsing file: " + srcFile); + + try { + var src = IO.readFile(srcFile); + } + catch(e) { + LOG.warn("Can't read source file '"+srcFile+"': "+e.message); + } + + var tr = new JSDOC.TokenReader(); + var ts = new JSDOC.TokenStream(tr.tokenize(new JSDOC.TextStream(src))); + + JSDOC.Parser.parse(ts, srcFile); + + } + JSDOC.Parser.finish(); + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onFinishedParsing", JSDOC.Parser.symbols); + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/JsPlate.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/JsPlate.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,109 @@ +/** + @constructor +*/ +JSDOC.JsPlate = function(templateFile) { + if (templateFile) this.template = IO.readFile(templateFile); + + this.templateFile = templateFile; + this.code = ""; + this.parse(); +} + +JSDOC.JsPlate.prototype.parse = function() { + this.template = this.template.replace(/\{#[\s\S]+?#\}/gi, ""); + this.code = "var output=\u001e"+this.template; + + this.code = this.code.replace( + //gi, + function (match, eachName, inName) { + return "\u001e;\rvar $"+eachName+"_keys = keys("+inName+");\rfor(var $"+eachName+"_i = 0; $"+eachName+"_i < $"+eachName+"_keys.length; $"+eachName+"_i++) {\rvar $"+eachName+"_last = ($"+eachName+"_i == $"+eachName+"_keys.length-1);\rvar $"+eachName+"_key = $"+eachName+"_keys[$"+eachName+"_i];\rvar "+eachName+" = "+inName+"[$"+eachName+"_key];\routput+=\u001e"; + } + ); + this.code = this.code.replace(//g, "\u001e;\rif ($1) { output+=\u001e"); + this.code = this.code.replace(//g, "\u001e;}\relse if ($1) { output+=\u001e"); + this.code = this.code.replace(//g, "\u001e;}\relse { output+=\u001e"); + this.code = this.code.replace(/<\/(if|for)>/g, "\u001e;\r};\routput+=\u001e"); + this.code = this.code.replace( + /\{\+\s*([\s\S]+?)\s*\+\}/gi, + function (match, code) { + code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code + code = code.replace(/(\r?\n)/g, " "); + return "\u001e+ ("+code+") +\u001e"; + } + ); + this.code = this.code.replace( + /\{!\s*([\s\S]+?)\s*!\}/gi, + function (match, code) { + code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code + code = code.replace(/(\n)/g, " "); + return "\u001e; "+code+";\routput+=\u001e"; + } + ); + this.code = this.code+"\u001e;"; + + this.code = this.code.replace(/(\r?\n)/g, "\\n"); + this.code = this.code.replace(/"/g, "\\\""); + this.code = this.code.replace(/\u001e/g, "\""); +} + +JSDOC.JsPlate.prototype.toCode = function() { + return this.code; +} + +JSDOC.JsPlate.keys = function(obj) { + var keys = []; + if (obj.constructor.toString().indexOf("Array") > -1) { + for (var i = 0; i < obj.length; i++) { + keys.push(i); + } + } + else { + for (var i in obj) { + keys.push(i); + } + } + return keys; +}; + +JSDOC.JsPlate.values = function(obj) { + var values = []; + if (obj.constructor.toString().indexOf("Array") > -1) { + for (var i = 0; i < obj.length; i++) { + values.push(obj[i]); + } + } + else { + for (var i in obj) { + values.push(obj[i]); + } + } + return values; +}; + +JSDOC.JsPlate.prototype.process = function(data, compact) { + var keys = JSDOC.JsPlate.keys; + var values = JSDOC.JsPlate.values; + + try { + eval(this.code); + } + catch (e) { + print(">> There was an error evaluating the compiled code from template: "+this.templateFile); + print(" The error was on line "+e.lineNumber+" "+e.name+": "+e.message); + var lines = this.code.split("\r"); + if (e.lineNumber-2 >= 0) print("line "+(e.lineNumber-1)+": "+lines[e.lineNumber-2]); + print("line "+e.lineNumber+": "+lines[e.lineNumber-1]); + print(""); + } + + if (compact) { // patch by mcbain.asm + // Remove lines that contain only space-characters, usually left by lines in the template + // which originally only contained JSPlate tags or code. This makes it easier to write + // non-tricky templates which still put out nice code (not bloated with extra lines). + // Lines purposely left blank (just a line ending) are left alone. + output = output.replace(/\s+?(\r?)\n/g, "$1\n"); + } + + /*debug*///print(this.code); + return output; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Lang.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Lang.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,144 @@ +/** + @namespace +*/ +JSDOC.Lang = { +} + +JSDOC.Lang.isBuiltin = function(name) { + return (JSDOC.Lang.isBuiltin.coreObjects.indexOf(name) > -1); +} +JSDOC.Lang.isBuiltin.coreObjects = ['_global_', 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String']; + +JSDOC.Lang.whitespace = function(ch) { + return JSDOC.Lang.whitespace.names[ch]; +} +JSDOC.Lang.whitespace.names = { + " ": "SPACE", + "\f": "FORMFEED", + "\t": "TAB", + "\u0009": "UNICODE_TAB", + "\u000A": "UNICODE_NBR", + "\u0008": "VERTICAL_TAB" +}; + +JSDOC.Lang.newline = function(ch) { + return JSDOC.Lang.newline.names[ch]; +} +JSDOC.Lang.newline.names = { + "\n": "NEWLINE", + "\r": "RETURN", + "\u000A": "UNICODE_LF", + "\u000D": "UNICODE_CR", + "\u2029": "UNICODE_PS", + "\u2028": "UNICODE_LS" +}; + +JSDOC.Lang.keyword = function(word) { + return JSDOC.Lang.keyword.names["="+word]; +} +JSDOC.Lang.keyword.names = { + "=break": "BREAK", + "=case": "CASE", + "=catch": "CATCH", + "=const": "VAR", + "=continue": "CONTINUE", + "=default": "DEFAULT", + "=delete": "DELETE", + "=do": "DO", + "=else": "ELSE", + "=false": "FALSE", + "=finally": "FINALLY", + "=for": "FOR", + "=function": "FUNCTION", + "=if": "IF", + "=in": "IN", + "=instanceof": "INSTANCEOF", + "=new": "NEW", + "=null": "NULL", + "=return": "RETURN", + "=switch": "SWITCH", + "=this": "THIS", + "=throw": "THROW", + "=true": "TRUE", + "=try": "TRY", + "=typeof": "TYPEOF", + "=void": "VOID", + "=while": "WHILE", + "=with": "WITH", + "=var": "VAR" +}; + +JSDOC.Lang.punc = function(ch) { + return JSDOC.Lang.punc.names[ch]; +} +JSDOC.Lang.punc.names = { + ";": "SEMICOLON", + ",": "COMMA", + "?": "HOOK", + ":": "COLON", + "||": "OR", + "&&": "AND", + "|": "BITWISE_OR", + "^": "BITWISE_XOR", + "&": "BITWISE_AND", + "===": "STRICT_EQ", + "==": "EQ", + "=": "ASSIGN", + "!==": "STRICT_NE", + "!=": "NE", + "<<": "LSH", + "<=": "LE", + "<": "LT", + ">>>": "URSH", + ">>": "RSH", + ">=": "GE", + ">": "GT", + "++": "INCREMENT", + "--": "DECREMENT", + "+": "PLUS", + "-": "MINUS", + "*": "MUL", + "/": "DIV", + "%": "MOD", + "!": "NOT", + "~": "BITWISE_NOT", + ".": "DOT", + "[": "LEFT_BRACKET", + "]": "RIGHT_BRACKET", + "{": "LEFT_CURLY", + "}": "RIGHT_CURLY", + "(": "LEFT_PAREN", + ")": "RIGHT_PAREN" +}; + +JSDOC.Lang.matching = function(name) { + return JSDOC.Lang.matching.names[name]; +} +JSDOC.Lang.matching.names = { + "LEFT_PAREN": "RIGHT_PAREN", + "RIGHT_PAREN": "LEFT_PAREN", + "LEFT_CURLY": "RIGHT_CURLY", + "RIGHT_CURLY": "LEFT_CURLY", + "LEFT_BRACE": "RIGHT_BRACE", + "RIGHT_BRACE": "LEFT_BRACE" +} + +JSDOC.Lang.isNumber = function(str) { + return /^(\.[0-9]|[0-9]+\.|[0-9])[0-9]*([eE][+-][0-9]+)?$/i.test(str); +} + +JSDOC.Lang.isHexDec = function(str) { + return /^0x[0-9A-F]+$/i.test(str); +} + +JSDOC.Lang.isWordChar = function(str) { + return /^[a-zA-Z0-9$_.]+$/.test(str); +} + +JSDOC.Lang.isSpace = function(str) { + return (typeof JSDOC.Lang.whitespace(str) != "undefined"); +} + +JSDOC.Lang.isNewline = function(str) { + return (typeof JSDOC.Lang.newline(str) != "undefined"); +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Parser.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Parser.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,146 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @namespace + @requires JSDOC.Walker + @requires JSDOC.Symbol + @requires JSDOC.DocComment +*/ +JSDOC.Parser = { + conf: { + ignoreCode: JSDOC.opt.n, + ignoreAnonymous: true, // factory: true + treatUnderscoredAsPrivate: true, // factory: true + explain: false // factory: false + }, + + addSymbol: function(symbol) { + + if (JSDOC.Parser.rename) { + for (var n in JSDOC.Parser.rename) { + if (symbol.alias.indexOf(n) == 0) { + if (symbol.name == symbol.alias) { + symbol.name = symbol.name.replace(n, JSDOC.Parser.rename[n]); + } + symbol.alias = symbol.alias.replace(n, JSDOC.Parser.rename[n]); + } + } + } + + if (JSDOC.opt.S) { + if (typeof JSDOC.Parser.secureModules == "undefined") JSDOC.Parser.secureModules = {}; + if (/^exports\./.test(symbol.alias)) { + symbol.srcFile.match(/(^|[\\\/])([^\\\/]+)\.js/i); + var fileNS = RegExp.$2; + + // need to create the namespace associated with this file first + if (!JSDOC.Parser.secureModules[fileNS]) { + JSDOC.Parser.secureModules[fileNS] = 1; + var nsSymbol = new JSDOC.Symbol(fileNS, [], "GLOBAL", new JSDOC.DocComment("")); + nsSymbol.isNamespace = true; + nsSymbol.srcFile = ""; + nsSymbol.isPrivate = false; + nsSymbol.srcFile = symbol.srcFile; + nsSymbol.desc = (JSDOC.Parser.symbols.getSymbol(symbol.srcFile) || {desc: ""}).desc; + JSDOC.Parser.addSymbol(nsSymbol); + } + + symbol.alias = symbol.alias.replace(/^exports\./, fileNS + '.'); + symbol.name = symbol.name.replace(/^exports\./, ''); + symbol.memberOf = fileNS; + symbol.isStatic = true; + } + } + + // if a symbol alias is documented more than once the first one with the user docs wins + if (JSDOC.Parser.symbols.hasSymbol(symbol.alias)) { + var oldSymbol = JSDOC.Parser.symbols.getSymbol(symbol.alias); + if (oldSymbol.comment.isUserComment) { + if (JSDOC.opt.m) return; + if (symbol.comment.isUserComment) { // old and new are both documented + LOG.warn("The symbol '"+symbol.alias+"' is documented more than once."); + return; + } + else { // old is documented but new isn't + return; + } + } + } + + // we don't document anonymous things + if (JSDOC.Parser.conf.ignoreAnonymous && symbol.name.match(/\$anonymous\b/)) return; + + // uderscored things may be treated as if they were marked private, this cascades + if (JSDOC.Parser.conf.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) { + if (!symbol.comment.getTag("public").length > 0) symbol.isPrivate = true; + } + + // -p flag is required to document private things + if (!JSDOC.opt.p && symbol.isPrivate) return; // issue #161 fixed by mcbain.asm + + // ignored things are not documented, this doesn't cascade + if (symbol.isIgnored) return; + JSDOC.Parser.symbols.addSymbol(symbol); + }, + + addBuiltin: function(name) { + var builtin = new JSDOC.Symbol(name, [], "CONSTRUCTOR", new JSDOC.DocComment("")); + builtin.isNamespace = true; + builtin.srcFile = ""; + builtin.isPrivate = false; + JSDOC.Parser.addSymbol(builtin); + return builtin; + }, + + init: function() { + JSDOC.Parser.symbols = new JSDOC.SymbolSet(); + JSDOC.Parser.walker = new JSDOC.Walker(); + }, + + finish: function() { + JSDOC.Parser.symbols.relate(); + + // make a litle report about what was found + if (JSDOC.Parser.conf.explain) { + var symbols = JSDOC.Parser.symbols.toArray(); + var srcFile = ""; + for (var i = 0, l = symbols.length; i < l; i++) { + var symbol = symbols[i]; + if (srcFile != symbol.srcFile) { + srcFile = symbol.srcFile; + print("\n"+srcFile+"\n-------------------"); + } + print(i+":\n alias => "+symbol.alias + "\n name => "+symbol.name+ "\n isa => "+symbol.isa + "\n memberOf => " + symbol.memberOf + "\n isStatic => " + symbol.isStatic + ", isInner => " + symbol.isInner+ ", isPrivate => " + symbol.isPrivate); + } + print("-------------------\n"); + } + } +} + +JSDOC.Parser.parse = function(/**JSDOC.TokenStream*/ts, /**String*/srcFile) { + JSDOC.Symbol.srcFile = (srcFile || ""); + JSDOC.DocComment.shared = ""; // shared comments don't cross file boundaries + + if (!JSDOC.Parser.walker) JSDOC.Parser.init(); + JSDOC.Parser.walker.walk(ts); // adds to our symbols + + // filter symbols by option + for (var p = JSDOC.Parser.symbols._index.first(); p; p = JSDOC.Parser.symbols._index.next()) { + var symbol = p.value; + + if (!symbol) continue; + + if (symbol.is("FILE") || symbol.is("GLOBAL")) { + continue; + } + else if (!JSDOC.opt.a && !symbol.comment.isUserComment) { + JSDOC.Parser.symbols.deleteSymbol(symbol.alias); + } + + if (/#$/.test(symbol.alias)) { // we don't document prototypes + JSDOC.Parser.symbols.deleteSymbol(symbol.alias); + } + } + + return JSDOC.Parser.symbols.toArray(); +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/PluginManager.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/PluginManager.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,33 @@ +/** + @namespace Holds functionality related to running plugins. +*/ +JSDOC.PluginManager = { +} + +/** + @param name A unique name that identifies that plugin. + @param handlers A collection of named functions. The names correspond to hooks in the core code. +*/ +JSDOC.PluginManager.registerPlugin = function(/**String*/name, /**Object*/handlers) { + if (!defined(JSDOC.PluginManager.plugins)) + /** The collection of all plugins. Requires a unique name for each. + */ + JSDOC.PluginManager.plugins = {}; + + + JSDOC.PluginManager.plugins[name] = handlers; +} + +/** + @param hook The name of the hook that is being caught. + @param target Any object. This will be passed as the only argument to the handler whose + name matches the hook name. Handlers cannot return a value, so must modify the target + object to have an effect. +*/ +JSDOC.PluginManager.run = function(/**String*/hook, /**Mixed*/target) { + for (var name in JSDOC.PluginManager.plugins) { + if (defined(JSDOC.PluginManager.plugins[name][hook])) { + JSDOC.PluginManager.plugins[name][hook](target); + } + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Symbol.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Symbol.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,644 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + Create a new Symbol. + @class Represents a symbol in the source code. + */ +JSDOC.Symbol = function() { + this.init(); + if (arguments.length) this.populate.apply(this, arguments); +} + +JSDOC.Symbol.count = 0; + +JSDOC.Symbol.prototype.init = function() { + this._name = ""; + this._params = []; + this.$args = []; + this.addOn = ""; + this.alias = ""; + this.augments = []; + this.author = ""; + this.classDesc = ""; + this.comment = {}; + this.defaultValue = undefined; + this.deprecated = ""; + this.desc = ""; + this.example = []; + this.exceptions = []; + this.fires = []; + this.id = JSDOC.Symbol.count++; + this.inherits = []; + this.inheritsFrom = []; + this.isa = "OBJECT"; + this.isConstant = false; + this.isEvent = false; + this.isIgnored = false; + this.isInner = false; + this.isNamespace = false; + this.isPrivate = false; + this.isStatic = false; + this.memberOf = ""; + this.methods = []; + this.properties = []; + this.requires = []; + this.returns = []; + this.see = []; + this.since = ""; + this.srcFile = {}; + this.type = ""; + this.version = ""; +} + +JSDOC.Symbol.prototype.serialize = function() { + var keys = []; + for (var p in this) { + keys.push (p); + } + keys = keys.sort(); + + var out = ""; + for (var i in keys) { + if (typeof this[keys[i]] == "function") continue; + out += keys[i]+" => "+Dumper.dump(this[keys[i]])+",\n"; + } + return "\n{\n" + out + "}\n"; +} + +JSDOC.Symbol.prototype.clone = function() { + var clone = new JSDOC.Symbol(); + clone.populate.apply(clone, this.$args); // repopulate using the original arguments + clone.srcFile = this.srcFile; // not the current srcFile, the one when the original was made + return clone; +} + +JSDOC.Symbol.prototype.__defineSetter__("name", + function(n) { n = n.replace(/^_global_[.#-]/, ""); n = n.replace(/\.prototype\.?/g, '#'); this._name = n; } +); +JSDOC.Symbol.prototype.__defineGetter__("name", + function() { return this._name; } +); +JSDOC.Symbol.prototype.__defineSetter__("params", + function(v) { + for (var i = 0, l = v.length; i < l; i++) { + if (v[i].constructor != JSDOC.DocTag) { // may be a generic object parsed from signature, like {type:..., name:...} + this._params[i] = new JSDOC.DocTag("param"+((v[i].type)?" {"+v[i].type+"}":"")+" "+v[i].name); + } + else { + this._params[i] = v[i]; + } + } + } +); +JSDOC.Symbol.prototype.__defineGetter__("params", + function() { return this._params; } +); + +JSDOC.Symbol.prototype.getEvents = function() { + var events = []; + for (var i = 0, l = this.methods.length; i < l; i++) { + if (this.methods[i].isEvent) { + this.methods[i].name = this.methods[i].name.replace("event:", ""); + events.push(this.methods[i]); + } + } + return events; +} + +JSDOC.Symbol.prototype.getMethods = function() { + var nonEvents = []; + for (var i = 0, l = this.methods.length; i < l; i++) { + if (!this.methods[i].isEvent) { + nonEvents.push(this.methods[i]); + } + } + return nonEvents; +} + + +JSDOC.Symbol.prototype.populate = function( + /** String */ name, + /** Object[] */ params, + /** String */ isa, + /** JSDOC.DocComment */ comment +) { + this.$args = arguments; + + this.name = name; + this.alias = this.name; + + this.params = params; + this.isa = (isa == "VIRTUAL")? "OBJECT":isa; + this.comment = comment || new JSDOC.DocComment(""); + this.srcFile = JSDOC.Symbol.srcFile; + + if (this.is("FILE") && !this.alias) this.alias = this.srcFile; + + this.setTags(); + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onSymbol", this); + } +} + +JSDOC.Symbol.prototype.setTags = function() { + // @author + var authors = this.comment.getTag("author"); + if (authors.length) { + this.author = authors.map(function($){return $.desc;}).join(", "); + } + + /*t: + plan(34, "testing JSDOC.Symbol"); + + requires("../lib/JSDOC/DocComment.js"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@author Joe Smith*"+"/")); + is(sym.author, "Joe Smith", "@author tag, author is found."); + */ + + // @desc + var descs = this.comment.getTag("desc"); + if (descs.length) { + this.desc = descs.map(function($){return $.desc;}).join("\n"); // multiple descriptions are concatenated into one + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@desc This is a description.*"+"/")); + is(sym.desc, "This is a description.", "@desc tag, description is found."); + */ + + // @overview + if (this.is("FILE")) { + if (!this.alias) this.alias = this.srcFile; + + var overviews = this.comment.getTag("overview"); + if (overviews.length) { + this.desc = [this.desc].concat(overviews.map(function($){return $.desc;})).join("\n"); + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@overview This is an overview.*"+"/")); + is(sym.desc, "\nThis is an overview.", "@overview tag, description is found."); + */ + + // @since + var sinces = this.comment.getTag("since"); + if (sinces.length) { + this.since = sinces.map(function($){return $.desc;}).join(", "); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@since 1.01*"+"/")); + is(sym.since, "1.01", "@since tag, description is found."); + */ + + // @constant + if (this.comment.getTag("constant").length) { + this.isConstant = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@constant*"+"/")); + is(sym.isConstant, true, "@constant tag, isConstant set."); + */ + + // @version + var versions = this.comment.getTag("version"); + if (versions.length) { + this.version = versions.map(function($){return $.desc;}).join(", "); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@version 2.0x*"+"/")); + is(sym.version, "2.0x", "@version tag, version is found."); + */ + + // @deprecated + var deprecateds = this.comment.getTag("deprecated"); + if (deprecateds.length) { + this.deprecated = deprecateds.map(function($){return $.desc;}).join("\n"); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@deprecated Use other method.*"+"/")); + is(sym.deprecated, "Use other method.", "@deprecated tag, desc is found."); + */ + + // @example + var examples = this.comment.getTag("example"); + if (examples.length) { + this.example = examples.map( + // trim trailing whitespace + function($) { + $.desc = $.desc.replace(/\s+$/, ""); + return $; + } + ); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@example This\n is an example. \n*"+"/")); + isnt(typeof sym.example[0], "undefined", "@example tag, creates sym.example array."); + is(sym.example[0], "This\n is an example.", "@example tag, desc is found."); + */ + + // @see + var sees = this.comment.getTag("see"); + if (sees.length) { + var thisSee = this.see; + sees.map(function($){thisSee.push($.desc);}); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@see The other thing.*"+"/")); + is(sym.see, "The other thing.", "@see tag, desc is found."); + */ + + // @class + var classes = this.comment.getTag("class"); + if (classes.length) { + this.isa = "CONSTRUCTOR"; + this.classDesc = classes[0].desc; // desc can't apply to the constructor as there is none. + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@class This describes the class.*"+"/")); + is(sym.isa, "CONSTRUCTOR", "@class tag, makes symbol a constructor."); + is(sym.classDesc, "This describes the class.", "@class tag, class description is found."); + */ + + // @namespace + var namespaces = this.comment.getTag("namespace"); + if (namespaces.length) { + this.classDesc = namespaces[0].desc; + this.isNamespace = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@namespace This describes the namespace.*"+"/")); + is(sym.classDesc, "This describes the namespace.", "@namespace tag, class description is found."); + */ + + // @param + var params = this.comment.getTag("param"); + if (params.length) { + // user-defined params overwrite those with same name defined by the parser + var thisParams = this.params; + + if (thisParams.length == 0) { // none exist yet, so just bung all these user-defined params straight in + this.params = params; + } + else { // need to overlay these user-defined params on to existing parser-defined params + for (var i = 0, l = params.length; i < l; i++) { + if (thisParams[i]) { + if (params[i].type) thisParams[i].type = params[i].type; + thisParams[i].name = params[i].name; + thisParams[i].desc = params[i].desc; + thisParams[i].isOptional = params[i].isOptional; + thisParams[i].defaultValue = params[i].defaultValue; + } + else thisParams[i] = params[i]; + } + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.*"+"/")); + is(sym.params.length, 1, "parser defined param is found."); + + sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages*"+"/")); + is(sym.params.length, 1, "user defined param is found."); + is(sym.params[0].type, "array", "user defined param type is found."); + is(sym.params[0].name, "pages", "user defined param name is found."); + + sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/")); + is(sym.params.length, 1, "user defined param overwrites parser defined param."); + is(sym.params[0].type, "string", "user defined param type overwrites parser defined param type."); + is(sym.params[0].name, "uid", "user defined param name overwrites parser defined param name."); + + sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}, {type: "number", name: "count"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/")); + is(sym.params.length, 2, "user defined params overlay parser defined params."); + is(sym.params[1].type, "number", "user defined param type overlays parser defined param type."); + is(sym.params[1].name, "count", "user defined param name overlays parser defined param name."); + + sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages The pages description.*"+"/")); + is(sym.params.length, 1, "user defined param with description is found."); + is(sym.params[0].desc, "The pages description.", "user defined param description is found."); + */ + + // @constructor + if (this.comment.getTag("constructor").length) { + this.isa = "CONSTRUCTOR"; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@constructor*"+"/")); + is(sym.isa, "CONSTRUCTOR", "@constructor tag, makes symbol a constructor."); + */ + + // @static + if (this.comment.getTag("static").length) { + this.isStatic = true; + if (this.isa == "CONSTRUCTOR") { + this.isNamespace = true; + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@static\n@constructor*"+"/")); + is(sym.isStatic, true, "@static tag, makes isStatic true."); + is(sym.isNamespace, true, "@static and @constructor tag, makes isNamespace true."); + */ + + // @inner + if (this.comment.getTag("inner").length) { + this.isInner = true; + this.isStatic = false; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@inner*"+"/")); + is(sym.isStatic, false, "@inner tag, makes isStatic false."); + is(sym.isInner, true, "@inner makes isInner true."); + */ + + // @name + var names = this.comment.getTag("name"); + if (names.length) { + this.name = names[0].desc; + } + + /*t: + // todo + */ + + // @field + if (this.comment.getTag("field").length) { + this.isa = "OBJECT"; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**@field*"+"/")); + is(sym.isa, "OBJECT", "@field tag, makes symbol an object."); + */ + + // @function + if (this.comment.getTag("function").length) { + this.isa = "FUNCTION"; + if (/event:/.test(this.alias)) this.isEvent = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@function*"+"/")); + is(sym.isa, "FUNCTION", "@function tag, makes symbol a function."); + */ + + // @event + var events = this.comment.getTag("event"); + if (events.length) { + this.isa = "FUNCTION"; + this.isEvent = true; + if (!/event:/.test(this.alias)) + this.alias = this.alias.replace(/^(.*[.#-])([^.#-]+)$/, "$1event:$2"); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@event*"+"/")); + is(sym.isa, "FUNCTION", "@event tag, makes symbol a function."); + is(sym.isEvent, true, "@event makes isEvent true."); + */ + + // @fires + var fires = this.comment.getTag("fires"); + if (fires.length) { + for (var i = 0; i < fires.length; i++) { + this.fires.push(fires[i].desc); + } + } + + /*t: + // todo + */ + + // @property + var properties = this.comment.getTag("property"); + if (properties.length) { + thisProperties = this.properties; + for (var i = 0; i < properties.length; i++) { + var property = new JSDOC.Symbol(this.alias+"#"+properties[i].name, [], "OBJECT", new JSDOC.DocComment("/**"+properties[i].desc+"*/")); + // TODO: shouldn't the following happen in the addProperty method of Symbol? + if (properties[i].type) property.type = properties[i].type; + if (properties[i].defaultValue) property.defaultValue = properties[i].defaultValue; + this.addProperty(property); + if (!JSDOC.Parser.symbols.getSymbolByName(property.name)) + JSDOC.Parser.addSymbol(property); + } + } + + /*t: + // todo + */ + + // @return + var returns = this.comment.getTag("return"); + if (returns.length) { // there can be many return tags in a single doclet + this.returns = returns; + this.type = returns.map(function($){return $.type}).join(", "); + } + + /*t: + // todo + */ + + // @exception + this.exceptions = this.comment.getTag("throws"); + + /*t: + // todo + */ + + // @requires + var requires = this.comment.getTag("requires"); + if (requires.length) { + this.requires = requires.map(function($){return $.desc}); + } + + /*t: + // todo + */ + + // @type + var types = this.comment.getTag("type"); + if (types.length) { + this.type = types[0].desc; //multiple type tags are ignored + } + + /*t: + // todo + */ + + // @private + if (this.comment.getTag("private").length || this.isInner) { + this.isPrivate = true; + } + + // @ignore + if (this.comment.getTag("ignore").length) { + this.isIgnored = true; + } + + /*t: + // todo + */ + + // @inherits ... as ... + var inherits = this.comment.getTag("inherits"); + if (inherits.length) { + for (var i = 0; i < inherits.length; i++) { + if (/^\s*([a-z$0-9_.#:-]+)(?:\s+as\s+([a-z$0-9_.#:-]+))?/i.test(inherits[i].desc)) { + var inAlias = RegExp.$1; + var inAs = RegExp.$2 || inAlias; + + if (inAlias) inAlias = inAlias.replace(/\.prototype\.?/g, "#"); + + if (inAs) { + inAs = inAs.replace(/\.prototype\.?/g, "#"); + inAs = inAs.replace(/^this\.?/, "#"); + } + + if (inAs.indexOf(inAlias) != 0) { //not a full namepath + var joiner = "."; + if (this.alias.charAt(this.alias.length-1) == "#" || inAs.charAt(0) == "#") { + joiner = ""; + } + inAs = this.alias + joiner + inAs; + } + } + this.inherits.push({alias: inAlias, as: inAs}); + } + } + + /*t: + // todo + */ + + // @augments + this.augments = this.comment.getTag("augments"); + + // @default + var defaults = this.comment.getTag("default"); + if (defaults.length) { + if (this.is("OBJECT")) { + this.defaultValue = defaults[0].desc; + } + } + + /*t: + // todo + */ + + // @memberOf + var memberOfs = this.comment.getTag("memberOf"); + if (memberOfs.length) { + this.memberOf = memberOfs[0].desc; + this.memberOf = this.memberOf.replace(/\.prototype\.?/g, "#"); + } + + /*t: + // todo + */ + + // @public + if (this.comment.getTag("public").length) { + this.isPrivate = false; + } + + /*t: + // todo + */ + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onSetTags", this); + } +} + +JSDOC.Symbol.prototype.is = function(what) { + return this.isa === what; +} + +JSDOC.Symbol.prototype.isBuiltin = function() { + return JSDOC.Lang.isBuiltin(this.alias); +} + +JSDOC.Symbol.prototype.setType = function(/**String*/comment, /**Boolean*/overwrite) { + if (!overwrite && this.type) return; + var typeComment = JSDOC.DocComment.unwrapComment(comment); + this.type = typeComment; +} + +JSDOC.Symbol.prototype.inherit = function(symbol) { + if (!this.hasMember(symbol.name) && !symbol.isInner) { + if (symbol.is("FUNCTION")) + this.methods.push(symbol); + else if (symbol.is("OBJECT")) + this.properties.push(symbol); + } +} + +JSDOC.Symbol.prototype.hasMember = function(name) { + return (this.hasMethod(name) || this.hasProperty(name)); +} + +JSDOC.Symbol.prototype.addMember = function(symbol) { + if (symbol.is("FUNCTION")) { this.addMethod(symbol); } + else if (symbol.is("OBJECT")) { this.addProperty(symbol); } +} + +JSDOC.Symbol.prototype.hasMethod = function(name) { + var thisMethods = this.methods; + for (var i = 0, l = thisMethods.length; i < l; i++) { + if (thisMethods[i].name == name) return true; + if (thisMethods[i].alias == name) return true; + } + return false; +} + +JSDOC.Symbol.prototype.addMethod = function(symbol) { + var methodAlias = symbol.alias; + var thisMethods = this.methods; + for (var i = 0, l = thisMethods.length; i < l; i++) { + if (thisMethods[i].alias == methodAlias) { + thisMethods[i] = symbol; // overwriting previous method + return; + } + } + thisMethods.push(symbol); // new method with this alias +} + +JSDOC.Symbol.prototype.hasProperty = function(name) { + var thisProperties = this.properties; + for (var i = 0, l = thisProperties.length; i < l; i++) { + if (thisProperties[i].name == name) return true; + if (thisProperties[i].alias == name) return true; + } + return false; +} + +JSDOC.Symbol.prototype.addProperty = function(symbol) { + var propertyAlias = symbol.alias; + var thisProperties = this.properties; + for (var i = 0, l = thisProperties.length; i < l; i++) { + if (thisProperties[i].alias == propertyAlias) { + thisProperties[i] = symbol; // overwriting previous property + return; + } + } + + thisProperties.push(symbol); // new property with this alias +} + +JSDOC.Symbol.srcFile = ""; //running reference to the current file being parsed diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/SymbolSet.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/SymbolSet.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,243 @@ +/** @constructor */ +JSDOC.SymbolSet = function() { + this.init(); +} + +JSDOC.SymbolSet.prototype.init = function() { + this._index = new Hash(); +} + +JSDOC.SymbolSet.prototype.keys = function() { + return this._index.keys(); +} + +JSDOC.SymbolSet.prototype.hasSymbol = function(alias) { + return this._index.hasKey(alias); +} + +JSDOC.SymbolSet.prototype.addSymbol = function(symbol) { + if (JSDOC.opt.a && this.hasSymbol(symbol.alias)) { + LOG.warn("Overwriting symbol documentation for: " + symbol.alias + "."); + this.deleteSymbol(symbol.alias); + } + this._index.set(symbol.alias, symbol); +} + +JSDOC.SymbolSet.prototype.getSymbol = function(alias) { + if (this.hasSymbol(alias)) return this._index.get(alias); +} + +JSDOC.SymbolSet.prototype.getSymbolByName = function(name) { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + if (symbol.name == name) return symbol; + } +} + +JSDOC.SymbolSet.prototype.toArray = function() { + return this._index.values(); +} + +JSDOC.SymbolSet.prototype.deleteSymbol = function(alias) { + if (!this.hasSymbol(alias)) return; + this._index.drop(alias); +} + +JSDOC.SymbolSet.prototype.renameSymbol = function(oldName, newName) { + // todo: should check if oldname or newname already exist + this._index.replace(oldName, newName); + this._index.get(newName).alias = newName; + return newName; +} + +JSDOC.SymbolSet.prototype.relate = function() { + this.resolveBorrows(); + this.resolveMemberOf(); + this.resolveAugments(); +} + +JSDOC.SymbolSet.prototype.resolveBorrows = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; + + var borrows = symbol.inherits; + for (var i = 0; i < borrows.length; i++) { + +if (/#$/.test(borrows[i].alias)) { + LOG.warn("Attempted to borrow entire instance of "+borrows[i].alias+" but that feature is not yet implemented."); + return; +} + var borrowed = this.getSymbol(borrows[i].alias); + + if (!borrowed) { + LOG.warn("Can't borrow undocumented "+borrows[i].alias+"."); + continue; + } + + if (borrows[i].as == borrowed.alias) { + var assumedName = borrowed.name.split(/([#.-])/).pop(); + borrows[i].as = symbol.name+RegExp.$1+assumedName; + LOG.inform("Assuming borrowed as name is "+borrows[i].as+" but that feature is experimental."); + } + + var borrowAsName = borrows[i].as; + var borrowAsAlias = borrowAsName; + if (!borrowAsName) { + LOG.warn("Malformed @borrow, 'as' is required."); + continue; + } + + if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) { + borrowAsName = borrowAsName.replace(borrowed.alias, "") + } + else { + var joiner = ""; + if (borrowAsName.charAt(0) != "#") joiner = "."; + borrowAsAlias = borrowed.alias + joiner + borrowAsName; + } + + borrowAsName = borrowAsName.replace(/^[#.]/, ""); + + if (this.hasSymbol(borrowAsAlias)) continue; + + var clone = borrowed.clone(); + clone.name = borrowAsName; + clone.alias = borrowAsAlias; + this.addSymbol(clone); + } + } +} + +JSDOC.SymbolSet.prototype.resolveMemberOf = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + + if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; + + // the memberOf value was provided in the @memberOf tag + else if (symbol.memberOf) { + // like foo.bar is a memberOf foo + if (symbol.alias.indexOf(symbol.memberOf) == 0) { + var memberMatch = new RegExp("^("+symbol.memberOf+")[.#-]?(.+)$"); + var aliasParts = symbol.alias.match(memberMatch); + + if (aliasParts) { + symbol.memberOf = aliasParts[1]; + symbol.name = aliasParts[2]; + } + + var nameParts = symbol.name.match(memberMatch); + + if (nameParts) { + symbol.name = nameParts[2]; + } + } + // like bar is a memberOf foo + else { + var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1); + if (!/[.#-]/.test(joiner)) symbol.memberOf += "."; + this.renameSymbol(symbol.alias, symbol.memberOf + symbol.name); + } + } + // the memberOf must be calculated + else { + var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/); + + if (parts) { + symbol.memberOf = parts[1]; + symbol.name = parts[2]; + } + } + + // set isStatic, isInner + if (symbol.memberOf) { + switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) { + case '#' : + symbol.isStatic = false; + symbol.isInner = false; + break; + case '.' : + symbol.isStatic = true; + symbol.isInner = false; + break; + case '-' : + symbol.isStatic = false; + symbol.isInner = true; + break; + default: // memberOf ends in none of the above + symbol.isStatic = true; + break; + } + } + + // unowned methods and fields belong to the global object + if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") { + symbol.memberOf = "_global_"; + } + + // clean up + if (symbol.memberOf.match(/[.#-]$/)) { + symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1); + } + // add to parent's methods or properties list + if (symbol.memberOf) { + + var container = this.getSymbol(symbol.memberOf); + if (!container) { + if (JSDOC.Lang.isBuiltin(symbol.memberOf)) container = JSDOC.Parser.addBuiltin(symbol.memberOf); + else { + LOG.warn("Trying to document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+"."); + } + } + + if (container) container.addMember(symbol); + } + } +} + +JSDOC.SymbolSet.prototype.resolveAugments = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + + if (symbol.alias == "_global_" || symbol.is("FILE")) continue; + JSDOC.SymbolSet.prototype.walk.apply(this, [symbol]); + } +} + +JSDOC.SymbolSet.prototype.walk = function(symbol) { + var augments = symbol.augments; + for(var i = 0; i < augments.length; i++) { + var contributer = this.getSymbol(augments[i]); + if (!contributer && JSDOC.Lang.isBuiltin(''+augments[i])) { + contributer = new JSDOC.Symbol("_global_."+augments[i], [], augments[i], new JSDOC.DocComment("Built in.")); + contributer.isNamespace = true; + contributer.srcFile = ""; + contributer.isPrivate = false; + JSDOC.Parser.addSymbol(contributer); + } + + if (contributer) { + if (contributer.augments.length) { + JSDOC.SymbolSet.prototype.walk.apply(this, [contributer]); + } + + symbol.inheritsFrom.push(contributer.alias); + //if (!isUnique(symbol.inheritsFrom)) { + // LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once."); + //} + //else { + var cmethods = contributer.methods; + var cproperties = contributer.properties; + + for (var ci = 0, cl = cmethods.length; ci < cl; ci++) { + if (!cmethods[ci].isStatic) symbol.inherit(cmethods[ci]); + } + for (var ci = 0, cl = cproperties.length; ci < cl; ci++) { + if (!cproperties[ci].isStatic) symbol.inherit(cproperties[ci]); + } + //} + } + else LOG.warn("Can't augment contributer: "+augments[i]+", not found."); + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/TextStream.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/TextStream.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,41 @@ + +/** + @constructor +*/ +JSDOC.TextStream = function(text) { + if (typeof(text) == "undefined") text = ""; + text = ""+text; + this.text = text; + this.cursor = 0; +} + +JSDOC.TextStream.prototype.look = function(n) { + if (typeof n == "undefined") n = 0; + + if (this.cursor+n < 0 || this.cursor+n >= this.text.length) { + var result = new String(""); + result.eof = true; + return result; + } + return this.text.charAt(this.cursor+n); +} + +JSDOC.TextStream.prototype.next = function(n) { + if (typeof n == "undefined") n = 1; + if (n < 1) return null; + + var pulled = ""; + for (var i = 0; i < n; i++) { + if (this.cursor+i < this.text.length) { + pulled += this.text.charAt(this.cursor+i); + } + else { + var result = new String(""); + result.eof = true; + return result; + } + } + + this.cursor += n; + return pulled; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Token.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Token.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,18 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor +*/ +JSDOC.Token = function(data, type, name) { + this.data = data; + this.type = type; + this.name = name; +} + +JSDOC.Token.prototype.toString = function() { + return "<"+this.type+" name=\""+this.name+"\">"+this.data+""; +} + +JSDOC.Token.prototype.is = function(what) { + return this.name === what || this.type === what; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/TokenReader.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/TokenReader.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,332 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @class Search a {@link JSDOC.TextStream} for language tokens. +*/ +JSDOC.TokenReader = function() { + this.keepDocs = true; + this.keepWhite = false; + this.keepComments = false; +} + +/** + @type {JSDOC.Token[]} + */ +JSDOC.TokenReader.prototype.tokenize = function(/**JSDOC.TextStream*/stream) { + var tokens = []; + /**@ignore*/ tokens.last = function() { return tokens[tokens.length-1]; } + /**@ignore*/ tokens.lastSym = function() { + for (var i = tokens.length-1; i >= 0; i--) { + if (!(tokens[i].is("WHIT") || tokens[i].is("COMM"))) return tokens[i]; + } + } + + while (!stream.look().eof) { + if (this.read_mlcomment(stream, tokens)) continue; + if (this.read_slcomment(stream, tokens)) continue; + if (this.read_dbquote(stream, tokens)) continue; + if (this.read_snquote(stream, tokens)) continue; + if (this.read_regx(stream, tokens)) continue; + if (this.read_numb(stream, tokens)) continue; + if (this.read_punc(stream, tokens)) continue; + if (this.read_newline(stream, tokens)) continue; + if (this.read_space(stream, tokens)) continue; + if (this.read_word(stream, tokens)) continue; + + // if execution reaches here then an error has happened + tokens.push(new JSDOC.Token(stream.next(), "TOKN", "UNKNOWN_TOKEN")); + } + return tokens; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_word = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + while (!stream.look().eof && JSDOC.Lang.isWordChar(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + var name; + if ((name = JSDOC.Lang.keyword(found))) tokens.push(new JSDOC.Token(found, "KEYW", name)); + else tokens.push(new JSDOC.Token(found, "NAME", "NAME")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_punc = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + var name; + while (!stream.look().eof && JSDOC.Lang.punc(found+stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + tokens.push(new JSDOC.Token(found, "PUNC", JSDOC.Lang.punc(found))); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_space = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isSpace(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (this.collapseWhite) found = " "; + if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "SPACE")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_newline = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (this.collapseWhite) found = "\n"; + if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "NEWLINE")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_mlcomment = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "/" && stream.look(1) == "*") { + var found = stream.next(2); + + while (!stream.look().eof && !(stream.look(-1) == "/" && stream.look(-2) == "*")) { + found += stream.next(); + } + + // to start doclet we allow /** or /*** but not /**/ or /**** + if (/^\/\*\*([^\/]|\*[^*])/.test(found) && this.keepDocs) tokens.push(new JSDOC.Token(found, "COMM", "JSDOC")); + else if (this.keepComments) tokens.push(new JSDOC.Token(found, "COMM", "MULTI_LINE_COMM")); + return true; + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_slcomment = function(/**JSDOC.TokenStream*/stream, tokens) { + var found; + if ( + (stream.look() == "/" && stream.look(1) == "/" && (found=stream.next(2))) + || + (stream.look() == "<" && stream.look(1) == "!" && stream.look(2) == "-" && stream.look(3) == "-" && (found=stream.next(4))) + ) { + + while (!stream.look().eof && !JSDOC.Lang.isNewline(stream.look())) { + found += stream.next(); + } + + if (this.keepComments) { + tokens.push(new JSDOC.Token(found, "COMM", "SINGLE_LINE_COMM")); + } + return true; + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_dbquote = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "\"") { + // find terminator + var string = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { + if (JSDOC.Lang.isNewline(stream.look(1))) { + do { + stream.next(); + } while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look())); + string += "\\\n"; + } + else { + string += stream.next(2); + } + } + else if (stream.look() == "\"") { + string += stream.next(); + tokens.push(new JSDOC.Token(string, "STRN", "DOUBLE_QUOTE")); + return true; + } + else { + string += stream.next(); + } + } + } + return false; // error! unterminated string +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_snquote = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "'") { + // find terminator + var string = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { // escape sequence + string += stream.next(2); + } + else if (stream.look() == "'") { + string += stream.next(); + tokens.push(new JSDOC.Token(string, "STRN", "SINGLE_QUOTE")); + return true; + } + else { + string += stream.next(); + } + } + } + return false; // error! unterminated string +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_numb = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() === "0" && stream.look(1) == "x") { + return this.read_hex(stream, tokens); + } + + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isNumber(found+stream.look())){ + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (/^0[0-7]/.test(found)) tokens.push(new JSDOC.Token(found, "NUMB", "OCTAL")); + else tokens.push(new JSDOC.Token(found, "NUMB", "DECIMAL")); + return true; + } +} +/*t: + requires("../lib/JSDOC/TextStream.js"); + requires("../lib/JSDOC/Token.js"); + requires("../lib/JSDOC/Lang.js"); + + plan(3, "testing JSDOC.TokenReader.prototype.read_numb"); + + //// setup + var src = "function foo(num){while (num+8.0 >= 0x20 && num < 0777){}}"; + var tr = new JSDOC.TokenReader(); + var tokens = tr.tokenize(new JSDOC.TextStream(src)); + + var hexToken, octToken, decToken; + for (var i = 0; i < tokens.length; i++) { + if (tokens[i].name == "HEX_DEC") hexToken = tokens[i]; + if (tokens[i].name == "OCTAL") octToken = tokens[i]; + if (tokens[i].name == "DECIMAL") decToken = tokens[i]; + } + //// + + is(decToken.data, "8.0", "decimal number is found in source."); + is(hexToken.data, "0x20", "hexdec number is found in source (issue #99)."); + is(octToken.data, "0777", "octal number is found in source."); +*/ + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_hex = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = stream.next(2); + + while (!stream.look().eof) { + if (JSDOC.Lang.isHexDec(found) && !JSDOC.Lang.isHexDec(found+stream.look())) { // done + tokens.push(new JSDOC.Token(found, "NUMB", "HEX_DEC")); + return true; + } + else { + found += stream.next(); + } + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_regx = function(/**JSDOC.TokenStream*/stream, tokens) { + var last; + if ( + stream.look() == "/" + && + ( + + ( + !(last = tokens.lastSym()) // there is no last, the regex is the first symbol + || + ( + !last.is("NUMB") + && !last.is("NAME") + && !last.is("RIGHT_PAREN") + && !last.is("RIGHT_BRACKET") + ) + ) + ) + ) { + var regex = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { // escape sequence + regex += stream.next(2); + } + else if (stream.look() == "/") { + regex += stream.next(); + + while (/[gmi]/.test(stream.look())) { + regex += stream.next(); + } + + tokens.push(new JSDOC.Token(regex, "REGX", "REGX")); + return true; + } + else { + regex += stream.next(); + } + } + // error: unterminated regex + } + return false; +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/TokenStream.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/TokenStream.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,133 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor +*/ +JSDOC.TokenStream = function(tokens) { + this.tokens = (tokens || []); + this.rewind(); +} + +/** + @constructor + @private +*/ +function VoidToken(/**String*/type) { + this.toString = function() {return ""}; + this.is = function(){return false;} +} + +JSDOC.TokenStream.prototype.rewind = function() { + this.cursor = -1; +} + +/** + @type JSDOC.Token +*/ +JSDOC.TokenStream.prototype.look = function(/**Number*/n, /**Boolean*/considerWhitespace) { + if (typeof n == "undefined") n = 0; + + if (considerWhitespace == true) { + if (this.cursor+n < 0 || this.cursor+n > this.tokens.length) return {}; + return this.tokens[this.cursor+n]; + } + else { + var count = 0; + var i = this.cursor; + + while (true) { + if (i < 0) return new JSDOC.Token("", "VOID", "START_OF_STREAM"); + else if (i > this.tokens.length) return new JSDOC.Token("", "VOID", "END_OF_STREAM"); + + if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT"))) { + if (n < 0) i--; else i++; + continue; + } + + if (count == Math.abs(n)) { + return this.tokens[i]; + } + count++; + (n < 0)? i-- : i++; + } + + return new JSDOC.Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object + } +} + +/** + @type JSDOC.Token|JSDOC.Token[] +*/ +JSDOC.TokenStream.prototype.next = function(/**Number*/howMany) { + if (typeof howMany == "undefined") howMany = 1; + if (howMany < 1) return null; + var got = []; + + for (var i = 1; i <= howMany; i++) { + if (this.cursor+i >= this.tokens.length) { + return null; + } + got.push(this.tokens[this.cursor+i]); + } + this.cursor += howMany; + + if (howMany == 1) { + return got[0]; + } + else return got; +} + +/** + @type JSDOC.Token[] +*/ +JSDOC.TokenStream.prototype.balance = function(/**String*/start, /**String*/stop) { + if (!stop) stop = JSDOC.Lang.matching(start); + + var depth = 0; + var got = []; + var started = false; + + while ((token = this.look())) { + if (token.is(start)) { + depth++; + started = true; + } + + if (started) { + got.push(token); + } + + if (token.is(stop)) { + depth--; + if (depth == 0) return got; + } + if (!this.next()) break; + } +} + +JSDOC.TokenStream.prototype.getMatchingToken = function(/**String*/start, /**String*/stop) { + var depth = 0; + var cursor = this.cursor; + + if (!start) { + start = JSDOC.Lang.matching(stop); + depth = 1; + } + if (!stop) stop = JSDOC.Lang.matching(start); + + while ((token = this.tokens[cursor])) { + if (token.is(start)) { + depth++; + } + + if (token.is(stop) && cursor) { + depth--; + if (depth == 0) return this.tokens[cursor]; + } + cursor++; + } +} + +JSDOC.TokenStream.prototype.insertAhead = function(/**JSDOC.Token*/token) { + this.tokens.splice(this.cursor+1, 0, token); +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Util.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Util.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,32 @@ +/** + * @namespace + * @deprecated Use {@link FilePath} instead. + */ +JSDOC.Util = { +} + +/** + * @deprecated Use {@link FilePath.fileName} instead. + */ +JSDOC.Util.fileName = function(path) { + LOG.warn("JSDOC.Util.fileName is deprecated. Use FilePath.fileName instead."); + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(nameStart); +} + +/** + * @deprecated Use {@link FilePath.fileExtension} instead. + */ +JSDOC.Util.fileExtension = function(filename) { + LOG.warn("JSDOC.Util.fileExtension is deprecated. Use FilePath.fileExtension instead."); + return filename.split(".").pop().toLowerCase(); +}; + +/** + * @deprecated Use {@link FilePath.dir} instead. + */ +JSDOC.Util.dir = function(path) { + LOG.warn("JSDOC.Util.dir is deprecated. Use FilePath.dir instead."); + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(0, nameStart-1); +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/lib/JSDOC/Walker.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/lib/JSDOC/Walker.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,507 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** @constructor */ +JSDOC.Walker = function(/**JSDOC.TokenStream*/ts) { + this.init(); + if (typeof ts != "undefined") { + this.walk(ts); + } +} + +JSDOC.Walker.prototype.init = function() { + this.ts = null; + + var globalSymbol = new JSDOC.Symbol("_global_", [], "GLOBAL", new JSDOC.DocComment("")); + globalSymbol.isNamespace = true; + globalSymbol.srcFile = ""; + globalSymbol.isPrivate = false; + JSDOC.Parser.addSymbol(globalSymbol); + this.lastDoc = null; + this.token = null; + + /** + The chain of symbols under which we are currently nested. + @type Array + */ + this.namescope = [globalSymbol]; + this.namescope.last = function(n){ if (!n) n = 0; return this[this.length-(1+n)] || "" }; +} + +JSDOC.Walker.prototype.walk = function(/**JSDOC.TokenStream*/ts) { + this.ts = ts; + while (this.token = this.ts.look()) { + if (this.token.popNamescope) { + + var symbol = this.namescope.pop(); + if (symbol.is("FUNCTION")) { + if (this.ts.look(1).is("LEFT_PAREN") && symbol.comment.getTag("function").length == 0) { + symbol.isa = "OBJECT"; + } + } + } + this.step(); + if (!this.ts.next()) break; + } +} + +JSDOC.Walker.prototype.step = function() { + if (this.token.is("JSDOC")) { // it's a doc comment + + var doc = new JSDOC.DocComment(this.token.data); + + + if (doc.getTag("exports").length > 0) { + var exports = doc.getTag("exports")[0]; + + exports.desc.match(/(\S+) as (\S+)/i); + var n1 = RegExp.$1; + var n2 = RegExp.$2; + + if (!n1 && n2) throw "@exports tag requires a value like: 'name as ns.name'"; + + JSDOC.Parser.rename = (JSDOC.Parser.rename || {}); + JSDOC.Parser.rename[n1] = n2 + } + + if (doc.getTag("lends").length > 0) { + var lends = doc.getTag("lends")[0]; + + var name = lends.desc + if (!name) throw "@lends tag requires a value."; + + var symbol = new JSDOC.Symbol(name, [], "OBJECT", doc); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + + this.lastDoc = null; + return true; + } + else if (doc.getTag("name").length > 0 && doc.getTag("overview").length == 0) { // it's a virtual symbol + var virtualName = doc.getTag("name")[0].desc; + if (!virtualName) throw "@name tag requires a value."; + + if (doc.getTag("memberOf").length > 0) { + virtualName = (doc.getTag("memberOf")[0] + "." + virtualName) + .replace(/([#.])\./, "$1"); + doc.deleteTag("memberOf"); + } + + var symbol = new JSDOC.Symbol(virtualName, [], "VIRTUAL", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.lastDoc = null; + return true; + } + else if (doc.meta) { // it's a meta doclet + if (doc.meta == "@+") JSDOC.DocComment.shared = doc.src; + else if (doc.meta == "@-") JSDOC.DocComment.shared = ""; + else if (doc.meta == "nocode+") JSDOC.Parser.conf.ignoreCode = true; + else if (doc.meta == "nocode-") JSDOC.Parser.conf.ignoreCode = JSDOC.opt.n; + else throw "Unrecognized meta comment: "+doc.meta; + + this.lastDoc = null; + return true; + } + else if (doc.getTag("overview").length > 0) { // it's a file overview + symbol = new JSDOC.Symbol("", [], "FILE", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.lastDoc = null; + return true; + } + else { + this.lastDoc = doc; + return false; + } + } + else if (!JSDOC.Parser.conf.ignoreCode) { // it's code + if (this.token.is("NAME")) { // it's the name of something + var symbol; + var name = this.token.data; + var doc = null; if (this.lastDoc) doc = this.lastDoc; + var params = []; + + // it's inside an anonymous object + if (this.ts.look(1).is("COLON") && this.ts.look(-1).is("LEFT_CURLY") && !(this.ts.look(-2).is("JSDOC") || this.namescope.last().comment.getTag("lends").length || this.ts.look(-2).is("ASSIGN") || this.ts.look(-2).is("COLON"))) { + name = "$anonymous"; + name = this.namescope.last().alias+"-"+name + + params = []; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken(null, "RIGHT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // function foo() {} + else if (this.ts.look(-1).is("FUNCTION") && this.ts.look(1).is("LEFT_PAREN")) { + var isInner; + + if (this.lastDoc) doc = this.lastDoc; + + if (doc && doc.getTag("memberOf").length > 0) { + name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#"); + doc.deleteTag("memberOf"); + } + else { + name = this.namescope.last().alias+"-"+name; + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + + if (!this.namescope.last().is("GLOBAL")) isInner = true; + + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + if (isInner) symbol.isInner = true; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = function() {} + else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("FUNCTION")) { + var constructs; + var isConstructor = false; + if (doc && (constructs = doc.getTag("constructs")) && constructs.length) { + if (constructs[0].desc) { + name = constructs[0].desc; + isConstructor = true; + } + } + + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + if (doc && doc.getTag("memberOf").length > 0) { + name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#"); + doc.deleteTag("memberOf"); + } + else { + name = this.namescope.last().alias+"-"+name; + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + + if (isInner) symbol.isInner = true; + if (isConstructor) symbol.isa = "CONSTRUCTOR"; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = new function() {} or foo = (function() {} + else if (this.ts.look(1).is("ASSIGN") && (this.ts.look(2).is("NEW") || this.ts.look(2).is("LEFT_PAREN")) && this.ts.look(3).is("FUNCTION")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + this.ts.next(3); // advance past the "new" or "(" + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + symbol.scopeType = "INSTANCE"; + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo: function() {} + else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("FUNCTION")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#"); + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + if (doc && doc.getTag("constructs").length) { + name = name.replace(/\.prototype(\.|$)/, "#"); + + if (name.indexOf("#") > -1) name = name.match(/(^[^#]+)/)[0]; + else name = this.namescope.last().alias; + + symbol = new JSDOC.Symbol(name, params, "CONSTRUCTOR", doc); + } + else { + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + } + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = {} + else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("LEFT_CURLY")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // var foo; + else if (this.ts.look(1).is("SEMICOLON")) { + var isInner; + + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + } + // foo = x + else if (this.ts.look(1).is("ASSIGN")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + // foo: {} + else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("LEFT_CURLY")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#"); + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + + if (doc) JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo: x + else if (this.ts.look(1).is("COLON")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#");; + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + // foo(...) + else if (this.ts.look(1).is("LEFT_PAREN")) { + if (typeof JSDOC.PluginManager != "undefined") { + var functionCall = {name: name}; + + var cursor = this.ts.cursor; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + this.ts.cursor = cursor; + + for (var i = 0; i < params.length; i++) + functionCall["arg" + (i + 1)] = params[i].name; + + JSDOC.PluginManager.run("onFunctionCall", functionCall); + if (functionCall.doc) { + this.ts.insertAhead(new JSDOC.Token(functionCall.doc, "COMM", "JSDOC")); + } + } + } + this.lastDoc = null; + } + else if (this.token.is("FUNCTION")) { // it's an anonymous function + if ( + (!this.ts.look(-1).is("COLON") || !this.ts.look(-1).is("ASSIGN")) + && !this.ts.look(1).is("NAME") + ) { + if (this.lastDoc) doc = this.lastDoc; + + name = "$anonymous"; + name = this.namescope.last().alias+"-"+name + + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + } + } + return true; +} + +/** + Resolves what "this." means when it appears in a name. + @param name The name that starts with "this.". + @returns The name with "this." resolved. + */ +JSDOC.Walker.prototype.resolveThis = function(name) { + name.match(/^this\.(.+)$/) + var nameFragment = RegExp.$1; + if (!nameFragment) return name; + + var symbol = this.namescope.last(); + var scopeType = symbol.scopeType || symbol.isa; + + // if we are in a constructor function, `this` means the instance + if (scopeType == "CONSTRUCTOR") { + name = symbol.alias+"#"+nameFragment; + } + + // if we are in an anonymous constructor function, `this` means the instance + else if (scopeType == "INSTANCE") { + name = symbol.alias+"."+nameFragment; + } + + // if we are in a function, `this` means the container (possibly the global) + else if (scopeType == "FUNCTION") { + // in a method of a prototype, so `this` means the constructor + if (symbol.alias.match(/(^.*)[#.-][^#.-]+/)) { + var parentName = RegExp.$1; + var parent = JSDOC.Parser.symbols.getSymbol(parentName); + + if (!parent) { + if (JSDOC.Lang.isBuiltin(parentName)) parent = JSDOC.Parser.addBuiltin(parentName); + else { + if (symbol.alias.indexOf("$anonymous") < 0) // these will be ignored eventually + LOG.warn("Trying to document "+symbol.alias+" without first documenting "+parentName+"."); + } + } + if (parent) name = parentName+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment; + } + else { + parent = this.namescope.last(1); + name = parent.alias+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment; + } + } + // otherwise it means the global + else { + name = nameFragment; + } + + return name; +} + +JSDOC.Walker.onParamList = function(/**Array*/paramTokens) { + if (!paramTokens) { + LOG.warn("Malformed parameter list. Can't parse code."); + return []; + } + var params = []; + for (var i = 0, l = paramTokens.length; i < l; i++) { + if (paramTokens[i].is("JSDOC")) { + var paramType = paramTokens[i].data.replace(/(^\/\*\* *| *\*\/$)/g, ""); + + if (paramTokens[i+1] && paramTokens[i+1].is("NAME")) { + i++; + params.push({type: paramType, name: paramTokens[i].data}); + } + } + else if (paramTokens[i].is("NAME")) { + params.push({name: paramTokens[i].data}); + } + } + return params; +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/main.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/main.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,111 @@ +/** + * @version $Id: main.js 818 2009-11-08 14:51:41Z micmath $ + */ + +function main() { + IO.include("lib/JSDOC.js"); + IO.includeDir("plugins/"); + + // process the options + + // the -c option: options are defined in a configuration file + if (JSDOC.opt.c) { + eval("JSDOC.conf = " + IO.readFile(JSDOC.opt.c)); + + LOG.inform("Using configuration file at '"+JSDOC.opt.c+"'."); + + for (var c in JSDOC.conf) { + if (c !== "D" && !defined(JSDOC.opt[c])) { // commandline overrules config file + JSDOC.opt[c] = JSDOC.conf[c]; + } + } + + if (typeof JSDOC.conf["_"] != "undefined") { + JSDOC.opt["_"] = JSDOC.opt["_"].concat(JSDOC.conf["_"]); + } + + LOG.inform("With configuration: "); + for (var o in JSDOC.opt) { + LOG.inform(" "+o+": "+JSDOC.opt[o]); + } + } + + // be verbose + if (JSDOC.opt.v) LOG.verbose = true; + + // send log messages to a file + if (JSDOC.opt.o) LOG.out = IO.open(JSDOC.opt.o); + + // run the unit tests + if (JSDOC.opt.T) { + LOG.inform("JsDoc Toolkit running in test mode at "+new Date()+"."); + IO.include("frame/Testrun.js"); + IO.include("test.js"); + } + else { + // a template must be defined and must be a directory path + if (!JSDOC.opt.t && System.getProperty("jsdoc.template.dir")) { + JSDOC.opt.t = System.getProperty("jsdoc.template.dir"); + } + if (JSDOC.opt.t && SYS.slash != JSDOC.opt.t.slice(-1)) { + JSDOC.opt.t += SYS.slash; + } + + // verbose messages about the options we were given + LOG.inform("JsDoc Toolkit main() running at "+new Date()+"."); + LOG.inform("With options: "); + for (var o in JSDOC.opt) { + LOG.inform(" "+o+": "+JSDOC.opt[o]); + } + + // initialize and build a symbolSet from your code + JSDOC.JsDoc(); + + // debugger's option: dump the entire symbolSet produced from your code + if (JSDOC.opt.Z) { + LOG.warn("So you want to see the data structure, eh? This might hang if you have circular refs..."); + IO.include("frame/Dumper.js"); + var symbols = JSDOC.JsDoc.symbolSet.toArray(); + for (var i = 0, l = symbols.length; i < l; i++) { + var symbol = symbols[i]; + print("// symbol: " + symbol.alias); + print(symbol.serialize()); + } + } + else { + if (typeof JSDOC.opt.t != "undefined") { + try { + // a file named "publish.js" must exist in the template directory + load(JSDOC.opt.t+"publish.js"); + + // and must define a function named "publish" + if (!publish) { + LOG.warn("No publish() function is defined in that template so nothing to do."); + } + else { + // which will be called with the symbolSet produced from your code + publish(JSDOC.JsDoc.symbolSet); + } + } + catch(e) { + LOG.warn("Sorry, that doesn't seem to be a valid template: "+JSDOC.opt.t+"publish.js : "+e); + } + } + else { + LOG.warn("No template given. Might as well read the usage notes."); + JSDOC.usage(); + } + } + } + + // notify of any warnings + if (!JSDOC.opt.q && LOG.warnings.length) { + print(LOG.warnings.length+" warning"+(LOG.warnings.length != 1? "s":"")+"."); + } + + // stop sending log messages to a file + if (LOG.out) { + LOG.out.flush(); + LOG.out.close(); + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/commentSrcJson.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/commentSrcJson.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,20 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.commentSrcJson", + { + onDocCommentSrc: function(comment) { + var json; + if (/^\s*@json\b/.test(comment)) { + comment.src = new String(comment.src).replace("@json", ""); + + eval("json = "+comment.src); + var tagged = ""; + for (var i in json) { + var tag = json[i]; + // todo handle cases where tag is an object + tagged += "@"+i+" "+tag+"\n"; + } + comment.src = tagged; + } + } + } +); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/frameworkPrototype.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/frameworkPrototype.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,16 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.frameworkPrototype", + { + onPrototypeClassCreate: function(classCreator) { + var desc = ""; + if (classCreator.comment) { + desc = classCreator.comment; + } + var insert = desc+"/** @name "+classCreator.name+"\n@constructor\n@scope "+classCreator.name+".prototype */" + + insert = insert.replace(/\*\/\/\*\*/g, "\n"); + /*DEBUG*///print("insert is "+insert); + classCreator.addComment.data = insert; + } + } +); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/functionCall.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/functionCall.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.functionCall", + { + onFunctionCall: function(functionCall) { + if (functionCall.name == "dojo.define" && functionCall.arg1) { + functionCall.doc = "/** @lends "+eval(functionCall.arg1)+".prototype */"; + } + } + } +); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/publishSrcHilite.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/publishSrcHilite.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,62 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.publishSrcHilite", + { + onPublishSrc: function(src) { + if (src.path in JsHilite.cache) { + return; // already generated src code + } + else JsHilite.cache[src.path] = true; + + try { + var sourceCode = IO.readFile(src.path); + } + catch(e) { + print(e.message); + quit(); + } + + var hiliter = new JsHilite(sourceCode, src.charset); + src.hilited = hiliter.hilite(); + } + } +); + +function JsHilite(src, charset) { + + var tr = new JSDOC.TokenReader(); + + tr.keepComments = true; + tr.keepDocs = true; + tr.keepWhite = true; + + this.tokens = tr.tokenize(new JSDOC.TextStream(src)); + + // TODO is redefining toString() the best way? + JSDOC.Token.prototype.toString = function() { + return ""+this.data.replace(/"; + } + + if (!charset) charset = "utf-8"; + + this.header = ' '+ + "

";
+	this.footer = "
"; + this.showLinenumbers = true; +} + +JsHilite.cache = {}; + +JsHilite.prototype.hilite = function() { + var hilited = this.tokens.join(""); + var line = 1; + if (this.showLinenumbers) hilited = hilited.replace(/(^|\n)/g, function(m){return m+""+((line<10)? " ":"")+((line<100)? " ":"")+(line++)+" "}); + + return this.header+hilited+this.footer; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/symbolLink.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/symbolLink.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.symbolLink", + { + onSymbolLink: function(link) { + // modify link.linkPath (the href part of the link) + // or link.linkText (the text displayed) + // or link.linkInner (the #name part of the link) + } + } +); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/tagParamConfig.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/tagParamConfig.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,31 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.tagParamConfig", + { + onDocCommentTags: function(comment) { + var currentParam = null; + var tags = comment.tags; + for (var i = 0, l = tags.length; i < l; i++) { + + if (tags[i].title == "param") { + if (tags[i].name.indexOf(".") == -1) { + currentParam = i; + } + } + else if (tags[i].title == "config") { + tags[i].title = "param"; + if (currentParam == null) { + tags[i].name = "arguments"+"."+tags[i].name; + } + else if (tags[i].name.indexOf(tags[currentParam].name+".") != 0) { + tags[i].name = tags[currentParam].name+"."+tags[i].name; + } + currentParam != null + //tags[currentParam].properties.push(tags[i]); + } + else { + currentParam = null; + } + } + } + } +); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/plugins/tagSynonyms.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/plugins/tagSynonyms.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,43 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.tagSynonyms", + { + onDocCommentSrc: function(comment) { + comment.src = comment.src.replace(/@methodOf\b/i, "@function\n@memberOf"); + comment.src = comment.src.replace(/@fieldOf\b/i, "@field\n@memberOf"); + }, + + onDocCommentTags: function(comment) { + for (var i = 0, l = comment.tags.length; i < l; i++) { + var title = comment.tags[i].title.toLowerCase(); + var syn; + if ((syn = JSDOC.tagSynonyms.synonyms["="+title])) { + comment.tags[i].title = syn; + } + } + } + } +); + +new Namespace( + "JSDOC.tagSynonyms", + function() { + JSDOC.tagSynonyms.synonyms = { + "=member": "memberOf", + "=memberof": "memberOf", + "=description": "desc", + "=exception": "throws", + "=argument": "param", + "=returns": "return", + "=classdescription": "class", + "=fileoverview": "overview", + "=extends": "augments", + "=base": "augments", + "=projectdescription": "overview", + "=classdescription": "class", + "=link": "see", + "=borrows": "inherits", + "=scope": "lends", + "=construct": "constructor" + } + } +); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/run.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/run.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,348 @@ +/** + * @fileOverview + * A bootstrap script that creates some basic required objects + * for loading other scripts. + * @author Michael Mathews, micmath@gmail.com + * @version $Id: run.js 756 2009-01-07 21:32:58Z micmath $ + */ + +/** + * @namespace Keep track of any messages from the running script. + */ +LOG = { + warn: function(msg, e) { + if (JSDOC.opt.q) return; + if (e) msg = e.fileName+", line "+e.lineNumber+": "+msg; + + msg = ">> WARNING: "+msg; + LOG.warnings.push(msg); + if (LOG.out) LOG.out.write(msg+"\n"); + else print(msg); + }, + + inform: function(msg) { + if (JSDOC.opt.q) return; + msg = " > "+msg; + if (LOG.out) LOG.out.write(msg+"\n"); + else if (typeof LOG.verbose != "undefined" && LOG.verbose) print(msg); + } +}; +LOG.warnings = []; +LOG.verbose = false +LOG.out = undefined; + +/** + * @class Manipulate a filepath. + */ +function FilePath(absPath, separator) { + this.slash = separator || "/"; + this.root = this.slash; + this.path = []; + this.file = ""; + + var parts = absPath.split(/[\\\/]/); + if (parts) { + if (parts.length) this.root = parts.shift() + this.slash; + if (parts.length) this.file = parts.pop() + if (parts.length) this.path = parts; + } + + this.path = this.resolvePath(); +} + +/** Collapse any dot-dot or dot items in a filepath. */ +FilePath.prototype.resolvePath = function() { + var resolvedPath = []; + for (var i = 0; i < this.path.length; i++) { + if (this.path[i] == "..") resolvedPath.pop(); + else if (this.path[i] != ".") resolvedPath.push(this.path[i]); + } + return resolvedPath; +} + +/** Trim off the filename. */ +FilePath.prototype.toDir = function() { + if (this.file) this.file = ""; + return this; +} + +/** Go up a directory. */ +FilePath.prototype.upDir = function() { + this.toDir(); + if (this.path.length) this.path.pop(); + return this; +} + +FilePath.prototype.toString = function() { + return this.root + + this.path.join(this.slash) + + ((this.path.length > 0)? this.slash : "") + + this.file; +} + +/** + * Turn a path into just the name of the file. + */ +FilePath.fileName = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(nameStart); +} + +/** + * Get the extension of a filename + */ +FilePath.fileExtension = function(filename) { + return filename.split(".").pop().toLowerCase(); +}; + +/** + * Turn a path into just the directory part. + */ +FilePath.dir = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(0, nameStart-1); +} + + +importClass(java.lang.System); + +/** + * @namespace A collection of information about your system. + */ +SYS = { + /** + * Information about your operating system: arch, name, version. + * @type string + */ + os: [ + new String(System.getProperty("os.arch")), + new String(System.getProperty("os.name")), + new String(System.getProperty("os.version")) + ].join(", "), + + /** + * Which way does your slash lean. + * @type string + */ + slash: System.getProperty("file.separator")||"/", + + /** + * The path to the working directory where you ran java. + * @type string + */ + userDir: new String(System.getProperty("user.dir")), + + /** + * Where is Java's home folder. + * @type string + */ + javaHome: new String(System.getProperty("java.home")), + + /** + * The absolute path to the directory containing this script. + * @type string + */ + pwd: undefined +}; + +// jsrun appends an argument, with the path to here. +if (arguments[arguments.length-1].match(/^-j=(.+)/)) { + if (RegExp.$1.charAt(0) == SYS.slash || RegExp.$1.charAt(1) == ":") { // absolute path to here + SYS.pwd = new FilePath(RegExp.$1).toDir().toString(); + } + else { // relative path to here + SYS.pwd = new FilePath(SYS.userDir + SYS.slash + RegExp.$1).toDir().toString(); + } + arguments.pop(); +} +else { + print("The run.js script requires you use jsrun.jar."); + quit(); +} + +// shortcut +var File = Packages.java.io.File; + +/** + * @namespace A collection of functions that deal with reading a writing to disk. + */ +IO = { + + /** + * Create a new file in the given directory, with the given name and contents. + */ + saveFile: function(/**string*/ outDir, /**string*/ fileName, /**string*/ content) { + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outDir+SYS.slash+fileName), + IO.encoding + ) + ); + out.write(content); + out.flush(); + out.close(); + }, + + /** + * @type string + */ + readFile: function(/**string*/ path) { + if (!IO.exists(path)) { + throw "File doesn't exist there: "+path; + } + return readFile(path, IO.encoding); + }, + + /** + * @param inFile + * @param outDir + * @param [fileName=The original filename] + */ + copyFile: function(/**string*/ inFile, /**string*/ outDir, /**string*/ fileName) { + if (fileName == null) fileName = FilePath.fileName(inFile); + + var inFile = new File(inFile); + var outFile = new File(outDir+SYS.slash+fileName); + + var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096); + var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096); + var theChar; + while ((theChar = bis.read()) != -1) { + bos.write(theChar); + } + bos.close(); + bis.close(); + }, + + /** + * Creates a series of nested directories. + */ + mkPath: function(/**Array*/ path) { + if (path.constructor != Array) path = path.split(/[\\\/]/); + var make = ""; + for (var i = 0, l = path.length; i < l; i++) { + make += path[i] + SYS.slash; + if (! IO.exists(make)) { + IO.makeDir(make); + } + } + }, + + /** + * Creates a directory at the given path. + */ + makeDir: function(/**string*/ path) { + (new File(path)).mkdir(); + }, + + /** + * @type string[] + * @param dir The starting directory to look in. + * @param [recurse=1] How many levels deep to scan. + * @returns An array of all the paths to files in the given dir. + */ + ls: function(/**string*/ dir, /**number*/ recurse, _allFiles, _path) { + if (_path === undefined) { // initially + var _allFiles = []; + var _path = [dir]; + } + if (_path.length == 0) return _allFiles; + if (recurse === undefined) recurse = 1; + + dir = new File(dir); + if (!dir.directory) return [String(dir)]; + var files = dir.list(); + + for (var f = 0; f < files.length; f++) { + var file = String(files[f]); + if (file.match(/^\.[^\.\/\\]/)) continue; // skip dot files + + if ((new File(_path.join(SYS.slash)+SYS.slash+file)).list()) { // it's a directory + _path.push(file); + if (_path.length-1 < recurse) IO.ls(_path.join(SYS.slash), recurse, _allFiles, _path); + _path.pop(); + } + else { + _allFiles.push((_path.join(SYS.slash)+SYS.slash+file).replace(SYS.slash+SYS.slash, SYS.slash)); + } + } + + return _allFiles; + }, + + /** + * @type boolean + */ + exists: function(/**string*/ path) { + file = new File(path); + + if (file.isDirectory()){ + return true; + } + if (!file.exists()){ + return false; + } + if (!file.canRead()){ + return false; + } + return true; + }, + + /** + * + */ + open: function(/**string*/ path, /**string*/ append) { + var append = true; + var outFile = new File(path); + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outFile, append), + IO.encoding + ) + ); + return out; + }, + + /** + * Sets {@link IO.encoding}. + * Encoding is used when reading and writing text to files, + * and in the meta tags of HTML output. + */ + setEncoding: function(/**string*/ encoding) { + if (/ISO-8859-([0-9]+)/i.test(encoding)) { + IO.encoding = "ISO8859_"+RegExp.$1; + } + else { + IO.encoding = encoding; + } + }, + + /** + * @default "utf-8" + * @private + */ + encoding: "utf-8", + + /** + * Load the given script. + */ + include: function(relativePath) { + load(SYS.pwd+relativePath); + }, + + /** + * Loads all scripts from the given directory path. + */ + includeDir: function(path) { + if (!path) return; + + for (var lib = IO.ls(SYS.pwd+path), i = 0; i < lib.length; i++) + if (/\.js$/i.test(lib[i])) load(lib[i]); + } +} + +// now run the application +IO.include("frame.js"); +IO.include("main.js"); + +main(); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/t/TestDoc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/t/TestDoc.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,144 @@ +var TestDoc = { + fails: 0, + plans: 0, + passes: 0, + results: [] +}; + +TestDoc.record = function(result) { + TestDoc.results.push(result); + if (typeof result.verdict == "boolean") { + if (result.verdict === false) TestDoc.fails++; + if (result.verdict === true) TestDoc.passes++; + } +} + +TestDoc.prove = function(filePath) { + if (typeof document != "undefined" && typeof document.write != "undefined") { + if (TestDoc.console) print = function(s) { TestDoc.console.appendChild(document.createTextNode(s+"\n")); } + else print = function(s) { document.write(s+"
"); } + } + TestDoc.run(TestDoc.readFile(filePath)); +} + +TestDoc.run = function(src) { + try { eval(src); } catch(e) { print("# ERROR! "+e); } + + var chunks = src.split(/\/\*t:/); + + var run = function(chunk) { + // local shortcuts + var is = TestDoc.assertEquals; + var isnt = TestDoc.assertNotEquals; + var plan = TestDoc.plan; + var requires = TestDoc.requires; + + try { eval(chunk); } catch(e) { print("# ERROR! "+e); } + } + for (var start = -1, end = 0; (start = src.indexOf("/*t:", end)) > end; start = end) { + run( + src.substring( + start+4, + (end = src.indexOf("*/", start)) + ) + ); + } +} + +TestDoc.Result = function(verdict, message) { + this.verdict = verdict; + this.message = message; +} + +TestDoc.Result.prototype.toString = function() { + if (typeof this.verdict == "boolean") { + return (this.verdict? "ok" : "not ok") + " " + (++TestDoc.report.counter) + " - " + this.message; + } + + return "# " + this.message; +} + +TestDoc.requires = function(file) { + if (!TestDoc.requires.loaded[file]) { + load(file); + TestDoc.requires.loaded[file] = true; + } +} +TestDoc.requires.loaded = {}; + +TestDoc.report = function() { + TestDoc.report.counter = 0; + print("1.."+TestDoc.plans); + for (var i = 0; i < TestDoc.results.length; i++) { + print(TestDoc.results[i]); + } + print("----------------------------------------"); + if (TestDoc.fails == 0 && TestDoc.passes == TestDoc.plans) { + print("All tests successful."); + } + else { + print("Failed " + TestDoc.fails + "/" + TestDoc.plans + " tests, "+((TestDoc.plans == 0)? 0 : Math.round(TestDoc.passes/(TestDoc.passes+TestDoc.fails)*10000)/100)+"% okay. Planned to run "+TestDoc.plans+", did run "+(TestDoc.passes+TestDoc.fails)+".") + } +} + +TestDoc.plan = function(n, message) { + TestDoc.plans += n; + TestDoc.record(new TestDoc.Result(null, message+" ("+n+" tests)")); +} + +TestDoc.assertEquals = function(a, b, message) { + var result = (a == b); + if (!result) message += "\n#\n# " + a + " does not equal " + b + "\n#"; + TestDoc.record(new TestDoc.Result(result, message)); +} + +TestDoc.assertNotEquals = function(a, b, message) { + var result = (a != b); + if (!result) message += "\n#\n# " + a + " equals " + b + "\n#"; + TestDoc.record(new TestDoc.Result(result, message)); +} + +TestDoc.readFile = (function(){ + // rhino + if (typeof readFile == "function") { + return function(url) { + var text = readFile(url); + return text || ""; + } + } + + // a web browser + else { + return function(url) { + var httpRequest; + + if (window.XMLHttpRequest) { // Mozilla, Safari, etc + httpRequest = new XMLHttpRequest(); + } + else if (window.ActiveXObject) { // IE + try { + httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); + } + catch (e) { + try { + httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); + } + catch (e) { + } + } + } + + if (!httpRequest) { throw "Cannot create HTTP Request."; } + + httpRequest.open('GET', url, false); + httpRequest.send(''); + if (httpRequest.readyState == 4) { + if (httpRequest.status >= 400) { + throw "The HTTP Request returned an error code: "+httpRequest.status; + } + } + + return httpRequest.responseText || ""; + } + } +})(); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/t/runner.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/t/runner.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,13 @@ +// try: java -jar ../../jsrun.jar runner.js + +load("TestDoc.js"); + +TestDoc.prove("../frame/Opt.js"); +TestDoc.prove("../lib/JSDOC.js"); +TestDoc.prove("../frame/String.js"); +TestDoc.prove("../lib/JSDOC/DocTag.js"); +TestDoc.prove("../lib/JSDOC/DocComment.js"); +TestDoc.prove("../lib/JSDOC/TokenReader.js"); +TestDoc.prove("../lib/JSDOC/Symbol.js"); + +TestDoc.report(); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,342 @@ +load("app/frame/Dumper.js"); +function symbolize(opt) { + symbols = null; + JSDOC.JsDoc(opt); + symbols = JSDOC.JsDoc.symbolSet; +} + +var testCases = [ + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/overview.js"]}); + //print(Dumper.dump(symbols)); + is('symbols.getSymbolByName("My Cool Library").name', 'My Cool Library', 'File overview can be found by alias.'); + } + , + function() { + symbolize({_: [SYS.pwd+"test/name.js"]}); + + is('symbols.getSymbol("Response").name', "Response", 'Virtual class name is found.'); + is('symbols.getSymbol("Response#text").alias', "Response#text", 'Virtual method name is found.'); + is('symbols.getSymbol("Response#text").memberOf', "Response", 'Virtual method parent name is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Function set to constructor prototype with inner constructor name is found.'); + is('symbols.getSymbol("Article").hasMethod("init")', true, 'The initializer method name of prototype function is correct.'); + is('symbols.getSymbol("Article").hasMember("counter")', true, 'A static property set in the prototype definition is found.'); + is('symbols.getSymbol("Article").hasMember("title")', true, 'An instance property set in the prototype is found.'); + is('symbols.getSymbol("Article#title").isStatic', false, 'An instance property has isStatic set to false.'); + is('symbols.getSymbol("Article.counter").name', "counter", 'A static property set in the initializer has the name set correctly.'); + is('symbols.getSymbol("Article.counter").memberOf', "Article", 'A static property set in the initializer has the memberOf set correctly.'); + is('symbols.getSymbol("Article.counter").isStatic', true, 'A static property set in the initializer has isStatic set to true.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/prototype_oblit.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype name is found.'); + is('typeof symbols.getSymbol("Article.prototype")', "undefined", 'The prototype oblit is not a symbol.'); + is('symbols.getSymbol("Article#getTitle").name', "getTitle", 'The nonstatic method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").alias', "Article#getTitle", 'The alias of non-static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").isStatic', false, 'The isStatic of a nonstatic method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").name', "getTitle", 'The static method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").isStatic', true, 'The isStatic of a static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").isa', "FUNCTION", 'The isa of non-static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").alias', "Article.getTitle", 'The alias of a static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").isa', "FUNCTION", 'The isa of static method of prototype oblit is correct.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype_oblit_constructor.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype with inner constructor name is found.'); + is('symbols.getSymbol("Article#init").name', "init", 'The initializer method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article").hasMember("pages")', true, 'Property set by initializer method "this" is on the outer constructor.'); + is('symbols.getSymbol("Article#Title").name', "Title", 'Name of the inner constructor name is found.'); + is('symbols.getSymbol("Article#Title").memberOf', "Article", 'The memberOf of the inner constructor name is found.'); + is('symbols.getSymbol("Article#Title").isa', "CONSTRUCTOR", 'The isa of the inner constructor name is constructor.'); + is('symbols.getSymbol("Article#Title").hasMember("title")', true, 'A property set on the inner constructor "this" is on the inner constructor.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/inner.js"]}); + + is('symbols.getSymbol("Outer").name', "Outer", 'Outer constructor prototype name is found.'); + is('symbols.getSymbol("Outer").methods.length', 1, 'Inner function doesnt appear as a method of the outer.'); + is('symbols.getSymbol("Outer").hasMethod("open")', true, 'Outer constructors methods arent affected by inner function.'); + is('symbols.getSymbol("Outer-Inner").alias', "Outer-Inner", 'Alias of inner function is found.'); + is('symbols.getSymbol("Outer-Inner").isa', "CONSTRUCTOR", 'isa of inner function constructor is found.'); + is('symbols.getSymbol("Outer-Inner").memberOf', "Outer", 'The memberOf of inner function is found.'); + is('symbols.getSymbol("Outer-Inner").name', "Inner", 'The name of inner function is found.'); + is('symbols.getSymbol("Outer-Inner#name").name', "name", 'A member of the inner function constructor, attached to "this" is found on inner.'); + is('symbols.getSymbol("Outer-Inner#name").memberOf', "Outer-Inner", 'The memberOf of an inner function member is found.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/prototype_nested.js"]}); + + is('symbols.getSymbol("Word").name', "Word", 'Base constructor name is found.'); + is('symbols.getSymbol("Word").hasMethod("reverse")', true, 'Base constructor method is found.'); + is('symbols.getSymbol("Word").methods.length', 1, 'Base constructor has only one method.'); + is('symbols.getSymbol("Word").memberOf', "", 'Base constructor memberOf is empty.'); + is('symbols.getSymbol("Word#reverse").name', "reverse", 'Member of constructor prototype name is found.'); + is('symbols.getSymbol("Word#reverse").memberOf', "Word", 'Member of constructor prototype memberOf is found.'); + is('symbols.getSymbol("Word#reverse.utf8").name', "utf8", 'Member of constructor prototype method name is found.'); + is('symbols.getSymbol("Word#reverse.utf8").memberOf', "Word#reverse", 'Static nested member memberOf is found.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/namespace_nested.js"]}); + + is('symbols.getSymbol("ns1").name', "ns1", 'Base namespace name is found.'); + is('symbols.getSymbol("ns1").memberOf', "", 'Base namespace memberOf is empty (its a constructor).'); + is('symbols.getSymbol("ns1.ns2").name', "ns2", 'Nested namespace name is found.'); + is('symbols.getSymbol("ns1.ns2").alias', "ns1.ns2", 'Nested namespace alias is found.'); + is('symbols.getSymbol("ns1.ns2").memberOf', "ns1", 'Nested namespace memberOf is found.'); + is('symbols.getSymbol("ns1.ns2.Function1").name', "Function1", 'Method of nested namespace name is found.'); + is('symbols.getSymbol("ns1.ns2.Function1").memberOf', "ns1.ns2", 'Constructor of nested namespace memberOf is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_nested.js"]}); + + is('symbols.getSymbol("Zop").name', "Zop", 'Any constructor name is found.'); + is('symbols.getSymbol("Zop").isa', "CONSTRUCTOR", 'It isa constructor.'); + is('symbols.getSymbol("Zop").hasMethod("zap")', true, 'Its method name, set later, is in methods array.'); + is('symbols.getSymbol("Foo").name', "Foo", 'The containing constructor name is found.'); + is('symbols.getSymbol("Foo").hasMethod("methodOne")', true, 'Its method name is found.'); + is('symbols.getSymbol("Foo").hasMethod("methodTwo")', true, 'Its second method name is found.'); + is('symbols.getSymbol("Foo#methodOne").alias', "Foo#methodOne", 'A methods alias is found.'); + is('symbols.getSymbol("Foo#methodOne").isStatic', false, 'A methods is not static.'); + is('symbols.getSymbol("Bar").name', "Bar", 'A global function declared inside another function is found.'); + is('symbols.getSymbol("Bar").isa', "FUNCTION", 'It isa function.'); + is('symbols.getSymbol("Bar").memberOf', "_global_", 'It is global.'); + is('symbols.getSymbol("Foo-inner").name', "inner", 'An inner functions name is found.'); + is('symbols.getSymbol("Foo-inner").memberOf', "Foo", 'It is member of the outer function.'); + is('symbols.getSymbol("Foo-inner").isInner', true, 'It is an inner function.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/memberof_constructor.js"]}); + + is('symbols.getSymbol("Circle#Tangent").name', "Tangent", 'Constructor set on prototype using @member has correct name.'); + is('symbols.getSymbol("Circle#Tangent").memberOf', "Circle", 'Constructor set on prototype using @member has correct memberOf.'); + is('symbols.getSymbol("Circle#Tangent").alias', "Circle#Tangent", 'Constructor set on prototype using @member has correct alias.'); + is('symbols.getSymbol("Circle#Tangent").isa', "CONSTRUCTOR", 'Constructor set on prototype using @member has correct isa.'); + is('symbols.getSymbol("Circle#Tangent").isStatic', false, 'Constructor set on prototype using @member is not static.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").name', "getDiameter", 'Method set on prototype using @member has correct name.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").memberOf', "Circle#Tangent", 'Method set on prototype using @member has correct memberOf.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").alias', "Circle#Tangent#getDiameter", 'Method set on prototype using @member has correct alias.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").isa', "FUNCTION", 'Method set on prototype using @member has correct isa.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").isStatic', false, 'Method set on prototype using @member is not static.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof.js"]}); + + is('symbols.getSymbol("pack.install").alias', "pack.install", 'Using @memberOf sets alias, when parent name is in memberOf tag.'); + is('symbols.getSymbol("pack.install.overwrite").name', "install.overwrite", 'Using @memberOf sets name, even if the name is dotted.'); + is('symbols.getSymbol("pack.install.overwrite").memberOf', "pack", 'Using @memberOf sets memberOf.'); + is('symbols.getSymbol("pack.install.overwrite").isStatic', true, 'Using @memberOf with value not ending in octothorp sets isStatic to true.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof2.js"]}); + + is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'An inner function can be documented as an instance method.'); + is('symbols.getSymbol("Foo.zip").alias', "Foo.zip", 'An inner function can be documented as a static method.'); + is('symbols.getSymbol("Foo.Fiz").alias', "Foo.Fiz", 'An inner function can be documented as a static constructor.'); + is('symbols.getSymbol("Foo.Fiz#fipple").alias', "Foo.Fiz#fipple", 'An inner function can be documented as a static constructor with a method.'); + is('symbols.getSymbol("Foo#blat").alias', "Foo#blat", 'An global function can be documented as an instance method.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof3.js"]}); + + is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'A virtual field can be documented as an instance method.'); + is('symbols.getSymbol("Foo2#bar").alias', "Foo2#bar", 'A virtual field with the same name can be documented as an instance method.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows.js"]}); + + is('symbols.getSymbol("Layout").name', "Layout", 'Constructor can be found.'); + is('symbols.getSymbol("Layout").hasMethod("init")', true, 'Constructor method name can be found.'); + is('symbols.getSymbol("Layout").hasMember("orientation")', true, 'Constructor property name can be found.'); + + is('symbols.getSymbol("Page").hasMethod("reset")', true, 'Second constructor method name can be found.'); + is('symbols.getSymbol("Page").hasMember("orientation")', true, 'Second constructor borrowed property name can be found in properties.'); + is('symbols.getSymbol("Page#orientation").memberOf', "Page", 'Second constructor borrowed property memberOf can be found.'); + is('symbols.getSymbol("Page-getInnerElements").alias', "Page-getInnerElements", 'Can borrow an inner function and it is still inner.'); + is('symbols.getSymbol("Page.units").alias', "Page.units", 'Can borrow a static function and it is still static.'); + + is('symbols.getSymbol("ThreeColumnPage#init").alias', "ThreeColumnPage#init", 'Third constructor method can be found even though method with same name is borrowed.'); + is('symbols.getSymbol("ThreeColumnPage#reset").alias', "ThreeColumnPage#reset", 'Borrowed method can be found.'); + is('symbols.getSymbol("ThreeColumnPage#orientation").alias', "ThreeColumnPage#orientation", 'Twice borrowed method can be found.'); + + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows2.js"]}); + + is('symbols.getSymbol("Foo").hasMethod("my_zop")', true, 'Borrowed method can be found.'); + is('symbols.getSymbol("Bar").hasMethod("my_zip")', true, 'Second borrowed method can be found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/constructs.js"]}); + + is('symbols.getSymbol("Person").hasMethod("say")', true, 'The constructs tag creates a class that lends can add a method to.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/augments.js", SYS.pwd+"test/augments2.js"]}); + + is('symbols.getSymbol("Page").augments[0]', "Layout", 'An augmented class can be found.'); + is('symbols.getSymbol("Page#reset").alias', "Page#reset", 'Method of augmenter can be found.'); + is('symbols.getSymbol("Page").hasMethod("Layout#init")', true, 'Method from augmented can be found.'); + is('symbols.getSymbol("Page").hasMember("Layout#orientation")', true, 'Property from augmented can be found.'); + is('symbols.getSymbol("Page").methods.length', 3, 'Methods of augmented class are included in methods array.'); + + is('symbols.getSymbol("ThreeColumnPage").augments[0]', "Page", 'The extends tag is a synonym for augments.'); + is('symbols.getSymbol("ThreeColumnPage").hasMethod("ThreeColumnPage#init")', true, 'Local method overrides augmented method of same name.'); + is('symbols.getSymbol("ThreeColumnPage").methods.length', 3, 'Local method count is right.'); + + is('symbols.getSymbol("NewsletterPage").augments[0]', "ThreeColumnPage", 'Can augment across file boundaries.'); + is('symbols.getSymbol("NewsletterPage").augments.length', 2, 'Multiple augments are supported.'); + is('symbols.getSymbol("NewsletterPage").inherits[0].alias', "Junkmail#annoy", 'Inherited method with augments.'); + is('symbols.getSymbol("NewsletterPage").methods.length', 6, 'Methods of augmented class are included in methods array across files.'); + is('symbols.getSymbol("NewsletterPage").properties.length', 1, 'Properties of augmented class are included in properties array across files.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/static_this.js"]}); + + is('symbols.getSymbol("box.holder").name', "holder", 'Static namespace name can be found.'); + is('symbols.getSymbol("box.holder.foo").name', "foo", 'Static namespace method name can be found.'); + is('symbols.getSymbol("box.holder").isStatic', true, 'Static namespace method is static.'); + + is('symbols.getSymbol("box.holder.counter").name', "counter", 'Instance namespace property name set on "this" can be found.'); + is('symbols.getSymbol("box.holder.counter").alias', "box.holder.counter", 'Instance namespace property alias set on "this" can be found.'); + is('symbols.getSymbol("box.holder.counter").memberOf', "box.holder", 'Static namespace property memberOf set on "this" can be found.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/lend.js"]}); + + is('symbols.getSymbol("Person").name', "Person", 'Class defined in lend comment is found.'); + is('symbols.getSymbol("Person").hasMethod("initialize")', true, 'Lent instance method name can be found.'); + is('symbols.getSymbol("Person").hasMethod("say")', true, 'Second instance method can be found.'); + is('symbols.getSymbol("Person#sing").isStatic', false, 'Instance method is known to be not static.'); + + is('symbols.getSymbol("Person.getCount").name', "getCount", 'Static method name from second lend comment can be found.'); + is('symbols.getSymbol("Person.getCount").isStatic', true, 'Static method from second lend comment is known to be static.'); + + is('LOG.warnings.filter(function($){if($.indexOf("notok") > -1) return $}).length', 1, 'A warning is emitted when lending to an undocumented parent.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/param_inline.js"]}); + + is('symbols.getSymbol("Layout").params[0].type', "int", 'Inline param name is set.'); + is('symbols.getSymbol("Layout").params[0].desc', "The number of columns.", 'Inline param desc is set from comment.'); + is('symbols.getSymbol("Layout#getElement").params[0].name', "id", 'User defined param documentation takes precedence over parser defined.'); + is('symbols.getSymbol("Layout#getElement").params[0].isOptional', true, 'Default for param is to not be optional.'); + is('symbols.getSymbol("Layout#getElement").params[1].isOptional', false, 'Can mark a param as being optional.'); + is('symbols.getSymbol("Layout#getElement").params[1].type', "number|string", 'Type of inline param doc can have multiple values.'); + is('symbols.getSymbol("Layout#Canvas").params[0].type', "", 'Type can be not defined for some params.'); + is('symbols.getSymbol("Layout#Canvas").params[2].type', "int", 'Type can be defined inline for only some params.'); + is('symbols.getSymbol("Layout#rotate").params.length', 0, 'Docomments inside function sig is ignored without a param.'); + is('symbols.getSymbol("Layout#init").params[2].type', "zoppler", 'Doc comment type overrides inline type for param with same name.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/shared.js", SYS.pwd+"test/shared2.js"]}); + + is('symbols.getSymbol("Array#some").name', 'some', 'The name of a symbol in a shared section is found.'); + is('symbols.getSymbol("Array#some").alias', 'Array#some', 'The alias of a symbol in a shared section is found.'); + is('symbols.getSymbol("Array#some").desc', "Extension to builtin array.", 'A description can be shared.'); + is('symbols.getSymbol("Array#filter").desc', "Extension to builtin array.\nChange every element of an array.", 'A shared description is appended.'); + is('symbols.getSymbol("Queue").desc', "A first in, first out data structure.", 'A description is not shared when outside a shared section.'); + is('symbols.getSymbol("Queue.rewind").alias', "Queue.rewind", 'Second shared tag can be started.'); + is('symbols.getSymbol("startOver").alias', "startOver", 'Shared tag doesnt cross over files.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/config.js"]}); + is('symbols.getSymbol("Contact").params[0].name', 'person', 'The name of a param is found.'); + is('symbols.getSymbol("Contact").params[1].name', 'person.name', 'The name of a param set with a dot name is found.'); + is('symbols.getSymbol("Contact").params[2].name', 'person.age', 'The name of a second param set with a dot name is found.'); + is('symbols.getSymbol("Contact").params[4].name', 'connection', 'The name of a param after config is found.'); + + is('symbols.getSymbol("Family").params[0].name', 'persons', 'Another name of a param is found.'); + is('symbols.getSymbol("Family").params[1].name', 'persons.Father', 'The name of a param+config is found.'); + is('symbols.getSymbol("Family").params[2].name', 'persons.Mother', 'The name of a second param+config is found.'); + is('symbols.getSymbol("Family").params[3].name', 'persons.Children', 'The name of a third param+config is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/ignore.js"]}); + is('LOG.warnings.filter(function($){if($.indexOf("undocumented symbol Ignored") > -1) return $}).length', 1, 'A warning is emitted when documenting members of an ignored parent.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_anon.js"]}); + is('symbols.getSymbol("a.b").alias', 'a.b', 'In anonymous constructor this is found to be the container object.'); + is('symbols.getSymbol("a.f").alias', 'a.f', 'In anonymous constructor this can have a method.'); + is('symbols.getSymbol("a.c").alias', 'a.c', 'In anonymous constructor method this is found to be the container object.'); + is('symbols.getSymbol("g").alias', 'g', 'In anonymous function executed inline this is the global.'); + is('symbols.getSymbol("bar2.p").alias', 'bar2.p', 'In named constructor executed inline this is the container object.'); + is('symbols.getSymbol("module.pub").alias', 'module.pub', 'In parenthesized anonymous function executed inline function scoped variables arent documented.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/oblit_anon.js"]}); + is('symbols.getSymbol("opt").name', 'opt', 'Anonymous object properties are created.'); + is('symbols.getSymbol("opt.conf.keep").alias', 'opt.conf.keep', 'Anonymous object first property is assigned to $anonymous.'); + is('symbols.getSymbol("opt.conf.base").alias', 'opt.conf.base', 'Anonymous object second property is assigned to $anonymous.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/params_optional.js"]}); + is('symbols.getSymbol("Document").params.length', 3, 'Correct number of params are found when optional param syntax is used.'); + is('symbols.getSymbol("Document").params[1].name', "id", 'Name of optional param is found.'); + is('symbols.getSymbol("Document").params[1].isOptional', true, 'Optional param is marked isOptional.'); + is('symbols.getSymbol("Document").params[2].name', "title", 'Name of optional param with default value is found.'); + is('symbols.getSymbol("Document").params[2].isOptional', true, 'Optional param with default value is marked isOptional.'); + is('symbols.getSymbol("Document").params[2].defaultValue', " This is untitled.", 'Optional param default value is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/synonyms.js"]}); + is('symbols.getSymbol("myObject.myFunc").type', 'function', 'Type can be set to function.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/event.js"]}); + is('symbols.getSymbol("Kitchen#event:cakeEaten").isEvent', true, 'Function with event prefix is an event.'); + is('symbols.getSymbol("Kitchen#cakeEaten").isa', "FUNCTION", 'Function with same name as event isa function.'); + } + , + function() { + symbolize({x:"js", a:true, _: [SYS.pwd+"test/scripts/"]}); + is('JSDOC.JsDoc.srcFiles.length', 1, 'Only js files are scanned when -x=js.'); + } + , + function() { + symbolize({x:"js", a:true, _: [SYS.pwd+"test/exports.js"]}); + is('symbols.getSymbol("mxn.Map#doThings").name', 'doThings', 'Exports creates a documentation alias that can have methods.'); + } + , + function() { + symbolize({p:true, a:true, _: [SYS.pwd+"test/module.js"]}); + is('symbols.getSymbol("myProject.myModule.myPublicMethod").name', 'myPublicMethod', 'A function wrapped in parens can be recognized.'); + is('symbols.getSymbol("myProject.myModule-myPrivateMethod").name', 'myPrivateMethod', 'A private method in the scope of a function wrapped in parens can be recognized.'); + is('symbols.getSymbol("myProject.myModule-myPrivateVar").name', 'myPrivateVar', 'A private member in the scope of a function wrapped in parens can be recognized.'); + } +]; + +//// run and print results +print(testrun(testCases)); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/addon.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/addon.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,24 @@ +String.prototype.reverse = function() { +} + +String.prototype.reverse.utf8 = function() { +} + +Function.count = function() { +} + +/** @memberOf Function */ +Function.count.reset = function() { +} + +/** @memberOf Function */ +count.getValue = function() { +} + +/** @memberOf Function.prototype */ +getSig = function() { +} + +/** @memberOf Function.prototype */ +Function.prototype.getProps = function() { +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/anon_inner.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/anon_inner.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,14 @@ +/** + * @name bar + * @namespace + */ + +new function() { + /** + * @name bar-foo + * @function + * @param {number} x + */ + function foo(x) { + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/augments.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/augments.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,31 @@ +/** +@constructor +*/ +function Layout(p) { + this.init = function(p) { + } + + this.getId = function() { + } + + /** @type Page */ + this.orientation = "landscape"; +} + +/** +@constructor +@augments Layout +*/ +function Page() { + this.reset = function(b) { + } +} + +/** +@extends Page +@constructor +*/ +function ThreeColumnPage() { + this.init = function(resetCode) { + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/augments2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/augments2.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,26 @@ +/** +@constructor +*/ +function LibraryItem() { + this.reserve = function() { + } +} + +/** +@constructor +*/ +function Junkmail() { + this.annoy = function() { + } +} + +/** +@inherits Junkmail.prototype.annoy as pester +@augments ThreeColumnPage +@augments LibraryItem +@constructor +*/ +function NewsletterPage() { + this.getHeadline = function() { + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/borrows.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/borrows.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,46 @@ +/** +@constructor +*/ +function Layout(p) { + /** initilize 1 */ + this.init = function(p) { + } + + /** get the id */ + this.getId = function() { + } + + /** @type string */ + this.orientation = "landscape"; + + function getInnerElements(elementSecretId){ + } +} + +/** A static method. */ +Layout.units = function() { +} + +/** +@constructor +@borrows Layout#orientation +@borrows Layout-getInnerElements +@borrows Layout.units +*/ +function Page() { + /** reset the page */ + this.reset = function(b) { + } +} + +/** +@constructor +@borrows Layout.prototype.orientation as this.orientation +@borrows Layout.prototype.init as #init +@inherits Page.prototype.reset as #reset +*/ +function ThreeColumnPage() { + /** initilize 2 */ + this.init = function(p) { + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/borrows2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/borrows2.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,23 @@ +// testing circular borrows + +/** + @class + @borrows Bar#zop as this.my_zop +*/ +function Foo() { + /** this is a zip. */ + this.zip = function() {} + + this.my_zop = new Bar().zop; +} + +/** + @class + @borrows Foo#zip as this.my_zip +*/ +function Bar() { + /** this is a zop. */ + this.zop = function() {} + + this.my_zip = new Foo().zip; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/config.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/config.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,22 @@ +/** + * @constructor + * @param person The person. + * @param {string} person.name The person's name. + * @config {integer} age The person's age. + * @config [id=1] Optional id number to use. + * @param connection + */ +function Contact(person, connection) { + +} + +/** + * @constructor + * @param persons + * @config {string} Father The paternal person. + * @config {string} Mother The maternal person. + * @config {string[]} Children And the rest. + */ +function Family(/**Object*/persons) { + +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/constructs.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/constructs.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,18 @@ +var Person = makeClass( + /** + @scope Person + */ + { + /** + This is just another way to define a constructor. + @constructs + @param {string} name The name of the person. + */ + initialize: function(name) { + this.name = name; + }, + say: function(message) { + return this.name + " says: " + message; + } + } +); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/encoding.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/encoding.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ + +/** + * @Constructor + * @desc 配置文件 + * @class 什么也不返回 + */ +function Test(conf) { + // do something; +} + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/encoding_other.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/encoding_other.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,12 @@ + +/** + * @Constructor + * @desc + * @class + */ +function Test(conf) { + // do something; +} + +// run with commanline option -e=iso-8859-5 + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/event.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/event.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,54 @@ +/** + * @name Kitchen + * @constructor + * @fires Bakery#event:donutOrdered + */ + +/** + * Fired when some cake is eaten. + * @name Kitchen#event:cakeEaten + * @function + * @param {Number} pieces The number of pieces eaten. + */ + +/** + * Find out if cake was eaten. + * @name Kitchen#cakeEaten + * @function + * @param {Boolean} wasEaten + */ + +/** + * @name getDesert + * @function + * @fires Kitchen#event:cakeEaten + */ + +/** + * @name Bakery + * @constructor + * @extends Kitchen + */ + +/** + * Fired when a donut order is made. + * @name Bakery#event:donutOrdered + * @event + * @param {Event} e The event object. + * @param {String} [e.topping] Optional sprinkles. + */ + +/** + * @constructor + * @borrows Bakery#event:donutOrdered as this.event:cakeOrdered + */ +function CakeShop() { +} + +/** @event */ +CakeShop.prototype.icingReady = function(isPink) { +} + +/** @event */ +function amHungry(/**Boolean*/enoughToEatAHorse) { +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/exports.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/exports.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,14 @@ +/** @namespace */ +var mxn = {}; + +(function(){ + /** @exports Map as mxn.Map */ + var Map = + /** @constructor */ + mxn.Map = function() { + }; + + /** A method. */ + Map.prototype.doThings = function() { + }; +})(); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/functions_anon.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/functions_anon.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,39 @@ +/** an anonymous constructor executed inline */ +a = new function() { + /** a.b*/ + this.b = 1; + /** a.f */ + this.f = function() { + /** a.c */ + this.c = 2; + } +} + + +/** + named function executed inline +*/ +bar1 = function Zoola1() { + /** property of global */ + this.g = 1; +}(); + +/** + named constructor executed inline +*/ +bar2 = new function Zoola2() { + /** property of bar */ + this.p = 1; +}; + +/** module pattern */ +module = (function () { + /** won't appear in documentation */ + var priv = 1; + + /** @scope module */ + return { + /** will appear as a property of module */ + pub: 1 + } +})(); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/functions_nested.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/functions_nested.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,33 @@ +/** @constructor */ +function Zop() { +} + +/** + @class +*/ +Foo = function(id) { + // this is a bit twisted, but if you call Foo() you will then + // modify Foo(). This is kinda, sorta non-insane, because you + // would have to call Foo() 100% of the time to use Foo's methods + Foo.prototype.methodOne = function(bar) { + alert(bar); + }; + + // same again + Foo.prototype.methodTwo = function(bar2) { + alert(bar2); + }; + + // and these are only executed if the enclosing function is actually called + // and who knows if that will ever happen? + Bar = function(pez) { + alert(pez); + }; + Zop.prototype.zap = function(p){ + alert(p); + }; + + // but this is only visible inside Foo + function inner() { + } +}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/global.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/global.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,13 @@ +/** ecks */ +var x = [1, 2, 4]; + +var y = { + foo: function(){ + } +} + +bar = function() { +} + +function zop() { +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/globals.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/globals.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,25 @@ +function example(/**Circle*/a, b) { + /** a global defined in function */ + var number = a; + + var hideNumber = function(){ + } + + setNumber = function(){ + } + alert('You have chosen: ' + b); +} + +function initPage() { + var supported = document.createElement && document.getElementsByTagName; + if (!supported) return; + // start of DOM script + var x = document.getElementById('writeroot'); + // etc. +} + +/** an example var */ +var document = new Document(x, y); + +var getNumber = function(){ +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/ignore.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/ignore.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ +/** + * A test constructor. + * @constructor + * @ignore + */ +function Ignored() { + /** a method */ + this.bar = function() { + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/inner.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/inner.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,16 @@ +/** + * @constructor + */ +function Outer() { + /** + * @constructor + */ + function Inner(name) { + /** The name of this. */ + this.name = name; + } + + this.open = function(name) { + return (new Inner(name)); + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/jsdoc_test.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/jsdoc_test.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,477 @@ +/** + * @fileoverview This file is to be used for testing the JSDoc parser + * It is not intended to be an example of good JavaScript OO-programming, + * nor is it intended to fulfill any specific purpose apart from + * demonstrating the functionality of the + * JSDoc parser + * + * @author Gabriel Reid gab_reid@users.sourceforge.net + * @version 0.1 + */ + + +/** + * Construct a new Shape object. + * @class This is the basic Shape class. + * It can be considered an abstract class, even though no such thing + * really existing in JavaScript + * @constructor + * @throws MemoryException if there is no more memory + * @throws GeneralShapeException rarely (if ever) + * @return {Shape|Coordinate} A new shape. + */ +function Shape(){ + + /** + * This is an example of a function that is not given as a property + * of a prototype, but instead it is assigned within a constructor. + * For inner functions like this to be picked up by the parser, the + * function that acts as a constructor must be denoted with + * the @constructor tag in its comment. + * @type String + */ + this.getClassName = function(){ + return "Shape"; + } + + /** + * This is an inner method, just used here as an example + * @since version 0.5 + * @author Sue Smart + */ + function addReference(){ + // Do nothing... + } + +} + +/** + * Create a new Hexagon instance. + * @extends Shape + * @class Hexagon is a class that is a logical sublcass of + * {@link Shape} (thanks to the @extends tag), but in + * reality it is completely unrelated to Shape. + * @param {int} sideLength The length of one side for the new Hexagon + * @example + * var h = new Hexagon(2); + * @example + * if (hasHex) { + * hex = new Hexagon(5); + * color = hex.getColor(); + * } + */ +function Hexagon(sideLength) { +} + + +/** + * This is an unattached (static) function that adds two integers together. + * @param {int} One The first number to add + * @param {int} Two The second number to add + * @author Gabriel Reid + * @deprecated So you shouldn't use it anymore! Use {@link Shape#getClassName} instead. + */ +function Add(One, Two){ + return One + Two; +} + + +/** + * The color of this shape + * @type Color + */ +Shape.prototype.color = null; + +/** + * The border of this shape. + * @field + * @type int + */ +Shape.prototype.border = function(){return border;}; + +/* + * These are all the instance method implementations for Shape + */ + +/** + * Get the coordinates of this shape. It is assumed that we're always talking + * about shapes in a 2D location here. + * @requires The {@link Shape} class + * @returns A Coordinate object representing the location of this Shape + * @type Coordinate[] + */ +Shape.prototype.getCoords = function(){ + return this.coords; +} + +/** + * Get the color of this shape. + * @see #setColor + * @see The Color library. + * @link Shape + * @type Color + */ +Shape.prototype.getColor = function(){ + return this.color; +} + +/** + * Set the coordinates for this Shape + * @param {Coordinate} coordinates The coordinates to set for this Shape + */ +Shape.prototype.setCoords = function(coordinates){ + this.coords = coordinates; +} + +/** + * Set the color for this Shape + * @param {Color} color The color to set for this Shape + * @param other There is no other param, but it can still be documented if + * optional parameters are used + * @throws NonExistantColorException (no, not really!) + * @see #getColor + */ +Shape.prototype.setColor = function(color){ + this.color = color; +} + +/** + * Clone this shape + * @returns A copy of this shape + * @type Shape + * @author Gabriel Reid + */ +Shape.prototype.clone = function(){ + return new Shape(); +} + +/** + * Create a new Rectangle instance. + * @class A basic rectangle class, inherits from Shape. + * This class could be considered a concrete implementation class + * @constructor + * @param {int} width The optional width for this Rectangle + * @param {int} height Thie optional height for this Rectangle + * @author Gabriel Reid + * @see Shape is the base class for this + * @augments Shape + * @hilited + */ +function Rectangle(width, // This is the width + height // This is the height + ){ + if (width){ + this.width = width; + if (height){ + this.height = height; + } + } +} + + +/* Inherit from Shape */ +Rectangle.prototype = new Shape(); + +/** + * Value to represent the width of the Rectangle. + *
Text in bold and italic and a + * link to SourceForge + * @private + * @type int + */ +Rectangle.prototype.width = 0; + +/** + * Value to represent the height of the Rectangle + * @private + * @type int + */ +Rectangle.prototype.height = 0; + +/** + * Get the type of this object. + * @type String + */ +Rectangle.prototype.getClassName= function(){ + return "Rectangle"; +} + +/** + * Get the value of the width for the Rectangle + * @type int + * @see Rectangle#setWidth + */ +Rectangle.prototype.getWidth = function(){ + return this.width; +} + +/** + * Get the value of the height for the Rectangle. + * Another getter is the {@link Shape#getColor} method in the + * {@link Shape} base class. + * @return The height of this Rectangle + * @type int + * @see Rectangle#setHeight + */ +Rectangle.prototype.getHeight = function(){ + return this.height; +} + +/** + * Set the width value for this Rectangle. + * @param {int} width The width value to be set + * @see #setWidth + */ +Rectangle.prototype.setWidth = function(width){ + this.width = width; +} + +/** + * Set the height value for this Rectangle. + * @param {int} height The height value to be set + * @see #getHeight + */ +Rectangle.prototype.setHeight = function(height){ + this.height = height; +} + +/** + * Get the value for the total area of this Rectangle + * @return total area of this Rectangle + * @type int + */ +Rectangle.prototype.getArea = function(){ + return width * height; +} + + +/** + * Create a new Square instance. + * @class A Square is a subclass of {@link Rectangle} + * @param {int} width The optional width for this Rectangle + * @param {int} height The optional height for this Rectangle + * @augments Rectangle + */ +function Square(width, height){ + if (width){ + this.width = width; + if (height){ + this.height = height; + } + } + +} + +/* Square is a subclass of Rectangle */ +Square.prototype = new Rectangle(); + +/** + * Set the width value for this Shape. + * @param {int} width The width value to be set + * @see #getWidth + */ +Square.prototype.setWidth = function(width){ + this.width = this.height = width; +} + +/** + * Set the height value for this Shape + * Sets the {@link Rectangle#height} attribute in the Rectangle. + * @param {int} height The height value to be set + */ +Square.prototype.setHeight = function(height){ + this.height = this.width = height; +} + + +/** + * Create a new Circle instance based on a radius. + * @class Circle class is another subclass of Shape + * @extends Shape + * @param {int} radius The optional radius of this {@link Circle } + * @mixin Square.prototype.setWidth as this.setDiameter + */ +function Circle(radius){ + if (radius) { + /** The radius of the this Circle. */ + this.radius = radius; + } +} + +/* Circle inherits from {@link Shape} */ +Circle.prototype = new Shape(); + +/** + * The radius value for this Circle + * @private + * @type int + */ +Circle.prototype.radius = 0; + +/** + * A very simple class (static) field that is also a constant + * @final + * @type float + */ +Circle.PI = 3.14; + +/** + * Get the radius value for this Circle + * @type int + * @see #setRadius + */ +Circle.prototype.getRadius = function(){ + return this.radius; +} + +/** + * Set the radius value for this Circle + * @param {int} radius The {@link Circle#radius} value to set + * @see #getRadius + */ +Circle.prototype.setRadius = function(radius){ + this.radius = radius; +} + +/** + * An example of a class (static) method that acts as a factory for Circle + * objects. Given a radius value, this method creates a new Circle. + * @param {int} radius The radius value to use for the new Circle. + * @type Circle + */ +Circle.createCircle = function(radius){ + return new Circle(radius); +} + + +/** + * Create a new Coordinate instance based on x and y grid data. + * @class Coordinate is a class that can encapsulate location information. + * @param {int} [x=0] The optional x portion of the Coordinate + * @param {int} [y=0] The optinal y portion of the Coordinate + */ +function Coordinate(x, y){ + if (x){ + this.x = x; + if (y){ + this.y = y; + } + } +} + +/** + * The x portion of the Coordinate + * @type int + * @see #getX + * @see #setX + */ +Coordinate.prototype.x = 0; + +/** + * The y portion of the Coordinate + * @type int + * @see #getY + * @see #setY + */ +Coordinate.prototype.y = 0; + +/** + * Gets the x portion of the Coordinate. + * @type int + * @see #setX + */ +Coordinate.prototype.getX = function(){ + return this.x; +} + +/** + * Get the y portion of the Coordinate. + * @type int + * @see #setY + */ +Coordinate.prototype.getY = function(){ + return this.y; +} + +/** + * Sets the x portion of the Coordinate. + * @param {int} x The x value to set + * @see #getX + */ +Coordinate.prototype.setX = function(x){ + this.x = x; +} + +/** + * Sets the y portion of the Coordinate. + * @param {int} y The y value to set + * @see #getY + */ +Coordinate.prototype.setY = function(y){ + this.y = y; +} + +/** + * @class This class exists to demonstrate the assignment of a class prototype + * as an anonymous block. + */ +function ShapeFactory(){ +} + +ShapeFactory.prototype = { + /** + * Creates a new {@link Shape} instance. + * @return A new {@link Shape} + * @type Shape + */ + createShape: function(){ + return new Shape(); + } +} + +/** + * An example of a singleton class + * @param ... Arguments represent {@link coordinate}s in the shape. + * @constructor + */ +MySingletonShapeFactory = function(){ + + /** + * Get the next {@link Shape} + * @type Shape + * @return A new {@link Shape} + */ + this.getShape = function(){ + return null; + } + +} + + +/** + * Create a new Foo instance. + * @class This is the Foo class. It exists to demonstrate 'nested' classes. + * @constructor + * @see Foo.Bar + */ +function Foo(){} + +/** + * Creates a new instance of Bar. + * @class This class exists to demonstrate 'nested' classes. + * @constructor + * @see Foo.Bar + */ +function Bar(){} + +/** + * Nested class + * @constructor + */ +Foo.Bar = function(){ + /** The x. */ this.x = 2; +} + +Foo.Bar.prototype = new Bar(); +/** The y. */ +Foo.Bar.prototype.y = '3'; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/lend.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/lend.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,33 @@ + /** @class */ +var Person = Class.create( + /** + @lends Person.prototype + */ + { + initialize: function(name) { + this.name = name; + }, + say: function(message) { + return this.name + ': ' + message; + } + } + ); + +/** @lends Person.prototype */ +{ + /** like say but more musical */ + sing: function(song) { + } +} + +/** @lends Person */ +{ + getCount: function() { + } +} + +/** @lends Unknown.prototype */ +{ + notok: function() { + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/memberof.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/memberof.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,19 @@ +/** @constructor */ +pack = function() { + this.init = function(){} + function config(){} +} + + pack.build = function(task) {}; + +/** @memberOf pack */ +pack.install = function() {} + +/** @memberOf pack */ +pack.install.overwrite = function() {} + +/** @memberOf pack */ +clean = function() {} + +/** @memberOf pack-config */ +install = function() {}; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/memberof2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/memberof2.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,38 @@ +/** + * @constructor + */ +function Foo() { + /** + @memberOf Foo.prototype + */ + function bar(a, b) { + } + + /** + @memberOf Foo + */ + var zip = function(p, q) { + } + + /** + @memberOf Foo + */ + function zop( x,y ) { + } + + /** + @memberOf Foo + @constructor + */ + function Fiz() { + /** A method of Foo#Fiz. */ + this.fipple = function(fop){} + } +} + +/** + @memberOf Foo# + */ +var blat = function() { + +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/memberof3.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/memberof3.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,33 @@ +/** +* @name Foo +* @class +*/ + +/**#@+ +* @memberOf Foo# +* @field +*/ + +/** +* @name bar +* @type Object[] +*/ + +/**#@-*/ + +/** +* @name Foo2 +* @class +*/ + +/**#@+ +* @memberOf Foo2# +* @field +*/ + +/** +* @name bar +* @type Object[] +*/ + +/**#@-*/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/memberof_constructor.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/memberof_constructor.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,17 @@ +/** @constructor */ +function Circle(){} + +/** + @constructor + @memberOf Circle# + */ +Circle.prototype.Tangent = function(){}; + +// renaming Circle#Tangent to Circle#Circle#Tangent + +/** + @memberOf Circle#Tangent# + */ +Circle.prototype.Tangent.prototype.getDiameter = function(){}; + + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/module.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/module.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,17 @@ +/** @namespace */ +myProject = myProject || {}; + +/** @namespace */ +myProject.myModule = (function () { + /** describe myPrivateVar here */ + var myPrivateVar = ""; + + var myPrivateMethod = function () { + } + + /** @scope myProject.myModule */ + return { + myPublicMethod: function () { + } + }; +})(); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/multi_methods.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/multi_methods.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,25 @@ + +/** + Get the entire flavor. + @name flavor^3 + @function + @returns {Object} The entire flavor hash. +*/ +/** + Get a named flavor. + @name flavor^2 + @function + @param {String} name The name of the flavor to get. + @returns {String} The value of that flavor. +*/ +/** + Set the flavor. + @param {String} name The name of the flavor to set. + @param {String} value The value of the flavor. + @returns {String} The value of that flavor. +*/ +function flavor(name, value) { + if (arguments.length > 1) flavor[name] = value; + else if (arguments.length == 1) return flavor[name]; + else return flavor; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/name.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/name.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,19 @@ +/** + @name Response + @class +*/ + +Response.prototype = { + /** + @name Response#text + @function + @description + Gets the body of the response as plain text + @returns {String} + Response as text + */ + + text: function() { + return this.nativeResponse.responseText; + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/namespace_nested.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/namespace_nested.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,23 @@ +/** + @namespace This is the first namespace. +*/ +ns1 = {}; + +/** + This is the second namespace. + @namespace +*/ +ns1.ns2 = {}; + +/** + This part of ns1.ns2 + @constructor +*/ +ns1.ns2.Function1 = function() { +}; + +ns1.staticFunction = function() { +}; + +/** A static field in a namespace. */ +ns1.ns2.staticField = 1; diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/nocode.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/nocode.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,13 @@ +/**#nocode+*/ + /** + @name star + @function + */ + function blahblah() { + + } +/**#nocode-*/ + +function yaddayadda() { + +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/oblit_anon.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/oblit_anon.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,20 @@ +/** the options */ +opt = Opt.get( + arguments, + { + d: "directory", + c: "conf", + "D[]": "define" + } +); + +/** configuration */ +opt.conf = { + /** keep */ + keep: true, + /** base */ + base: getBase(this, {p: properties}) +} + + + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/overview.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/overview.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,20 @@ +/** + * @overview This "library" contains a + * lot of classes and functions. + * @example +
+	var x (x < 1);
+	alert("This 'is' \"code\"");
+ 
+ * @name My Cool Library + * @author Joe Smith jsmith@company.com + * @version 0.1 + */ + +/** + * Gets the current foo + * @param {String} fooId The unique identifier for the foo. + * @return {Object} Returns the current foo. + */ +function getFoo(fooID){ +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/param_inline.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/param_inline.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,37 @@ +/** + @constructor + @param columns The number of columns. +*/ +function Layout(/**int*/columns){ + /** + @param [id] The id of the element. + @param elName The name of the element. + */ + this.getElement = function( + /** string */ elName, + /** number|string */ id + ) { + }; + + /** + @constructor + */ + this.Canvas = function(top, left, /**int*/width, height) { + /** Is it initiated yet? */ + this.initiated = true; + } + + this.rotate = function(/**nothing*/) { + } + + /** + @param x + @param y + @param {zoppler} z*/ + this.init = function(x, y, /**abbler*/z) { + /** The xyz. */ + this.xyz = x+y+z; + this.getXyz = function() { + } + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/params_optional.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/params_optional.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,8 @@ + +/** + * @param {Page[]} pages + * @param {number} [id] Specifies the id, if applicable. + * @param {String} [title = This is untitled.] Specifies the title. + */ +function Document(pages, id, title){ +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/prototype.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/prototype.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,17 @@ +/** @constructor */ +function Article() { +} + +Article.prototype.init = function(title) { + /** the instance title */ + this.title = title; + + /** the static counter */ + Article.counter = 1; +} + +a = new Article(); +a.Init("my title"); + +print(a.title); +print(Article.counter); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/prototype_nested.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/prototype_nested.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,9 @@ +/** @constructor */ +function Word() { +} + +Word.prototype.reverse = function() { +} + +Word.prototype.reverse.utf8 = function() { +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/prototype_oblit.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/prototype_oblit.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,13 @@ +/** @constructor */ +function Article() { +} + +Article.prototype = { + /** instance get title */ + getTitle: function(){ + } +} + +/** static get title */ +Article.getTitle = function(){ +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/prototype_oblit_constructor.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/prototype_oblit_constructor.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,24 @@ +/** @constructor */ +function Article() { +} + +Article.prototype = { + /** @constructor */ + Title: function(title) { + /** the value of the Title instance */ + this.title = title; + }, + + init: function(pages) { + /** the value of the pages of the Article instance */ + this.pages = pages; + } +} + +f = new Article(); +f.init("one two three"); + +t = new f.Title("my title"); + +print(f.pages); +print(t.title); \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/public.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/public.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,10 @@ +/**@constructor*/ +function Foo() { + /** + @public + @static + @field + */ + var bar = function(x) { + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/scripts/code.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/scripts/code.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,5 @@ +/** + @class + */ +function thisiscode() { +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/scripts/notcode.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/scripts/notcode.txt Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,5 @@ +(This is not code) +function foo(){{{{ +( +! +@ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/shared.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/shared.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,42 @@ + +/** + * Builtin object. + * @class + * @name Array + */ + +/**#@+ + * Extension to builtin array. + * @memberOf Array + * @method + */ + +/** + * @returns Boolen if some array members... + */ +Array.prototype.some = function(){}; + +/** + * Change every element of an array. + * @returns Filtered array copy. + */ +Array.prototype.filter = function(){}; + +/**#@-*/ + + +/** + * A first in, first out data structure. + * @constructor + */ +Queue = function(){}; + +/**#@+ + * Extension to Queue. + * @memberOf Queue + */ + +rewind = function(){ +} + +// should close automatically here. \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/shared2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/shared2.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,2 @@ +startOver = function(){ +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/shortcuts.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/shortcuts.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,22 @@ +// /**#=+ +// * { +// * 'D': 'Date.prototype', +// * '$N': 'Number' +// * } +// */ +// var D = Date.prototype, +// $N = Number; +// +// D.locale = function(){ +// }; +// +// /** +// @return {string} The cardinal number string. +// */ +// $N.nth = function(n){ +// }; +// +// LOAD.file = function(){ +// } +// +// /**#=-*/ \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/static_this.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/static_this.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,13 @@ +/** the parent */ +var box = {}; + +/** @namespace */ +box.holder = {} + +box.holder.foo = function() { + /** the counter */ + this.counter = 1; +} + +box.holder.foo(); +print(box.holder.counter); diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/synonyms.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/synonyms.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,31 @@ +/** + @class + @inherits Bar#zop as #my_zop +*/ +function Foo() { + /** this is a zip. */ + this.zip = function() {} + + /** from Bar */ + this.my_zop = new Bar().zop; +} + +/** + @class + @borrows Foo#zip as this.my_zip +*/ +function Bar() { + /** this is a zop. */ + this.zop = function() {} + + /** from Foo */ + this.my_zip = new Foo().zip; +} + +/** @namespace */ +var myObject = { + /** + @type function + */ + myFunc: getFunction() +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/tosource.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/tosource.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,23 @@ +/** + * @param {Object} object + * @return {string} + */ +function valueOf(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function toString(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function toSource(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function constructor(object) {} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/app/test/variable_redefine.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/app/test/variable_redefine.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,14 @@ +/** @constructor */ +function Foo() { + var bar = 1; + bar = 2; // redefining a private + + this.baz = 1; + baz = 2; // global + + /** a private */ + var blap = { + /** in here */ + tada: 1 + } +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/changes.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/changes.txt Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,124 @@ +== 2.4.0 == + + * Fixed bug that added mutiple symbols with the same name to docs. + * Added support for the -m option to suppress warnings for multiple docs. + * Added patch by brownsea42 to support quoted user variables on the command line. ( issue #281 ) + * Fixed bug that sometimes caused links to events to be incorrect. ( issue #292 ) + +== 2.3.3 == + + * Fixed bug that made all fields declared with the @property tag static. ( issue #262 ) + * Minor fix to better handle trailing slash on path to template (from jwmetrocat). ( issue #237 ) + * Fix for @memberOf when applied to inner members. ( issue #264 ) + * Fix for @memberOf when applied to symbols documented with @name. ( issue #260 ) + * Applied patch from kunhualqk, fix for bug where @link to borrowed member did not resolve to parent class. ( issue #218 ) + * Fix for @requires not linking back to the required class + * Added experimental support for @constructs to have an argument, the class name, when applied to a function assignment. + +== 2.3.2 == + + * Minor update to the usage notes and corrected the version number displayed in the output. + +== 2.3.1 == + + * Fixed HTML typo in allfiles template. ( issue #228 ) + * Modified template to display version information for classes. + * Modified template to better support multiple methods with the same name. + * Fixed bug that caused template to error when backtick characters appeared around class names. + +== 2.3.0 == + + * Added option -u, --unique to avoid bug that causes multiple symbols with names that differ only by case to overwrite each others output on case-insensitive filesystems. ( issue #162 ) + * Fixed bug where {@links} in @deprecated tags did not resolve. ( issue #220 ) + * Fixed bug that caused parens around a function to make it to be unrecognized. ( issue #213 ) + * Fixed bug prevented explicit links to named anchors from working (thanks katgao.pku). ( issue #215 ) + * Fixed bug that prevented full description from appearing in file overview. ( issue #224 ) + +== 2.2.1 == + + * Fixed bug with class template, where sorting of methods was accidentally removed (thanks dezfowler). + * Added missing test files for the @exports unit tests. + +== 2.2.0 == + + * Fixed bug that caused exception when given a folder containing non-js files, even with the x commandline option set to "js". ( issue #193 ) + * Fixed typo in index template [patch submitted by olle]. ( issue #198 ) + * Modified @borrows tag experimentally to allow for missing "as ..." clause. + * Added support for the @exports tag, to allow one symbol to be documented as another. + * Added support for the -S option to document code following the Secure Modules pattern. + +== 2.1.0 == + + * Added support for the @event tag. + * Fixed bug that prevented the : character from appearing in symbol names. + * Fixed bug that prevented underscored symbols marked with @public being tagged as private. (issue #184 ) + * Fixed bug that randomly affected the @memberOf tag when the name of the symbol did not include the parent name. + * Fixed bug that prevented templates that were not in the jsdoc-toolkit folder from being found. ( issue #176 ) + * Added ability to check for trailing slash on template path. ( issue #177 ) + * Modified classDesc so that it no longer is appended with the constructor desc. + * Fixed call to plugin onDocCommentSrc. + * Added missing support for inline doc comments for function return types. ( issue #189 ) + * Added command line option -q, --quiet. + * Added command line option -E, --exclude. ( issue #143 ) + * Added 2 more hooks for plugins. ( issue #163 ) + * Added support for extending built-ins. ( issue #160 ) + * Added "compact" option to JSDOC.JsPlate.prototype.process. ( issue #159 ) + * @augments no longer documents static members as inherited. ( issue #138 ) + * @link to a class now goes to the page for that class, not the constructor. ( issue #178 ) + * Warnings of mismatched curly brace now include filename. ( issue #166 ) + * Fixed bug affecting template paths loaded via a configuration file when the trailing slash is missing. ( issue #191 ) + * Minor optimizations. + +== 2.0.2 == + + * Fixed bug that sometimes caused an example of division in the source code to be interpretted as a regex by the JsDoc Toolkit analyzer. ( issue #158 ) + * Fixed a bug that prevented private variables marked as @public from appearing in the documentation. ( issue #161 ) + * Fixed bug that prevented variable names with underscored properties from appearing in summaries. ( issue #173 ) + +== 2.0.1 == + + * Fixed bug that prevented @fileOverview tag from being recognized. + * Added support for @fieldOf as a synonym for @field plus @memberOf. + * Added support for @name tag in a @fileOverview comment to control the displayed name of the file. + * Added support for multiple @example tags. ( issue #152 ) + * Modified style sheet of jsdoc template to make more readable. ( issue #151 ) + * Fixed bug that prevented @since documentation from displaying correctly when it appeared in a class. ( issue #150 ) + * Fixed bug that caused inhertited properties to sometimes not resolve correctly. ( issue #144 ) + * Modified so that trailing whitespace in @example is always trimmed. ( issue #153 ) + * Added support for elseif to JsPlate. (hat tip to fredck) + * Added support for @location urls in the @overview comment to the jsdoc template. + +== Changes From Versions 1.4.0 to 2.0.0 == + + * Upgraded included version of Rhino from 1.6 to 1.7R1. + * Removed circular references in parsed documentation objects. + * Improved inheritance handling, now properties and events can be inherited same as methods. + * Improved handling of cross-file relationships, now having two related objects in separate files is not a problem. + * Improved ability to recognize membership of previously defined objects. + * Added ability to redefine parsing behavior with plugins. + * @methodOf is a synonym for @function and @memberOf. + * Added @default to document default values of members that are objects. + * Added ability to parse and refer to inner functions. + * Fixed bug that appeared when calling a method to set properties of the instance referred to by "this". + * Added ability to automatically create links to other symbols. + * New "jsdoc" template now produces fully W3C valid XHTML. + * Inline parameter type hint comments are now documented. + * Fixed error: Locally scoped variables (declared with var) no longer appear as global. + * It is now possible to run JsDoc Toolkit from any directory. + * Added support for inline {@link ...} tags. + * Added support for the -H command-line option to allow for custom content handlers. + * Tag names @inherits and @scope changed to @borrows and @lends. + ? Combining @constructor in a doclet with @lends now supported. + * Multiple @lend tags now supported. + * Added support for the @constructs tag, used inside a @lends block. + * Added support for the @constant tag. + * Fixed bug that prevented the use of [] as a default value. + * Added support for the @field tag. + * Added support for the @public tag (applied to inner functions). + * @namespace tag can now be applied to functions, not just object literals. + * Added support for the -s command line option to suppress source code output. + * Added new unit test framework. + * Underscored symbols are now treated as if they have a @private tag by default. + * Improved support for anonymous constructors. + * Added support for the nocode meta tag. + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/conf/sample.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/conf/sample.conf Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,31 @@ +/* + This is an example of one way you could set up a configuration file to more + conveniently define some commandline options. You might like to do this if + you frequently reuse the same options. Note that you don't need to define + every option in this file, you can combine a configuration file with + additional options on the commandline if your wish. + + You would include this configuration file by running JsDoc Toolkit like so: + java -jar jsrun.jar app/run.js -c=conf/sample.conf + +*/ + +{ + // source files to use + _: ['app/test/jsdoc_test.js'], + + // document all functions, even uncommented ones + a: true, + + // including those marked @private + p: true, + + // some extra variables I want to include + D: {generatedBy: "Michael Mathews", copyright: "2008"}, + + // use this directory as the output directory + d: "docs", + + // use this template + t: "templates/jsdoc" +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/java/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/java/build.xml Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/java/build_1.4.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/java/build_1.4.xml Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/java/classes/js.jar Binary file sbin/res/jsdoc/java/classes/js.jar has changed diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/java/src/JsDebugRun.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/java/src/JsDebugRun.java Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,21 @@ +/** + * A trivial bootstrap class that simply adds the path to the + * .js file as an argument to the Rhino call. This little hack + * allows the code in the .js file to have access to it's own + * path via the Rhino arguments object. This is necessary to + * allow the .js code to find resource files in a location + * relative to itself. + * + * USAGE: java -jar jsdebug.jar path/to/file.js + */ +public class JsDebugRun { + public static void main(String[] args) { + String[] jsargs = {"-j="+args[0]}; + + String[] allArgs = new String[jsargs.length + args.length]; + System.arraycopy(args, 0, allArgs, 0, args.length); + System.arraycopy(jsargs, 0, allArgs, args.length ,jsargs.length); + + org.mozilla.javascript.tools.debugger.Main.main(allArgs); + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/java/src/JsRun.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/java/src/JsRun.java Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,21 @@ +/** + * A trivial bootstrap class that simply adds the path to the + * .js file as an argument to the Rhino call. This little hack + * allows the code in the .js file to have access to it's own + * path via the Rhino arguments object. This is necessary to + * allow the .js code to find resource files in a location + * relative to itself. + * + * USAGE: java -jar jsrun.jar path/to/file.js + */ +public class JsRun { + public static void main(String[] args) { + String[] jsargs = {"-j="+args[0]}; + + String[] allArgs = new String[jsargs.length + args.length]; + System.arraycopy(args, 0, allArgs, 0, args.length); + System.arraycopy(jsargs, 0, allArgs, args.length ,jsargs.length); + + org.mozilla.javascript.tools.shell.Main.main(allArgs); + } +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/jsdebug.jar Binary file sbin/res/jsdoc/jsdebug.jar has changed diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/jsrun.jar Binary file sbin/res/jsdoc/jsrun.jar has changed diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/jsrun.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/jsrun.sh Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,52 @@ +#!/bin/ksh + +# launcher script for jsdoc +# Author: Avi Deitcher +# +# This program is released under the MIT License as follows: + +# Copyright (c) 2008-2009 Atomic Inc +# +#Permission is hereby granted, free of charge, to any person +#obtaining a copy of this software and associated documentation +#files (the "Software"), to deal in the Software without +#restriction, including without limitation the rights to use, +#copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the +#Software is furnished to do so, subject to the following +#conditions: +## +#The above copyright notice and this permission notice shall be +#included in all copies or substantial portions of the Software. +# +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +#OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +#HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +#OTHER DEALINGS IN THE SOFTWARE. +# + + +if [[ -n "$JSDOCDIR" ]]; then + _DOCDIR="-Djsdoc.dir=$JSDOCDIR" + _APPDIR="$JSDOCDIR/app" + _BASEDIR="$JSDOCDIR" +else + _DOCDIR="" + _APPDIR="./app" + _BASEDIR="." +fi + +if [[ -n "$JSDOCTEMPLATEDIR" ]]; then + _TDIR="-Djsdoc.template.dir=$JSDOCTEMPLATEDIR" +else + _TDIR="" +fi + +CMD="java $_DOCDIR $_TDIR -jar $_BASEDIR/jsrun.jar $_APPDIR/run.js $@" +echo $CMD +$CMD + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/out/jsdoc/files.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/out/jsdoc/files.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,216 @@ + + + + + + JsDoc Reference - File Index + + + + + + + + +
+ +
+

Classes

+ +
+
+ +
+

File Index

+ + +
+

LdtPlayer-release.js

+ +
+ + + + +
+
+
+ + +
+
+ + Documentation generated by JsDoc Toolkit 2.4.0 on Fri Dec 23 2011 10:50:32 GMT+0100 (CET) +
+ + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/out/jsdoc/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/out/jsdoc/index.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,210 @@ + + + + + + JsDoc Reference - Index + + + + + + + + +
+ +
+

Classes

+ +
+
+ +
+

Class Index

+ + +
+

_global_

+ +
+
+ + +
+
+ + Documentation generated by JsDoc Toolkit 2.4.0 on Fri Dec 23 2011 10:50:32 GMT+0100 (CET) +
+ + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/out/jsdoc/symbols/_global_.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/out/jsdoc/symbols/_global_.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,778 @@ + + + + + + + JsDoc Reference - _global_ + + + + + + + + + + + +
+ + +
+

Classes

+ +
+ +
+ +
+ +

+ + Built-In Namespace _global_ +

+ + +

+ + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Field Summary
Field AttributesField Name and Description
  +
+ Mustache +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  +
b(a) +
+
+
  +
Clusters(json) +
+
+
  +
d() +
+
+
  + +
+
  +
Frames(json) +
+
+
  +
handler() +
+
+
  +
J(a, c) +
+
+
  +
log_error(msg, err) +
+
+
  +
log_msg(msg) +
+
+
  + +
+
+ + + + + + + + + + + + +
+ Field Detail +
+ + +
+ + + Mustache + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + + + + + + + + + + + +
+ Method Detail +
+ + +
+ + + b(a) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ a + +
+
+ +
+ + + + + + + + +
+ + +
+ + + Clusters(json) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ json + +
+
+ +
+ + + + + + + + +
+ + +
+ + + d() + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + + + + + + + + +
+ + +
+ + + finished_cb() + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + + + + + + + + +
+ + +
+ + + Frames(json) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ json + +
+
+ +
+ + + + + + + + +
+ + +
+ + + handler() + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + + + + + + + + +
+ + +
+ + + J(a, c) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ a + +
+
+ +
+ c + +
+
+ +
+ + + + + + + + +
+ + +
+ + + log_error(msg, err) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ msg + +
+
+ +
+ err + +
+
+ +
+ + + + + + + + +
+ + +
+ + + log_msg(msg) + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + +
+
Parameters:
+ +
+ msg + +
+
+ +
+ + + + + + + + +
+ + +
+ + + ready_cb() + +
+
+ + +
+ Defined in: LdtPlayer-release.js. + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.4.0 on Fri Dec 23 2011 10:50:32 GMT+0100 (CET) +
+ + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/out/jsdoc/symbols/src/LdtPlayer-release.js.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/out/jsdoc/symbols/src/LdtPlayer-release.js.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,3549 @@ +
  1 /* 
+  2  * 	
+  3  *	Copyright 2010 Institut de recherche et d'innovation 
+  4  *	contributor(s) : Samuel Huron 
+  5  *	 
+  6  *	contact@iri.centrepompidou.fr
+  7  *	http://www.iri.centrepompidou.fr 
+  8  *	 
+  9  *	This software is a computer program whose purpose is to show and add annotations on a video .
+ 10  *	This software is governed by the CeCILL-C license under French law and
+ 11  *	abiding by the rules of distribution of free software. You can  use, 
+ 12  *	modify and/ or redistribute the software under the terms of the CeCILL-C
+ 13  *	license as circulated by CEA, CNRS and INRIA at the following URL
+ 14  *	"http://www.cecill.info". 
+ 15  *	
+ 16  *	The fact that you are presently reading this means that you have had
+ 17  *	knowledge of the CeCILL-C license and that you accept its terms.
+ 18 */
+ 19 /*! LAB.js (LABjs :: Loading And Blocking JavaScript)
+ 20     v2.0.3 (c) Kyle Simpson
+ 21     MIT License
+ 22 */
+ 23 
+ 24 (function(global){
+ 25 	var _$LAB = global.$LAB,
+ 26 	
+ 27 		// constants for the valid keys of the options object
+ 28 		_UseLocalXHR = "UseLocalXHR",
+ 29 		_AlwaysPreserveOrder = "AlwaysPreserveOrder",
+ 30 		_AllowDuplicates = "AllowDuplicates",
+ 31 		_CacheBust = "CacheBust",
+ 32 		/*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
+ 33 		_BasePath = "BasePath",
+ 34 		
+ 35 		// stateless variables used across all $LAB instances
+ 36 		root_page = /^[^?#]*\//.exec(location.href)[0],
+ 37 		root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
+ 38 		append_to = document.head || document.getElementsByTagName("head"),
+ 39 		
+ 40 		// inferences... ick, but still necessary
+ 41 		opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
+ 42 
+ 43 /*!START_DEBUG*/
+ 44 		// console.log() and console.error() wrappers
+ 45 		log_msg = function(){}, 
+ 46 		log_error = log_msg,
+ 47 /*!END_DEBUG*/
+ 48 		
+ 49 		// feature sniffs (yay!)
+ 50 		test_script_elem = document.createElement("script"),
+ 51 		explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
+ 52 		real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
+ 53 		script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+ 54 		
+ 55 		// XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
+ 56 		xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
+ 57 	;
+ 58 
+ 59 /*!START_DEBUG*/
+ 60 	// define console wrapper functions if applicable
+ 61 	if (global.console && global.console.log) {
+ 62 		if (!global.console.error) global.console.error = global.console.log;
+ 63 		log_msg = function(msg) { global.console.log(msg); };
+ 64 		log_error = function(msg,err) { global.console.error(msg,err); };
+ 65 	}
+ 66 /*!END_DEBUG*/
+ 67 
+ 68 	// test for function
+ 69 	function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
+ 70 
+ 71 	// test for array
+ 72 	function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
+ 73 
+ 74 	// make script URL absolute/canonical
+ 75 	function canonical_uri(src,base_path) {
+ 76 		var absolute_regex = /^\w+\:\/\//;
+ 77 		
+ 78 		// is `src` is protocol-relative (begins with // or ///), prepend protocol
+ 79 		if (/^\/\/\/?/.test(src)) {
+ 80 			src = location.protocol + src;
+ 81 		}
+ 82 		// is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
+ 83 		else if (!absolute_regex.test(src) && src.charAt(0) != "/") {
+ 84 			// prepend `base_path`, if any
+ 85 			src = (base_path || "") + src;
+ 86 		}
+ 87 		// make sure to return `src` as absolute
+ 88 		return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src);
+ 89 	}
+ 90 
+ 91 	// merge `source` into `target`
+ 92 	function merge_objs(source,target) {
+ 93 		for (var k in source) { if (source.hasOwnProperty(k)) {
+ 94 			target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
+ 95 		}}
+ 96 		return target;
+ 97 	}
+ 98 
+ 99 	// does the chain group have any ready-to-execute scripts?
+100 	function check_chain_group_scripts_ready(chain_group) {
+101 		var any_scripts_ready = false;
+102 		for (var i=0; i<chain_group.scripts.length; i++) {
+103 			if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
+104 				any_scripts_ready = true;
+105 				chain_group.scripts[i].exec_trigger();
+106 				chain_group.scripts[i].exec_trigger = null;
+107 			}
+108 		}
+109 		return any_scripts_ready;
+110 	}
+111 
+112 	// creates a script load listener
+113 	function create_script_load_listener(elem,registry_item,flag,onload) {
+114 		elem.onload = elem.onreadystatechange = function() {
+115 			if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
+116 			elem.onload = elem.onreadystatechange = null;
+117 			onload();
+118 		};
+119 	}
+120 
+121 	// script executed handler
+122 	function script_executed(registry_item) {
+123 		registry_item.ready = registry_item.finished = true;
+124 		for (var i=0; i<registry_item.finished_listeners.length; i++) {
+125 			registry_item.finished_listeners[i]();
+126 		}
+127 		registry_item.ready_listeners = [];
+128 		registry_item.finished_listeners = [];
+129 	}
+130 
+131 	// make the request for a scriptha
+132 	function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
+133 		// setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
+134 		setTimeout(function(){
+135 			var script, src = script_obj.real_src, xhr;
+136 			
+137 			// don't proceed until `append_to` is ready to append to
+138 			if ("item" in append_to) { // check if `append_to` ref is still a live node list
+139 				if (!append_to[0]) { // `append_to` node not yet ready
+140 					// try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
+141 					setTimeout(arguments.callee,25);
+142 					return;
+143 				}
+144 				// reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
+145 				append_to = append_to[0];
+146 			}
+147 			script = document.createElement("script");
+148 			if (script_obj.type) script.type = script_obj.type;
+149 			if (script_obj.charset) script.charset = script_obj.charset;
+150 			
+151 			// should preloading be used for this script?
+152 			if (preload_this_script) {
+153 				// real script preloading?
+154 				if (real_preloading) {
+155 					/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
+156 					registry_item.elem = script;
+157 					if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
+158 						script.preload = true;
+159 						script.onpreload = onload;
+160 					}
+161 					else {
+162 						script.onreadystatechange = function(){
+163 							if (script.readyState == "loaded") onload();
+164 						};
+165 					}
+166 					script.src = src;
+167 					// NOTE: no append to DOM yet, appending will happen when ready to execute
+168 				}
+169 				// same-domain and XHR allowed? use XHR preloading
+170 				else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
+171 					xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
+172 					/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
+173 					xhr.onreadystatechange = function() {
+174 						if (xhr.readyState == 4) {
+175 							xhr.onreadystatechange = function(){}; // fix a memory leak in IE
+176 							registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
+177 							onload();
+178 						}
+179 					};
+180 					xhr.open("GET",src);
+181 					xhr.send();
+182 				}
+183 				// as a last resort, use cache-preloading
+184 				else {
+185 					/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
+186 					script.type = "text/cache-script";
+187 					create_script_load_listener(script,registry_item,"ready",function() {
+188 						append_to.removeChild(script);
+189 						onload();
+190 					});
+191 					script.src = src;
+192 					append_to.insertBefore(script,append_to.firstChild);
+193 				}
+194 			}
+195 			// use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+196 			else if (script_ordered_async) {
+197 				/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
+198 				script.async = false;
+199 				create_script_load_listener(script,registry_item,"finished",onload);
+200 				script.src = src;
+201 				append_to.insertBefore(script,append_to.firstChild);
+202 			}
+203 			// otherwise, just a normal script element
+204 			else {
+205 				/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
+206 				create_script_load_listener(script,registry_item,"finished",onload);
+207 				script.src = src;
+208 				append_to.insertBefore(script,append_to.firstChild);
+209 			}
+210 		},0);
+211 	}
+212 		
+213 	// create a clean instance of $LAB
+214 	function create_sandbox() {
+215 		var global_defaults = {},
+216 			can_use_preloading = real_preloading || xhr_or_cache_preloading,
+217 			queue = [],
+218 			registry = {},
+219 			instanceAPI
+220 		;
+221 		
+222 		// global defaults
+223 		global_defaults[_UseLocalXHR] = true;
+224 		global_defaults[_AlwaysPreserveOrder] = false;
+225 		global_defaults[_AllowDuplicates] = false;
+226 		global_defaults[_CacheBust] = false;
+227 		/*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
+228 		global_defaults[_BasePath] = "";
+229 
+230 		// execute a script that has been preloaded already
+231 		function execute_preloaded_script(chain_opts,script_obj,registry_item) {
+232 			var script;
+233 			
+234 			function preload_execute_finished() {
+235 				if (script != null) { // make sure this only ever fires once
+236 					script = null;
+237 					script_executed(registry_item);
+238 				}
+239 			}
+240 			
+241 			if (registry[script_obj.src].finished) return;
+242 			if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
+243 			
+244 			script = registry_item.elem || document.createElement("script");
+245 			if (script_obj.type) script.type = script_obj.type;
+246 			if (script_obj.charset) script.charset = script_obj.charset;
+247 			create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
+248 			
+249 			// script elem was real-preloaded
+250 			if (registry_item.elem) {
+251 				registry_item.elem = null;
+252 			}
+253 			// script was XHR preloaded
+254 			else if (registry_item.text) {
+255 				script.onload = script.onreadystatechange = null;	// script injection doesn't fire these events
+256 				script.text = registry_item.text;
+257 			}
+258 			// script was cache-preloaded
+259 			else {
+260 				script.src = script_obj.real_src;
+261 			}
+262 			append_to.insertBefore(script,append_to.firstChild);
+263 
+264 			// manually fire execution callback for injected scripts, since events don't fire
+265 			if (registry_item.text) {
+266 				preload_execute_finished();
+267 			}
+268 		}
+269 	
+270 		// process the script request setup
+271 		function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
+272 			var registry_item,
+273 				registry_items,
+274 				ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
+275 				finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
+276 			;
+277 			
+278 			script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
+279 			script_obj.real_src = script_obj.src + 
+280 				// append cache-bust param to URL?
+281 				(chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
+282 			;
+283 			
+284 			if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
+285 			registry_items = registry[script_obj.src].items;
+286 
+287 			// allowing duplicates, or is this the first recorded load of this script?
+288 			if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
+289 				registry_item = registry_items[registry_items.length] = {
+290 					ready:false,
+291 					finished:false,
+292 					ready_listeners:[ready_cb],
+293 					finished_listeners:[finished_cb]
+294 				};
+295 
+296 				request_script(chain_opts,script_obj,registry_item,
+297 					// which callback type to pass?
+298 					(
+299 					 	(preload_this_script) ? // depends on script-preloading
+300 						function(){
+301 							registry_item.ready = true;
+302 							for (var i=0; i<registry_item.ready_listeners.length; i++) {
+303 								registry_item.ready_listeners[i]();
+304 							}
+305 							registry_item.ready_listeners = [];
+306 						} :
+307 						function(){ script_executed(registry_item); }
+308 					),
+309 					// signal if script-preloading should be used or not
+310 					preload_this_script
+311 				);
+312 			}
+313 			else {
+314 				registry_item = registry_items[0];
+315 				if (registry_item.finished) {
+316 					finished_cb();
+317 				}
+318 				else {
+319 					registry_item.finished_listeners.push(finished_cb);
+320 				}
+321 			}
+322 		}
+323 
+324 		// creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
+325 		function create_chain() {
+326 			var chainedAPI,
+327 				chain_opts = merge_objs(global_defaults,{}),
+328 				chain = [],
+329 				exec_cursor = 0,
+330 				scripts_currently_loading = false,
+331 				group
+332 			;
+333 			
+334 			// called when a script has finished preloading
+335 			function chain_script_ready(script_obj,exec_trigger) {
+336 				/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
+337 				script_obj.ready = true;
+338 				script_obj.exec_trigger = exec_trigger;
+339 				advance_exec_cursor(); // will only check for 'ready' scripts to be executed
+340 			}
+341 
+342 			// called when a script has finished executing
+343 			function chain_script_executed(script_obj,chain_group) {
+344 				/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
+345 				script_obj.ready = script_obj.finished = true;
+346 				script_obj.exec_trigger = null;
+347 				// check if chain group is all finished
+348 				for (var i=0; i<chain_group.scripts.length; i++) {
+349 					if (!chain_group.scripts[i].finished) return;
+350 				}
+351 				// chain_group is all finished if we get this far
+352 				chain_group.finished = true;
+353 				advance_exec_cursor();
+354 			}
+355 
+356 			// main driver for executing each part of the chain
+357 			function advance_exec_cursor() {
+358 				while (exec_cursor < chain.length) {
+359 					if (is_func(chain[exec_cursor])) {
+360 						/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
+361 						try { chain[exec_cursor++](); } catch (err) {
+362 							/*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
+363 						}
+364 						continue;
+365 					}
+366 					else if (!chain[exec_cursor].finished) {
+367 						if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
+368 						break;
+369 					}
+370 					exec_cursor++;
+371 				}
+372 				// we've reached the end of the chain (so far)
+373 				if (exec_cursor == chain.length) {
+374 					scripts_currently_loading = false;
+375 					group = false;
+376 				}
+377 			}
+378 			
+379 			// setup next chain script group
+380 			function init_script_chain_group() {
+381 				if (!group || !group.scripts) {
+382 					chain.push(group = {scripts:[],finished:true});
+383 				}
+384 			}
+385 
+386 			// API for $LAB chains
+387 			chainedAPI = {
+388 				// start loading one or more scripts
+389 				script:function(){
+390 					for (var i=0; i<arguments.length; i++) {
+391 						(function(script_obj,script_list){
+392 							var splice_args;
+393 							
+394 							if (!is_array(script_obj)) {
+395 								script_list = [script_obj];
+396 							}
+397 							for (var j=0; j<script_list.length; j++) {
+398 								init_script_chain_group();
+399 								script_obj = script_list[j];
+400 								
+401 								if (is_func(script_obj)) script_obj = script_obj();
+402 								if (!script_obj) continue;
+403 								if (is_array(script_obj)) {
+404 									// set up an array of arguments to pass to splice()
+405 									splice_args = [].slice.call(script_obj); // first include the actual array elements we want to splice in
+406 									splice_args.unshift(j,1); // next, put the `index` and `howMany` parameters onto the beginning of the splice-arguments array
+407 									[].splice.apply(script_list,splice_args); // use the splice-arguments array as arguments for splice()
+408 									j--; // adjust `j` to account for the loop's subsequent `j++`, so that the next loop iteration uses the same `j` index value
+409 									continue;
+410 								}
+411 								if (typeof script_obj == "string") script_obj = {src:script_obj};
+412 								script_obj = merge_objs(script_obj,{
+413 									ready:false,
+414 									ready_cb:chain_script_ready,
+415 									finished:false,
+416 									finished_cb:chain_script_executed
+417 								});
+418 								group.finished = false;
+419 								group.scripts.push(script_obj);
+420 								
+421 								do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
+422 								scripts_currently_loading = true;
+423 								
+424 								if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
+425 							}
+426 						})(arguments[i],arguments[i]);
+427 					}
+428 					return chainedAPI;
+429 				},
+430 				// force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
+431 				wait:function(){
+432 					if (arguments.length > 0) {
+433 						for (var i=0; i<arguments.length; i++) {
+434 							chain.push(arguments[i]);
+435 						}
+436 						group = chain[chain.length-1];
+437 					}
+438 					else group = false;
+439 					
+440 					advance_exec_cursor();
+441 					
+442 					return chainedAPI;
+443 				}
+444 			};
+445 
+446 			// the first chain link API (includes `setOptions` only this first time)
+447 			return {
+448 				script:chainedAPI.script, 
+449 				wait:chainedAPI.wait, 
+450 				setOptions:function(opts){
+451 					merge_objs(opts,chain_opts);
+452 					return chainedAPI;
+453 				}
+454 			};
+455 		}
+456 
+457 		// API for each initial $LAB instance (before chaining starts)
+458 		instanceAPI = {
+459 			// main API functions
+460 			setGlobalDefaults:function(opts){
+461 				merge_objs(opts,global_defaults);
+462 				return instanceAPI;
+463 			},
+464 			setOptions:function(){
+465 				return create_chain().setOptions.apply(null,arguments);
+466 			},
+467 			script:function(){
+468 				return create_chain().script.apply(null,arguments);
+469 			},
+470 			wait:function(){
+471 				return create_chain().wait.apply(null,arguments);
+472 			},
+473 
+474 			// built-in queuing for $LAB `script()` and `wait()` calls
+475 			// useful for building up a chain programmatically across various script locations, and simulating
+476 			// execution of the chain
+477 			queueScript:function(){
+478 				queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
+479 				return instanceAPI;
+480 			},
+481 			queueWait:function(){
+482 				queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
+483 				return instanceAPI;
+484 			},
+485 			runQueue:function(){
+486 				var $L = instanceAPI, len=queue.length, i=len, val;
+487 				for (;--i>=0;) {
+488 					val = queue.shift();
+489 					$L = $L[val.type].apply(null,val.args);
+490 				}
+491 				return $L;
+492 			},
+493 
+494 			// rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
+495 			noConflict:function(){
+496 				global.$LAB = _$LAB;
+497 				return instanceAPI;
+498 			},
+499 
+500 			// create another clean instance of $LAB
+501 			sandbox:function(){
+502 				return create_sandbox();
+503 			}
+504 		};
+505 
+506 		return instanceAPI;
+507 	}
+508 
+509 	// create the main instance of $LAB
+510 	global.$LAB = create_sandbox();
+511 
+512 
+513 	/* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+514 	   NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
+515 	   
+516 	   The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does 
+517 	   proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked 
+518 	   document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready. 
+519 	   For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or 
+520 	   fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
+521 	*/ 
+522 	(function(addEvent,domLoaded,handler){
+523 		if (document.readyState == null && document[addEvent]){
+524 			document.readyState = "loading";
+525 			document[addEvent](domLoaded,handler = function(){
+526 				document.removeEventListener(domLoaded,handler,false);
+527 				document.readyState = "complete";
+528 			},false);
+529 		}
+530 	})("addEventListener","DOMContentLoaded");
+531 
+532 })(this);/*
+533   mustache.js — Logic-less templates in JavaScript
+534 
+535   See http://mustache.github.com/ for more info.
+536 */
+537 
+538 var Mustache = function() {
+539   var Renderer = function() {};
+540 
+541   Renderer.prototype = {
+542     otag: "{{",
+543     ctag: "}}",
+544     pragmas: {},
+545     buffer: [],
+546     pragmas_implemented: {
+547       "IMPLICIT-ITERATOR": true
+548     },
+549     context: {},
+550 
+551     render: function(template, context, partials, in_recursion) {
+552       // reset buffer & set context
+553       if(!in_recursion) {
+554         this.context = context;
+555         this.buffer = []; // TODO: make this non-lazy
+556       }
+557 
+558       // fail fast
+559       if(!this.includes("", template)) {
+560         if(in_recursion) {
+561           return template;
+562         } else {
+563           this.send(template);
+564           return;
+565         }
+566       }
+567 
+568       template = this.render_pragmas(template);
+569       var html = this.render_section(template, context, partials);
+570       if(in_recursion) {
+571         return this.render_tags(html, context, partials, in_recursion);
+572       }
+573 
+574       this.render_tags(html, context, partials, in_recursion);
+575     },
+576 
+577     /*
+578       Sends parsed lines
+579     */
+580     send: function(line) {
+581       if(line !== "") {
+582         this.buffer.push(line);
+583       }
+584     },
+585 
+586     /*
+587       Looks for %PRAGMAS
+588     */
+589     render_pragmas: function(template) {
+590       // no pragmas
+591       if(!this.includes("%", template)) {
+592         return template;
+593       }
+594 
+595       var that = this;
+596       var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
+597             this.ctag, "g");
+598       return template.replace(regex, function(match, pragma, options) {
+599         if(!that.pragmas_implemented[pragma]) {
+600           throw({message: 
+601             "This implementation of mustache doesn't understand the '" +
+602             pragma + "' pragma"});
+603         }
+604         that.pragmas[pragma] = {};
+605         if(options) {
+606           var opts = options.split("=");
+607           that.pragmas[pragma][opts[0]] = opts[1];
+608         }
+609         return "";
+610         // ignore unknown pragmas silently
+611       });
+612     },
+613 
+614     /*
+615       Tries to find a partial in the curent scope and render it
+616     */
+617     render_partial: function(name, context, partials) {
+618       name = this.trim(name);
+619       if(!partials || partials[name] === undefined) {
+620         throw({message: "unknown_partial '" + name + "'"});
+621       }
+622       if(typeof(context[name]) != "object") {
+623         return this.render(partials[name], context, partials, true);
+624       }
+625       return this.render(partials[name], context[name], partials, true);
+626     },
+627 
+628     /*
+629       Renders inverted (^) and normal (#) sections
+630     */
+631     render_section: function(template, context, partials) {
+632       if(!this.includes("#", template) && !this.includes("^", template)) {
+633         return template;
+634       }
+635 
+636       var that = this;
+637       // CSW - Added "+?" so it finds the tighest bound, not the widest
+638       var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
+639               "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
+640               "\\s*", "mg");
+641 
+642       // for each {{#foo}}{{/foo}} section do...
+643       return template.replace(regex, function(match, type, name, content) {
+644         var value = that.find(name, context);
+645         if(type == "^") { // inverted section
+646           if(!value || that.is_array(value) && value.length === 0) {
+647             // false or empty list, render it
+648             return that.render(content, context, partials, true);
+649           } else {
+650             return "";
+651           }
+652         } else if(type == "#") { // normal section
+653           if(that.is_array(value)) { // Enumerable, Let's loop!
+654             return that.map(value, function(row) {
+655               return that.render(content, that.create_context(row),
+656                 partials, true);
+657             }).join("");
+658           } else if(that.is_object(value)) { // Object, Use it as subcontext!
+659             return that.render(content, that.create_context(value),
+660               partials, true);
+661           } else if(typeof value === "function") {
+662             // higher order section
+663             return value.call(context, content, function(text) {
+664               return that.render(text, context, partials, true);
+665             });
+666           } else if(value) { // boolean section
+667             return that.render(content, context, partials, true);
+668           } else {
+669             return "";
+670           }
+671         }
+672       });
+673     },
+674 
+675     /*
+676       Replace {{foo}} and friends with values from our view
+677     */
+678     render_tags: function(template, context, partials, in_recursion) {
+679       // tit for tat
+680       var that = this;
+681 
+682       var new_regex = function() {
+683         return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
+684           that.ctag + "+", "g");
+685       };
+686 
+687       var regex = new_regex();
+688       var tag_replace_callback = function(match, operator, name) {
+689         switch(operator) {
+690         case "!": // ignore comments
+691           return "";
+692         case "=": // set new delimiters, rebuild the replace regexp
+693           that.set_delimiters(name);
+694           regex = new_regex();
+695           return "";
+696         case ">": // render partial
+697           return that.render_partial(name, context, partials);
+698         case "{": // the triple mustache is unescaped
+699           return that.find(name, context);
+700         default: // escape the value
+701           return that.escape(that.find(name, context));
+702         }
+703       };
+704       var lines = template.split("\n");
+705       for(var i = 0; i < lines.length; i++) {
+706         lines[i] = lines[i].replace(regex, tag_replace_callback, this);
+707         if(!in_recursion) {
+708           this.send(lines[i]);
+709         }
+710       }
+711 
+712       if(in_recursion) {
+713         return lines.join("\n");
+714       }
+715     },
+716 
+717     set_delimiters: function(delimiters) {
+718       var dels = delimiters.split(" ");
+719       this.otag = this.escape_regex(dels[0]);
+720       this.ctag = this.escape_regex(dels[1]);
+721     },
+722 
+723     escape_regex: function(text) {
+724       // thank you Simon Willison
+725       if(!arguments.callee.sRE) {
+726         var specials = [
+727           '/', '.', '*', '+', '?', '|',
+728           '(', ')', '[', ']', '{', '}', '\\'
+729         ];
+730         arguments.callee.sRE = new RegExp(
+731           '(\\' + specials.join('|\\') + ')', 'g'
+732         );
+733       }
+734       return text.replace(arguments.callee.sRE, '\\$1');
+735     },
+736 
+737     /*
+738       find `name` in current `context`. That is find me a value
+739       from the view object
+740     */
+741     find: function(name, context) {
+742       name = this.trim(name);
+743 
+744       // Checks whether a value is thruthy or false or 0
+745       function is_kinda_truthy(bool) {
+746         return bool === false || bool === 0 || bool;
+747       }
+748 
+749       var value;
+750       if(is_kinda_truthy(context[name])) {
+751         value = context[name];
+752       } else if(is_kinda_truthy(this.context[name])) {
+753         value = this.context[name];
+754       }
+755 
+756       if(typeof value === "function") {
+757         return value.apply(context);
+758       }
+759       if(value !== undefined) {
+760         return value;
+761       }
+762       // silently ignore unkown variables
+763       return "";
+764     },
+765 
+766     // Utility methods
+767 
+768     /* includes tag */
+769     includes: function(needle, haystack) {
+770       return haystack.indexOf(this.otag + needle) != -1;
+771     },
+772 
+773     /*
+774       Does away with nasty characters
+775     */
+776     escape: function(s) {
+777       s = String(s === null ? "" : s);
+778       return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
+779         switch(s) {
+780         case "&": return "&";
+781         case "\\": return "\\\\";
+782         case '"': return '"';
+783         case "'": return ''';
+784         case "<": return "<";
+785         case ">": return ">";
+786         default: return s;
+787         }
+788       });
+789     },
+790 
+791     // by @langalex, support for arrays of strings
+792     create_context: function(_context) {
+793       if(this.is_object(_context)) {
+794         return _context;
+795       } else {
+796         var iterator = ".";
+797         if(this.pragmas["IMPLICIT-ITERATOR"]) {
+798           iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
+799         }
+800         var ctx = {};
+801         ctx[iterator] = _context;
+802         return ctx;
+803       }
+804     },
+805 
+806     is_object: function(a) {
+807       return a && typeof a == "object";
+808     },
+809 
+810     is_array: function(a) {
+811       return Object.prototype.toString.call(a) === '[object Array]';
+812     },
+813 
+814     /*
+815       Gets rid of leading and trailing whitespace
+816     */
+817     trim: function(s) {
+818       return s.replace(/^\s*|\s*$/g, "");
+819     },
+820 
+821     /*
+822       Why, why, why? Because IE. Cry, cry cry.
+823     */
+824     map: function(array, fn) {
+825       if (typeof array.map == "function") {
+826         return array.map(fn);
+827       } else {
+828         var r = [];
+829         var l = array.length;
+830         for(var i = 0; i < l; i++) {
+831           r.push(fn(array[i]));
+832         }
+833         return r;
+834       }
+835     }
+836   };
+837 
+838   return({
+839     name: "mustache.js",
+840     version: "0.3.1-dev",
+841 
+842     /*
+843       Turns a template and view into HTML
+844     */
+845     to_html: function(template, view, partials, send_fun) {
+846       var renderer = new Renderer();
+847       if(send_fun) {
+848         renderer.send = send_fun;
+849       }
+850       renderer.render(template, view, partials);
+851       if(!send_fun) {
+852         return renderer.buffer.join("\n");
+853       }
+854     }
+855   });
+856 }();
+857 // Underscore.js 1.2.3
+858 // (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc.
+859 // Underscore is freely distributable under the MIT license.
+860 // Portions of Underscore are inspired or borrowed from Prototype,
+861 // Oliver Steele's Functional, and John Resig's Micro-Templating.
+862 // For all details and documentation:
+863 // http://documentcloud.github.com/underscore
+864 (function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+865 c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c,
+866 h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.concat,H=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&&
+867 define.amd?define("underscore",function(){return b}):s._=b;b.VERSION="1.2.3";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(b,a[e],e,a)===o)break}else for(e in a)if(m.call(a,e)&&c.call(b,a[e],e,a)===o)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.map===w)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});return e};b.reduce=b.foldl=b.inject=function(a,
+868 c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,
+869 c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c,
+870 b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});return e};var D=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a,
+871 d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,
+872 computed:b})});return e.value};b.shuffle=function(a){var c=[],b;j(a,function(a,f){f==0?c[0]=a:(b=Math.floor(Math.random()*(f+1)),c[f]=c[b],c[b]=a)});return c};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b<d?-1:b>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=
+873 function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-
+874 1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},
+875 []);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,
+876 c,d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(q&&a.indexOf===q)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(C&&a.lastIndexOf===C)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
+877 var E=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));E.prototype=a.prototype;var b=new E,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
+878 c){var d={};c||(c=b.identity);return function(){var b=c.apply(this,arguments);return m.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
+879 a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=G.apply([a],arguments);return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=
+880 function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,
+881 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===
+882 Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)==
+883 "[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){J(c,
+884 b[c]=a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,
+885 "'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b,
+886 a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this);
+887 /* main file */
+888 
+889 if ( window.IriSP === undefined && window.__IriSP === undefined ) { 
+890 	var IriSP = {}; 
+891 	var __IriSP = IriSP; /* for backward compatibility */
+892 }
+893 
+894 IriSP.loadLibs = function( libs, config, metadata_url, callback ) {
+895     // Localize jQuery variable
+896 		IriSP.jQuery = null;
+897     var $L = $LAB.script(libs.jQuery).script(libs.swfObject)
+898                 .script(libs.jQueryUI)
+899                                    
+900     if (config.player.type === "jwplayer") {
+901       // load our popcorn.js lookalike
+902       $L = $L.script(libs.jwplayer);
+903     } else {
+904       // load the real popcorn
+905       $L = $L.script(libs.popcorn).script(libs["popcorn.code"]);
+906       if (config.player.type === "youtube") {
+907         $L = $L.script(libs["popcorn.youtube"]);
+908       } 
+909       if (config.player.type === "vimeo")
+910         $L = $L.script(libs["popcorn.vimeo"]);
+911       
+912       /* do nothing for html5 */
+913     }       
+914     
+915     /* widget specific requirements */
+916     for (var idx in config.gui.widgets) {
+917       if (config.gui.widgets[idx].type === "PolemicWidget") {        
+918         $L.script(libs.raphael);
+919       }
+920     }
+921     
+922     // same for modules
+923     /*
+924     for (var idx in config.modules) {
+925       if (config.modules[idx].type === "PolemicWidget")
+926         $L.script(libs.raphaelJs);
+927     }
+928     */
+929 
+930     $L.wait(function() {
+931       IriSP.jQuery = window.jQuery.noConflict( true );
+932       IriSP._ = window._.noConflict();
+933       IriSP.underscore = IriSP._;
+934       
+935       var css_link_jquery = IriSP.jQuery( "<link>", { 
+936         rel: "stylesheet", 
+937         type: "text/css", 
+938         href: libs.cssjQueryUI,
+939         'class': "dynamic_css"
+940       } );
+941       var css_link_custom = IriSP.jQuery( "<link>", { 
+942         rel: "stylesheet", 
+943         type: "text/css", 
+944         href: config.gui.css,
+945         'class': "dynamic_css"
+946       } );
+947       
+948       css_link_jquery.appendTo('head');
+949       css_link_custom.appendTo('head');
+950           
+951       IriSP.setupDataLoader();
+952       IriSP.__dataloader.get(metadata_url, 
+953           function(data) {
+954             /* save the data so that we could re-use it to
+955                configure the video
+956             */
+957             IriSP.__jsonMetadata = data;
+958             callback.call(window) });
+959     });
+960 };
+961 IriSP.annotation_template = "{{! template for an annotation displayed in a segmentWidget }}<div title='{{divTitle}}' id='{{id}}'	class='Ldt-iri-chapter' 	style='left: {{startPixel}}px;          width: {{pxWidth}}px;          background-color:#{{hexa_color}};' 	></div>";
+962 IriSP.annotationWidget_template = "{{! template for the annotation widget }}<div class='Ldt-AnnotationsWidget'>  <!-- ugly div because we want to have a double border -->  <div class='Ldt-Annotation-DoubleBorder'>      <div class='Ldt-AnnotationContent'>        <div class='Ldt-AnnotationShareIcons'>         <a class='Ldt-fbShare' href=''><img src='{{img_dir}}/facebook.png' alt='share on facebook'></img></a>         <a class='Ldt-TwShare' href=''><img src='{{img_dir}}/twitter.png' alt='share on twitter'></img></a>         <a class='Ldt-GplusShare' href=''><img src='{{img_dir}}/google.png' alt='share on google+'></img></a>      </div>		  <div class='Ldt-SaTitle'></div>	  	<div class='Ldt-SaDescription'></div>    </div>  </div></div>";
+963 IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}<div id='Ldt-load-container'><div id='Ldt-loader'> </div> Chargement... </div>";
+964 IriSP.arrowWidget_template = "<div class='Ldt-arrowWidget'></div>";
+965 IriSP.overlay_marker_template = "{{! the template for the small bars which is z-indexed over our segment widget }}<div class='Ldt-SegmentPositionMarker' style='background-color: #F7268E;'></div>";
+966 IriSP.player_template = "{{! template for the radio player }}<div class='Ldt-controler demo'>	<div class='Ldt-LeftPlayerControls'>    <div class='Ldt-button Ldt-CtrlPlay'></div>		<div class='Ldt-button Ldt-CtrlAnnotate'></div>    <div class='Ldt-button Ldt-CtrlSearch'></div>	</div>		<div class='Ldt-RightPlayerControls'>    <div class='Ldt-Time'>      <div class='Ldt-ElapsedTime'></div>      <div class='Ldt-TimeSeparator'>/</div>      <div class='Ldt-TotalTime'></div>    </div>		<div class='Ldt-button Ldt-CtrlSound'></div>	</div></div>";
+967 IriSP.search_template = "{{! template for the search container }}<div class='LdtSearchContainer'	style='margin-left: {{margin_left}}; position: absolute; margin-top: -60px;'>	<div class='LdtSearch'		style='display: none; background-color: #EEE; width: 165px; boder: 1px; border-color: #CFCFCF; position: absolute; text-align: center;'>		<input class='LdtSearchInput'			style='margin-top: 2px; margin-bottom: 2px;' />	</div></div><div class='cleaner'></div>";
+968 IriSP.share_template = "{{! social network sharing template }}<a onclick='__IriSP.MyApiPlayer.share(\'delicious\');' title='partager avec delicious'><span class='share shareDelicious'> </span></a>		<a onclick='__IriSP.MyApiPlayer.share(\'facebook\');' title='partager avec facebook'> <span class='share shareFacebook'> </span></a><a onclick='__IriSP.MyApiPlayer.share(\'twitter\');' title='partager avec twitter'>  <span class='share shareTwitter'> </span></a><a onclick='__IriSP.MyApiPlayer.share(\'myspace\');' title='partager avec Myspace'>  <span class='share shareMySpace'> </span></a>";
+969 IriSP.sliderWidget_template = "{{! template for the slider widget - it's composed of two divs we one overlayed on top    of the other }}<div class='Ldt-sliderBackground'></div><div class='Ldt-sliderForeground'></div><div class='Ldt-sliderPositionMarker'></div>";
+970 IriSP.tooltip_template = "{{! template used by the jquery ui tooltip }}<div class='Ldt-tooltip'>  <div class='title'>{{title}}</div>  <div class='time'>{{begin}} : {{end}} </div>  <div class='description'>{{description}}</div></div>";
+971 IriSP.tooltipWidget_template = "{{! template for the tooltip widget }}<div class='tip'>	<div class='tipcolor' style='height:10px;width:10px'></div>	<div class='tiptext'></div>";
+972 IriSP.tweetWidget_template = "{{! template for the tweet widget }}<div class='Ldt-tweetWidget'>  <div class='Ldt-tweet-DoubleBorder'>      <img src='{{img_dir}}/minimize.png' class='Ldt-tweetWidgetKeepOpen' alt='dont minimize automatically'></img>      <img src='{{img_dir}}/minimize.png' class='Ldt-tweetWidgetMinimize' alt='minimize window'></img>      <div class='Ldt-tweetAvatar'></div>      <img src='{{img_dir}}/profile_arrow.png' class='Ldt-tweetAvatar-profileArrow'></img>      <div class='Ldt-tweetContents'></div>      <a href='' target='_blank' class='Ldt-Retweet'><div class='Ldt-RetweetIcon'></div> - Retweet </a>      <a href='' target='_blank' class='Ldt-TweetReply'><div class='Ldt-TweetReplyIcon'></div> - Reply</a>  </div></div>";/* wrapper that simulates popcorn.js because
+973    popcorn is a bit unstable at the time */
+974 
+975 IriSP.PopcornReplacement = {
+976   msgPump : {} /* used by jquery to receive and send messages */
+977 };
+978 
+979 IriSP.PopcornReplacement.media = { 
+980   "paused": true,
+981   "muted": false
+982 };
+983 
+984 IriSP.PopcornReplacement.listen = function(msg, callback) {
+985 //  IriSP.jQuery(IriSP.PopcornReplacement.msgPump).bind(msg, function(event, rest) { callback(rest); });
+986   if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg))
+987     IriSP.PopcornReplacement.msgPump[msg] = [];
+988 
+989   IriSP.PopcornReplacement.msgPump[msg].push(callback);
+990 };
+991 
+992 IriSP.PopcornReplacement.trigger = function(msg, params) {
+993 //  IriSP.jQuery(IriSP.PopcornReplacement.msgPump).trigger(msg, params);
+994   
+995   if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg))
+996     return;
+997 
+998   var d = IriSP.PopcornReplacement.msgPump[msg];
+999   for(var entry in d) {
+1000     d[entry].call(window, params);
+1001   }
+1002 
+1003 };
+1004 
+1005 IriSP.PopcornReplacement.guid = function(prefix) {
+1006   var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+1007       var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+1008       return v.toString(16);
+1009    });
+1010 
+1011   return prefix + str;
+1012 };
+1013 
+1014 IriSP.PopcornReplacement.__initApi = function() {
+1015   IriSP.PopcornReplacement.trigger("loadedmetadata"); // we've done more than loading metadata of course,
+1016                                                       // but popcorn doesn't need to know more.
+1017   IriSP.PopcornReplacement.media.muted = jwplayer(IriSP.PopcornReplacement._container).getMute();
+1018 };
+1019 
+1020 IriSP.PopcornReplacement.jwplayer = function(container, options) {
+1021   IriSP.PopcornReplacement._container = container.slice(1); //eschew the '#'
+1022   options.events = {
+1023       onReady: IriSP.PopcornReplacement.__initApi,
+1024       onTime: IriSP.PopcornReplacement.__timeHandler,
+1025       onPlay: IriSP.PopcornReplacement.__playHandler,
+1026       onPause: IriSP.PopcornReplacement.__pauseHandler,
+1027       onSeek: IriSP.PopcornReplacement.__seekHandler 
+1028       }
+1029     
+1030   jwplayer(IriSP.PopcornReplacement._container).setup(options);
+1031   IriSP.PopcornReplacement.media.duration = options.duration;
+1032   return IriSP.PopcornReplacement;
+1033 };
+1034 
+1035 IriSP.PopcornReplacement.currentTime = function(time) {
+1036   if (typeof(time) === "undefined") {
+1037       return jwplayer(IriSP.PopcornReplacement._container).getPosition();            
+1038   } else {
+1039      var currentTime = +time;
+1040      jwplayer( IriSP.PopcornReplacement._container ).seek( currentTime );
+1041      IriSP.PopcornReplacement.trigger("seeked");
+1042      return jwplayer(IriSP.PopcornReplacement._container).getPosition();            
+1043   }
+1044 };
+1045 
+1046 IriSP.PopcornReplacement.play = function() {
+1047       IriSP.PopcornReplacement.media.paused = false;
+1048       IriSP.PopcornReplacement.trigger("play");
+1049 //      IriSP.PopcornReplacement.trigger("playing");
+1050       jwplayer( IriSP.PopcornReplacement._container ).play();
+1051 };
+1052     
+1053 IriSP.PopcornReplacement.pause = function() {
+1054       if ( !IriSP.PopcornReplacement.media.paused ) {
+1055         IriSP.PopcornReplacement.media.paused = true;
+1056         IriSP.PopcornReplacement.trigger( "pause" );
+1057         jwplayer( IriSP.PopcornReplacement._container ).pause();
+1058       }
+1059 };
+1060 
+1061 IriSP.PopcornReplacement.muted = function(val) {
+1062   if (typeof(val) !== "undefined") {
+1063 
+1064     if (jwplayer(IriSP.PopcornReplacement._container).getMute() !== val) {
+1065       if (val) {
+1066         jwplayer(IriSP.PopcornReplacement._container).setMute(true);
+1067         IriSP.PopcornReplacement.media.muted = true;
+1068       } else {
+1069         jwplayer( IriSP.PopcornReplacement._container ).setMute(false);
+1070         IriSP.PopcornReplacement.media.muted = false;
+1071       }
+1072 
+1073       IriSP.PopcornReplacement.trigger( "volumechange" );
+1074     }
+1075     
+1076     return jwplayer( IriSP.PopcornReplacement._container ).getMute();
+1077   } else {
+1078     return jwplayer( IriSP.PopcornReplacement._container ).getMute();
+1079   }
+1080 };
+1081 
+1082 IriSP.PopcornReplacement.mute = IriSP.PopcornReplacement.muted;
+1083 
+1084 IriSP.PopcornReplacement.__codes = [];
+1085 IriSP.PopcornReplacement.code = function(options) {
+1086   IriSP.PopcornReplacement.__codes.push(options);
+1087   return IriSP.PopcornReplacement;
+1088 };
+1089 
+1090 IriSP.PopcornReplacement.__runCode = function() {
+1091   var currentTime = jwplayer(IriSP.PopcornReplacement._container).getPosition();
+1092   var i = 0;
+1093   for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) {
+1094     var c = IriSP.PopcornReplacement.__codes[i];
+1095     if (currentTime == c.start) {
+1096       c.onStart();
+1097     }
+1098     
+1099     if (currentTime == c.end) {
+1100       c.onEnd();
+1101     }
+1102 
+1103   }
+1104 };
+1105 
+1106 /* called everytime the player updates itself 
+1107    (onTime event)
+1108  */
+1109 
+1110 IriSP.PopcornReplacement.__timeHandler = function(event) {
+1111   var pos = event.position;
+1112 
+1113   var i = 0;
+1114   for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) {
+1115      var c = IriSP.PopcornReplacement.__codes[i];
+1116      
+1117      if (pos >= c.start && pos < c.end && 
+1118          pos - 0.1 <= c.start) {       
+1119         c.onStart();
+1120      }
+1121  
+1122      if (pos > c.start && pos > c.end && 
+1123          pos - 0.1 <= c.end) {
+1124          console.log("eonedn");
+1125         c.onEnd();
+1126      }
+1127    
+1128   }
+1129  
+1130   IriSP.PopcornReplacement.trigger("timeupdate");
+1131 };
+1132 
+1133 IriSP.PopcornReplacement.__seekHandler = function(event) {
+1134   var i = 0;
+1135   
+1136   for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) {
+1137      var c = IriSP.PopcornReplacement.__codes[i];
+1138     
+1139      if (event.position >= c.start && event.position < c.end) {        
+1140         c.onEnd();
+1141      }         
+1142    }
+1143 
+1144    for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) {
+1145      var c = IriSP.PopcornReplacement.__codes[i];
+1146 
+1147      if (typeof(event.offset) === "undefined")
+1148        event.offset = 0;
+1149            
+1150      if (event.offset >= c.start && event.offset < c.end) { 
+1151        c.onStart();
+1152      }
+1153      
+1154    }
+1155 
+1156   IriSP.PopcornReplacement.trigger("timeupdate");
+1157 };
+1158 
+1159 
+1160 IriSP.PopcornReplacement.__playHandler = function(event) {
+1161   IriSP.PopcornReplacement.media.paused = false;
+1162   IriSP.PopcornReplacement.trigger("play");
+1163 };
+1164 
+1165 IriSP.PopcornReplacement.__pauseHandler = function(event) {
+1166   IriSP.PopcornReplacement.media.paused = true;
+1167   IriSP.PopcornReplacement.trigger("pause");
+1168 };
+1169 
+1170 IriSP.PopcornReplacement.roundTime = function() {
+1171   var currentTime = IriSP.PopcornReplacement.currentTime();
+1172   return Math.round(currentTime);
+1173 };
+1174 /* utils.js - various utils that don't belong anywhere else */
+1175 
+1176 /* trace function, for debugging */
+1177 
+1178 IriSP.traceNum = 0;
+1179 IriSP.trace = function( msg, value ) {
+1180 /*
+1181 	if( IriSP.config.gui.debug === true ) {
+1182 		IriSP.traceNum += 1;
+1183 		IriSP.jQuery( "<div>"+IriSP.traceNum+" - "+msg+" : "+value+"</div>" ).appendTo( "#Ldt-output" );
+1184 	}
+1185 */
+1186 };
+1187 
+1188 /* used in callbacks - because in callbacks we lose "this",
+1189    we need to have a special function which wraps "this" in 
+1190    a closure. This way, the 
+1191 */   
+1192 IriSP.wrap = function (obj, fn) {
+1193   return function() {    
+1194     var args = Array.prototype.slice.call(arguments, 0);
+1195     return fn.apply(obj, args);
+1196   }
+1197 }
+1198 
+1199 /* convert a time to a percentage in the media */
+1200 IriSP.timeToPourcent = function(time, timetotal){
+1201 	var time = Math.abs(time);
+1202   var timetotal = Math.abs(timetotal);
+1203   
+1204 	return Math.floor((time/timetotal) * 100);
+1205 };
+1206 
+1207 IriSP.padWithZeros = function(num) {
+1208   if (Math.abs(num) < 10) {
+1209     return "0" + num.toString();
+1210   } else {
+1211     return num.toString();
+1212   }
+1213 };
+1214 /* convert a number of seconds to a tuple of the form 
+1215    [hours, minutes, seconds]
+1216 */
+1217 IriSP.secondsToTime = function(secs) {  
+1218   var hours = Math.abs(parseInt( secs / 3600 ) % 24);
+1219   var minutes = Math.abs(parseInt( secs / 60 ) % 60);
+1220   var seconds = parseFloat(Math.abs(secs % 60).toFixed(0));
+1221   
+1222   var toString_fn = function() {
+1223     var ret = "";
+1224     if (hours > 0)
+1225        ret = IriSP.padWithZeros(this.hours) + ":";
+1226     ret += IriSP.padWithZeros(this.minutes) + ":" + IriSP.padWithZeros(this.seconds);
+1227 
+1228     return ret;
+1229   }
+1230   return {"hours" : hours, "minutes" : minutes, "seconds" : seconds, toString: toString_fn};
+1231 };
+1232 
+1233 IriSP.secondsToString
+1234 
+1235 /* format a tweet - replaces @name by a link to the profile, #hashtag, etc. */
+1236 IriSP.formatTweet = function(tweet) {
+1237   /*
+1238     an array of arrays which hold a regexp and its replacement.
+1239   */
+1240   var regExps = [
+1241     /* copied from http://codegolf.stackexchange.com/questions/464/shortest-url-regex-match-in-javascript/480#480 */
+1242     [/((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/gi, "<a href='$1'>$1</a>"],
+1243     [/@(\w+)/gi, "<a href='http://twitter.com/$1'>@$1</a>"], // matches a @handle
+1244     [/#(\w+)/gi, "<a href='http://twitter.com/search?q=%23$1'>#$1</a>"],// matches a hashtag
+1245     [/(\+\+)/gi, "<span class='Ldt-PolemicPlusPlus'>$1</span>"],
+1246     [/(--)/gi, "<span class='Ldt-PolemicMinusMinus'>$1</span>"],
+1247     [/(==)/gi, "<span class='Ldt-PolemicEqualEqual'>$1</span>"],
+1248     [/(\?\?)/gi, "<span class='Ldt-PolemicQuestion'>$1</span>"]
+1249   ]; 
+1250 
+1251   var i = 0;
+1252   for(i = 0; i < regExps.length; i++) {
+1253      tweet = tweet.replace(regExps[i][0], regExps[i][1]);
+1254   }
+1255   
+1256   return tweet;
+1257 };
+1258 
+1259 IriSP.countProperties = function(obj) {
+1260     var count = 0;
+1261 
+1262     for(var prop in obj) {
+1263         if(obj.hasOwnProperty(prop))
+1264                 ++count;
+1265     }
+1266 
+1267     return count;
+1268 };
+1269 
+1270 // conversion de couleur Decimal vers HexaDecimal || 000 si fff
+1271 IriSP.DEC_HEXA_COLOR = function (dec) {
+1272 	 var hexa='0123456789ABCDEF';
+1273    var hex='';
+1274 	 var tmp;
+1275 	 while (dec>15){
+1276 		  tmp = dec-(Math.floor(dec/16))*16;
+1277 		  hex = hexa.charAt(tmp)+hex;
+1278 		  dec = Math.floor(dec/16);
+1279 	 }
+1280 	 hex = hexa.charAt(dec)+hex;	 
+1281 	 return(hex);
+1282 };
+1283 
+1284 /* shortcut to have global variables in templates */
+1285 IriSP.templToHTML = function(template, values) {
+1286   var params = IriSP.jQuery.extend(IriSP.default_templates_vars, values);
+1287   return Mustache.to_html(template, params);
+1288 };
+1289 
+1290 /* we need to be stricter than encodeURIComponent,
+1291    because of twitter
+1292 */  
+1293 IriSP.encodeURI = function(str) {
+1294   return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').  
+1295                                  replace(/\)/g, '%29').replace(/\*/g, '%2A');  
+1296 }  
+1297 
+1298 IriSP.__guidCounter = 0;
+1299 IriSP.guid = function(prefix) {
+1300   IriSP.__guidCounter += 1;
+1301   return prefix + IriSP.__guidCounter;
+1302 };
+1303 /* for ie compatibility
+1304 if (Object.prototype.__defineGetter__&&!Object.defineProperty) {
+1305    Object.defineProperty=function(obj,prop,desc) {
+1306       if ("get" in desc) obj.__defineGetter__(prop,desc.get);
+1307       if ("set" in desc) obj.__defineSetter__(prop,desc.set);
+1308    }
+1309 }
+1310 */
+1311 /* data.js - this file deals with how the players gets and sends data */
+1312 
+1313 IriSP.DataLoader = function() {
+1314   this._cache = {};
+1315   
+1316   /*
+1317     A structure to hold callbacks for specific urls. We need it because
+1318     ajax calls are asynchronous, so it means that sometimes we ask
+1319     multiple times for a ressource because the first call hasn't been
+1320     received yet.
+1321   */
+1322   this._callbacks = {};
+1323 };
+1324 
+1325 IriSP.DataLoader.prototype.get = function(url, callback) {
+1326 
+1327   var base_url = url.split("&")[0]
+1328   if (this._cache.hasOwnProperty(base_url)) {
+1329     callback(this._cache[base_url]);
+1330   } else {  
+1331     if (!this._callbacks.hasOwnProperty(base_url)) {
+1332       this._callbacks[base_url] = [];
+1333       this._callbacks[base_url].push(callback);   
+1334       /* we need a closure because this gets lost when it's called back */
+1335   
+1336       // uncomment you don't want to use caching.
+1337       // IriSP.jQuery.get(url, callback);
+1338       
+1339       var func = function(data) {
+1340                   this._cache[base_url] = data;                                
+1341                   var i = 0;
+1342                   
+1343                   for (i = 0; i < this._callbacks[base_url].length; i++) {
+1344                     this._callbacks[base_url][i](this._cache[base_url]);                                  
+1345                   }
+1346       };
+1347       
+1348       /* automagically choose between json and jsonp */
+1349       if (url.indexOf(document.location.hostname) === -1 &&
+1350           url.indexOf("http://") !== -1 /* not a relative url */ ) {
+1351         // we contacting a foreign domain, use JSONP
+1352 
+1353         IriSP.jQuery.get(url, {}, IriSP.wrap(this, func), "jsonp");
+1354       } else {
+1355 
+1356         // otherwise, hey, whatever rows your boat
+1357         IriSP.jQuery.get(url, IriSP.wrap(this, func));
+1358       }
+1359     
+1360     } else {
+1361       /* simply push the callback - it'll get called when the ressource
+1362          has been received */
+1363       
+1364       this._callbacks[base_url].push(callback);   
+1365    
+1366     }
+1367   }
+1368 }
+1369 
+1370 /* the base abstract "class" */
+1371 IriSP.Serializer = function(DataLoader, url) {
+1372   this._DataLoader = DataLoader;
+1373   this._url = url;
+1374   this._data = [];
+1375 };
+1376 
+1377 IriSP.Serializer.prototype.serialize = function(data) { };
+1378 IriSP.Serializer.prototype.deserialize = function(data) {};
+1379 
+1380 IriSP.Serializer.prototype.currentMedia = function() {  
+1381 };
+1382 
+1383 IriSP.Serializer.prototype.sync = function(callback) {  
+1384   callback.call(this, this._data);  
+1385 };
+1386 
+1387 IriSP.SerializerFactory = function(DataLoader) {
+1388   this._dataloader = DataLoader;
+1389 };
+1390 
+1391 IriSP.SerializerFactory.prototype.getSerializer = function(metadataOptions) {
+1392   /* This function returns serializer set-up with the correct
+1393      configuration - takes a metadata struct describing the metadata source
+1394   */
+1395   
+1396   if (metadataOptions === undefined)
+1397     /* return an empty serializer */
+1398     return IriSP.Serializer("", "");
+1399             
+1400   switch(metadataOptions.type) {
+1401     case "json":
+1402       return new IriSP.JSONSerializer(this._dataloader, metadataOptions.src);
+1403       break;
+1404     
+1405     case "dummy": /* only used for unit testing - not defined in production */
+1406       return new IriSP.MockSerializer(this._dataloader, metadataOptions.src);
+1407       break;
+1408     
+1409     case "empty":
+1410       return new IriSP.Serializer("", "empty");
+1411       break;
+1412       
+1413     default:      
+1414       return undefined;
+1415   }
+1416 };
+1417 /* site.js - all our site-dependent config : player chrome, cdn locations, etc...*/
+1418 
+1419 IriSP.lib = { 
+1420 		jQuery : "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js",
+1421 		jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js",
+1422 		jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js",
+1423 		swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js",
+1424 		cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css",
+1425     popcorn : "/mdp/src/js/libs/popcorn.js",
+1426     jwplayer : "/mdp/src/js/libs/jwplayer.js",
+1427     popcornReplacement: "/mdp/src/js/libs/pop.js",
+1428     raphael: "/mdp/src/js/libs/raphael.js",
+1429     "popcorn.mediafragment" : "/mdp/src/js/libs/popcorn.mediafragment.js",
+1430     "popcorn.code" : "/mdp/src/js/libs/popcorn.code.js",
+1431     "popcorn.jwplayer": "/mdp/src/js/libs/popcorn.jwplayer.js",
+1432     "popcorn.youtube": "/mdp/src/js/libs/popcorn.youtube.js"
+1433 };
+1434 
+1435 //Player Configuration 
+1436 IriSP.config = undefined;
+1437 
+1438 IriSP.widgetsDefaults = {
+1439   "LayoutManager" : {spacer_div_height : "0px" },
+1440   "PlayerWidget" : {},
+1441   "AnnotationsWidget": {
+1442     "share_text" : "I'm watching ",     
+1443     "fb_link" : "http://www.facebook.com/share.php?u=",
+1444     "tw_link" : "http://twitter.com/home?status=",
+1445     "gplus_link" : ""
+1446     },
+1447   "TweetsWidget" : {
+1448       default_profile_picture : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png",
+1449       tweet_display_period: 10000 // how long do we show a tweet ?
+1450   },
+1451   "SliderWidget" : {
+1452       minimize_period: 850 // how long does the slider stays maximized after the user leaves the zone ?
+1453   },
+1454   "Main" : {
+1455       autoplay: true
+1456   }
+1457   
+1458 };
+1459 
+1460 IriSP.paths = {
+1461 //  "imgs": "/tweetlive/res/metadataplayer/src/css/imgs"
+1462   "imgs": "/mdp/src/css/imgs"
+1463 };
+1464 IriSP.default_templates_vars = {
+1465   "img_dir" : IriSP.paths.imgs 
+1466 };
+1467 
+1468 /* ui.js - ui related functions */
+1469 
+1470 /* FIXME: use an sharing library */
+1471 IriSP.LdtShareTool = IriSP.share_template; /* the contents come from share.html */
+1472 
+1473 IriSP.createPlayerChrome = function(){
+1474 	var width = IriSP.config.gui.width;
+1475 	var height = IriSP.config.gui.height;
+1476 	var heightS = IriSP.config.gui.height-20;
+1477 	
+1478 	// AUDIO  */
+1479 	// PB dans le html : ; 
+1480 	IriSP.trace( "__IriSP.createMyHtml",IriSP.config.gui.container );
+1481 
+1482 	
+1483 	/* FIXME : factor this in another file */
+1484 	if( IriSP.config.gui.mode=="radio" ){
+1485 
+1486 		IriSP.jQuery( "#"+IriSP.config.gui.container ).before(IriSP.search_template);
+1487 		var radioPlayer = Mustache.to_html(IriSP.radio_template, {"share_template" : IriSP.share_template});
+1488 		IriSP.jQuery(radioPlayer).appendTo("#"+IriSP.config.gui.container);
+1489 
+1490 		// special tricks for IE 7
+1491 		if (IriSP.jQuery.browser.msie==true && IriSP.jQuery.browser.version=="7.0"){
+1492 			//LdtSearchContainer
+1493 			//__IriSP.jQuery("#LdtPlayer").attr("margin-top","50px");
+1494 			IriSP.jQuery("#Ldt-Root").css("padding-top","25px");
+1495 			IriSP.trace("__IriSP.createHtml","IE7 SPECIAL ");
+1496 		}
+1497 	} else if(IriSP.config.gui.mode=="video") {
+1498 	
+1499 		var videoPlayer = Mustache.to_html(IriSP.video_template, {"share_template" : IriSP.share_template, "heightS" : heightS});
+1500 		IriSP.jQuery(videoPlayer).appendTo("#"+IriSP.config.gui.container);
+1501 	}
+1502 	
+1503 	IriSP.jQuery("#Ldt-Annotations").width(width-(75*2));
+1504 	IriSP.jQuery("#Ldt-Show-Arrow-container").width(width-(75*2));
+1505 	IriSP.jQuery("#Ldt-ShowAnnotation-audio").width(width-10);
+1506 	IriSP.jQuery("#Ldt-ShowAnnotation-video").width(width-10);
+1507 	IriSP.jQuery("#Ldt-SaKeyword").width(width-10);
+1508 	IriSP.jQuery("#Ldt-controler").width(width-10);
+1509 	IriSP.jQuery("#Ldt-Control").attr("z-index","100");
+1510 	IriSP.jQuery("#Ldt-controler").hide();
+1511 	
+1512 	IriSP.jQuery(IriSP.annotation_loading_template).appendTo("#Ldt-ShowAnnotation-audio");
+1513 
+1514 	if(IriSP.config.gui.mode=='radio'){
+1515 		IriSP.jQuery("#Ldt-load-container").attr("width",IriSP.config.gui.width);
+1516 	}
+1517 	// Show or not the output
+1518 	if(IriSP.config.gui.debug===true){
+1519 		IriSP.jQuery("#Ldt-output").show();
+1520 	} else {
+1521 		IriSP.jQuery("#Ldt-output").hide();
+1522 	}
+1523 	
+1524 };
+1525 
+1526 
+1527 /* create the buttons and the slider   */
+1528 IriSP.createInterface = function( width, height, duration ) {
+1529 		
+1530 		IriSP.jQuery( "#Ldt-controler" ).show();
+1531 		//__IriSP.jQuery("#Ldt-Root").css('display','visible');
+1532 		IriSP.trace( "__IriSP.createInterface" , width+","+height+","+duration+"," );
+1533 		
+1534 		IriSP.jQuery( "#Ldt-ShowAnnotation").click( function () { 
+1535 			 //__IriSP.jQuery(this).slideUp(); 
+1536 		} );
+1537 
+1538 		var LdtpPlayerY = IriSP.jQuery("#Ldt-PlaceHolder").attr("top");
+1539 		var LdtpPlayerX = IriSP.jQuery("#Ldt-PlaceHolder").attr("left");
+1540 		
+1541 		IriSP.jQuery( "#slider-range-min" ).slider( { //range: "min",
+1542 			value: 0,
+1543 			min: 1,
+1544 			max: duration/1000,//1:54:52.66 = 3600+3240+
+1545 			step: 0.1,
+1546 			slide: function(event, ui) {
+1547 				
+1548 				//__IriSP.jQuery("#amount").val(ui.value+" s");
+1549 				//player.sendEvent('SEEK', ui.value)
+1550 				IriSP.MyApiPlayer.seek(ui.value);
+1551 				//changePageUrlOffset(ui.value);
+1552 				//player.sendEvent('PAUSE')
+1553 			}
+1554 		} );
+1555 		
+1556 		IriSP.trace("__IriSP.createInterface","ICI");
+1557 		IriSP.jQuery("#amount").val(IriSP.jQuery("#slider-range-min").slider("value")+" s");
+1558 		IriSP.jQuery(".Ldt-Control1 button:first").button({
+1559 			icons: {
+1560 				primary: 'ui-icon-play'
+1561 			},
+1562 			text: false
+1563 		}).next().button({
+1564 			icons: {
+1565 				primary: 'ui-icon-seek-next'
+1566 			},
+1567 			 text: false
+1568 		});
+1569 		IriSP.jQuery(".Ldt-Control2 button:first").button({
+1570 			icons: {
+1571 				primary: 'ui-icon-search'//,
+1572 				//secondary: 'ui-icon-volume-off'
+1573 			},
+1574 			text: false
+1575 		}).next().button({
+1576 			icons: {
+1577 				primary: 'ui-icon-volume-on'
+1578 			},
+1579 			 text: false
+1580 		});
+1581 
+1582 		// /!\ PB A MODIFIER 
+1583 		//__IriSP.MyTags.draw();
+1584 		IriSP.trace("__IriSP.createInterface","ICI2");
+1585 		IriSP.jQuery( "#ldt-CtrlPlay" ).attr( "style", "background-color:#CD21C24;" );
+1586 		
+1587 		IriSP.jQuery( "#Ldt-load-container" ).hide();
+1588 		
+1589 		if( IriSP.config.gui.mode=="radio" & IriSP.jQuery.browser.msie != true ) {
+1590 			IriSP.jQuery( "#Ldtplayer1" ).attr( "height", "0" );
+1591 		}
+1592 		IriSP.trace( "__IriSP.createInterface" , "3" );
+1593 
+1594 		IriSP.trace( "__IriSP.createInterface", "END" );
+1595 		
+1596 	};
+1597 /* the widget classes and definitions */
+1598 
+1599 IriSP.Widget = function(Popcorn, config, Serializer) {
+1600 
+1601   if (config === undefined || config === null) {
+1602     config = {}
+1603   }
+1604   
+1605   this._Popcorn = Popcorn;
+1606   this._config = config;  
+1607   this._serializer = Serializer;
+1608   
+1609   if (config.hasOwnProperty("container")) {
+1610      this._id = config.container;
+1611      this.selector = IriSP.jQuery("#" + this._id);
+1612   }
+1613 
+1614   if (config.hasOwnProperty("spacer")) {
+1615      this._spacerId = config.spacer;
+1616      this.spacer = IriSP.jQuery("#" + this._spacerId);
+1617   }
+1618 
+1619 
+1620   if (config.hasOwnProperty("width")) {
+1621      // this.width and not this._width because we consider it public.
+1622      this.width = config.width;     
+1623   }
+1624   
+1625   if (config.hasOwnProperty("height")) {    
+1626      this.height = config.height;     
+1627   }
+1628   
+1629   if (config.hasOwnProperty("heightmax")) {
+1630      this.heightmax = config.heightmax;     
+1631   }
+1632 
+1633   if (config.hasOwnProperty("widthmax")) {
+1634      this.widthmax = config.widthmax;     
+1635   }
+1636   
+1637 };
+1638 
+1639 IriSP.Widget.prototype.draw = function() {
+1640   /* implemented by "sub-classes" */  
+1641 };
+1642 
+1643 IriSP.Widget.prototype.redraw = function() {
+1644   /* implemented by "sub-classes" */  
+1645 };
+1646 /* modules are non-graphical entities, similar to widgets */
+1647 
+1648 IriSP.Module = function(Popcorn, config, Serializer) {
+1649 
+1650   if (config === undefined || config === null) {
+1651     config = {}
+1652   }
+1653   
+1654   this._Popcorn = Popcorn;
+1655   this._config = config;  
+1656   this._serializer = Serializer;
+1657 };
+1658 /* layout.js - very basic layout management */
+1659 
+1660 /*
+1661   a layout manager manages a div and the layout of objects
+1662   inside it.
+1663 */
+1664 
+1665 IriSP.LayoutManager = function(options) {
+1666     this._Popcorn = null;
+1667     this._widgets = [];
+1668     
+1669     this._div = "LdtPlayer";
+1670     this._width = 640;
+1671     
+1672     if (options === undefined) {
+1673       options = {};
+1674     };
+1675     
+1676     if (options.hasOwnProperty('container')) {
+1677       this._div = options.container;
+1678     }
+1679 
+1680     if (options.hasOwnProperty('width')) {
+1681       this._width = options.width;
+1682     }    
+1683     
+1684     if (options.hasOwnProperty('height')) {
+1685       this._height = options.height;
+1686     } 
+1687     
+1688     /* this is a shortcut */
+1689     this.selector = IriSP.jQuery("#" + this._div);
+1690     
+1691     this.selector.css("width", this._width);
+1692     
+1693     if (this._height !== undefined)
+1694       this.selector.css("height", this._height);
+1695 };
+1696 
+1697 /* we need this special setter because of a chicken and egg problem :
+1698    we want the manager to use popcorn but the popcorn div will be managed
+1699    by the manager. So we need a way to set the instance the manager uses
+1700 */
+1701    
+1702 IriSP.LayoutManager.prototype.setPopcornInstance = function(popcorn) {
+1703     this._Popcorn = popcorn;
+1704 }
+1705 
+1706 /* stem is a string to append to the id of the widget */
+1707 IriSP.LayoutManager.prototype.createDiv = function(stem) {
+1708     if (typeof(stem) === "undefined")
+1709        stem = "";
+1710 
+1711     var newDiv = IriSP.guid(this._div + "_widget_" + stem + "_");
+1712     var spacerDiv = IriSP.guid("LdtPlayer_spacer_");
+1713     this._widgets.push(newDiv);
+1714 
+1715     var divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative;'></div";
+1716     var spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}};'></div";
+1717     
+1718     var divCode = Mustache.to_html(divTempl, {id: newDiv, width: this._width});
+1719     var spacerCode = Mustache.to_html(spacerTempl, {spacer_id: spacerDiv, width: this._width,
+1720                                                     spacer_div_height: IriSP.widgetsDefaults.LayoutManager.spacer_div_height });
+1721 
+1722     this.selector.append(divCode);
+1723     this.selector.append(spacerCode);
+1724 
+1725     return [newDiv, spacerDiv];
+1726 };
+1727 /* init.js - initialization and configuration of Popcorn and the widgets
+1728 exemple json configuration:
+1729  
+1730  */
+1731 
+1732 IriSP.setupDataLoader = function() {
+1733   /* we set it up separately because we need to
+1734      get data at the very beginning, for instance when
+1735      setting up the video */
+1736   IriSP.__dataloader = new IriSP.DataLoader();
+1737 };
+1738 
+1739 IriSP.configurePopcorn = function (layoutManager, options) {
+1740     var pop;
+1741     var ret = layoutManager.createDiv(); 
+1742     var containerDiv = ret[0];
+1743     
+1744     switch(options.type) {
+1745       /*
+1746         todo : dynamically create the div/video tag which
+1747         will contain the video.
+1748       */
+1749       case "html5":
+1750            var tmpId = Popcorn.guid("video"); 
+1751            IriSP.jQuery("#" + containerDiv).append("<video src='" + options.file + "' id='" + tmpId + "'></video>");
+1752 
+1753            if (options.hasOwnProperty("width"))
+1754              IriSP.jQuery("#" + containerDiv).css("width", options.width);
+1755            
+1756            if (options.hasOwnProperty("height"))
+1757              IriSP.jQuery("#" + containerDiv).css("height", options.height);
+1758 
+1759            pop = Popcorn("#" + tmpId);
+1760         break;
+1761         
+1762       case "jwplayer":
+1763           var opts = IriSP.jQuery.extend({}, options);
+1764           delete opts.container;
+1765 
+1766           if (options.provider === "rtmp") {
+1767             /* exit if we can't access the metadata */
+1768             if (typeof(IriSP.__jsonMetadata) === "undefined") {
+1769                 break;
+1770             };
+1771 
+1772 
+1773             // the json format is totally illogical
+1774             opts.streamer = IriSP.__jsonMetadata["medias"][0]["meta"]["item"]["value"];
+1775             var source = IriSP.__jsonMetadata["medias"][0]["href"];
+1776 
+1777             // the source if a full url but jwplayer wants an url relative to the
+1778             // streamer url, so we've got to remove the common part.
+1779             opts.file = source.slice(opts.streamer.length);
+1780           } else {
+1781             /* other providers type, video for instance -
+1782                pass everything as is */
+1783           }
+1784 
+1785           pop = IriSP.PopcornReplacement.jwplayer("#" + containerDiv, opts);
+1786         break;
+1787       
+1788       case "youtube":
+1789           var opts = IriSP.jQuery.extend({}, options);
+1790           delete opts.container;
+1791           opts.controls = 0;
+1792           opts.autostart = false;
+1793           templ = "width: {{width}}px; height: {{height}}px;";
+1794           var str = Mustache.to_html(templ, {width: opts.width, height: opts.height});    
+1795           // Popcorn.youtube wants us to specify the size of the player in the style attribute of its container div.
+1796           IriSP.jQuery("#" + containerDiv).attr("style", str);
+1797           
+1798           pop = Popcorn.youtube("#" + containerDiv, opts.video, opts);
+1799         break;
+1800         
+1801       default:
+1802         pop = undefined;
+1803     };
+1804     
+1805     return pop;
+1806 };
+1807 
+1808 IriSP.configureWidgets = function (popcornInstance, layoutManager, guiOptions) {
+1809  
+1810   var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader);
+1811   var params = {width: guiOptions.width, height: guiOptions.height};
+1812 
+1813   var ret_widgets = [];
+1814   var index;
+1815   
+1816   for (index = 0; index < guiOptions.widgets.length; index++) {    
+1817     var widgetConfig = guiOptions.widgets[index];
+1818     var widget = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig);
+1819     ret_widgets.push(widget);
+1820    
+1821   };
+1822 
+1823   return ret_widgets;
+1824 };
+1825 
+1826 IriSP.configureModules = function (popcornInstance, modulesList) {
+1827  
+1828   var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader);
+1829   var ret_modules = [];
+1830   var index;
+1831   
+1832   for (index = 0; index < modulesList.length; index++) {    
+1833     var moduleConfig = modulesList[index];
+1834     
+1835     var serializer = serialFactory.getSerializer(moduleConfig.metadata);
+1836     var module = new IriSP[moduleConfig.type](popcornInstance, moduleConfig, serializer);    
+1837     ret_modules.push(module);
+1838   };
+1839 
+1840   return ret_modules;
+1841 };
+1842 
+1843 IriSP.instantiateWidget = function(popcornInstance, serialFactory, layoutManager, widgetConfig) {
+1844     /* create div returns us a container for the widget and a spacer */
+1845     var ret = layoutManager.createDiv(widgetConfig.type);        
+1846     var container = ret[0];
+1847     var spacer = ret[1];
+1848 
+1849     var arr = IriSP.jQuery.extend({}, widgetConfig);
+1850     arr.container = container;
+1851     arr.spacer = spacer;
+1852     
+1853     var serializer = serialFactory.getSerializer(widgetConfig.metadata);    
+1854     
+1855     if (typeof serializer == "undefined")   
+1856       debugger;
+1857     
+1858     // instantiate the object passed as a string
+1859     var widget = new IriSP[widgetConfig.type](popcornInstance, arr, serializer);    
+1860     
+1861     if (widgetConfig.hasOwnProperty("requires")) {
+1862       // also create the widgets this one depends on.
+1863       // the dependency widget is available in the parent widget context as
+1864       // this.WidgetName (for instance, this.TipWidget);
+1865       
+1866       var i = 0;
+1867       for(i = 0; i < widgetConfig.requires.length; i++) {
+1868         var widgetName = widgetConfig.requires[i]["type"];
+1869         widget[widgetName] = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig.requires[i]);
+1870       }
+1871     }       
+1872      
+1873     serializer.sync(IriSP.wrap(widget, function() { this.draw(); }));
+1874     return widget;
+1875 };
+1876 /* mediafragment module */
+1877 
+1878 IriSP.MediaFragment = function(Popcorn, config, Serializer) {
+1879   IriSP.Module.call(this, Popcorn, config, Serializer);
+1880 
+1881   this.mutex = false; /* a mutex because we access the url from two different functions */
+1882 
+1883   this._Popcorn.listen( "loadedmetadata", IriSP.wrap(this, IriSP.MediaFragment.advanceTime));
+1884   this._Popcorn.listen( "pause", IriSP.wrap(this, IriSP.MediaFragment.updateTime));
+1885   this._Popcorn.listen( "seeked", IriSP.wrap(this, IriSP.MediaFragment.updateTime));
+1886   this._Popcorn.listen( "IriSP.PolemicTweet.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation));
+1887   this._Popcorn.listen( "IriSP.SegmentsWidget.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation));
+1888 };
+1889 
+1890 IriSP.MediaFragment.advanceTime = function() {
+1891              var url = window.location.href;
+1892 
+1893               if ( url.split( "#" )[ 1 ] != null ) {
+1894                   pageoffset = url.split( "#" )[1];
+1895 
+1896                   if ( pageoffset.substring(0, 2) === "t=") {
+1897                     // timecode 
+1898                     if ( pageoffset.substring( 2 ) != null ) {
+1899                     var offsettime = pageoffset.substring( 2 );
+1900                     this._Popcorn.currentTime( parseFloat( offsettime ) );
+1901                     }
+1902                   } else if ( pageoffset.substring(0, 2) === "a=") {
+1903                     // annotation
+1904                     var annotationId = pageoffset.substring( 2 );
+1905 
+1906                     // there's no better way than that because
+1907                     // of possible race conditions
+1908                     this._serializer.sync(IriSP.wrap(this, function() {
+1909                           IriSP.MediaFragment.lookupAnnotation.call(this, annotationId); 
+1910                           }));
+1911                   }
+1912               }
+1913 };
+1914 
+1915 IriSP.MediaFragment.updateTime = function() {
+1916   if (this.mutex === true) {
+1917     return;
+1918   }
+1919 
+1920   var history = window.history;
+1921   if ( !history.pushState ) {
+1922     return false;
+1923   }
+1924   
+1925   splitArr = window.location.href.split( "#" )
+1926   history.replaceState( {}, "", splitArr[0] + "#t=" + this._Popcorn.currentTime().toFixed( 2 ) );
+1927 };
+1928 
+1929 
+1930 IriSP.MediaFragment.updateAnnotation = function(annotationId) {
+1931   var _this = this;
+1932   this.mutex = true;
+1933 
+1934   var history = window.history;
+1935   if ( !history.pushState ) {
+1936     return false;
+1937   }
+1938   
+1939   splitArr = window.location.href.split( "#" )
+1940   history.replaceState( {}, "", splitArr[0] + "#a=" + annotationId);
+1941  
+1942   window.setTimeout(function() { _this.mutex = false }, 50);
+1943 };
+1944 
+1945 // lookup and seek to the beginning of an annotation
+1946 IriSP.MediaFragment.lookupAnnotation = function(annotationId) {
+1947   var annotation = undefined;
+1948   var annotations = this._serializer._data.annotations;
+1949 
+1950   var i;
+1951   for (i = 0; i < annotations.length; i++) {
+1952       if (annotations[i].id === annotationId) {
+1953         annotation = annotations[i];
+1954         break;
+1955       }
+1956   }
+1957 
+1958   if (typeof(annotation) !== "undefined") {
+1959     this._Popcorn.currentTime(annotation.begin / 1000);
+1960   }
+1961 };
+1962 IriSP.AnnotationsWidget = function(Popcorn, config, Serializer) {
+1963   IriSP.Widget.call(this, Popcorn, config, Serializer);
+1964   
+1965 };
+1966 
+1967 
+1968 IriSP.AnnotationsWidget.prototype = new IriSP.Widget();
+1969 
+1970 IriSP.AnnotationsWidget.prototype.clear = function() {
+1971     this.selector.find(".Ldt-SaTitle").text("");
+1972     this.selector.find(".Ldt-SaDescription").text("");
+1973     this.selector.find(".Ldt-SaKeywordText").text("");
+1974 };
+1975 
+1976 IriSP.AnnotationsWidget.prototype.displayAnnotation = function(annotation) {   
+1977 
+1978     var title = annotation.content.title;
+1979     var description = annotation.content.description;
+1980     var keywords =  "" // FIXME;
+1981     var begin = +annotation.begin / 1000;
+1982     var end = +annotation.end / 1000;
+1983     var duration = +this._serializer.currentMedia().meta["dc:duration"];
+1984     
+1985     var title_templ = "{{title}} - ( {{begin}} - {{end}} )";
+1986     var endstr = Mustache.to_html(title_templ, {title: title, begin: IriSP.secondsToTime(begin), end: IriSP.secondsToTime(end)});
+1987 
+1988     this.selector.find(".Ldt-SaTitle").text(endstr);
+1989     this.selector.find(".Ldt-SaDescription").text(description);
+1990     
+1991     // update sharing buttons
+1992     var defaults = IriSP.widgetsDefaults.AnnotationsWidget;
+1993     var text = defaults.share_text;
+1994     var fb_link = defaults.fb_link;
+1995     var tw_link = defaults.tw_link;
+1996     var gplus_link = defaults.gplus_link;
+1997     var url = document.location.href + "#a=" + annotation.id;
+1998     this.selector.find(".Ldt-fbShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url));
+1999     this.selector.find(".Ldt-TwShare").attr("href", tw_link + IriSP.encodeURI(text) + IriSP.encodeURI(url));
+2000     this.selector.find(".Ldt-GplusShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url));
+2001 };
+2002 
+2003 IriSP.AnnotationsWidget.prototype.clearWidget = function() {
+2004 
+2005     
+2006     /* retract the pane between two annotations */
+2007     this.selector.find(".Ldt-SaTitle").text("");
+2008     this.selector.find(".Ldt-SaDescription").text("");
+2009     this.selector.find(".Ldt-SaKeywordText").html("");
+2010     this.selector.find(".Ldt-ShowAnnotation").slideUp();
+2011 };
+2012 
+2013 IriSP.AnnotationsWidget.prototype.draw = function() {
+2014   var _this = this;
+2015 
+2016   var annotationMarkup = IriSP.templToHTML(IriSP.annotationWidget_template);
+2017 	this.selector.append(annotationMarkup);
+2018   var view;
+2019 
+2020   if (typeof(this._serializer._data.views) !== "undefined" && this._serializer._data.views !== null)
+2021      view = this._serializer._data.views[0];
+2022 
+2023   var view_type = "";
+2024 
+2025   if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
+2026           view_type = view.annotation_types[0];
+2027   }
+2028  
+2029   var annotations = this._serializer._data.annotations;
+2030   var i;
+2031   
+2032 	for (i in annotations) {    
+2033     var annotation = annotations[i];
+2034     var begin = Math.round((+ annotation.begin) / 1000);
+2035     var end = Math.round((+ annotation.end) / 1000);
+2036 
+2037     if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined"
+2038           && annotation.meta["id-ref"] != view_type) {
+2039         continue;
+2040     }
+2041 
+2042 
+2043     var conf = {start: begin, end: end, 
+2044                 onStart: 
+2045                        function(annotation) { 
+2046                         return function() { 
+2047                             _this.displayAnnotation(annotation); 
+2048                           
+2049                         } }(annotation),
+2050                 onEnd: 
+2051                        function() { _this.clearWidget.call(_this); }
+2052                 };
+2053     this._Popcorn = this._Popcorn.code(conf);                                             
+2054   }
+2055 
+2056 };
+2057 IriSP.ArrowWidget = function(Popcorn, config, Serializer) {
+2058   IriSP.Widget.call(this, Popcorn, config, Serializer);
+2059 
+2060   this._oldAnnotation = null;
+2061   
+2062 };
+2063 
+2064 
+2065 IriSP.ArrowWidget.prototype = new IriSP.Widget();
+2066 
+2067 IriSP.ArrowWidget.prototype.clear = function() {
+2068 
+2069 };
+2070 
+2071 IriSP.ArrowWidget.prototype.clearWidget = function() {
+2072 };
+2073 
+2074 IriSP.ArrowWidget.prototype.draw = function() {
+2075   var templ = Mustache.to_html(IriSP.arrowWidget_template, {});
+2076   this.selector.append(templ);
+2077   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler));
+2078 };
+2079 
+2080 IriSP.ArrowWidget.prototype.timeUpdateHandler = function(percents) {
+2081   var currentTime = this._Popcorn.currentTime();
+2082   var currentAnnotation = this._serializer.currentAnnotations(currentTime)[0]; // FIXME : use the others ?
+2083 
+2084   /* move the arrow only if the current annotation changes */
+2085   if (currentAnnotation != this._oldAnnotation) {
+2086     var begin = (+ currentAnnotation.begin) / 1000;
+2087     var end = (+ currentAnnotation.end) / 1000;
+2088 
+2089     var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000;
+2090     var middle_time = (begin + end) / 2;
+2091     var percents = Math.floor((middle_time / duration) * 100);
+2092 
+2093     // we need to apply a fix because the arrow has a certain length
+2094     // it's half the length of the arrow (27 / 2). We need to convert
+2095     // it in percents though.
+2096     var totalWidth = this.selector.width();
+2097     var correction = ((27 / 2) / totalWidth) * 100;
+2098     var corrected_percents = percents - correction;
+2099 
+2100     /* don't move out of the screen */
+2101     if (corrected_percents <= 0)
+2102       corrected_percents = 0;
+2103 
+2104     this.selector.children(".Ldt-arrowWidget").animate({"left" : corrected_percents + "%"});
+2105 
+2106     this._oldAnnotation = currentAnnotation;
+2107   }
+2108 }
+2109 IriSP.PlayerWidget = function(Popcorn, config, Serializer) {
+2110   IriSP.Widget.call(this, Popcorn, config, Serializer);
+2111   
+2112   this._searchBlockOpen = false;
+2113   this._searchLastValue = "";
+2114 };
+2115 
+2116 IriSP.PlayerWidget.prototype = new IriSP.Widget();
+2117 
+2118 IriSP.PlayerWidget.prototype.draw = function() {
+2119   var self = this;
+2120   var width = this.width;
+2121 	var height = this.height;
+2122 	var heightS = this.height-20;
+2123 	  
+2124 	var Player_templ = Mustache.to_html(IriSP.player_template, {"share_template" : IriSP.share_template});
+2125   this.selector.append(Player_templ);		
+2126 	
+2127   this.selector.children(".Ldt-controler").show();
+2128     
+2129   // handle clicks by the user on the video.
+2130   this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater));
+2131   this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater));
+2132   
+2133   this._Popcorn.listen("volumechange", IriSP.wrap(this, this.muteButtonUpdater));
+2134 
+2135   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater));
+2136   this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch));
+2137   this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch));
+2138   
+2139   
+2140   this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); });
+2141   this.selector.find(".Ldt-CtrlNext").click(function() { });
+2142   this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); });
+2143   
+2144   this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } );
+2145 
+2146   this.selector.find(".Ldt-CtrlPlay").attr( "style", "background-color:#CD21C24;" );
+2147   
+2148   var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position();
+2149   var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"});
+2150   this.selector.append(searchBox);
+2151   
+2152   // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
+2153   this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, 
+2154                       function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); });
+2155  
+2156   this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */
+2157 };
+2158 
+2159 /* Update the elasped time div */
+2160 IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() {
+2161   
+2162   if (this._previousSecond === undefined)
+2163     this._previousSecond = this._Popcorn.roundTime();
+2164   
+2165   else {
+2166     /* we're still in the same second, so it's not necessary to update time */
+2167     if (this._Popcorn.roundTime() == this._previousSecond)
+2168       return;
+2169       
+2170   }
+2171   
+2172   // we get it at each call because it may change.
+2173   var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; 
+2174   var totalTime = IriSP.secondsToTime(duration);
+2175   var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime());
+2176   
+2177   this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString());
+2178   this.selector.find(".Ldt-TotalTime").html(totalTime.toString());
+2179   this._previousSecond = this._Popcorn.roundTime();
+2180 };
+2181 
+2182 /* update the icon of the button - separate function from playHandler
+2183    because in some cases (for instance, when the user directly clicks on
+2184    the jwplayer window) we have to change the icon without playing/pausing
+2185 */
+2186 IriSP.PlayerWidget.prototype.playButtonUpdater = function() {
+2187   var status = this._Popcorn.media.paused;
+2188   
+2189   if ( status == true ){        
+2190     this.selector.find(".Ldt-CtrlPlay").attr("title", "Play");
+2191    
+2192     // we use templToHTML because it has some predefined
+2193     // vars like where to get the images
+2194     var templ = IriSP.templToHTML("url({{img_dir}}/play_sprite.png)");
+2195     this.selector.find(".Ldt-CtrlPlay").css("background-image", templ);
+2196 
+2197   } else {
+2198     this.selector.find(".Ldt-CtrlPlay").attr("title", "Pause");
+2199 
+2200     // we use templToHTML because it has some predefined
+2201     // vars like where to get the images
+2202     var templ = IriSP.templToHTML("url({{img_dir}}/pause_sprite.png)");
+2203     this.selector.find(".Ldt-CtrlPlay").css("background-image", templ);
+2204   }  
+2205 
+2206   return;
+2207 };
+2208 
+2209 
+2210 IriSP.PlayerWidget.prototype.playHandler = function() {
+2211   var status = this._Popcorn.media.paused;
+2212   
+2213   if ( status == true ){        
+2214     this._Popcorn.play();   
+2215   } else {
+2216     this._Popcorn.pause();
+2217   }  
+2218 };
+2219 
+2220 IriSP.PlayerWidget.prototype.muteHandler = function() {
+2221   if (!this._Popcorn.muted()) {    
+2222       this._Popcorn.mute(true);
+2223     } else {
+2224       this._Popcorn.mute(false);
+2225     }
+2226 };
+2227 
+2228 IriSP.PlayerWidget.prototype.muteButtonUpdater = function() {
+2229   var status = this._Popcorn.media.muted;
+2230   
+2231   if ( status == true ){        
+2232     this.selector.find(".Ldt-CtrlSound").attr("title", "Unmute");
+2233    
+2234     // we use templToHTML because it has some predefined
+2235     // vars like where to get the images
+2236     var templ = IriSP.templToHTML("url({{img_dir}}/sound_sprite.png)");
+2237     this.selector.find(".Ldt-CtrlSound").css("background-image", templ);
+2238 
+2239   } else {
+2240     this.selector.find(".Ldt-CtrlSound").attr("title", "Mute");
+2241 
+2242     // we use templToHTML because it has some predefined
+2243     // vars like where to get the images
+2244     var templ = IriSP.templToHTML("url({{img_dir}}/mute_sprite.png)");
+2245     this.selector.find(".Ldt-CtrlSound").css("background-image", templ);
+2246   }  
+2247 
+2248   return;
+2249 };
+2250 
+2251 
+2252 IriSP.PlayerWidget.prototype.searchButtonHandler = function() {
+2253     var self = this;
+2254 
+2255     /* show the search field if it is not shown */
+2256   	if ( this._searchBlockOpen == false ) {      
+2257       this.selector.find(".LdtSearch").show(100);
+2258       
+2259       this.selector.find(".LdtSearchInput").css('background-color','#fff');
+2260       this.selector.find(".LdtSearchInput").focus();
+2261       this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue);      
+2262       this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural.
+2263       
+2264       this._searchBlockOpen = true;           
+2265       this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } );
+2266       
+2267       // we need this variable because some widget can find a match in
+2268       // their data while at the same time other's don't. As we want the
+2269       // search field to become green when there's a match, we need a 
+2270       // variable to remember that we had one.
+2271       this._positiveMatch = false;
+2272 
+2273       // tell the world the field is open
+2274       this._Popcorn.trigger("IriSP.search.open");
+2275       
+2276 	} else {
+2277       this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
+2278       this.selector.find(".LdtSearchInput").attr('value','');
+2279       this.selector.find(".LdtSearch").hide(100);
+2280       
+2281       // unbind the watcher event.
+2282       this.selector.find(".LdtSearchInput").unbind('keypress set');
+2283       this._searchBlockOpen = false;
+2284 
+2285       this._positiveMatch = false;
+2286       
+2287       this._Popcorn.trigger("IriSP.search.closed");
+2288   }
+2289 };
+2290 
+2291 /* this handler is called whenever the content of the search
+2292    field changes */
+2293 IriSP.PlayerWidget.prototype.searchHandler = function() {
+2294   this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
+2295   this._positiveMatch = false;
+2296   
+2297   // do nothing if the search field is empty, instead of highlighting everything.
+2298   if (this._searchLastValue == "") {
+2299     this._Popcorn.trigger("IriSP.search.cleared");
+2300     this.selector.find(".LdtSearchInput").css('background-color','');
+2301   } else {
+2302     this._Popcorn.trigger("IriSP.search", this._searchLastValue);
+2303   }
+2304 };
+2305 
+2306 /*
+2307   handler for the IriSP.search.found message, which is sent by some views when they
+2308   highlight a match.
+2309 */
+2310 IriSP.PlayerWidget.prototype.searchMatch = function() {
+2311   this._positiveMatch = true;
+2312   this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1');
+2313 }
+2314 
+2315 /* the same, except that no value could be found */
+2316 IriSP.PlayerWidget.prototype.searchNoMatch = function() {
+2317   if (this._positiveMatch !== true)
+2318     this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a");
+2319 }
+2320 
+2321 /* 
+2322  *   
+2323  *  Copyright 2010 Institut de recherche et d'innovation 
+2324  *  contributor(s) : Samuel Huron 
+2325  *   
+2326  *  contact@iri.centrepompidou.fr
+2327  *  http://www.iri.centrepompidou.fr 
+2328  *   
+2329  *  This software is a computer program whose purpose is to show and add annotations on a video .
+2330  *  This software is governed by the CeCILL-C license under French law and
+2331  *  abiding by the rules of distribution of free software. You can  use, 
+2332  *  modify and/ or redistribute the software under the terms of the CeCILL-C
+2333  *  license as circulated by CEA, CNRS and INRIA at the following URL
+2334  *  "http://www.cecill.info". 
+2335  *  
+2336  *  The fact that you are presently reading this means that you have had
+2337  *  knowledge of the CeCILL-C license and that you accept its terms.
+2338 */
+2339 // CHART TIMELINE / VERSION PROTOTYPE  ::
+2340 
+2341 IriSP.PolemicWidget = function(Popcorn, config, Serializer) {
+2342   IriSP.Widget.call(this, Popcorn, config, Serializer);
+2343  
+2344   this.userPol    = new Array();
+2345   this.userNoPol  = new Array();
+2346   this.userst      = new Array();
+2347   this.numberOfTweet = 0;
+2348   this.Users;
+2349   this.TweetPolemic;
+2350   this.yMax        = this.height; 
+2351   this.PaperSlider;
+2352   this.heightOfChart;
+2353   this.tweets  = new Array();
+2354   this.svgElements = {};
+2355   
+2356   // Make and define the Raphael area
+2357   this.paper = Raphael(document.getElementById(this._id), config.width, config.height);
+2358   
+2359   this.oldSearchMatches = [];
+2360 
+2361   // event handlers
+2362   this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); }));
+2363   this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler));
+2364   this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler));
+2365 
+2366 };
+2367 
+2368 IriSP.PolemicWidget.prototype = new IriSP.Widget();
+2369   
+2370 IriSP.PolemicWidget.prototype.draw = function() {
+2371   
+2372     // variable 
+2373     // yMax
+2374     
+2375     var self = this;
+2376     var yCoef        = 2;             // coef for height of 1 tweet 
+2377     var frameSize     = 5;             // frame size 
+2378     var margin         = 1;            // marge between frame
+2379     var lineSize      = this.width;        // timeline pixel width 
+2380     var nbrframes     = lineSize/frameSize;     // frame numbers
+2381     var numberOfTweet   = 0;            // number of tweet overide later 
+2382     var duration      = +this._serializer.currentMedia().meta["dc:duration"];      // timescale width 
+2383     var frameLength   = lineSize / frameSize;    // frame timescale  
+2384     var timeline;
+2385     var colors  = new Array("","#1D973D","#C5A62D","#CE0A15","#036AAE","#585858");
+2386     
+2387     // array 
+2388     //var tweets  = new Array();
+2389     var element = new Array();
+2390     var cluster = new Array();
+2391     var frames  = new Array(frameLength);
+2392     var slices  = new Array();
+2393     
+2394     
+2395     // Classes =======================================================================
+2396     var Frames = function(){
+2397       
+2398       var Myclusters;
+2399       var x;
+2400       var y;
+2401       var width;
+2402       var height;
+2403     };
+2404     Frames = function(json){
+2405       // make my clusters
+2406       // ou Frame vide 
+2407     };
+2408     Frames.prototype.draw = function(){
+2409     };
+2410     Frames.prototype.zoom = function(){
+2411     };
+2412     Frames.prototype.inside = function(){
+2413     };
+2414     var Clusters = function(){
+2415       var Object;
+2416       var yDist;
+2417       var x;
+2418       var y;
+2419       var width;
+2420       var height;
+2421     };
+2422     Clusters = function(json){
+2423       // make my object
+2424     };
+2425     var Tweet = function(){
+2426     };
+2427     // Classes =======================================================================
+2428 
+2429     // Refactoring (parametere) ************************************************************
+2430     // color translastion
+2431     var qTweet_0  =0;
+2432     var qTweet_Q  =0;
+2433     var qTweet_REF=0;
+2434     var qTweet_OK =0;
+2435     var qTweet_KO =0;
+2436     function colorTranslation(value){
+2437       if(value == "Q"){
+2438         qTweet_Q+=1;
+2439         return 2;
+2440       }else if(value =="REF"){
+2441         qTweet_REF+=1;
+2442         return 4;
+2443       }else if(value =="OK"){
+2444         qTweet_OK+=1;
+2445         return 1;
+2446       }else if(value =="KO"){
+2447         qTweet_KO+=1;
+2448         return 3;
+2449       }else if(value ==""){
+2450         qTweet_0+=1;
+2451         return 5;
+2452       }
+2453     }
+2454     
+2455 
+2456       this._serializer.sync(function(data) { loaded_callback.call(self, data) });
+2457       
+2458       function loaded_callback (json) {
+2459 
+2460         // get current view (the first ???)
+2461         view = json.views[0];
+2462         
+2463         // the tweets are by definition of the second annotation type FIXME ?
+2464         tweet_annot_type = null;
+2465         if(typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
+2466           tweet_annot_type = view.annotation_types[1];
+2467         }
+2468       
+2469       for(var i = 0; i < json.annotations.length; i++) {
+2470         var item = json.annotations[i];        
+2471         var MyTime  = Math.floor(item.begin/duration*lineSize);
+2472         var Myframe = Math.floor(MyTime/lineSize*frameLength);
+2473 
+2474         if (typeof(item.meta) !== "undefined" 
+2475           && typeof(item.meta["id-ref"]) !== "undefined"
+2476           && item.meta["id-ref"] === tweet_annot_type) {
+2477             
+2478           var MyTJson = JSON.parse(item.meta['dc:source']['content']);
+2479           
+2480             if (item.content['polemics'] != undefined 
+2481             && item.content['polemics'][0] != null) {
+2482             
+2483               // a tweet can have many polemics at the same time.
+2484               for(var j=0; j<item.content['polemics'].length; j++){
+2485                   
+2486                   this.tweets[numberOfTweet] = {
+2487                         id:i,
+2488                         qualification:colorTranslation(item.content['polemics'][j]),
+2489                         yIndicator:MyTime,
+2490                         yframe:Myframe,
+2491                         title:item.content['title'],
+2492                         timeframe:item.begin,
+2493                         userId: MyTJson.id,
+2494                         userScreenName: MyTJson.screen_name,
+2495                         tsource:MyTJson,
+2496                         cinecast_id: item.id
+2497                         };
+2498                   numberOfTweet+=1;
+2499                   
+2500               }
+2501           }
+2502           else {
+2503             this.tweets[numberOfTweet] = {
+2504                   id:i,
+2505                   qualification:colorTranslation(""),
+2506                   yIndicator:MyTime,
+2507                   yframe:Myframe,
+2508                   title:item.content['title'],
+2509                   timeframe:item.begin,
+2510                   userId: MyTJson.id,
+2511                   userScreenName: MyTJson.screen_name,
+2512                   tsource:MyTJson,
+2513                   cinecast_id: item.id
+2514             };
+2515             numberOfTweet+=1;
+2516           }
+2517           
+2518         } 
+2519       };  
+2520       
+2521        DrawTweets.call (this); // FIXME: ugly.
+2522        
+2523       };      
+2524 
+2525     // tweet Drawing (in raphael) 
+2526     function DrawTweets (){
+2527     // GROUPES TWEET ============================================
+2528     // Count nbr of cluster and tweet in a frame an save int in "frames"
+2529       numberOfTweet = this.tweets.length;
+2530       for(var i=0; i<nbrframes; i++) {  
+2531         for(var j=0; j<numberOfTweet; j++) {  
+2532         
+2533           if (i==this.tweets[j].yframe){
+2534             
+2535             var k = this.tweets[j].qualification;
+2536             
+2537             // make array for frame cluster
+2538             if(frames[i]==undefined){
+2539               frames[i] = {id:i,
+2540                      qualifVol:new Array(),
+2541                      mytweetsID:new Array()
+2542                     };
+2543             }
+2544             // add my tweet to frame
+2545             frames[i].mytweetsID.push(this.tweets[j]);
+2546             
+2547             // count opinion by frame
+2548             if( frames[i].qualifVol[k] == undefined){
+2549               frames[i].qualifVol[k] = 1;
+2550             }else{
+2551               frames[i].qualifVol[k] += 1;
+2552             }
+2553             
+2554           }
+2555         }
+2556       }
+2557     
+2558     // GROUPES TWEET ============================================    
+2559     // max of tweet by Frame 
+2560       var max = 0; 
+2561       for(var i = 0; i < nbrframes; i++) {
+2562         var moy  = 0;
+2563         for (var j = 0; j < 6; j++) {    
+2564           if (frames[i] != undefined) {
+2565             if (frames[i].qualifVol[j] != undefined) {
+2566               moy += frames[i].qualifVol[j];
+2567             }
+2568           }
+2569         }
+2570         
+2571         if (moy > max) {
+2572           max = moy;
+2573         }
+2574       }
+2575     
+2576       var tweetDrawed = new Array();
+2577       var TweetHeight = 5;
+2578       
+2579       // DRAW  TWEETS ============================================
+2580       for(var i = 0; i < nbrframes; i++) {
+2581         var addEheight = 5;
+2582         if (frames[i] != undefined){                
+2583           // by type 
+2584           
+2585           for (var j = 6; j > -1; j--) {
+2586             if (frames[i].qualifVol[j] != undefined) {
+2587               // show tweet by type 
+2588               for (var k = 0; k < frames[i].mytweetsID.length; k++) {
+2589               
+2590                 if (frames[i].mytweetsID[k].qualification == j) {                
+2591                   var x = i * frameSize;
+2592                   var y = this.heightmax - addEheight;
+2593                   
+2594                   if (this.yMax > y) {
+2595                     this.yMax = y;
+2596                   }
+2597                   
+2598                   var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */)
+2599                                     .attr({stroke:"#00","stroke-width":0.1,  fill: colors[j]});  
+2600                   
+2601                   addEheight += TweetHeight;
+2602                   
+2603                   e.color = colors[j];
+2604                   e.time = frames[i].mytweetsID[k].timeframe;
+2605                   e.title = frames[i].mytweetsID[k].title;
+2606                   e.id = frames[i].mytweetsID[k].cinecast_id;
+2607 
+2608                   this.svgElements[e.id] = e;
+2609 
+2610                   /*
+2611                   e.mouseover(function(element) { return function (event) {
+2612                         // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery.                        
+2613                         self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.clientX - 106, event.clientY - 160);
+2614                         element.displayed = true;
+2615                   }}(e)).mouseout(function(element) { return function () {                          
+2616                           self.TooltipWidget.hide.call(self.TooltipWidget);
+2617                   }}(e)).mousedown(function () {
+2618                     self._Popcorn.currentTime(this.time/1000);
+2619                     self._Popcorn.trigger("IriSP.PolemicTweet.click", this.id); 
+2620                   });
+2621                   */
+2622                   
+2623                   IriSP.jQuery(e.node).mouseenter(function(element) { return function (event) {                        
+2624                         // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery.                        
+2625                         self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.pageX - 106, event.pageY - 160);
+2626                         element.displayed = true;
+2627                   }}(e)).mousedown(function(element) { return function () {                    
+2628                     self._Popcorn.currentTime(element.time/1000);
+2629                     self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); 
+2630                     }
+2631                   }(e));                  
+2632                   
+2633                   IriSP.jQuery(e.node).attr('id', 't' + k + '');
+2634                   IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title);
+2635                   IriSP.jQuery(e.node).attr('begin',  frames[i].mytweetsID[k].timeframe);                  
+2636                 }
+2637               }
+2638             }
+2639           }
+2640         }
+2641 
+2642       }    
+2643       // DRAW UI :: resize border and bgd      
+2644       this.paperBackground = this.paper.rect(0, 0, this.width, this.heightmax).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1});  
+2645 
+2646       // outer borders
+2647       this.outerBorders   = [];
+2648       this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
+2649       this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
+2650 
+2651       // inner borders
+2652       this.innerBorders   = [];
+2653       this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
+2654       this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
+2655       this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8}));  
+2656       this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
+2657 
+2658 
+2659 
+2660       this.paperSlider   = this.paper.rect(0, 0, 0, this.heightmax).attr({fill:"#D4D5D5", stroke: "none", opacity: 1});
+2661       
+2662       // the small white line displayed over the slider.
+2663       this.sliderTip = this.paper.rect(0, 0, 1, this.heightmax).attr({fill:"#fc00ff", stroke: "none", opacity: 1});
+2664       // decalage 
+2665       // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1});  
+2666       
+2667       
+2668       this.paperSlider.toBack();
+2669       this.paperBackground.toBack();
+2670       this.sliderTip.toFront();
+2671     }
+2672     
+2673     this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); }));
+2674     this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater));
+2675 }
+2676 
+2677 IriSP.PolemicWidget.prototype.sliderUpdater = function() {
+2678 
+2679     var time = +this._Popcorn.currentTime();
+2680     var duration = +this._serializer.currentMedia().meta["dc:duration"];
+2681     
+2682     this.paperSlider.attr("width", time * (this.width / (duration / 1000)));
+2683         
+2684     this.sliderTip.attr("x", time * (this.width / (duration / 1000)));
+2685 };
+2686     
+2687 IriSP.PolemicWidget.prototype.searchHandler = function(searchString) {
+2688   if (searchString == "")
+2689     return;
+2690 
+2691   var matches = this._serializer.searchTweetsOccurences(searchString);
+2692 
+2693   if (IriSP.countProperties(matches) > 0) {
+2694     this._Popcorn.trigger("IriSP.search.matchFound");
+2695   } else {
+2696     this._Popcorn.trigger("IriSP.search.noMatchFound");
+2697   }
+2698 
+2699   for (var id in matches) {
+2700     if (this.svgElements.hasOwnProperty(id)) {
+2701       var e = this.svgElements[id];
+2702       this.svgElements[id].attr({fill: "#fc00ff"});
+2703     }
+2704   }
+2705 
+2706   // clean up the blocks that were in the previous search
+2707   // but who aren't in the current one.
+2708   for (var id in this.oldSearchMatches) {
+2709     if (!matches.hasOwnProperty(id)) {
+2710       var e = this.svgElements[id];
+2711       e.attr({fill: e.color});
+2712     }
+2713   }
+2714   
+2715   this.oldSearchMatches = matches;
+2716 };
+2717 
+2718 IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() {
+2719   // clean up the blocks that were in the previous search
+2720   // but who aren't in the current one.
+2721   for (var id in this.oldSearchMatches) {
+2722       var e = this.svgElements[id];
+2723       e.attr({fill: e.color});
+2724   }
+2725  
+2726 };
+2727 
+2728 IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() {
+2729   // clean up the blocks that were in the previous search
+2730   // but who aren't in the current one.
+2731   for (var id in this.oldSearchMatches) {
+2732       var e = this.svgElements[id];
+2733       e.attr({fill: e.color});
+2734   }
+2735  
+2736 };
+2737    
+2738 IriSP.SegmentsWidget = function(Popcorn, config, Serializer) {
+2739 
+2740   var self = this;
+2741   IriSP.Widget.call(this, Popcorn, config, Serializer);
+2742   this.oldSearchMatches = [];
+2743 
+2744   // event handlers
+2745   this._Popcorn.listen("IriSP.search", function(searchString) { self.searchHandler.call(self, searchString); });
+2746   this._Popcorn.listen("IriSP.search.closed", function() { self.searchFieldClosedHandler.call(self); });
+2747   this._Popcorn.listen("IriSP.search.cleared", function() { self.searchFieldClearedHandler.call(self); });
+2748 };
+2749 
+2750 IriSP.SegmentsWidget.prototype = new IriSP.Widget();
+2751 
+2752 /* Get the width of a segment, in pixels. */
+2753 IriSP.SegmentsWidget.prototype.segmentToPixel = function(annotation) {  
+2754   var begin = Math.round((+ annotation.begin) / 1000);
+2755   var end = Math.round((+ annotation.end) / 1000);    
+2756   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+2757   
+2758   var startPourcent 	= IriSP.timeToPourcent(begin, duration);
+2759   var startPixel = Math.floor(this.selector.parent().width() * (startPourcent / 100));
+2760   
+2761   var endPourcent 	= Math.floor(IriSP.timeToPourcent(end, duration) - startPourcent);
+2762   var endPixel = Math.floor(this.selector.parent().width() * (endPourcent / 100));
+2763   
+2764   return endPixel;
+2765 };
+2766 
+2767 /* compute the total length of a group of segments */
+2768 IriSP.SegmentsWidget.prototype.segmentsLength = function(segmentsList) {
+2769   var self = this;
+2770   var total = 0;
+2771   
+2772   for (var i = 0; i < segmentsList.length; i++)
+2773     total += self.segmentToPixel(segmentsList[i].annotation);
+2774   
+2775   return total;  
+2776 };
+2777 
+2778 IriSP.SegmentsWidget.prototype.draw = function() {
+2779 
+2780   var self = this;
+2781   var annotations = this._serializer._data.annotations;
+2782 
+2783   this.selector.addClass("Ldt-SegmentsWidget");
+2784   this.selector.append(Mustache.to_html(IriSP.overlay_marker_template));
+2785           
+2786   var view_type = this._serializer.getNonTweetIds()[0];    
+2787   
+2788   this.positionMarker = this.selector.children(":first");
+2789   
+2790   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.positionUpdater));
+2791   
+2792   
+2793   var i = 0;
+2794   
+2795   var segments_annotations = [];
+2796   
+2797   for (i = 0; i < annotations.length; i++) {
+2798     var annotation = annotations[i];
+2799 
+2800     /* filter the annotations whose type is not the one we want */
+2801     if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined"
+2802           && annotation.meta["id-ref"] != view_type) {
+2803         continue;
+2804     }
+2805 
+2806     segments_annotations.push(annotation);
+2807   }
+2808     
+2809   var totalWidth = this.selector.width() - segments_annotations.length;
+2810   var lastSegment = IriSP.underscore.max(segments_annotations, function(annotation) { return annotation.end; });
+2811   
+2812   for (i = 0; i < segments_annotations.length; i++) {
+2813   
+2814     var annotation = segments_annotations[i];
+2815     var begin = (+ annotation.begin);
+2816     var end = (+ annotation.end);
+2817     var duration = this._serializer.currentMedia().meta["dc:duration"];
+2818     var id = annotation.id;
+2819         
+2820     var startPixel = Math.floor(this.selector.parent().width() * (begin / duration));
+2821 
+2822     var endPixel = Math.floor(this.selector.parent().width() * (end / duration));
+2823     
+2824     if (annotation.id !== lastSegment.id) 
+2825       var pxWidth = endPixel - startPixel -1;
+2826     else
+2827       /* the last segment has no segment following it */
+2828       var pxWidth = endPixel - startPixel;
+2829  
+2830     var divTitle = (annotation.content.title + " - " + annotation.content.description).substr(0,55);
+2831 
+2832     if (typeof(annotation.content.color) !== "undefined")
+2833       var color = annotation.content.color;
+2834     else
+2835       var color = annotation.color;
+2836     
+2837     var hexa_color = IriSP.DEC_HEXA_COLOR(color);
+2838 
+2839     if (hexa_color === "FFCC00")
+2840       hexa_color = "333";
+2841     if (hexa_color.length == 4)
+2842       hexa_color = hexa_color + '00';
+2843     
+2844     var annotationTemplate = Mustache.to_html(IriSP.annotation_template,
+2845         {"divTitle" : divTitle, "id" : id, "startPixel" : startPixel,
+2846         "pxWidth" : pxWidth, "hexa_color" : hexa_color,
+2847         "seekPlace" : Math.round(begin/1000)});
+2848 
+2849         
+2850     this.selector.append(annotationTemplate);
+2851     
+2852     /* add a special class to the last segment and change its border */
+2853     if (annotation.id === lastSegment.id) {
+2854         this.selector.find("#" + id).addClass("Ldt-lastSegment");        
+2855         this.selector.find(".Ldt-lastSegment").css("border-color", "#" + hexa_color);        
+2856     }
+2857 
+2858     IriSP.jQuery("#" + id).fadeTo(0, 0.3);
+2859 
+2860     IriSP.jQuery("#" + id).mouseover(
+2861     /* we wrap the handler in another function because js's scoping
+2862        rules are function-based - otherwise, the internal vars like
+2863        divTitle are preserved but they are looked-up from the draw
+2864        method scope, so after that the loop is run, so they're not
+2865        preserved */
+2866     (function(divTitle) { 
+2867      return function(event) {
+2868           IriSP.jQuery(this).animate({opacity: 0.6}, 5);
+2869           var offset = IriSP.jQuery(this).offset();
+2870           var correction = IriSP.jQuery(this).outerWidth() / 2;
+2871 
+2872           var offset_x = offset.left + correction - 106;
+2873           if (offset_x < 0)
+2874             offset_x = 0;
+2875                     
+2876           self.TooltipWidget.show(divTitle, color, offset_x, event.pageY - 160);
+2877     } })(divTitle)).mouseout(function(){
+2878       IriSP.jQuery(this).animate({opacity: 0.3}, 5);
+2879       self.TooltipWidget.hide();
+2880     });
+2881 
+2882     IriSP.jQuery("#" + id).click(function(_this, annotation) {
+2883                                     return function() { _this.clickHandler(annotation)};
+2884                                  }(this, annotation));
+2885   }
+2886 };
+2887 
+2888 /* restores the view after a search */
+2889 IriSP.SegmentsWidget.prototype.clear = function() {
+2890   this.selector.children(".Ldt-iri-chapter").animate({opacity:0.3}, 100);
+2891 };
+2892 
+2893 IriSP.SegmentsWidget.prototype.clickHandler = function(annotation) {
+2894   this._Popcorn.trigger("IriSP.SegmentsWidget.click", annotation.id);
+2895   var begin = (+ annotation.begin) / 1000;
+2896   this._Popcorn.currentTime(Math.round(begin));
+2897 };
+2898 
+2899 IriSP.SegmentsWidget.prototype.searchHandler = function(searchString) {
+2900 
+2901   if (searchString == "")
+2902     return;
+2903 
+2904   var matches = this._serializer.searchOccurences(searchString);
+2905 
+2906   if (IriSP.countProperties(matches) > 0) {
+2907     this._Popcorn.trigger("IriSP.search.matchFound");
+2908   } else {
+2909     this._Popcorn.trigger("IriSP.search.noMatchFound");
+2910   }
+2911 
+2912   // un-highlight all the blocks
+2913   this.selector.children(".Ldt-iri-chapter").css("opacity", 0.1);
+2914  
+2915   // then highlight the ones with matches.
+2916   for (var id in matches) {
+2917     var factor = 0.5 + matches[id] * 0.2;
+2918     this.selector.find("#"+id).dequeue();
+2919     this.selector.find("#"+id).animate({opacity:factor}, 200);
+2920   }
+2921 
+2922  
+2923   this.oldSearchMatches = matches;
+2924 };
+2925 
+2926 IriSP.SegmentsWidget.prototype.searchFieldClearedHandler = function() {
+2927   this.clear();
+2928 };
+2929 
+2930 IriSP.SegmentsWidget.prototype.searchFieldClosedHandler = function() {
+2931   this.clear();
+2932 };
+2933 
+2934 IriSP.SegmentsWidget.prototype.positionUpdater = function() {  
+2935   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+2936   var time = this._Popcorn.currentTime();
+2937   //var position 	= ((time / duration) * 100).toFixed(2);
+2938   var position 	= ((time / duration) * 100).toFixed(2);
+2939 
+2940   this.positionMarker.css("left", position + "%");  
+2941 };
+2942 IriSP.SliderWidget = function(Popcorn, config, Serializer) {
+2943   IriSP.Widget.call(this, Popcorn, config, Serializer);
+2944 };
+2945 
+2946 IriSP.SliderWidget.prototype = new IriSP.Widget();
+2947 
+2948 IriSP.SliderWidget.prototype.draw = function() {
+2949   var self = this;
+2950 
+2951   this.selector.append(Mustache.to_html(IriSP.sliderWidget_template, {}));
+2952   this.selector.addClass("Ldt-SliderMinimized");
+2953 
+2954   this.sliderBackground = this.selector.find(".Ldt-sliderBackground");
+2955   this.sliderForeground = this.selector.find(".Ldt-sliderForeground");
+2956   this.positionMarker = this.selector.find(".Ldt-sliderPositionMarker");
+2957 
+2958 
+2959   // a special variable to stop methods from tinkering
+2960   // with the positionMarker when the user is dragging it
+2961   this.draggingOngoing = false;
+2962 
+2963   // another special variable used by the timeout handler to
+2964   // open or close the slider.
+2965   this.sliderMaximized = false;
+2966   this.timeOutId = null;
+2967 
+2968   
+2969   this.positionMarker.draggable({axis: "x",
+2970   start: IriSP.wrap(this, this.positionMarkerDraggingStartedHandler),
+2971   stop: IriSP.wrap(this, this.positionMarkerDraggedHandler),
+2972   containment: "parent"
+2973   });
+2974   this.positionMarker.css("position", "absolute");
+2975   
+2976   this.sliderBackground.click(function(event) { self.backgroundClickHandler.call(self, event); });
+2977   this.sliderForeground.click(function(event) { self.foregroundClickHandler.call(self, event); });
+2978 
+2979   this.selector.hover(IriSP.wrap(this, this.mouseOverHandler), IriSP.wrap(this, this.mouseOutHandler));
+2980 
+2981   // update the positions
+2982   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater));
+2983 
+2984   // special messages :
+2985   this._Popcorn.listen("IriSP.PlayerWidget.MouseOver", IriSP.wrap(this, this.mouseOverHandler));
+2986   this._Popcorn.listen("IriSP.PlayerWidget.MouseOut", IriSP.wrap(this, this.mouseOutHandler));
+2987 };
+2988 
+2989 /* update the slider and the position marker as time passes */
+2990 IriSP.SliderWidget.prototype.sliderUpdater = function() {
+2991   if(this.draggingOngoing || this._disableUpdate)
+2992     return;
+2993   
+2994   var time = this._Popcorn.currentTime();
+2995 
+2996   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+2997   var percent = ((time / duration) * 100).toFixed(2);
+2998   
+2999   /* we do these complicated calculations to center exactly
+3000      the position Marker */
+3001   var pixels_to_percents = 100 / this.selector.width(); /* how much is a pixel in percents */
+3002   var positionMarker_width = this.positionMarker.width();
+3003   var correction = (pixels_to_percents * positionMarker_width) / 2;
+3004 
+3005   var newPos = percent - correction;
+3006   if (newPos <= 0)
+3007     newPos = 0;
+3008   
+3009 	this.sliderForeground.css("width", percent + "%");
+3010 	this.positionMarker.css("left", newPos + "%");
+3011 
+3012 };
+3013 
+3014 IriSP.SliderWidget.prototype.backgroundClickHandler = function(event) {
+3015   /* this piece of code is a little bit convoluted - here's how it works :
+3016      we want to handle clicks on the progress bar and convert those to seeks in the media.
+3017      However, jquery only gives us a global position, and we want a number of pixels relative
+3018      to our container div, so we get the parent position, and compute an offset to this position,
+3019      and finally compute the progress ratio in the media.
+3020      Finally we multiply this ratio with the duration to get the correct time
+3021   */
+3022 
+3023   var parentOffset = this.sliderBackground.parent().offset();
+3024   var width = this.sliderBackground.width();
+3025   var relX = event.pageX - parentOffset.left;
+3026 
+3027   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+3028   var newTime = ((relX / width) * duration).toFixed(2);
+3029 
+3030   this._Popcorn.currentTime(newTime);
+3031 };
+3032 
+3033 /* same function as the previous one, except that it handles clicks
+3034    on the foreground element */
+3035 IriSP.SliderWidget.prototype.foregroundClickHandler = function(event) {
+3036   var parentOffset = this.sliderForeground.parent().offset();
+3037   var width = this.sliderBackground.width();
+3038   var relX = event.pageX - parentOffset.left;
+3039 
+3040   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+3041   var newTime = ((relX / width) * duration).toFixed(2);
+3042 
+3043   this._Popcorn.currentTime(newTime);
+3044 };
+3045 
+3046 /* handles mouse over the slider */
+3047 IriSP.SliderWidget.prototype.mouseOverHandler = function(event) {
+3048   
+3049   if (this.timeOutId !== null) {
+3050     window.clearTimeout(this.timeOutId);
+3051   }
+3052  
+3053   this.sliderMaximized = true;
+3054 
+3055   this.sliderBackground.animate({"height": "9px"}, 100);
+3056   this.sliderForeground.animate({"height": "9px"}, 100);
+3057   this.positionMarker.animate({"height": "9px", "width": "9px"}, 100);
+3058   //this.positionMarker.css("margin-top", "-4px");
+3059   
+3060 //  this.selector.removeClass("Ldt-SliderMinimized");
+3061 //  this.selector.addClass("Ldt-SliderMaximized");
+3062 };
+3063 
+3064 /* handles when the mouse leaves the slider */
+3065 IriSP.SliderWidget.prototype.mouseOutHandler = function(event) {
+3066 
+3067   this.timeOutId = window.setTimeout(IriSP.wrap(this, this.minimizeOnTimeout),
+3068                                      IriSP.widgetsDefaults.SliderWidget.minimize_period);
+3069 };
+3070 
+3071 IriSP.SliderWidget.prototype.minimizeOnTimeout = function(event) {
+3072   this.sliderBackground.animate({"height": "5px"}, 100);
+3073   this.sliderForeground.animate({"height": "5px"}, 100);
+3074   this.positionMarker.animate({"height": "5px", "width": "5px"}, 100);
+3075   this.positionMarker.css("margin-top", "0px");
+3076   this.sliderMinimized = true;
+3077   
+3078 //  this.selector.removeClass("Ldt-SliderMaximized");
+3079 //  this.selector.addClass("Ldt-SliderMinimized");
+3080 
+3081 };
+3082 
+3083 // called when the user starts dragging the position indicator
+3084 IriSP.SliderWidget.prototype.positionMarkerDraggingStartedHandler = function(event, ui) {  
+3085   this.draggingOngoing = true;
+3086 };
+3087 
+3088 IriSP.SliderWidget.prototype.positionMarkerDraggedHandler = function(event, ui) {   
+3089   this._disableUpdate = true; // disable slider position updates while dragging is ongoing.
+3090   window.setTimeout(IriSP.wrap(this, function() { this._disableUpdate = false; }), 500);
+3091 
+3092   var parentOffset = this.sliderForeground.parent().offset();
+3093   var width = this.sliderBackground.width();
+3094   var relX = event.pageX - parentOffset.left;
+3095 
+3096   var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000;
+3097   var newTime = ((relX / width) * duration).toFixed(2);
+3098 
+3099   this._Popcorn.currentTime(newTime);
+3100   
+3101   this.draggingOngoing = false;
+3102 };
+3103 
+3104 /* this widget displays a small tooltip */
+3105 IriSP.TooltipWidget = function(Popcorn, config, Serializer) {
+3106   IriSP.Widget.call(this, Popcorn, config, Serializer);
+3107   this._shown = false;
+3108   this._displayedText = "";
+3109   this._hideTimeout = -1;
+3110 };
+3111 
+3112 
+3113 IriSP.TooltipWidget.prototype = new IriSP.Widget();
+3114 
+3115 IriSP.TooltipWidget.prototype.draw = function() {
+3116   var templ = Mustache.to_html(IriSP.tooltipWidget_template);
+3117 
+3118   this.selector.append(templ);
+3119   this.hide();
+3120 
+3121 };
+3122 
+3123 IriSP.TooltipWidget.prototype.clear = function() {
+3124 	this.selector.find(".tiptext").text("");
+3125 };
+3126 
+3127 IriSP.TooltipWidget.prototype.show = function(text, color, x, y) {
+3128 
+3129   if (this._displayedText == text)
+3130     return;
+3131   
+3132   this.selector.find(".tipcolor").css("background-color", color);
+3133   this._displayedText = text;
+3134 	this.selector.find(".tiptext").text(text);
+3135   //this.selector.find(".tip").css("left", x).css("top", y);  
+3136   this.selector.find(".tip").css("left", x).css("top", y);
+3137   this.selector.find(".tip").show();
+3138   this._shown = true;
+3139 };
+3140 
+3141 IriSP.TooltipWidget.prototype.hide = function() {                                                   
+3142   this.selector.find(".tip").hide();
+3143   this._shown = false;  
+3144 };/* a widget that displays tweet - used in conjunction with the polemicWidget */
+3145 
+3146 IriSP.TweetsWidget = function(Popcorn, config, Serializer) {
+3147   IriSP.Widget.call(this, Popcorn, config, Serializer);
+3148 
+3149   this._displayingTweet = false;
+3150   this._timeoutId = undefined;  
+3151 };
+3152 
+3153 
+3154 IriSP.TweetsWidget.prototype = new IriSP.Widget();
+3155 
+3156 
+3157 IriSP.TweetsWidget.prototype.drawTweet = function(annotation) {
+3158     
+3159     var title = IriSP.formatTweet(annotation.content.title);
+3160     var img = annotation.content.img.src;
+3161     if (typeof(img) === "undefined" || img === "" || img === "None") {
+3162       img = IriSP.widgetsDefaults.TweetsWidget.default_profile_picture;
+3163     }
+3164 
+3165     var imageMarkup = IriSP.templToHTML("<img src='{{src}}' alt='user image'></img>", 
+3166                                        {src : img});
+3167     
+3168     if (typeof(annotation.meta["dc:source"].content) !== "undefined") {
+3169       var tweetContents = JSON.parse(annotation.meta["dc:source"].content);
+3170       var creator = tweetContents.user.screen_name;
+3171       var real_name = tweetContents.user.name;
+3172 
+3173       imageMarkup = IriSP.templToHTML("<a href='http://twitter.com/{{creator}}'><img src='{{src}}' alt='user image'></img></a>", 
+3174                                        {src : img, creator: creator});
+3175             
+3176       var formatted_date = new Date(tweetContents.created_at).toLocaleDateString();
+3177       title = IriSP.templToHTML("<a class='Ldt-tweet_userHandle' href='http://twitter.com/{{creator}}'>@{{creator}}</a> - " + 
+3178                                 "<div class='Ldt-tweet_realName'>{{real_name}}</div>" +
+3179                                 "<div class='Ldt-tweet_tweetContents'>{{{ contents }}}</div>" +
+3180                                 "<div class='Ldt-tweet_date'>{{ date }}</div>", 
+3181                                 {creator: creator, real_name: real_name, contents : title, date : formatted_date});
+3182 
+3183       this.selector.find(".Ldt-TweetReply").attr("href", "http://twitter.com/home?status=@" + creator + ":%20");
+3184 
+3185 
+3186       var rtText = Mustache.to_html("http://twitter.com/home?status=RT @{{creator}}: {{text}}",
+3187                                     {creator: creator, text: IriSP.encodeURI(annotation.content.title)});
+3188       this.selector.find(".Ldt-Retweet").attr("href", rtText);
+3189     }
+3190 
+3191     this.selector.find(".Ldt-tweetContents").html(title);
+3192     this.selector.find(".Ldt-tweetAvatar").html(imageMarkup);
+3193     this.selector.show("blind", 250); 
+3194 };
+3195 
+3196 IriSP.TweetsWidget.prototype.displayTweet = function(annotation) {
+3197   if (this._displayingTweet === false) {
+3198     this._displayingTweet = true;
+3199   } else {
+3200     window.clearTimeout(this._timeoutId);
+3201   }
+3202 
+3203   this.drawTweet(annotation);
+3204 
+3205   var time = this._Popcorn.currentTime();  
+3206   this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), IriSP.widgetsDefaults.TweetsWidget.tweet_display_period);
+3207 };
+3208 
+3209 
+3210 IriSP.TweetsWidget.prototype.clearPanel = function() {  
+3211     this._displayingTweet = false;
+3212     this._timeoutId = undefined;
+3213     this.closePanel();
+3214     
+3215 };
+3216 
+3217 IriSP.TweetsWidget.prototype.closePanel = function() {
+3218     if (this._timeoutId != undefined) {
+3219       /* we're called from the "close window" link */
+3220       /* cancel the timeout */
+3221       window.clearTimeout(this._timeoutId);
+3222       this._timeoutId = null;
+3223     }
+3224     
+3225     this.selector.hide("blind", 400);
+3226     
+3227 };
+3228 
+3229 /* cancel the timeout if the user clicks on the keep panel open button */
+3230 IriSP.TweetsWidget.prototype.keepPanel = function() {
+3231     if (this._timeoutId != undefined) {
+3232       /* we're called from the "close window" link */
+3233       /* cancel the timeout */
+3234       window.clearTimeout(this._timeoutId);
+3235       this._timeoutId = null;
+3236     }
+3237 };
+3238 
+3239 IriSP.TweetsWidget.prototype.draw = function() {
+3240   var _this = this;
+3241   
+3242   var tweetMarkup = IriSP.templToHTML(IriSP.tweetWidget_template, {"share_template" : IriSP.share_template});
+3243   this.selector.append(tweetMarkup);
+3244   this.selector.hide();
+3245   this.selector.find(".Ldt-tweetWidgetMinimize").click(IriSP.wrap(this, this.closePanel));
+3246   this.selector.find(".Ldt-tweetWidgetKeepOpen").click(IriSP.wrap(this, this.keepPanel));
+3247   
+3248   this._Popcorn.listen("IriSP.PolemicTweet.click", IriSP.wrap(this, this.PolemicTweetClickHandler));
+3249 };
+3250 
+3251 IriSP.TweetsWidget.prototype.PolemicTweetClickHandler = function(tweet_id) {  
+3252   var index, annotation;
+3253   for (index in this._serializer._data.annotations) {
+3254     annotation = this._serializer._data.annotations[index];
+3255     
+3256     if (annotation.id === tweet_id)
+3257       break;
+3258   }
+3259     
+3260   if (annotation.id !== tweet_id)
+3261       /* we haven't found it */
+3262       return;
+3263   
+3264   this.displayTweet(annotation);
+3265   return;
+3266 };
+3267 
+3268 IriSP.JSONSerializer = function(DataLoader, url) {
+3269   IriSP.Serializer.call(this, DataLoader, url);
+3270 };
+3271 
+3272 IriSP.JSONSerializer.prototype = new IriSP.Serializer();
+3273 
+3274 IriSP.JSONSerializer.prototype.serialize = function(data) {
+3275   return JSON.stringify(data);
+3276 };
+3277 
+3278 IriSP.JSONSerializer.prototype.deserialize = function(data) {
+3279   return JSON.parse(data);
+3280 };
+3281 
+3282 IriSP.JSONSerializer.prototype.sync = function(callback) {
+3283   /* we don't have to do much because jQuery handles json for us */
+3284 
+3285   var self = this;
+3286 
+3287   var fn = function(data) {      
+3288       self._data = data;      
+3289       // sort the data too     
+3290       self._data["annotations"].sort(function(a, b) 
+3291           { var a_begin = +a.begin;
+3292             var b_begin = +b.begin;
+3293             return a_begin - b_begin;
+3294           });
+3295      
+3296       callback(data);      
+3297   };
+3298   
+3299   this._DataLoader.get(this._url, fn);
+3300 };
+3301 
+3302 IriSP.JSONSerializer.prototype.currentMedia = function() {  
+3303   return this._data.medias[0]; /* FIXME: don't hardcode it */
+3304 };
+3305 
+3306 /* this function searches for an annotation which matches title, description and keyword 
+3307    "" matches any field. 
+3308    Note: it ignores tweets.
+3309 */    
+3310 IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) {
+3311     /* we can have many types of annotations. We want search to only look for regular segments */
+3312     /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either
+3313        null or undefined.
+3314     */
+3315     var view;
+3316 
+3317     if (typeof(this._data.views) !== "undefined" && this._data.views !== null)
+3318        view = this._data.views[0];
+3319 
+3320     var searchViewType = "";
+3321 
+3322     if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
+3323             searchViewType = view.annotation_types[0];
+3324     }
+3325 
+3326     var filterfn = function(annotation) {
+3327       if( searchViewType  != "" && 
+3328           typeof(annotation.meta) !== "undefined" && 
+3329           typeof(annotation.meta["id-ref"]) !== "undefined" &&
+3330           annotation.meta["id-ref"] !== searchViewType) {
+3331         return true; // don't pass
+3332       } else {
+3333           return false;
+3334       }
+3335     };
+3336 
+3337     return this.searchAnnotationsFilter(title, description, keyword, filterfn);
+3338 
+3339 };
+3340 
+3341 /* only look for tweets */
+3342 IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) {
+3343     /* we can have many types of annotations. We want search to only look for regular segments */
+3344     /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either
+3345        null or undefined.
+3346     */
+3347     var view;
+3348 
+3349     if (typeof(this._data.views) !== "undefined" && this._data.views !== null)
+3350        view = this._data.views[0];
+3351 
+3352     var searchViewType = "";
+3353 
+3354     if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
+3355             searchViewType = view.annotation_types[0];
+3356     }
+3357 
+3358     var filterfn = function(annotation) {
+3359       if( searchViewType  != "" && 
+3360           typeof(annotation.meta) !== "undefined" && 
+3361           typeof(annotation.meta["id-ref"]) !== "undefined" &&
+3362           annotation.meta["id-ref"] !== searchViewType) {
+3363         return false; // pass
+3364       } else {
+3365           return true;
+3366       }
+3367     };
+3368 
+3369     return this.searchAnnotationsFilter(title, description, keyword, filterfn);
+3370 
+3371 };
+3372 
+3373 /*
+3374   the previous function call this one, which is more general:
+3375  */    
+3376 IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) {
+3377 
+3378     var rTitle;
+3379     var rDescription;
+3380     var rKeyword;
+3381     /* match anything if given the empty string */
+3382     if (title == "")
+3383       title = ".*";
+3384     if (description == "")
+3385       description = ".*";
+3386     if (keyword == "")
+3387       keyword = ".*";
+3388     
+3389     rTitle = new RegExp(title, "i");  
+3390     rDescription = new RegExp(description, "i");  
+3391     rKeyword = new RegExp(keyword, "i");  
+3392     
+3393     var ret_array = [];
+3394     
+3395     var i;
+3396     for (i in this._data.annotations) {
+3397       var annotation = this._data.annotations[i];
+3398       
+3399       /* filter the annotations whose type is not the one we want */
+3400       if (filter(annotation)) {
+3401           continue;
+3402       }
+3403       
+3404       if (rTitle.test(annotation.content.title) && 
+3405           rDescription.test(annotation.content.description)) {
+3406           /* FIXME : implement keyword support */
+3407           ret_array.push(annotation);
+3408       }
+3409     }
+3410     
+3411     return ret_array;
+3412 };
+3413 
+3414 /* breaks a string in words and searches each of these words. Returns an array
+3415    of objects with the id of the annotation and its number of occurences.
+3416    
+3417    FIXME: optimize ? seems to be n^2 in the worst case.
+3418 */
+3419 IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) {
+3420   var ret = { };
+3421   var keywords = searchString.split(/\s+/);
+3422   
+3423   for (var i in keywords) {
+3424     var keyword = keywords[i];
+3425     
+3426     // search this keyword in descriptions and title
+3427     var found_annotations = []
+3428     found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", ""));
+3429     found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, ""));
+3430     
+3431     for (var j in found_annotations) {
+3432       var current_annotation = found_annotations[j];
+3433       
+3434       if (!ret.hasOwnProperty(current_annotation.id)) {
+3435         ret[current_annotation.id] = 1;
+3436       } else {
+3437         ret[current_annotation.id] += 1;
+3438       }
+3439       
+3440     }
+3441 
+3442   };
+3443   
+3444   return ret;
+3445 };
+3446 
+3447 /* breaks a string in words and searches each of these words. Returns an array
+3448    of objects with the id of the annotation and its number of occurences.
+3449    
+3450    FIXME: optimize ? seems to be n^2 in the worst case.
+3451 */
+3452 IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) {
+3453   var ret = { };
+3454   var keywords = searchString.split(/\s+/);
+3455   
+3456   for (var i in keywords) {
+3457     var keyword = keywords[i];
+3458     
+3459     // search this keyword in descriptions and title
+3460     var found_annotations = []
+3461     found_annotations = found_annotations.concat(this.searchTweets(keyword, "", ""));
+3462     found_annotations = found_annotations.concat(this.searchTweets("", keyword, ""));
+3463     
+3464     for (var j in found_annotations) {
+3465       var current_annotation = found_annotations[j];
+3466       
+3467       if (!ret.hasOwnProperty(current_annotation.id)) {
+3468         ret[current_annotation.id] = 1;
+3469       } else {
+3470         ret[current_annotation.id] += 1;
+3471       }
+3472       
+3473     }
+3474 
+3475   };
+3476   
+3477   return ret;
+3478 };
+3479 
+3480 /* takes the currentTime and returns all the annotations that are displayable at the moment 
+3481    NB: only takes account the first type of annotations - ignores tweets 
+3482    currentTime is in seconds.
+3483  */
+3484 
+3485 IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime) {
+3486   var view;
+3487   var currentTimeMs = 1000 * currentTime;
+3488 
+3489   if (typeof(this._data.views) !== "undefined" && this._data.views !== null)
+3490      view = this._data.views[0];
+3491 
+3492   var view_type = "";
+3493 
+3494   if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length >= 1) {
+3495           view_type = view.annotation_types[0];
+3496   }
+3497 
+3498   var ret_array = [];
+3499   
+3500   var i;
+3501  
+3502   for (i in this._data.annotations) {
+3503     var annotation = this._data.annotations[i];
+3504     
+3505     if (annotation.meta["id-ref"] === view_type && annotation.begin <= currentTimeMs && annotation.end >= currentTimeMs)
+3506       ret_array.push(annotation);
+3507   }
+3508 
+3509   return ret_array;
+3510 };
+3511 
+3512 
+3513 /* this function returns a list of ids of tweet lines */
+3514 IriSP.JSONSerializer.prototype.getTweetIds = function() {
+3515   if (typeof(this._data.lists) === "undefined" || this._data.lists === null)
+3516     return [];
+3517 
+3518   var tweetsId = [];
+3519   
+3520   /* first get the list containing the tweets */
+3521   var tweets = IriSP.underscore.filter(this._data.lists, function(entry) { return entry.id.indexOf("tweet") !== -1 });
+3522   
+3523   // FIXME: collect tweets from multiple sources ?
+3524   tweetsId = IriSP.underscore.pluck(tweets[0].items, "id-ref");
+3525 
+3526   return tweetsId;
+3527 };
+3528 
+3529 /* this function returns a list of lines which are not tweet lines */
+3530 IriSP.JSONSerializer.prototype.getNonTweetIds = function() {
+3531   if (typeof(this._data.lists) === "undefined" || this._data.lists === null)
+3532     return [];
+3533   
+3534   /* get all the ids */
+3535   var ids = IriSP.underscore.map(this._data.lists, function(entry) {                                                         
+3536                                                          return IriSP.underscore.pluck(entry.items, "id-ref"); });
+3537                                                          
+3538   var illegal_values = this.getTweetIds();
+3539   return IriSP.underscore.difference(ids, illegal_values);
+3540   
+3541 };
+3542 
\ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/allclasses.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/allclasses.tmpl Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,17 @@ +
{+new Link().toFile("index.html").withText("Class Index")+} +| {+new Link().toFile("files.html").withText("File Index")+}
+
+

Classes

+
    + +
  • {! + if (thisClass.alias == "_global_") { + output += ""+new Link().toClass(thisClass.alias)+""; + } + else { + output += new Link().toClass(thisClass.alias); + } + !}
  • +
    +
+
\ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/allfiles.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/allfiles.tmpl Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,56 @@ + + + + + {! Link.base = ""; /* all generated links will be relative to this */ !} + JsDoc Reference - File Index + + + + + + + {+include("static/header.html")+} + +
+ {+publish.classesIndex+} +
+ +
+

File Index

+ + +
+

{+new Link().toSrc(item.alias).withText(item.name)+}

+ {+resolveLinks(item.desc)+} +
+ +
Author:
+
{+item.author+}
+
+ +
Version:
+
{+item.version+}
+
+ {! var locations = item.comment.getTag('location').map(function($){return $.toString().replace(/(^\$ ?| ?\$$)/g, '').replace(/^HeadURL: https:/g, 'http:');}) !} + +
Location:
+ +
{+location+}
+
+
+
+
+
+
+ +
+
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/class.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/class.tmpl Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,649 @@ + + + + + + {! Link.base = "../"; /* all generated links will be relative to this */ !} + JsDoc Reference - {+data.alias+} + + + + + + + + {+include("static/header.html")+} + + + +
+ + {+publish.classesIndex+} + +
+ +
+ +

+ {! + var classType = ""; + + if (data.isBuiltin()) { + classType += "Built-In "; + } + + if (data.isNamespace) { + if (data.is('FUNCTION')) { + classType += "Function "; + } + classType += "Namespace "; + } + else { + classType += "Class "; + } + !} + {+classType+}{+data.alias+} +

+ + +

+
Version + {+ data.version +}.
+
+
Extends + {+ + data.augments + .sort() + .map( + function($) { return new Link().toSymbol($); } + ) + .join(", ") + +}.
+
+ + {+resolveLinks(data.classDesc)+} + + {# isn't defined in any file #} +
Defined in: {+new Link().toSrc(data.srcFile)+}. +
+

+ + + + + + + + + + + + + + + + + +
{+classType+}Summary
Constructor AttributesConstructor Name and Description
{! + if (data.isPrivate) output += "<private> "; + if (data.isInner) output += "<inner> "; + !}  +
+ {+ new Link().toSymbol(data.alias).inner('constructor')+}{+ makeSignature(data.params) +} +
+
{+resolveLinks(summarize(data.desc))+}
+
+
+ + + + {! var ownProperties = data.properties.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Field Summary
Field AttributesField Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + if (member.isConstant) output += "<constant> "; + !}  +
+ {+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.properties.filter(function($) {return $.memberOf != data.alias}); + + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Fields borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + !} +
+
+
+ + + + {! var ownMethods = data.methods.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !}  +
{+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name.replace(/\^\d+$/, ''))+}{+makeSignature(member.params)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.methods.filter(function($) {return $.memberOf != data.alias}); + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Methods borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + + !} +
+
+
+ + + {! var ownEvents = data.events.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Event Summary
Event AttributesEvent Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !}  +
{+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name)+}{+makeSignature(member.params)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.events.filter(function($) {return $.memberOf != data.alias}); + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Events borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + + !} +
+
+
+ + + +
+
+ {+classType+}Detail +
+ +
{! + if (data.isPrivate) output += "<private> "; + if (data.isInner) output += "<inner> "; + !} + {+ data.alias +}{+ makeSignature(data.params) +} +
+ +
+ {+resolveLinks(data.desc)+} +
Author: {+data.author+}.
+
+ + + +
{+example+}
+
+
+ + + +
+
Parameters:
+ +
+ {+((item.type)?""+("{"+(new Link().toSymbol(item.type)+"} ")) : "")+} {+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Deprecated:
+
+ {+resolveLinks(data.deprecated)+} +
+
+
+ +
+
Since:
+
{+ data.since +}
+
+
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+ + + +
+ Field Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + if (member.isConstant) output += "<constant> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Deprecated:
+
+ {+ resolveLinks(member.deprecated) +} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
Default Value:
+
+ {+resolveLinks(member.defaultValue)+} +
+
+
+ +
+
+
+ + + +
+ Method Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name.replace(/\^\d+$/, '')+}{+makeSignature(member.params)+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Parameters:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Deprecated:
+
+ {+ resolveLinks(member.deprecated) +} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+ +
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ resolveLinks(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+
+ + + +
+ Event Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name+}{+makeSignature(member.params)+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Parameters:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+ resolveLinks(item.desc) +}
+
+
+
+ +
+
Deprecated:
+
+ {+ resolveLinks(member.deprecated) +} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+ +
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+ resolveLinks(item.desc) +}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ resolveLinks(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+
+ +
+
+ + + +
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/index.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/index.tmpl Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,39 @@ + + + + + + JsDoc Reference - Index + + + + + + + {+include("static/header.html")+} + +
+ {+publish.classesIndex+} +
+ +
+

Class Index

+ + +
+

{+(new Link().toSymbol(thisClass.alias))+}

+ {+resolveLinks(summarize(thisClass.classDesc))+} +
+
+
+ +
+
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/publish.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/publish.js Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,201 @@ +/** Called automatically by JsDoc Toolkit. */ +function publish(symbolSet) { + publish.conf = { // trailing slash expected for dirs + ext: ".html", + outDir: JSDOC.opt.d || SYS.pwd+"../out/jsdoc/", + templatesDir: JSDOC.opt.t || SYS.pwd+"../templates/jsdoc/", + symbolsDir: "symbols/", + srcDir: "symbols/src/" + }; + + // is source output is suppressed, just display the links to the source file + if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) { + Link.prototype._makeSrcLink = function(srcFilePath) { + return "<"+srcFilePath+">"; + } + } + + // create the folders and subfolders to hold the output + IO.mkPath((publish.conf.outDir+"symbols/src").split("/")); + + // used to allow Link to check the details of things being linked to + Link.symbolSet = symbolSet; + + // create the required templates + try { + var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl"); + var classesTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allclasses.tmpl"); + } + catch(e) { + print("Couldn't create the required templates: "+e); + quit(); + } + + // some ustility filters + function hasNoParent($) {return ($.memberOf == "")} + function isaFile($) {return ($.is("FILE"))} + function isaClass($) {return ($.is("CONSTRUCTOR") || $.isNamespace)} + + // get an array version of the symbolset, useful for filtering + var symbols = symbolSet.toArray(); + + // create the hilited source code files + var files = JSDOC.opt.srcFiles; + for (var i = 0, l = files.length; i < l; i++) { + var file = files[i]; + var srcDir = publish.conf.outDir + "symbols/src/"; + makeSrcFile(file, srcDir); + } + + // get a list of all the classes in the symbolset + var classes = symbols.filter(isaClass).sort(makeSortby("alias")); + + // create a filemap in which outfiles must be to be named uniquely, ignoring case + if (JSDOC.opt.u) { + var filemapCounts = {}; + Link.filemap = {}; + for (var i = 0, l = classes.length; i < l; i++) { + var lcAlias = classes[i].alias.toLowerCase(); + + if (!filemapCounts[lcAlias]) filemapCounts[lcAlias] = 1; + else filemapCounts[lcAlias]++; + + Link.filemap[classes[i].alias] = + (filemapCounts[lcAlias] > 1)? + lcAlias+"_"+filemapCounts[lcAlias] : lcAlias; + } + } + + // create a class index, displayed in the left-hand column of every class page + Link.base = "../"; + publish.classesIndex = classesTemplate.process(classes); // kept in memory + + // create each of the class pages + for (var i = 0, l = classes.length; i < l; i++) { + var symbol = classes[i]; + + symbol.events = symbol.getEvents(); // 1 order matters + symbol.methods = symbol.getMethods(); // 2 + + Link.currentSymbol= symbol; + var output = ""; + output = classTemplate.process(symbol); + + IO.saveFile(publish.conf.outDir+"symbols/", ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output); + } + + // regenerate the index with different relative links, used in the index pages + Link.base = ""; + publish.classesIndex = classesTemplate.process(classes); + + // create the class index page + try { + var classesindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"index.tmpl"); + } + catch(e) { print(e.message); quit(); } + + var classesIndex = classesindexTemplate.process(classes); + IO.saveFile(publish.conf.outDir, "index"+publish.conf.ext, classesIndex); + classesindexTemplate = classesIndex = classes = null; + + // create the file index page + try { + var fileindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allfiles.tmpl"); + } + catch(e) { print(e.message); quit(); } + + var documentedFiles = symbols.filter(isaFile); // files that have file-level docs + var allFiles = []; // not all files have file-level docs, but we need to list every one + + for (var i = 0; i < files.length; i++) { + allFiles.push(new JSDOC.Symbol(files[i], [], "FILE", new JSDOC.DocComment("/** */"))); + } + + for (var i = 0; i < documentedFiles.length; i++) { + var offset = files.indexOf(documentedFiles[i].alias); + allFiles[offset] = documentedFiles[i]; + } + + allFiles = allFiles.sort(makeSortby("name")); + + // output the file index page + var filesIndex = fileindexTemplate.process(allFiles); + IO.saveFile(publish.conf.outDir, "files"+publish.conf.ext, filesIndex); + fileindexTemplate = filesIndex = files = null; +} + + +/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */ +function summarize(desc) { + if (typeof desc != "undefined") + return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i)? RegExp.$1 : desc; +} + +/** Make a symbol sorter by some attribute. */ +function makeSortby(attribute) { + return function(a, b) { + if (a[attribute] != undefined && b[attribute] != undefined) { + a = a[attribute].toLowerCase(); + b = b[attribute].toLowerCase(); + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + } +} + +/** Pull in the contents of an external file at the given path. */ +function include(path) { + var path = publish.conf.templatesDir+path; + return IO.readFile(path); +} + +/** Turn a raw source file into a code-hilited page in the docs. */ +function makeSrcFile(path, srcDir, name) { + if (JSDOC.opt.s) return; + + if (!name) { + name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_"); + name = name.replace(/\:/g, "_"); + } + + var src = {path: path, name:name, charset: IO.encoding, hilited: ""}; + + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onPublishSrc", src); + } + + if (src.hilited) { + IO.saveFile(srcDir, name+publish.conf.ext, src.hilited); + } +} + +/** Build output for displaying function parameters. */ +function makeSignature(params) { + if (!params) return "()"; + var signature = "(" + + + params.filter( + function($) { + return $.name.indexOf(".") == -1; // don't show config params in signature + } + ).map( + function($) { + return $.name; + } + ).join(", ") + + + ")"; + return signature; +} + +/** Find symbol {@link ...} strings in text and turn into html links */ +function resolveLinks(str, from) { + str = str.replace(/\{@link ([^} ]+) ?\}/gi, + function(match, symbolName) { + return new Link().toSymbol(symbolName); + } + ); + + return str; +} diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/static/default.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/static/default.css Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,162 @@ +/* default.css */ +body +{ + font: 12px "Lucida Grande", Tahoma, Arial, Helvetica, sans-serif; + width: 800px; +} + +.header +{ + clear: both; + background-color: #ccc; + padding: 8px; +} + +h1 +{ + font-size: 150%; + font-weight: bold; + padding: 0; + margin: 1em 0 0 .3em; +} + +hr +{ + border: none 0; + border-top: 1px solid #7F8FB1; + height: 1px; +} + +pre.code +{ + display: block; + padding: 8px; + border: 1px dashed #ccc; +} + +#index +{ + margin-top: 24px; + float: left; + width: 160px; + position: absolute; + left: 8px; + background-color: #F3F3F3; + padding: 8px; +} + +#content +{ + margin-left: 190px; + width: 600px; +} + +.classList +{ + list-style-type: none; + padding: 0; + margin: 0 0 0 8px; + font-family: arial, sans-serif; + font-size: 1em; + overflow: auto; +} + +.classList li +{ + padding: 0; + margin: 0 0 8px 0; +} + +.summaryTable { width: 100%; } + +h1.classTitle +{ + font-size:170%; + line-height:130%; +} + +h2 { font-size: 110%; } +caption, div.sectionTitle +{ + background-color: #7F8FB1; + color: #fff; + font-size:130%; + text-align: left; + padding: 2px 6px 2px 6px; + border: 1px #7F8FB1 solid; +} + +div.sectionTitle { margin-bottom: 8px; } +.summaryTable thead { display: none; } + +.summaryTable td +{ + vertical-align: top; + padding: 4px; + border-bottom: 1px #7F8FB1 solid; + border-right: 1px #7F8FB1 solid; +} + +/*col#summaryAttributes {}*/ +.summaryTable td.attributes +{ + border-left: 1px #7F8FB1 solid; + width: 140px; + text-align: right; +} + +td.attributes, .fixedFont +{ + line-height: 15px; + color: #002EBE; + font-family: "Courier New",Courier,monospace; + font-size: 13px; +} + +.summaryTable td.nameDescription +{ + text-align: left; + font-size: 13px; + line-height: 15px; +} + +.summaryTable td.nameDescription, .description +{ + line-height: 15px; + padding: 4px; + padding-left: 4px; +} + +.summaryTable { margin-bottom: 8px; } + +ul.inheritsList +{ + list-style: square; + margin-left: 20px; + padding-left: 0; +} + +.detailList { + margin-left: 20px; + line-height: 15px; +} +.detailList dt { margin-left: 20px; } + +.detailList .heading +{ + font-weight: bold; + padding-bottom: 6px; + margin-left: 0; +} + +.light, td.attributes, .light a:link, .light a:visited +{ + color: #777; + font-style: italic; +} + +.fineprint +{ + text-align: right; + font-size: 10px; +} \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/static/header.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/static/header.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,2 @@ + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/static/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/static/index.html Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,19 @@ + + + + + Generated Javascript Documentation + + + + + + <body> + <p> + This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + </p> + </body> + + + \ No newline at end of file diff -r 97599ff43072 -r df716b99c5bb sbin/res/jsdoc/templates/jsdoc/symbol.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/templates/jsdoc/symbol.tmpl Fri Dec 23 11:41:46 2011 +0100 @@ -0,0 +1,35 @@ + + {+data.name+} + {+data.memberOf+} + {+data.isStatic+} + {+data.isa+} + {+data.desc+} + {+data.classDesc+} + + + + {+method.name+} + {+method.memberOf+} + {+method.isStatic+} + {+method.desc+} + + + {+param.type+} + {+param.name+} + {+param.desc+} + {+param.defaultValue+} + + + + + + + + {+property.name+} + {+property.memberOf+} + {+property.isStatic+} + {+property.desc+} + {+property.type+} + + + diff -r 97599ff43072 -r df716b99c5bb src/js/main.js --- a/src/js/main.js Fri Dec 23 10:46:07 2011 +0100 +++ b/src/js/main.js Fri Dec 23 11:41:46 2011 +0100 @@ -1,6 +1,11 @@ /* main file */ + if ( window.IriSP === undefined && window.__IriSP === undefined ) { + /** + We define here IriSP, the object under which everything goes. + We also alias it to __IriSP for backward compatibility + */ var IriSP = {}; var __IriSP = IriSP; /* for backward compatibility */ } diff -r 97599ff43072 -r df716b99c5bb src/js/widgets.js --- a/src/js/widgets.js Fri Dec 23 10:46:07 2011 +0100 +++ b/src/js/widgets.js Fri Dec 23 11:41:46 2011 +0100 @@ -1,5 +1,16 @@ /* the widget classes and definitions */ +/** + * @class Widget is an "abstract" class. It's mostly used to define some properties common to every widget. + * + * Note that widget constructors are never called directly by the user. Instead, the widgets are instantiated by functions + * defined in init.js + * + * @constructor + * @param Popcorn a reference to the popcorn Object + * @param config configuration options for the widget + * @param Serializer a serializer instance from which the widget reads data fromCharCode +*/ IriSP.Widget = function(Popcorn, config, Serializer) { if (config === undefined || config === null) { @@ -40,10 +51,16 @@ }; +/** + * This method responsible of drawing a widget on screen. + */ IriSP.Widget.prototype.draw = function() { /* implemented by "sub-classes" */ }; +/** + * Optional method if you want your widget to support redraws. + */ IriSP.Widget.prototype.redraw = function() { /* implemented by "sub-classes" */ };