// ------------------------------------------------------------------------------------------ // // 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 += "'; } } // 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 += "\n"; if (this.previousDiffURI) { str += "\n"; } else { str += "\n"; } str += '\n'; str += '

Please wait...

'; str += "\n"; var x = window.open() ; x.document.write(str) ; x.document.close() ; x.document.form.submit() ; }, toHTML: function () { var x = window.open(); x.document.write(this.toString()); x.document.close(); }, toHTMLSource: function () { var x = window.open(); x.document.write("
" + 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 += "" + name + "s:"; } else { header += "
" + name + ":
"; } for (var i = 0; i < people.length; i++) { var pers = people[i]; if (this.doRDFa) { header += ""; } else { header += "
"; } if (pers.url) { if (this.doRDFa) { header += "" + pers.name + ""; } else { header += ""+ pers.name + ""; } } else { header += "" + pers.name + ""; } if (pers.company) { header += ", "; if (pers.companyURL) { header += "" + pers.company + ""; } else { header += pers.company; } } if (pers.mailto) { header += " " + pers.mailto + " "; } if (pers.note) { header += " ( " + pers.note + " )"; } if (this.doRDFa) { header += "\n"; } header += "
\n"; } return header; }, makeTAGHeaders: function () { var base = "http://www.w3.org/2001/tag/doc/", latestVersion = base + this.shortName, thisVersion = latestVersion + "-" + this._concatDate(this.publishDate, "-"), header = "

" + "W3C"; header += "

" + this.title + "

"; if (this.subtitle) header += "

" + this.subtitle + "

"; header += "

" + this.status2text[this.specStatus] + " " + this._humanDate(this.publishDate) + "

"; header += "
This version:
" + thisVersion + "
\n" + "
Latest published version:
" + latestVersion + "
"; if (this.edDraftURI) { header += "
Latest editor's draft:
" + this.edDraftURI + "
"; } if (this.previousPublishDate) { var prevVersion = latestVersion + "-" + this._concatDate(this.previousPublishDate, "-"); header += "
Previous version:
" + prevVersion + "
"; } if(this.editors.length == 0) { header += "
" + "Editor" + ":
"; error("There must be at least one editor."); } header += this.showPeople("Editor", this.editors); header += this.showPeople("Author", this.authors); header += "

"; return header; }, makeNormalHeaders: function () { var mat = (this.status2maturity[this.specStatus]) ? this.status2maturity[this.specStatus] : this.specStatus; var thisVersion = "http://www.w3.org/TR/" + this.publishDate.getFullYear() + "/" + mat + "-" + this.shortName + "-" + this._concatDate(this.publishDate) + "/"; if (this.specStatus == "ED") thisVersion = this.edDraftURI; var latestVersion, prevVersion; if (this.previousPublishDate) { var pmat = (this.status2maturity[this.previousMaturity]) ? this.status2maturity[this.previousMaturity] : this.previousMaturity; if (!this.previousURI) { this.previousURI = "http://www.w3.org/TR/" + this.previousPublishDate.getFullYear() + "/" + pmat + "-" + this.shortName + "-" + this._concatDate(this.previousPublishDate) + "/"; } if (this.doRDFa) { prevVersion = "" + this.previousURI + ""; } else { prevVersion = "" + this.previousURI + ""; } // var latestURI = "http://www.w3.org/TR/" + this.shortName + "/"; // latestVersion = "" + latestURI + ""; } else { prevVersion = "none"; // latestVersion = "none"; } var latestURI = "http://www.w3.org/TR/" + this.shortName + "/"; latestVersion = "" + latestURI + ""; var header = "

"; if (this.specStatus != "unofficial") header += "W3C"; if (this.specStatus == 'XGR') header += "W3C Incubator Report"; if ( this.doRDFa ) { header += "

" + this.title + "

" ; if (this.subtitle) { header += "

" + this.subtitle + "

" ; } header += "

" + (this.specStatus == "unofficial" ? "" : "W3C ") + this.status2text[this.specStatus] + " " + this._humanDate(this.publishDate) + "

"; } else { header += "

" + this.title + "

" ; if (this.subtitle) { header += "

" + this.subtitle + "

" ; } header += "

" + (this.specStatus == "unofficial" ? "" : "W3C ") + this.status2text[this.specStatus] + " " + this._humanDate(this.publishDate) + "

