Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / documentation / DocumentationView.js
index 471a7ff..d1fe7c1 100644 (file)
 
 /**
  * @constructor
- * @extends {WebInspector.VBox}
+ * @extends {WebInspector.View}
  */
 WebInspector.DocumentationView = function()
 {
-    WebInspector.VBox.call(this);
+    WebInspector.View.call(this);
+    this.element.classList.add("documentation-view");
+    this.registerRequiredCSS("documentationView.css");
 }
 
 /**
  * @param {string} url
+ * @param {string} searchItem
  */
-WebInspector.DocumentationView.showDocumentationURL = function(url)
+WebInspector.DocumentationView.showDocumentationURL = function(url, searchItem)
 {
     if (!WebInspector.DocumentationView._view)
         WebInspector.DocumentationView._view = new WebInspector.DocumentationView();
     var view = WebInspector.DocumentationView._view;
+    view.element.removeChildren();
     WebInspector.inspectorView.showCloseableViewInDrawer("documentation", WebInspector.UIString("Documentation"), view);
+    view.showDocumentation(url, searchItem);
 }
 
+WebInspector.DocumentationView._languageToMimeType = {
+    "javascript": "text/javascript",
+    "html": "text/html"
+};
+
 WebInspector.DocumentationView.prototype = {
-    __proto__: WebInspector.VBox.prototype
+    /**
+     * @param {string} url
+     * @param {string} searchItem
+     */
+    showDocumentation: function(url, searchItem)
+    {
+        if (!url) {
+            this._createEmptyPage();
+            return;
+        }
+        loadXHR(url)
+            .then(this._createArticle.bind(this, searchItem), this._createEmptyPage.bind(this))
+            .catch(this._createEmptyPage.bind(this));
+    },
+
+    /**
+     * @param {string} searchItem
+     * @param {string} responseText
+     */
+    _createArticle: function(searchItem, responseText)
+    {
+        var json = JSON.parse(responseText);
+        var pages = json["query"]["pages"];
+        var wikiKeys = Object.keys(pages);
+        if (wikiKeys.length === 1 && wikiKeys[0] === "-1") {
+            this._createEmptyPage();
+            return;
+        }
+        var wikiMarkupText = pages[wikiKeys[0]]["revisions"]["0"]["*"];
+        var article;
+        try {
+            article = WebInspector.JSArticle.parse(wikiMarkupText);
+        } catch (error) {
+            console.error("Article could not be parsed. " + error.message);
+        }
+        if (!article) {
+            this._createEmptyPage();
+            return;
+        }
+
+        this.element.removeChildren();
+        var renderer = new WebInspector.DocumentationView.Renderer(article, searchItem);
+        this.element.appendChild(renderer.renderJSArticle());
+    },
+
+    _createEmptyPage: function()
+    {
+        this.element.removeChildren();
+        var emptyPage = this.element.createChild("div", "documentation-empty-page fill");
+        var pageTitle = emptyPage.createChild("div", "documentation-not-found");
+        pageTitle.textContent = WebInspector.UIString("No documentation found.");
+        emptyPage.createChild("div", "documentation-empty-page-align");
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.JSArticle} article
+ * @param {string} searchItem
+ */
+WebInspector.DocumentationView.Renderer = function(article, searchItem)
+{
+    this._searchItem = searchItem;
+    this._element = document.createElement("div");
+    this._article = article;
+}
+
+WebInspector.DocumentationView.Renderer.prototype = {
+    /**
+     * @return {!Element}
+     */
+    renderJSArticle: function()
+    {
+        this._element.appendChild(this._createPageTitle(this._article.pageTitle, this._searchItem));
+        var signatureElement = this._createSignatureSection(this._article.parameters, this._article.methods);
+        if (signatureElement)
+            this._element.appendChild(signatureElement);
+
+        var descriptionElement = this._element.createChild("div", "documentation-description");
+        var summarySection = this._article.summary ? this._renderBlock(this._article.summary) : null;
+        if (summarySection)
+            descriptionElement.appendChild(summarySection);
+        var parametersSection = this._createParametersSection(this._article.parameters);
+        if (parametersSection)
+            descriptionElement.appendChild(parametersSection);
+
+        var examplesSection = this._createExamplesSection(this._article.examples);
+        if (examplesSection) {
+            var examplesTitle = this._element.createChild("div", "documentation-title");
+            examplesTitle.textContent = WebInspector.UIString("Examples");
+            descriptionElement = this._element.createChild("div", "documentation-description");
+            descriptionElement.appendChild(examplesSection);
+        }
+
+        var remarksSection = this._article.remarks ? this._renderBlock(this._article.remarks) : null;
+        if (remarksSection) {
+            var remarksTitle = this._element.createChild("div", "documentation-title");
+            remarksTitle.textContent = WebInspector.UIString("Remarks");
+            descriptionElement = this._element.createChild("div", "documentation-description");
+            descriptionElement.appendChild(remarksSection);
+        }
+        return this._element;
+    },
+
+    /**
+     * @param {string} titleText
+     * @param {string} searchItem
+     * @return {!Element}
+     */
+    _createPageTitle: function(titleText, searchItem)
+    {
+        var pageTitle = document.createElementWithClass("div", "documentation-page-title");
+        if (titleText)
+            pageTitle.textContent = titleText;
+        else if (searchItem)
+            pageTitle.textContent = searchItem;
+        return pageTitle;
+    },
+
+    /**
+     * @param {!Array.<!WebInspector.JSArticle.Parameter>} parameters
+     * @param {?WebInspector.JSArticle.Method} method
+     * @return {?Element}
+     */
+    _createSignatureSection: function(parameters, method)
+    {
+        if (!parameters.length && !method)
+            return null;
+        var signature = document.createElementWithClass("div", "documentation-method-signature monospace");
+        if (method && method.returnValueName) {
+            var returnTypeElement = signature.createChild("span", "documentation-parameter-data-type-value");
+            returnTypeElement.textContent = method.returnValueName;
+        }
+        var methodName = signature.createChild("span", "documentation-method-name");
+        methodName.textContent = this._searchItem.split(".").peekLast() + "(";
+        for (var i = 0; i < parameters.length; ++i) {
+            if (i > 0)
+                signature.createTextChild(",")
+            var parameterType = signature.createChild("span", "documentation-parameter-data-type-value");
+            parameterType.textContent = parameters[i].dataType;
+            var parameterName = signature.createChild("span", "documentation-parameter-name");
+            parameterName.textContent = parameters[i].name;
+        }
+
+        signature.createTextChild(")");
+        return signature;
+    },
+
+    /**
+     * @param {!Array.<!WebInspector.JSArticle.Parameter>} parameters
+     * @return {?Element}
+     */
+    _createParametersSection: function(parameters)
+    {
+        if (!parameters.length)
+            return null;
+        var table = document.createElementWithClass("table", "documentation-table");
+        var tableBody = table.createChild("tbody");
+        var headerRow = tableBody.createChild("tr", "documentation-table-row");
+        var tableHeader = headerRow.createChild("th", "documentation-table-header");
+        tableHeader.textContent = WebInspector.UIString("Parameters");
+        tableHeader.colSpan = 3;
+        for (var i = 0; i < parameters.length; ++i) {
+            var tableRow = tableBody.createChild("tr", "documentation-table-row");
+            var type = tableRow.createChild("td", "documentation-table-cell");
+            type.textContent = parameters[i].dataType;
+            var name = tableRow.createChild("td", "documentation-table-cell");
+            name.textContent = parameters[i].optional ? WebInspector.UIString("(optional)\n") : "";
+            name.textContent += parameters[i].name;
+            var description = tableRow.createChild("td", "documentation-table-cell");
+            if (parameters[i].description)
+                description.appendChild(this._renderBlock(/** @type {!WebInspector.WikiParser.Block} */(parameters[i].description)));
+        }
+        return table;
+    },
+
+    /**
+     * @param {!Array.<!WebInspector.JSArticle.Example>} examples
+     */
+    _createExamplesSection: function(examples)
+    {
+        if (!examples.length)
+            return;
+
+        var section = document.createElementWithClass("div", "documentation-section");
+
+        for (var i = 0; i < examples.length; ++i) {
+            var example = section.createChild("div", "documentation-example");
+            var exampleDescription = example.createChild("div", "documentation-example-description-section");
+            if (examples[i].description) {
+                var description = this._renderBlock(/** @type {!WebInspector.WikiParser.Block} */(examples[i].description));
+                description.classList.add("documentation-text");
+                exampleDescription.appendChild(description);
+            }
+            var code = example.createChild("div", "documentation-code source-code");
+            code.textContent = examples[i].code;
+            if (!examples[i].language)
+                continue;
+            var syntaxHighlighter = new WebInspector.DOMSyntaxHighlighter(WebInspector.DocumentationView._languageToMimeType[examples[i].language.toLowerCase()], true);
+            syntaxHighlighter.syntaxHighlightNode(code);
+        }
+        return section;
+    },
+
+    /**
+     * @param {!WebInspector.WikiParser.ArticleElement} article
+     * @return {!Element}
+     */
+    _renderBlock: function(article)
+    {
+        var element;
+        var elementTypes = WebInspector.WikiParser.ArticleElement.Type;
+
+        switch (article.type()) {
+        case elementTypes.Inline:
+            element = document.createElement("span");
+            break;
+        case elementTypes.Link:
+            element = document.createElementWithClass("a", "documentation-link");
+            element.href = article.url();
+            if (!article.children().length)
+                element.textContent = article.url();
+            break;
+        case elementTypes.Code:
+            element = document.createElementWithClass("span", "documentation-code-tag");
+            break;
+        case elementTypes.CodeBlock:
+            element = document.createElementWithClass("pre", "documentation-code source-code");
+            element.textContent = article.code();
+            break;
+        case elementTypes.PlainText:
+            element = document.createElement("span");
+            element.textContent = article.text();
+            if (article.isHighlighted())
+                element.classList.add("documentation-highlighted-text");
+            break;
+        case elementTypes.Block:
+            element = document.createElement(article.hasBullet() ? "li" : "div");
+            if (!article.hasBullet())
+                element.classList.add("documentation-paragraph");
+            break;
+        case elementTypes.Table:
+            return this._renderTable(/** @type {!WebInspector.WikiParser.Table} */(article));
+        default:
+            throw new Error("Unknown ArticleElement type " + article.type());
+        }
+
+        if (article.type() === WebInspector.WikiParser.ArticleElement.Type.Block
+            || article.type() === WebInspector.WikiParser.ArticleElement.Type.Code
+            || article.type() === WebInspector.WikiParser.ArticleElement.Type.Inline) {
+            for (var i = 0; i < article.children().length; ++i) {
+                var child = this._renderBlock(article.children()[i]);
+                if (child)
+                    element.appendChild(child);
+            }
+        }
+
+        return element;
+    },
+
+    /**
+     * @param {!WebInspector.WikiParser.Table} table
+     * @return {!Element}
+     */
+    _renderTable: function(table)
+    {
+        var tableElement = document.createElementWithClass("table", "documentation-table");
+        var tableBody = tableElement.createChild("tbody");
+        var headerRow = tableBody.createChild("tr", "documentation-table-row");
+        for (var i = 0; i < table.columnNames().length; ++i) {
+            var tableHeader = headerRow.createChild("th", "documentation-table-header");
+            tableHeader.appendChild(this._renderBlock(table.columnNames()[i]));
+        }
+        for (var i = 0; i < table.rows().length; ++i) {
+            var tableRow = tableBody.createChild("tr", "documentation-table-row");
+            var row = table.rows()[i];
+            for (var j = 0; j < row.length; ++j) {
+                var cell = tableRow.createChild("td", "documentation-table-cell");
+                cell.appendChild(this._renderBlock(row[j]));
+            }
+        }
+
+        return tableElement;
+    }
 }
 
 /**
@@ -44,53 +339,91 @@ WebInspector.DocumentationView.ContextMenuProvider.prototype = {
     {
         if (!(target instanceof WebInspector.CodeMirrorTextEditor))
             return;
+        WebInspector.DocumentationCatalog.instance().startLoadingIfNeeded();
+        if (WebInspector.DocumentationCatalog.instance().isLoading()) {
+            var itemName = WebInspector.useLowerCaseMenuTitles() ? "Loading documentation..." : "Loading Documentation...";
+            contextMenu.appendItem(itemName, function() {}, true);
+            return;
+        }
         var textEditor = /** @type {!WebInspector.CodeMirrorTextEditor} */ (target);
         var descriptors = this._determineDescriptors(textEditor);
-
         if (!descriptors.length)
             return;
         if (descriptors.length === 1) {
             var formatString = WebInspector.useLowerCaseMenuTitles() ? "Show documentation for %s.%s" : "Show Documentation for %s.%s";
-            contextMenu.appendItem(WebInspector.UIString(formatString, descriptors[0].name, descriptors[0].searchItem), WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[0].url));
+            var methodName = String.sprintf("%s.%s", descriptors[0].name(), descriptors[0].searchItem());
+            contextMenu.appendItem(WebInspector.UIString(formatString, descriptors[0].name(), descriptors[0].searchItem()), WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[0].url(), methodName));
             return;
         }
         var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show documentation for..." : "Show Documentation for..."));
