short-jsdoc
Version:
short and simple jsdoc Object Oriented syntax format and implementation
419 lines (374 loc) • 9.93 kB
JavaScript
// @module shortjsdoc.html
// this file add methods to Abstract Application for dealing with types and html markup.
// @class AbstractView @extends Backbone.View
_(AbstractView.prototype).extend({
//@method printTag
printTag: function(text, classAttribute, tag)
{
tag = tag || 'span';
classAttribute = classAttribute ||'';
if(text)
{
return '<'+tag+ (classAttribute?(' class="'+classAttribute+'"'):'') +'>'+text+'</'+tag+'>';
}
return '';
}
//@method simpleName @param {String}name
, simpleName: function(name, prefix)
{
return this.application.maker.simpleName(name, prefix);
}
//@method makeLink @param {boolean} htmlAnchors will output anchor elements html @param {Object|String} options
, makeLink: function(node, htmlAnchors, options)
{
if(!node)
{
debugger;
}
var className = node.annotation + '-name';
var s = htmlAnchors ? ('<a class="' + className + '" href="') : '';
var href = '';
if(_.isString(node))
{
href += '#' + node;
}
else if(node.annotation==='method')
{
href += '#method/' + node.absoluteName;
}
else if(node.annotation==='constructor')
{
href += '#constructor/' + node.absoluteName;
}
else if(node.annotation==='function')
{
href += '#function/' + node.absoluteName;
}
else if(node.annotation==='property')
{
href += '#property/' + node.absoluteName;
}
else if(node.annotation==='event')
{
href += '#event/' + node.absoluteName;
}
else if(node.annotation==='class'||node.annotation==='interface')
{
href += '#class/' + node.absoluteName;
}
else if(node.annotation==='module')
{
href += '#module/' + node.name;
}
else
{
return '';
}
//preserve current params
var search = location.hash.indexOf('?')===-1 ? '' : location.hash.split('?')[1];
search = this.paramStringToObject(search);
if(_.isString(options))
{
options = this.paramStringToObject(options);
}
_.extend(search, options||{});
search = this.paramObjectToString(search);
href += search ? ('?' + search) : '';
s += href + (htmlAnchors?('">'+node.name+'</a>'):'');
return s;
}
, paramStringToObject: function(s)
{
var a = s.split('&');
var o = {};
_.each(a, function(pf)
{
var a2 = pf.split('=');
o[a2[0]] = a2[1];
});
return o;
}
, paramObjectToString: function(o)
{
var s = [];
_.each(o, function(val,name)
{
if(name)
{
s.push(name+'='+val);
}
});
return s.join('&');
}
, printLiteralObjectType: function(context)
{
var self = this;
var buf = [];
context.buffer.push(this.printType(context.type, true));
var has_only_proto = _(context.type.properties).keys().length===1 && context.type.properties.prototype;
if(has_only_proto) //dirty hack to resolve incompatibility between literal types and Object class inherited props
{
return;
}
if(context.type.name==='Object')
{
context.buffer.push('{')
_(context.type.properties).each(function(value, key)
{
buf.push(key + ': ' + self.printSingleTypeAsString(value, true));
});
}
context.buffer.push(buf.join(', '));
if(context.type.name==='Object')
{
context.buffer.push('}');
}
}
// @method printType prints a type as html support generic. This is really a html template function
// @param {Object}context @return {String} the type html
, printType: function(context, ignoreLiteralObject)
{
if(!context || !context.type)
{
return '';
}
var self = this;
var href = context.type.nativeTypeUrl || this.makeLink(context.type);//'#class/'+context.type.absoluteName;
var htmlText = context.type.name;
var aclass = (context.type.nativeTypeUrl ? ' type external ' : ' type ');
var iconHtml = context.type.nativeTypeUrl ? '<span class="glyphicon glyphicon-share"></span>' : '';
context.buffer.push('<a class="'+aclass+'" href="'+href+'">'+iconHtml+htmlText+'</a>');
if(context.type.properties && !ignoreLiteralObject)
{
this.printLiteralObjectType(context);
}
else if(context.type.params && context.type.annotation!=='function')
{
context.buffer.push('<');
for (var i = 0; i < (context.type.params||[]).length; i++)
{
var param = context.type.params[i];
self.printType({ //recurse!
type:param
, buffer: context.buffer
});
if(i < context.type.params.length - 1)
{
context.buffer.push(',');
}
}
context.buffer.push('>');
}
}
//@method printSingleTypeAsString this is the public method for printing a type - supports any type @param {String} type @return {String} @return {String} the type html
, printSingleTypeAsString: function(type, dontRecurse)
{
var buffer = [];
var context = {type: type, typeTemplate: this.printType, buffer: buffer};
this.printType(context);
var typeOutput = buffer.join('');
return typeOutput;
}
//@method printTypeAsString @param {Array<Type>|Type} type @return {String} the type html
, printTypeAsString: function(type)
{
var self = this;
if(_(type).isArray())
{
var a = [];
_(type).each(function(t)
{
a.push(self.printSingleTypeAsString(t));
});
return a.join('<span class="type-separator">or</span>');
}
else
{
return this.printSingleTypeAsString(type);
}
}
//@method getTextHtml depends on lib/marked/ - all texts should be printed using this method
, getTextHtml: function(node)
{
if(!node || !node.text)
{
return '';
}
if(node.text_html_app) //caching
{
return node.text_html_app;
}
var self2 = this //TODO investigate why I need self2 and self always binds to other thing than this...
, text = node.text
, type = this.application.textFormat || 'markdown'
, html = _(node.children).find(function(c){return c.annotation==='html'; })
, markdown = _(node.children).find(function(c){return c.annotation==='markdown'; });
if(html)
{
type = 'html';
}
if(markdown)
{
type = 'markdown';
}
// perform text marks replacement.
_(node.textMarks).each(function(mark, markId)
{
if(mark.name === 'link')
{
if(type === 'markdown')
{
text = text.replace(markId, '['+mark.linkLabel+']('+mark.linkUrl+')');
}
else
{
text = text.replace(markId, '< href="mark.linkUrl" class="text-mark-link">'+mark.linkLabel+'</a>');
}
}
else if(mark.binding)
{
text = text.replace(markId, self2.makeLink(mark.binding, true));
}
});
if(type === 'markdown')
{
text = marked(text);
}
node.text_html_app = text;
return text;
}
//@method printMethod
, printMethod: function(m)
{
var isConstructor = m.annotation==='constructor';
var s = '<span class="method">';
var methodName = isConstructor ? this.simpleName(m.ownerClass) : m.name;
if(!isConstructor && m.returns)
{
s += this.printTypeAsString(m.returns) + ' ';
}
s += '<a href="' + this.makeLink(m) + '">' + methodName + '</a>';
return s + '</span>';
}
, getInherited: function(c, what)
{
var data = {};
if(what==='method')
{
data = _(c.methods).clone();
_(data).extend(c.inherited.methods || {});
}
return data;
}
, getClassName: function(absoluteName, data)
{
data = data || this.application.data;
var a = absoluteName.split('.')
while(a)
{
a = _.initial(a)
var name = a.join('.')
if(data.classes[name])
{
return name;
}
}
return absoluteName.substring(0, absoluteName.lastIndexOf('.')); //probably an error
}
, getSimpleName: function(absoluteName)
{
var className = this.getClassName(absoluteName);
return absoluteName.substring(className.length + 1, absoluteName.length);
}
, getModuleClasses: function(moduleName, data)
{
if(!data)
{
data = this.application.data;
}
var a = [];
_(data.classes).each(function(c)
{
if(c.absoluteName.indexOf(moduleName)===0)
{
a.push(c);
}
});
return a;
}
// TODO: move the following to misc utility class
//@method parseOptions @return {Object<String,String>}
, parseOptions: function(options, propSep, valueSep)
{
propSep = propSep || '&';
valueSep = valueSep || '=';
if(!options)
{
return {};
}
var params = {};
_(options.split(propSep)).each(function(p)
{
var a = p.split(valueSep);
if (a.length >= 2)
{
params[a[0]] = a[1];
if(!a[1] || a[1]==='0' || a[1]==='false')
{
params[a[0]] = false;
}
}
});
return params;
}
, getOptionsFromHash: function(hash)
{
hash = hash || window.location.hash;
var options = hash.split('?');
options = options.length<2 ? '' : options[1];
return this.parseOptions(options);
}
, setOptionsToHash: function(hash, newOptions)
{
hash = hash || window.location.hash;
var options = hash.split('?');
options = options.length<2 ? '' : options[1];
options = this.parseOptions(options);
_(options).extend(newOptions);
return hash.split('?')[0] + '?' + this.optionsToString(options);
}
, optionsToString: function(options, propSep, valueSep)
{
propSep = propSep || '&';
valueSep = valueSep || '=';
var a = [];
_(options).each(function(value, key)
{
a.push(key + valueSep + value);
});
return a.join(propSep);
}
//public / private
, propertyIsPublicPredicate: function(p)
{
return _.find(p.children, function(c)
{
return c.annotation === 'public';
});
}
, isClassPublic:function(c)
{
var isPublic = this.propertyIsPublicPredicate(c)
isPublic = isPublic || _.find(c.methods, this.propertyIsPublicPredicate)
isPublic = isPublic || _.find(c.properties, this.propertyIsPublicPredicate)
isPublic = isPublic || _.find(c.events, this.propertyIsPublicPredicate)
isPublic = isPublic || _.find(c.attributes, this.propertyIsPublicPredicate)
return isPublic;
}
, isModulePublic: function(m)
{
var classes = this.getModuleClasses(m.name);
// debugger;
return _.find(classes, _.bind(this.isClassPublic, this))
}
});