##// END OF EJS Templates
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
marcink -
r4221:654aa611 stable
parent child Browse files
Show More
@@ -1,41 +1,45 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2018-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 def includeme(config):
23 23
24 24 config.add_route(
25 25 name='hovercard_user',
26 26 pattern='/_hovercard/user/{user_id}')
27 27
28 28 config.add_route(
29 name='hovercard_username',
30 pattern='/_hovercard/username/{username}')
31
32 config.add_route(
29 33 name='hovercard_user_group',
30 34 pattern='/_hovercard/user_group/{user_group_id}')
31 35
32 36 config.add_route(
33 37 name='hovercard_pull_request',
34 38 pattern='/_hovercard/pull_request/{pull_request_id}')
35 39
36 40 config.add_route(
37 41 name='hovercard_repo_commit',
38 42 pattern='/_hovercard/commit/{repo_name:.*?[^/]}/{commit_id}', repo_route=True)
39 43
40 44 # Scan module for configuration decorators.
41 45 config.scan('.views', ignore='.tests')
@@ -1,110 +1,123 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import re
22 22 import logging
23 23 import collections
24 24
25 25 from pyramid.httpexceptions import HTTPNotFound
26 26 from pyramid.view import view_config
27 27
28 28 from rhodecode.apps._base import BaseAppView, RepoAppView
29 29 from rhodecode.lib import helpers as h
30 30 from rhodecode.lib.auth import (
31 31 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired,
32 32 HasRepoPermissionAnyDecorator)
33 33 from rhodecode.lib.codeblocks import filenode_as_lines_tokens
34 34 from rhodecode.lib.index import searcher_from_config
35 35 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
36 36 from rhodecode.lib.ext_json import json
37 37 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError, EmptyRepositoryError
38 38 from rhodecode.lib.vcs.nodes import FileNode
39 39 from rhodecode.model.db import (
40 40 func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup, PullRequest)
41 41 from rhodecode.model.repo import RepoModel
42 42 from rhodecode.model.repo_group import RepoGroupModel
43 43 from rhodecode.model.scm import RepoGroupList, RepoList
44 44 from rhodecode.model.user import UserModel
45 45 from rhodecode.model.user_group import UserGroupModel
46 46
47 47 log = logging.getLogger(__name__)
48 48
49 49
50 50 class HoverCardsView(BaseAppView):
51 51
52 52 def load_default_context(self):
53 53 c = self._get_local_tmpl_context()
54 54 return c
55 55
56 56 @LoginRequired()
57 57 @view_config(
58 58 route_name='hovercard_user', request_method='GET', xhr=True,
59 59 renderer='rhodecode:templates/hovercards/hovercard_user.mako')
60 60 def hovercard_user(self):
61 61 c = self.load_default_context()
62 62 user_id = self.request.matchdict['user_id']
63 63 c.user = User.get_or_404(user_id)
64 64 return self._get_template_context(c)
65 65
66 66 @LoginRequired()
67 67 @view_config(
68 route_name='hovercard_username', request_method='GET', xhr=True,
69 renderer='rhodecode:templates/hovercards/hovercard_user.mako')
70 def hovercard_username(self):
71 c = self.load_default_context()
72 username = self.request.matchdict['username']
73 c.user = User.get_by_username(username)
74 if not c.user:
75 raise HTTPNotFound()
76
77 return self._get_template_context(c)
78
79 @LoginRequired()
80 @view_config(
68 81 route_name='hovercard_user_group', request_method='GET', xhr=True,
69 82 renderer='rhodecode:templates/hovercards/hovercard_user_group.mako')
70 83 def hovercard_user_group(self):
71 84 c = self.load_default_context()
72 85 user_group_id = self.request.matchdict['user_group_id']
73 86 c.user_group = UserGroup.get_or_404(user_group_id)
74 87 return self._get_template_context(c)
75 88
76 89 @LoginRequired()
77 90 @view_config(
78 91 route_name='hovercard_pull_request', request_method='GET', xhr=True,
79 92 renderer='rhodecode:templates/hovercards/hovercard_pull_request.mako')
80 93 def hovercard_pull_request(self):
81 94 c = self.load_default_context()
82 95 c.pull_request = PullRequest.get_or_404(
83 96 self.request.matchdict['pull_request_id'])
84 97 perms = ['repository.read', 'repository.write', 'repository.admin']
85 98 c.can_view_pr = h.HasRepoPermissionAny(*perms)(
86 99 c.pull_request.target_repo.repo_name)
87 100 return self._get_template_context(c)
88 101
89 102
90 103 class HoverCardsRepoView(RepoAppView):
91 104 def load_default_context(self):
92 105 c = self._get_local_tmpl_context()
93 106 return c
94 107
95 108 @LoginRequired()
96 109 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin')
97 110 @view_config(
98 111 route_name='hovercard_repo_commit', request_method='GET', xhr=True,
99 112 renderer='rhodecode:templates/hovercards/hovercard_repo_commit.mako')
100 113 def hovercard_repo_commit(self):
101 114 c = self.load_default_context()
102 115 commit_id = self.request.matchdict['commit_id']
103 116 pre_load = ['author', 'branch', 'date', 'message']
104 117 try:
105 118 c.commit = self.rhodecode_vcs_repo.get_commit(
106 119 commit_id=commit_id, pre_load=pre_load)
107 120 except (CommitDoesNotExistError, EmptyRepositoryError):
108 121 raise HTTPNotFound()
109 122
110 123 return self._get_template_context(c)
@@ -1,405 +1,406 b''
1 1 all_tags = [
2 2 "a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio",
3 3 "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br", "button",
4 4 "canvas", "caption", "center", "cite", "code", "col", "colgroup", "command", "content",
5 5 "data", "datalist", "dd", "del", "detals", "dfn", "dialog", "dir", "div", "dl", "dt",
6 6 "element", "em", "embed",
7 7 "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset",
8 8 "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html",
9 9 "i", "iframe", "image", "img", "input", "ins", "isindex",
10 10 "kbd", "keygen",
11 11 "label", "legend", "li", "link", "listing",
12 12 "main", "map", "mark", "marquee", "menu", "menuitem", "meta", "meter", "multicol",
13 13 "nav", "nobr", "noembed", "noframes", "noscript",
14 14 "object", "ol", "optgroup", "option", "output",
15 15 "p", "param", "picture", "plaintext", "pre", "progress",
16 16 "q",
17 17 "rp", "rt", "ruby",
18 18 "s", "samp", "script", "section", "select", "shadow", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup",
19 19 "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt",
20 20 "u", "ul",
21 21 "var", "video",
22 22 "wbr",
23 23 "xmp",
24 24 ]
25 25
26 26 # List tags that, if included in a page, could break markup or open XSS.
27 27 generally_xss_unsafe = [
28 28 "applet", "audio",
29 29 "bgsound", "body",
30 30 "canvas",
31 31 "embed",
32 32 "frame", "frameset",
33 33 "head", "html",
34 34 "iframe",
35 35 "link",
36 36 "meta",
37 37 "object",
38 38 "param",
39 39 "source", "script",
40 40 "ruby", "rt",
41 41 "title", "track",
42 42 "video",
43 43 "xmp"
44 44 ]
45 45
46 46 # Tags that, if included on the page, will probably not break markup or open
47 47 # XSS. Note that these must be combined with attribute whitelisting, or things
48 48 # like <img> and <style> could still be unsafe.
49 49 generally_xss_safe = list(set(all_tags) - set(generally_xss_unsafe))
50 50 generally_xss_safe.sort()
51 51
52 52 # Tags suitable for rendering markdown
53 53 markdown_tags = [
54 54 "h1", "h2", "h3", "h4", "h5", "h6",
55 55 "b", "i", "strong", "em", "tt",
56 56 "p", "br",
57 57 "span", "div", "blockquote", "code", "hr", "pre", "del",
58 58 "ul", "ol", "li",
59 59 "dl", "dd", "dt",
60 60 "table", "thead", "tbody", "tfoot", "tr", "th", "td",
61 61 "img",
62 62 "a",
63 63 "input",
64 64 ]
65 65
66 66 markdown_attrs = {
67 67 "*": ["class", "style", "align"],
68 68 "img": ["src", "alt", "title"],
69 "a": ["href", "alt", "title", "name"],
69 "a": ["href", "alt", "title", "name", "data-hovercard-alt", "data-hovercard-url"],
70 70 "abbr": ["title"],
71 71 "acronym": ["title"],
72 72 "pre": ["lang"],
73 "input": ["type", "disabled", "checked"]
73 "input": ["type", "disabled", "checked"],
74 "strong": ["title", "data-hovercard-alt", "data-hovercard-url"],
74 75 }
75 76
76 77 standard_styles = [
77 78 # Taken from https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
78 79 # This includes pseudo-classes, pseudo-elements, @-rules, units, and
79 80 # selectors in addition to properties, but it doesn't matter for our
80 81 # purposes -- we don't need to filter styles..
81 82 ":active", "::after (:after)", "align-content", "align-items", "align-self",
82 83 "all", "<angle>", "animation", "animation-delay", "animation-direction",
83 84 "animation-duration", "animation-fill-mode", "animation-iteration-count",
84 85 "animation-name", "animation-play-state", "animation-timing-function",
85 86 "@annotation", "annotation()", "attr()", "::backdrop", "backface-visibility",
86 87 "background", "background-attachment", "background-blend-mode",
87 88 "background-clip", "background-color", "background-image", "background-origin",
88 89 "background-position", "background-repeat", "background-size", "<basic-shape>",
89 90 "::before (:before)", "<blend-mode>", "blur()", "border", "border-bottom",
90 91 "border-bottom-color", "border-bottom-left-radius",
91 92 "border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
92 93 "border-collapse", "border-color", "border-image", "border-image-outset",
93 94 "border-image-repeat", "border-image-slice", "border-image-source",
94 95 "border-image-width", "border-left", "border-left-color", "border-left-style",
95 96 "border-left-width", "border-radius", "border-right", "border-right-color",
96 97 "border-right-style", "border-right-width", "border-spacing", "border-style",
97 98 "border-top", "border-top-color", "border-top-left-radius",
98 99 "border-top-right-radius", "border-top-style", "border-top-width",
99 100 "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing",
100 101 "break-after", "break-before", "break-inside", "brightness()", "calc()",
101 102 "caption-side", "ch", "@character-variant", "character-variant()", "@charset",
102 103 ":checked", "circle()", "clear", "clip", "clip-path", "cm", "color", "<color>",
103 104 "columns", "column-count", "column-fill", "column-gap", "column-rule",
104 105 "column-rule-color", "column-rule-style", "column-rule-width", "column-span",
105 106 "column-width", "content", "contrast()", "<counter>", "counter-increment",
106 107 "counter-reset", "@counter-style", "cubic-bezier()", "cursor",
107 108 "<custom-ident>", ":default", "deg", ":dir()", "direction", ":disabled",
108 109 "display", "@document", "dpcm", "dpi", "dppx", "drop-shadow()", "element()",
109 110 "ellipse()", "em", ":empty", "empty-cells", ":enabled", "ex", "filter",
110 111 ":first", ":first-child", "::first-letter", "::first-line",
111 112 ":first-of-type", "flex", "flex-basis", "flex-direction",
112 113 "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", "float", ":focus",
113 114 "font", "@font-face", "font-family", "font-feature-settings",
114 115 "@font-feature-values", "font-kerning", "font-language-override", "font-size",
115 116 "font-size-adjust", "font-stretch", "font-style", "font-synthesis",
116 117 "font-variant", "font-variant-alternates", "font-variant-caps",
117 118 "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric",
118 119 "font-variant-position", "font-weight", "<frequency>", ":fullscreen", "grad",
119 120 "<gradient>", "grayscale()", "grid", "grid-area", "grid-auto-columns",
120 121 "grid-auto-flow", "grid-auto-position", "grid-auto-rows", "grid-column",
121 122 "grid-column-start", "grid-column-end", "grid-row", "grid-row-start",
122 123 "grid-row-end", "grid-template", "grid-template-areas", "grid-template-rows",
123 124 "grid-template-columns", "height", ":hover", "hsl()", "hsla()", "hue-rotate()",
124 125 "hyphens", "hz", "<image>", "image()", "image-rendering", "image-resolution",
125 126 "image-orientation", "ime-mode", "@import", "in", ":indeterminate", "inherit",
126 127 "initial", ":in-range", "inset()", "<integer>", ":invalid", "invert()",
127 128 "isolation", "justify-content", "@keyframes", "khz", ":lang()", ":last-child",
128 129 ":last-of-type", "left", ":left", "<length>", "letter-spacing",
129 130 "linear-gradient()", "line-break", "line-height", ":link", "list-style",
130 131 "list-style-image", "list-style-position", "list-style-type", "margin",
131 132 "margin-bottom", "margin-left", "margin-right", "margin-top", "marks", "mask",
132 133 "mask-type", "matrix()", "matrix3d()", "max-height", "max-width", "@media",
133 134 "min-height", "minmax()", "min-width", "mix-blend-mode", "mm", "ms",
134 135 "@namespace", ":not()", ":nth-child()", ":nth-last-child()",
135 136 ":nth-last-of-type()", ":nth-of-type()", "<number>", "object-fit",
136 137 "object-position", ":only-child", ":only-of-type", "opacity", "opacity()",
137 138 ":optional", "order", "@ornaments", "ornaments()", "orphans", "outline",
138 139 "outline-color", "outline-offset", "outline-style", "outline-width",
139 140 ":out-of-range", "overflow", "overflow-wrap", "overflow-x", "overflow-y",
140 141 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
141 142 "@page", "page-break-after", "page-break-before", "page-break-inside", "pc",
142 143 "<percentage>", "perspective", "perspective()", "perspective-origin",
143 144 "pointer-events", "polygon()", "position", "<position>", "pt", "px", "quotes",
144 145 "rad", "radial-gradient()", "<ratio>", ":read-only", ":read-write", "rect()",
145 146 "rem", "repeat()", "::repeat-index", "::repeat-item",
146 147 "repeating-linear-gradient()", "repeating-radial-gradient()", ":required",
147 148 "resize", "<resolution>", "rgb()", "rgba()", "right", ":right", ":root",
148 149 "rotate()", "rotatex()", "rotatey()", "rotatez()", "rotate3d()", "ruby-align",
149 150 "ruby-merge", "ruby-position", "s", "saturate()", "scale()", "scalex()",
150 151 "scaley()", "scalez()", "scale3d()", ":scope", "scroll-behavior",
151 152 "::selection", "sepia()", "<shape>", "shape-image-threshold", "shape-margin",
152 153 "shape-outside", "skew()", "skewx()", "skewy()", "steps()", "<string>",
153 154 "@styleset", "styleset()", "@stylistic", "stylistic()", "@supports", "@swash",
154 155 "swash()", "symbol()", "table-layout", "tab-size", ":target", "text-align",
155 156 "text-align-last", "text-combine-upright", "text-decoration",
156 157 "text-decoration-color", "text-decoration-line", "text-decoration-style",
157 158 "text-indent", "text-orientation", "text-overflow", "text-rendering",
158 159 "text-shadow", "text-transform", "text-underline-position", "<time>",
159 160 "<timing-function>", "top", "touch-action", "transform", "transform-origin",
160 161 "transform-style", "transition", "transition-delay", "transition-duration",
161 162 "transition-property", "transition-timing-function", "translate()",
162 163 "translatex()", "translatey()", "translatez()", "translate3d()", "turn",
163 164 "unicode-bidi", "unicode-range", "unset", "<uri>", "url()", "<user-ident>",
164 165 ":valid", "::value", "var()", "vertical-align", "vh", "@viewport",
165 166 "visibility", ":visited", "vmax", "vmin", "vw", "white-space", "widows",
166 167 "width", "will-change", "word-break", "word-spacing", "word-wrap",
167 168 "writing-mode", "z-index",
168 169
169 170 ]
170 171
171 172 webkit_prefixed_styles = [
172 173 # Webkit-prefixed styles
173 174 # https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Webkit_Extensions
174 175 "-webkit-animation", "-webkit-animation-delay", "-webkit-animation-direction",
175 176 "-webkit-animation-duration", "-webkit-animation-fill-mode",
176 177 "-webkit-animation-iteration-count", "-webkit-animation-name",
177 178 "-webkit-animation-play-state", "-webkit-animation-timing-function",
178 179 "-webkit-backface-visibility", "-webkit-border-image", "-webkit-column-count",
179 180 "-webkit-column-gap", "-webkit-column-width", "-webkit-column-rule",
180 181 "-webkit-column-rule-width", "-webkit-column-rule-style",
181 182 "-webkit-column-rule-color", "-webkit-columns", "-webkit-column-span",
182 183 "-webkit-font-feature-settings", "-webkit-font-kerning",
183 184 "-webkit-font-size-delta", "-webkit-font-variant-ligatures",
184 185 "-webkit-grid-column", "-webkit-grid-row", "-webkit-hyphens", "-webkit-mask",
185 186 "-webkit-mask-clip", "-webkit-mask-composite", "-webkit-mask-image",
186 187 "-webkit-mask-origin", "-webkit-mask-position", "-webkit-mask-repeat",
187 188 "-webkit-mask-size", "-webkit-perspective", "-webkit-perspective-origin",
188 189 "-webkit-region-fragment", "-webkit-shape-outside", "-webkit-text-emphasis",
189 190 "-webkit-text-emphasis-color", "-webkit-text-emphasis-position",
190 191 "-webkit-text-emphasis-style", "-webkit-transform", "-webkit-transform-origin",
191 192 "-webkit-transform-style", "-webkit-transition", "-webkit-transition-delay",
192 193 "-webkit-transition-duration", "-webkit-transition-property",
193 194 "-webkit-transition-timing-function", "-epub-word-break", "-epub-writing-mode",
194 195 # WebKit-prefixed properties with an unprefixed counterpart
195 196 "-webkit-background-clip", "-webkit-background-origin",
196 197 "-webkit-background-size", "-webkit-border-bottom-left-radius",
197 198 "-webkit-border-bottom-right-radius", "-webkit-border-radius",
198 199 "-webkit-border-top-left-radius", "-webkit-border-top-right-radius",
199 200 "-webkit-box-sizing", "-epub-caption-side", "-webkit-opacity",
200 201 "-epub-text-transform",
201 202 ]
202 203
203 204 mozilla_prefixed_styles = [
204 205 "-moz-column-count", "-moz-column-fill", "-moz-column-gap",
205 206 "-moz-column-width", "-moz-column-rule", "-moz-column-rule-width",
206 207 "-moz-column-rule-style", "-moz-column-rule-color",
207 208 "-moz-font-feature-settings", "-moz-font-language-override", "-moz-hyphens",
208 209 "-moz-text-align-last", "-moz-text-decoration-color",
209 210 "-moz-text-decoration-line", "-moz-text-decoration-style",
210 211 ]
211 212
212 213 all_prefixed_styles = [
213 214 # From http://peter.sh/experiments/vendor-prefixed-css-property-overview/
214 215 "-ms-accelerator", "-webkit-app-region", "-webkit-appearance",
215 216 "-webkit-appearance", "-moz-appearance", "-webkit-aspect-ratio",
216 217 "-webkit-backdrop-filter", "backface-visibility",
217 218 "-webkit-backface-visibility", "backface-visibility", "backface-visibility",
218 219 "-webkit-background-composite", "-webkit-background-composite", "-moz-binding",
219 220 "-ms-block-progression", "-webkit-border-after", "-webkit-border-after",
220 221 "-webkit-border-after-color", "-webkit-border-after-color",
221 222 "-webkit-border-after-style", "-webkit-border-after-style",
222 223 "-webkit-border-after-width", "-webkit-border-after-width",
223 224 "-webkit-border-before", "-webkit-border-before",
224 225 "-webkit-border-before-color", "-webkit-border-before-color",
225 226 "-webkit-border-before-style", "-webkit-border-before-style",
226 227 "-webkit-border-before-width", "-webkit-border-before-width",
227 228 "-moz-border-bottom-colors", "-webkit-border-end", "-webkit-border-end",
228 229 "-moz-border-end", "-webkit-border-end-color", "-webkit-border-end-color",
229 230 "-moz-border-end-color", "-webkit-border-end-style",
230 231 "-webkit-border-end-style", "-moz-border-end-style",
231 232 "-webkit-border-end-width", "-webkit-border-end-width",
232 233 "-moz-border-end-width", "-webkit-border-fit",
233 234 "-webkit-border-horizontal-spacing", "-webkit-border-horizontal-spacing",
234 235 "-moz-border-left-colors", "-moz-border-right-colors", "-webkit-border-start",
235 236 "-webkit-border-start", "-moz-border-start", "-webkit-border-start-color",
236 237 "-webkit-border-start-color", "-moz-border-start-color",
237 238 "-webkit-border-start-style", "-webkit-border-start-style",
238 239 "-moz-border-start-style", "-webkit-border-start-width",
239 240 "-webkit-border-start-width", "-moz-border-start-width",
240 241 "-moz-border-top-colors", "-webkit-border-vertical-spacing",
241 242 "-webkit-border-vertical-spacing", "-webkit-box-align", "-webkit-box-align",
242 243 "-moz-box-align", "-webkit-box-decoration-break",
243 244 "-webkit-box-decoration-break", "box-decoration-break",
244 245 "-webkit-box-direction", "-webkit-box-direction", "-moz-box-direction",
245 246 "-webkit-box-flex", "-webkit-box-flex", "-moz-box-flex",
246 247 "-webkit-box-flex-group", "-webkit-box-flex-group", "-webkit-box-lines",
247 248 "-webkit-box-lines", "-webkit-box-ordinal-group", "-webkit-box-ordinal-group",
248 249 "-moz-box-ordinal-group", "-webkit-box-orient", "-webkit-box-orient",
249 250 "-moz-box-orient", "-webkit-box-pack", "-webkit-box-pack", "-moz-box-pack",
250 251 "-webkit-box-reflect", "-webkit-box-reflect", "clip-path", "-webkit-clip-path",
251 252 "clip-path", "clip-path", "-webkit-color-correction", "-webkit-column-axis",
252 253 "-webkit-column-break-after", "-webkit-column-break-after",
253 254 "-webkit-column-break-before", "-webkit-column-break-before",
254 255 "-webkit-column-break-inside", "-webkit-column-break-inside",
255 256 "-webkit-column-count", "column-count", "-moz-column-count", "column-count",
256 257 "column-fill", "column-fill", "-moz-column-fill", "column-fill",
257 258 "-webkit-column-gap", "column-gap", "-moz-column-gap", "column-gap",
258 259 "-webkit-column-rule", "column-rule", "-moz-column-rule", "column-rule",
259 260 "-webkit-column-rule-color", "column-rule-color", "-moz-column-rule-color",
260 261 "column-rule-color", "-webkit-column-rule-style", "column-rule-style",
261 262 "-moz-column-rule-style", "column-rule-style", "-webkit-column-rule-width",
262 263 "column-rule-width", "-moz-column-rule-width", "column-rule-width",
263 264 "-webkit-column-span", "column-span", "column-span", "-webkit-column-width",
264 265 "column-width", "-moz-column-width", "column-width", "-webkit-columns",
265 266 "columns", "-moz-columns", "columns", "-ms-content-zoom-chaining",
266 267 "-ms-content-zoom-limit", "-ms-content-zoom-limit-max",
267 268 "-ms-content-zoom-limit-min", "-ms-content-zoom-snap",
268 269 "-ms-content-zoom-snap-points", "-ms-content-zoom-snap-type",
269 270 "-ms-content-zooming", "-moz-control-character-visibility",
270 271 "-webkit-cursor-visibility", "-webkit-dashboard-region", "filter",
271 272 "-webkit-filter", "filter", "filter", "-ms-flex-align", "-ms-flex-item-align",
272 273 "-ms-flex-line-pack", "-ms-flex-negative", "-ms-flex-order", "-ms-flex-pack",
273 274 "-ms-flex-positive", "-ms-flex-preferred-size", "-moz-float-edge",
274 275 "-webkit-flow-from", "-ms-flow-from", "-webkit-flow-into", "-ms-flow-into",
275 276 "-webkit-font-feature-settings", "-webkit-font-feature-settings",
276 277 "font-feature-settings", "font-feature-settings", "font-kerning",
277 278 "-webkit-font-kerning", "font-kerning", "-webkit-font-size-delta",
278 279 "-webkit-font-size-delta", "-webkit-font-smoothing", "-webkit-font-smoothing",
279 280 "font-variant-ligatures", "-webkit-font-variant-ligatures",
280 281 "font-variant-ligatures", "-moz-force-broken-image-icon", "grid",
281 282 "-webkit-grid", "grid", "grid-area", "-webkit-grid-area", "grid-area",
282 283 "grid-auto-columns", "-webkit-grid-auto-columns", "grid-auto-columns",
283 284 "grid-auto-flow", "-webkit-grid-auto-flow", "grid-auto-flow", "grid-auto-rows",
284 285 "-webkit-grid-auto-rows", "grid-auto-rows", "grid-column",
285 286 "-webkit-grid-column", "grid-column", "-ms-grid-column",
286 287 "-ms-grid-column-align", "grid-column-end", "-webkit-grid-column-end",
287 288 "grid-column-end", "-ms-grid-column-span", "grid-column-start",
288 289 "-webkit-grid-column-start", "grid-column-start", "-ms-grid-columns",
289 290 "grid-row", "-webkit-grid-row", "grid-row", "-ms-grid-row",
290 291 "-ms-grid-row-align", "grid-row-end", "-webkit-grid-row-end", "grid-row-end",
291 292 "-ms-grid-row-span", "grid-row-start", "-webkit-grid-row-start",
292 293 "grid-row-start", "-ms-grid-rows", "grid-template", "-webkit-grid-template",
293 294 "grid-template", "grid-template-areas", "-webkit-grid-template-areas",
294 295 "grid-template-areas", "grid-template-columns",
295 296 "-webkit-grid-template-columns", "grid-template-columns", "grid-template-rows",
296 297 "-webkit-grid-template-rows", "grid-template-rows", "-ms-high-contrast-adjust",
297 298 "-webkit-highlight", "-webkit-hyphenate-character",
298 299 "-webkit-hyphenate-character", "-webkit-hyphenate-limit-after",
299 300 "-webkit-hyphenate-limit-before", "-ms-hyphenate-limit-chars",
300 301 "-webkit-hyphenate-limit-lines", "-ms-hyphenate-limit-lines",
301 302 "-ms-hyphenate-limit-zone", "-webkit-hyphens", "-moz-hyphens", "-ms-hyphens",
302 303 "-moz-image-region", "-ms-ime-align", "-webkit-initial-letter",
303 304 "-ms-interpolation-mode", "justify-self", "-webkit-justify-self",
304 305 "-webkit-line-align", "-webkit-line-box-contain", "-webkit-line-box-contain",
305 306 "-webkit-line-break", "-webkit-line-break", "line-break", "-webkit-line-clamp",
306 307 "-webkit-line-clamp", "-webkit-line-grid", "-webkit-line-snap",
307 308 "-webkit-locale", "-webkit-locale", "-webkit-logical-height",
308 309 "-webkit-logical-height", "-webkit-logical-width", "-webkit-logical-width",
309 310 "-webkit-margin-after", "-webkit-margin-after",
310 311 "-webkit-margin-after-collapse", "-webkit-margin-after-collapse",
311 312 "-webkit-margin-before", "-webkit-margin-before",
312 313 "-webkit-margin-before-collapse", "-webkit-margin-before-collapse",
313 314 "-webkit-margin-bottom-collapse", "-webkit-margin-bottom-collapse",
314 315 "-webkit-margin-collapse", "-webkit-margin-collapse", "-webkit-margin-end",
315 316 "-webkit-margin-end", "-moz-margin-end", "-webkit-margin-start",
316 317 "-webkit-margin-start", "-moz-margin-start", "-webkit-margin-top-collapse",
317 318 "-webkit-margin-top-collapse", "-webkit-marquee", "-webkit-marquee-direction",
318 319 "-webkit-marquee-increment", "-webkit-marquee-repetition",
319 320 "-webkit-marquee-speed", "-webkit-marquee-style", "mask", "-webkit-mask",
320 321 "mask", "-webkit-mask-box-image", "-webkit-mask-box-image",
321 322 "-webkit-mask-box-image-outset", "-webkit-mask-box-image-outset",
322 323 "-webkit-mask-box-image-repeat", "-webkit-mask-box-image-repeat",
323 324 "-webkit-mask-box-image-slice", "-webkit-mask-box-image-slice",
324 325 "-webkit-mask-box-image-source", "-webkit-mask-box-image-source",
325 326 "-webkit-mask-box-image-width", "-webkit-mask-box-image-width",
326 327 "-webkit-mask-clip", "-webkit-mask-clip", "-webkit-mask-composite",
327 328 "-webkit-mask-composite", "-webkit-mask-image", "-webkit-mask-image",
328 329 "-webkit-mask-origin", "-webkit-mask-origin", "-webkit-mask-position",
329 330 "-webkit-mask-position", "-webkit-mask-position-x", "-webkit-mask-position-x",
330 331 "-webkit-mask-position-y", "-webkit-mask-position-y", "-webkit-mask-repeat",
331 332 "-webkit-mask-repeat", "-webkit-mask-repeat-x", "-webkit-mask-repeat-x",
332 333 "-webkit-mask-repeat-y", "-webkit-mask-repeat-y", "-webkit-mask-size",
333 334 "-webkit-mask-size", "mask-source-type", "-webkit-mask-source-type",
334 335 "-moz-math-display", "-moz-math-variant", "-webkit-max-logical-height",
335 336 "-webkit-max-logical-height", "-webkit-max-logical-width",
336 337 "-webkit-max-logical-width", "-webkit-min-logical-height",
337 338 "-webkit-min-logical-height", "-webkit-min-logical-width",
338 339 "-webkit-min-logical-width", "-webkit-nbsp-mode", "-moz-orient",
339 340 "-moz-osx-font-smoothing", "-moz-outline-radius",
340 341 "-moz-outline-radius-bottomleft", "-moz-outline-radius-bottomright",
341 342 "-moz-outline-radius-topleft", "-moz-outline-radius-topright",
342 343 "-webkit-overflow-scrolling", "-ms-overflow-style", "-webkit-padding-after",
343 344 "-webkit-padding-after", "-webkit-padding-before", "-webkit-padding-before",
344 345 "-webkit-padding-end", "-webkit-padding-end", "-moz-padding-end",
345 346 "-webkit-padding-start", "-webkit-padding-start", "-moz-padding-start",
346 347 "perspective", "-webkit-perspective", "perspective", "perspective",
347 348 "perspective-origin", "-webkit-perspective-origin", "perspective-origin",
348 349 "perspective-origin", "-webkit-perspective-origin-x",
349 350 "-webkit-perspective-origin-x", "perspective-origin-x",
350 351 "-webkit-perspective-origin-y", "-webkit-perspective-origin-y",
351 352 "perspective-origin-y", "-webkit-print-color-adjust",
352 353 "-webkit-print-color-adjust", "-webkit-region-break-after",
353 354 "-webkit-region-break-before", "-webkit-region-break-inside",
354 355 "-webkit-region-fragment", "-webkit-rtl-ordering", "-webkit-rtl-ordering",
355 356 "-webkit-ruby-position", "-webkit-ruby-position", "ruby-position",
356 357 "-moz-script-level", "-moz-script-min-size", "-moz-script-size-multiplier",
357 358 "-ms-scroll-chaining", "-ms-scroll-limit", "-ms-scroll-limit-x-max",
358 359 "-ms-scroll-limit-x-min", "-ms-scroll-limit-y-max", "-ms-scroll-limit-y-min",
359 360 "-ms-scroll-rails", "-webkit-scroll-snap-coordinate",
360 361 "-webkit-scroll-snap-destination", "-webkit-scroll-snap-points-x",
361 362 "-ms-scroll-snap-points-x", "-webkit-scroll-snap-points-y",
362 363 "-ms-scroll-snap-points-y", "-webkit-scroll-snap-type", "-ms-scroll-snap-type",
363 364 "-ms-scroll-snap-x", "-ms-scroll-snap-y", "-ms-scroll-translation",
364 365 "-ms-scrollbar-3dlight-color", "shape-image-threshold",
365 366 "-webkit-shape-image-threshold", "shape-margin", "-webkit-shape-margin",
366 367 "shape-outside", "-webkit-shape-outside", "-moz-stack-sizing", "tab-size",
367 368 "tab-size", "-moz-tab-size", "-webkit-tap-highlight-color",
368 369 "-webkit-tap-highlight-color", "text-align-last", "-webkit-text-align-last",
369 370 "-moz-text-align-last", "text-align-last", "-webkit-text-combine",
370 371 "-webkit-text-combine", "-ms-text-combine-horizontal", "text-decoration-color",
371 372 "-webkit-text-decoration-color", "text-decoration-color",
372 373 "text-decoration-color", "text-decoration-line",
373 374 "-webkit-text-decoration-line", "text-decoration-line",
374 375 "-webkit-text-decoration-skip", "text-decoration-style",
375 376 "-webkit-text-decoration-style", "text-decoration-style",
376 377 "-webkit-text-decorations-in-effect", "-webkit-text-decorations-in-effect",
377 378 "-webkit-text-emphasis", "text-emphasis", "-webkit-text-emphasis-color",
378 379 "text-emphasis-color", "-webkit-text-emphasis-position",
379 380 "text-emphasis-position", "-webkit-text-emphasis-style", "text-emphasis-style",
380 381 "-webkit-text-fill-color", "-webkit-text-fill-color", "text-justify",
381 382 "-webkit-text-justify", "text-justify", "-webkit-text-orientation",
382 383 "-webkit-text-orientation", "text-orientation", "-webkit-text-security",
383 384 "-webkit-text-security", "-webkit-text-size-adjust", "-moz-text-size-adjust",
384 385 "-ms-text-size-adjust", "-webkit-text-stroke", "-webkit-text-stroke",
385 386 "-webkit-text-stroke-color", "-webkit-text-stroke-color",
386 387 "-webkit-text-stroke-width", "-webkit-text-stroke-width",
387 388 "text-underline-position", "-webkit-text-underline-position",
388 389 "text-underline-position", "-webkit-touch-callout", "-ms-touch-select",
389 390 "transform", "-webkit-transform", "transform", "transform", "transform-origin",
390 391 "-webkit-transform-origin", "transform-origin", "transform-origin",
391 392 "-webkit-transform-origin-x", "-webkit-transform-origin-x",
392 393 "transform-origin-x", "-webkit-transform-origin-y",
393 394 "-webkit-transform-origin-y", "transform-origin-y",
394 395 "-webkit-transform-origin-z", "-webkit-transform-origin-z",
395 396 "transform-origin-z", "transform-style", "-webkit-transform-style",
396 397 "transform-style", "transform-style", "-webkit-user-drag", "-webkit-user-drag",
397 398 "-moz-user-focus", "-moz-user-input", "-webkit-user-modify",
398 399 "-webkit-user-modify", "-moz-user-modify", "-webkit-user-select",
399 400 "-webkit-user-select", "-moz-user-select", "-ms-user-select",
400 401 "-moz-window-dragging", "-moz-window-shadow", "-ms-wrap-flow",
401 402 "-ms-wrap-margin", "-ms-wrap-through", "writing-mode", "-webkit-writing-mode",
402 403 "writing-mode", "writing-mode",
403 404 ]
404 405
405 406 all_styles = standard_styles + all_prefixed_styles No newline at end of file
@@ -1,564 +1,580 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 """
23 23 Renderer for markup languages with ability to parse using rst or markdown
24 24 """
25 25
26 26 import re
27 27 import os
28 28 import lxml
29 29 import logging
30 30 import urlparse
31 31 import bleach
32 32
33 33 from mako.lookup import TemplateLookup
34 34 from mako.template import Template as MakoTemplate
35 35
36 36 from docutils.core import publish_parts
37 37 from docutils.parsers.rst import directives
38 38 from docutils import writers
39 39 from docutils.writers import html4css1
40 40 import markdown
41 41
42 42 from rhodecode.lib.markdown_ext import GithubFlavoredMarkdownExtension
43 43 from rhodecode.lib.utils2 import (safe_unicode, md5_safe, MENTIONS_REGEX)
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47 # default renderer used to generate automated comments
48 48 DEFAULT_COMMENTS_RENDERER = 'rst'
49 49
50 try:
51 from lxml.html import fromstring
52 from lxml.html import tostring
53 except ImportError:
54 log.exception('Failed to import lxml')
55 fromstring = None
56 tostring = None
57
50 58
51 59 class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
52 60 """
53 61 Custom HTML Translator used for sandboxing potential
54 62 JS injections in ref links
55 63 """
56 64 def visit_literal_block(self, node):
57 65 self.body.append(self.starttag(node, 'pre', CLASS='codehilite literal-block'))
58 66
59 67 def visit_reference(self, node):
60 68 if 'refuri' in node.attributes:
61 69 refuri = node['refuri']
62 70 if ':' in refuri:
63 71 prefix, link = refuri.lstrip().split(':', 1)
64 72 prefix = prefix or ''
65 73
66 74 if prefix.lower() == 'javascript':
67 75 # we don't allow javascript type of refs...
68 76 node['refuri'] = 'javascript:alert("SandBoxedJavascript")'
69 77
70 78 # old style class requires this...
71 79 return html4css1.HTMLTranslator.visit_reference(self, node)
72 80
73 81
74 82 class RhodeCodeWriter(writers.html4css1.Writer):
75 83 def __init__(self):
76 84 writers.Writer.__init__(self)
77 85 self.translator_class = CustomHTMLTranslator
78 86
79 87
80 88 def relative_links(html_source, server_paths):
81 89 if not html_source:
82 90 return html_source
83 91
84 try:
85 from lxml.html import fromstring
86 from lxml.html import tostring
87 except ImportError:
88 log.exception('Failed to import lxml')
92 if not fromstring and tostring:
89 93 return html_source
90 94
91 95 try:
92 96 doc = lxml.html.fromstring(html_source)
93 97 except Exception:
94 98 return html_source
95 99
96 100 for el in doc.cssselect('img, video'):
97 101 src = el.attrib.get('src')
98 102 if src:
99 103 el.attrib['src'] = relative_path(src, server_paths['raw'])
100 104
101 105 for el in doc.cssselect('a:not(.gfm)'):
102 106 src = el.attrib.get('href')
103 107 if src:
104 108 raw_mode = el.attrib['href'].endswith('?raw=1')
105 109 if raw_mode:
106 110 el.attrib['href'] = relative_path(src, server_paths['raw'])
107 111 else:
108 112 el.attrib['href'] = relative_path(src, server_paths['standard'])
109 113
110 114 return lxml.html.tostring(doc)
111 115
112 116
113 117 def relative_path(path, request_path, is_repo_file=None):
114 118 """
115 119 relative link support, path is a rel path, and request_path is current
116 120 server path (not absolute)
117 121
118 122 e.g.
119 123
120 124 path = '../logo.png'
121 125 request_path= '/repo/files/path/file.md'
122 126 produces: '/repo/files/logo.png'
123 127 """
124 128 # TODO(marcink): unicode/str support ?
125 129 # maybe=> safe_unicode(urllib.quote(safe_str(final_path), '/:'))
126 130
127 131 def dummy_check(p):
128 132 return True # assume default is a valid file path
129 133
130 134 is_repo_file = is_repo_file or dummy_check
131 135 if not path:
132 136 return request_path
133 137
134 138 path = safe_unicode(path)
135 139 request_path = safe_unicode(request_path)
136 140
137 141 if path.startswith((u'data:', u'javascript:', u'#', u':')):
138 142 # skip data, anchor, invalid links
139 143 return path
140 144
141 145 is_absolute = bool(urlparse.urlparse(path).netloc)
142 146 if is_absolute:
143 147 return path
144 148
145 149 if not request_path:
146 150 return path
147 151
148 152 if path.startswith(u'/'):
149 153 path = path[1:]
150 154
151 155 if path.startswith(u'./'):
152 156 path = path[2:]
153 157
154 158 parts = request_path.split('/')
155 159 # compute how deep we need to traverse the request_path
156 160 depth = 0
157 161
158 162 if is_repo_file(request_path):
159 163 # if request path is a VALID file, we use a relative path with
160 164 # one level up
161 165 depth += 1
162 166
163 167 while path.startswith(u'../'):
164 168 depth += 1
165 169 path = path[3:]
166 170
167 171 if depth > 0:
168 172 parts = parts[:-depth]
169 173
170 174 parts.append(path)
171 175 final_path = u'/'.join(parts).lstrip(u'/')
172 176
173 177 return u'/' + final_path
174 178
175 179
176 180 _cached_markdown_renderer = None
177 181
178 182
179 183 def get_markdown_renderer(extensions, output_format):
180 184 global _cached_markdown_renderer
181 185
182 186 if _cached_markdown_renderer is None:
183 187 _cached_markdown_renderer = markdown.Markdown(
184 188 extensions=extensions,
185 189 enable_attributes=False, output_format=output_format)
186 190 return _cached_markdown_renderer
187 191
188 192
189 193 _cached_markdown_renderer_flavored = None
190 194
191 195
192 196 def get_markdown_renderer_flavored(extensions, output_format):
193 197 global _cached_markdown_renderer_flavored
194 198
195 199 if _cached_markdown_renderer_flavored is None:
196 200 _cached_markdown_renderer_flavored = markdown.Markdown(
197 201 extensions=extensions + [GithubFlavoredMarkdownExtension()],
198 202 enable_attributes=False, output_format=output_format)
199 203 return _cached_markdown_renderer_flavored
200 204
201 205
202 206 class MarkupRenderer(object):
203 207 RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw']
204 208
205 209 MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE)
206 210 RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE)
207 211 JUPYTER_PAT = re.compile(r'\.(ipynb)$', re.IGNORECASE)
208 212 PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE)
209 213
210 214 URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
211 215 r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
212 216
217 MENTION_PAT = re.compile(MENTIONS_REGEX)
218
213 219 extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
214 220 'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
215 221
216 222 output_format = 'html4'
217 223
218 224 # extension together with weights. Lower is first means we control how
219 225 # extensions are attached to readme names with those.
220 226 PLAIN_EXTS = [
221 227 # prefer no extension
222 228 ('', 0), # special case that renders READMES names without extension
223 229 ('.text', 2), ('.TEXT', 2),
224 230 ('.txt', 3), ('.TXT', 3)
225 231 ]
226 232
227 233 RST_EXTS = [
228 234 ('.rst', 1), ('.rest', 1),
229 235 ('.RST', 2), ('.REST', 2)
230 236 ]
231 237
232 238 MARKDOWN_EXTS = [
233 239 ('.md', 1), ('.MD', 1),
234 240 ('.mkdn', 2), ('.MKDN', 2),
235 241 ('.mdown', 3), ('.MDOWN', 3),
236 242 ('.markdown', 4), ('.MARKDOWN', 4)
237 243 ]
238 244
239 245 def _detect_renderer(self, source, filename=None):
240 246 """
241 247 runs detection of what renderer should be used for generating html
242 248 from a markup language
243 249
244 250 filename can be also explicitly a renderer name
245 251
246 252 :param source:
247 253 :param filename:
248 254 """
249 255
250 256 if MarkupRenderer.MARKDOWN_PAT.findall(filename):
251 257 detected_renderer = 'markdown'
252 258 elif MarkupRenderer.RST_PAT.findall(filename):
253 259 detected_renderer = 'rst'
254 260 elif MarkupRenderer.JUPYTER_PAT.findall(filename):
255 261 detected_renderer = 'jupyter'
256 262 elif MarkupRenderer.PLAIN_PAT.findall(filename):
257 263 detected_renderer = 'plain'
258 264 else:
259 265 detected_renderer = 'plain'
260 266
261 267 return getattr(MarkupRenderer, detected_renderer)
262 268
263 269 @classmethod
264 270 def bleach_clean(cls, text):
265 271 from .bleach_whitelist import markdown_attrs, markdown_tags
266 272 allowed_tags = markdown_tags
267 273 allowed_attrs = markdown_attrs
268 274
269 275 try:
270 276 return bleach.clean(text, tags=allowed_tags, attributes=allowed_attrs)
271 277 except Exception:
272 278 return 'UNPARSEABLE TEXT'
273 279
274 280 @classmethod
275 281 def renderer_from_filename(cls, filename, exclude):
276 282 """
277 283 Detect renderer markdown/rst from filename and optionally use exclude
278 284 list to remove some options. This is mostly used in helpers.
279 285 Returns None when no renderer can be detected.
280 286 """
281 287 def _filter(elements):
282 288 if isinstance(exclude, (list, tuple)):
283 289 return [x for x in elements if x not in exclude]
284 290 return elements
285 291
286 292 if filename.endswith(
287 293 tuple(_filter([x[0] for x in cls.MARKDOWN_EXTS if x[0]]))):
288 294 return 'markdown'
289 295 if filename.endswith(tuple(_filter([x[0] for x in cls.RST_EXTS if x[0]]))):
290 296 return 'rst'
291 297
292 298 return None
293 299
294 300 def render(self, source, filename=None):
295 301 """
296 302 Renders a given filename using detected renderer
297 303 it detects renderers based on file extension or mimetype.
298 304 At last it will just do a simple html replacing new lines with <br/>
299 305
300 306 :param file_name:
301 307 :param source:
302 308 """
303 309
304 310 renderer = self._detect_renderer(source, filename)
305 311 readme_data = renderer(source)
306 312 return readme_data
307 313
308 314 @classmethod
309 315 def _flavored_markdown(cls, text):
310 316 """
311 317 Github style flavored markdown
312 318
313 319 :param text:
314 320 """
315 321
316 322 # Extract pre blocks.
317 323 extractions = {}
318 324
319 325 def pre_extraction_callback(matchobj):
320 326 digest = md5_safe(matchobj.group(0))
321 327 extractions[digest] = matchobj.group(0)
322 328 return "{gfm-extraction-%s}" % digest
323 329 pattern = re.compile(r'<pre>.*?</pre>', re.MULTILINE | re.DOTALL)
324 330 text = re.sub(pattern, pre_extraction_callback, text)
325 331
326 332 # Prevent foo_bar_baz from ending up with an italic word in the middle.
327 333 def italic_callback(matchobj):
328 334 s = matchobj.group(0)
329 335 if list(s).count('_') >= 2:
330 336 return s.replace('_', r'\_')
331 337 return s
332 338 text = re.sub(r'^(?! {4}|\t)\w+_\w+_\w[\w_]*', italic_callback, text)
333 339
334 340 # Insert pre block extractions.
335 341 def pre_insert_callback(matchobj):
336 342 return '\n\n' + extractions[matchobj.group(1)]
337 343 text = re.sub(r'\{gfm-extraction-([0-9a-f]{32})\}',
338 344 pre_insert_callback, text)
339 345
340 346 return text
341 347
342 348 @classmethod
343 349 def urlify_text(cls, text):
344 350 def url_func(match_obj):
345 351 url_full = match_obj.groups()[0]
346 352 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
347 353
348 354 return cls.URL_PAT.sub(url_func, text)
349 355
350 356 @classmethod
357 def convert_mentions(cls, text, mode):
358 mention_pat = cls.MENTION_PAT
359
360 def wrapp(match_obj):
361 uname = match_obj.groups()[0]
362 hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname
363
364 if mode == 'markdown':
365 tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>'
366 elif mode == 'rst':
367 tmpl = ' **@{uname}** '
368 else:
369 raise ValueError('mode must be rst or markdown')
370
371 return tmpl.format(**{'uname': uname,
372 'hovercard_url': hovercard_url})
373
374 return mention_pat.sub(wrapp, text).strip()
375
376 @classmethod
351 377 def plain(cls, source, universal_newline=True, leading_newline=True):
352 378 source = safe_unicode(source)
353 379 if universal_newline:
354 380 newline = '\n'
355 381 source = newline.join(source.splitlines())
356 382
357 383 rendered_source = cls.urlify_text(source)
358 384 source = ''
359 385 if leading_newline:
360 386 source += '<br />'
361 387 source += rendered_source.replace("\n", '<br />')
362 388
363 389 rendered = cls.bleach_clean(source)
364 390 return rendered
365 391
366 392 @classmethod
367 393 def markdown(cls, source, safe=True, flavored=True, mentions=False,
368 394 clean_html=True):
369 395 """
370 396 returns markdown rendered code cleaned by the bleach library
371 397 """
372 398
373 399 if flavored:
374 400 markdown_renderer = get_markdown_renderer_flavored(
375 401 cls.extensions, cls.output_format)
376 402 else:
377 403 markdown_renderer = get_markdown_renderer(
378 404 cls.extensions, cls.output_format)
379 405
380 406 if mentions:
381 mention_pat = re.compile(MENTIONS_REGEX)
382
383 def wrapp(match_obj):
384 uname = match_obj.groups()[0]
385 return ' **@%(uname)s** ' % {'uname': uname}
386 mention_hl = mention_pat.sub(wrapp, source).strip()
407 mention_hl = cls.convert_mentions(source, mode='markdown')
387 408 # we extracted mentions render with this using Mentions false
388 409 return cls.markdown(mention_hl, safe=safe, flavored=flavored,
389 410 mentions=False)
390 411
391 412 source = safe_unicode(source)
392 413
393 414 try:
394 415 if flavored:
395 416 source = cls._flavored_markdown(source)
396 417 rendered = markdown_renderer.convert(source)
397 418 except Exception:
398 419 log.exception('Error when rendering Markdown')
399 420 if safe:
400 421 log.debug('Fallback to render in plain mode')
401 422 rendered = cls.plain(source)
402 423 else:
403 424 raise
404 425
405 426 if clean_html:
406 427 rendered = cls.bleach_clean(rendered)
407 428 return rendered
408 429
409 430 @classmethod
410 431 def rst(cls, source, safe=True, mentions=False, clean_html=False):
411 432 if mentions:
412 mention_pat = re.compile(MENTIONS_REGEX)
413
414 def wrapp(match_obj):
415 uname = match_obj.groups()[0]
416 return ' **@%(uname)s** ' % {'uname': uname}
417 mention_hl = mention_pat.sub(wrapp, source).strip()
433 mention_hl = cls.convert_mentions(source, mode='rst')
418 434 # we extracted mentions render with this using Mentions false
419 435 return cls.rst(mention_hl, safe=safe, mentions=False)
420 436
421 437 source = safe_unicode(source)
422 438 try:
423 439 docutils_settings = dict(
424 440 [(alias, None) for alias in
425 441 cls.RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES])
426 442
427 443 docutils_settings.update({
428 444 'input_encoding': 'unicode',
429 445 'report_level': 4,
430 446 'syntax_highlight': 'short',
431 447 })
432 448
433 449 for k, v in docutils_settings.iteritems():
434 450 directives.register_directive(k, v)
435 451
436 452 parts = publish_parts(source=source,
437 453 writer=RhodeCodeWriter(),
438 454 settings_overrides=docutils_settings)
439 455 rendered = parts["fragment"]
440 456 if clean_html:
441 457 rendered = cls.bleach_clean(rendered)
442 458 return parts['html_title'] + rendered
443 459 except Exception:
444 460 log.exception('Error when rendering RST')
445 461 if safe:
446 log.debug('Fallbacking to render in plain mode')
462 log.debug('Fallback to render in plain mode')
447 463 return cls.plain(source)
448 464 else:
449 465 raise
450 466
451 467 @classmethod
452 468 def jupyter(cls, source, safe=True):
453 469 from rhodecode.lib import helpers
454 470
455 471 from traitlets.config import Config
456 472 import nbformat
457 473 from nbconvert import HTMLExporter
458 474 from nbconvert.preprocessors import Preprocessor
459 475
460 476 class CustomHTMLExporter(HTMLExporter):
461 477 def _template_file_default(self):
462 478 return 'basic'
463 479
464 480 class Sandbox(Preprocessor):
465 481
466 482 def preprocess(self, nb, resources):
467 483 sandbox_text = 'SandBoxed(IPython.core.display.Javascript object)'
468 484 for cell in nb['cells']:
469 485 if not safe:
470 486 continue
471 487
472 488 if 'outputs' in cell:
473 489 for cell_output in cell['outputs']:
474 490 if 'data' in cell_output:
475 491 if 'application/javascript' in cell_output['data']:
476 492 cell_output['data']['text/plain'] = sandbox_text
477 493 cell_output['data'].pop('application/javascript', None)
478 494
479 495 if 'source' in cell and cell['cell_type'] == 'markdown':
480 496 # sanitize similar like in markdown
481 497 cell['source'] = cls.bleach_clean(cell['source'])
482 498
483 499 return nb, resources
484 500
485 501 def _sanitize_resources(input_resources):
486 502 """
487 503 Skip/sanitize some of the CSS generated and included in jupyter
488 504 so it doesn't messes up UI so much
489 505 """
490 506
491 507 # TODO(marcink): probably we should replace this with whole custom
492 508 # CSS set that doesn't screw up, but jupyter generated html has some
493 509 # special markers, so it requires Custom HTML exporter template with
494 510 # _default_template_path_default, to achieve that
495 511
496 512 # strip the reset CSS
497 513 input_resources[0] = input_resources[0][input_resources[0].find('/*! Source'):]
498 514 return input_resources
499 515
500 516 def as_html(notebook):
501 517 conf = Config()
502 518 conf.CustomHTMLExporter.preprocessors = [Sandbox]
503 519 html_exporter = CustomHTMLExporter(config=conf)
504 520
505 521 (body, resources) = html_exporter.from_notebook_node(notebook)
506 522 header = '<!-- ## IPYTHON NOTEBOOK RENDERING ## -->'
507 523 js = MakoTemplate(r'''
508 524 <!-- MathJax configuration -->
509 525 <script type="text/x-mathjax-config">
510 526 MathJax.Hub.Config({
511 527 jax: ["input/TeX","output/HTML-CSS", "output/PreviewHTML"],
512 528 extensions: ["tex2jax.js","MathMenu.js","MathZoom.js", "fast-preview.js", "AssistiveMML.js", "[Contrib]/a11y/accessibility-menu.js"],
513 529 TeX: {
514 530 extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]
515 531 },
516 532 tex2jax: {
517 533 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
518 534 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
519 535 processEscapes: true,
520 536 processEnvironments: true
521 537 },
522 538 // Center justify equations in code and markdown cells. Elsewhere
523 539 // we use CSS to left justify single line equations in code cells.
524 540 displayAlign: 'center',
525 541 "HTML-CSS": {
526 542 styles: {'.MathJax_Display': {"margin": 0}},
527 543 linebreaks: { automatic: true },
528 544 availableFonts: ["STIX", "TeX"]
529 545 },
530 546 showMathMenu: false
531 547 });
532 548 </script>
533 549 <!-- End of MathJax configuration -->
534 550 <script src="${h.asset('js/src/math_jax/MathJax.js')}"></script>
535 551 ''').render(h=helpers)
536 552
537 553 css = MakoTemplate(r'''
538 554 <link rel="stylesheet" type="text/css" href="${h.asset('css/style-ipython.css', ver=ver)}" media="screen"/>
539 555 ''').render(h=helpers, ver='ver1')
540 556
541 557 body = '\n'.join([header, css, js, body])
542 558 return body, resources
543 559
544 560 notebook = nbformat.reads(source, as_version=4)
545 561 (body, resources) = as_html(notebook)
546 562 return body
547 563
548 564
549 565 class RstTemplateRenderer(object):
550 566
551 567 def __init__(self):
552 568 base = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
553 569 rst_template_dirs = [os.path.join(base, 'templates', 'rst_templates')]
554 570 self.template_store = TemplateLookup(
555 571 directories=rst_template_dirs,
556 572 input_encoding='utf-8',
557 573 imports=['from rhodecode.lib import helpers as h'])
558 574
559 575 def _get_template(self, templatename):
560 576 return self.template_store.get_template(templatename)
561 577
562 578 def render(self, template_name, **kwargs):
563 579 template = self._get_template(template_name)
564 580 return template.render(**kwargs)
@@ -1,3037 +1,3041 b''
1 1 //Primary CSS
2 2
3 3 //--- IMPORTS ------------------//
4 4
5 5 @import 'helpers';
6 6 @import 'mixins';
7 7 @import 'rcicons';
8 8 @import 'variables';
9 9 @import 'bootstrap-variables';
10 10 @import 'form-bootstrap';
11 11 @import 'codemirror';
12 12 @import 'legacy_code_styles';
13 13 @import 'readme-box';
14 14 @import 'progress-bar';
15 15
16 16 @import 'type';
17 17 @import 'alerts';
18 18 @import 'buttons';
19 19 @import 'tags';
20 20 @import 'code-block';
21 21 @import 'examples';
22 22 @import 'login';
23 23 @import 'main-content';
24 24 @import 'select2';
25 25 @import 'comments';
26 26 @import 'panels-bootstrap';
27 27 @import 'panels';
28 28 @import 'deform';
29 29 @import 'tooltips';
30 30
31 31 //--- BASE ------------------//
32 32 .noscript-error {
33 33 top: 0;
34 34 left: 0;
35 35 width: 100%;
36 36 z-index: 101;
37 37 text-align: center;
38 38 font-size: 120%;
39 39 color: white;
40 40 background-color: @alert2;
41 41 padding: 5px 0 5px 0;
42 42 font-weight: @text-semibold-weight;
43 43 font-family: @text-semibold;
44 44 }
45 45
46 46 html {
47 47 display: table;
48 48 height: 100%;
49 49 width: 100%;
50 50 }
51 51
52 52 body {
53 53 display: table-cell;
54 54 width: 100%;
55 55 }
56 56
57 57 //--- LAYOUT ------------------//
58 58
59 59 .hidden{
60 60 display: none !important;
61 61 }
62 62
63 63 .box{
64 64 float: left;
65 65 width: 100%;
66 66 }
67 67
68 68 .browser-header {
69 69 clear: both;
70 70 }
71 71 .main {
72 72 clear: both;
73 73 padding:0 0 @pagepadding;
74 74 height: auto;
75 75
76 76 &:after { //clearfix
77 77 content:"";
78 78 clear:both;
79 79 width:100%;
80 80 display:block;
81 81 }
82 82 }
83 83
84 84 .action-link{
85 85 margin-left: @padding;
86 86 padding-left: @padding;
87 87 border-left: @border-thickness solid @border-default-color;
88 88 }
89 89
90 .cursor-pointer {
91 cursor: pointer;
92 }
93
90 94 input + .action-link, .action-link.first{
91 95 border-left: none;
92 96 }
93 97
94 98 .action-link.last{
95 99 margin-right: @padding;
96 100 padding-right: @padding;
97 101 }
98 102
99 103 .action-link.active,
100 104 .action-link.active a{
101 105 color: @grey4;
102 106 }
103 107
104 108 .action-link.disabled {
105 109 color: @grey4;
106 110 cursor: inherit;
107 111 }
108 112
109 113
110 114 .clipboard-action {
111 115 cursor: pointer;
112 116 margin-left: 5px;
113 117
114 118 &:not(.no-grey) {
115 119
116 120 &:hover {
117 121 color: @grey2;
118 122 }
119 123 color: @grey4;
120 124 }
121 125 }
122 126
123 127 ul.simple-list{
124 128 list-style: none;
125 129 margin: 0;
126 130 padding: 0;
127 131 }
128 132
129 133 .main-content {
130 134 padding-bottom: @pagepadding;
131 135 }
132 136
133 137 .wide-mode-wrapper {
134 138 max-width:4000px !important;
135 139 }
136 140
137 141 .wrapper {
138 142 position: relative;
139 143 max-width: @wrapper-maxwidth;
140 144 margin: 0 auto;
141 145 }
142 146
143 147 #content {
144 148 clear: both;
145 149 padding: 0 @contentpadding;
146 150 }
147 151
148 152 .advanced-settings-fields{
149 153 input{
150 154 margin-left: @textmargin;
151 155 margin-right: @padding/2;
152 156 }
153 157 }
154 158
155 159 .cs_files_title {
156 160 margin: @pagepadding 0 0;
157 161 }
158 162
159 163 input.inline[type="file"] {
160 164 display: inline;
161 165 }
162 166
163 167 .error_page {
164 168 margin: 10% auto;
165 169
166 170 h1 {
167 171 color: @grey2;
168 172 }
169 173
170 174 .alert {
171 175 margin: @padding 0;
172 176 }
173 177
174 178 .error-branding {
175 179 color: @grey4;
176 180 font-weight: @text-semibold-weight;
177 181 font-family: @text-semibold;
178 182 }
179 183
180 184 .error_message {
181 185 font-family: @text-regular;
182 186 }
183 187
184 188 .sidebar {
185 189 min-height: 275px;
186 190 margin: 0;
187 191 padding: 0 0 @sidebarpadding @sidebarpadding;
188 192 border: none;
189 193 }
190 194
191 195 .main-content {
192 196 position: relative;
193 197 margin: 0 @sidebarpadding @sidebarpadding;
194 198 padding: 0 0 0 @sidebarpadding;
195 199 border-left: @border-thickness solid @grey5;
196 200
197 201 @media (max-width:767px) {
198 202 clear: both;
199 203 width: 100%;
200 204 margin: 0;
201 205 border: none;
202 206 }
203 207 }
204 208
205 209 .inner-column {
206 210 float: left;
207 211 width: 29.75%;
208 212 min-height: 150px;
209 213 margin: @sidebarpadding 2% 0 0;
210 214 padding: 0 2% 0 0;
211 215 border-right: @border-thickness solid @grey5;
212 216
213 217 @media (max-width:767px) {
214 218 clear: both;
215 219 width: 100%;
216 220 border: none;
217 221 }
218 222
219 223 ul {
220 224 padding-left: 1.25em;
221 225 }
222 226
223 227 &:last-child {
224 228 margin: @sidebarpadding 0 0;
225 229 border: none;
226 230 }
227 231
228 232 h4 {
229 233 margin: 0 0 @padding;
230 234 font-weight: @text-semibold-weight;
231 235 font-family: @text-semibold;
232 236 }
233 237 }
234 238 }
235 239 .error-page-logo {
236 240 width: 130px;
237 241 height: 160px;
238 242 }
239 243
240 244 // HEADER
241 245 .header {
242 246
243 247 // TODO: johbo: Fix login pages, so that they work without a min-height
244 248 // for the header and then remove the min-height. I chose a smaller value
245 249 // intentionally here to avoid rendering issues in the main navigation.
246 250 min-height: 49px;
247 251 min-width: 1024px;
248 252
249 253 position: relative;
250 254 vertical-align: bottom;
251 255 padding: 0 @header-padding;
252 256 background-color: @grey1;
253 257 color: @grey5;
254 258
255 259 .title {
256 260 overflow: visible;
257 261 }
258 262
259 263 &:before,
260 264 &:after {
261 265 content: "";
262 266 clear: both;
263 267 width: 100%;
264 268 }
265 269
266 270 // TODO: johbo: Avoids breaking "Repositories" chooser
267 271 .select2-container .select2-choice .select2-arrow {
268 272 display: none;
269 273 }
270 274 }
271 275
272 276 #header-inner {
273 277 &.title {
274 278 margin: 0;
275 279 }
276 280 &:before,
277 281 &:after {
278 282 content: "";
279 283 clear: both;
280 284 }
281 285 }
282 286
283 287 // Gists
284 288 #files_data {
285 289 clear: both; //for firefox
286 290 padding-top: 10px;
287 291 }
288 292
289 293 #gistid {
290 294 margin-right: @padding;
291 295 }
292 296
293 297 // Global Settings Editor
294 298 .textarea.editor {
295 299 float: left;
296 300 position: relative;
297 301 max-width: @texteditor-width;
298 302
299 303 select {
300 304 position: absolute;
301 305 top:10px;
302 306 right:0;
303 307 }
304 308
305 309 .CodeMirror {
306 310 margin: 0;
307 311 }
308 312
309 313 .help-block {
310 314 margin: 0 0 @padding;
311 315 padding:.5em;
312 316 background-color: @grey6;
313 317 &.pre-formatting {
314 318 white-space: pre;
315 319 }
316 320 }
317 321 }
318 322
319 323 ul.auth_plugins {
320 324 margin: @padding 0 @padding @legend-width;
321 325 padding: 0;
322 326
323 327 li {
324 328 margin-bottom: @padding;
325 329 line-height: 1em;
326 330 list-style-type: none;
327 331
328 332 .auth_buttons .btn {
329 333 margin-right: @padding;
330 334 }
331 335
332 336 }
333 337 }
334 338
335 339
336 340 // My Account PR list
337 341
338 342 #show_closed {
339 343 margin: 0 1em 0 0;
340 344 }
341 345
342 346 #pull_request_list_table {
343 347 .closed {
344 348 background-color: @grey6;
345 349 }
346 350
347 351 .state-creating,
348 352 .state-updating,
349 353 .state-merging
350 354 {
351 355 background-color: @grey6;
352 356 }
353 357
354 358 .td-status {
355 359 padding-left: .5em;
356 360 }
357 361 .log-container .truncate {
358 362 height: 2.75em;
359 363 white-space: pre-line;
360 364 }
361 365 table.rctable .user {
362 366 padding-left: 0;
363 367 }
364 368 table.rctable {
365 369 td.td-description,
366 370 .rc-user {
367 371 min-width: auto;
368 372 }
369 373 }
370 374 }
371 375
372 376 // Pull Requests
373 377
374 378 .pullrequests_section_head {
375 379 display: block;
376 380 clear: both;
377 381 margin: @padding 0;
378 382 font-weight: @text-bold-weight;
379 383 font-family: @text-bold;
380 384 }
381 385
382 386 .pr-commit-flow {
383 387 position: relative;
384 388 font-weight: 600;
385 389
386 390 .tag {
387 391 display: inline-block;
388 392 margin: 0 1em .5em 0;
389 393 }
390 394
391 395 .clone-url {
392 396 display: inline-block;
393 397 margin: 0 0 .5em 0;
394 398 padding: 0;
395 399 line-height: 1.2em;
396 400 }
397 401 }
398 402
399 403 .pr-mergeinfo {
400 404 min-width: 95% !important;
401 405 padding: 0 !important;
402 406 border: 0;
403 407 }
404 408 .pr-mergeinfo-copy {
405 409 padding: 0 0;
406 410 }
407 411
408 412 .pr-pullinfo {
409 413 min-width: 95% !important;
410 414 padding: 0 !important;
411 415 border: 0;
412 416 }
413 417 .pr-pullinfo-copy {
414 418 padding: 0 0;
415 419 }
416 420
417 421 .pr-title-input {
418 422 width: 80%;
419 423 font-size: 1em;
420 424 margin: 0 0 4px 0;
421 425 padding: 0;
422 426 line-height: 1.7em;
423 427 color: @text-color;
424 428 letter-spacing: .02em;
425 429 font-weight: @text-bold-weight;
426 430 font-family: @text-bold;
427 431
428 432 &:hover {
429 433 box-shadow: none;
430 434 }
431 435 }
432 436
433 437 #pr-title {
434 438 input {
435 439 border: 1px transparent;
436 440 color: black;
437 441 opacity: 1;
438 442 background: #fff;
439 443 }
440 444 }
441 445
442 446 .pr-title-closed-tag {
443 447 font-size: 16px;
444 448 }
445 449
446 450 #pr-desc {
447 451 padding: 10px 0;
448 452
449 453 .markdown-block {
450 454 padding: 0;
451 455 margin-bottom: -30px;
452 456 }
453 457 }
454 458
455 459 #pullrequest_title {
456 460 width: 100%;
457 461 box-sizing: border-box;
458 462 }
459 463
460 464 #pr_open_message {
461 465 border: @border-thickness solid #fff;
462 466 border-radius: @border-radius;
463 467 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
464 468 text-align: left;
465 469 overflow: hidden;
466 470 }
467 471
468 472 .pr-details-title {
469 473 height: 16px
470 474 }
471 475
472 476 .pr-details-title-author-pref {
473 477 padding-right: 10px
474 478 }
475 479
476 480 .label-pr-detail {
477 481 display: table-cell;
478 482 width: 120px;
479 483 padding-top: 7.5px;
480 484 padding-bottom: 7.5px;
481 485 padding-right: 7.5px;
482 486 }
483 487
484 488 .source-details ul {
485 489 padding: 10px 16px;
486 490 }
487 491
488 492 .source-details-action {
489 493 color: @grey4;
490 494 font-size: 11px
491 495 }
492 496
493 497 .pr-submit-button {
494 498 float: right;
495 499 margin: 0 0 0 5px;
496 500 }
497 501
498 502 .pr-spacing-container {
499 503 padding: 20px;
500 504 clear: both
501 505 }
502 506
503 507 #pr-description-input {
504 508 margin-bottom: 0;
505 509 }
506 510
507 511 .pr-description-label {
508 512 vertical-align: top;
509 513 }
510 514
511 515 #open_edit_pullrequest {
512 516 padding: 0;
513 517 }
514 518
515 519 #close_edit_pullrequest {
516 520
517 521 }
518 522
519 523 #delete_pullrequest {
520 524 clear: inherit;
521 525
522 526 form {
523 527 display: inline;
524 528 }
525 529
526 530 }
527 531
528 532 .perms_section_head {
529 533 min-width: 625px;
530 534
531 535 h2 {
532 536 margin-bottom: 0;
533 537 }
534 538
535 539 .label-checkbox {
536 540 float: left;
537 541 }
538 542
539 543 &.field {
540 544 margin: @space 0 @padding;
541 545 }
542 546
543 547 &:first-child.field {
544 548 margin-top: 0;
545 549
546 550 .label {
547 551 margin-top: 0;
548 552 padding-top: 0;
549 553 }
550 554
551 555 .radios {
552 556 padding-top: 0;
553 557 }
554 558 }
555 559
556 560 .radios {
557 561 position: relative;
558 562 width: 505px;
559 563 }
560 564 }
561 565
562 566 //--- MODULES ------------------//
563 567
564 568
565 569 // Server Announcement
566 570 #server-announcement {
567 571 width: 95%;
568 572 margin: @padding auto;
569 573 padding: @padding;
570 574 border-width: 2px;
571 575 border-style: solid;
572 576 .border-radius(2px);
573 577 font-weight: @text-bold-weight;
574 578 font-family: @text-bold;
575 579
576 580 &.info { border-color: @alert4; background-color: @alert4-inner; }
577 581 &.warning { border-color: @alert3; background-color: @alert3-inner; }
578 582 &.error { border-color: @alert2; background-color: @alert2-inner; }
579 583 &.success { border-color: @alert1; background-color: @alert1-inner; }
580 584 &.neutral { border-color: @grey3; background-color: @grey6; }
581 585 }
582 586
583 587 // Fixed Sidebar Column
584 588 .sidebar-col-wrapper {
585 589 padding-left: @sidebar-all-width;
586 590
587 591 .sidebar {
588 592 width: @sidebar-width;
589 593 margin-left: -@sidebar-all-width;
590 594 }
591 595 }
592 596
593 597 .sidebar-col-wrapper.scw-small {
594 598 padding-left: @sidebar-small-all-width;
595 599
596 600 .sidebar {
597 601 width: @sidebar-small-width;
598 602 margin-left: -@sidebar-small-all-width;
599 603 }
600 604 }
601 605
602 606
603 607 // FOOTER
604 608 #footer {
605 609 padding: 0;
606 610 text-align: center;
607 611 vertical-align: middle;
608 612 color: @grey2;
609 613 font-size: 11px;
610 614
611 615 p {
612 616 margin: 0;
613 617 padding: 1em;
614 618 line-height: 1em;
615 619 }
616 620
617 621 .server-instance { //server instance
618 622 display: none;
619 623 }
620 624
621 625 .title {
622 626 float: none;
623 627 margin: 0 auto;
624 628 }
625 629 }
626 630
627 631 button.close {
628 632 padding: 0;
629 633 cursor: pointer;
630 634 background: transparent;
631 635 border: 0;
632 636 .box-shadow(none);
633 637 -webkit-appearance: none;
634 638 }
635 639
636 640 .close {
637 641 float: right;
638 642 font-size: 21px;
639 643 font-family: @text-bootstrap;
640 644 line-height: 1em;
641 645 font-weight: bold;
642 646 color: @grey2;
643 647
644 648 &:hover,
645 649 &:focus {
646 650 color: @grey1;
647 651 text-decoration: none;
648 652 cursor: pointer;
649 653 }
650 654 }
651 655
652 656 // GRID
653 657 .sorting,
654 658 .sorting_desc,
655 659 .sorting_asc {
656 660 cursor: pointer;
657 661 }
658 662 .sorting_desc:after {
659 663 content: "\00A0\25B2";
660 664 font-size: .75em;
661 665 }
662 666 .sorting_asc:after {
663 667 content: "\00A0\25BC";
664 668 font-size: .68em;
665 669 }
666 670
667 671
668 672 .user_auth_tokens {
669 673
670 674 &.truncate {
671 675 white-space: nowrap;
672 676 overflow: hidden;
673 677 text-overflow: ellipsis;
674 678 }
675 679
676 680 .fields .field .input {
677 681 margin: 0;
678 682 }
679 683
680 684 input#description {
681 685 width: 100px;
682 686 margin: 0;
683 687 }
684 688
685 689 .drop-menu {
686 690 // TODO: johbo: Remove this, should work out of the box when
687 691 // having multiple inputs inline
688 692 margin: 0 0 0 5px;
689 693 }
690 694 }
691 695 #user_list_table {
692 696 .closed {
693 697 background-color: @grey6;
694 698 }
695 699 }
696 700
697 701
698 702 input, textarea {
699 703 &.disabled {
700 704 opacity: .5;
701 705 }
702 706
703 707 &:hover {
704 708 border-color: @grey3;
705 709 box-shadow: @button-shadow;
706 710 }
707 711
708 712 &:focus {
709 713 border-color: @rcblue;
710 714 box-shadow: @button-shadow;
711 715 }
712 716 }
713 717
714 718 // remove extra padding in firefox
715 719 input::-moz-focus-inner { border:0; padding:0 }
716 720
717 721 .adjacent input {
718 722 margin-bottom: @padding;
719 723 }
720 724
721 725 .permissions_boxes {
722 726 display: block;
723 727 }
724 728
725 729 //FORMS
726 730
727 731 .medium-inline,
728 732 input#description.medium-inline {
729 733 display: inline;
730 734 width: @medium-inline-input-width;
731 735 min-width: 100px;
732 736 }
733 737
734 738 select {
735 739 //reset
736 740 -webkit-appearance: none;
737 741 -moz-appearance: none;
738 742
739 743 display: inline-block;
740 744 height: 28px;
741 745 width: auto;
742 746 margin: 0 @padding @padding 0;
743 747 padding: 0 18px 0 8px;
744 748 line-height:1em;
745 749 font-size: @basefontsize;
746 750 border: @border-thickness solid @grey5;
747 751 border-radius: @border-radius;
748 752 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
749 753 color: @grey4;
750 754 box-shadow: @button-shadow;
751 755
752 756 &:after {
753 757 content: "\00A0\25BE";
754 758 }
755 759
756 760 &:focus, &:hover {
757 761 outline: none;
758 762 border-color: @grey4;
759 763 color: @rcdarkblue;
760 764 }
761 765 }
762 766
763 767 option {
764 768 &:focus {
765 769 outline: none;
766 770 }
767 771 }
768 772
769 773 input,
770 774 textarea {
771 775 padding: @input-padding;
772 776 border: @input-border-thickness solid @border-highlight-color;
773 777 .border-radius (@border-radius);
774 778 font-family: @text-light;
775 779 font-size: @basefontsize;
776 780
777 781 &.input-sm {
778 782 padding: 5px;
779 783 }
780 784
781 785 &#description {
782 786 min-width: @input-description-minwidth;
783 787 min-height: 1em;
784 788 padding: 10px;
785 789 }
786 790 }
787 791
788 792 .field-sm {
789 793 input,
790 794 textarea {
791 795 padding: 5px;
792 796 }
793 797 }
794 798
795 799 textarea {
796 800 display: block;
797 801 clear: both;
798 802 width: 100%;
799 803 min-height: 100px;
800 804 margin-bottom: @padding;
801 805 .box-sizing(border-box);
802 806 overflow: auto;
803 807 }
804 808
805 809 label {
806 810 font-family: @text-light;
807 811 }
808 812
809 813 // GRAVATARS
810 814 // centers gravatar on username to the right
811 815
812 816 .gravatar {
813 817 display: inline;
814 818 min-width: 16px;
815 819 min-height: 16px;
816 820 margin: -5px 0;
817 821 padding: 0;
818 822 line-height: 1em;
819 823 box-sizing: content-box;
820 824 border-radius: 50%;
821 825
822 826 &.gravatar-large {
823 827 margin: -0.5em .25em -0.5em 0;
824 828 }
825 829
826 830 & + .user {
827 831 display: inline;
828 832 margin: 0;
829 833 padding: 0 0 0 .17em;
830 834 line-height: 1em;
831 835 }
832 836
833 837 & + .no-margin {
834 838 margin: 0
835 839 }
836 840
837 841 }
838 842
839 843 .user-inline-data {
840 844 display: inline-block;
841 845 float: left;
842 846 padding-left: .5em;
843 847 line-height: 1.3em;
844 848 }
845 849
846 850 .rc-user { // gravatar + user wrapper
847 851 float: left;
848 852 position: relative;
849 853 min-width: 100px;
850 854 max-width: 200px;
851 855 min-height: (@gravatar-size + @border-thickness * 2); // account for border
852 856 display: block;
853 857 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
854 858
855 859
856 860 .gravatar {
857 861 display: block;
858 862 position: absolute;
859 863 top: 0;
860 864 left: 0;
861 865 min-width: @gravatar-size;
862 866 min-height: @gravatar-size;
863 867 margin: 0;
864 868 }
865 869
866 870 .user {
867 871 display: block;
868 872 max-width: 175px;
869 873 padding-top: 2px;
870 874 overflow: hidden;
871 875 text-overflow: ellipsis;
872 876 }
873 877 }
874 878
875 879 .gist-gravatar,
876 880 .journal_container {
877 881 .gravatar-large {
878 882 margin: 0 .5em -10px 0;
879 883 }
880 884 }
881 885
882 886 .gist-type-fields {
883 887 line-height: 30px;
884 888 height: 30px;
885 889
886 890 .gist-type-fields-wrapper {
887 891 vertical-align: middle;
888 892 display: inline-block;
889 893 line-height: 25px;
890 894 }
891 895 }
892 896
893 897 // ADMIN SETTINGS
894 898
895 899 // Tag Patterns
896 900 .tag_patterns {
897 901 .tag_input {
898 902 margin-bottom: @padding;
899 903 }
900 904 }
901 905
902 906 .locked_input {
903 907 position: relative;
904 908
905 909 input {
906 910 display: inline;
907 911 margin: 3px 5px 0px 0px;
908 912 }
909 913
910 914 br {
911 915 display: none;
912 916 }
913 917
914 918 .error-message {
915 919 float: left;
916 920 width: 100%;
917 921 }
918 922
919 923 .lock_input_button {
920 924 display: inline;
921 925 }
922 926
923 927 .help-block {
924 928 clear: both;
925 929 }
926 930 }
927 931
928 932 // Notifications
929 933
930 934 .notifications_buttons {
931 935 margin: 0 0 @space 0;
932 936 padding: 0;
933 937
934 938 .btn {
935 939 display: inline-block;
936 940 }
937 941 }
938 942
939 943 .notification-list {
940 944
941 945 div {
942 946 vertical-align: middle;
943 947 }
944 948
945 949 .container {
946 950 display: block;
947 951 margin: 0 0 @padding 0;
948 952 }
949 953
950 954 .delete-notifications {
951 955 margin-left: @padding;
952 956 text-align: right;
953 957 cursor: pointer;
954 958 }
955 959
956 960 .read-notifications {
957 961 margin-left: @padding/2;
958 962 text-align: right;
959 963 width: 35px;
960 964 cursor: pointer;
961 965 }
962 966
963 967 .icon-minus-sign {
964 968 color: @alert2;
965 969 }
966 970
967 971 .icon-ok-sign {
968 972 color: @alert1;
969 973 }
970 974 }
971 975
972 976 .user_settings {
973 977 float: left;
974 978 clear: both;
975 979 display: block;
976 980 width: 100%;
977 981
978 982 .gravatar_box {
979 983 margin-bottom: @padding;
980 984
981 985 &:after {
982 986 content: " ";
983 987 clear: both;
984 988 width: 100%;
985 989 }
986 990 }
987 991
988 992 .fields .field {
989 993 clear: both;
990 994 }
991 995 }
992 996
993 997 .advanced_settings {
994 998 margin-bottom: @space;
995 999
996 1000 .help-block {
997 1001 margin-left: 0;
998 1002 }
999 1003
1000 1004 button + .help-block {
1001 1005 margin-top: @padding;
1002 1006 }
1003 1007 }
1004 1008
1005 1009 // admin settings radio buttons and labels
1006 1010 .label-2 {
1007 1011 float: left;
1008 1012 width: @label2-width;
1009 1013
1010 1014 label {
1011 1015 color: @grey1;
1012 1016 }
1013 1017 }
1014 1018 .checkboxes {
1015 1019 float: left;
1016 1020 width: @checkboxes-width;
1017 1021 margin-bottom: @padding;
1018 1022
1019 1023 .checkbox {
1020 1024 width: 100%;
1021 1025
1022 1026 label {
1023 1027 margin: 0;
1024 1028 padding: 0;
1025 1029 }
1026 1030 }
1027 1031
1028 1032 .checkbox + .checkbox {
1029 1033 display: inline-block;
1030 1034 }
1031 1035
1032 1036 label {
1033 1037 margin-right: 1em;
1034 1038 }
1035 1039 }
1036 1040
1037 1041 // CHANGELOG
1038 1042 .container_header {
1039 1043 float: left;
1040 1044 display: block;
1041 1045 width: 100%;
1042 1046 margin: @padding 0 @padding;
1043 1047
1044 1048 #filter_changelog {
1045 1049 float: left;
1046 1050 margin-right: @padding;
1047 1051 }
1048 1052
1049 1053 .breadcrumbs_light {
1050 1054 display: inline-block;
1051 1055 }
1052 1056 }
1053 1057
1054 1058 .info_box {
1055 1059 float: right;
1056 1060 }
1057 1061
1058 1062
1059 1063
1060 1064 #graph_content{
1061 1065
1062 1066 // adjust for table headers so that graph renders properly
1063 1067 // #graph_nodes padding - table cell padding
1064 1068 padding-top: (@space - (@basefontsize * 2.4));
1065 1069
1066 1070 &.graph_full_width {
1067 1071 width: 100%;
1068 1072 max-width: 100%;
1069 1073 }
1070 1074 }
1071 1075
1072 1076 #graph {
1073 1077
1074 1078 .pagination-left {
1075 1079 float: left;
1076 1080 clear: both;
1077 1081 }
1078 1082
1079 1083 .log-container {
1080 1084 max-width: 345px;
1081 1085
1082 1086 .message{
1083 1087 max-width: 340px;
1084 1088 }
1085 1089 }
1086 1090
1087 1091 .graph-col-wrapper {
1088 1092
1089 1093 #graph_nodes {
1090 1094 width: 100px;
1091 1095 position: absolute;
1092 1096 left: 70px;
1093 1097 z-index: -1;
1094 1098 }
1095 1099 }
1096 1100
1097 1101 .load-more-commits {
1098 1102 text-align: center;
1099 1103 }
1100 1104 .load-more-commits:hover {
1101 1105 background-color: @grey7;
1102 1106 }
1103 1107 .load-more-commits {
1104 1108 a {
1105 1109 display: block;
1106 1110 }
1107 1111 }
1108 1112 }
1109 1113
1110 1114 .obsolete-toggle {
1111 1115 line-height: 30px;
1112 1116 margin-left: -15px;
1113 1117 }
1114 1118
1115 1119 #rev_range_container, #rev_range_clear, #rev_range_more {
1116 1120 margin-top: -5px;
1117 1121 margin-bottom: -5px;
1118 1122 }
1119 1123
1120 1124 #filter_changelog {
1121 1125 float: left;
1122 1126 }
1123 1127
1124 1128
1125 1129 //--- THEME ------------------//
1126 1130
1127 1131 #logo {
1128 1132 float: left;
1129 1133 margin: 9px 0 0 0;
1130 1134
1131 1135 .header {
1132 1136 background-color: transparent;
1133 1137 }
1134 1138
1135 1139 a {
1136 1140 display: inline-block;
1137 1141 }
1138 1142
1139 1143 img {
1140 1144 height:30px;
1141 1145 }
1142 1146 }
1143 1147
1144 1148 .logo-wrapper {
1145 1149 float:left;
1146 1150 }
1147 1151
1148 1152 .branding {
1149 1153 float: left;
1150 1154 padding: 9px 2px;
1151 1155 line-height: 1em;
1152 1156 font-size: @navigation-fontsize;
1153 1157
1154 1158 a {
1155 1159 color: @grey5
1156 1160 }
1157 1161 @media screen and (max-width: 1200px) {
1158 1162 display: none;
1159 1163 }
1160 1164 }
1161 1165
1162 1166 img {
1163 1167 border: none;
1164 1168 outline: none;
1165 1169 }
1166 1170 user-profile-header
1167 1171 label {
1168 1172
1169 1173 input[type="checkbox"] {
1170 1174 margin-right: 1em;
1171 1175 }
1172 1176 input[type="radio"] {
1173 1177 margin-right: 1em;
1174 1178 }
1175 1179 }
1176 1180
1177 1181 .review-status {
1178 1182 &.under_review {
1179 1183 color: @alert3;
1180 1184 }
1181 1185 &.approved {
1182 1186 color: @alert1;
1183 1187 }
1184 1188 &.rejected,
1185 1189 &.forced_closed{
1186 1190 color: @alert2;
1187 1191 }
1188 1192 &.not_reviewed {
1189 1193 color: @grey5;
1190 1194 }
1191 1195 }
1192 1196
1193 1197 .review-status-under_review {
1194 1198 color: @alert3;
1195 1199 }
1196 1200 .status-tag-under_review {
1197 1201 border-color: @alert3;
1198 1202 }
1199 1203
1200 1204 .review-status-approved {
1201 1205 color: @alert1;
1202 1206 }
1203 1207 .status-tag-approved {
1204 1208 border-color: @alert1;
1205 1209 }
1206 1210
1207 1211 .review-status-rejected,
1208 1212 .review-status-forced_closed {
1209 1213 color: @alert2;
1210 1214 }
1211 1215 .status-tag-rejected,
1212 1216 .status-tag-forced_closed {
1213 1217 border-color: @alert2;
1214 1218 }
1215 1219
1216 1220 .review-status-not_reviewed {
1217 1221 color: @grey5;
1218 1222 }
1219 1223 .status-tag-not_reviewed {
1220 1224 border-color: @grey5;
1221 1225 }
1222 1226
1223 1227 .test_pattern_preview {
1224 1228 margin: @space 0;
1225 1229
1226 1230 p {
1227 1231 margin-bottom: 0;
1228 1232 border-bottom: @border-thickness solid @border-default-color;
1229 1233 color: @grey3;
1230 1234 }
1231 1235
1232 1236 .btn {
1233 1237 margin-bottom: @padding;
1234 1238 }
1235 1239 }
1236 1240 #test_pattern_result {
1237 1241 display: none;
1238 1242 &:extend(pre);
1239 1243 padding: .9em;
1240 1244 color: @grey3;
1241 1245 background-color: @grey7;
1242 1246 border-right: @border-thickness solid @border-default-color;
1243 1247 border-bottom: @border-thickness solid @border-default-color;
1244 1248 border-left: @border-thickness solid @border-default-color;
1245 1249 }
1246 1250
1247 1251 #repo_vcs_settings {
1248 1252 #inherit_overlay_vcs_default {
1249 1253 display: none;
1250 1254 }
1251 1255 #inherit_overlay_vcs_custom {
1252 1256 display: custom;
1253 1257 }
1254 1258 &.inherited {
1255 1259 #inherit_overlay_vcs_default {
1256 1260 display: block;
1257 1261 }
1258 1262 #inherit_overlay_vcs_custom {
1259 1263 display: none;
1260 1264 }
1261 1265 }
1262 1266 }
1263 1267
1264 1268 .issue-tracker-link {
1265 1269 color: @rcblue;
1266 1270 }
1267 1271
1268 1272 // Issue Tracker Table Show/Hide
1269 1273 #repo_issue_tracker {
1270 1274 #inherit_overlay {
1271 1275 display: none;
1272 1276 }
1273 1277 #custom_overlay {
1274 1278 display: custom;
1275 1279 }
1276 1280 &.inherited {
1277 1281 #inherit_overlay {
1278 1282 display: block;
1279 1283 }
1280 1284 #custom_overlay {
1281 1285 display: none;
1282 1286 }
1283 1287 }
1284 1288 }
1285 1289 table.issuetracker {
1286 1290 &.readonly {
1287 1291 tr, td {
1288 1292 color: @grey3;
1289 1293 }
1290 1294 }
1291 1295 .edit {
1292 1296 display: none;
1293 1297 }
1294 1298 .editopen {
1295 1299 .edit {
1296 1300 display: inline;
1297 1301 }
1298 1302 .entry {
1299 1303 display: none;
1300 1304 }
1301 1305 }
1302 1306 tr td.td-action {
1303 1307 min-width: 117px;
1304 1308 }
1305 1309 td input {
1306 1310 max-width: none;
1307 1311 min-width: 30px;
1308 1312 width: 80%;
1309 1313 }
1310 1314 .issuetracker_pref input {
1311 1315 width: 40%;
1312 1316 }
1313 1317 input.edit_issuetracker_update {
1314 1318 margin-right: 0;
1315 1319 width: auto;
1316 1320 }
1317 1321 }
1318 1322
1319 1323 table.integrations {
1320 1324 .td-icon {
1321 1325 width: 20px;
1322 1326 .integration-icon {
1323 1327 height: 20px;
1324 1328 width: 20px;
1325 1329 }
1326 1330 }
1327 1331 }
1328 1332
1329 1333 .integrations {
1330 1334 a.integration-box {
1331 1335 color: @text-color;
1332 1336 &:hover {
1333 1337 .panel {
1334 1338 background: #fbfbfb;
1335 1339 }
1336 1340 }
1337 1341 .integration-icon {
1338 1342 width: 30px;
1339 1343 height: 30px;
1340 1344 margin-right: 20px;
1341 1345 float: left;
1342 1346 }
1343 1347
1344 1348 .panel-body {
1345 1349 padding: 10px;
1346 1350 }
1347 1351 .panel {
1348 1352 margin-bottom: 10px;
1349 1353 }
1350 1354 h2 {
1351 1355 display: inline-block;
1352 1356 margin: 0;
1353 1357 min-width: 140px;
1354 1358 }
1355 1359 }
1356 1360 a.integration-box.dummy-integration {
1357 1361 color: @grey4
1358 1362 }
1359 1363 }
1360 1364
1361 1365 //Permissions Settings
1362 1366 #add_perm {
1363 1367 margin: 0 0 @padding;
1364 1368 cursor: pointer;
1365 1369 }
1366 1370
1367 1371 .perm_ac {
1368 1372 input {
1369 1373 width: 95%;
1370 1374 }
1371 1375 }
1372 1376
1373 1377 .autocomplete-suggestions {
1374 1378 width: auto !important; // overrides autocomplete.js
1375 1379 min-width: 278px;
1376 1380 margin: 0;
1377 1381 border: @border-thickness solid @grey5;
1378 1382 border-radius: @border-radius;
1379 1383 color: @grey2;
1380 1384 background-color: white;
1381 1385 }
1382 1386
1383 1387 .autocomplete-qfilter-suggestions {
1384 1388 width: auto !important; // overrides autocomplete.js
1385 1389 max-height: 100% !important;
1386 1390 min-width: 376px;
1387 1391 margin: 0;
1388 1392 border: @border-thickness solid @grey5;
1389 1393 color: @grey2;
1390 1394 background-color: white;
1391 1395 }
1392 1396
1393 1397 .autocomplete-selected {
1394 1398 background: #F0F0F0;
1395 1399 }
1396 1400
1397 1401 .ac-container-wrap {
1398 1402 margin: 0;
1399 1403 padding: 8px;
1400 1404 border-bottom: @border-thickness solid @grey5;
1401 1405 list-style-type: none;
1402 1406 cursor: pointer;
1403 1407
1404 1408 &:hover {
1405 1409 background-color: @grey7;
1406 1410 }
1407 1411
1408 1412 img {
1409 1413 height: @gravatar-size;
1410 1414 width: @gravatar-size;
1411 1415 margin-right: 1em;
1412 1416 }
1413 1417
1414 1418 strong {
1415 1419 font-weight: normal;
1416 1420 }
1417 1421 }
1418 1422
1419 1423 // Settings Dropdown
1420 1424 .user-menu .container {
1421 1425 padding: 0 4px;
1422 1426 margin: 0;
1423 1427 }
1424 1428
1425 1429 .user-menu .gravatar {
1426 1430 cursor: pointer;
1427 1431 }
1428 1432
1429 1433 .codeblock {
1430 1434 margin-bottom: @padding;
1431 1435 clear: both;
1432 1436
1433 1437 .stats {
1434 1438 overflow: hidden;
1435 1439 }
1436 1440
1437 1441 .message{
1438 1442 textarea{
1439 1443 margin: 0;
1440 1444 }
1441 1445 }
1442 1446
1443 1447 .code-header {
1444 1448 .stats {
1445 1449 line-height: 2em;
1446 1450
1447 1451 .revision_id {
1448 1452 margin-left: 0;
1449 1453 }
1450 1454 .buttons {
1451 1455 padding-right: 0;
1452 1456 }
1453 1457 }
1454 1458
1455 1459 .item{
1456 1460 margin-right: 0.5em;
1457 1461 }
1458 1462 }
1459 1463
1460 1464 #editor_container {
1461 1465 position: relative;
1462 1466 margin: @padding 10px;
1463 1467 }
1464 1468 }
1465 1469
1466 1470 #file_history_container {
1467 1471 display: none;
1468 1472 }
1469 1473
1470 1474 .file-history-inner {
1471 1475 margin-bottom: 10px;
1472 1476 }
1473 1477
1474 1478 // Pull Requests
1475 1479 .summary-details {
1476 1480 width: 72%;
1477 1481 }
1478 1482 .pr-summary {
1479 1483 border-bottom: @border-thickness solid @grey5;
1480 1484 margin-bottom: @space;
1481 1485 }
1482 1486 .reviewers-title {
1483 1487 width: 25%;
1484 1488 min-width: 200px;
1485 1489 }
1486 1490 .reviewers {
1487 1491 width: 25%;
1488 1492 min-width: 200px;
1489 1493 }
1490 1494 .reviewers ul li {
1491 1495 position: relative;
1492 1496 width: 100%;
1493 1497 padding-bottom: 8px;
1494 1498 list-style-type: none;
1495 1499 }
1496 1500
1497 1501 .reviewer_entry {
1498 1502 min-height: 55px;
1499 1503 }
1500 1504
1501 1505 .reviewers_member {
1502 1506 width: 100%;
1503 1507 overflow: auto;
1504 1508 }
1505 1509 .reviewer_reason {
1506 1510 padding-left: 20px;
1507 1511 line-height: 1.5em;
1508 1512 }
1509 1513 .reviewer_status {
1510 1514 display: inline-block;
1511 1515 width: 25px;
1512 1516 min-width: 25px;
1513 1517 height: 1.2em;
1514 1518 line-height: 1em;
1515 1519 }
1516 1520
1517 1521 .reviewer_name {
1518 1522 display: inline-block;
1519 1523 max-width: 83%;
1520 1524 padding-right: 20px;
1521 1525 vertical-align: middle;
1522 1526 line-height: 1;
1523 1527
1524 1528 .rc-user {
1525 1529 min-width: 0;
1526 1530 margin: -2px 1em 0 0;
1527 1531 }
1528 1532
1529 1533 .reviewer {
1530 1534 float: left;
1531 1535 }
1532 1536 }
1533 1537
1534 1538 .reviewer_member_mandatory {
1535 1539 position: absolute;
1536 1540 left: 15px;
1537 1541 top: 8px;
1538 1542 width: 16px;
1539 1543 font-size: 11px;
1540 1544 margin: 0;
1541 1545 padding: 0;
1542 1546 color: black;
1543 1547 }
1544 1548
1545 1549 .reviewer_member_mandatory_remove,
1546 1550 .reviewer_member_remove {
1547 1551 position: absolute;
1548 1552 right: 0;
1549 1553 top: 0;
1550 1554 width: 16px;
1551 1555 margin-bottom: 10px;
1552 1556 padding: 0;
1553 1557 color: black;
1554 1558 }
1555 1559
1556 1560 .reviewer_member_mandatory_remove {
1557 1561 color: @grey4;
1558 1562 }
1559 1563
1560 1564 .reviewer_member_status {
1561 1565 margin-top: 5px;
1562 1566 }
1563 1567 .pr-summary #summary{
1564 1568 width: 100%;
1565 1569 }
1566 1570 .pr-summary .action_button:hover {
1567 1571 border: 0;
1568 1572 cursor: pointer;
1569 1573 }
1570 1574 .pr-details-title {
1571 1575 padding-bottom: 8px;
1572 1576 border-bottom: @border-thickness solid @grey5;
1573 1577
1574 1578 .action_button.disabled {
1575 1579 color: @grey4;
1576 1580 cursor: inherit;
1577 1581 }
1578 1582 .action_button {
1579 1583 color: @rcblue;
1580 1584 }
1581 1585 }
1582 1586 .pr-details-content {
1583 1587 margin-top: @textmargin - 5;
1584 1588 margin-bottom: @textmargin - 5;
1585 1589 }
1586 1590
1587 1591 .pr-reviewer-rules {
1588 1592 padding: 10px 0px 20px 0px;
1589 1593 }
1590 1594
1591 1595 .todo-resolved {
1592 1596 text-decoration: line-through;
1593 1597 }
1594 1598
1595 1599 .todo-table {
1596 1600 width: 100%;
1597 1601
1598 1602 td {
1599 1603 padding: 5px 0px;
1600 1604 }
1601 1605
1602 1606 .td-todo-number {
1603 1607 text-align: left;
1604 1608 white-space: nowrap;
1605 1609 width: 15%;
1606 1610 }
1607 1611
1608 1612 .td-todo-gravatar {
1609 1613 width: 5%;
1610 1614
1611 1615 img {
1612 1616 margin: -3px 0;
1613 1617 }
1614 1618 }
1615 1619
1616 1620 }
1617 1621
1618 1622 .todo-comment-text-wrapper {
1619 1623 display: inline-grid;
1620 1624 }
1621 1625
1622 1626 .todo-comment-text {
1623 1627 margin-left: 5px;
1624 1628 white-space: nowrap;
1625 1629 overflow: hidden;
1626 1630 text-overflow: ellipsis;
1627 1631 }
1628 1632
1629 1633 .group_members {
1630 1634 margin-top: 0;
1631 1635 padding: 0;
1632 1636 list-style: outside none none;
1633 1637
1634 1638 img {
1635 1639 height: @gravatar-size;
1636 1640 width: @gravatar-size;
1637 1641 margin-right: .5em;
1638 1642 margin-left: 3px;
1639 1643 }
1640 1644
1641 1645 .to-delete {
1642 1646 .user {
1643 1647 text-decoration: line-through;
1644 1648 }
1645 1649 }
1646 1650 }
1647 1651
1648 1652 .compare_view_commits_title {
1649 1653 .disabled {
1650 1654 cursor: inherit;
1651 1655 &:hover{
1652 1656 background-color: inherit;
1653 1657 color: inherit;
1654 1658 }
1655 1659 }
1656 1660 }
1657 1661
1658 1662 .subtitle-compare {
1659 1663 margin: -15px 0px 0px 0px;
1660 1664 }
1661 1665
1662 1666 // new entry in group_members
1663 1667 .td-author-new-entry {
1664 1668 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1665 1669 }
1666 1670
1667 1671 .usergroup_member_remove {
1668 1672 width: 16px;
1669 1673 margin-bottom: 10px;
1670 1674 padding: 0;
1671 1675 color: black !important;
1672 1676 cursor: pointer;
1673 1677 }
1674 1678
1675 1679 .reviewer_ac .ac-input {
1676 1680 width: 92%;
1677 1681 margin-bottom: 1em;
1678 1682 }
1679 1683
1680 1684 .compare_view_commits tr{
1681 1685 height: 20px;
1682 1686 }
1683 1687 .compare_view_commits td {
1684 1688 vertical-align: top;
1685 1689 padding-top: 10px;
1686 1690 }
1687 1691 .compare_view_commits .author {
1688 1692 margin-left: 5px;
1689 1693 }
1690 1694
1691 1695 .compare_view_commits {
1692 1696 .color-a {
1693 1697 color: @alert1;
1694 1698 }
1695 1699
1696 1700 .color-c {
1697 1701 color: @color3;
1698 1702 }
1699 1703
1700 1704 .color-r {
1701 1705 color: @color5;
1702 1706 }
1703 1707
1704 1708 .color-a-bg {
1705 1709 background-color: @alert1;
1706 1710 }
1707 1711
1708 1712 .color-c-bg {
1709 1713 background-color: @alert3;
1710 1714 }
1711 1715
1712 1716 .color-r-bg {
1713 1717 background-color: @alert2;
1714 1718 }
1715 1719
1716 1720 .color-a-border {
1717 1721 border: 1px solid @alert1;
1718 1722 }
1719 1723
1720 1724 .color-c-border {
1721 1725 border: 1px solid @alert3;
1722 1726 }
1723 1727
1724 1728 .color-r-border {
1725 1729 border: 1px solid @alert2;
1726 1730 }
1727 1731
1728 1732 .commit-change-indicator {
1729 1733 width: 15px;
1730 1734 height: 15px;
1731 1735 position: relative;
1732 1736 left: 15px;
1733 1737 }
1734 1738
1735 1739 .commit-change-content {
1736 1740 text-align: center;
1737 1741 vertical-align: middle;
1738 1742 line-height: 15px;
1739 1743 }
1740 1744 }
1741 1745
1742 1746 .compare_view_filepath {
1743 1747 color: @grey1;
1744 1748 }
1745 1749
1746 1750 .show_more {
1747 1751 display: inline-block;
1748 1752 width: 0;
1749 1753 height: 0;
1750 1754 vertical-align: middle;
1751 1755 content: "";
1752 1756 border: 4px solid;
1753 1757 border-right-color: transparent;
1754 1758 border-bottom-color: transparent;
1755 1759 border-left-color: transparent;
1756 1760 font-size: 0;
1757 1761 }
1758 1762
1759 1763 .journal_more .show_more {
1760 1764 display: inline;
1761 1765
1762 1766 &:after {
1763 1767 content: none;
1764 1768 }
1765 1769 }
1766 1770
1767 1771 .compare_view_commits .collapse_commit:after {
1768 1772 cursor: pointer;
1769 1773 content: "\00A0\25B4";
1770 1774 margin-left: -3px;
1771 1775 font-size: 17px;
1772 1776 color: @grey4;
1773 1777 }
1774 1778
1775 1779 .diff_links {
1776 1780 margin-left: 8px;
1777 1781 }
1778 1782
1779 1783 #pull_request_overview {
1780 1784 div.ancestor {
1781 1785 margin: -33px 0;
1782 1786 }
1783 1787 }
1784 1788
1785 1789 div.ancestor {
1786 1790 line-height: 33px;
1787 1791 }
1788 1792
1789 1793 .cs_icon_td input[type="checkbox"] {
1790 1794 display: none;
1791 1795 }
1792 1796
1793 1797 .cs_icon_td .expand_file_icon:after {
1794 1798 cursor: pointer;
1795 1799 content: "\00A0\25B6";
1796 1800 font-size: 12px;
1797 1801 color: @grey4;
1798 1802 }
1799 1803
1800 1804 .cs_icon_td .collapse_file_icon:after {
1801 1805 cursor: pointer;
1802 1806 content: "\00A0\25BC";
1803 1807 font-size: 12px;
1804 1808 color: @grey4;
1805 1809 }
1806 1810
1807 1811 /*new binary
1808 1812 NEW_FILENODE = 1
1809 1813 DEL_FILENODE = 2
1810 1814 MOD_FILENODE = 3
1811 1815 RENAMED_FILENODE = 4
1812 1816 COPIED_FILENODE = 5
1813 1817 CHMOD_FILENODE = 6
1814 1818 BIN_FILENODE = 7
1815 1819 */
1816 1820 .cs_files_expand {
1817 1821 font-size: @basefontsize + 5px;
1818 1822 line-height: 1.8em;
1819 1823 float: right;
1820 1824 }
1821 1825
1822 1826 .cs_files_expand span{
1823 1827 color: @rcblue;
1824 1828 cursor: pointer;
1825 1829 }
1826 1830 .cs_files {
1827 1831 clear: both;
1828 1832 padding-bottom: @padding;
1829 1833
1830 1834 .cur_cs {
1831 1835 margin: 10px 2px;
1832 1836 font-weight: bold;
1833 1837 }
1834 1838
1835 1839 .node {
1836 1840 float: left;
1837 1841 }
1838 1842
1839 1843 .changes {
1840 1844 float: right;
1841 1845 color: white;
1842 1846 font-size: @basefontsize - 4px;
1843 1847 margin-top: 4px;
1844 1848 opacity: 0.6;
1845 1849 filter: Alpha(opacity=60); /* IE8 and earlier */
1846 1850
1847 1851 .added {
1848 1852 background-color: @alert1;
1849 1853 float: left;
1850 1854 text-align: center;
1851 1855 }
1852 1856
1853 1857 .deleted {
1854 1858 background-color: @alert2;
1855 1859 float: left;
1856 1860 text-align: center;
1857 1861 }
1858 1862
1859 1863 .bin {
1860 1864 background-color: @alert1;
1861 1865 text-align: center;
1862 1866 }
1863 1867
1864 1868 /*new binary*/
1865 1869 .bin.bin1 {
1866 1870 background-color: @alert1;
1867 1871 text-align: center;
1868 1872 }
1869 1873
1870 1874 /*deleted binary*/
1871 1875 .bin.bin2 {
1872 1876 background-color: @alert2;
1873 1877 text-align: center;
1874 1878 }
1875 1879
1876 1880 /*mod binary*/
1877 1881 .bin.bin3 {
1878 1882 background-color: @grey2;
1879 1883 text-align: center;
1880 1884 }
1881 1885
1882 1886 /*rename file*/
1883 1887 .bin.bin4 {
1884 1888 background-color: @alert4;
1885 1889 text-align: center;
1886 1890 }
1887 1891
1888 1892 /*copied file*/
1889 1893 .bin.bin5 {
1890 1894 background-color: @alert4;
1891 1895 text-align: center;
1892 1896 }
1893 1897
1894 1898 /*chmod file*/
1895 1899 .bin.bin6 {
1896 1900 background-color: @grey2;
1897 1901 text-align: center;
1898 1902 }
1899 1903 }
1900 1904 }
1901 1905
1902 1906 .cs_files .cs_added, .cs_files .cs_A,
1903 1907 .cs_files .cs_added, .cs_files .cs_M,
1904 1908 .cs_files .cs_added, .cs_files .cs_D {
1905 1909 height: 16px;
1906 1910 padding-right: 10px;
1907 1911 margin-top: 7px;
1908 1912 text-align: left;
1909 1913 }
1910 1914
1911 1915 .cs_icon_td {
1912 1916 min-width: 16px;
1913 1917 width: 16px;
1914 1918 }
1915 1919
1916 1920 .pull-request-merge {
1917 1921 border: 1px solid @grey5;
1918 1922 padding: 10px 0px 20px;
1919 1923 margin-top: 10px;
1920 1924 margin-bottom: 20px;
1921 1925 }
1922 1926
1923 1927 .pull-request-merge-refresh {
1924 1928 margin: 2px 7px;
1925 1929 a {
1926 1930 color: @grey3;
1927 1931 }
1928 1932 }
1929 1933
1930 1934 .pull-request-merge ul {
1931 1935 padding: 0px 0px;
1932 1936 }
1933 1937
1934 1938 .pull-request-merge li {
1935 1939 list-style-type: none;
1936 1940 }
1937 1941
1938 1942 .pull-request-merge .pull-request-wrap {
1939 1943 height: auto;
1940 1944 padding: 0px 0px;
1941 1945 text-align: right;
1942 1946 }
1943 1947
1944 1948 .pull-request-merge span {
1945 1949 margin-right: 5px;
1946 1950 }
1947 1951
1948 1952 .pull-request-merge-actions {
1949 1953 min-height: 30px;
1950 1954 padding: 0px 0px;
1951 1955 }
1952 1956
1953 1957 .pull-request-merge-info {
1954 1958 padding: 0px 5px 5px 0px;
1955 1959 }
1956 1960
1957 1961 .merge-status {
1958 1962 margin-right: 5px;
1959 1963 }
1960 1964
1961 1965 .merge-message {
1962 1966 font-size: 1.2em
1963 1967 }
1964 1968
1965 1969 .merge-message.success i,
1966 1970 .merge-icon.success i {
1967 1971 color:@alert1;
1968 1972 }
1969 1973
1970 1974 .merge-message.warning i,
1971 1975 .merge-icon.warning i {
1972 1976 color: @alert3;
1973 1977 }
1974 1978
1975 1979 .merge-message.error i,
1976 1980 .merge-icon.error i {
1977 1981 color:@alert2;
1978 1982 }
1979 1983
1980 1984 .pr-versions {
1981 1985 font-size: 1.1em;
1982 1986 padding: 7.5px;
1983 1987
1984 1988 table {
1985 1989
1986 1990 }
1987 1991
1988 1992 td {
1989 1993 line-height: 15px;
1990 1994 }
1991 1995
1992 1996 .compare-radio-button {
1993 1997 position: relative;
1994 1998 top: -3px;
1995 1999 }
1996 2000 }
1997 2001
1998 2002
1999 2003 #close_pull_request {
2000 2004 margin-right: 0px;
2001 2005 }
2002 2006
2003 2007 .empty_data {
2004 2008 color: @grey4;
2005 2009 }
2006 2010
2007 2011 #changeset_compare_view_content {
2008 2012 clear: both;
2009 2013 width: 100%;
2010 2014 box-sizing: border-box;
2011 2015 .border-radius(@border-radius);
2012 2016
2013 2017 .help-block {
2014 2018 margin: @padding 0;
2015 2019 color: @text-color;
2016 2020 &.pre-formatting {
2017 2021 white-space: pre;
2018 2022 }
2019 2023 }
2020 2024
2021 2025 .empty_data {
2022 2026 margin: @padding 0;
2023 2027 }
2024 2028
2025 2029 .alert {
2026 2030 margin-bottom: @space;
2027 2031 }
2028 2032 }
2029 2033
2030 2034 .table_disp {
2031 2035 .status {
2032 2036 width: auto;
2033 2037 }
2034 2038 }
2035 2039
2036 2040
2037 2041 .creation_in_progress {
2038 2042 color: @grey4
2039 2043 }
2040 2044
2041 2045 .status_box_menu {
2042 2046 margin: 0;
2043 2047 }
2044 2048
2045 2049 .notification-table{
2046 2050 margin-bottom: @space;
2047 2051 display: table;
2048 2052 width: 100%;
2049 2053
2050 2054 .container{
2051 2055 display: table-row;
2052 2056
2053 2057 .notification-header{
2054 2058 border-bottom: @border-thickness solid @border-default-color;
2055 2059 }
2056 2060
2057 2061 .notification-subject{
2058 2062 display: table-cell;
2059 2063 }
2060 2064 }
2061 2065 }
2062 2066
2063 2067 // Notifications
2064 2068 .notification-header{
2065 2069 display: table;
2066 2070 width: 100%;
2067 2071 padding: floor(@basefontsize/2) 0;
2068 2072 line-height: 1em;
2069 2073
2070 2074 .desc, .delete-notifications, .read-notifications{
2071 2075 display: table-cell;
2072 2076 text-align: left;
2073 2077 }
2074 2078
2075 2079 .delete-notifications, .read-notifications{
2076 2080 width: 35px;
2077 2081 min-width: 35px; //fixes when only one button is displayed
2078 2082 }
2079 2083 }
2080 2084
2081 2085 .notification-body {
2082 2086 .markdown-block,
2083 2087 .rst-block {
2084 2088 padding: @padding 0;
2085 2089 }
2086 2090
2087 2091 .notification-subject {
2088 2092 padding: @textmargin 0;
2089 2093 border-bottom: @border-thickness solid @border-default-color;
2090 2094 }
2091 2095 }
2092 2096
2093 2097
2094 2098 .notifications_buttons{
2095 2099 float: right;
2096 2100 }
2097 2101
2098 2102 #notification-status{
2099 2103 display: inline;
2100 2104 }
2101 2105
2102 2106 // Repositories
2103 2107
2104 2108 #summary.fields{
2105 2109 display: table;
2106 2110
2107 2111 .field{
2108 2112 display: table-row;
2109 2113
2110 2114 .label-summary{
2111 2115 display: table-cell;
2112 2116 min-width: @label-summary-minwidth;
2113 2117 padding-top: @padding/2;
2114 2118 padding-bottom: @padding/2;
2115 2119 padding-right: @padding/2;
2116 2120 }
2117 2121
2118 2122 .input{
2119 2123 display: table-cell;
2120 2124 padding: @padding/2;
2121 2125
2122 2126 input{
2123 2127 min-width: 29em;
2124 2128 padding: @padding/4;
2125 2129 }
2126 2130 }
2127 2131 .statistics, .downloads{
2128 2132 .disabled{
2129 2133 color: @grey4;
2130 2134 }
2131 2135 }
2132 2136 }
2133 2137 }
2134 2138
2135 2139 #summary{
2136 2140 width: 70%;
2137 2141 }
2138 2142
2139 2143
2140 2144 // Journal
2141 2145 .journal.title {
2142 2146 h5 {
2143 2147 float: left;
2144 2148 margin: 0;
2145 2149 width: 70%;
2146 2150 }
2147 2151
2148 2152 ul {
2149 2153 float: right;
2150 2154 display: inline-block;
2151 2155 margin: 0;
2152 2156 width: 30%;
2153 2157 text-align: right;
2154 2158
2155 2159 li {
2156 2160 display: inline;
2157 2161 font-size: @journal-fontsize;
2158 2162 line-height: 1em;
2159 2163
2160 2164 list-style-type: none;
2161 2165 }
2162 2166 }
2163 2167 }
2164 2168
2165 2169 .filterexample {
2166 2170 position: absolute;
2167 2171 top: 95px;
2168 2172 left: @contentpadding;
2169 2173 color: @rcblue;
2170 2174 font-size: 11px;
2171 2175 font-family: @text-regular;
2172 2176 cursor: help;
2173 2177
2174 2178 &:hover {
2175 2179 color: @rcdarkblue;
2176 2180 }
2177 2181
2178 2182 @media (max-width:768px) {
2179 2183 position: relative;
2180 2184 top: auto;
2181 2185 left: auto;
2182 2186 display: block;
2183 2187 }
2184 2188 }
2185 2189
2186 2190
2187 2191 #journal{
2188 2192 margin-bottom: @space;
2189 2193
2190 2194 .journal_day{
2191 2195 margin-bottom: @textmargin/2;
2192 2196 padding-bottom: @textmargin/2;
2193 2197 font-size: @journal-fontsize;
2194 2198 border-bottom: @border-thickness solid @border-default-color;
2195 2199 }
2196 2200
2197 2201 .journal_container{
2198 2202 margin-bottom: @space;
2199 2203
2200 2204 .journal_user{
2201 2205 display: inline-block;
2202 2206 }
2203 2207 .journal_action_container{
2204 2208 display: block;
2205 2209 margin-top: @textmargin;
2206 2210
2207 2211 div{
2208 2212 display: inline;
2209 2213 }
2210 2214
2211 2215 div.journal_action_params{
2212 2216 display: block;
2213 2217 }
2214 2218
2215 2219 div.journal_repo:after{
2216 2220 content: "\A";
2217 2221 white-space: pre;
2218 2222 }
2219 2223
2220 2224 div.date{
2221 2225 display: block;
2222 2226 margin-bottom: @textmargin;
2223 2227 }
2224 2228 }
2225 2229 }
2226 2230 }
2227 2231
2228 2232 // Files
2229 2233 .edit-file-title {
2230 2234 font-size: 16px;
2231 2235
2232 2236 .title-heading {
2233 2237 padding: 2px;
2234 2238 }
2235 2239 }
2236 2240
2237 2241 .edit-file-fieldset {
2238 2242 margin: @sidebarpadding 0;
2239 2243
2240 2244 .fieldset {
2241 2245 .left-label {
2242 2246 width: 13%;
2243 2247 }
2244 2248 .right-content {
2245 2249 width: 87%;
2246 2250 max-width: 100%;
2247 2251 }
2248 2252 .filename-label {
2249 2253 margin-top: 13px;
2250 2254 }
2251 2255 .commit-message-label {
2252 2256 margin-top: 4px;
2253 2257 }
2254 2258 .file-upload-input {
2255 2259 input {
2256 2260 display: none;
2257 2261 }
2258 2262 margin-top: 10px;
2259 2263 }
2260 2264 .file-upload-label {
2261 2265 margin-top: 10px;
2262 2266 }
2263 2267 p {
2264 2268 margin-top: 5px;
2265 2269 }
2266 2270
2267 2271 }
2268 2272 .custom-path-link {
2269 2273 margin-left: 5px;
2270 2274 }
2271 2275 #commit {
2272 2276 resize: vertical;
2273 2277 }
2274 2278 }
2275 2279
2276 2280 .delete-file-preview {
2277 2281 max-height: 250px;
2278 2282 }
2279 2283
2280 2284 .new-file,
2281 2285 #filter_activate,
2282 2286 #filter_deactivate {
2283 2287 float: right;
2284 2288 margin: 0 0 0 10px;
2285 2289 }
2286 2290
2287 2291 .file-upload-transaction-wrapper {
2288 2292 margin-top: 57px;
2289 2293 clear: both;
2290 2294 }
2291 2295
2292 2296 .file-upload-transaction-wrapper .error {
2293 2297 color: @color5;
2294 2298 }
2295 2299
2296 2300 .file-upload-transaction {
2297 2301 min-height: 200px;
2298 2302 padding: 54px;
2299 2303 border: 1px solid @grey5;
2300 2304 text-align: center;
2301 2305 clear: both;
2302 2306 }
2303 2307
2304 2308 .file-upload-transaction i {
2305 2309 font-size: 48px
2306 2310 }
2307 2311
2308 2312 h3.files_location{
2309 2313 line-height: 2.4em;
2310 2314 }
2311 2315
2312 2316 .browser-nav {
2313 2317 width: 100%;
2314 2318 display: table;
2315 2319 margin-bottom: 20px;
2316 2320
2317 2321 .info_box {
2318 2322 float: left;
2319 2323 display: inline-table;
2320 2324 height: 2.5em;
2321 2325
2322 2326 .browser-cur-rev, .info_box_elem {
2323 2327 display: table-cell;
2324 2328 vertical-align: middle;
2325 2329 }
2326 2330
2327 2331 .drop-menu {
2328 2332 margin: 0 10px;
2329 2333 }
2330 2334
2331 2335 .info_box_elem {
2332 2336 border-top: @border-thickness solid @grey5;
2333 2337 border-bottom: @border-thickness solid @grey5;
2334 2338 box-shadow: @button-shadow;
2335 2339
2336 2340 #at_rev, a {
2337 2341 padding: 0.6em 0.4em;
2338 2342 margin: 0;
2339 2343 .box-shadow(none);
2340 2344 border: 0;
2341 2345 height: 12px;
2342 2346 color: @grey2;
2343 2347 }
2344 2348
2345 2349 input#at_rev {
2346 2350 max-width: 50px;
2347 2351 text-align: center;
2348 2352 }
2349 2353
2350 2354 &.previous {
2351 2355 border: @border-thickness solid @grey5;
2352 2356 border-top-left-radius: @border-radius;
2353 2357 border-bottom-left-radius: @border-radius;
2354 2358
2355 2359 &:hover {
2356 2360 border-color: @grey4;
2357 2361 }
2358 2362
2359 2363 .disabled {
2360 2364 color: @grey5;
2361 2365 cursor: not-allowed;
2362 2366 opacity: 0.5;
2363 2367 }
2364 2368 }
2365 2369
2366 2370 &.next {
2367 2371 border: @border-thickness solid @grey5;
2368 2372 border-top-right-radius: @border-radius;
2369 2373 border-bottom-right-radius: @border-radius;
2370 2374
2371 2375 &:hover {
2372 2376 border-color: @grey4;
2373 2377 }
2374 2378
2375 2379 .disabled {
2376 2380 color: @grey5;
2377 2381 cursor: not-allowed;
2378 2382 opacity: 0.5;
2379 2383 }
2380 2384 }
2381 2385 }
2382 2386
2383 2387 .browser-cur-rev {
2384 2388
2385 2389 span{
2386 2390 margin: 0;
2387 2391 color: @rcblue;
2388 2392 height: 12px;
2389 2393 display: inline-block;
2390 2394 padding: 0.7em 1em ;
2391 2395 border: @border-thickness solid @rcblue;
2392 2396 margin-right: @padding;
2393 2397 }
2394 2398 }
2395 2399
2396 2400 }
2397 2401
2398 2402 .select-index-number {
2399 2403 margin: 0 0 0 20px;
2400 2404 color: @grey3;
2401 2405 }
2402 2406
2403 2407 .search_activate {
2404 2408 display: table-cell;
2405 2409 vertical-align: middle;
2406 2410
2407 2411 input, label{
2408 2412 margin: 0;
2409 2413 padding: 0;
2410 2414 }
2411 2415
2412 2416 input{
2413 2417 margin-left: @textmargin;
2414 2418 }
2415 2419
2416 2420 }
2417 2421 }
2418 2422
2419 2423 .browser-cur-rev{
2420 2424 margin-bottom: @textmargin;
2421 2425 }
2422 2426
2423 2427 #node_filter_box_loading{
2424 2428 .info_text;
2425 2429 }
2426 2430
2427 2431 .browser-search {
2428 2432 margin: -25px 0px 5px 0px;
2429 2433 }
2430 2434
2431 2435 .files-quick-filter {
2432 2436 float: right;
2433 2437 width: 180px;
2434 2438 position: relative;
2435 2439 }
2436 2440
2437 2441 .files-filter-box {
2438 2442 display: flex;
2439 2443 padding: 0px;
2440 2444 border-radius: 3px;
2441 2445 margin-bottom: 0;
2442 2446
2443 2447 a {
2444 2448 border: none !important;
2445 2449 }
2446 2450
2447 2451 li {
2448 2452 list-style-type: none
2449 2453 }
2450 2454 }
2451 2455
2452 2456 .files-filter-box-path {
2453 2457 line-height: 33px;
2454 2458 padding: 0;
2455 2459 width: 20px;
2456 2460 position: absolute;
2457 2461 z-index: 11;
2458 2462 left: 5px;
2459 2463 }
2460 2464
2461 2465 .files-filter-box-input {
2462 2466 margin-right: 0;
2463 2467
2464 2468 input {
2465 2469 border: 1px solid @white;
2466 2470 padding-left: 25px;
2467 2471 width: 145px;
2468 2472
2469 2473 &:hover {
2470 2474 border-color: @grey6;
2471 2475 }
2472 2476
2473 2477 &:focus {
2474 2478 border-color: @grey5;
2475 2479 }
2476 2480 }
2477 2481 }
2478 2482
2479 2483 .browser-result{
2480 2484 td a{
2481 2485 margin-left: 0.5em;
2482 2486 display: inline-block;
2483 2487
2484 2488 em {
2485 2489 font-weight: @text-bold-weight;
2486 2490 font-family: @text-bold;
2487 2491 }
2488 2492 }
2489 2493 }
2490 2494
2491 2495 .browser-highlight{
2492 2496 background-color: @grey5-alpha;
2493 2497 }
2494 2498
2495 2499
2496 2500 .edit-file-fieldset #location,
2497 2501 .edit-file-fieldset #filename {
2498 2502 display: flex;
2499 2503 width: -moz-available; /* WebKit-based browsers will ignore this. */
2500 2504 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2501 2505 width: fill-available;
2502 2506 border: 0;
2503 2507 }
2504 2508
2505 2509 .path-items {
2506 2510 display: flex;
2507 2511 padding: 0;
2508 2512 border: 1px solid #eeeeee;
2509 2513 width: 100%;
2510 2514 float: left;
2511 2515
2512 2516 .breadcrumb-path {
2513 2517 line-height: 30px;
2514 2518 padding: 0 4px;
2515 2519 white-space: nowrap;
2516 2520 }
2517 2521
2518 2522 .location-path {
2519 2523 width: -moz-available; /* WebKit-based browsers will ignore this. */
2520 2524 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2521 2525 width: fill-available;
2522 2526
2523 2527 .file-name-input {
2524 2528 padding: 0.5em 0;
2525 2529 }
2526 2530
2527 2531 }
2528 2532
2529 2533 ul {
2530 2534 display: flex;
2531 2535 margin: 0;
2532 2536 padding: 0;
2533 2537 width: 100%;
2534 2538 }
2535 2539
2536 2540 li {
2537 2541 list-style-type: none;
2538 2542 }
2539 2543
2540 2544 }
2541 2545
2542 2546 .editor-items {
2543 2547 height: 40px;
2544 2548 margin: 10px 0 -17px 10px;
2545 2549
2546 2550 .editor-action {
2547 2551 cursor: pointer;
2548 2552 }
2549 2553
2550 2554 .editor-action.active {
2551 2555 border-bottom: 2px solid #5C5C5C;
2552 2556 }
2553 2557
2554 2558 li {
2555 2559 list-style-type: none;
2556 2560 }
2557 2561 }
2558 2562
2559 2563 .edit-file-fieldset .message textarea {
2560 2564 border: 1px solid #eeeeee;
2561 2565 }
2562 2566
2563 2567 #files_data .codeblock {
2564 2568 background-color: #F5F5F5;
2565 2569 }
2566 2570
2567 2571 #editor_preview {
2568 2572 background: white;
2569 2573 }
2570 2574
2571 2575 .show-editor {
2572 2576 padding: 10px;
2573 2577 background-color: white;
2574 2578
2575 2579 }
2576 2580
2577 2581 .show-preview {
2578 2582 padding: 10px;
2579 2583 background-color: white;
2580 2584 border-left: 1px solid #eeeeee;
2581 2585 }
2582 2586 // quick filter
2583 2587 .grid-quick-filter {
2584 2588 float: right;
2585 2589 position: relative;
2586 2590 }
2587 2591
2588 2592 .grid-filter-box {
2589 2593 display: flex;
2590 2594 padding: 0px;
2591 2595 border-radius: 3px;
2592 2596 margin-bottom: 0;
2593 2597
2594 2598 a {
2595 2599 border: none !important;
2596 2600 }
2597 2601
2598 2602 li {
2599 2603 list-style-type: none
2600 2604 }
2601 2605 }
2602 2606
2603 2607 .grid-filter-box-icon {
2604 2608 line-height: 33px;
2605 2609 padding: 0;
2606 2610 width: 20px;
2607 2611 position: absolute;
2608 2612 z-index: 11;
2609 2613 left: 5px;
2610 2614 }
2611 2615
2612 2616 .grid-filter-box-input {
2613 2617 margin-right: 0;
2614 2618
2615 2619 input {
2616 2620 border: 1px solid @white;
2617 2621 padding-left: 25px;
2618 2622 width: 145px;
2619 2623
2620 2624 &:hover {
2621 2625 border-color: @grey6;
2622 2626 }
2623 2627
2624 2628 &:focus {
2625 2629 border-color: @grey5;
2626 2630 }
2627 2631 }
2628 2632 }
2629 2633
2630 2634
2631 2635
2632 2636 // Search
2633 2637
2634 2638 .search-form{
2635 2639 #q {
2636 2640 width: @search-form-width;
2637 2641 }
2638 2642 .fields{
2639 2643 margin: 0 0 @space;
2640 2644 }
2641 2645
2642 2646 label{
2643 2647 display: inline-block;
2644 2648 margin-right: @textmargin;
2645 2649 padding-top: 0.25em;
2646 2650 }
2647 2651
2648 2652
2649 2653 .results{
2650 2654 clear: both;
2651 2655 margin: 0 0 @padding;
2652 2656 }
2653 2657
2654 2658 .search-tags {
2655 2659 padding: 5px 0;
2656 2660 }
2657 2661 }
2658 2662
2659 2663 div.search-feedback-items {
2660 2664 display: inline-block;
2661 2665 }
2662 2666
2663 2667 div.search-code-body {
2664 2668 background-color: #ffffff; padding: 5px 0 5px 10px;
2665 2669 pre {
2666 2670 .match { background-color: #faffa6;}
2667 2671 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2668 2672 }
2669 2673 }
2670 2674
2671 2675 .expand_commit.search {
2672 2676 .show_more.open {
2673 2677 height: auto;
2674 2678 max-height: none;
2675 2679 }
2676 2680 }
2677 2681
2678 2682 .search-results {
2679 2683
2680 2684 h2 {
2681 2685 margin-bottom: 0;
2682 2686 }
2683 2687 .codeblock {
2684 2688 border: none;
2685 2689 background: transparent;
2686 2690 }
2687 2691
2688 2692 .codeblock-header {
2689 2693 border: none;
2690 2694 background: transparent;
2691 2695 }
2692 2696
2693 2697 .code-body {
2694 2698 border: @border-thickness solid @grey6;
2695 2699 .border-radius(@border-radius);
2696 2700 }
2697 2701
2698 2702 .td-commit {
2699 2703 &:extend(pre);
2700 2704 border-bottom: @border-thickness solid @border-default-color;
2701 2705 }
2702 2706
2703 2707 .message {
2704 2708 height: auto;
2705 2709 max-width: 350px;
2706 2710 white-space: normal;
2707 2711 text-overflow: initial;
2708 2712 overflow: visible;
2709 2713
2710 2714 .match { background-color: #faffa6;}
2711 2715 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2712 2716 }
2713 2717
2714 2718 .path {
2715 2719 border-bottom: none !important;
2716 2720 border-left: 1px solid @grey6 !important;
2717 2721 border-right: 1px solid @grey6 !important;
2718 2722 }
2719 2723 }
2720 2724
2721 2725 table.rctable td.td-search-results div {
2722 2726 max-width: 100%;
2723 2727 }
2724 2728
2725 2729 #tip-box, .tip-box{
2726 2730 padding: @menupadding/2;
2727 2731 display: block;
2728 2732 border: @border-thickness solid @border-highlight-color;
2729 2733 .border-radius(@border-radius);
2730 2734 background-color: white;
2731 2735 z-index: 99;
2732 2736 white-space: pre-wrap;
2733 2737 }
2734 2738
2735 2739 #linktt {
2736 2740 width: 79px;
2737 2741 }
2738 2742
2739 2743 #help_kb .modal-content{
2740 2744 max-width: 750px;
2741 2745 margin: 10% auto;
2742 2746
2743 2747 table{
2744 2748 td,th{
2745 2749 border-bottom: none;
2746 2750 line-height: 2.5em;
2747 2751 }
2748 2752 th{
2749 2753 padding-bottom: @textmargin/2;
2750 2754 }
2751 2755 td.keys{
2752 2756 text-align: center;
2753 2757 }
2754 2758 }
2755 2759
2756 2760 .block-left{
2757 2761 width: 45%;
2758 2762 margin-right: 5%;
2759 2763 }
2760 2764 .modal-footer{
2761 2765 clear: both;
2762 2766 }
2763 2767 .key.tag{
2764 2768 padding: 0.5em;
2765 2769 background-color: @rcblue;
2766 2770 color: white;
2767 2771 border-color: @rcblue;
2768 2772 .box-shadow(none);
2769 2773 }
2770 2774 }
2771 2775
2772 2776
2773 2777
2774 2778 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2775 2779
2776 2780 @import 'statistics-graph';
2777 2781 @import 'tables';
2778 2782 @import 'forms';
2779 2783 @import 'diff';
2780 2784 @import 'summary';
2781 2785 @import 'navigation';
2782 2786
2783 2787 //--- SHOW/HIDE SECTIONS --//
2784 2788
2785 2789 .btn-collapse {
2786 2790 float: right;
2787 2791 text-align: right;
2788 2792 font-family: @text-light;
2789 2793 font-size: @basefontsize;
2790 2794 cursor: pointer;
2791 2795 border: none;
2792 2796 color: @rcblue;
2793 2797 }
2794 2798
2795 2799 table.rctable,
2796 2800 table.dataTable {
2797 2801 .btn-collapse {
2798 2802 float: right;
2799 2803 text-align: right;
2800 2804 }
2801 2805 }
2802 2806
2803 2807 table.rctable {
2804 2808 &.permissions {
2805 2809
2806 2810 th.td-owner {
2807 2811 padding: 0;
2808 2812 }
2809 2813
2810 2814 th {
2811 2815 font-weight: normal;
2812 2816 padding: 0 5px;
2813 2817 }
2814 2818
2815 2819 }
2816 2820 }
2817 2821
2818 2822
2819 2823 // TODO: johbo: Fix for IE10, this avoids that we see a border
2820 2824 // and padding around checkboxes and radio boxes. Move to the right place,
2821 2825 // or better: Remove this once we did the form refactoring.
2822 2826 input[type=checkbox],
2823 2827 input[type=radio] {
2824 2828 padding: 0;
2825 2829 border: none;
2826 2830 }
2827 2831
2828 2832 .toggle-ajax-spinner{
2829 2833 height: 16px;
2830 2834 width: 16px;
2831 2835 }
2832 2836
2833 2837
2834 2838 .markup-form .clearfix {
2835 2839 .border-radius(@border-radius);
2836 2840 margin: 0px;
2837 2841 }
2838 2842
2839 2843 .markup-form-area {
2840 2844 padding: 8px 12px;
2841 2845 border: 1px solid @grey4;
2842 2846 .border-radius(@border-radius);
2843 2847 }
2844 2848
2845 2849 .markup-form-area-header .nav-links {
2846 2850 display: flex;
2847 2851 flex-flow: row wrap;
2848 2852 -webkit-flex-flow: row wrap;
2849 2853 width: 100%;
2850 2854 }
2851 2855
2852 2856 .markup-form-area-footer {
2853 2857 display: flex;
2854 2858 }
2855 2859
2856 2860 .markup-form-area-footer .toolbar {
2857 2861
2858 2862 }
2859 2863
2860 2864 // markup Form
2861 2865 div.markup-form {
2862 2866 margin-top: 20px;
2863 2867 }
2864 2868
2865 2869 .markup-form strong {
2866 2870 display: block;
2867 2871 margin-bottom: 15px;
2868 2872 }
2869 2873
2870 2874 .markup-form textarea {
2871 2875 width: 100%;
2872 2876 height: 100px;
2873 2877 font-family: @text-monospace;
2874 2878 }
2875 2879
2876 2880 form.markup-form {
2877 2881 margin-top: 10px;
2878 2882 margin-left: 10px;
2879 2883 }
2880 2884
2881 2885 .markup-form .comment-block-ta,
2882 2886 .markup-form .preview-box {
2883 2887 .border-radius(@border-radius);
2884 2888 .box-sizing(border-box);
2885 2889 background-color: white;
2886 2890 }
2887 2891
2888 2892 .markup-form .preview-box.unloaded {
2889 2893 height: 50px;
2890 2894 text-align: center;
2891 2895 padding: 20px;
2892 2896 background-color: white;
2893 2897 }
2894 2898
2895 2899
2896 2900 .dropzone-wrapper {
2897 2901 border: 1px solid @grey5;
2898 2902 padding: 20px;
2899 2903 }
2900 2904
2901 2905 .dropzone,
2902 2906 .dropzone-pure {
2903 2907 border: 2px dashed @grey5;
2904 2908 border-radius: 5px;
2905 2909 background: white;
2906 2910 min-height: 200px;
2907 2911 padding: 54px;
2908 2912
2909 2913 .dz-message {
2910 2914 font-weight: 700;
2911 2915 text-align: center;
2912 2916 margin: 2em 0;
2913 2917 }
2914 2918
2915 2919 }
2916 2920
2917 2921 .dz-preview {
2918 2922 margin: 10px 0 !important;
2919 2923 position: relative;
2920 2924 vertical-align: top;
2921 2925 padding: 10px;
2922 2926 border-bottom: 1px solid @grey5;
2923 2927 }
2924 2928
2925 2929 .dz-filename {
2926 2930 font-weight: 700;
2927 2931 float: left;
2928 2932 }
2929 2933
2930 2934 .dz-sending {
2931 2935 float: right;
2932 2936 }
2933 2937
2934 2938 .dz-response {
2935 2939 clear: both
2936 2940 }
2937 2941
2938 2942 .dz-filename-size {
2939 2943 float: right
2940 2944 }
2941 2945
2942 2946 .dz-error-message {
2943 2947 color: @alert2;
2944 2948 padding-top: 10px;
2945 2949 clear: both;
2946 2950 }
2947 2951
2948 2952
2949 2953 .user-hovercard {
2950 2954 padding: 5px;
2951 2955 }
2952 2956
2953 2957 .user-hovercard-icon {
2954 2958 display: inline;
2955 2959 padding: 0;
2956 2960 box-sizing: content-box;
2957 2961 border-radius: 50%;
2958 2962 float: left;
2959 2963 }
2960 2964
2961 2965 .user-hovercard-name {
2962 2966 float: right;
2963 2967 vertical-align: top;
2964 2968 padding-left: 10px;
2965 2969 min-width: 150px;
2966 2970 }
2967 2971
2968 2972 .user-hovercard-bio {
2969 2973 clear: both;
2970 2974 padding-top: 10px;
2971 2975 }
2972 2976
2973 2977 .user-hovercard-header {
2974 2978 clear: both;
2975 2979 min-height: 10px;
2976 2980 }
2977 2981
2978 2982 .user-hovercard-footer {
2979 2983 clear: both;
2980 2984 min-height: 10px;
2981 2985 }
2982 2986
2983 2987 .user-group-hovercard {
2984 2988 padding: 5px;
2985 2989 }
2986 2990
2987 2991 .user-group-hovercard-icon {
2988 2992 display: inline;
2989 2993 padding: 0;
2990 2994 box-sizing: content-box;
2991 2995 border-radius: 50%;
2992 2996 float: left;
2993 2997 }
2994 2998
2995 2999 .user-group-hovercard-name {
2996 3000 float: left;
2997 3001 vertical-align: top;
2998 3002 padding-left: 10px;
2999 3003 min-width: 150px;
3000 3004 }
3001 3005
3002 3006 .user-group-hovercard-icon i {
3003 3007 border: 1px solid @grey4;
3004 3008 border-radius: 4px;
3005 3009 }
3006 3010
3007 3011 .user-group-hovercard-bio {
3008 3012 clear: both;
3009 3013 padding-top: 10px;
3010 3014 line-height: 1.0em;
3011 3015 }
3012 3016
3013 3017 .user-group-hovercard-header {
3014 3018 clear: both;
3015 3019 min-height: 10px;
3016 3020 }
3017 3021
3018 3022 .user-group-hovercard-footer {
3019 3023 clear: both;
3020 3024 min-height: 10px;
3021 3025 }
3022 3026
3023 3027 .pr-hovercard-header {
3024 3028 clear: both;
3025 3029 display: block;
3026 3030 line-height: 20px;
3027 3031 }
3028 3032
3029 3033 .pr-hovercard-user {
3030 3034 display: flex;
3031 3035 align-items: center;
3032 3036 padding-left: 5px;
3033 3037 }
3034 3038
3035 3039 .pr-hovercard-title {
3036 3040 padding-top: 5px;
3037 3041 } No newline at end of file
@@ -1,392 +1,393 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('favicon', '/favicon.ico', []);
16 16 pyroutes.register('robots', '/robots.txt', []);
17 17 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
18 18 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
19 19 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
20 20 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
21 21 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
22 22 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
23 23 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
24 24 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
25 25 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
26 26 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
27 27 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
28 28 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
29 29 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
30 30 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
31 31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
32 32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
33 33 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
34 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
34 35 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
35 36 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
36 37 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
37 38 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
38 39 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
39 40 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
40 41 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
41 42 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
42 43 pyroutes.register('admin_home', '/_admin', []);
43 44 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
44 45 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
45 46 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
46 47 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
47 48 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
48 49 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
49 50 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
50 51 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
51 52 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
52 53 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
53 54 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
54 55 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
55 56 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
56 57 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
57 58 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
58 59 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
59 60 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
60 61 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
61 62 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
62 63 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
63 64 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
64 65 pyroutes.register('admin_settings', '/_admin/settings', []);
65 66 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
66 67 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
67 68 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
68 69 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
69 70 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
70 71 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
71 72 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
72 73 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
73 74 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
74 75 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
75 76 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
76 77 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
77 78 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
78 79 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
79 80 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
80 81 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
81 82 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
82 83 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
83 84 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
84 85 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
85 86 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
86 87 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
87 88 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
88 89 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
89 90 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
90 91 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
91 92 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
92 93 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
93 94 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
94 95 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
95 96 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
96 97 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
97 98 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
98 99 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
99 100 pyroutes.register('users', '/_admin/users', []);
100 101 pyroutes.register('users_data', '/_admin/users_data', []);
101 102 pyroutes.register('users_create', '/_admin/users/create', []);
102 103 pyroutes.register('users_new', '/_admin/users/new', []);
103 104 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
104 105 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
105 106 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
106 107 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
107 108 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
108 109 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
109 110 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
110 111 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
111 112 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
112 113 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
113 114 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
114 115 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
115 116 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
116 117 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
117 118 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
118 119 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
119 120 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
120 121 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
121 122 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
122 123 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
123 124 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
124 125 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
125 126 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
126 127 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
127 128 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
128 129 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
129 130 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
130 131 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
131 132 pyroutes.register('user_groups', '/_admin/user_groups', []);
132 133 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
133 134 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
134 135 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
135 136 pyroutes.register('repos', '/_admin/repos', []);
136 137 pyroutes.register('repos_data', '/_admin/repos_data', []);
137 138 pyroutes.register('repo_new', '/_admin/repos/new', []);
138 139 pyroutes.register('repo_create', '/_admin/repos/create', []);
139 140 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
140 141 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
141 142 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
142 143 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
143 144 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
144 145 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
145 146 pyroutes.register('channelstream_proxy', '/_channelstream', []);
146 147 pyroutes.register('upload_file', '/_file_store/upload', []);
147 148 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
148 149 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
149 150 pyroutes.register('logout', '/_admin/logout', []);
150 151 pyroutes.register('reset_password', '/_admin/password_reset', []);
151 152 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
152 153 pyroutes.register('home', '/', []);
153 154 pyroutes.register('main_page_repos_data', '/_home_repos', []);
154 155 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
155 156 pyroutes.register('user_autocomplete_data', '/_users', []);
156 157 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
157 158 pyroutes.register('repo_list_data', '/_repos', []);
158 159 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
159 160 pyroutes.register('goto_switcher_data', '/_goto_data', []);
160 161 pyroutes.register('markup_preview', '/_markup_preview', []);
161 162 pyroutes.register('file_preview', '/_file_preview', []);
162 163 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
163 164 pyroutes.register('journal', '/_admin/journal', []);
164 165 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
165 166 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
166 167 pyroutes.register('journal_public', '/_admin/public_journal', []);
167 168 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
168 169 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
169 170 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
170 171 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
171 172 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
172 173 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
173 174 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
174 175 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
175 176 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
176 177 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
177 178 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
178 179 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
179 180 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
180 181 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
181 182 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
182 183 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
183 184 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
184 185 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
185 186 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
186 187 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
187 188 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
188 189 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
189 190 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
190 191 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
191 192 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 193 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
193 194 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
194 195 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 196 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 197 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 198 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 199 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
199 200 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 201 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 202 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 203 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 204 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 205 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
205 206 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
206 207 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
207 208 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
208 209 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 210 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
210 211 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 212 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
212 213 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
213 214 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
214 215 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
215 216 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
216 217 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
217 218 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
218 219 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
219 220 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
220 221 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
221 222 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
222 223 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
223 224 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
224 225 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
225 226 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
226 227 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
227 228 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
228 229 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
229 230 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
230 231 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
231 232 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
232 233 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
233 234 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
234 235 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
235 236 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
236 237 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
237 238 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
238 239 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
239 240 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
240 241 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
241 242 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
242 243 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
243 244 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
244 245 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
245 246 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
246 247 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
247 248 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
248 249 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
249 250 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
250 251 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
251 252 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
252 253 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
253 254 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
254 255 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
255 256 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
256 257 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
257 258 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
258 259 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
259 260 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
260 261 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
261 262 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
262 263 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
263 264 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
264 265 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
265 266 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
266 267 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
267 268 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
268 269 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
269 270 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
270 271 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
271 272 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
272 273 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
273 274 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
274 275 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
275 276 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
276 277 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
277 278 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
278 279 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
279 280 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
280 281 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
281 282 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
282 283 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
283 284 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
284 285 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
285 286 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
286 287 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
287 288 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
288 289 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
289 290 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
290 291 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
291 292 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
292 293 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
293 294 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
294 295 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
295 296 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
296 297 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
297 298 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
298 299 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
299 300 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
300 301 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
301 302 pyroutes.register('search', '/_admin/search', []);
302 303 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
303 304 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
304 305 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
305 306 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
306 307 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
307 308 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
308 309 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
309 310 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
310 311 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
311 312 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
312 313 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
313 314 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
314 315 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
315 316 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
316 317 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
317 318 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
318 319 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
319 320 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
320 321 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
321 322 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
322 323 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
323 324 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
324 325 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
325 326 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
326 327 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
327 328 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
328 329 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
329 330 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
330 331 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
331 332 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
332 333 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
333 334 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
334 335 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
335 336 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
336 337 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
337 338 pyroutes.register('gists_show', '/_admin/gists', []);
338 339 pyroutes.register('gists_new', '/_admin/gists/new', []);
339 340 pyroutes.register('gists_create', '/_admin/gists/create', []);
340 341 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
341 342 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
342 343 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
343 344 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
344 345 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
345 346 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
346 347 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
347 348 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
348 349 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
349 350 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
350 351 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
351 352 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
352 353 pyroutes.register('apiv2', '/_admin/api', []);
353 354 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
354 355 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
355 356 pyroutes.register('login', '/_admin/login', []);
356 357 pyroutes.register('register', '/_admin/register', []);
357 358 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
358 359 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
359 360 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
360 361 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
361 362 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
362 363 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
363 364 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
364 365 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
365 366 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
366 367 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
367 368 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
368 369 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
369 370 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
370 371 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
371 372 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
372 373 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
373 374 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
374 375 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
375 376 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
376 377 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
377 378 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
378 379 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
379 380 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
380 381 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
381 382 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
382 383 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
383 384 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
384 385 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
385 386 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
386 387 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
387 388 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
388 389 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
389 390 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
390 391 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
391 392 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
392 393 }
@@ -1,691 +1,695 b''
1 1 // # Copyright (C) 2010-2019 RhodeCode GmbH
2 2 // #
3 3 // # This program is free software: you can redistribute it and/or modify
4 4 // # it under the terms of the GNU Affero General Public License, version 3
5 5 // # (only), as published by the Free Software Foundation.
6 6 // #
7 7 // # This program is distributed in the hope that it will be useful,
8 8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 // # GNU General Public License for more details.
11 11 // #
12 12 // # You should have received a copy of the GNU Affero General Public License
13 13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 // #
15 15 // # This program is dual-licensed. If you wish to learn more about the
16 16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 /**
20 20 RhodeCode JS Files
21 21 **/
22 22
23 23 if (typeof console == "undefined" || typeof console.log == "undefined"){
24 24 console = { log: function() {} }
25 25 }
26 26
27 27 // TODO: move the following function to submodules
28 28
29 29 /**
30 30 * show more
31 31 */
32 32 var show_more_event = function(){
33 33 $('table .show_more').click(function(e) {
34 34 var cid = e.target.id.substring(1);
35 35 var button = $(this);
36 36 if (button.hasClass('open')) {
37 37 $('#'+cid).hide();
38 38 button.removeClass('open');
39 39 } else {
40 40 $('#'+cid).show();
41 41 button.addClass('open one');
42 42 }
43 43 });
44 44 };
45 45
46 46 var compare_radio_buttons = function(repo_name, compare_ref_type){
47 47 $('#compare_action').on('click', function(e){
48 48 e.preventDefault();
49 49
50 50 var source = $('input[name=compare_source]:checked').val();
51 51 var target = $('input[name=compare_target]:checked').val();
52 52 if(source && target){
53 53 var url_data = {
54 54 repo_name: repo_name,
55 55 source_ref: source,
56 56 source_ref_type: compare_ref_type,
57 57 target_ref: target,
58 58 target_ref_type: compare_ref_type,
59 59 merge: 1
60 60 };
61 61 window.location = pyroutes.url('repo_compare', url_data);
62 62 }
63 63 });
64 64 $('.compare-radio-button').on('click', function(e){
65 65 var source = $('input[name=compare_source]:checked').val();
66 66 var target = $('input[name=compare_target]:checked').val();
67 67 if(source && target){
68 68 $('#compare_action').removeAttr("disabled");
69 69 $('#compare_action').removeClass("disabled");
70 70 }
71 71 })
72 72 };
73 73
74 74 var showRepoSize = function(target, repo_name, commit_id, callback) {
75 75 var container = $('#' + target);
76 76 var url = pyroutes.url('repo_stats',
77 77 {"repo_name": repo_name, "commit_id": commit_id});
78 78
79 79 container.show();
80 80 if (!container.hasClass('loaded')) {
81 81 $.ajax({url: url})
82 82 .complete(function (data) {
83 83 var responseJSON = data.responseJSON;
84 84 container.addClass('loaded');
85 85 container.html(responseJSON.size);
86 86 callback(responseJSON.code_stats)
87 87 })
88 88 .fail(function (data) {
89 89 console.log('failed to load repo stats');
90 90 });
91 91 }
92 92
93 93 };
94 94
95 95 var showRepoStats = function(target, data){
96 96 var container = $('#' + target);
97 97
98 98 if (container.hasClass('loaded')) {
99 99 return
100 100 }
101 101
102 102 var total = 0;
103 103 var no_data = true;
104 104 var tbl = document.createElement('table');
105 105 tbl.setAttribute('class', 'trending_language_tbl rctable');
106 106
107 107 $.each(data, function(key, val){
108 108 total += val.count;
109 109 });
110 110
111 111 var sortedStats = [];
112 112 for (var obj in data){
113 113 sortedStats.push([obj, data[obj]])
114 114 }
115 115 var sortedData = sortedStats.sort(function (a, b) {
116 116 return b[1].count - a[1].count
117 117 });
118 118 var cnt = 0;
119 119 $.each(sortedData, function(idx, val){
120 120 cnt += 1;
121 121 no_data = false;
122 122
123 123 var tr = document.createElement('tr');
124 124
125 125 var key = val[0];
126 126 var obj = {"desc": val[1].desc, "count": val[1].count};
127 127
128 128 // meta language names
129 129 var td1 = document.createElement('td');
130 130 var trending_language_label = document.createElement('div');
131 131 trending_language_label.innerHTML = obj.desc;
132 132 td1.appendChild(trending_language_label);
133 133
134 134 // extensions
135 135 var td2 = document.createElement('td');
136 136 var extension = document.createElement('div');
137 137 extension.innerHTML = ".{0}".format(key)
138 138 td2.appendChild(extension);
139 139
140 140 // number of files
141 141 var td3 = document.createElement('td');
142 142 var file_count = document.createElement('div');
143 143 var percentage_num = Math.round((obj.count / total * 100), 2);
144 144 var label = _ngettext('file', 'files', obj.count);
145 145 file_count.innerHTML = "{0} {1} ({2}%)".format(obj.count, label, percentage_num) ;
146 146 td3.appendChild(file_count);
147 147
148 148 // percentage
149 149 var td4 = document.createElement('td');
150 150 td4.setAttribute("class", 'trending_language');
151 151
152 152 var percentage = document.createElement('div');
153 153 percentage.setAttribute('class', 'lang-bar');
154 154 percentage.innerHTML = "&nbsp;";
155 155 percentage.style.width = percentage_num + '%';
156 156 td4.appendChild(percentage);
157 157
158 158 tr.appendChild(td1);
159 159 tr.appendChild(td2);
160 160 tr.appendChild(td3);
161 161 tr.appendChild(td4);
162 162 tbl.appendChild(tr);
163 163
164 164 });
165 165
166 166 $(container).html(tbl);
167 167 $(container).addClass('loaded');
168 168
169 169 $('#code_stats_show_more').on('click', function (e) {
170 170 e.preventDefault();
171 171 $('.stats_hidden').each(function (idx) {
172 172 $(this).css("display", "");
173 173 });
174 174 $('#code_stats_show_more').hide();
175 175 });
176 176
177 177 };
178 178
179 179 // returns a node from given html;
180 180 var fromHTML = function(html){
181 181 var _html = document.createElement('element');
182 182 _html.innerHTML = html;
183 183 return _html;
184 184 };
185 185
186 186 // Toggle Collapsable Content
187 187 function collapsableContent() {
188 188
189 189 $('.collapsable-content').not('.no-hide').hide();
190 190
191 191 $('.btn-collapse').unbind(); //in case we've been here before
192 192 $('.btn-collapse').click(function() {
193 193 var button = $(this);
194 194 var togglename = $(this).data("toggle");
195 195 $('.collapsable-content[data-toggle='+togglename+']').toggle();
196 196 if ($(this).html()=="Show Less")
197 197 $(this).html("Show More");
198 198 else
199 199 $(this).html("Show Less");
200 200 });
201 201 };
202 202
203 203 var timeagoActivate = function() {
204 204 $("time.timeago").timeago();
205 205 };
206 206
207 207
208 208 var clipboardActivate = function() {
209 209 /*
210 210 *
211 211 * <i class="tooltip icon-plus clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
212 212 * */
213 213 var clipboard = new ClipboardJS('.clipboard-action');
214 214
215 215 clipboard.on('success', function(e) {
216 216 var callback = function () {
217 217 $(e.trigger).animate({'opacity': 1.00}, 200)
218 218 };
219 219 $(e.trigger).animate({'opacity': 0.15}, 200, callback);
220 220 e.clearSelection();
221 221 });
222 222 };
223 223
224 224 var tooltipActivate = function () {
225 225 var delay = 50;
226 226 var animation = 'fade';
227 227 var theme = 'tooltipster-shadow';
228 228 var debug = false;
229 229
230 230 $('.tooltip').tooltipster({
231 231 debug: debug,
232 232 theme: theme,
233 233 animation: animation,
234 234 delay: delay,
235 235 contentCloning: true,
236 236 contentAsHTML: true,
237 237
238 238 functionBefore: function (instance, helper) {
239 239 var $origin = $(helper.origin);
240 240 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(instance.content());
241 241 instance.content(data);
242 242 }
243 243 });
244 244 var hovercardCache = {};
245 245
246 246 var loadHoverCard = function (url, altHovercard, callback) {
247 247 var id = url;
248 248
249 249 if (hovercardCache[id] !== undefined) {
250 250 callback(hovercardCache[id]);
251 251 return true;
252 252 }
253 253
254 254 hovercardCache[id] = undefined;
255 255 $.get(url, function (data) {
256 256 hovercardCache[id] = data;
257 257 callback(hovercardCache[id]);
258 258 return true;
259 259 }).fail(function (data, textStatus, errorThrown) {
260 260
261 261 if (parseInt(data.status) === 404) {
262 262 var msg = "<p>{0}</p>".format(altHovercard || "No Data exists for this hovercard");
263 263 } else {
264 264 var msg = "<p class='error-message'>Error while fetching hovercard.\nError code {0} ({1}).</p>".format(data.status,data.statusText);
265 265 }
266 266 callback(msg);
267 267 return false
268 268 });
269 269 };
270 270
271 271 $('.tooltip-hovercard').tooltipster({
272 272 debug: debug,
273 273 theme: theme,
274 274 animation: animation,
275 275 delay: delay,
276 276 interactive: true,
277 277 contentCloning: true,
278 278
279 279 trigger: 'custom',
280 280 triggerOpen: {
281 281 mouseenter: true,
282 282 },
283 283 triggerClose: {
284 284 mouseleave: true,
285 285 originClick: true,
286 286 touchleave: true
287 287 },
288 288 content: _gettext('Loading...'),
289 289 contentAsHTML: true,
290 290 updateAnimation: null,
291 291
292 292 functionBefore: function (instance, helper) {
293 293
294 294 var $origin = $(helper.origin);
295 295
296 296 // we set a variable so the data is only loaded once via Ajax, not every time the tooltip opens
297 297 if ($origin.data('loaded') !== true) {
298 298 var hovercardUrl = $origin.data('hovercardUrl');
299 299 var altHovercard =$origin.data('hovercardAlt');
300 300
301 301 if (hovercardUrl !== undefined && hovercardUrl !== "") {
302 if (hovercardUrl.substr(0,12) === 'pyroutes.url'){
303 hovercardUrl = eval(hovercardUrl)
304 }
305
302 306 var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
303 307 instance.content(data);
304 308 })
305 309 } else {
306 310 if ($origin.data('hovercardAltHtml')) {
307 311 var data = atob($origin.data('hovercardAltHtml'));
308 312 } else {
309 313 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(altHovercard)
310 314 }
311 315 var loaded = true;
312 316 instance.content(data);
313 317 }
314 318
315 319 // to remember that the data has been loaded
316 320 $origin.data('loaded', loaded);
317 321 }
318 322 }
319 323 })
320 324 };
321 325
322 326 // Formatting values in a Select2 dropdown of commit references
323 327 var formatSelect2SelectionRefs = function(commit_ref){
324 328 var tmpl = '';
325 329 if (!commit_ref.text || commit_ref.type === 'sha'){
326 330 return commit_ref.text;
327 331 }
328 332 if (commit_ref.type === 'branch'){
329 333 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
330 334 } else if (commit_ref.type === 'tag'){
331 335 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
332 336 } else if (commit_ref.type === 'book'){
333 337 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
334 338 }
335 339 return tmpl.concat(escapeHtml(commit_ref.text));
336 340 };
337 341
338 342 // takes a given html element and scrolls it down offset pixels
339 343 function offsetScroll(element, offset) {
340 344 setTimeout(function() {
341 345 var location = element.offset().top;
342 346 // some browsers use body, some use html
343 347 $('html, body').animate({ scrollTop: (location - offset) });
344 348 }, 100);
345 349 }
346 350
347 351 // scroll an element `percent`% from the top of page in `time` ms
348 352 function scrollToElement(element, percent, time) {
349 353 percent = (percent === undefined ? 25 : percent);
350 354 time = (time === undefined ? 100 : time);
351 355
352 356 var $element = $(element);
353 357 if ($element.length == 0) {
354 358 throw('Cannot scroll to {0}'.format(element))
355 359 }
356 360 var elOffset = $element.offset().top;
357 361 var elHeight = $element.height();
358 362 var windowHeight = $(window).height();
359 363 var offset = elOffset;
360 364 if (elHeight < windowHeight) {
361 365 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
362 366 }
363 367 setTimeout(function() {
364 368 $('html, body').animate({ scrollTop: offset});
365 369 }, time);
366 370 }
367 371
368 372 /**
369 373 * global hooks after DOM is loaded
370 374 */
371 375 $(document).ready(function() {
372 376 firefoxAnchorFix();
373 377
374 378 $('.navigation a.menulink').on('click', function(e){
375 379 var menuitem = $(this).parent('li');
376 380 if (menuitem.hasClass('open')) {
377 381 menuitem.removeClass('open');
378 382 } else {
379 383 menuitem.addClass('open');
380 384 $(document).on('click', function(event) {
381 385 if (!$(event.target).closest(menuitem).length) {
382 386 menuitem.removeClass('open');
383 387 }
384 388 });
385 389 }
386 390 });
387 391
388 392 $('body').on('click', '.cb-lineno a', function(event) {
389 393 function sortNumber(a,b) {
390 394 return a - b;
391 395 }
392 396
393 397 var lineNo = $(this).data('lineNo');
394 398 var lineName = $(this).attr('name');
395 399
396 400 if (lineNo) {
397 401 var prevLine = $('.cb-line-selected a').data('lineNo');
398 402
399 403 // on shift, we do a range selection, if we got previous line
400 404 if (event.shiftKey && prevLine !== undefined) {
401 405 var prevLine = parseInt(prevLine);
402 406 var nextLine = parseInt(lineNo);
403 407 var pos = [prevLine, nextLine].sort(sortNumber);
404 408 var anchor = '#L{0}-{1}'.format(pos[0], pos[1]);
405 409
406 410 // single click
407 411 } else {
408 412 var nextLine = parseInt(lineNo);
409 413 var pos = [nextLine, nextLine];
410 414 var anchor = '#L{0}'.format(pos[0]);
411 415
412 416 }
413 417 // highlight
414 418 var range = [];
415 419 for (var i = pos[0]; i <= pos[1]; i++) {
416 420 range.push(i);
417 421 }
418 422 // clear old selected lines
419 423 $('.cb-line-selected').removeClass('cb-line-selected');
420 424
421 425 $.each(range, function (i, lineNo) {
422 426 var line_td = $('td.cb-lineno#L' + lineNo);
423 427
424 428 if (line_td.length) {
425 429 line_td.addClass('cb-line-selected'); // line number td
426 430 line_td.prev().addClass('cb-line-selected'); // line data
427 431 line_td.next().addClass('cb-line-selected'); // line content
428 432 }
429 433 });
430 434
431 435 } else if (lineName !== undefined) { // lineName only occurs in diffs
432 436 // clear old selected lines
433 437 $('td.cb-line-selected').removeClass('cb-line-selected');
434 438 var anchor = '#{0}'.format(lineName);
435 439 var diffmode = templateContext.session_attrs.diffmode || "sideside";
436 440
437 441 if (diffmode === "unified") {
438 442 $(this).closest('tr').find('td').addClass('cb-line-selected');
439 443 } else {
440 444 var activeTd = $(this).closest('td');
441 445 activeTd.addClass('cb-line-selected');
442 446 activeTd.next('td').addClass('cb-line-selected');
443 447 }
444 448
445 449 }
446 450
447 451 // Replace URL without jumping to it if browser supports.
448 452 // Default otherwise
449 453 if (history.pushState && anchor !== undefined) {
450 454 var new_location = location.href.rstrip('#');
451 455 if (location.hash) {
452 456 // location without hash
453 457 new_location = new_location.replace(location.hash, "");
454 458 }
455 459
456 460 // Make new anchor url
457 461 new_location = new_location + anchor;
458 462 history.pushState(true, document.title, new_location);
459 463
460 464 return false;
461 465 }
462 466
463 467 });
464 468
465 469 $('.collapse_file').on('click', function(e) {
466 470 e.stopPropagation();
467 471 if ($(e.target).is('a')) { return; }
468 472 var node = $(e.delegateTarget).first();
469 473 var icon = $($(node.children().first()).children().first());
470 474 var id = node.attr('fid');
471 475 var target = $('#'+id);
472 476 var tr = $('#tr_'+id);
473 477 var diff = $('#diff_'+id);
474 478 if(node.hasClass('expand_file')){
475 479 node.removeClass('expand_file');
476 480 icon.removeClass('expand_file_icon');
477 481 node.addClass('collapse_file');
478 482 icon.addClass('collapse_file_icon');
479 483 diff.show();
480 484 tr.show();
481 485 target.show();
482 486 } else {
483 487 node.removeClass('collapse_file');
484 488 icon.removeClass('collapse_file_icon');
485 489 node.addClass('expand_file');
486 490 icon.addClass('expand_file_icon');
487 491 diff.hide();
488 492 tr.hide();
489 493 target.hide();
490 494 }
491 495 });
492 496
493 497 $('#expand_all_files').click(function() {
494 498 $('.expand_file').each(function() {
495 499 var node = $(this);
496 500 var icon = $($(node.children().first()).children().first());
497 501 var id = $(this).attr('fid');
498 502 var target = $('#'+id);
499 503 var tr = $('#tr_'+id);
500 504 var diff = $('#diff_'+id);
501 505 node.removeClass('expand_file');
502 506 icon.removeClass('expand_file_icon');
503 507 node.addClass('collapse_file');
504 508 icon.addClass('collapse_file_icon');
505 509 diff.show();
506 510 tr.show();
507 511 target.show();
508 512 });
509 513 });
510 514
511 515 $('#collapse_all_files').click(function() {
512 516 $('.collapse_file').each(function() {
513 517 var node = $(this);
514 518 var icon = $($(node.children().first()).children().first());
515 519 var id = $(this).attr('fid');
516 520 var target = $('#'+id);
517 521 var tr = $('#tr_'+id);
518 522 var diff = $('#diff_'+id);
519 523 node.removeClass('collapse_file');
520 524 icon.removeClass('collapse_file_icon');
521 525 node.addClass('expand_file');
522 526 icon.addClass('expand_file_icon');
523 527 diff.hide();
524 528 tr.hide();
525 529 target.hide();
526 530 });
527 531 });
528 532
529 533 // Mouse over behavior for comments and line selection
530 534
531 535 // Select the line that comes from the url anchor
532 536 // At the time of development, Chrome didn't seem to support jquery's :target
533 537 // element, so I had to scroll manually
534 538
535 539 if (location.hash) {
536 540 var result = splitDelimitedHash(location.hash);
537 541
538 542 var loc = result.loc;
539 543
540 544 if (loc.length > 1) {
541 545
542 546 var highlightable_line_tds = [];
543 547
544 548 // source code line format
545 549 var page_highlights = loc.substring(loc.indexOf('#') + 1).split('L');
546 550
547 551 // multi-line HL, for files
548 552 if (page_highlights.length > 1) {
549 553 var highlight_ranges = page_highlights[1].split(",");
550 554 var h_lines = [];
551 555 for (var pos in highlight_ranges) {
552 556 var _range = highlight_ranges[pos].split('-');
553 557 if (_range.length === 2) {
554 558 var start = parseInt(_range[0]);
555 559 var end = parseInt(_range[1]);
556 560 if (start < end) {
557 561 for (var i = start; i <= end; i++) {
558 562 h_lines.push(i);
559 563 }
560 564 }
561 565 } else {
562 566 h_lines.push(parseInt(highlight_ranges[pos]));
563 567 }
564 568 }
565 569 for (pos in h_lines) {
566 570 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
567 571 if (line_td.length) {
568 572 highlightable_line_tds.push(line_td);
569 573 }
570 574 }
571 575 }
572 576
573 577 // now check a direct id reference of line in diff / pull-request page)
574 578 if ($(loc).length > 0 && $(loc).hasClass('cb-lineno')) {
575 579 highlightable_line_tds.push($(loc));
576 580 }
577 581
578 582 // mark diff lines as selected
579 583 $.each(highlightable_line_tds, function (i, $td) {
580 584 $td.addClass('cb-line-selected'); // line number td
581 585 $td.prev().addClass('cb-line-selected'); // line data
582 586 $td.next().addClass('cb-line-selected'); // line content
583 587 });
584 588
585 589 if (highlightable_line_tds.length > 0) {
586 590 var $first_line_td = highlightable_line_tds[0];
587 591 scrollToElement($first_line_td);
588 592 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
589 593 td: $first_line_td,
590 594 remainder: result.remainder
591 595 });
592 596 } else {
593 597 // case for direct anchor to comments
594 598 var $line = $(loc);
595 599
596 600 if ($line.hasClass('comment-general')) {
597 601 $line.show();
598 602 } else if ($line.hasClass('comment-inline')) {
599 603 $line.show();
600 604 var $cb = $line.closest('.cb');
601 605 $cb.removeClass('cb-collapsed')
602 606 }
603 607 if ($line.length > 0) {
604 608 $line.addClass('comment-selected-hl');
605 609 offsetScroll($line, 70);
606 610 }
607 611 if (!$line.hasClass('comment-outdated') && result.remainder === '/ReplyToComment') {
608 612 $line.nextAll('.cb-comment-add-button').trigger('click');
609 613 }
610 614 }
611 615
612 616 }
613 617 }
614 618 collapsableContent();
615 619 });
616 620
617 621 var feedLifetimeOptions = function(query, initialData){
618 622 var data = {results: []};
619 623 var isQuery = typeof query.term !== 'undefined';
620 624
621 625 var section = _gettext('Lifetime');
622 626 var children = [];
623 627
624 628 //filter results
625 629 $.each(initialData.results, function(idx, value) {
626 630
627 631 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
628 632 children.push({
629 633 'id': this.id,
630 634 'text': this.text
631 635 })
632 636 }
633 637
634 638 });
635 639 data.results.push({
636 640 'text': section,
637 641 'children': children
638 642 });
639 643
640 644 if (isQuery) {
641 645
642 646 var now = moment.utc();
643 647
644 648 var parseQuery = function(entry, now){
645 649 var fmt = 'DD/MM/YYYY H:mm';
646 650 var parsed = moment.utc(entry, fmt);
647 651 var diffInMin = parsed.diff(now, 'minutes');
648 652
649 653 if (diffInMin > 0){
650 654 return {
651 655 id: diffInMin,
652 656 text: parsed.format(fmt)
653 657 }
654 658 } else {
655 659 return {
656 660 id: undefined,
657 661 text: parsed.format('DD/MM/YYYY') + ' ' + _gettext('date not in future')
658 662 }
659 663 }
660 664
661 665
662 666 };
663 667
664 668 data.results.push({
665 669 'text': _gettext('Specified expiration date'),
666 670 'children': [{
667 671 'id': parseQuery(query.term, now).id,
668 672 'text': parseQuery(query.term, now).text
669 673 }]
670 674 });
671 675 }
672 676
673 677 query.callback(data);
674 678 };
675 679
676 680
677 681 var storeUserSessionAttr = function (key, val) {
678 682
679 683 var postData = {
680 684 'key': key,
681 685 'val': val,
682 686 'csrf_token': CSRF_TOKEN
683 687 };
684 688
685 689 var success = function(o) {
686 690 return true
687 691 };
688 692
689 693 ajaxPOST(pyroutes.url('store_user_session_value'), postData, success);
690 694 return false;
691 695 };
General Comments 0
You need to be logged in to leave comments. Login now