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("documentation/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))
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 = 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 = 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 = 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 = 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 = 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 = createElement("span");
255 case elementTypes.Link:
256 element = WebInspector.createExternalAnchor(article.url(), article.children().length ? "" : article.url());
258 case elementTypes.Code:
259 element = createElementWithClass("span", "documentation-code-tag");
261 case elementTypes.CodeBlock:
262 element = createElementWithClass("pre", "documentation-code source-code");
263 element.textContent = article.code();
265 case elementTypes.PlainText:
266 element = createElement("span");
267 element.textContent = article.text();
268 if (article.isHighlighted())
269 element.classList.add("documentation-highlighted-text");
271 case elementTypes.Block:
272 element = createElement(article.hasBullet() ? "li" : "div");
273 if (!article.hasBullet())
274 element.classList.add("documentation-paragraph");
276 case elementTypes.Table:
277 return this._renderTable(/** @type {!WebInspector.WikiParser.Table} */(article));
279 throw new Error("Unknown ArticleElement type " + article.type());
282 if (article.type() === WebInspector.WikiParser.ArticleElement.Type.Block
283 || article.type() === WebInspector.WikiParser.ArticleElement.Type.Code
284 || article.type() === WebInspector.WikiParser.ArticleElement.Type.Inline) {
285 for (var i = 0; i < article.children().length; ++i) {
286 var child = this._renderBlock(article.children()[i]);
288 element.appendChild(child);
296 * @param {!WebInspector.WikiParser.Table} table
299 _renderTable: function(table)
301 var tableElement = createElementWithClass("table", "documentation-table");
302 var tableBody = tableElement.createChild("tbody");
303 var headerRow = tableBody.createChild("tr", "documentation-table-row");
304 for (var i = 0; i < table.columnNames().length; ++i) {
305 var tableHeader = headerRow.createChild("th", "documentation-table-header");
306 tableHeader.appendChild(this._renderBlock(table.columnNames()[i]));
308 for (var i = 0; i < table.rows().length; ++i) {
309 var tableRow = tableBody.createChild("tr", "documentation-table-row");
310 var row = table.rows()[i];
311 for (var j = 0; j < row.length; ++j) {
312 var cell = tableRow.createChild("td", "documentation-table-cell");
313 cell.appendChild(this._renderBlock(row[j]));
323 * @implements {WebInspector.ContextMenu.Provider}
325 WebInspector.DocumentationView.ContextMenuProvider = function()
329 WebInspector.DocumentationView.ContextMenuProvider.prototype = {
331 * @param {!Event} event
332 * @param {!WebInspector.ContextMenu} contextMenu
333 * @param {!Object} target
335 appendApplicableItems: function(event, contextMenu, target)
337 if (!(target instanceof WebInspector.CodeMirrorTextEditor))
339 WebInspector.DocumentationCatalog.instance().startLoadingIfNeeded();
340 if (WebInspector.DocumentationCatalog.instance().isLoading()) {
341 var itemName = WebInspector.useLowerCaseMenuTitles() ? "Loading documentation..." : "Loading Documentation...";
342 contextMenu.appendItem(itemName, function() {}, true);
345 var textEditor = /** @type {!WebInspector.CodeMirrorTextEditor} */ (target);
346 var descriptors = this._determineDescriptors(textEditor);
347 if (!descriptors.length)
349 if (descriptors.length === 1) {
350 var formatString = WebInspector.useLowerCaseMenuTitles() ? "Show documentation for %s.%s" : "Show Documentation for %s.%s";
351 var methodName = String.sprintf("%s.%s", descriptors[0].name(), descriptors[0].searchItem());
352 contextMenu.appendItem(WebInspector.UIString(formatString, descriptors[0].name(), descriptors[0].searchItem()), WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[0].url(), methodName));
355 var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show documentation for..." : "Show Documentation for..."));
356 for (var i = 0; i < descriptors.length; ++i) {
357 var methodName = String.sprintf("%s.%s", descriptors[i].name(), descriptors[i].searchItem());
358 subMenuItem.appendItem(methodName, WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[i].url(), methodName));
363 * @param {!WebInspector.CodeMirrorTextEditor} textEditor
364 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
366 _determineDescriptors: function(textEditor)
368 var catalog = WebInspector.DocumentationCatalog.instance();
369 var textSelection = textEditor.selection().normalize();
370 var previousTokenText = findPreviousToken(textSelection);
372 if (!textSelection.isEmpty()) {
373 if (textSelection.startLine !== textSelection.endLine)
375 return computeDescriptors(textSelection);
378 var descriptors = computeDescriptors(getTokenRangeByColumn(textSelection.startColumn));
379 if (descriptors.length)
382 return computeDescriptors(getTokenRangeByColumn(textSelection.startColumn - 1));
385 * @param {number} column
386 * @return {?WebInspector.TextRange}
388 function getTokenRangeByColumn(column)
390 var token = textEditor.tokenAtTextPosition(textSelection.startLine, column);
393 return new WebInspector.TextRange(textSelection.startLine, token.startColumn, textSelection.startLine, token.endColumn);
397 * @param {?WebInspector.TextRange} textRange
398 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
400 function computeDescriptors(textRange)
404 var propertyName = textEditor.copyRange(textRange);
405 var descriptors = catalog.itemDescriptors(propertyName);
406 if (descriptors.length)
408 if (propertyName.toUpperCase() !== propertyName || !previousTokenText || !window[previousTokenText] || !window[previousTokenText][propertyName])
410 return catalog.constantDescriptors(previousTokenText);
414 * @param {!WebInspector.TextRange} textRange
417 function findPreviousToken(textRange)
419 var line = textEditor.line(textRange.startLine);
420 if (textRange.startColumn < 3 || line[textRange.startColumn - 1] !== ".")
422 var token = textEditor.tokenAtTextPosition(textRange.startLine, textRange.startColumn - 2);
423 return token ? line.substring(token.startColumn, token.endColumn) : null;