'use strict'; /* An OxDoc comment is an inline or multi-line comment that starts with `@`: ``` //@ ... /*@ ... */ ``` The syntax is simple: almost every line has the form `name summary`. If it doesn't, its meaning depends on its context. */ this.My = {}; /* If the first line of the comment doesn't match `name summary`, it is a section definition. Here, it marks a section named 'Primitives'. */ //@ Primitives /* This inline comment documents an item by providing its name, type and one-line summary. */ //@ My.REQUEST_TIMEOUT Request timeout, in milliseconds My.REQUEST_TIMEOUT = 60000; /* In a multiline comment, lines that follow the inital definition are indented, as they refer to the item defined in the line above. Lines that don't match `name summary` are parsed as a description. Like the summary, the description can contain `markdown`. */ /*@ My.MAGIC_CONSTANT Magic constant, needed for HTTP requests Please note that the value of `My.MAGIC_CONSTANT` (either `23` or `42`) is browser-dependent. */ My.MAGIC_CONSTANT = navigator.userAgent.length % 2 ? 23 : 42; /* This defines a new section named 'Objects'. */ //@ Objects /* Lines that start with `#` are inline comments. The follwing lines document properties of the `My.favorites` object. This example shows all possible values for `type`. These values can be shortened, it's sufficient to specify their first character. */ /*@ My.favorites ... # Properties -------------------------------------------------------------- array My favorite array boolean My favorite boolean value date My favorite date error My favorite error function My favorite function arguments My favorite arguments htmlelement My favorite HTML element nodelist My favorite nodelist number My favorite number object My favorite object regexp My favorite regular expression string My favorite string undefined Undefined is an all-time favorite window ... other <+> ... any <*> Favorite of the day # Events ------------------------------------------------------------------- event Fires when My.favorite['function'] is called */ My.favorites = (function() { var favorites = { array: [], boolean: false, date: new Date(), error: new Error(), 'function': function() { My.triggerEvent(this, 'event'); }, arguments: (function() { return arguments; }()), htmlelement: document.createElement('a'), nodelist: document.getElementsByTagName('a'), number: 0, object: {}, regexp: new RegExp(), string: '', 'undefined': void 0, 'window': window, other: document }, keys = Object.keys(favorites); favorites.any = favorites[keys[Math.floor(Math.random() * keys.length)]]; return favorites; }()); /* Documentation can be nested. In other words, one can document the properties of a property (of a property...). Also, if all elements of an array are of a known type (in this case `string`), one can mark the type as `<[s]>` instead of just ``. */ /*@ My.HTMLUtils HTML Utilities namedEntities <[s]> Named HTML entities replace Entity decoding utilities namedEntities Can be passed to `String.prototype.replace` 0 Matches named entities 1 Decodes named entities numericEntities Can be passed to `String.prototype.replace` 0 Matches numeric entities 1 Decodes numeric entities */ My.HTMLUtils = (function() { var chars = '"&\'<>', entities = ['"', '&', ''', '<', '>']; return { namedEntities: entities, replace: { namedEntities: [ new RegExp('(' + entities.join('|') + ')', 'g'), function(match) { return chars[entities.indexOf(match)]; } ], numericEntities: [ /&#([0-9A-FX]+);/gi, function(match, code) { return String.fromCharCode( /^X/i.test(code) ? parseInt(code.slice(1), 16) : parseInt(code, 10) ); } ], } }; }()); /* The beginning of another section, named 'Functions'. */ //@ Functions /* In the case of a function, the indented lines don't document properties, but the function's signature, return value and arguments. Signature and return value are just a special case of `name summary`, where `name` has the form `(arguments) ->`. If an item can be of more than one type (in this case `string` or `function`), this is documented as ``. If it has a default value (in this case the string `'GET'`), this is documented as ``. In the case of a `function`-type argument (usually a callback function), there is no return value to document, only the arguments it gets passed. */ /*@ My.readURL Asynchronously reads a remote resource (url[, method], callback) -> undefined Please note that the return value of `My.readURL` may change in the future. url Remote URL, or function that returns one method Request method ('GET', 'POST', 'PUT' or 'DELETE') callback Callback function result Response text, or `null` in case of an error error Error object, or `null` in case of success code Error code text Error text */ My.readURL = function(url, method, callback) { var request = new XMLHttpRequest(); if (Ox.isFunction(url)) { url = url(); } if (arguments.length == 2) { callback = method; method = 'GET'; } request.open(method, url, true); request.onreadystatechange = function() { if (request.readyState == 4) { if (request.status == 200) { callback(request.responseText, null); } else { callback(null, { code: request.status, text: request.statusText }); } } }; request.send(); }; /* If a function's return value depends on the absence or presence of optional arguments, there can be multiple `(arguments) -> summary` lines. */ /*@ My.isOdd Synchronously or asynchronously computes if a given number is odd (number) -> True if the number is odd (number, callback) -> undefined number Any number callback Callback function isOdd True if the number is odd ms Time it took to compute the result, in milliseconds */ My.isOdd = function(number, callback) { var time = +new Date, isOdd = !!(number % 2); if (callback) { callback(isOdd, +new Date - time); } else { return isOdd; } }; /* Another case for multiple `(arguments) -> summary` lines are functions whose signature cannot be represented in `(required[, optional])` notation. For a range function — `(stop)` or `(start, stop)` or `(start, stop, step)` — the notation `([start, ]stop[, step])` would be ambigious, since you cannot call it with `(stop, step)`. */ /*@ My.range Returns a python-style range (b) -> <[n]> Integers from 0 (inclusive) to b (exclusive) (a, b) -> <[n]> Integers from a (inclusice) to b (exclusive) (a, b, c) -> <[n]> Numbers from a (inclusive) to b (exclusive), growing by c */ My.range = function() { var a = []; Ox.loop.apply(null, Ox.toArray(arguments).concat(function(i) { a.push(i); })); return a; }; /* In case a function has a property or method one wants to document, it gets prefixed with `.`, in order to differentiate it from an argument. */ /*@ My.localStorage Returns a localStorage handler for a given namespace (ns) -> storage localStorage handler () -> Returns all key:value pairs (key) -> <*> Returns one value (key, value) -> Sets one value, returns the handler ({key: value, ...}) -> Sets one or more values, returns the handler key Any string value <*> Any value that can be JSON-serialized .delete Delete method () -> Deletes all key:value pairs, returns the handler (key[, ...]) -> Deletes one or more pairs, returns the handler key Any string ns Namespace */ My.localStorage = (function() { if (!window.localStorage) { window.localStorage = {}; } return function(ns) { function storage(key, value) { var args, ret; if (arguments.length == 0) { ret = {}; Ox.forEach(localStorage, function(value, key) { if (Ox.startsWith(key, ns + '.')) { ret[key.slice(ns.length + 1)] = JSON.parse(value); } }); } else if (arguments.length == 1 && !Ox.isObject(key)) { value = localStorage[ns + '.' + key]; ret = Ox.isUndefined(value) ? void 0 : JSON.parse(value); } else { Ox.forEach(Ox.makeObject(arguments), function(value, key) { localStorage[ns + '.' + key] = JSON.stringify(value); }); ret = this; } return ret; }; storage.delete = function() { var keys = arguments.length == 0 ? Object.keys(storage()) : Ox.toArray(arguments) keys.forEach(function(key) { delete localStorage[ns + '.' + key]; }); return storage; }; return storage; }; }()); /* And one more section, named 'UI Elements'. */ //@ UI Element /*@ My.Box A very simple colored box options Options color <[n]> RGB value self Shared private object ([options[, self]]) -> Box object grayscale Fires when changing the color of the box to grayscale color Value between `0` and `255` */ My.Box = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({color: [255, 0, 0]}) .options(options || {}) .update(setColor) .css({width: '256px', height: '256px'}); function setColor() { that.css({background: 'rgb(' + self.options.color.join(', ') + ')'}); } /*@ .toGrayscale Changes the color of the box to grayscale. () -> The box object */ that.toGrayscale = function() { return that.options({ color: Ox.repeat([Ox.avg(self.options.color)], 3) }).triggerEvent('grayscale', {color: self.options.color[0]}); }; return that; }; //@ Ox.load('UI', function() { var file = 'example.js', path = Ox.PATH + '../examples/documentation/oxdoc/js/'; Ox.get(path + file, function(source) { var doc = Ox.doc(source); Ox.TabPanel({ content: { source: Ox.SyntaxHighlighter({source: path + file}), doc: Ox.TreeList({data: doc}), docpanel: Ox.DocPanel({ expanded: true, files: 'example.js', path: path }) }, tabs: [ {id: 'source', title: 'source'}, {id: 'doc', title: 'doc = Ox.doc(source)'}, {id: 'docpanel', title: 'Ox.DocPanel({items: doc})'} ] }).appendTo(Ox.$body); }); });