-        for (var i = 0; i < descriptors.length; ++i)
-            subMenuItem.appendItem(String.sprintf("%s.%s", descriptors[i].name, descriptors[i].searchItem), WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[i].url));
+        for (var i = 0; i < descriptors.length; ++i) {
+            var methodName = String.sprintf("%s.%s", descriptors[i].name(), descriptors[i].searchItem());
+            subMenuItem.appendItem(methodName, WebInspector.DocumentationView.showDocumentationURL.bind(null, descriptors[i].url(), methodName));
+        }
     },
 
     /**
      * @param {!WebInspector.CodeMirrorTextEditor} textEditor
-     * @return {!Array.<!WebInspector.DocumentationURLProvider.ItemDescriptor>}
+     * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
      */
     _determineDescriptors: function(textEditor)
     {
-        var urlProvider = new WebInspector.DocumentationURLProvider();
+        var catalog = WebInspector.DocumentationCatalog.instance();
         var textSelection = textEditor.selection().normalize();
+        var previousTokenText = findPreviousToken(textSelection);
 
         if (!textSelection.isEmpty()) {
             if (textSelection.startLine !== textSelection.endLine)
                 return [];
-            return urlProvider.itemDescriptors(textEditor.copyRange(textSelection));
+            return computeDescriptors(textSelection);
         }
 
-        var descriptors = computeDescriptors(textSelection.startColumn);
+        var descriptors = computeDescriptors(getTokenRangeByColumn(textSelection.startColumn));
         if (descriptors.length)
             return descriptors;
 
-        return computeDescriptors(textSelection.startColumn - 1);
+        return computeDescriptors(getTokenRangeByColumn(textSelection.startColumn - 1));
 
         /**
          * @param {number} column
-         * @return {!Array.<!WebInspector.DocumentationURLProvider.ItemDescriptor>}
+         * @return {?WebInspector.TextRange}
          */
-        function computeDescriptors(column)
+        function getTokenRangeByColumn(column)
         {
             var token = textEditor.tokenAtTextPosition(textSelection.startLine, column);
             if (!token)
+                return null;
+            return new WebInspector.TextRange(textSelection.startLine, token.startColumn, textSelection.startLine, token.endColumn);
+        }
+
+        /**
+         * @param {?WebInspector.TextRange} textRange
+         * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>}
+         */
+        function computeDescriptors(textRange)
+        {
+            if (!textRange)
+                return [];
+            var propertyName = textEditor.copyRange(textRange);
+            var descriptors = catalog.itemDescriptors(propertyName);
+            if (descriptors.length)
+                return descriptors;
+            if (propertyName.toUpperCase() !== propertyName || !previousTokenText || !window[previousTokenText] || !window[previousTokenText][propertyName])
                 return [];
-            var tokenText = textEditor.line(textSelection.startLine).substring(token.startColumn, token.endColumn);
-            return urlProvider.itemDescriptors(tokenText);
+            return catalog.constantDescriptors(previousTokenText);
+        }
+
+        /**
+         * @param {!WebInspector.TextRange} textRange
+         * @return {?string}
+         */
+        function findPreviousToken(textRange)
+        {
+            var line = textEditor.line(textRange.startLine);
+            if (textRange.startColumn < 3 || line[textRange.startColumn - 1] !== ".")
+                return null;
+            var token = textEditor.tokenAtTextPosition(textRange.startLine, textRange.startColumn - 2);
+            return token ? line.substring(token.startColumn, token.endColumn) : null;
         }
     }
-}
+}
\ No newline at end of file