diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 38b70c8f3..447029722 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -14,7 +14,6 @@ defmodule ExDoc.Formatter.HTML do File.rm_rf! output :ok = File.mkdir_p output - generate_index(output, config) generate_assets(output, config) has_readme = config.readme && generate_readme(output, modules, config) @@ -23,22 +22,29 @@ defmodule ExDoc.Formatter.HTML do exceptions = filter_list(:exceptions, all) protocols = filter_list(:protocols, all) - generate_overview(modules, exceptions, protocols, output, config) - generate_list(:modules, modules, all, output, config, has_readme) - generate_list(:exceptions, exceptions, all, output, config, has_readme) - generate_list(:protocols, protocols, all, output, config, has_readme) + generate_overview(modules, exceptions, protocols, output, config, has_readme) + generate_sidebar_items(modules, exceptions, protocols, output) + generate_list(modules, all, output, config, has_readme) + generate_list(exceptions, all, output, config, has_readme) + generate_list(protocols, all, output, config, has_readme) Path.join(config.output, "index.html") end - defp generate_index(output, config) do - content = Templates.index_template(config) - :ok = File.write("#{output}/index.html", content) + defp generate_overview(modules, exceptions, protocols, output, config, has_readme) do + content = Templates.overview_template(config, modules, exceptions, protocols, has_readme) + + if has_readme do + :ok = File.write("#{output}/overview.html", content) + else + :ok = File.write("#{output}/index.html", content) + end end - defp generate_overview(modules, exceptions, protocols, output, config) do - content = Templates.overview_template(config, modules, exceptions, protocols) - :ok = File.write("#{output}/overview.html", content) + defp generate_sidebar_items(modules, exceptions, protocols, output) do + input = for node <- [%{id: "modules", value: modules}, %{id: "exceptions", value: exceptions}, %{id: "protocols", value: protocols}], !Enum.empty?(node.value), do: node + content = Templates.sidebar_items_template(input) + :ok = File.write("#{output}/sidebar_items.js", content) end defp assets do @@ -66,7 +72,7 @@ defmodule ExDoc.Formatter.HTML do defp write_readme(output, {:ok, content}, modules, config) do content = Autolink.project_doc(content, modules) readme_html = Templates.readme_template(config, content) |> pretty_codeblocks - File.write("#{output}/README.html", readme_html) + File.write("#{output}/index.html", readme_html) true end @@ -110,14 +116,12 @@ defmodule ExDoc.Formatter.HTML do Enum.filter nodes, &match?(%ExDoc.ModuleNode{type: x} when x in [:protocol], &1) end - defp generate_list(scope, nodes, all, output, config, has_readme) do - Enum.each nodes, &generate_module_page(&1, all, output, config) - content = Templates.list_page(scope, nodes, config, has_readme) - File.write("#{output}/#{scope}_list.html", content) + defp generate_list(nodes, all, output, config, has_readme) do + Enum.each nodes, &generate_module_page(&1, all, output, config, has_readme) end - defp generate_module_page(node, modules, output, config) do - content = Templates.module_page(node, config, modules) + defp generate_module_page(node, modules, output, config, has_readme) do + content = Templates.module_page(node, config, modules, has_readme) File.write("#{output}/#{node.id}.html", content) end diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index 11c1200a3..7d48b1251 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -8,19 +8,12 @@ defmodule ExDoc.Formatter.HTML.Templates do @doc """ Generate content from the module template for a given `node` """ - def module_page(node, config, all) do + def module_page(node, config, all, has_readme) do types = node.typespecs functions = Enum.filter node.docs, &match?(%ExDoc.FunctionNode{type: :def}, &1) macros = Enum.filter node.docs, &match?(%ExDoc.FunctionNode{type: :defmacro}, &1) callbacks = Enum.filter node.docs, &match?(%ExDoc.FunctionNode{type: :defcallback}, &1) - module_template(config, node, types, functions, macros, callbacks, all) - end - - @doc """ - Generates the listing. - """ - def list_page(scope, nodes, config, has_readme) do - list_template(scope, nodes, config, has_readme) + module_template(config, node, types, functions, macros, callbacks, all, has_readme) end # Get the full specs from a function, already in HTML form. @@ -109,16 +102,19 @@ defmodule ExDoc.Formatter.HTML.Templates do end templates = [ - index_template: [:config], - list_template: [:scope, :nodes, :config, :has_readme], - overview_template: [:config, :modules, :exceptions, :protocols], - module_template: [:config, :module, :types, :functions, :macros, :callbacks, :all], + overview_template: [:config, :modules, :exceptions, :protocols, :has_readme], + sidebar_template: [:config, :has_readme], + sidebar_items_template: [:input], + sidebar_items_keys_template: [:node], + sidebar_items_entry_template: [:node], + module_template: [:config, :module, :types, :functions, :macros, :callbacks, :all, :has_readme], readme_template: [:config, :content], - list_item_template: [:node], overview_entry_template: [:node], summary_template: [:node], detail_template: [:node, :_module], type_detail_template: [:node, :_module], + head_template: [:page], + footer_template: [] ] Enum.each templates, fn({ name, args }) -> diff --git a/lib/ex_doc/formatter/html/templates/css/full_list.css b/lib/ex_doc/formatter/html/templates/css/full_list.css deleted file mode 100644 index 64cf934bd..000000000 --- a/lib/ex_doc/formatter/html/templates/css/full_list.css +++ /dev/null @@ -1,215 +0,0 @@ -/*** DOCUMENT STRUCTURE: list_template.eex *** -body.frames - section#content [.in_search] - h1#full_list_header - h2#sub_list_header - div#nav - div#search [.loading] > input#search_field - ul#full_list - li.node [.collpased, .search_uncollapsed, .found] - a.toggle - a.object_link - span.node_name - li.docs [.collpased, .search_uncollapsed, .found] - a.toggle - a.object_link - span.node_name - ... - div.no_results -*/ - -/* DOCUMENT STYLES */ -body { - font: 13px "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; - height: 101%; - margin: 0; - overflow-x: hidden; -} -h1 { - font-size: 1.4em; - margin: 0; - padding: 12px 10px 0; -} -a:link, a:visited { - color: #05a; - text-decoration: none; -} -li { - color: #888; - cursor: pointer; -} -li:hover { - background: #ddd; -} -span.node_name { - font-size: 0.8em; -} - -/*** LEFT FRAME ***/ -.frames li { - white-space: nowrap; - cursor: default; -} - -/* HEADERS */ -.frames h1 { - margin-top: 0; -} -.frames h2 { - font-size: 0.9em; - margin: 5px 10px 15px; -} - -/* NAVIGATION BAR */ -.nav { - margin: 0 0 10px 5px; - font-size: 0.9em; - color: #aaa; -} -.nav a:link, -.nav a:visited { - color: #358; -} -.nav a:hover { - background: transparent; - color: #5af; -} -.nav span { - border-left: 1px solid #ccc; - padding: 0 3px 0 5px; -} -.nav span:first-child { - border-left: 0; - border-radius: 3px; -} -.nav span.selected { - text-decoration: underline; -} - -/* SEARCH BOX */ -#search { - font-size: 0.9em; - color: #888; - margin: 3px; margin-left: 10px; - padding-left: 0; padding-right: 24px; -} -#search_field { - width: 180px; - margin-right:35px; - border:2px solid #d8d8e5; - padding:2px 4px; - -moz-box-sizing: border-box; -} -#search.loading { - background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat 188px center; - min-height:18px; -} -#content #no_results { - margin-left: 7px; - padding: 7px 12px; -} - -/* FULL LIST OF CONTENTS */ -#full_list { - list-style: none; - margin-left: 0; - padding: 0; -} -#full_list ul { - margin:0; - padding: 0; -} -#full_list li { - margin: 0; - padding: 5px 5px 5px 0; - font-size: 1.1em; - list-style: none; -} -#full_list li.node { - padding-left: 25px; -} -#full_list li.docs { - padding:0; -} -#full_list li.docs li { - padding-left: 25px; -} -#full_list li span.node_name { - display: none; -} -#full_list .no_padding { - padding-left:0; -} -/* while searching */ -.in_search #full_list ul { - margin-left:0;} -.in_search #full_list li { - display: none; -} -.in_search #full_list li.found { - display: list-item; -} -.in_search #full_list li a.toggle { - display: none; -} -.in_search #full_list li span.node_name { - display: block; -} -/* collapsed menu */ -#full_list .search_uncollapsed, -#full_list .search_uncollapsed ul { - display:block !important; -} -#full_list ul.collapsed ul, -#full_list ul.collapsed li, -#full_list li.collapsed ul, -#full_list li.collapsed li { - display: none; -} -#full_list ul.search_uncollapsed li.found, -#full_list li.search_uncollapsed li.found { - display: list-item; -} -li.deprecated { - text-decoration: line-through; - font-style: italic; -} -li.r1 { - background: #f0f0f0; -} -li.r2 { - background: #fafafa; -} -/* link properties */ -li a.toggle { - display: block; - float: left; - position: relative; - left: -5px; - top: 4px; - width: 10px; - height: 9px; - margin-left: -10px; - text-indent: -999px; - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; - cursor: default; -} -li.collapsed a.toggle { - opacity: 0.5; - cursor: default; - background-position: top left; -} -li.clicked { - background: #05a; - color: #ccc; -} -li.clicked a:link, li.clicked a:visited { - color: #eee; -} -li.clicked a.toggle { - opacity: 0.5; - background-position: bottom right; -} -li.collapsed.clicked a.toggle { - background-position: top right; -} diff --git a/lib/ex_doc/formatter/html/templates/css/normalize.css b/lib/ex_doc/formatter/html/templates/css/normalize.css new file mode 100644 index 000000000..458eea1ea --- /dev/null +++ b/lib/ex_doc/formatter/html/templates/css/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/lib/ex_doc/formatter/html/templates/css/style.css b/lib/ex_doc/formatter/html/templates/css/style.css index 59dc0daf4..3b5b1fa60 100644 --- a/lib/ex_doc/formatter/html/templates/css/style.css +++ b/lib/ex_doc/formatter/html/templates/css/style.css @@ -1,15 +1,29 @@ /*** DOCUMENT STRUCTURE: module_template.eex *** body + section#sidebar [.in_search] + h1#full_list_header + h2#sub_list_header + div#nav + div#search [.loading] > input#search_field + ul#full_list + li.node [.collpased, .search_uncollapsed, .found] + a.toggle + a.object_link + span.node_name + li.docs [.collpased, .search_uncollapsed, .found] + a.toggle + a.object_link + span.node_name + ... + div.no_results + section#content div.breadcrumbs - h1 small - ul.summary_links li > a ... - section.docstring#moduledoc a.view_source @@ -19,7 +33,6 @@ body td.summary_signature > a td.summary_synopsis > p ... - section.details_list#types_details h2 > a.to_top_link div.type_detail @@ -44,32 +57,288 @@ body */ +@import "normalize.css"; + /* DOCUMENT STYLES */ + body { font: 13px "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; - padding: 0 20px; + padding: 0; + margin: 0; + line-height: 1.618; +} + +#sidebar h1 { + font-size: 1.4em; + margin: 0; + padding: 12px 10px 0; +} + +#sidebar a:link, +#sidebar a:visited { + color: #05a; + text-decoration: none; +} + +#sidebar li { + color: #888; + cursor: pointer; +} + +#sidebar li:hover { + background: #ddd; +} + +#sidebar span.node_name { + font-size: 0.8em; +} + +#sidebar li { + white-space: nowrap; + cursor: default; +} + + +/* HEADERS */ + +#sidebar h1 { + margin-top: 0; +} + +#sidebar h2 { + font-size: 0.9em; + margin: 5px 10px 15px; +} + + +/* NAVIGATION BAR */ + +.nav { + margin: 0 0 10px 5px; + font-size: 0.9em; + color: #aaa; +} + +.nav a:link, +.nav a:visited { + color: #358; +} + +.nav a:hover { + background: transparent; + color: #5af; +} + +.nav span { + border-left: 1px solid #ccc; + padding: 0 3px 0 5px; +} + +.nav span:first-child { + border-left: 0; + border-radius: 3px; +} + +.nav span.selected { + background-color: #f0f0f0; + color: #05a; +} + + +/* SEARCH BOX */ + +#search { + font-size: 0.9em; + color: #888; + margin: 3px; + margin-left: 10px; + padding-left: 0; + padding-right: 24px; +} + +#search_field { + width: 180px; + margin-right: 35px; + border: 2px solid #d8d8e5; + padding: 2px 4px; + -moz-box-sizing: border-box; +} + +#search.loading { + background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat 188px center; + min-height: 18px; +} + +#no_results { + margin-left: 7px; + padding: 7px 12px; +} + + +/* FULL LIST OF CONTENTS */ + +#full_list { + list-style: none; + margin-left: 0; + padding: 0; +} + +#full_list ul { + margin: 0; + padding: 0; +} + +#full_list li { + margin: 0; + padding: 5px 5px 5px 0; + font-size: 1.1em; + list-style: none; +} + +#full_list li.node { + padding-left: 25px; +} + +#full_list li.docs { + padding: 0; +} + +#full_list li.docs li { + padding-left: 25px; +} + +#full_list li span.node_name { + display: none; +} + +#full_list .no_padding { + padding-left: 0; +} + + +/* while searching */ + +.in_search #full_list ul { + margin-left: 0; +} + +.in_search #full_list li { + display: none; +} + +.in_search #full_list li.found { + display: list-item; +} + +.in_search #full_list li a.toggle { + display: none; +} + +.in_search #full_list li span.node_name { + display: block; +} + + +/* collapsed menu */ + +#full_list .search_uncollapsed, +#full_list .search_uncollapsed ul { + display: block !important; +} + +#full_list ul.collapsed ul, +#full_list ul.collapsed li, +#full_list li.collapsed ul, +#full_list li.collapsed li { + display: none; +} + +#full_list ul.search_uncollapsed li.found, +#full_list li.search_uncollapsed li.found { + display: list-item; +} + +#full_list li.deprecated { + text-decoration: line-through; + font-style: italic; +} + +#full_list li.r1 { + background: #f0f0f0; +} + +#full_list li.r2 { + background: #fafafa; +} + + +/* link properties */ + +#full_list li a.toggle { + display: block; + float: left; + position: relative; + left: -5px; + top: 4px; + width: 10px; + height: 9px; + margin-left: -10px; + text-indent: -999px; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; + cursor: default; +} + +#full_list li.collapsed a.toggle { + opacity: 0.5; + cursor: default; + background-position: top left; +} + +#full_list li.clicked { + background: #05a; + color: #ccc; +} + +#full_list li.clicked a:link, +#full_list li.clicked a:visited { + color: #eee; +} + +#full_list li.clicked a.toggle { + opacity: 0.5; + background-position: bottom right; } +#full_list li.collapsed.clicked a.toggle { + background-position: top right; +} + + +/* DOCUMENT STYLES */ + a:link, a:visited { color: #05a; text-decoration: none; } + a:hover { color: #27c; } -h1 { +h1:not(#full_list_header) { font-size: 25px; border-top: 0; margin-top: 0; padding-top: 4px; } + h1 small { color: #888; font-size: 18px; } -h2 { + +h2:not(#sub_list_header) { padding: 0; padding-bottom: 3px; border-bottom: 1px #aaa solid; @@ -86,40 +355,47 @@ table { border-collapse: collapse; margin-top: 1em; } + table th { background: #fafafa; } + table th, table td { border: 1px solid #ddd; padding: 0.4em 1em 0.4em 0.4em; } + table tr:nth-child(odd) { background: #f0f0f0; } + table tr:nth-child(even) { background: #fafafa; } + /* OTHERS */ -body.frames { - padding: 0 5px; -} + li.r1 { background: #f0f0f0; } + li.r2 { background: #fafafa; } + div.breadcrumbs { padding-bottom: 0.5em; } /* SUMMARY LINKS */ + ul.summary_links { margin: 0 0 1em 0; padding: 0em; } + ul.summary_links li { display: inline-block; list-style-type: none; @@ -128,11 +404,14 @@ ul.summary_links li { background: #f0f0f0; } + /* DOCSTRING */ + section.docstring, p.docstring { margin-right: 6em; } + .docstring h1, .docstring h2, .docstring h3, @@ -140,80 +419,105 @@ p.docstring { padding: 0; border: 0; } + .docstring h1 { font-size: 1.3em; } + .docstring h2 { font-size: 1.2em; } + .docstring h3, .docstring h4 { font-size: 1em; padding-top: 10px; } + .docstring ul { padding-left: 20px; } + .docstring li > p { margin: 0; } + /* SUMMARY */ + div.detail_header_links { float: right; } + a.to_top_link { padding-left: 0.3em; font-size: 1em; font-weight: normal; } + table.summary { border: 0; border-collapse: separate; } + table.summary tr:nth-child(odd) { background: #f0f0f0; } + table.summary tr:nth-child(even) { background: #fafafa; } + table.summary tr td { border: 0; - padding-top: 0.5em; padding-bottom: 0.5em; + padding-top: 0.5em; + padding-bottom: 0.5em; } + td.summary_signature { padding-right: 0.5em; } + td.summary_synopsis { padding-left: 0.5em; } + td.summary_synopsis p { margin: 0; } + /* DETAILS LIST */ -.spec, .typespec { + +.spec, +.typespec { font: bold 1em Courier, monospace; } + ul.spec { padding: 6px 10px 6px 25px; list-style-type: none; } + .type_detail { margin-top: 15px; padding-top: 0; } + .type_detail > div.typespec_doc { margin-left: 3em; } + .detail { border-top: 1px dotted #aaa; margin-top: 15px; padding-top: 0; } + .detail:nth-child(2) { border: 0; } + div.detail_header { background: #e5e8ff; border: 1px solid #d8d8e5; @@ -221,19 +525,58 @@ div.detail_header { margin-top: 18px; padding: 6px 10px; } + span.signature { font: normal 1.1em Monaco, Consolas, Courier, monospace; } + span.detail_type { font-style: italic; font-size: 0.9em; } + a.detail_link { padding-left: 0.3em; } -/* CUSTOMIZATION FOR elixir.css */ +/* Layout */ + +#sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + overflow-y: auto; + overflow-x: hidden; + border-right: 1px solid #ccc; + width: 250px; + padding: 5px; + background: #fff; + box-sizing: border-box; +} + +#content { + position: fixed; + top: 0; + bottom: 0; + right: 0; + left: 255px; + overflow: auto; + padding: 5px; + box-sizing: border-box; +} + + +/* Media print */ + +@media print { + #sidebar { + display: none; + } +} + +/* CUSTOMIZATION FOR elixir.css */ .hljs { background: #fffde8; border: #ffe0bb dotted 1px; -} \ No newline at end of file +} diff --git a/lib/ex_doc/formatter/html/templates/footer_template.eex b/lib/ex_doc/formatter/html/templates/footer_template.eex new file mode 100644 index 000000000..279ddc1ee --- /dev/null +++ b/lib/ex_doc/formatter/html/templates/footer_template.eex @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/lib/ex_doc/formatter/html/templates/head_template.eex b/lib/ex_doc/formatter/html/templates/head_template.eex new file mode 100644 index 000000000..6ceb7f62e --- /dev/null +++ b/lib/ex_doc/formatter/html/templates/head_template.eex @@ -0,0 +1,20 @@ + + + + + + <%= cond do %> + <%= page.id == :module -> %> + <%= page.content %> + <%= page.id == :readme -> %> + <%= page.content.project %> v<%= page.content.version %> README + <%= page.id == :overview -> %> + <%= page.content.project %> v<%= page.content.version %> Overview + <% end %> + + + + + + + diff --git a/lib/ex_doc/formatter/html/templates/index_template.eex b/lib/ex_doc/formatter/html/templates/index_template.eex deleted file mode 100644 index 76e435a32..000000000 --- a/lib/ex_doc/formatter/html/templates/index_template.eex +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - <%= config.project %> v<%= config.version %> Documentation - - - - - - - diff --git a/lib/ex_doc/formatter/html/templates/js/app.js b/lib/ex_doc/formatter/html/templates/js/app.js index c2a5594e1..abda9cc9d 100644 --- a/lib/ex_doc/formatter/html/templates/js/app.js +++ b/lib/ex_doc/formatter/html/templates/js/app.js @@ -1,13 +1,353 @@ -;$(function () { +/*jslint browser: true, es5: true */ +/*globals $, hljs, sidebarNodes: true */ +(function () { + "use strict"; + + // full_list.js + var inSearch = null, + defaultSearchItemTimeOut = 0, //set to "0" if not testing + searchIndex = 0, + searchCache = [], + searchString = '', + regexSearchString = '', + caseSensitiveMatch = false, + ignoreKeyCodeMin = 8, + ignoreKeyCodeMax = 46, + commandKey = 91, + lastRowClass = '', + sidebarNav = $('.nav'), + clicked = null; + // Fix outside world links function fixOutsideWorldLinks() { - $('a').each(function() { - if (window.location.host != this.host) this.target = '_parent'; - }); + $('a').each(function () { + if (window.location.host !== this.host) { + this.target = '_parent'; + } + }); } fixOutsideWorldLinks(); + function escapeText(text) { + return text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + } + + function highlight(no_padding) { + var n = 1; + $('#full_list a.object_link:visible').each(function () { + var next = n === 1 ? 2 : 1, + li = $(this).parent(); + li.removeClass("r" + next).addClass("r" + n); + if (no_padding) { + li.addClass("no_padding"); + } else { + li.removeClass("no_padding"); + } + n = next; + }); + } + + function showAllResults() { + clearTimeout(inSearch); + inSearch = defaultSearchItemTimeOut; + $('.search_uncollapsed').removeClass('search_uncollapsed'); + $('#sidebar').removeClass('in_search'); + $('#full_list li').removeClass('found').each(function () { + var link = $(this).find('a.object_link:first'); + link.text(link.text()); + }); + if (clicked) { + clicked.parents('li').each(function () { + $(this).removeClass('collapsed').prev().removeClass('collapsed'); + }); + } + $('#no_results').text(''); + $('#search').removeClass('loading'); + highlight(); + } + + function searchDone() { + highlight(true); + if ($('#full_list li.found').size() === 0) { + $('#no_results').text('No results were found.').hide().fadeIn(); + } else { + $('#no_results').text(''); + } + + $('#search').removeClass('loading'); + clearTimeout(inSearch); + inSearch = null; + } + + function searchItem() { + var i, + item, + searchName, + matchString, + matchRegexp; + for (i = 0; i < searchCache.length / 50; i += 1) { + item = searchCache[searchIndex]; + searchName = (searchString.indexOf('.') !== -1 ? item.fullName : item.name); + matchString = regexSearchString; + matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); + + if (searchName.match(matchRegexp) === null) { + item.node.removeClass('found'); + } else { + item.node.addClass('found'); + item.node.parents('li').addClass('search_uncollapsed'); + item.node.removeClass(lastRowClass).addClass(lastRowClass === 'r1' ? 'r2' : 'r1'); + lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; + item.link.html(item.name.replace(matchRegexp, "$&")); + } + + if (searchCache.length === searchIndex + 1) { + searchDone(); + return; + } + searchIndex += 1; + } + inSearch = setTimeout(function () { + searchItem(); + }, defaultSearchItemTimeOut); + } + + function fullListSearch() { + // generate cache + searchCache = []; + $('#full_list li').each(function () { + var link = $(this).find('a.object_link:first'), + fullName; + if (link.attr('title')) { + fullName = link.attr('title').split(' ')[0]; + searchCache.push({ + name: link.text(), + fullName: fullName, + node: $(this), + link: link + }); + } + }); + + $('#search input').keypress(function (e) { + if (e.which === 13) { + $('#full_list li.found:first').find('a.object_link:first').click(); + } + }); + + $('#search input').bind("keyup search reset change propertychange input paste", function (evnt) { + if ((evnt.keyCode > ignoreKeyCodeMin && evnt.keyCode < ignoreKeyCodeMax) || evnt.keyCode === commandKey) { + return; + } + + $('#search').addClass('loading'); + searchString = this.value; + caseSensitiveMatch = searchString.match(/[A-Z]/) !== null; + regexSearchString = escapeText(searchString); + if (searchString === "") { + showAllResults(); + } else { + if (inSearch) { + clearTimeout(inSearch); + } + searchIndex = 0; + lastRowClass = ''; + $('#sidebar').addClass('in_search'); + $('#no_results').text(''); + searchItem(); + } + }); + + $('#search input').focus(); + } + + function linkList() { + $('#full_list li, #full_list li a:last').click(function (evt) { + var toggle, + win; + + if ($(this).hasClass('toggle')) { + return true; + } + + if (this.tagName.toLowerCase() === "li") { + toggle = $(this).children('a.toggle'); + if (toggle.size() > 0 && evt.pageX < toggle.offset().left) { + toggle.click(); + return false; + } + } + + if (clicked) { + clicked.removeClass('clicked'); + } + + win = window.top.frames.main || window.parent; + if (this.tagName.toLowerCase() === "a") { + clicked = $(this).parent('li').addClass('clicked'); + win.location = this.href; + } else { + clicked = $(this).addClass('clicked'); + win.location = $(this).find('a:last').attr('href'); + } + + return false; + }); + } + + function collapse() { + $('#full_list a.toggle').click(function () { + $(this).parent().toggleClass('collapsed').next().toggleClass('collapsed'); + highlight(); + return false; + }); + + $('#full_list > li.node').each(function () { + $(this).addClass('collapsed').next('li.docs').addClass('collapsed'); + }); + + highlight(); + } + + function escapeShortcut() { + $(document).keydown(function (evt) { + if (evt.which === 27) { + $('#search_frame', window.top.document).slideUp(100); + $('#search a', window.top.document).removeClass('active inactive'); + $(window.top).focus(); + } + }); + } + + $(escapeShortcut); + $(fullListSearch); + $(linkList); + $(collapse); + + /** + * Fill the sidebar with links to different nodes + * + * This function replace an empty unordered list with an + * an unordered list full of links to the different procotols, exceptions + * and modules mentioned in the documentation. + * + * @param {Object} nodes - Container of protocols, exceptions and modules. + * @param {String} filter - Filter of nodes, by default 'modules'. + */ + function fillSidebarWithNodes(nodes, filter) { + var full_list = $("#full_list"); + + function scope(items) { + var filtered = nodes[items], + fullList = $('