1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * @extends {WebInspector.View}
9 WebInspector.DocumentationView = function()
11 WebInspector.View.call(this);
12 this.element.classList.add("documentation-view");
13 this.registerRequiredCSS("documentationView.css");
18 * @param {string} searchItem
20 WebInspector.DocumentationView.showDocumentationURL = function(url, searchItem)
22 if (!WebInspector.DocumentationView._view)
23 WebInspector.DocumentationView._view = new WebInspector.DocumentationView();
24 var view = WebInspector.DocumentationView._view;
25 view.element.removeChildren();
26 WebInspector.inspectorView.showCloseableViewInDrawer("documentation", WebInspector.UIString("Documentation"), view);
27 view.showDocumentation(url, searchItem);
30 WebInspector.DocumentationView._languageToMimeType = {
31 "javascript": "text/javascript",
35 WebInspector.DocumentationView.prototype = {
38 * @param {string} searchItem
40 showDocumentation: function(url, searchItem)
43 this._createEmptyPage();
47 .then(this._createArticle.bind(this, searchItem), this._createEmptyPage.bind(this))
48 .catch(this._createEmptyPage.bind(this));
52 * @param {string} searchItem
53 * @param {string} responseText
55 _createArticle: function(searchItem, responseText)
57 var json = JSON.parse(responseText);
58 var pages = json["query"]["pages"];
59 var wikiKeys = Object.keys(pages);
60 if (wikiKeys.length === 1 && wikiKeys[0] === "-1") {
61 this._createEmptyPage();
64 var wikiMarkupText = pages[wikiKeys[0]]["revisions"]["0"]["*"];
67 article = WebInspector.JSArticle.parse(wikiMarkupText);
69 console.error("Article could not be parsed. " + error.message);
72 this._createEmptyPage();
76 this.element.removeChildren();
77 var renderer = new WebInspector.DocumentationView.Renderer(article, searchItem);
78 this.element.appendChild(renderer.renderJSArticle());
81 _createEmptyPage: function()
83 this.element.removeChildren();
84 var emptyPage = this.element.createChild("div", "documentation-empty-page fill");
85 var pageTitle = emptyPage.createChild("div", "documentation-not-found");
86 pageTitle.textContent = WebInspector.UIString("No documentation found.");
87 emptyPage.createChild("div", "documentation-empty-page-align");
90 __proto__: WebInspector.View.prototype
95 * @param {!WebInspector.JSArticle} article
96 * @param {string} searchItem
98 WebInspector.DocumentationView.Renderer = function(article, searchItem)
100 this._searchItem = searchItem;
101 this._element = document.createElement("div");
102 this._article = article;
105 WebInspector.DocumentationView.Renderer.prototype = {
109 renderJSArticle: function()
111 this._element.appendChild(this._createPageTitle(this._article.pageTitle, this._searchItem));
112 var signatureElement = this._createSignatureSection(this._article.parameters, this._article.methods);
113 if (signatureElement)
114 this._element.appendChild(signatureElement);
116 var descriptionElement = this._element.createChild("div", "documentation-description");
117 var summarySection = this._article.summary ? this._renderBlock(this._article.summary) : null;
119 descriptionElement.appendChild(summarySection);
120 var parametersSection = this._createParametersSection(this._article.parameters);
121 if (parametersSection)
122 descriptionElement.appendChild(parametersSection);
124 var examplesSection = this._createExamplesSection(this._article.examples);
125 if (examplesSection) {
126 var examplesTitle = this._element.createChild("div", "documentation-title");
127 examplesTitle.textContent = WebInspector.UIString("Examples");
128 descriptionElement = this._element.createChild("div", "documentation-description");
129 descriptionElement.appendChild(examplesSection);
132 var remarksSection = this._article.remarks ? this._renderBlock(this._article.remarks) : null;
133 if (remarksSection) {
134 var remarksTitle = this._element.createChild("div", "documentation-title");
135 remarksTitle.textContent = WebInspector.UIString("Remarks");
136 descriptionElement = this._element.createChild("div", "documentation-description");
137 descriptionElement.appendChild(remarksSection);
139 return this._element;
143 * @param {string} titleText
144 * @param {string} searchItem
147 _createPageTitle: function(titleText, searchItem)
149 var pageTitle = document.createElementWithClass("div", "documentation-page-title");
151 pageTitle.textContent = titleText;
153 pageTitle.textContent = searchItem;
158 * @param {!Array.<!WebInspector.JSArticle.Parameter>} parameters
159 * @param {?WebInspector.JSArticle.Method} method
162 _createSignatureSection: function(parameters, method)
164 if (!parameters.length && !method)
166 var signature = document.createElementWithClass("div", "documentation-method-signature monospace");
167 if (method && method.returnValueName) {
168 var returnTypeElement = signature.createChild("span", "documentation-parameter-data-type-value");
169 returnTypeElement.textContent = method.returnValueName;
171 var methodName = signature.createChild("span", "documentation-method-name");
172 methodName.textContent = this._searchItem.split(".").peekLast() + "(";
173 for (var i = 0; i < parameters.length; ++i) {
175 signature.createTextChild(",")
176 var parameterType = signature.createChild("span", "documentation-parameter-data-type-value");
177 parameterType.textContent = parameters[i].dataType;
178 var parameterName = signature.createChild("span", "documentation-parameter-name");
179 parameterName.textContent = parameters[i].name;
182 signature.createTextChild(")");
187 * @param {!Array.<!WebInspector.JSArticle.Parameter>} parameters
190 _createParametersSection: function(parameters)
192 if (!parameters.length)
194 var table = document.createElementWithClass("table", "documentation-table");
195 var tableBody = table.createChild("tbody");
196 var headerRow = tableBody.createChild("tr", "documentation-table-row");
197 var tableHeader = headerRow.createChild("th", "documentation-table-header");
198 tableHeader.textContent = WebInspector.UIString("Parameters");
199 tableHeader.colSpan = 3;
200 for (var i = 0; i < parameters.length; ++i) {
201 var tableRow = tableBody.createChild("tr", "documentation-table-row");
202 var type = tableRow.createChild("td", "documentation-table-cell");
203 type.textContent = parameters[i].dataType;
204 var name = tableRow.createChild("td", "documentation-table-cell");
205 name.textContent = parameters[i].optional ? WebInspector.UIString("(optional)\n") : "";
206 name.textContent += parameters[i].name;
207 var description = tableRow.createChild("td", "documentation-table-cell");
208 if (parameters[i].description)
209 description.appendChild(this._renderBlock(/** @type {!WebInspector.WikiParser.Block} */(parameters[i].description)));
215 * @param {!Array.<!WebInspector.JSArticle.Example>} examples
217 _createExamplesSection: function(examples)
219 if (!examples.length)
222 var section = document.createElementWithClass("div", "documentation-section");
224 for (var i = 0; i < examples.length; ++i) {
225 var example = section.createChild("div", "documentation-example");
226 var exampleDescription = example.createChild("div", "documentation-example-description-section");
227 if (examples[i].description) {
228 var description = this._renderBlock(/** @type {!WebInspector.WikiParser.Block} */(examples[i].description));
229 description.classList.add("documentation-text");
230 exampleDescription.appendChild(description);
232 var code = example.createChild("div", "documentation-code source-code");
233 code.textContent = examples[i].code;
234 if (!examples[i].language)
236 var syntaxHighlighter = new WebInspector.DOMSyntaxHighlighter(WebInspector.DocumentationView._languageToMimeType[examples[i].language.toLowerCase()], true);
237 syntaxHighlighter.syntaxHighlightNode(code);
243 * @param {!WebInspector.WikiParser.ArticleElement} article
246 _renderBlock: function(article)
249 var elementTypes = WebInspector.WikiParser.ArticleElement.Type;
251 switch (article.type()) {
252 case elementTypes.Inline:
253 element = document.createElement("span");
255 case elementTypes.Link:
256 element = document.createElementWithClass("a", "documentation-link");
257 element.href = article.url();
258 if (!article.children().length)
259 element.textContent = article.url();
261 case elementTypes.Code:
262 element = document.createElementWithClass("span", "documentation-code-tag");
264 case elementTypes.CodeBlock:
265 element = document.createElementWithClass("pre", "documentation-code source-code");
266 element.textContent = article.code();
268 case elementTypes.PlainText:
269 element = document.createElement("span");
270 element.textContent = article.text();
271 if (article.isHighlighted())
272 element.classList.add("documentation-highlighted-text");
274 case elementTypes.Block:
275 element = document.createElement(article.hasBullet() ? "li" : "div");
276 if (!article.hasBullet())
277 element.classList.add("documentation-paragraph");
279 case elementTypes.Table:
280 return this._renderTable(/** @type {!WebInspector.WikiParser.Table} */(article));
282 throw new Error("Unknown ArticleElement type " + article.type());
285 if (article.type() === WebInspector.WikiParser.ArticleElement.Type.Block
286 || article.type() === WebInspector.WikiParser.ArticleElement.Type.Code
287 || article.type() === WebInspector.WikiParser.ArticleElement.Type.Inline) {
288 for (var i = 0; i < article.children().length; ++i) {
289 var child = this._renderBlock(article.children()[i]);
291 element.appendChild(child);
299 * @param {!WebInspector.WikiParser.Table} table
302 _renderTable: function(table)
304 var tableElement = document.createElementWithClass("table", "documentation-table");
305 var tableBody = tableElement.createChild("tbody");
306 var headerRow = tableBody.createChild("tr", "documentation-table-row");
307 for (var i = 0; i < table.columnNames().length; ++i) {
308 var tableHeader = headerRow.createChild("th", "documentation-table-header");
309 tableHeader.appendChild(this._renderBlock(table.columnNames()[i]));
311 for (var i = 0; i < table.rows().length; ++i) {
312 var tableRow = tableBody.createChild("tr", "documentation-table-row");
313 var row = table.rows()[i];
314 for (var j = 0; j < row.length; ++j) {
315 var cell = tableRow.createChild("td", "documentation-table-cell");
316 cell.appendChild(this._renderBlock(row[j]));
326 * @implements {WebInspector.ContextMenu.Provider}
328 WebInspector.DocumentationView.ContextMenuProvider = function()
332 WebInspector.DocumentationView.ContextMenuProvider.prototype = {
334 * @param {!Event} event
335 * @param {!WebInspector.ContextMenu} contextMenu
336 * @param {!Object} target
338 appendApplicableItems: function(event, contextMenu, target)
340 if (!(target instanceof WebInspector.CodeMirrorTextEditor))
342 WebInspector.DocumentationCatalog.instance().startLoadingIfNeeded();
343 if (WebInspector.DocumentationCatalog.instance().isLoading()) {
344 var itemName = WebInspector.useLowerCaseMenuTitles() ? "Loading documentation..." : "Loading Documentation...";
345 contextMenu.appendItem(itemName, function() {}, true);
348 var textEditor = /** @type {!WebInspector.CodeMirrorTextEditor} */ (target);
349 var descriptors = this._determineDescriptors(textEditor);
350 if (!descriptors.length)
352 if (descriptors.length === 1) {
353 var formatString = WebInspector.useLowerCaseMenuTitles() ? "Show documentation for %s.%s" : "Show Documentation for %s.%s";
354 var methodName = String.sprintf("%s.%s", descriptors[0].name(), descriptors[0].searchItem());
355 contextMenu.appendItem(WebInspector.UIString(formatString, descriptors[0].name(), descriptors[0].searchItem()), WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[0].url(), methodName));
358 var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show documentation for..." : "Show Documentation for..."));
359 for (var i = 0; i < descriptors.length; ++i) {
360 var methodName = String.sprintf("%s.%s", descriptors[i].name(), descriptors[i].searchItem());
361 subMenuItem.appendItem(methodName, WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[i].url(), methodName));
366 * @param {!WebInspector.CodeMirrorTextEditor} textEditor
367 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
369 _determineDescriptors: function(textEditor)
371 var catalog = WebInspector.DocumentationCatalog.instance();
372 var textSelection = textEditor.selection().normalize();
373 var previousTokenText = findPreviousToken(textSelection);
375 if (!textSelection.isEmpty()) {
376 if (textSelection.startLine !== textSelection.endLine)
378 return computeDescriptors(textSelection);
381 var descriptors = computeDescriptors(getTokenRangeByColumn(textSelection.startColumn));
382 if (descriptors.length)
385 return computeDescriptors(getTokenRangeByColumn(textSelection.startColumn - 1));
388 * @param {number} column
389 * @return {?WebInspector.TextRange}
391 function getTokenRangeByColumn(column)
393 var token = textEditor.tokenAtTextPosition(textSelection.startLine, column);
396 return new WebInspector.TextRange(textSelection.startLine, token.startColumn, textSelection.startLine, token.endColumn);
400 * @param {?WebInspector.TextRange} textRange
401 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
403 function computeDescriptors(textRange)
407 var propertyName = textEditor.copyRange(textRange);
408 var descriptors = catalog.itemDescriptors(propertyName);
409 if (descriptors.length)
411 if (propertyName.toUpperCase() !== propertyName || !previousTokenText || !window[previousTokenText] || !window[previousTokenText][propertyName])
413 return catalog.constantDescriptors(previousTokenText);
417 * @param {!WebInspector.TextRange} textRange
420 function findPreviousToken(textRange)
422 var line = textEditor.line(textRange.startLine);
423 if (textRange.startColumn < 3 || line[textRange.startColumn - 1] !== ".")
425 var token = textEditor.tokenAtTextPosition(textRange.startLine, textRange.startColumn - 2);
426 return token ? line.substring(token.startColumn, token.endColumn) : null;