"; } if (!this.isNoTrack) { header += "
This version:
" + thisVersion + "
" + "
Latest published version:
" + latestVersion + "
"; if (this.edDraftURI) { header += "
Latest editor's draft:
" + this.edDraftURI + "
"; } } if (this.testSuiteURI) { header += "
Test suite:
" + this.testSuiteURI + "
"; } if (this.implementationReportURI) { header += "
Implementation report:
" + this.implementationReportURI + "
"; } if (this.specStatus != "FPWD" && this.specStatus != "FPWD-NOTE" && !this.isNoTrack) { if (!this.prevED) { header += "
Previous version:
" + prevVersion + "
"; } else { header += "
Previous editor's draft:
" + prevED + "
"; } } if (this.prevRecShortname) { var prevRecURI = "http://www.w3.org/TR/" + this.prevRecShortname + "/"; header += "
Latest recommendation:
" + '' + prevRecURI + "
"; } if(this.editors.length == 0) { header += "
" + "Editor" + ":
"; error("There must be at least one editor."); } header += this.showPeople("Editor", this.editors); header += this.showPeople("Author", this.authors); header += "
"; if (this.errata) { 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 = ""; else if (this.overrideCopyright) copyright = this.overrideCopyright; else copyright = ""; header += copyright; } else { if (this.overrideCopyright) { header += this.overrideCopyright; } else { header += ""; } } header += "
"; return header; }, makeHeaders: function () { var header; if (this.specStatus === "finding" || this.specStatus === "draft-finding") header = this.makeTAGHeaders(); else header = this.makeNormalHeaders(); var tmp = sn.element("div"); tmp.innerHTML = header; document.body.insertBefore(tmp.firstChild, document.body.firstChild); }, makeAbstract: function () { var abs = document.getElementById("abstract"); if (!abs) error("Document must have one element with ID 'abstract'"); var h2 = sn.element("h2", {}, null, "Abstract"); abs.insertBefore(h2, abs.firstChild); sn.addClass(abs, "introductory"); }, makeSotD: function () { var sotd; var mat = (this.status2maturity[this.specStatus]) ? this.status2maturity[this.specStatus] : this.specStatus; var custom = document.getElementById("sotd"); if (this.specStatus == "unofficial") { sotd = "

Status of This Document

" + "

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 += "
"; } else if (this.specStatus === "finding" || this.specStatus === "draft-finding") { sotd = "

Status of This Document

"; if (custom) sotd += custom.innerHTML; else sotd += "

ReSpec does not support automated SotD generation for TAG findings, please specify one using a <section> element with ID=sotd.

"; sotd += "
"; } else if (this.isNoTrack) { var mc = (this.specStatus == "MO") ? " member-confidential" : ""; sotd = "

Status of This Document

" + "

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 += "
"; } else { var art = "a "; if (this.specStatus == "ED" || this.specStatus == "XGR" || this.specStatus == "IG-NOTE") art = "an "; sotd = "

Status of This Document

" + "

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 += "
"; } if (custom) custom.parentNode.removeChild(custom); var tmp = sn.element("div"); tmp.innerHTML = sotd; var abs = document.getElementById("abstract"); abs.parentNode.insertBefore(tmp.firstChild, abs.nextSibling); }, makeConformance: function () { var confo = document.getElementById("conformance"); if (!confo) return; var dummy = sn.element("div"); if (confo.childNodes.length > 0) sn.copyChildren(confo, dummy); sn.element("h2", {}, confo, "Conformance"); confo.innerHTML += "

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.

\n

The 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 = "

Best Practices Summary

    " // scan all the best practices to number them and add handle // at same time generate summary section contents if section // is provided in source, using links if possible // // probably not the most efficient here but only used for best // practices document for (var i = 0; i < spans.length; i++) { var span = spans[i]; var label = span.innerHTML; var ref = span.getAttribute("id"); var handle = "Best Practice " + this.practiceNum; var content = ": " + label; var item = handle + content; if(!ref) { contents += "
  • " + handle + content + "
  • "; } else { contents += "
  • " + handle + "" + content + "
  • "; } span.innerHTML = item; this.practiceNum++; } contents += "
"; var sec = document.getElementById("bp-summary"); if(!sec) { // alert("no bp-summary section"); return; } sec.innerHTML = contents; }, // // returnObjById: function( id ) // { // if (document.getElementById) // var returnVar = document.getElementById(id); // else if (document.all) // var returnVar = document.all[id]; // else if (document.layers) // var returnVar = document.layers[id]; // return returnVar; // }, makeSectionRefs: function () { var secrefs = document.querySelectorAll("a.sectionRef"); for (var i = 0; i < secrefs.length; i++) { var secref = secrefs[i]; // get the link href and section title var h = secref.getAttribute('href'); var id = h.substring(1); var sec = document.getElementById(id); var secno = "Not found"+ id; if(sec) { var span = sec.firstElementChild; if(span) { secno = span.textContent; } } title = "section " + secno; // create new a reference to section using section title secref.innerHTML = title; } }, // --- WEB IDL -------------------------------------------------------------------------------------------- webIDL: function () { var idls = document.querySelectorAll(".idl"); // should probably check that it's not inside one var infNames = []; for (var i = 0; i < idls.length; i++) { var idl = idls[i]; var w = new berjon.WebIDLProcessor({ noIDLSorting: this.noIDLSorting, noIDLIn: this.noIDLIn }); var inf = w.definition(idl); var df = w.makeMarkup(); idl.parentNode.replaceChild(df, idl); if (inf.type == "interface" || inf.type == "exception" || inf.type == "dictionary") infNames.push(inf.id); } document.normalize(); var ants = document.querySelectorAll("a:not([href])"); for (var i = 0; i < ants.length; i++) { var ant = ants[i]; if (sn.hasClass(ant, "externalDFN")) continue; var name = ant.textContent; if (infNames.indexOf(name) >= 0) { ant.setAttribute("href", "#idl-def-" + name); // ant.setAttribute("class", "idlType"); sn.addClass(ant, "idlType"); ant.innerHTML = "" + 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); } })();