diff --git a/assets/javascripts/templates/pages/about_tmpl.coffee b/assets/javascripts/templates/pages/about_tmpl.coffee index 985155ae..f9b69e3b 100644 --- a/assets/javascripts/templates/pages/about_tmpl.coffee +++ b/assets/javascripts/templates/pages/about_tmpl.coffee @@ -631,6 +631,11 @@ credits = [ '2013-present Facebook Inc.', 'MIT', 'https://raw.githubusercontent.com/facebook/react/master/LICENSE' + ], [ + 'ReactiveX', + 'ReactiveX contributors', + 'Apache', + 'https://raw.githubusercontent.com/ReactiveX/reactivex.github.io/develop/LICENSE' ], [ 'Redis', '2009-2018 Salvatore Sanfilippo', diff --git a/assets/javascripts/vendor/prism.js b/assets/javascripts/vendor/prism.js index 9e886921..a01a207c 100644 --- a/assets/javascripts/vendor/prism.js +++ b/assets/javascripts/vendor/prism.js @@ -1,5 +1,5 @@ /* PrismJS 1.17.1 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+c+bash+cpp+coffeescript+ruby+d+dart+markup-templating+elixir+erlang+go+java+php+json+julia+kotlin+crystal+lua+django+matlab+typescript+nginx+nim+perl+sql+scss+python+jsx+rust+yaml */ +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+c+bash+cpp+coffeescript+ruby+d+dart+markup-templating+elixir+erlang+go+groovy+java+php+json+julia+kotlin+crystal+lua+django+matlab+typescript+nginx+nim+perl+sql+scss+python+jsx+rust+yaml */ var _self = (typeof window !== 'undefined') ? window // if in browser : ( @@ -1686,6 +1686,72 @@ Prism.languages.go = Prism.languages.extend('clike', { }); delete Prism.languages.go['class-name']; +Prism.languages.groovy = Prism.languages.extend('clike', { + 'keyword': /\b(?:as|def|in|abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/, + 'string': [ + { + pattern: /("""|''')[\s\S]*?\1|(?:\$\/)(?:\$\/\$|[\s\S])*?\/\$/, + greedy: true + }, + { + pattern: /(["'\/])(?:\\.|(?!\1)[^\\\r\n])*\1/, + greedy: true + } + ], + 'number': /\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?[\d]+)?)[glidf]?\b/i, + 'operator': { + pattern: /(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.{1,2}(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/, + lookbehind: true + }, + 'punctuation': /\.+|[{}[\];(),:$]/ +}); + +Prism.languages.insertBefore('groovy', 'string', { + 'shebang': { + pattern: /#!.+/, + alias: 'comment' + } +}); + +Prism.languages.insertBefore('groovy', 'punctuation', { + 'spock-block': /\b(?:setup|given|when|then|and|cleanup|expect|where):/ +}); + +Prism.languages.insertBefore('groovy', 'function', { + 'annotation': { + alias: 'punctuation', + pattern: /(^|[^.])@\w+/, + lookbehind: true + } +}); + +// Handle string interpolation +Prism.hooks.add('wrap', function(env) { + if (env.language === 'groovy' && env.type === 'string') { + var delimiter = env.content[0]; + + if (delimiter != "'") { + var pattern = /([^\\])(?:\$(?:\{.*?\}|[\w.]+))/; + if (delimiter === '$') { + pattern = /([^\$])(?:\$(?:\{.*?\}|[\w.]+))/; + } + + // To prevent double HTML-encoding we have to decode env.content first + env.content = env.content.replace(/</g, '<').replace(/&/g, '&'); + + env.content = Prism.highlight(env.content, { + 'expression': { + pattern: pattern, + lookbehind: true, + inside: Prism.languages.groovy + } + }); + + env.classes.push(delimiter === '/' ? 'regex' : 'gstring'); + } + } +}); + (function (Prism) { var keywords = /\b(?:abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while|var|null|exports|module|open|opens|provides|requires|to|transitive|uses|with)\b/; diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss index 22f539b7..c5fcc239 100644 --- a/assets/stylesheets/application.css.scss +++ b/assets/stylesheets/application.css.scss @@ -92,6 +92,7 @@ 'pages/ramda', 'pages/rdoc', 'pages/react_native', + 'pages/reactivex', 'pages/redis', 'pages/rethinkdb', 'pages/rfc', diff --git a/assets/stylesheets/pages/_reactivex.scss b/assets/stylesheets/pages/_reactivex.scss new file mode 100644 index 00000000..dd67b850 --- /dev/null +++ b/assets/stylesheets/pages/_reactivex.scss @@ -0,0 +1,51 @@ +._reactivex { + @extend %simple; + + img { + max-width: 50%; + } + + figure { + margin: 0; + } + + dfn { + cursor: text; + font-style: italic; + text-decoration: none; + border-bottom: none; + } + + #tree { + dt, dd { + font-weight: normal; + } + + dt { + float: left; + clear: left; + + margin-top: 0; + + &:before { + content: "\2026"; + } + } + + dd:not(.sub) { + float: left; + + margin: 0 0 0 5px; + padding: 0; + } + + dl#outer > dt { + font-weight: bold; + margin-top: 5px; + + & + dd { + margin-top: 5px; + } + } + } +} diff --git a/lib/docs/core/doc.rb b/lib/docs/core/doc.rb index da21daf8..a5268300 100644 --- a/lib/docs/core/doc.rb +++ b/lib/docs/core/doc.rb @@ -262,5 +262,11 @@ module Docs json = fetch_json("https://api.github.com/repos/#{owner}/#{repo}/contents/#{path}", opts) Base64.decode64(json['content']) end + + def get_latest_github_commit_date(owner, repo, opts) + commits = fetch_json("https://api.github.com/repos/#{owner}/#{repo}/commits", opts) + timestamp = commits[0]['commit']['author']['date'] + Date.iso8601(timestamp).to_time.to_i + end end end diff --git a/lib/docs/filters/reactivex/clean_html.rb b/lib/docs/filters/reactivex/clean_html.rb new file mode 100644 index 00000000..e8a209af --- /dev/null +++ b/lib/docs/filters/reactivex/clean_html.rb @@ -0,0 +1,96 @@ +module Docs + class Reactivex + class CleanHtmlFilter < Filter + def call + # Can't use options[:container] because then the navigation bar wouldn't be scraped + @doc = at_css(root_page? ? '.col-md-8' : '.col-sm-8') + + # Remove breadcrumbs + css('.breadcrumb').remove + + # Titleize title on Backpressure Operators page + if subpath == 'documentation/operators/backpressure.html' + title = at_css('h1') + title.content = title.content.titleize + end + + # Lower all h1 headers except the first one + css('* + h1').each do |node| + node.name = 'h2' + end + + # Pull code blocks in links out of their parent (if possible) + css('a > strong > code').each do |node| + # Skip if the parent had multiple code nodes and node.parent.replace already ran for one + next unless node.parent.name == 'strong' + + node.parent.replace node.parent.children + end + + # Pull header out of trees + tree = at_css('#tree') + unless tree.nil? + title = tree.at_css('h1') + title.name = 'h2' + tree.before(title) + end + + # Beautify operator descriptions + at_css('h3').name = 'blockquote' if subpath.include?('operators/') + + # Replace interactive demo's with links to them + css('rx-marbles').each do |node| + node.name = 'a' + node.content = 'Open interactive diagram on rxmarbles.com' + node['href'] = "https://rxmarbles.com/##{node['key']}" + node.remove_attribute('key') + end + + # Syntax-highlighted code blocks + css('.code').each do |node| + language = node['class'].gsub('code', '').strip + + pre = node.at_css('pre') + pre['data-language'] = language + pre.content = pre.content.strip + + node.replace(pre) + end + + # Assume JavaScript syntax for code blocks not surrounded by a div.code + css('pre').each do |node| + next if node['data-language'] + + node.content = node.content.strip + node['data-language'] = 'javascript' + end + + # Make language specific implementation titles prettier + css('.panel-title').each do |node| + # Remove the link, keep the children + link = node.at_css('a') + link.replace(link.children) unless link.nil? + + # Transform it into a header for better styling + node.name = 'h3' + end + + # Remove language specific implementations that are TBD + css('span').each do |node| + next unless node.content == 'TBD' + node.xpath('./ancestor::div[contains(@class, "panel-default")][1]').remove + end + + # Remove the : at the end of "Language-Specific Information:" + css('h2').each do |node| + node.inner_html = node.inner_html.gsub('Information:', 'Information') + end + + # Remove attributes to reduce file size + css('div').remove_attr('class') + + doc + end + end + end +end diff --git a/lib/docs/filters/reactivex/entries.rb b/lib/docs/filters/reactivex/entries.rb new file mode 100644 index 00000000..4a6b08e9 --- /dev/null +++ b/lib/docs/filters/reactivex/entries.rb @@ -0,0 +1,21 @@ +module Docs + class Reactivex + class EntriesFilter < Docs::EntriesFilter + def get_name + title = at_css('h1').content + title = title.titleize if is_backpressure_operators? + title + end + + def get_type + return 'Manual' if is_backpressure_operators? + links = css('.breadcrumb > li:nth-child(2) > a') + links.size > 0 ? links.first.content : 'Manual' + end + + def is_backpressure_operators? + subpath == 'documentation/operators/backpressure.html' + end + end + end +end diff --git a/lib/docs/scrapers/reactivex.rb b/lib/docs/scrapers/reactivex.rb new file mode 100644 index 00000000..007ae00f --- /dev/null +++ b/lib/docs/scrapers/reactivex.rb @@ -0,0 +1,27 @@ +module Docs + class Reactivex < UrlScraper + self.name = 'ReactiveX' + self.type = 'reactivex' + self.base_url = 'http://reactivex.io/' + self.root_path = 'intro.html' + self.links = { + home: 'http://reactivex.io/' + } + + html_filters.push 'reactivex/entries', 'reactivex/clean_html' + + options[:download_images] = false + + options[:only_patterns] = [/documentation\//] + options[:skip_patterns] = [/ko\//] + + options[:attribution] = <<-HTML + © ReactiveX contributors
+ Licensed under the Apache License 2.0. + HTML + + def get_latest_version(opts) + get_latest_github_commit_date('ReactiveX', 'reactivex.github.io', opts) + end + end +end diff --git a/public/icons/docs/reactivex/16.png b/public/icons/docs/reactivex/16.png new file mode 100644 index 00000000..790f8390 Binary files /dev/null and b/public/icons/docs/reactivex/16.png differ diff --git a/public/icons/docs/reactivex/16@2x.png b/public/icons/docs/reactivex/16@2x.png new file mode 100644 index 00000000..a45cd5cb Binary files /dev/null and b/public/icons/docs/reactivex/16@2x.png differ diff --git a/public/icons/docs/reactivex/SOURCE b/public/icons/docs/reactivex/SOURCE new file mode 100644 index 00000000..f9c25e1e --- /dev/null +++ b/public/icons/docs/reactivex/SOURCE @@ -0,0 +1 @@ +https://github.com/ReactiveX/reactivex.github.io/blob/develop/assets/Rx_Icon.png