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. 4 5/** 6 * @constructor 7 */ 8WebInspector.DocumentationCatalog = function() 9{ 10 /** @type {!StringMap.<!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>>} */ 11 this._articleList = new StringMap(); 12 this._loader = new WebInspector.DocumentationCatalog.Loader(this); 13} 14 15/** 16 * @return {!WebInspector.DocumentationCatalog} 17 */ 18WebInspector.DocumentationCatalog.instance = function() 19{ 20 if (!WebInspector.DocumentationCatalog._instance) 21 WebInspector.DocumentationCatalog._instance = new WebInspector.DocumentationCatalog(); 22 return WebInspector.DocumentationCatalog._instance; 23} 24 25/** 26 * @constructor 27 * @param {string} url 28 * @param {string} name 29 * @param {string} searchTerm 30 */ 31WebInspector.DocumentationCatalog.ItemDescriptor = function(url, name, searchTerm) 32{ 33 this._url = String.sprintf(WebInspector.DocumentationCatalog._articleURLFormat, url, searchTerm); 34 this._name = name; 35 this._searchItem = searchTerm; 36} 37 38WebInspector.DocumentationCatalog.ItemDescriptor.prototype = { 39 /** 40 * @return {string} 41 */ 42 url: function() 43 { 44 return this._url; 45 }, 46 47 /** 48 * @return {string} 49 */ 50 name: function() 51 { 52 return this._name; 53 }, 54 55 /** 56 * @return {string} 57 */ 58 searchItem: function() 59 { 60 return this._searchItem; 61 } 62} 63 64/** 65 * @const 66 */ 67WebInspector.DocumentationCatalog.apiURLPrefix = "http://docs.webplatform.org/w/api.php?action=query"; 68 69/** 70 * @const 71 */ 72WebInspector.DocumentationCatalog._articleURLFormat = WebInspector.DocumentationCatalog.apiURLPrefix + "&titles=%s%s&prop=revisions&rvprop=timestamp|content&format=json"; 73 74/** 75 * @const 76 */ 77WebInspector.DocumentationCatalog._articleListURLFormat = WebInspector.DocumentationCatalog.apiURLPrefix + "&generator=allpages&gaplimit=500&gapfrom=%s&format=json"; 78 79WebInspector.DocumentationCatalog.prototype = { 80 /** 81 * @param {string} searchTerm 82 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>} 83 */ 84 itemDescriptors: function(searchTerm) 85 { 86 return this._articleList.get(searchTerm) || []; 87 }, 88 89 /** 90 * @param {string} sourceName 91 * @return {!Array.<!WebInspector.DocumentationCatalog.ItemDescriptor>} 92 */ 93 constantDescriptors: function(sourceName) 94 { 95 return [new WebInspector.DocumentationCatalog.ItemDescriptor("javascript/" + sourceName + "/", sourceName, "constants")] 96 }, 97 98 startLoadingIfNeeded: function() 99 { 100 if (this._loader._state === WebInspector.DocumentationCatalog.Loader.DownloadStates.NotStarted) 101 this._loader._loadArticleList(); 102 }, 103 104 /** 105 * @return {boolean} 106 */ 107 isLoading: function() 108 { 109 return this._loader._state === WebInspector.DocumentationCatalog.Loader.DownloadStates.InProgress; 110 }, 111 112 /** 113 * @param {string} itemPath 114 */ 115 _addDescriptorToList: function(itemPath) 116 { 117 // There are some properties that have several words in their name. 118 // In article list they are written with whitespace, while in URL they are written with underscore. 119 // We are creating URL for current property, so we have to replace all the whitespaces with underscores. 120 var correctedItemPath = itemPath.replace(" ", "_"); 121 var tokens = correctedItemPath.split("/"); 122 if (tokens.length === 1) 123 return; 124 var propertyName = tokens.pop(); 125 var sourceName = tokens.length === 1 ? "window" : tokens.pop(); 126 if (!sourceName) 127 return; 128 var descriptors = this._articleList.get(propertyName); 129 if (!descriptors) { 130 descriptors = []; 131 this._articleList.set(propertyName, descriptors); 132 } 133 var sourcePath = tokens.join("/") + "/" + (sourceName === "window" ? "" : sourceName + "/"); 134 descriptors.push(new WebInspector.DocumentationCatalog.ItemDescriptor(sourcePath, sourceName, propertyName)); 135 }, 136} 137 138/** 139 * @constructor 140 * @param {!WebInspector.DocumentationCatalog} catalog 141 */ 142WebInspector.DocumentationCatalog.Loader = function(catalog) 143{ 144 this._sectionIndex = 0; 145 this._section = WebInspector.DocumentationCatalog.Loader._sections[0]; 146 this._state = WebInspector.DocumentationCatalog.Loader.DownloadStates.NotStarted; 147 this._catalog = catalog; 148} 149 150/** 151 * @enum {string} 152 */ 153WebInspector.DocumentationCatalog.Loader.DownloadStates = { 154 NotStarted: "NotStarted", 155 InProgress: "InProgress", 156 Finished: "Finished", 157 Failed: "Failed" 158}; 159 160/** 161 * @const 162 * This array should be sorted alphabetically for correct WebInspector.DocumentationCatalog.Loader work. 163 */ 164WebInspector.DocumentationCatalog.Loader._sections = [ 165 "dom/", 166 "javascript/" 167]; 168 169WebInspector.DocumentationCatalog.Loader.prototype = { 170 _loadArticleList: function() 171 { 172 if (this._state === WebInspector.DocumentationCatalog.Loader.DownloadStates.Finished) 173 return; 174 this._state = WebInspector.DocumentationCatalog.Loader.DownloadStates.InProgress; 175 var url = String.sprintf(WebInspector.DocumentationCatalog._articleListURLFormat, this._section); 176 var boundReset = this._resetDownload.bind(this); 177 loadXHR(url).then(this._processData.bind(this), boundReset).catch(boundReset); 178 }, 179 180 /** 181 * @param {?string} responseText 182 */ 183 _processData: function(responseText) 184 { 185 if (!responseText) { 186 this._resetDownload.call(this); 187 return; 188 } 189 var json = JSON.parse(responseText); 190 var pages = json["query"]["pages"]; 191 for (var article in pages) 192 this._catalog._addDescriptorToList(pages[article]["title"]); 193 var sections = WebInspector.DocumentationCatalog.Loader._sections; 194 this._section = json["query-continue"]["allpages"]["gapcontinue"]; 195 while (this._sectionIndex < sections.length && this._section > sections[this._sectionIndex] && !this._section.startsWith(sections[this._sectionIndex])) 196 ++this._sectionIndex; 197 if (this._sectionIndex === sections.length) { 198 this._state = WebInspector.DocumentationCatalog.Loader.DownloadStates.Finished; 199 return; 200 } 201 if (this._section < sections[this._sectionIndex]) 202 this._section = sections[this._sectionIndex]; 203 this._loadArticleList(); 204 }, 205 206 _resetDownload: function() 207 { 208 WebInspector.console.error("Documentation article list download failed"); 209 this._state = WebInspector.DocumentationCatalog.Loader.DownloadStates.Failed; 210 } 211}