// ------------------------------------------------------------------------------------------ // // ReSpec.js -- a specification-writing tool // Robin Berjon, http://berjon.com/ // ----------------------------------------------------------------------------------------- // // Documentation: http://dev.w3.org/2009/dap/ReSpec.js/documentation.html // License: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 // ------------------------------------------------------------------------------------------ // // SUPPORT // The official support channel for ReSpec is spec-prod@w3.org. // The archives are available at http://lists.w3.org/Archives/Public/spec-prod/ // You can subscribe by sending email to spec-prod-request@w3.org with "subscribe" as the // subject line. // Please use that instead of emailing me (Robin) directly as the chances are that questions // or enhancement ideas will be shared by others. Thanks! // XXX TODO // - move to the top of dev. hierarchy // - add autolinking to headers in the output (like WebIDL) // - better inline dependent CSS // - add typographical conventions section // - WebIDL // . make it so that extended attributes on members and attributes are only wrapped if needed // . make processor aware of some extended attributes (e.g. Constructor) // . support variadic params // . support arrays // . support special operations: getter, setter, creator, deleter, caller, omittable // . support stringifiers // - add support for a test variant of the specification, based on the ideas in P+C // - some refactoring is in order // - make a widget that can save using the FS API, and inject the API without it being in the template, // inline CSS without hassle, etc. // - make a list of links to issues appear on a key combination // - warn on empty links to no dfn (perhaps in a special debug mode?) // - make everything that uses "::before" actually generate the real content instead (function () { if (typeof(berjon) == "undefined") berjon = {}; var sn; function _errEl () { var err = document.getElementById("respec-err"); if (err) return err.firstElementChild; err = sn.element("div", { id: "respec-err", style: "position: fixed; width: 350px; top: 10px; right: 10px; border: 3px double #f00; background: #fff", "class": "removeOnSave" }, document.body); return sn.element("ul", {}, err); } function error (str) { sn.element("li", { style: "color: #c00" }, _errEl(), str); } function warning (str) { sn.element("li", { style: "color: #666" }, _errEl(), str); } berjon.respec = function () { for (var k in this.status2text) { if (this.status2long[k]) continue; this.status2long[k] = this.status2text[k]; } }; berjon.respec.prototype = { title: null, additionalCopyrightHolders: null, overrideCopyright: null, editors: [], authors: [], recTrackStatus: ["FPWD", "WD", "LC", "CR", "PR", "PER", "REC"], noTrackStatus: ["MO", "unofficial", "base"], status2text: { NOTE: "Note", "WG-NOTE": "Working Group Note", "CG-NOTE": "Co-ordination Group Note", "IG-NOTE": "Interest Group Note", "Member-SUBM": "Member Submission", "Team-SUBM": "Team Submission", XGR: "Incubator Group Report", MO: "Member-Only Document", ED: "Editor's Draft", FPWD: "Working Draft", WD: "Working Draft", "FPWD-NOTE": "Working Draft", "WD-NOTE": "Working Draft", "LC-NOTE": "Working Draft", LC: "Working Draft", CR: "Candidate Recommendation", PR: "Proposed Recommendation", PER: "Proposed Edited Recommendation", REC: "Recommendation", RSCND: "Rescinded Recommendation", unofficial: "Unofficial Draft", base: "Document", "draft-finding": "Draft TAG Finding", "finding": "TAG Finding" }, status2long: { FPWD: "First Public Working Draft", "FPWD-NOTE": "First Public Working Draft", LC: "Last Call Working Draft", "LC-NOTE": "Last Call Working Draft" }, status2maturity: { FPWD: "WD", LC: "WD", "FPWD-NOTE": "WD", "WD-NOTE": "WD", "LC-NOTE": "LC", "WG-NOTE": "NOTE" }, isLocal: false, loadAndRun: function () { var scripts = document.querySelectorAll("script[src]"); var rs, base; for (var i = 0; i < scripts.length; i++) { var src = scripts[i].src; if (/\/js\/respec\.js$/.test(src)) { rs = scripts[i]; base = src.replace(/js\/respec\.js$/, ""); } } this.base = base; if (base.indexOf("file://") == 0) this.isLocal = true; var loaded = []; var deps = ["js/simple-node.js", "js/shortcut.js", "bibref/biblio.js", "js/sh_main.min.js"]; var head = document.getElementsByTagName('head')[0]; var obj = this; for (var i = 0; i < deps.length; i++) { var dep = deps[i]; var sel = document.createElement('script'); sel.type = 'text/javascript'; sel.src = base + dep; sel.setAttribute("class", "remove"); sel.onload = function (ev) { loaded.push(ev.target.src); if (obj.isLocal && ev.target.src.indexOf("sh_main") > 0) { // dirty hack to fix local loading of SHJS this.oldSHLoad = window.sh_load; window.sh_load = function (language, element, prefix, suffix) { if (language in sh_requests) { sh_requests[language].push(element); return; } sh_requests[language] = [element]; var url = prefix + 'sh_' + language + suffix; var shLang = document.createElement('script'); shLang.type = 'text/javascript'; shLang.src = url; shLang.setAttribute("class", "remove"); shLang.onload = function (ev) { var elements = sh_requests[language]; for (var i = 0; i < elements.length; i++) { sh_highlightElement(elements[i], sh_languages[language]); } }; head.appendChild(shLang); }; } if (loaded.length == deps.length) { sn = new berjon.simpleNode({ "": "http://www.w3.org/1999/xhtml", "x": "http://www.w3.org/1999/xhtml" }, document); obj.run(); } }; head.appendChild(sel); } }, run: function () { document.body.style.display = "none"; try { this.extractConfig(); if (respecConfig.preProcess) { for (var i = 0; i < respecConfig.preProcess.length; i++) respecConfig.preProcess[i].apply(this); } this.makeTemplate(); // This is done REALLY early in case the transform ends up // needing to include something this.doTransforms() ; // This is done early so that if other data gets embedded it will be // processed this.includeFiles(); this.dfn(); this.inlines(); this.webIDL(); this.examples(); // only process best practices if element with class // practicelab found, do not slow down non best-practice // docs. // doBestPractices must be called before makeTOC, fjh // this might not work with old browsers like IE 8 var bpnode = document.getElementsByClassName("practicelab"); if(bpnode.length > 0) this.doBestPractices(); this.informative(); this.fixHeaders(); this.makeTOC(); this.idHeaders(); if (respecConfig.postProcess) { for (var i = 0; i < respecConfig.postProcess.length; i++) respecConfig.postProcess[i].apply(this); } // if (this.doMicroData) this.makeMicroData(); if (this.doRDFa) this.makeRDFa(); this.makeSectionRefs(); // allow references to sections using name for text, fjh this.unHTML5(); this.removeRespec(); // shortcuts var obj = this; // shortcut.add("Alt+H", function () { obj.toHTML(); }); // shortcut.add("Shift+Alt+H", function () { obj.toHTMLSource(); }); shortcut.add("Ctrl+Shift+Alt+S", function () { obj.showSaveOptions(); }); shortcut.add("Esc", function () { obj.hideSaveOptions(); }); } catch (e) { document.body.style.display = "inherit"; error("Processing error: " + e); if (typeof(console) != "undefined" && console.log) console.log(e); } document.body.style.display = "inherit"; }, makeRDFa: function () { var abs = document.getElementById("abstract"); if (abs) { var rel = 'dcterms:abstract' ; var ref = abs.getAttribute('property') ; if (ref) { rel = ref + ' ' + rel ; } abs.setAttribute('property', rel) ; abs.setAttribute('datatype', '') ; } // annotate sections with Section data var secs = document.querySelectorAll("section"); for (var i = 0; i < secs.length; i++) { // if the section has an id, use that. if not, look at the first child for an id var about = '' ; // the first child should be a header - that's what we will annotate var fc = secs[i].firstElementChild; var ref = secs[i].getAttribute('id') ; if ( ref ) { about = '#' + ref ; } else { if (fc) { ref = fc.getAttribute('id') ; if (ref) { about = '#' + ref; } } } if (about != '') { secs[i].setAttribute('typeof', 'bibo:Chapter') ; secs[i].setAttribute('about', about) ; } } }, saveMenu: null, showSaveOptions: function () { var obj = this; this.saveMenu = sn.element("div", { style: "position: fixed; width: 400px; top: 10px; padding: 1em; border: 5px solid #90b8de; background: #fff" }, document.body); sn.element("h4", {}, this.saveMenu, "Save Options"); var butH = sn.element("button", {}, this.saveMenu, "Save as HTML"); butH.onclick = function () { obj.hideSaveOptions(); obj.toHTML(); }; var butS = sn.element("button", {}, this.saveMenu, "Save as HTML (Source)"); butS.onclick = function () { obj.hideSaveOptions(); obj.toHTMLSource(); }; var butS = sn.element("button", {}, this.saveMenu, "Save as XHTML"); butS.onclick = function () { obj.hideSaveOptions(); obj.toXHTML(); }; var butS = sn.element("button", {}, this.saveMenu, "Save as XHTML (Source)"); butS.onclick = function () { obj.hideSaveOptions(); obj.toXHTMLSource(); }; if (this.diffTool && (this.previousDiffURI || this.previousURI) ) { var butD = sn.element("button", {}, this.saveMenu, "Diffmark"); butD.onclick = function () { obj.hideSaveOptions(); obj.toDiffHTML(); }; } }, hideSaveOptions: function () { if (!this.saveMenu) return; this.saveMenu.parentNode.removeChild(this.saveMenu); }, toString: function () { var str = "\n"; str += "\n"; str += document.documentElement.innerHTML; str += ""; return str; }, toXML: function () { var str = "\n\n"; str += "\n"; // walk the entire DOM tree grabbing nodes and emitting them - possibly modifying them // if they need the funny closing tag var pRef = this ; var selfClosing = {}; "br img input area base basefont col isindex link meta param hr".split(" ").forEach(function (n) { selfClosing[n] = true; }); var dumpNode = function (node) { var out = '' ; // if the node is the document node.. process the children if ( node.nodeType == 9 || ( node.nodeType == 1 && node.nodeName.toLowerCase() == 'html' ) ) { for (var i = 0; i < node.childNodes.length; i++) out += dumpNode(node.childNodes[i]) ; } // element else if (1 === node.nodeType) { var ename = node.nodeName.toLowerCase() ; out += '<' + ename ; for (var i = 0; i < node.attributes.length; i++) { var atn = node.attributes[i] out += " " + atn.name + "=\"" + pRef._esc(atn.value) + "\""; } if (selfClosing[ename]) { out += ' />'; } else { out += '>'; // XXX removing this, as it does not seem correct at all // if ( ename == 'pre' ) { // out += "\n" + node.innerHTML; // } // else { for (var i = 0; i < node.childNodes.length; i++) out += dumpNode(node.childNodes[i]); // } out += '' + ename + '>'; } } // comments else if (8 === node.nodeType) { out += "\n\n"; } // text or cdata else if (3 === node.nodeType || 4 === node.nodeType) { out += pRef._esc(node.nodeValue); } // we don't handle other types for the time being else { warning("Cannot handle serialising nodes of type: " + node.nodeType); } return out; }; var node = document.documentElement; str += dumpNode(document.documentElement) ; str += ""; return str; }, toDiffHTMLSource: function () { }, toDiffHTML: function () { // create a diff marked version against the previousURI // strategy - open a window in which there is a form with the // data needed for diff marking - submit the form so that the response populates // page with the diff marked version var base = window.location.href; base = base.replace(/\/[^\/]*$/, "/"); var str = "\n"; str += "\n"; str += "
" + this._esc(this.toString()) + ""); x.document.close(); }, toXHTML: function () { var x = window.open(); x.document.write(this.toXML()) ; x.document.close(); }, toXHTMLSource: function () { var x = window.open(); x.document.write("
" + this._esc(this.toXML()) + ""); x.document.close(); }, // --- METADATA ------------------------------------------------------- extractConfig: function () { this.title = document.title; var cfg; if (respecConfig) cfg = respecConfig; else cfg = {}; // defaulting if (!cfg.specStatus) cfg.specStatus = "ED"; // the below is experimental, use this if it fails: // cfg.publishDate = new Date(); if (!cfg.publishDate) { cfg.publishDate = this._parseLastModified(document.lastModified); } else { cfg.publishDate = this._parseDate(cfg.publishDate); } if (cfg.previousPublishDate) cfg.previousPublishDate = this._parseDate(cfg.previousPublishDate); if (cfg.previousPublishDate && ! cfg.previousMaturity && cfg.specStatus.indexOf("finding") === -1) error("Previous date is set, but not previousMaturity"); if (cfg.lcEnd) cfg.lcEnd = this._parseDate(cfg.lcEnd); if (cfg.crEnd) cfg.crEnd = this._parseDate(cfg.crEnd); if (cfg.specStatus == "LC" && !cfg.lcEnd) error("If specStatus is set to LC, then lcEnd must be defined"); if (cfg.specStatus == "CR" && !cfg.crEnd) error("If specStatus is set to CR, then crEnd must be defined"); if (!cfg.editors) cfg.editors = []; if (!cfg.authors) cfg.authors = []; if (!cfg.alternateFormats) cfg.alternateFormats = []; if (cfg.inlineCSS === undefined) cfg.inlineCSS = true; if (!cfg.noIDLSorting) cfg.noIDLSorting = false; if (cfg.noIDLIn === undefined) cfg.noIDLIn = true; if (cfg.tocIntroductory === undefined) cfg.tocIntroductory = false; if (!cfg.maxTocLevel) cfg.maxTocLevel = 0; if (!cfg.diffTool) cfg.diffTool = 'http://www5.aptest.com/standards/htmldiff/htmldiff.pl'; if (!cfg.noRecTrack) cfg.noRecTrack = false; if (!cfg.doRDFa) cfg.doRDFa = false; for (var k in cfg) this[k] = cfg[k]; this.isRecTrack = cfg.noRecTrack ? false : this.recTrackStatus.indexOf(this.specStatus) >= 0; this.isNoTrack = this.noTrackStatus.indexOf(this.specStatus) >= 0; // this.specStatus = this._getMetaFor("http://berjon.com/prop/spec-status", "ED"); // this.shortName = this._getMetaFor("http://berjon.com/prop/short-name", "xxx-xxx"); // this.publishDate = this._getDateFor("head > time[itemprop='http://berjon.com/prop/publish-date']"); // this.prevPublishDate = this._getDateFor("head > time[itemprop='http://berjon.com/prop/previous-publish-date']"); }, _getMetaFor: function (iProp, def) { var meta = document.querySelector("head > meta[itemprop='" + iProp + "']"); if (meta) return meta.getAttribute("content"); else return def; }, _getDateFor: function (sel) { var el = document.querySelector(sel); if (el) { var val = el.getAttribute('datetime'); return new Date(val.substr(0, 4), val.substr(5, 2), val.substr(8, 2)); } else { return new Date(); } }, // --- W3C BASICS ----------------------------------------------------------------------------------------- makeTemplate: function () { this.rootAttr(); this.addCSS(); this.makeHeaders(); this.makeAbstract(); this.makeSotD(); this.makeConformance(); }, rootAttr: function () { document.documentElement.setAttribute("lang", "en"); document.documentElement.setAttribute("dir", "ltr"); if (this.doRDFa) { document.documentElement.setAttribute("about", ""); document.documentElement.setAttribute("property", "dcterms:language"); document.documentElement.setAttribute("content", "en"); } }, addCSS: function () { if (this.extraCSS) { for (var i = 0; i < this.extraCSS.length; i++) this._insertCSS(this.extraCSS[i], this.inlineCSS); } var statStyle = this.specStatus; if (statStyle == "FPWD" || statStyle == "LC" || statStyle == "WD-NOTE" || statStyle == "LC-NOTE" || statStyle == "FPWD-NOTE") { statStyle = "WD"; } else if (statStyle === "finding" || statStyle === "draft-finding") statStyle = "base"; // else if ( statStyle == "WD-NOTE" || statStyle == "LC-NOTE" // || statStyle == "FPWD-NOTE") { // statStyle = "WG-NOTE"; // } var css; if (statStyle == "unofficial") { css = "https://www.w3.org/StyleSheets/TR/w3c-unofficial"; } else if (statStyle == "base") { css = "https://www.w3.org/StyleSheets/TR/base"; } else { css = "https://www.w3.org/StyleSheets/TR/W3C-" + statStyle;// + ".css"; } this._insertCSS(css, false); }, doTransforms: function() { var divs = document.querySelectorAll("[data-transform]"); for (var i = 0; i < divs.length; i++) { var div = divs[i]; var content = div.innerHTML ; var flist = div.getAttribute('data-transform'); if (flist) { var methods = flist.split(/\s+/) ; for (var j = 0; j < methods.length; j++) { var call = 'content = ' + methods[j] + '(this,content)' ; try { eval(call) ; } catch (e) { warning('call to ' + call + ' failed with ' + e) ; } } div.removeAttribute('data-transform') ; } if (content) { div.innerHTML = content ; } } }, includeFiles: function() { var divs = document.querySelectorAll("[data-include]"); for (var i = 0; i < divs.length; i++) { var div = divs[i]; var URI = div.getAttribute('data-include'); var content = this._readFile(URI) ; if (content) { var flist = div.getAttribute('data-oninclude'); if (flist) { var methods = flist.split(/\s+/) ; for (var j = 0; j < methods.length; j++) { var call = 'content = ' + methods[j] + '(this,content,URI)' ; try { eval(call) ; } catch (e) { warning('call to ' + call + ' failed with ' + e) ; } } div.removeAttribute('data-oninclude') ; } div.removeAttribute('data-include') ; div.innerHTML = content ; } } }, // single function used to display people information for editors, // authors, etc (fjh 2009-12-04) showPeople: function(name, people) { var header = ""; if (people.length == 0) return header; var re = '' ; var rp = '' ; var rl = '' ; var rt = '' ; var rm = '' ; var rn = '' ; var rwu = '' ; var rpu = '' ; if ( this.doRDFa ) { if ( name == 'Editor' ) { re = " rel='bibo:editor'"; rn = " property='foaf:name'"; rm = " rel='foaf:mbox'"; rp = " typeof='foaf:Person'"; rwu = " rel='foaf:workplaceHomepage'"; rpu = " rel='foaf:homepage'"; } else if (name == 'Author' ) { re = " rel='dcterms:contributor'"; rn = " property='foaf:name'"; rm = " rel='foaf:mbox'"; rp = " typeof='foaf:Person'"; rwu = " rel='foaf:workplaceHomepage'"; rpu = " rel='foaf:homepage'"; } } if (people.length > 1) { header += "
"; header += "Copyright © " ; if (this.copyrightStart && this.copyrightStart != this.publishDate.getFullYear()) header += this.copyrightStart + '-'; header += this.publishDate.getFullYear(); header += " W3C® " + "(MIT, " + "ERCIM, " + "Keio), All Rights Reserved. " + "W3C liability, " + "trademark and " + "document use rules apply." + "
"; if (this.specStatus != "unofficial") header += ""; if (this.specStatus == 'XGR') header += ""; if ( this.doRDFa ) { header += "
Please refer to the errata for this document, which may include some normative corrections.
'; } if (this.alternateFormats.length > 0) { var len = this.alternateFormats.length ; if (len == 1) { header += 'This document is also available in this non-normative format: '; } else { header += '
This document is also available in these non-normative formats: '; } for (var f = 0; f < len; f++) { if (f > 0) { if ( len == 2) { header += ' '; } else { header += ', ' ; } if (f == len - 1) { header += 'and '; } } var ref = this.alternateFormats[f] ; header += "" + ref.label + "" ; } header += '.
'; } if (this.specStatus == "REC") header += 'The English version of this specification is the only normative version. Non-normative translations may also be available.
'; if (this.specStatus == "unofficial") { var copyright; if (this.additionalCopyrightHolders) copyright = "" + this.additionalCopyrightHolders + "
"; else if (this.overrideCopyright) copyright = this.overrideCopyright; else copyright = "This document is licensed under a Creative Commons Attribution 3.0 License.
"; header += copyright; } else { if (this.overrideCopyright) { header += this.overrideCopyright; } else { header += ""; if (this.doRDFa) { header += "Copyright © "; } else { header += "Copyright © "; } if (this.copyrightStart) { header += this.copyrightStart + '-'; } header += this.publishDate.getFullYear(); if (this.additionalCopyrightHolders) header += " " + this.additionalCopyrightHolders + " &"; if (this.doRDFa) { header += " W3C® "; } else { header += " W3C® "; } header += "(MIT, " + "ERCIM, " + "Keio), All Rights Reserved. " + "W3C liability, " + "trademark and " + "document use rules apply.
"; } } header += "This document is merely a public working draft of a potential specification. It has " + "no official standing of any kind and does not represent the support or consensus of any " + "standards organisation.
"; if (custom) sotd += custom.innerHTML; sotd += "ReSpec does not support automated SotD generation for TAG findings, please specify one using a <section> element with ID=sotd.
"; sotd += "This document is merely a W3C-internal" + mc + " document. It has no "+ "official standing of any kind and does not represent consensus of the W3C Membership.
"; if (custom) sotd += custom.innerHTML; sotd += "This section describes the status of this document at the time of its publication. Other " + "documents may supersede this document. A list of current W3C publications and the latest revision " + "of this technical report can be found in the W3C technical reports " + "index at http://www.w3.org/TR/.
"; if (custom) sotd += custom.innerHTML; sotd += "This document was published by the " + this.wg + " as " + art + this.status2long[this.specStatus] + "."; if (this.isRecTrack && this.specStatus != "REC") sotd += " This document is intended to become a W3C Recommendation."; sotd += " If you wish to make comments regarding this document, please send them to " + this.wgPublicList + "@w3.org (subscribe, " + "archives)."; if (this.specStatus == "LC") sotd += " The Last Call period ends " + this._humanDate(this.lcEnd) + "."; if (this.specStatus == "CR") sotd += " W3C publishes a Candidate Recommendation to indicate that the document is believed" + " to be stable and to encourage implementation by the developer community. This" + " Candidate Recommendation is expected to advance to Proposed Recommendation no earlier than " + this._humanDate(this.crEnd) + "."; sotd += " All feedback is welcome.
"; if (this.specStatus != "REC") { sotd += "Publication as a " + this.status2text[this.specStatus] + " does not imply endorsement by the W3C Membership. " + "This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate " + "to cite this document as other than work in progress.
"; } if (this.specStatus == "LC") sotd += "This is a Last Call Working Draft and thus the Working Group has determined that this document has satisfied the " + "relevant technical requirements and is sufficiently stable to advance through the Technical Recommendation process.
"; sotd += "This document was produced by a group operating under the 5 February " + "2004 W3C Patent Policy."; if (!this.isRecTrack && mat == "WD") sotd += " The group does not expect this document to become a W3C Recommendation."; sotd += " W3C maintains a public list of any patent disclosures " + "made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An " + "individual who has actual knowledge of a patent which the individual believes contains " + "Essential Claim(s) must disclose the " + "information in accordance with section " + "6 of the W3C Patent Policy.
"; if (this.addPatentNote) sotd += "" + this.addPatentNote + "
"; sotd += "As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, " + "and notes in this specification are non-normative. Everything else in this specification is " + "normative.
\nThe key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, " + "and OPTIONAL in this specification are to be interpreted as described in [[!RFC2119]].
\n"; sn.copyChildren(dummy, confo); }, informative: function () { var secs = document.querySelectorAll("section.informative"); for (var i = 0; i < secs.length; i++) { var sec = secs[i]; var p = sn.element("p"); sn.element("em", {}, p, "This section is non-normative."); sec.insertBefore(p, sec.firstElementChild.nextSibling); } }, examples: function () { // reindent var exes = document.querySelectorAll("pre.example"); for (var i = 0; i < exes.length; i++) { var ex = exes[i]; var lines = ex.innerHTML.split("\n"); while (lines.length && /^\s*$/.test(lines[0])) lines.shift(); while (/^\s*$/.test(lines[lines.length - 1])) lines.pop(); var matches = /^(\s+)/.exec(lines[0]); if (matches) { var rep = new RegExp("^" + matches[1]); for (var j = 0; j < lines.length; j++) { lines[j] = lines[j].replace(rep, ""); } } ex.innerHTML = lines.join("\n"); } // highlight sh_highlightDocument(this.base + "js/lang/", ".min.js"); }, fixHeaders: function () { var secs = document.querySelectorAll("section > h1:first-child, section > h2:first-child, section > h3:first-child, section > h4:first-child, section > h5:first-child, section > h6:first-child"); for (var i = 0; i < secs.length; i++) { var sec = secs[i]; var depth = sn.findNodes("ancestor::x:section|ancestor::section", sec).length + 1; if (depth > 6) depth = 6; var h = "h" + depth; if (sec.localName.toLowerCase() != h) sn.renameEl(sec, h); } }, makeTOC: function () { var ul = this.makeTOCAtLevel(document.body, [0], 1); if (!ul) return; var sec = sn.element("section", { id: "toc" }); sn.element("h2", { "class": "introductory" }, sec, "Table of Contents"); sec.appendChild(ul); document.body.insertBefore(sec, document.getElementById("sotd").nextSibling); }, appendixMode: false, lastNonAppendix: 0, alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", makeTOCAtLevel: function (parent, current, level) { var xpath = this.tocIntroductory ? "./x:section|./section" : "./x:section[not(@class='introductory')]|./section[not(@class='introductory')]" var secs = sn.findNodes(xpath, parent); if (secs.length == 0) return null; var ul = sn.element("ul", { "class": "toc" }); for (var i = 0; i < secs.length; i++) { var sec = secs[i], isIntro = sn.hasClass(sec, "introductory"); if (!sec.childNodes.length) continue; var h = sec.firstElementChild; var ln = h.localName.toLowerCase(); if (ln != "h2" && ln != "h3" && ln != "h4" && ln != "h5" && ln != "h6") continue; var title = h.textContent; var hKids = sn.documentFragment(); for (var j = 0; j < h.childNodes.length; j++) { var node = h.childNodes[j].cloneNode(true); hKids.appendChild(node); if (node.nodeType == Node.ELEMENT_NODE) { var ln = node.localName.toLowerCase(); if (ln == "a") { node = sn.renameEl(node, "span"); var cl = node.getAttribute("class"); if (!cl) cl = ""; else cl = " " + cl; // node.setAttribute("class", "formerLink" + cl); sn.addClass(node, "formerLink" + cl); node.removeAttribute("href"); } else if (ln == "dfn") { node = sn.renameEl(node, "span"); node.removeAttribute("id"); } } } var id = sn.makeID(sec, null, title); if (!isIntro) current[current.length-1]++; var secnos = current.slice(); if (sn.hasClass(sec, "appendix") && current.length == 1 && !this.appendixMode) { this.lastNonAppendix = current[0]; this.appendixMode = true; } if (this.appendixMode) secnos[0] = this.alphabet.charAt(current[0] - this.lastNonAppendix); var secno = secnos.join("."); if (!/\./.test(secno)) secno = secno + "."; var df = sn.documentFragment(); if (!isIntro) sn.element("span", { "class": "secno" }, df, secno + " "); // sn.text(" ", df); var df2 = df.cloneNode(true); h.insertBefore(df, h.firstChild); // if this is a top level item, insert // an OddPage comment so html2ps will correctly // paginate the output if (/\.$/.test(secno)) { var com = document.createComment('OddPage') ; h.parentNode.insertBefore(com, h) ; } // sn.text(title, df2); df2.appendChild(hKids); var a = sn.element("a", { href: "#" + id, 'class' : 'tocxref' }, null, [df2]); var item = sn.element("li", { "class":"tocline" }, ul, [a]); if (this.maxTocLevel && level >= this.maxTocLevel) continue; current.push(0); var sub = this.makeTOCAtLevel(sec, current, level + 1); if (sub) item.appendChild(sub) ; current.pop(); } return ul; }, idHeaders: function () { var heads = document.querySelectorAll("h2, h3, h4, h5, h6"); for (var i = 0; i < heads.length; i++) { var h = heads[i]; if (h.hasAttribute("id")) continue; var par = h.parentNode; if (par.localName.toLowerCase() == "section" && par.hasAttribute("id") && !h.previousElementSibling) continue; sn.makeID(h, null); } }, // --- INLINE PROCESSING ---------------------------------------------------------------------------------- inlines: function () { document.normalize(); // PRE-PROCESSING var norms = {}, informs = {}, abbrMap = {}, acroMap = {}, badrefs = {}; var badrefcount = 0; var abbrs = document.querySelectorAll("abbr[title]"); for (var i = 0; i < abbrs.length; i++) abbrMap[abbrs[i].textContent] = abbrs[i].getAttribute("title"); var acros = document.querySelectorAll("acronym[title]"); for (var i = 0; i < acros.length; i++) acroMap[acros[i].textContent] = acros[i].getAttribute("title"); var aKeys = []; for (var k in abbrMap) aKeys.push(k); for (var k in acroMap) aKeys.push(k); aKeys.sort(function (a, b) { if (b.length < a.length) return -1; if (a.length < b.length) return 1; return 0; }); var abbrRx = aKeys.length ? "|(?:\\b" + aKeys.join("\\b)|(?:\\b") + "\\b)" : ""; var rx = new RegExp("(\\bMUST(?:\\s+NOT)?\\b|\\bSHOULD(?:\\s+NOT)?\\b|\\bSHALL(?:\\s+NOT)?\\b|" + "\\bMAY\\b|\\b(?:NOT\\s+)?REQUIRED\\b|\\b(?:NOT\\s+)?RECOMMENDED\\b|\\bOPTIONAL\\b|" + "(?:\\[\\[(?:!)?[A-Za-z0-9-]+\\]\\])" + abbrRx + ")"); // PROCESSING var txts = sn.findNodes(".//text()", document.body); for (var i = 0; i < txts.length; i++) { var txt = txts[i]; var subtxt = txt.data.split(rx); var df = sn.documentFragment(); while (subtxt.length) { var t = subtxt.shift(); var matched = null; if (subtxt.length) matched = subtxt.shift(); sn.text(t, df); if (matched) { // RFC 2129 if (/MUST(?:\s+NOT)?|SHOULD(?:\s+NOT)?|SHALL(?:\s+NOT)?|MAY|(?:NOT\s+)?REQUIRED|(?:NOT\s+)?RECOMMENDED|OPTIONAL/.test(matched)) { matched = matched.toLowerCase(); sn.element("em", { "class": "rfc2119", title: matched }, df, matched); } // BIBREF else if (/^\[\[/.test(matched)) { var ref = matched; ref = ref.replace(/^\[\[/, ""); ref = ref.replace(/]]$/, ""); var norm = false; if (ref.indexOf("!") == 0) { norm = true; ref = ref.replace(/^!/, ""); } if (berjon.biblio[ref]) { if (norm) norms[ref] = true; else informs[ref] = true; sn.text("[", df); // embed a cite with an a inside of it var el = sn.element("cite", {} , df); sn.element("a", { "class": "bibref", rel: "biblioentry", href: "#bib-" + ref }, el, ref); sn.text("]", df); } else { badrefcount++; if ( badrefs[ref] ) { badrefs[ref] = badrefs[ref] + 1 ; } else { badrefs[ref] = 1 ; } } } // ABBR else if (abbrMap[matched]) { if (sn.findNodes("ancestor::abbr", txt)) sn.text(matched, df); else sn.element("abbr", { title: abbrMap[matched] }, df, matched); } // ACRO else if (acroMap[matched]) { if (sn.findNodes("ancestor::acronym", txt)) sn.text(matched, df); else sn.element("acronym", { title: acroMap[matched] }, df, matched); // sn.element("acronym", { title: acroMap[matched] }, df, matched); } // FAIL else { error("Found token '" + matched + "' but it does not correspond to anything"); } } } txt.parentNode.replaceChild(df, txt); } // POST-PROCESSING // bibref if(badrefcount > 0) { error("Got " + badrefcount + " tokens looking like a reference, not in biblio DB: "); for (var item in badrefs) { error("Bad ref: " + item + ", count = " + badrefs[item]); } } var del = []; for (var k in informs) { if (norms[k]) del.push(k); } for (var i = 0; i < del.length; i++) delete informs[del[i]]; var refsec = sn.element("section", { id: "references", "class": "appendix" }, document.body); sn.element("h2", {}, refsec, "References"); if (this.refNote) { var refnote = sn.element("p", {}, refsec); refnote.innerHTML= this.refNote; } var types = ["Normative", "Informative"]; for (var i = 0; i < types.length; i++) { var type = types[i]; var refMap = (type == "Normative") ? norms : informs; var sec = sn.element("section", {}, refsec); sn.makeID(sec, null, type + " references"); sn.element("h3", {}, sec, type + " references"); var refs = []; for (var k in refMap) refs.push(k); refs.sort(); if (refs.length) { var dl = sn.element("dl", { "class": "bibliography" }, sec); if (this.doRDFa) { dl.setAttribute('about', '') ; } for (var j = 0; j < refs.length; j++) { var ref = refs[j]; sn.element("dt", { id: "bib-" + ref }, dl, "[" + ref + "]"); var dd = sn.element("dd", {}, dl); if (this.doRDFa) { if (type == 'Normative') { dd.setAttribute('rel','dcterms:requires'); } else { dd.setAttribute('rel','dcterms:references'); } } if (berjon.biblio[ref]) dd.innerHTML = berjon.biblio[ref] + "\n"; } } else { sn.element("p", {}, sec, "No " + type.toLowerCase() + " references."); } } }, dfn: function () { document.normalize(); var dfnMap = {}; var dfns = document.querySelectorAll("dfn"); for (var i = 0; i < dfns.length; i++) { var dfn = dfns[i]; var title = this._getDfnTitle(dfn); dfnMap[title.toLowerCase()] = sn.makeID(dfn, "dfn", title); } var ants = document.querySelectorAll("a:not([href])"); for (var i = 0; i < ants.length; i++) { var ant = ants[i]; // if (ant.getAttribute("class") == "externalDFN") continue; if (sn.hasClass(ant, "externalDFN")) continue; var title = this._getDfnTitle(ant).toLowerCase(); if (dfnMap[title] && !(dfnMap[title] instanceof Function)) { ant.setAttribute("href", "#" + dfnMap[title]); // ant.setAttribute("class", "internalDFN"); sn.addClass(ant, "internalDFN"); } else { // we want to use these for other links too // error("No definition for title: " + title); } } }, doBestPractices: function () { this.practiceNum = 1; var spans = document.querySelectorAll("span.practicelab"); var contents = "" + name + "
";
}
}
},
// --- CLEANUP --------------------------------------------------------------------------------------------
removeRespec: function () {
var rs = document.querySelectorAll(".remove");
for (var i = 0; i < rs.length; i++) rs[i].parentNode.removeChild(rs[i]);
},
unHTML5: function () {
var secs = document.querySelectorAll("section");
for (var i = 0; i < secs.length; i++) {
var sec = secs[i];
var div = sn.renameEl(sec, "div");
// div.setAttribute("class", "section"); // XXX that kills previous class, may not be a problem
sn.addClass(div, "section");
}
},
// --- HELPERS --------------------------------------------------------------------------------------------
_insertCSS: function (css, inlined) {
// if (document.createStyleSheet) return document.createStyleSheet(css);
if (inlined) {
try {
// this is synchronous because order of the CSS matters (if though PubRules doesn't detect this
// correctly :-) If it's slow, turn off inlineCSS during development
var xhr = new XMLHttpRequest();
xhr.open("GET", css, false);
// xhr.onreadystatechange = function () {
// if (this.readyState == 4) {
// if (this.status == 200) {
// sn.element("style", { type: "text/css" }, document.documentElement.firstElementChild, this.responseText);
// }
// else {
// error("There appear to have been a problem fetching the style sheet; status=" + this.status);
// }
// }
// };
xhr.send(null);
if (xhr.status == 200) {
sn.element("style", { type: "text/css" }, document.documentElement.firstElementChild, xhr.responseText);
}
else {
error("There appears to have been a problem fetching the style sheet; status=" + xhr.status);
}
}
catch (e) {
// warning("There was an error with the request, probably that you're working from disk.");
this._insertCSS(css, false);
}
}
else {
sn.element("link", {
href: css,
rel: "stylesheet",
type: "text/css",
charset: "utf-8"
}, document.documentElement.firstElementChild);
}
},
_readFile: function (URI) {
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", URI, false);
xhr.send(null);
if (xhr.status == 200) {
return xhr.responseText ;
} else {
error("There appears to have been a problem fetching the file " + URI + "; status=" + xhr.status);
}
}
catch (e) {
warning("There was an error with the request to load " + URI + ", probably that you're working from disk.");
}
},
_humanMonths: ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"],
_humanDate: function (date) {
return this._lead0(date.getDate()) + " " + this._humanMonths[date.getMonth()] + " " + date.getFullYear();
},
_concatDate: function (date, sep) {
if (!sep) sep = "";
return "" + date.getFullYear() + sep + this._lead0(date.getMonth() + 1) + sep + this._lead0(date.getDate());
},
_ISODate: function (date) {
return "" + date.getUTCFullYear() +'-'+ this._lead0(date.getUTCMonth() + 1)+'-' + this._lead0(date.getUTCDate()) +'T'+this._lead0(date.getUTCHours())+':'+this._lead0(date.getUTCMinutes()) +":"+this._lead0(date.getUTCSeconds())+'+0000';
},
_parseDate: function (str) {
return new Date(str.substr(0, 4), (str.substr(5, 2) - 1), str.substr(8, 2));
},
_parseLastModified: function (str) {
if (!str) return new Date();
return new Date(Date.parse(str));
// return new Date(str.substr(6, 4), (str.substr(0, 2) - 1), str.substr(3, 2));
},
_lead0: function (str) {
str = "" + str;
return (str.length == 1) ? "0" + str : str;
},
_getDfnTitle: function (dfn) {
var title;
if (dfn.hasAttribute("title")) title = dfn.getAttribute("title");
else if (dfn.childNodes.length == 1 && dfn.firstChild.nodeType == Node.ELEMENT_NODE &&
(dfn.firstChild.localName.toLowerCase() == "abbr" || dfn.firstChild.localName.toLowerCase() == "acronym") &&
dfn.firstChild.hasAttribute("title")) title = dfn.firstChild.getAttribute("title");
else title = dfn.textContent;
title = this._norm(title);
return title;
},
_norm: function (str) {
str = str.replace(/^\s+/, "").replace(/\s+$/, "");
return str.split(/\s+/).join(" ");
},
_esc: function (s) {
s = s.replace(/&/g,'&');
s = s.replace(/>/g,'>');
s = s.replace(/"/g,'"');
s = s.replace(/ -1) {
isOptional = true;
pkw.splice(idx, 1);
p.datatype = pkw.join(" ");
}
p.optional = isOptional;
}
return mem;
}
// NOTHING MATCHED
error("Expected interface member, got: " + str);
},
parseExtendedAttributes: function (str, obj) {
str = str.replace(/^\s*\[([^\]]+)\]\s+/, function (x, m1) { obj.extendedAttributes = m1; return ""; });
return str;
},
makeMarkup: function () {
var df = sn.documentFragment();
var pre = sn.element("pre", { "class": "idl" }, df);
pre.innerHTML = this.writeAsWebIDL(this.parent, 0);
df.appendChild(this.writeAsHTML(this.parent));
return df;
},
writeAsHTML: function (obj) {
if (obj.type == "module") {
if (obj.id == "outermost") {
if (obj.children.length > 1) error("We currently only support one structural level per IDL fragment");
return this.writeAsHTML(obj.children[0]);
}
else {
warning("No HTML can be generated for module definitions.");
return sn.element("span");
}
}
else if (obj.type == "typedef") {
var cnt;
if (obj.description && obj.description.childNodes.length) {
cnt = [obj.description];
}
else {
// yuck -- should use a single model...
var tdt = sn.element("span", { "class": "idlTypedefType" }, null);
tdt.innerHTML = this.writeDatatype(obj.datatype);
cnt = [ sn.text("Throughout this specification, the identifier "),
sn.element("span", { "class": "idlTypedefID" }, null, obj.id),
sn.text(" is used to refer to the "),
sn.text(obj.array ? "array of " : ""),
tdt,
sn.text(obj.nullable ? " (nullable)" : ""),
sn.text(" type.")];
}
return sn.element("div", { "class": "idlTypedefDesc" }, null, cnt);
}
else if (obj.type == "implements") {
var cnt;
if (obj.description && obj.description.childNodes.length) {
cnt = [obj.description];
}
else {
cnt = [ sn.text("All instances of the "),
sn.element("code", {}, null, [sn.element("a", {}, null, obj.id)]),
sn.text(" type are defined to also implement the "),
sn.element("a", {}, null, obj.datatype),
sn.text(" interface.")];
cnt = [sn.element("p", {}, null, cnt)];
}
return sn.element("div", { "class": "idlImplementsDesc" }, null, cnt);
}
else if (obj.type == "exception") {
var df = sn.documentFragment();
var curLnk = "widl-" + obj.refId + "-";
var types = ["field", "constant"];
for (var i = 0; i < types.length; i++) {
var type = types[i];
var things = obj.children.filter(function (it) { return it.type == type });
if (things.length == 0) continue;
if (!this.noIDLSorting) {
things.sort(function (a, b) {
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
});
}
var sec = sn.element("section", {}, df);
var secTitle = type;
secTitle = secTitle.substr(0, 1).toUpperCase() + secTitle.substr(1) + "s";
sn.element("h2", {}, sec, secTitle);
var dl = sn.element("dl", { "class": type + "s" }, sec);
for (var j = 0; j < things.length; j++) {
var it = things[j];
var dt = sn.element("dt", { id: curLnk + it.refId }, dl);
sn.element("code", {}, dt, it.id);
var desc = sn.element("dd", {}, dl, [it.description]);
if (type == "field") {
sn.text(" of type ", dt);
if (it.array) sn.text("array of ", dt);
var span = sn.element("span", { "class": "idlFieldType" }, dt);
var matched = /^sequence<(.+)>$/.exec(it.datatype);
if (matched) {
sn.text("sequence<", span);
sn.element("a", {}, span, matched[1]);
sn.text(">", span);
}
else {
sn.element("a", {}, span, it.datatype);
}
if (it.nullable) sn.text(", nullable", dt);
}
else if (type == "constant") {
sn.text(" of type ", dt);
sn.element("span", { "class": "idlConstType" }, dt, [sn.element("a", {}, null, it.datatype)]);
if (it.nullable) sn.text(", nullable", dt);
}
}
}
return df;
}
else if (obj.type == "dictionary") {
var df = sn.documentFragment();
var curLnk = "widl-" + obj.refId + "-";
var things = obj.children;
if (things.length == 0) return df;
if (!this.noIDLSorting) {
things.sort(function (a, b) {
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
});
}
var sec = sn.element("section", {}, df);
cnt = [sn.text("Dictionary "),
sn.element("a", { "class": "idlType" }, null, obj.id),
sn.text(" Members")];
sn.element("h2", {}, sec, cnt);
var dl = sn.element("dl", { "class": "dictionary-members" }, sec);
for (var j = 0; j < things.length; j++) {
var it = things[j];
var dt = sn.element("dt", { id: curLnk + it.refId }, dl);
sn.element("code", {}, dt, it.id);
var desc = sn.element("dd", {}, dl, [it.description]);
sn.text(" of type ", dt);
if (it.array) sn.text("array of ", dt);
var span = sn.element("span", { "class": "idlMemberType" }, dt);
var matched = /^sequence<(.+)>$/.exec(it.datatype);
if (matched) {
sn.text("sequence<", span);
sn.element("a", {}, span, matched[1]);
sn.text(">", span);
}
else {
sn.element("a", {}, span, it.datatype);
}
if (it.nullable) sn.text(", nullable", dt);
if (it.defaultValue) {
sn.text(", defaulting to ", dt);
sn.element("code", {}, dt, [sn.text(it.defaultValue)]);
}
}
return df;
}
else if (obj.type == "interface") {
var df = sn.documentFragment();
var curLnk = "widl-" + obj.refId + "-";
var types = ["attribute", "method", "constant"];
for (var i = 0; i < types.length; i++) {
var type = types[i];
var things = obj.children.filter(function (it) { return it.type == type });
if (things.length == 0) continue;
if (!this.noIDLSorting) {
things.sort(function (a, b) {
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
});
}
var sec = sn.element("section", {}, df);
var secTitle = type;
secTitle = secTitle.substr(0, 1).toUpperCase() + secTitle.substr(1) + "s";
sn.element("h2", {}, sec, secTitle);
var dl = sn.element("dl", { "class": type + "s" }, sec);
for (var j = 0; j < things.length; j++) {
var it = things[j];
var id = (type == "method") ? this.makeMethodID(curLnk, it) : sn.idThatDoesNotExist(curLnk + it.refId);
var dt = sn.element("dt", { id: id }, dl);
sn.element("code", {}, dt, it.id);
var desc = sn.element("dd", {}, dl, [it.description]);
if (type == "method") {
if (it.params.length) {
var table = sn.element("table", { "class": "parameters" }, desc);
var tr = sn.element("tr", {}, table);
["Parameter", "Type", "Nullable", "Optional", "Description"].forEach(function (tit) { sn.element("th", {}, tr, tit); });
for (var k = 0; k < it.params.length; k++) {
var prm = it.params[k];
var tr = sn.element("tr", {}, table);
sn.element("td", { "class": "prmName" }, tr, prm.id);
var tyTD = sn.element("td", { "class": "prmType" }, tr);
var matched = /^sequence<(.+)>$/.exec(prm.datatype);
if (matched) {
sn.element("code", {}, tyTD, [ sn.text("sequence<"),
sn.element("a", {}, null, matched[1]),
sn.text(">")]);
}
else {
var cnt = [sn.element("a", {}, null, prm.datatype)];
if (prm.array) cnt.push(sn.text("[]"));
sn.element("code", {}, tyTD, cnt);
}
if (prm.nullable) sn.element("td", { "class": "prmNullTrue" }, tr, "\u2714");
else sn.element("td", { "class": "prmNullFalse" }, tr, "\u2718");
if (prm.optional) sn.element("td", { "class": "prmOptTrue" }, tr, "\u2714");
else sn.element("td", { "class": "prmOptFalse" }, tr, "\u2718");
var cnt = prm.description ? [prm.description] : "";
sn.element("td", { "class": "prmDesc" }, tr, cnt);
}
}
else {
sn.element("div", {}, desc, [sn.element("em", {}, null, "No parameters.")]);
}
if (it.raises.length) {
var table = sn.element("table", { "class": "exceptions" }, desc);
var tr = sn.element("tr", {}, table);
["Exception", "Description"].forEach(function (tit) { sn.element("th", {}, tr, tit); });
for (var k = 0; k < it.raises.length; k++) {
var exc = it.raises[k];
var tr = sn.element("tr", {}, table);
sn.element("td", { "class": "excName" }, tr, [sn.element("a", {}, null, exc.id)]);
var dtd = sn.element("td", { "class": "excDesc" }, tr);
if (exc.type == "simple") {
dtd.appendChild(exc.description);
}
else {
var ctab = sn.element("table", { "class": "exceptionCodes" }, dtd );
for (var m = 0; m < exc.description.length; m++) {
var cd = exc.description[m];
var tr = sn.element("tr", {}, ctab);
sn.element("td", { "class": "excCodeName" }, tr, [sn.element("code", {}, null, cd.id)]);
sn.element("td", { "class": "excCodeDesc" }, tr, [cd.description]);
}
}
}
}
else {
sn.element("div", {}, desc, [sn.element("em", {}, null, "No exceptions.")]);
}
var reDiv = sn.element("div", {}, desc);
sn.element("em", {}, reDiv, "Return type: ");
var matched = /^sequence<(.+)>$/.exec(it.datatype);
if (matched) {
sn.element("code", {}, reDiv, [ sn.text("sequence<"),
sn.element("a", {}, null, matched[1]),
sn.text(">")]);
}
else {
var cnt = [sn.element("a", {}, null, it.datatype)];
if (it.array) cnt.push(sn.text("[]"));
sn.element("code", {}, reDiv, cnt);
}
if (it.nullable) sn.text(", nullable", reDiv);
}
else if (type == "attribute") {
sn.text(" of type ", dt);
if (it.array) sn.text("array of ", dt);
var span = sn.element("span", { "class": "idlAttrType" }, dt);
var matched = /^sequence<(.+)>$/.exec(it.datatype);
if (matched) {
sn.text("sequence<", span);
sn.element("a", {}, span, matched[1]);
sn.text(">", span);
}
else {
sn.element("a", {}, span, it.datatype);
}
if (it.readonly) sn.text(", readonly", dt);
if (it.nullable) sn.text(", nullable", dt);
if (it.raises.length) {
var table = sn.element("table", { "class": "exceptions" }, desc);
var tr = sn.element("tr", {}, table);
["Exception", "On Get", "On Set", "Description"].forEach(function (tit) { sn.element("th", {}, tr, tit); });
for (var k = 0; k < it.raises.length; k++) {
var exc = it.raises[k];
var tr = sn.element("tr", {}, table);
sn.element("td", { "class": "excName" }, tr, [sn.element("a", {}, null, exc.id)]);
["onGet", "onSet"].forEach(function (gs) {
if (exc[gs]) sn.element("td", { "class": "excGetSetTrue" }, tr, "\u2714");
else sn.element("td", { "class": "excGetSetFalse" }, tr, "\u2718");
});
var dtd = sn.element("td", { "class": "excDesc" }, tr);
if (exc.type == "simple") {
dtd.appendChild(exc.description);
}
else {
var ctab = sn.element("table", { "class": "exceptionCodes" }, dtd );
for (var m = 0; m < exc.description.length; m++) {
var cd = exc.description[m];
var tr = sn.element("tr", {}, ctab);
sn.element("td", { "class": "excCodeName" }, tr, [sn.element("code", {}, null, cd.id)]);
sn.element("td", { "class": "excCodeDesc" }, tr, [cd.description]);
}
}
}
}
else {
sn.element("div", {}, desc, [sn.element("em", {}, null, "No exceptions.")]);
}
}
else if (type == "constant") {
sn.text(" of type ", dt);
sn.element("span", { "class": "idlConstType" }, dt, [sn.element("a", {}, null, it.datatype)]);
if (it.nullable) sn.text(", nullable", dt);
}
}
}
if (typeof obj.merge !== "undefined" && obj.merge.length > 0) {
// hackish: delay the execution until the DOM has been initialized, then merge
setTimeout(function () {
for (var i = 0; i < obj.merge.length; i++) {
var idlInterface = document.querySelector("#idl-def-" + obj.refId),
idlDictionary = document.querySelector("#idl-def-" + obj.merge[i]);
idlDictionary.parentNode.parentNode.removeChild(idlDictionary.parentNode);
idlInterface.appendChild(document.createElement("br"));
idlInterface.appendChild(idlDictionary);
}
}, 0);
}
return df;
}
},
makeMethodID: function (cur, obj) {
var id = cur + obj.refId + "-" + obj.datatype + "-";
var params = [];
for (var i = 0, n = obj.params.length; i < n; i++) {
var prm = obj.params[i];
params.push(prm.datatype + (prm.array ? "Array" : "") + "-" + prm.id)
}
id += params.join("-");
return sn.sanitiseID(id);
// return sn.idThatDoesNotExist(id);
},
writeAsWebIDL: function (obj, indent) {
if (obj.type == "module") {
if (obj.id == "outermost") {
var str = "";
for (var i = 0; i < obj.children.length; i++) str += this.writeAsWebIDL(obj.children[i], indent);
return str;
}
else {
var str = "";
if (obj.extendedAttributes) str += this._idn(indent) + "[" + obj.extendedAttributes + "]\n";
str += this._idn(indent) + "module " + obj.id + " {\n";
for (var i = 0; i < obj.children.length; i++) str += this.writeAsWebIDL(obj.children[i], indent + 1);
str += this._idn(indent) + "};\n";
return str;
}
}
else if (obj.type == "typedef") {
var nullable = obj.nullable ? "?" : "";
var arr = obj.array ? "[]" : "";
return "typedef " +
this.writeDatatype(obj.datatype) +
"" + arr + nullable + " " + obj.id + ";";
}
else if (obj.type == "implements") {
return "" + obj.id + " implements " + obj.datatype + ";";
}
else if (obj.type == "interface") {
var str = "";
if (obj.extendedAttributes) str += this._idn(indent) + "[" + obj.extendedAttributes + "]\n";
str += this._idn(indent);
if (obj.partial) str += "partial ";
str += "interface " + obj.id + "";
if (obj.superclasses && obj.superclasses.length) str += " : " +
obj.superclasses.map(function (it) {
return "" + it + ""
})
.join(", ");
str += " {\n";
// we process attributes and methods in place
var maxAttr = 0, maxMeth = 0, maxConst = 0, hasRO = false;
obj.children.forEach(function (it, idx) {
var len = it.datatype.length;
if (it.nullable) len = len + 1;
if (it.array) len = len + 2;
if (it.type == "attribute") maxAttr = (len > maxAttr) ? len : maxAttr;
else if (it.type == "method") maxMeth = (len > maxMeth) ? len : maxMeth;
else if (it.type == "constant") maxConst = (len > maxConst) ? len : maxConst;
if (it.type == "attribute" && it.readonly) hasRO = true;
});
var curLnk = "widl-" + obj.refId + "-";
for (var i = 0; i < obj.children.length; i++) {
var ch = obj.children[i];
if (ch.type == "attribute") str += this.writeAttribute(ch, maxAttr, indent + 1, curLnk, hasRO);
else if (ch.type == "method") str += this.writeMethod(ch, maxMeth, indent + 1, curLnk);
else if (ch.type == "constant") str += this.writeConst(ch, maxConst, indent + 1, curLnk);
}
str += this._idn(indent) + "};\n";
return str;
}
else if (obj.type == "exception") {
var str = "";
if (obj.extendedAttributes) str += this._idn(indent) + "[" + obj.extendedAttributes + "]\n";
str += this._idn(indent) + "exception " + obj.id + " {\n";
var maxAttr = 0, maxConst = 0, hasRO = false;
obj.children.forEach(function (it, idx) {
var len = it.datatype.length;
if (it.nullable) len = len + 1;
if (it.array) len = len + 2;
if (it.type == "field") maxAttr = (len > maxAttr) ? len : maxAttr;
else if (it.type == "constant") maxConst = (len > maxConst) ? len : maxConst;
});
var curLnk = "widl-" + obj.refId + "-";
for (var i = 0; i < obj.children.length; i++) {
var ch = obj.children[i];
if (ch.type == "field") str += this.writeField(ch, maxAttr, indent + 1, curLnk);
else if (ch.type == "constant") str += this.writeConst(ch, maxConst, indent + 1, curLnk);
}
str += this._idn(indent) + "};\n";
return str;
}
else if (obj.type == "dictionary") {
var str = "";
if (obj.extendedAttributes) str += this._idn(indent) + "[" + obj.extendedAttributes + "]\n";
str += this._idn(indent) + "dictionary " + obj.id + "";
if (obj.superclasses && obj.superclasses.length) str += " : " +
obj.superclasses.map(function (it) {
return "" + it + ""
})
.join(", ");
str += " {\n";
var max = 0;
obj.children.forEach(function (it, idx) {
var len = it.datatype.length;
if (it.nullable) len = len + 1;
if (it.array) len = len + 2;
max = (len > max) ? len : max;
});
var curLnk = "widl-" + obj.refId + "-";
for (var i = 0; i < obj.children.length; i++) {
var ch = obj.children[i];
str += this.writeMember(ch, max, indent + 1, curLnk);
}
str += this._idn(indent) + "};\n";
return str;
}
},
writeField: function (attr, max, indent, curLnk) {
var str = "";
if (attr.extendedAttributes) str += this._idn(indent) + "[" + attr.extendedAttributes + "]\n";
str += this._idn(indent);
var pad = max - attr.datatype.length;
if (attr.nullable) pad = pad - 1;
if (attr.array) pad = pad - 2;
var nullable = attr.nullable ? "?" : "";
var arr = attr.array ? "[]" : "";
str += "" + this.writeDatatype(attr.datatype) + arr + nullable + " ";
for (var i = 0; i < pad; i++) str += " ";
str += "" + attr.id + "";
str += ";\n";
return str;
},
writeAttribute: function (attr, max, indent, curLnk, hasRO) {
var sets = [], gets = [];
if (attr.raises.length) {
for (var i = 0; i < attr.raises.length; i++) {
var exc = attr.raises[i];
if (exc.onGet) gets.push(exc);
if (exc.onSet) sets.push(exc);
}
}
var str = "";
if (attr.extendedAttributes) str += this._idn(indent) + "[" + attr.extendedAttributes + "]\n";
str += this._idn(indent);
if (hasRO) {
if (attr.readonly) str += "readonly ";
else str += " ";
}
str += "attribute ";
var pad = max - attr.datatype.length;
if (attr.nullable) pad = pad - 1;
if (attr.array) pad = pad - 2;
var nullable = attr.nullable ? "?" : "";
var arr = attr.array ? "[]" : "";
str += "" + this.writeDatatype(attr.datatype) + arr + nullable + " ";
for (var i = 0; i < pad; i++) str += " ";
str += "" + attr.id + "";
if (gets.length) {
str += " getraises (" +
gets.map(function (it) { return "" + it.id + ""; }).join(", ") +
")";
}
if (sets.length) {
str += " setraises (" +
sets.map(function (it) { return "" + it.id + ""; }).join(", ") +
")";
}
str += ";\n";
return str;
},
writeMethod: function (meth, max, indent, curLnk) {
var str = "";
if (meth.extendedAttributes) str += this._idn(indent) + "[" + meth.extendedAttributes + "]\n";
str += this._idn(indent);
var pad = max - meth.datatype.length;
if (meth.nullable) pad = pad - 1;
if (meth.array) pad = pad - 2;
var nullable = meth.nullable ? "?" : "";
var arr = meth.array ? "[]" : "";
str += "" + this.writeDatatype(meth.datatype) + arr + nullable + " ";
for (var i = 0; i < pad; i++) str += " ";
var id = this.makeMethodID(curLnk, meth);
// str += "" + meth.id + " (";
str += "" + meth.id + " (";
var obj = this;
str += meth.params.map(function (it) {
var nullable = it.nullable ? "?" : "";
var optional = it.optional ? "optional " : "";
var arr = it.array ? "[]" : "";
var inp = obj.noIDLIn ? "" : "in ";
var prm = "";
if (it.extendedAttributes) prm += "[" + it.extendedAttributes + "] ";
prm += inp + optional + "" + obj.writeDatatype(it.datatype) + arr + nullable + " " +
"" + it.id + "" +
"";
return prm;
})
.join(", ");
str += ")";
if (meth.raises.length) {
str += " raises ("
str += meth.raises.map(function (it) { return "" + it.id + ""; })
.join(", ");
str += ")";
}
str += ";\n";
return str;
},
writeConst: function (cons, max, indent, curLnk) {
var str = "";
str += this._idn(indent);
str += "const ";
var pad = max - cons.datatype.length;
if (cons.nullable) pad = pad - 1;
var nullable = cons.nullable ? "?" : "";
str += "" + cons.datatype + "" + nullable + " ";
for (var i = 0; i < pad; i++) str += " ";
str += "" + cons.id + " = " +
"" + cons.value + ";\n";
return str;
},
writeMember: function (memb, max, indent, curLnk) {
var str = "";
str += this._idn(indent);
var pad = max - memb.datatype.length;
if (memb.nullable) pad = pad - 1;
var nullable = memb.nullable ? "?" : "";
str += "" + memb.datatype + "" + nullable + " ";
for (var i = 0; i < pad; i++) str += " ";
str += "" + memb.id + "";
if (memb.defaultValue) str += " = " + memb.defaultValue + ""
str += ";\n";
return str;
},
writeDatatype: function (dt) {
var matched = /^sequence<(.+)>$/.exec(dt);
if (matched) {
return "sequence<" + matched[1] + ">";
}
else {
return "" + dt + "";
}
},
_idn: function (lvl) {
var str = "";
for (var i = 0; i < lvl; i++) str += " ";
return str;
},
// XXX make this generally available (refactoring)
_norm: function (str) {
str = str.replace(/^\s+/, "").replace(/\s+$/, "");
return str.split(/\s+/).join(" ");
},
_id: function (id) {
return id.replace(/[^a-zA-Z_-]/g, "");
}
};
// hackish, but who cares?
window.onload = function () {
// (new berjon.respec()).run();
(new berjon.respec()).loadAndRun();
};
function dbg (obj) {
var str = "";
for (var k in obj) str += k + "=" + obj[k] + "\n";
alert("DUMP\n" + str);
}
})();