Add GTK documentation
Unified · Split
| @@ -1,4 +1,8 @@ | ||
| 1 | 1 | [ |
| 2 | + [ | |
| 3 | + "2020-12-23", | |
| 4 | + "New documentation: <a href=\"/gtk/\">GTK</a>" | |
| 5 | + ], | |
| 2 | 6 | [ |
| 3 | 7 | "2020-12-07", |
| 4 | 8 | "New documentations: <a href=\"/flask/\">Flask</a>, <a href=\"/groovy/\">Groovy</a>, <a href=\"/jinja/\">Jinja</a>, <a href=\"/werkzeug/\">Werkzeug</a>" |
| @@ -356,6 +356,11 @@ credits = [ · 355 unmodified lines | ||
| 356 | 356 | 'GruntJS Team', |
| 357 | 357 | 'MIT', |
| 358 | 358 | 'https://github.com/gruntjs/grunt-docs/blob/master/package.json#L10' |
| 359 | + ], [ | |
| 360 | + 'GTK', | |
| 361 | + 'The GNOME Project', | |
| 362 | + 'LGPLv2.1+', | |
| 363 | + 'https://gitlab.gnome.org/GNOME/gtk/-/blob/master/COPYING' | |
| 359 | 364 | ], [ |
| 360 | 365 | 'Handlebars', |
| 361 | 366 | '2011-2017 Yehuda Katz', |
| @@ -59,10 +59,11 @@ · 58 unmodified lines | ||
| 59 | 59 | 'pages/express', |
| 60 | 60 | 'pages/git', |
| 61 | 61 | 'pages/github', |
| 62 | + 'pages/gnuplot', | |
| 62 | 63 | 'pages/go', |
| 63 | 64 | 'pages/graphite', |
| 64 | 65 | 'pages/groovy', |
| 65 | − 'pages/gnuplot', | |
| 66 | + 'pages/gtk', | |
| 66 | 67 | 'pages/haproxy', |
| 67 | 68 | 'pages/haskell', |
| 68 | 69 | 'pages/jekyll', |
| @@ -0,0 +1,15 @@ | ||
| 1 | +._gtk { | |
| 2 | + padding-left: 1rem; | |
| 3 | + | |
| 4 | + h1, h2, h3 { margin-left: -1rem; } | |
| 5 | + h2 { @extend %block-heading; } | |
| 6 | + h3 { @extend %block-label, %label-blue; } | |
| 7 | + | |
| 8 | + div.toc { margin-top: 1.5em; } | |
| 9 | + .toc dl { margin-top: 0; margin-bottom: 0; } | |
| 10 | + | |
| 11 | + .note { @extend %note, %note-green; } | |
| 12 | + .warning { @extend %note, %note-orange; } | |
| 13 | + | |
| 14 | + .gallery-float { float:left; } | |
| 15 | +} | |
| @@ -190,6 +190,8 @@ More information about how filters work is available on the [Filter Reference](. · 189 unmodified lines | ||
| 190 | 190 | In order to keep scrapers up-to-date the `get_latest_version(opts)` method should be overridden. If `self.release` is defined, this should return the latest version of the documentation. If `self.release` is not defined, it should return the Epoch time when the documentation was last modified. If the documentation will never change, simply return `1.0.0`. The result of this method is periodically reported in a "Documentation versions report" issue which helps maintainers keep track of outdated documentations. |
| 191 | 191 | |
| 192 | 192 | To make life easier, there are a few utility methods that you can use in `get_latest_version`: |
| 193 | + | |
| 194 | +### General HTTP methods | |
| 193 | 195 | * `fetch(url, opts)` |
| 194 | 196 | |
| 195 | 197 | Makes a GET request to the url and returns the response body. |
| @@ -205,11 +207,15 @@ To make life easier, there are a few utility methods that you can use in `get_la · 9 unmodified lines | ||
| 205 | 207 | Makes a GET request to the url and returns the JSON body converted to a dictionary. |
| 206 | 208 | |
| 207 | 209 | Example: [lib/docs/scrapers/mdn/mdn.rb](../lib/docs/scrapers/mdn/mdn.rb) |
| 210 | + | |
| 211 | +### Package repository methods | |
| 208 | 212 | * `get_npm_version(package, opts)` |
| 209 | 213 | |
| 210 | 214 | Returns the latest version of the given npm package. |
| 211 | 215 | |
| 212 | 216 | Example: [lib/docs/scrapers/bower.rb](../lib/docs/scrapers/bower.rb) |
| 217 | + | |
| 218 | +### GitHub methods | |
| 213 | 219 | * `get_latest_github_release(owner, repo, opts)` |
| 214 | 220 | |
| 215 | 221 | Returns the tag name of the latest GitHub release of the given repository. If the tag name is preceded by a "v", the "v" will be removed. |
| @@ -225,3 +231,15 @@ To make life easier, there are a few utility methods that you can use in `get_la · 9 unmodified lines | ||
| 225 | 231 | Returns the contents of the requested file in the default branch of the given repository. |
| 226 | 232 | |
| 227 | 233 | Example: [lib/docs/scrapers/minitest.rb](../lib/docs/scrapers/minitest.rb) |
| 234 | +* `get_latest_github_commit_date(owner, repo, opts)` | |
| 235 | + | |
| 236 | + Returns the date of the most recent commit in the default branch of the given repository. | |
| 237 | + | |
| 238 | + Example: [lib/docs/scrapers/reactivex.rb](../lib/docs/scrapers/reactivex.rb) | |
| 239 | + | |
| 240 | +### GitLab methods | |
| 241 | +* `get_gitlab_tags(hostname, group, project, opts)` | |
| 242 | + | |
| 243 | + Returns the list of tags on the given repository ([format](https://docs.gitlab.com/ee/api/tags.html)). | |
| 244 | + | |
| 245 | + Example: [lib/docs/scrapers/gtk.rb](../lib/docs/scrapers/gtk.rb) | |
| @@ -270,5 +270,9 @@ module Docs · 269 unmodified lines | ||
| 270 | 270 | timestamp = commits[0]['commit']['author']['date'] |
| 271 | 271 | Date.iso8601(timestamp).to_time.to_i |
| 272 | 272 | end |
| 273 | + | |
| 274 | + def get_gitlab_tags(hostname, group, project, opts) | |
| 275 | + fetch_json("https://#{hostname}/api/v4/projects/#{group}%2F#{project}/repository/tags", opts) | |
| 276 | + end | |
| 273 | 277 | end |
| 274 | 278 | end |
| @@ -0,0 +1,69 @@ | ||
| 1 | +module Docs | |
| 2 | + class Gtk | |
| 3 | + class CleanHtmlFilter < Filter | |
| 4 | + def call | |
| 5 | + | |
| 6 | + css('table#top', 'table > colgroup', 'h2.title', '.footer', 'hr', 'br').remove | |
| 7 | + | |
| 8 | + if root_page? | |
| 9 | + css('span > a').each do |node| | |
| 10 | + node.parent.before(node).remove | |
| 11 | + end | |
| 12 | + end | |
| 13 | + | |
| 14 | + if top_table = at_css('.refnamediv > table') | |
| 15 | + top_table.css('td > p', 'td > img').each do |node| | |
| 16 | + top_table.before(node) | |
| 17 | + end | |
| 18 | + top_table.remove | |
| 19 | + end | |
| 20 | + | |
| 21 | + css('table').each do |node| | |
| 22 | + node.remove_attribute 'border' | |
| 23 | + node.remove_attribute 'width' | |
| 24 | + end | |
| 25 | + | |
| 26 | + # Move anchors to general headings | |
| 27 | + css('h2 > a[name]', 'h3 > a[name]').each do |node| | |
| 28 | + node.parent['id'] = node['name'] | |
| 29 | + end | |
| 30 | + | |
| 31 | + # Move anchors to function/struct/enum/etc. | |
| 32 | + css('a[name] + h2', 'a[name] + h3').each do |node| | |
| 33 | + node['id'] = node.previous_element['name'] | |
| 34 | + end | |
| 35 | + | |
| 36 | + # Move anchors to struct and enum members | |
| 37 | + css('td.struct_member_name', 'td.enum_member_name').each do |node| | |
| 38 | + node['id'] = node.at_css('a[name]')['name'] | |
| 39 | + end | |
| 40 | + | |
| 41 | + # Remove surrounding table from code blocks | |
| 42 | + css('.listing_frame').each do |node| | |
| 43 | + node.before(at_css('.listing_code')).remove | |
| 44 | + end | |
| 45 | + | |
| 46 | + css('.literallayout code').each do |node| | |
| 47 | + node.name = 'pre' | |
| 48 | + end | |
| 49 | + | |
| 50 | + # Fix code highlighting | |
| 51 | + css('pre').each do |node| | |
| 52 | + # If a codeblock has URLs, don't touch it | |
| 53 | + next if node.at_css('a[href]') | |
| 54 | + | |
| 55 | + node.content = node.content | |
| 56 | + | |
| 57 | + # it's not perfect, but make a guess at language | |
| 58 | + if node.content =~ /\<\?xml/ | |
| 59 | + node['data-language'] = 'xml' | |
| 60 | + else | |
| 61 | + node['data-language'] = 'c' | |
| 62 | + end | |
| 63 | + end | |
| 64 | + | |
| 65 | + doc | |
| 66 | + end | |
| 67 | + end | |
| 68 | + end | |
| 69 | +end | |
| @@ -0,0 +1,154 @@ | ||
| 1 | +module Docs | |
| 2 | + class Gtk | |
| 3 | + class EntriesFilter < Docs::EntriesFilter | |
| 4 | + # The GTK documentation paths are "flat" and while the contents of each | |
| 5 | + # page provides a way to determine the direct parent relationship, we | |
| 6 | + # really need a full hierarchy of pages *a priori* to be able to fully | |
| 7 | + # categorize all pages and entries. So we're going to recursivly generate | |
| 8 | + # a full map of page -> parent relationships from the table of contents... | |
| 9 | + PARENT_BY_PATH = {} | |
| 10 | + | |
| 11 | + # And then use it to generate the list of 'breadcrumb' paths for each page | |
| 12 | + # ex: ['gtkwidgets', 'fancywidgets', 'gtkexamplewidget'] | |
| 13 | + attr_accessor :breadcrumbs | |
| 14 | + | |
| 15 | + # Map of paths to Page Names/Titles | |
| 16 | + NAME_BY_PATH = {} | |
| 17 | + | |
| 18 | + # GTK+ 3 and GTK 4 | |
| 19 | + REPLACE_NAMES = { | |
| 20 | + 'I. GTK+ Overview' => '1. Overview', | |
| 21 | + 'II. GTK+ Widgets and Objects' => '2. Widgets and Objects', | |
| 22 | + 'III. GTK+ Core Reference' => '3. Core Reference', | |
| 23 | + 'IV. Theming in GTK+' => '4. Theming', | |
| 24 | + 'VI. GTK+ Tools' => '6. Tools', | |
| 25 | + 'VII. GTK+ Platform Support' => '7. Platform Support', | |
| 26 | + | |
| 27 | + 'I. Introduction' => '1. Introduction', | |
| 28 | + 'II. GTK Concepts' => '2. Concepts', | |
| 29 | + 'III. GTK Widgets and Objects' => '3. Widgets and Objects', | |
| 30 | + 'IV. GTK Core Reference' => '4. Core Reference', | |
| 31 | + 'V. Theming in GTK' => '5. Theming', | |
| 32 | + 'VII. GTK Tools' => '7. Tools', | |
| 33 | + 'VIII. GTK Platform Support' => '8. Platform Support' | |
| 34 | + } | |
| 35 | + | |
| 36 | + def call | |
| 37 | + if root_page? | |
| 38 | + # Generate NAME_BY_PATH Hash | |
| 39 | + css('dl.toc a').each do |node| | |
| 40 | + name = node.content | |
| 41 | + path = node['href'].split('/').last.remove('.html') | |
| 42 | + NAME_BY_PATH[path] = REPLACE_NAMES[name] || name | |
| 43 | + end | |
| 44 | + # Generate PARENT_BY_PATH Hash | |
| 45 | + process_toc(at_css('dl.toc'), nil) | |
| 46 | + end | |
| 47 | + super | |
| 48 | + end | |
| 49 | + | |
| 50 | + # Recursive depth-first search | |
| 51 | + # Treat solo 'dt' nodes as leaf nodes and | |
| 52 | + # sibling 'dt + dd' nodes as nodes with children | |
| 53 | + def process_toc(toc_dl_node, parent_path) | |
| 54 | + toc_dl_node.css('> dt').each do |node| | |
| 55 | + node_path = node.at_css('a')['href'].split('/').last.remove('.html') | |
| 56 | + PARENT_BY_PATH[node_path] = parent_path | |
| 57 | + | |
| 58 | + if node.next_element && node.next_element.name == 'dd' | |
| 59 | + children = node.next_element.children.first | |
| 60 | + process_toc(children, node_path) | |
| 61 | + end | |
| 62 | + end | |
| 63 | + end | |
| 64 | + | |
| 65 | + def breadcrumbs | |
| 66 | + @breadcrumbs ||= get_breadcrumbs | |
| 67 | + end | |
| 68 | + | |
| 69 | + def get_breadcrumbs | |
| 70 | + return [] if root_page? | |
| 71 | + | |
| 72 | + breadcrumbs = [] | |
| 73 | + path = slug.downcase | |
| 74 | + while path | |
| 75 | + breadcrumbs.prepend path | |
| 76 | + path = PARENT_BY_PATH[path] | |
| 77 | + end | |
| 78 | + | |
| 79 | + breadcrumbs | |
| 80 | + end | |
| 81 | + | |
| 82 | + def get_name | |
| 83 | + NAME_BY_PATH[self.breadcrumbs.last] | |
| 84 | + end | |
| 85 | + | |
| 86 | + def get_type | |
| 87 | + NAME_BY_PATH[self.breadcrumbs.first] | |
| 88 | + end | |
| 89 | + | |
| 90 | + def additional_entries | |
| 91 | + entries = [] | |
| 92 | + type = case self.breadcrumbs.first | |
| 93 | + when 'gtkobjects' | |
| 94 | + "Widgets / #{NAME_BY_PATH[self.breadcrumbs[1]]}" | |
| 95 | + when 'gtkbase' | |
| 96 | + "Base / #{self.name}" | |
| 97 | + when'theming' | |
| 98 | + "Theming / #{self.name}" | |
| 99 | + end | |
| 100 | + | |
| 101 | + if funcs = at_css('h2:contains("Functions")') | |
| 102 | + funcs.next_element.css('td.function_name > a').each do |node| | |
| 103 | + name = "#{node.content}()" | |
| 104 | + id = node['href'] | |
| 105 | + entries << [name, id, type] | |
| 106 | + end | |
| 107 | + end | |
| 108 | + | |
| 109 | + css('td.property_name > a').each do |node| | |
| 110 | + name = "#{node.content} (#{self.name} property)" | |
| 111 | + id = node['href'] | |
| 112 | + entries << [name, id, type] | |
| 113 | + end | |
| 114 | + | |
| 115 | + css('td.signal_name > a').each do |node| | |
| 116 | + name = "#{node.content} (#{self.name} signal)" | |
| 117 | + id = node['href'] | |
| 118 | + entries << [name, id, type] | |
| 119 | + end | |
| 120 | + | |
| 121 | + css('td.enum_member_name').each do |node| | |
| 122 | + name = node.content | |
| 123 | + id = node.at_css('a')['name'] | |
| 124 | + entries << [name, id, type] | |
| 125 | + end | |
| 126 | + | |
| 127 | + if values_node = at_css('h2:contains("Types and Values") + .informaltable') | |
| 128 | + values_node.css('tr').each do |node| | |
| 129 | + data_type = node.css('td').first.content | |
| 130 | + name = node.at_css('td.function_name').content | |
| 131 | + if data_type == ' ' | |
| 132 | + name = "#{name} (type)" | |
| 133 | + elsif data_type == 'enum' || data_type == 'struct' | |
| 134 | + name = "#{name} (#{data_type})" | |
| 135 | + end | |
| 136 | + id = node.at_css('td.function_name a')['href'] | |
| 137 | + entries << [name, id, type] | |
| 138 | + end | |
| 139 | + end | |
| 140 | + | |
| 141 | + if slug == 'gtk-running' | |
| 142 | + css('h3 > a[name]').each do |node| | |
| 143 | + name = node.parent.content | |
| 144 | + id = node['name'] | |
| 145 | + entries << [name, id, 'Platform / Environment Variables'] | |
| 146 | + end | |
| 147 | + end | |
| 148 | + | |
| 149 | + entries | |
| 150 | + end | |
| 151 | + | |
| 152 | + end | |
| 153 | + end | |
| 154 | +end | |
| @@ -0,0 +1,116 @@ | ||
| 1 | +module Docs | |
| 2 | + class Gtk < UrlScraper | |
| 3 | + self.name = 'GTK' | |
| 4 | + self.slug = 'gtk' | |
| 5 | + self.type = 'gtk' | |
| 6 | + self.root_path = 'index.html' | |
| 7 | + self.links = { | |
| 8 | + home: 'https://www.gtk.org/', | |
| 9 | + code: 'https://gitlab.gnome.org/GNOME/gtk/' | |
| 10 | + } | |
| 11 | + | |
| 12 | + html_filters.push 'gtk/entries', 'gtk/clean_html', 'title' | |
| 13 | + | |
| 14 | + options[:container] = '.content' | |
| 15 | + | |
| 16 | + # These are all "index"-ish pages with no valuable content | |
| 17 | + GTK3_SKIP = %w( | |
| 18 | + gtk.html | |
| 19 | + gtk-resources.html gtk-question-index.html | |
| 20 | + gtkobjects.html | |
| 21 | + Application.html Builder.html WindowWidgets.html LayoutContainers.html | |
| 22 | + DisplayWidgets.html ButtonWidgets.html NumericEntry.html | |
| 23 | + TextWidgetObjects.html TreeWidgetObjects.html MenusAndCombos.html | |
| 24 | + SelectorWidgets.html Ornaments.html ScrollingWidgets.html Printing.html | |
| 25 | + ShortcutsOverview.html MiscObjects.html AbstractObjects.html | |
| 26 | + PlugSocket.html RecentDocuments.html ApplicationChoosing.html | |
| 27 | + Gestures.html DeprecatedObjects.html | |
| 28 | + gtkbase.html | |
| 29 | + theming.html | |
| 30 | + migrating.html | |
| 31 | + ch26s02.html ch28s02.html | |
| 32 | + pt06.html | |
| 33 | + platform-support.html | |
| 34 | + glossary.html | |
| 35 | + annotation-glossary.html | |
| 36 | + ) | |
| 37 | + | |
| 38 | + GTK3_SKIP_PATTERNS = [ | |
| 39 | + /migrating/, /checklist/, /ch30/, /ch32/, /api-index-/ | |
| 40 | + ] | |
| 41 | + | |
| 42 | + # These are all "index"-ish pages with no valuable content | |
| 43 | + GTK4_SKIP = %w( | |
| 44 | + gtk.html | |
| 45 | + gtk-resources.html gtk-question-index.html ch02s02.html | |
| 46 | + concepts.html | |
| 47 | + gtkobjects.html | |
| 48 | + Lists.html Trees.html Application.html Builder.html WindowWidgets.html | |
| 49 | + LayoutContainers.html LayoutManagers.html DisplayWidgets.html | |
| 50 | + MediaSupport.html ButtonWidgets.html NumericEntry.html | |
| 51 | + MenusAndCombos.html SelectorWidgets.html DrawingWidgets.html | |
| 52 | + Ornaments.html ScrollingWidgets.html Printing.html | |
| 53 | + ShortcutsOverview.html MiscObjects.html AbstractObjects.html | |
| 54 | + RecentDocuments.html ApplicationChoosing.html Gestures.html ch36.html | |
| 55 | + ch37.html | |
| 56 | + gtkbase.html | |
| 57 | + theming.html | |
| 58 | + migrating.html | |
| 59 | + ch41s02.html ch41s03.html | |
| 60 | + pt07.html | |
| 61 | + platform-support.html | |
| 62 | + api-index-full.html | |
| 63 | + annotation-glossary.html | |
| 64 | + ) | |
| 65 | + | |
| 66 | + GTK4_SKIP_PATTERNS = [ | |
| 67 | + /migrating/, /ch03/, /ch09/, /ch10/ | |
| 68 | + ] | |
| 69 | + | |
| 70 | + options[:attribution] = <<-HTML | |
| 71 | + © 2005–2020 The GNOME Project<br> | |
| 72 | + Licensed under the GNU Lesser General Public License version 2.1 or later. | |
| 73 | + HTML | |
| 74 | + | |
| 75 | + version '4.0' do | |
| 76 | + self.release = '4.0.0' | |
| 77 | + self.base_url = "https://developer.gnome.org/gtk4/#{self.version}/" | |
| 78 | + | |
| 79 | + options[:root_title] = 'GTK 4 Reference Manual' | |
| 80 | + options[:skip] = GTK4_SKIP | |
| 81 | + options[:skip_patterns] = GTK4_SKIP_PATTERNS | |
| 82 | + end | |
| 83 | + | |
| 84 | + version '3.24' do | |
| 85 | + self.release = '3.24.24' | |
| 86 | + self.base_url = "https://developer.gnome.org/gtk3/#{self.version}/" | |
| 87 | + | |
| 88 | + options[:root_title] = 'GTK+ 3 Reference Manual' | |
| 89 | + options[:skip] = GTK3_SKIP | |
| 90 | + options[:skip_patterns] = GTK3_SKIP_PATTERNS | |
| 91 | + end | |
| 92 | + | |
| 93 | + version '3.22' do | |
| 94 | + self.release = '3.22.3' | |
| 95 | + self.base_url = "https://developer.gnome.org/gtk3/#{self.version}/" | |
| 96 | + | |
| 97 | + options[:root_title] = 'GTK+ 3 Reference Manual' | |
| 98 | + options[:skip] = GTK3_SKIP | |
| 99 | + options[:skip_patterns] = GTK3_SKIP_PATTERNS | |
| 100 | + end | |
| 101 | + | |
| 102 | + version '3.20' do | |
| 103 | + self.release = '3.20.4' | |
| 104 | + self.base_url = "https://developer.gnome.org/gtk3/#{self.version}/" | |
| 105 | + | |
| 106 | + options[:root_title] = 'GTK+ 3 Reference Manual' | |
| 107 | + options[:skip] = GTK3_SKIP | |
| 108 | + options[:skip_patterns] = GTK3_SKIP_PATTERNS | |
| 109 | + end | |
| 110 | + | |
| 111 | + def get_latest_version(opts) | |
| 112 | + tags = get_gitlab_tags('gitlab.gnome.org', 'GNOME', 'gtk', opts) | |
| 113 | + tags[0]['name'] | |
| 114 | + end | |
| 115 | + end | |
| 116 | +end | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1 @@ | ||
| 1 | +https://www.gtk.org/assets/img/logo-gtk-sm.png | |