##// END OF EJS Templates
diff parser: redefined operations stats for changes...
marcink -
r3821:ce4b7023 beta
parent child Browse files
Show More
@@ -0,0 +1,18 b''
1 diff --git a/gravatar.png b/gravatar.png
2 old mode 100644
3 new mode 100755
4 index 54d2d129e3372c45a4c68a742e269864222e99ae..0c1d65410bd51fdff935443e01931c9fc3ad7def
5 GIT binary patch
6 literal 740
7 zc%17D@N?(olHy`uVBq!ia0vp^dx3Z#2NRHduQ>B0kYX$ja(7}_cTVOdki%Kv5n0T@
8 zz%2~Ij105pNB{-dOFVsD*>AH+2@7*F&3eGWz`&H|>EaktaqI0JMZd!V5(hqpU(%ki
9 zz<{N_Dc~^g1GeA{8S#b#jBU<`Ij0FINT{SO2`=WI*Kku%Kte?~QvUtk`~FuatbIH`
10 zU*0#<bY2fr$(Coz4(2b|?k<qNz`M&4#A?WcvPzmkEJg29#pjiUe<s|iw%c!Ml>foD
11 zHLr#RtfPb(q61ZL^D3dLy27sS9LG1ks-ApS8e$A1NIi%J(b=2_we?fTsn6Zh<#UVP
12 z|9tiF%$|eaMRt7@#I6)<9go)1-`(@)=Q(p!@3vNKDKmRt(o@-7dHLx1lNY~Ad}g~_
13 za{b)1``zCC$!DbBm~WE-irmOC$k!;|zwzb_^B2daEtWo!yMN=;86Y!nbQtDu5Wn34
14 zbmZh?b(0@$%sb%=43(hD^~>9*yZ+6yNtdtp|J$sq{^jrc-CO$Jn%~HOWByJ0bK9TY
15 zg@4_kydS*R^JDe{4Z08FKRNbQ`g%Ud?r+k+d3UblwmiT6sL83<_jKRAJ-Pr-V6<tp
16 z?epIfY2R5iFZ#Ccl<T?EX78;p`&F5H??E-!-5(q%k>Y5MY!uto=R2=&d?)y?yZLYL
17 zJ^SCEe$Bh{bKS3dDW9<fAX0p_*<5X%lMalj*{B8|p0JPMtzFP9%Uvy?WXj;_>gTe~
18 RDWNH`I3+QqIFSoR0|1y<SJMCh No newline at end of file
@@ -0,0 +1,10 b''
1 diff --git a/README b/README.rst
2 rename from README
3 rename to README.rst
4 --- a/README
5 +++ b/README.rst
6 @@ -1,1 +1,4 @@
7 readme2
8 +line 1
9 + line2
10 + No newline at end of file
@@ -0,0 +1,15 b''
1 diff --git a/README.rst b/README
2 old mode 100755
3 new mode 100644
4 rename from README.rst
5 rename to README
6 --- a/README.rst
7 +++ b/README
8 @@ -1,4 +1,7 @@
9 readme2
10 line 1
11 line2
12
13 +line 1
14 + line2
15 + No newline at end of file
@@ -0,0 +1,5 b''
1 diff --git a/README.rst b/README
2 old mode 100644
3 new mode 100755
4 rename from README.rst
5 rename to README No newline at end of file
@@ -1,440 +1,439 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changeset
3 rhodecode.controllers.changeset
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changeset controller for pylons showoing changes beetween
6 changeset controller for pylons showoing changes beetween
7 revisions
7 revisions
8
8
9 :created_on: Apr 25, 2010
9 :created_on: Apr 25, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28 from collections import defaultdict
28 from collections import defaultdict
29 from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound
29 from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound
30
30
31 from pylons import tmpl_context as c, url, request, response
31 from pylons import tmpl_context as c, url, request, response
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from rhodecode.lib.utils import jsonify
34 from rhodecode.lib.utils import jsonify
35
35
36 from rhodecode.lib.vcs.exceptions import RepositoryError, \
36 from rhodecode.lib.vcs.exceptions import RepositoryError, \
37 ChangesetDoesNotExistError
37 ChangesetDoesNotExistError
38
38
39 import rhodecode.lib.helpers as h
39 import rhodecode.lib.helpers as h
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
41 NotAnonymous
41 NotAnonymous
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import action_logger
43 from rhodecode.lib.utils import action_logger
44 from rhodecode.lib.compat import OrderedDict
44 from rhodecode.lib.compat import OrderedDict
45 from rhodecode.lib import diffs
45 from rhodecode.lib import diffs
46 from rhodecode.model.db import ChangesetComment, ChangesetStatus
46 from rhodecode.model.db import ChangesetComment, ChangesetStatus
47 from rhodecode.model.comment import ChangesetCommentsModel
47 from rhodecode.model.comment import ChangesetCommentsModel
48 from rhodecode.model.changeset_status import ChangesetStatusModel
48 from rhodecode.model.changeset_status import ChangesetStatusModel
49 from rhodecode.model.meta import Session
49 from rhodecode.model.meta import Session
50 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.lib.diffs import LimitedDiffContainer
51 from rhodecode.lib.diffs import LimitedDiffContainer
52 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
52 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
53 from rhodecode.lib.vcs.backends.base import EmptyChangeset
53 from rhodecode.lib.vcs.backends.base import EmptyChangeset
54 from rhodecode.lib.utils2 import safe_unicode
54 from rhodecode.lib.utils2 import safe_unicode
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58
58
59 def _update_with_GET(params, GET):
59 def _update_with_GET(params, GET):
60 for k in ['diff1', 'diff2', 'diff']:
60 for k in ['diff1', 'diff2', 'diff']:
61 params[k] += GET.getall(k)
61 params[k] += GET.getall(k)
62
62
63
63
64 def anchor_url(revision, path, GET):
64 def anchor_url(revision, path, GET):
65 fid = h.FID(revision, path)
65 fid = h.FID(revision, path)
66 return h.url.current(anchor=fid, **dict(GET))
66 return h.url.current(anchor=fid, **dict(GET))
67
67
68
68
69 def get_ignore_ws(fid, GET):
69 def get_ignore_ws(fid, GET):
70 ig_ws_global = GET.get('ignorews')
70 ig_ws_global = GET.get('ignorews')
71 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
71 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
72 if ig_ws:
72 if ig_ws:
73 try:
73 try:
74 return int(ig_ws[0].split(':')[-1])
74 return int(ig_ws[0].split(':')[-1])
75 except Exception:
75 except Exception:
76 pass
76 pass
77 return ig_ws_global
77 return ig_ws_global
78
78
79
79
80 def _ignorews_url(GET, fileid=None):
80 def _ignorews_url(GET, fileid=None):
81 fileid = str(fileid) if fileid else None
81 fileid = str(fileid) if fileid else None
82 params = defaultdict(list)
82 params = defaultdict(list)
83 _update_with_GET(params, GET)
83 _update_with_GET(params, GET)
84 lbl = _('Show white space')
84 lbl = _('Show white space')
85 ig_ws = get_ignore_ws(fileid, GET)
85 ig_ws = get_ignore_ws(fileid, GET)
86 ln_ctx = get_line_ctx(fileid, GET)
86 ln_ctx = get_line_ctx(fileid, GET)
87 # global option
87 # global option
88 if fileid is None:
88 if fileid is None:
89 if ig_ws is None:
89 if ig_ws is None:
90 params['ignorews'] += [1]
90 params['ignorews'] += [1]
91 lbl = _('Ignore white space')
91 lbl = _('Ignore white space')
92 ctx_key = 'context'
92 ctx_key = 'context'
93 ctx_val = ln_ctx
93 ctx_val = ln_ctx
94 # per file options
94 # per file options
95 else:
95 else:
96 if ig_ws is None:
96 if ig_ws is None:
97 params[fileid] += ['WS:1']
97 params[fileid] += ['WS:1']
98 lbl = _('Ignore white space')
98 lbl = _('Ignore white space')
99
99
100 ctx_key = fileid
100 ctx_key = fileid
101 ctx_val = 'C:%s' % ln_ctx
101 ctx_val = 'C:%s' % ln_ctx
102 # if we have passed in ln_ctx pass it along to our params
102 # if we have passed in ln_ctx pass it along to our params
103 if ln_ctx:
103 if ln_ctx:
104 params[ctx_key] += [ctx_val]
104 params[ctx_key] += [ctx_val]
105
105
106 params['anchor'] = fileid
106 params['anchor'] = fileid
107 img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
107 img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
108 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
108 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
109
109
110
110
111 def get_line_ctx(fid, GET):
111 def get_line_ctx(fid, GET):
112 ln_ctx_global = GET.get('context')
112 ln_ctx_global = GET.get('context')
113 if fid:
113 if fid:
114 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
114 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
115 else:
115 else:
116 _ln_ctx = filter(lambda k: k.startswith('C'), GET)
116 _ln_ctx = filter(lambda k: k.startswith('C'), GET)
117 ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global
117 ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global
118 if ln_ctx:
118 if ln_ctx:
119 ln_ctx = [ln_ctx]
119 ln_ctx = [ln_ctx]
120
120
121 if ln_ctx:
121 if ln_ctx:
122 retval = ln_ctx[0].split(':')[-1]
122 retval = ln_ctx[0].split(':')[-1]
123 else:
123 else:
124 retval = ln_ctx_global
124 retval = ln_ctx_global
125
125
126 try:
126 try:
127 return int(retval)
127 return int(retval)
128 except Exception:
128 except Exception:
129 return 3
129 return 3
130
130
131
131
132 def _context_url(GET, fileid=None):
132 def _context_url(GET, fileid=None):
133 """
133 """
134 Generates url for context lines
134 Generates url for context lines
135
135
136 :param fileid:
136 :param fileid:
137 """
137 """
138
138
139 fileid = str(fileid) if fileid else None
139 fileid = str(fileid) if fileid else None
140 ig_ws = get_ignore_ws(fileid, GET)
140 ig_ws = get_ignore_ws(fileid, GET)
141 ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
141 ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
142
142
143 params = defaultdict(list)
143 params = defaultdict(list)
144 _update_with_GET(params, GET)
144 _update_with_GET(params, GET)
145
145
146 # global option
146 # global option
147 if fileid is None:
147 if fileid is None:
148 if ln_ctx > 0:
148 if ln_ctx > 0:
149 params['context'] += [ln_ctx]
149 params['context'] += [ln_ctx]
150
150
151 if ig_ws:
151 if ig_ws:
152 ig_ws_key = 'ignorews'
152 ig_ws_key = 'ignorews'
153 ig_ws_val = 1
153 ig_ws_val = 1
154
154
155 # per file option
155 # per file option
156 else:
156 else:
157 params[fileid] += ['C:%s' % ln_ctx]
157 params[fileid] += ['C:%s' % ln_ctx]
158 ig_ws_key = fileid
158 ig_ws_key = fileid
159 ig_ws_val = 'WS:%s' % 1
159 ig_ws_val = 'WS:%s' % 1
160
160
161 if ig_ws:
161 if ig_ws:
162 params[ig_ws_key] += [ig_ws_val]
162 params[ig_ws_key] += [ig_ws_val]
163
163
164 lbl = _('%s line context') % ln_ctx
164 lbl = _('%s line context') % ln_ctx
165
165
166 params['anchor'] = fileid
166 params['anchor'] = fileid
167 img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
167 img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
168 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
168 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
169
169
170
170
171 class ChangesetController(BaseRepoController):
171 class ChangesetController(BaseRepoController):
172
172
173 def __before__(self):
173 def __before__(self):
174 super(ChangesetController, self).__before__()
174 super(ChangesetController, self).__before__()
175 c.affected_files_cut_off = 60
175 c.affected_files_cut_off = 60
176 repo_model = RepoModel()
176 repo_model = RepoModel()
177 c.users_array = repo_model.get_users_js()
177 c.users_array = repo_model.get_users_js()
178 c.users_groups_array = repo_model.get_users_groups_js()
178 c.users_groups_array = repo_model.get_users_groups_js()
179
179
180 def _index(self, revision, method):
180 def _index(self, revision, method):
181 c.anchor_url = anchor_url
181 c.anchor_url = anchor_url
182 c.ignorews_url = _ignorews_url
182 c.ignorews_url = _ignorews_url
183 c.context_url = _context_url
183 c.context_url = _context_url
184 c.fulldiff = fulldiff = request.GET.get('fulldiff')
184 c.fulldiff = fulldiff = request.GET.get('fulldiff')
185 #get ranges of revisions if preset
185 #get ranges of revisions if preset
186 rev_range = revision.split('...')[:2]
186 rev_range = revision.split('...')[:2]
187 enable_comments = True
187 enable_comments = True
188 try:
188 try:
189 if len(rev_range) == 2:
189 if len(rev_range) == 2:
190 enable_comments = False
190 enable_comments = False
191 rev_start = rev_range[0]
191 rev_start = rev_range[0]
192 rev_end = rev_range[1]
192 rev_end = rev_range[1]
193 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
193 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
194 end=rev_end)
194 end=rev_end)
195 else:
195 else:
196 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
196 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
197
197
198 c.cs_ranges = list(rev_ranges)
198 c.cs_ranges = list(rev_ranges)
199 if not c.cs_ranges:
199 if not c.cs_ranges:
200 raise RepositoryError('Changeset range returned empty result')
200 raise RepositoryError('Changeset range returned empty result')
201
201
202 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
202 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
203 log.error(traceback.format_exc())
203 log.error(traceback.format_exc())
204 h.flash(str(e), category='error')
204 h.flash(str(e), category='error')
205 raise HTTPNotFound()
205 raise HTTPNotFound()
206
206
207 c.changes = OrderedDict()
207 c.changes = OrderedDict()
208
208
209 c.lines_added = 0 # count of lines added
209 c.lines_added = 0 # count of lines added
210 c.lines_deleted = 0 # count of lines removes
210 c.lines_deleted = 0 # count of lines removes
211
211
212 c.changeset_statuses = ChangesetStatus.STATUSES
212 c.changeset_statuses = ChangesetStatus.STATUSES
213 c.comments = []
213 c.comments = []
214 c.statuses = []
214 c.statuses = []
215 c.inline_comments = []
215 c.inline_comments = []
216 c.inline_cnt = 0
216 c.inline_cnt = 0
217
217
218 # Iterate over ranges (default changeset view is always one changeset)
218 # Iterate over ranges (default changeset view is always one changeset)
219 for changeset in c.cs_ranges:
219 for changeset in c.cs_ranges:
220 inlines = []
220 inlines = []
221 if method == 'show':
221 if method == 'show':
222 c.statuses.extend([ChangesetStatusModel().get_status(
222 c.statuses.extend([ChangesetStatusModel().get_status(
223 c.rhodecode_db_repo.repo_id, changeset.raw_id)])
223 c.rhodecode_db_repo.repo_id, changeset.raw_id)])
224
224
225 c.comments.extend(ChangesetCommentsModel()\
225 c.comments.extend(ChangesetCommentsModel()\
226 .get_comments(c.rhodecode_db_repo.repo_id,
226 .get_comments(c.rhodecode_db_repo.repo_id,
227 revision=changeset.raw_id))
227 revision=changeset.raw_id))
228
228
229 #comments from PR
229 #comments from PR
230 st = ChangesetStatusModel().get_statuses(
230 st = ChangesetStatusModel().get_statuses(
231 c.rhodecode_db_repo.repo_id, changeset.raw_id,
231 c.rhodecode_db_repo.repo_id, changeset.raw_id,
232 with_revisions=True)
232 with_revisions=True)
233 # from associated statuses, check the pull requests, and
233 # from associated statuses, check the pull requests, and
234 # show comments from them
234 # show comments from them
235
235
236 prs = set([x.pull_request for x in
236 prs = set([x.pull_request for x in
237 filter(lambda x: x.pull_request != None, st)])
237 filter(lambda x: x.pull_request != None, st)])
238
238
239 for pr in prs:
239 for pr in prs:
240 c.comments.extend(pr.comments)
240 c.comments.extend(pr.comments)
241 inlines = ChangesetCommentsModel()\
241 inlines = ChangesetCommentsModel()\
242 .get_inline_comments(c.rhodecode_db_repo.repo_id,
242 .get_inline_comments(c.rhodecode_db_repo.repo_id,
243 revision=changeset.raw_id)
243 revision=changeset.raw_id)
244 c.inline_comments.extend(inlines)
244 c.inline_comments.extend(inlines)
245
245
246 c.changes[changeset.raw_id] = []
246 c.changes[changeset.raw_id] = []
247
247
248 cs2 = changeset.raw_id
248 cs2 = changeset.raw_id
249 cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset()
249 cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset()
250 context_lcl = get_line_ctx('', request.GET)
250 context_lcl = get_line_ctx('', request.GET)
251 ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
251 ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
252
252
253 _diff = c.rhodecode_repo.get_diff(cs1, cs2,
253 _diff = c.rhodecode_repo.get_diff(cs1, cs2,
254 ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
254 ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
255 diff_limit = self.cut_off_limit if not fulldiff else None
255 diff_limit = self.cut_off_limit if not fulldiff else None
256 diff_processor = diffs.DiffProcessor(_diff,
256 diff_processor = diffs.DiffProcessor(_diff,
257 vcs=c.rhodecode_repo.alias,
257 vcs=c.rhodecode_repo.alias,
258 format='gitdiff',
258 format='gitdiff',
259 diff_limit=diff_limit)
259 diff_limit=diff_limit)
260 cs_changes = OrderedDict()
260 cs_changes = OrderedDict()
261 if method == 'show':
261 if method == 'show':
262 _parsed = diff_processor.prepare()
262 _parsed = diff_processor.prepare()
263 c.limited_diff = False
263 c.limited_diff = False
264 if isinstance(_parsed, LimitedDiffContainer):
264 if isinstance(_parsed, LimitedDiffContainer):
265 c.limited_diff = True
265 c.limited_diff = True
266 for f in _parsed:
266 for f in _parsed:
267 st = f['stats']
267 st = f['stats']
268 if st[0] != 'b':
268 c.lines_added += st['added']
269 c.lines_added += st[0]
269 c.lines_deleted += st['deleted']
270 c.lines_deleted += st[1]
271 fid = h.FID(changeset.raw_id, f['filename'])
270 fid = h.FID(changeset.raw_id, f['filename'])
272 diff = diff_processor.as_html(enable_comments=enable_comments,
271 diff = diff_processor.as_html(enable_comments=enable_comments,
273 parsed_lines=[f])
272 parsed_lines=[f])
274 cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
273 cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
275 diff, st]
274 diff, st]
276 else:
275 else:
277 # downloads/raw we only need RAW diff nothing else
276 # downloads/raw we only need RAW diff nothing else
278 diff = diff_processor.as_raw()
277 diff = diff_processor.as_raw()
279 cs_changes[''] = [None, None, None, None, diff, None]
278 cs_changes[''] = [None, None, None, None, diff, None]
280 c.changes[changeset.raw_id] = cs_changes
279 c.changes[changeset.raw_id] = cs_changes
281
280
282 #sort comments by how they were generated
281 #sort comments by how they were generated
283 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
282 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
284
283
285 # count inline comments
284 # count inline comments
286 for __, lines in c.inline_comments:
285 for __, lines in c.inline_comments:
287 for comments in lines.values():
286 for comments in lines.values():
288 c.inline_cnt += len(comments)
287 c.inline_cnt += len(comments)
289
288
290 if len(c.cs_ranges) == 1:
289 if len(c.cs_ranges) == 1:
291 c.changeset = c.cs_ranges[0]
290 c.changeset = c.cs_ranges[0]
292 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id
291 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id
293 for x in c.changeset.parents])
292 for x in c.changeset.parents])
294 if method == 'download':
293 if method == 'download':
295 response.content_type = 'text/plain'
294 response.content_type = 'text/plain'
296 response.content_disposition = 'attachment; filename=%s.diff' \
295 response.content_disposition = 'attachment; filename=%s.diff' \
297 % revision[:12]
296 % revision[:12]
298 return diff
297 return diff
299 elif method == 'patch':
298 elif method == 'patch':
300 response.content_type = 'text/plain'
299 response.content_type = 'text/plain'
301 c.diff = safe_unicode(diff)
300 c.diff = safe_unicode(diff)
302 return render('changeset/patch_changeset.html')
301 return render('changeset/patch_changeset.html')
303 elif method == 'raw':
302 elif method == 'raw':
304 response.content_type = 'text/plain'
303 response.content_type = 'text/plain'
305 return diff
304 return diff
306 elif method == 'show':
305 elif method == 'show':
307 if len(c.cs_ranges) == 1:
306 if len(c.cs_ranges) == 1:
308 return render('changeset/changeset.html')
307 return render('changeset/changeset.html')
309 else:
308 else:
310 return render('changeset/changeset_range.html')
309 return render('changeset/changeset_range.html')
311
310
312 @LoginRequired()
311 @LoginRequired()
313 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
312 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
314 'repository.admin')
313 'repository.admin')
315 def index(self, revision, method='show'):
314 def index(self, revision, method='show'):
316 return self._index(revision, method=method)
315 return self._index(revision, method=method)
317
316
318 @LoginRequired()
317 @LoginRequired()
319 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
318 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
320 'repository.admin')
319 'repository.admin')
321 def changeset_raw(self, revision):
320 def changeset_raw(self, revision):
322 return self._index(revision, method='raw')
321 return self._index(revision, method='raw')
323
322
324 @LoginRequired()
323 @LoginRequired()
325 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
324 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
326 'repository.admin')
325 'repository.admin')
327 def changeset_patch(self, revision):
326 def changeset_patch(self, revision):
328 return self._index(revision, method='patch')
327 return self._index(revision, method='patch')
329
328
330 @LoginRequired()
329 @LoginRequired()
331 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
330 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
332 'repository.admin')
331 'repository.admin')
333 def changeset_download(self, revision):
332 def changeset_download(self, revision):
334 return self._index(revision, method='download')
333 return self._index(revision, method='download')
335
334
336 @LoginRequired()
335 @LoginRequired()
337 @NotAnonymous()
336 @NotAnonymous()
338 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
337 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
339 'repository.admin')
338 'repository.admin')
340 @jsonify
339 @jsonify
341 def comment(self, repo_name, revision):
340 def comment(self, repo_name, revision):
342 status = request.POST.get('changeset_status')
341 status = request.POST.get('changeset_status')
343 change_status = request.POST.get('change_changeset_status')
342 change_status = request.POST.get('change_changeset_status')
344 text = request.POST.get('text')
343 text = request.POST.get('text')
345 if status and change_status:
344 if status and change_status:
346 text = text or (_('Status change -> %s')
345 text = text or (_('Status change -> %s')
347 % ChangesetStatus.get_status_lbl(status))
346 % ChangesetStatus.get_status_lbl(status))
348
347
349 c.co = comm = ChangesetCommentsModel().create(
348 c.co = comm = ChangesetCommentsModel().create(
350 text=text,
349 text=text,
351 repo=c.rhodecode_db_repo.repo_id,
350 repo=c.rhodecode_db_repo.repo_id,
352 user=c.rhodecode_user.user_id,
351 user=c.rhodecode_user.user_id,
353 revision=revision,
352 revision=revision,
354 f_path=request.POST.get('f_path'),
353 f_path=request.POST.get('f_path'),
355 line_no=request.POST.get('line'),
354 line_no=request.POST.get('line'),
356 status_change=(ChangesetStatus.get_status_lbl(status)
355 status_change=(ChangesetStatus.get_status_lbl(status)
357 if status and change_status else None)
356 if status and change_status else None)
358 )
357 )
359
358
360 # get status if set !
359 # get status if set !
361 if status and change_status:
360 if status and change_status:
362 # if latest status was from pull request and it's closed
361 # if latest status was from pull request and it's closed
363 # disallow changing status !
362 # disallow changing status !
364 # dont_allow_on_closed_pull_request = True !
363 # dont_allow_on_closed_pull_request = True !
365
364
366 try:
365 try:
367 ChangesetStatusModel().set_status(
366 ChangesetStatusModel().set_status(
368 c.rhodecode_db_repo.repo_id,
367 c.rhodecode_db_repo.repo_id,
369 status,
368 status,
370 c.rhodecode_user.user_id,
369 c.rhodecode_user.user_id,
371 comm,
370 comm,
372 revision=revision,
371 revision=revision,
373 dont_allow_on_closed_pull_request=True
372 dont_allow_on_closed_pull_request=True
374 )
373 )
375 except StatusChangeOnClosedPullRequestError:
374 except StatusChangeOnClosedPullRequestError:
376 log.error(traceback.format_exc())
375 log.error(traceback.format_exc())
377 msg = _('Changing status on a changeset associated with '
376 msg = _('Changing status on a changeset associated with '
378 'a closed pull request is not allowed')
377 'a closed pull request is not allowed')
379 h.flash(msg, category='warning')
378 h.flash(msg, category='warning')
380 return redirect(h.url('changeset_home', repo_name=repo_name,
379 return redirect(h.url('changeset_home', repo_name=repo_name,
381 revision=revision))
380 revision=revision))
382 action_logger(self.rhodecode_user,
381 action_logger(self.rhodecode_user,
383 'user_commented_revision:%s' % revision,
382 'user_commented_revision:%s' % revision,
384 c.rhodecode_db_repo, self.ip_addr, self.sa)
383 c.rhodecode_db_repo, self.ip_addr, self.sa)
385
384
386 Session().commit()
385 Session().commit()
387
386
388 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
387 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
389 return redirect(h.url('changeset_home', repo_name=repo_name,
388 return redirect(h.url('changeset_home', repo_name=repo_name,
390 revision=revision))
389 revision=revision))
391 #only ajax below
390 #only ajax below
392 data = {
391 data = {
393 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
392 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
394 }
393 }
395 if comm:
394 if comm:
396 data.update(comm.get_dict())
395 data.update(comm.get_dict())
397 data.update({'rendered_text':
396 data.update({'rendered_text':
398 render('changeset/changeset_comment_block.html')})
397 render('changeset/changeset_comment_block.html')})
399
398
400 return data
399 return data
401
400
402 @LoginRequired()
401 @LoginRequired()
403 @NotAnonymous()
402 @NotAnonymous()
404 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
403 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
405 'repository.admin')
404 'repository.admin')
406 def preview_comment(self):
405 def preview_comment(self):
407 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
406 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
408 raise HTTPBadRequest()
407 raise HTTPBadRequest()
409 text = request.POST.get('text')
408 text = request.POST.get('text')
410 if text:
409 if text:
411 return h.rst_w_mentions(text)
410 return h.rst_w_mentions(text)
412 return ''
411 return ''
413
412
414 @LoginRequired()
413 @LoginRequired()
415 @NotAnonymous()
414 @NotAnonymous()
416 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
415 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
417 'repository.admin')
416 'repository.admin')
418 @jsonify
417 @jsonify
419 def delete_comment(self, repo_name, comment_id):
418 def delete_comment(self, repo_name, comment_id):
420 co = ChangesetComment.get(comment_id)
419 co = ChangesetComment.get(comment_id)
421 owner = co.author.user_id == c.rhodecode_user.user_id
420 owner = co.author.user_id == c.rhodecode_user.user_id
422 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
421 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
423 ChangesetCommentsModel().delete(comment=co)
422 ChangesetCommentsModel().delete(comment=co)
424 Session().commit()
423 Session().commit()
425 return True
424 return True
426 else:
425 else:
427 raise HTTPForbidden()
426 raise HTTPForbidden()
428
427
429 @LoginRequired()
428 @LoginRequired()
430 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
429 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
431 'repository.admin')
430 'repository.admin')
432 @jsonify
431 @jsonify
433 def changeset_info(self, repo_name, revision):
432 def changeset_info(self, repo_name, revision):
434 if request.is_xhr:
433 if request.is_xhr:
435 try:
434 try:
436 return c.rhodecode_repo.get_changeset(revision)
435 return c.rhodecode_repo.get_changeset(revision)
437 except ChangesetDoesNotExistError, e:
436 except ChangesetDoesNotExistError, e:
438 return EmptyChangeset(message=str(e))
437 return EmptyChangeset(message=str(e))
439 else:
438 else:
440 raise HTTPBadRequest()
439 raise HTTPBadRequest()
@@ -1,269 +1,269 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.compare
3 rhodecode.controllers.compare
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 compare controller for pylons showing differences between two
6 compare controller for pylons showing differences between two
7 repos, branches, bookmarks or tips
7 repos, branches, bookmarks or tips
8
8
9 :created_on: May 6, 2012
9 :created_on: May 6, 2012
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import re
29 import re
30
30
31 from webob.exc import HTTPNotFound
31 from webob.exc import HTTPNotFound
32 from pylons import request, response, session, tmpl_context as c, url
32 from pylons import request, response, session, tmpl_context as c, url
33 from pylons.controllers.util import abort, redirect
33 from pylons.controllers.util import abort, redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
36 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
37 from rhodecode.lib.vcs.utils import safe_str
37 from rhodecode.lib.vcs.utils import safe_str
38 from rhodecode.lib.vcs.utils.hgcompat import scmutil
38 from rhodecode.lib.vcs.utils.hgcompat import scmutil
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib import diffs, unionrepo
42 from rhodecode.lib import diffs, unionrepo
43
43
44 from rhodecode.model.db import Repository
44 from rhodecode.model.db import Repository
45 from webob.exc import HTTPBadRequest
45 from webob.exc import HTTPBadRequest
46 from rhodecode.lib.diffs import LimitedDiffContainer
46 from rhodecode.lib.diffs import LimitedDiffContainer
47
47
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 class CompareController(BaseRepoController):
52 class CompareController(BaseRepoController):
53
53
54 def __before__(self):
54 def __before__(self):
55 super(CompareController, self).__before__()
55 super(CompareController, self).__before__()
56
56
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
58 partial=False):
58 partial=False):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to changeset with
60 Safe way to get changeset if error occur it redirects to changeset with
61 proper message. If partial is set then don't do redirect raise Exception
61 proper message. If partial is set then don't do redirect raise Exception
62 instead
62 instead
63
63
64 :param rev: revision to fetch
64 :param rev: revision to fetch
65 :param repo: repo instance
65 :param repo: repo instance
66 """
66 """
67
67
68 try:
68 try:
69 type_, rev = rev
69 type_, rev = rev
70 return repo.scm_instance.get_changeset(rev)
70 return repo.scm_instance.get_changeset(rev)
71 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
72 if not redirect_after:
72 if not redirect_after:
73 return None
73 return None
74 h.flash(h.literal(_('There are no changesets yet')),
74 h.flash(h.literal(_('There are no changesets yet')),
75 category='warning')
75 category='warning')
76 redirect(url('summary_home', repo_name=repo.repo_name))
76 redirect(url('summary_home', repo_name=repo.repo_name))
77
77
78 except RepositoryError, e:
78 except RepositoryError, e:
79 log.error(traceback.format_exc())
79 log.error(traceback.format_exc())
80 h.flash(str(e), category='warning')
80 h.flash(str(e), category='warning')
81 if not partial:
81 if not partial:
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
83 raise HTTPBadRequest()
83 raise HTTPBadRequest()
84
84
85 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge):
85 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge):
86 """
86 """
87 Returns a list of changesets that can be merged from org_repo@org_ref
87 Returns a list of changesets that can be merged from org_repo@org_ref
88 to other_repo@other_ref ... and the ancestor that would be used for merge
88 to other_repo@other_ref ... and the ancestor that would be used for merge
89
89
90 :param org_repo:
90 :param org_repo:
91 :param org_ref:
91 :param org_ref:
92 :param other_repo:
92 :param other_repo:
93 :param other_ref:
93 :param other_ref:
94 :param tmp:
94 :param tmp:
95 """
95 """
96
96
97 ancestor = None
97 ancestor = None
98
98
99 if alias == 'hg':
99 if alias == 'hg':
100 # lookup up the exact node id
100 # lookup up the exact node id
101 _revset_predicates = {
101 _revset_predicates = {
102 'branch': 'branch',
102 'branch': 'branch',
103 'book': 'bookmark',
103 'book': 'bookmark',
104 'tag': 'tag',
104 'tag': 'tag',
105 'rev': 'id',
105 'rev': 'id',
106 }
106 }
107
107
108 org_rev_spec = "max(%s(%%s))" % _revset_predicates[org_ref[0]]
108 org_rev_spec = "max(%s(%%s))" % _revset_predicates[org_ref[0]]
109 org_revs = org_repo._repo.revs(org_rev_spec, safe_str(org_ref[1]))
109 org_revs = org_repo._repo.revs(org_rev_spec, safe_str(org_ref[1]))
110 org_rev = org_repo._repo[org_revs[-1] if org_revs else -1].hex()
110 org_rev = org_repo._repo[org_revs[-1] if org_revs else -1].hex()
111
111
112 other_revs_spec = "max(%s(%%s))" % _revset_predicates[other_ref[0]]
112 other_revs_spec = "max(%s(%%s))" % _revset_predicates[other_ref[0]]
113 other_revs = other_repo._repo.revs(other_revs_spec, safe_str(other_ref[1]))
113 other_revs = other_repo._repo.revs(other_revs_spec, safe_str(other_ref[1]))
114 other_rev = other_repo._repo[other_revs[-1] if other_revs else -1].hex()
114 other_rev = other_repo._repo[other_revs[-1] if other_revs else -1].hex()
115
115
116 #case two independent repos
116 #case two independent repos
117 if org_repo != other_repo:
117 if org_repo != other_repo:
118 hgrepo = unionrepo.unionrepository(other_repo.baseui,
118 hgrepo = unionrepo.unionrepository(other_repo.baseui,
119 other_repo.path,
119 other_repo.path,
120 org_repo.path)
120 org_repo.path)
121 # all the changesets we are looking for will be in other_repo,
121 # all the changesets we are looking for will be in other_repo,
122 # so rev numbers from hgrepo can be used in other_repo
122 # so rev numbers from hgrepo can be used in other_repo
123
123
124 #no remote compare do it on the same repository
124 #no remote compare do it on the same repository
125 else:
125 else:
126 hgrepo = other_repo._repo
126 hgrepo = other_repo._repo
127
127
128 if merge:
128 if merge:
129 revs = hgrepo.revs("ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)",
129 revs = hgrepo.revs("ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)",
130 other_rev, org_rev, org_rev)
130 other_rev, org_rev, org_rev)
131
131
132 ancestors = hgrepo.revs("ancestor(id(%s), id(%s))", org_rev, other_rev)
132 ancestors = hgrepo.revs("ancestor(id(%s), id(%s))", org_rev, other_rev)
133 if ancestors:
133 if ancestors:
134 # pick arbitrary ancestor - but there is usually only one
134 # pick arbitrary ancestor - but there is usually only one
135 ancestor = hgrepo[ancestors[0]].hex()
135 ancestor = hgrepo[ancestors[0]].hex()
136 else:
136 else:
137 # TODO: have both + and - changesets
137 # TODO: have both + and - changesets
138 revs = hgrepo.revs("id(%s) :: id(%s) - id(%s)",
138 revs = hgrepo.revs("id(%s) :: id(%s) - id(%s)",
139 org_rev, other_rev, org_rev)
139 org_rev, other_rev, org_rev)
140
140
141 changesets = [other_repo.get_changeset(rev) for rev in revs]
141 changesets = [other_repo.get_changeset(rev) for rev in revs]
142
142
143 elif alias == 'git':
143 elif alias == 'git':
144 if org_repo != other_repo:
144 if org_repo != other_repo:
145 raise Exception('Comparing of different GIT repositories is not'
145 raise Exception('Comparing of different GIT repositories is not'
146 'allowed. Got %s != %s' % (org_repo, other_repo))
146 'allowed. Got %s != %s' % (org_repo, other_repo))
147
147
148 so, se = org_repo.run_git_command(
148 so, se = org_repo.run_git_command(
149 'log --reverse --pretty="format: %%H" -s -p %s..%s'
149 'log --reverse --pretty="format: %%H" -s -p %s..%s'
150 % (org_ref[1], other_ref[1])
150 % (org_ref[1], other_ref[1])
151 )
151 )
152 changesets = [org_repo.get_changeset(cs)
152 changesets = [org_repo.get_changeset(cs)
153 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
153 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
154
154
155 return changesets, ancestor
155 return changesets, ancestor
156
156
157 @LoginRequired()
157 @LoginRequired()
158 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
158 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
159 'repository.admin')
159 'repository.admin')
160 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
160 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
161 # org_ref will be evaluated in org_repo
161 # org_ref will be evaluated in org_repo
162 org_repo = c.rhodecode_db_repo.repo_name
162 org_repo = c.rhodecode_db_repo.repo_name
163 org_ref = (org_ref_type, org_ref)
163 org_ref = (org_ref_type, org_ref)
164 # other_ref will be evaluated in other_repo
164 # other_ref will be evaluated in other_repo
165 other_ref = (other_ref_type, other_ref)
165 other_ref = (other_ref_type, other_ref)
166 other_repo = request.GET.get('other_repo', org_repo)
166 other_repo = request.GET.get('other_repo', org_repo)
167 # If merge is True:
167 # If merge is True:
168 # Show what org would get if merged with other:
168 # Show what org would get if merged with other:
169 # List changesets that are ancestors of other but not of org.
169 # List changesets that are ancestors of other but not of org.
170 # New changesets in org is thus ignored.
170 # New changesets in org is thus ignored.
171 # Diff will be from common ancestor, and merges of org to other will thus be ignored.
171 # Diff will be from common ancestor, and merges of org to other will thus be ignored.
172 # If merge is False:
172 # If merge is False:
173 # Make a raw diff from org to other, no matter if related or not.
173 # Make a raw diff from org to other, no matter if related or not.
174 # Changesets in one and not in the other will be ignored
174 # Changesets in one and not in the other will be ignored
175 merge = bool(request.GET.get('merge'))
175 merge = bool(request.GET.get('merge'))
176 # fulldiff disables cut_off_limit
176 # fulldiff disables cut_off_limit
177 c.fulldiff = request.GET.get('fulldiff')
177 c.fulldiff = request.GET.get('fulldiff')
178 # partial uses compare_cs.html template directly
178 # partial uses compare_cs.html template directly
179 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
179 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
180 # as_form puts hidden input field with changeset revisions
180 # as_form puts hidden input field with changeset revisions
181 c.as_form = partial and request.GET.get('as_form')
181 c.as_form = partial and request.GET.get('as_form')
182 # swap url for compare_diff page - never partial and never as_form
182 # swap url for compare_diff page - never partial and never as_form
183 c.swap_url = h.url('compare_url',
183 c.swap_url = h.url('compare_url',
184 repo_name=other_repo,
184 repo_name=other_repo,
185 org_ref_type=other_ref[0], org_ref=other_ref[1],
185 org_ref_type=other_ref[0], org_ref=other_ref[1],
186 other_repo=org_repo,
186 other_repo=org_repo,
187 other_ref_type=org_ref[0], other_ref=org_ref[1],
187 other_ref_type=org_ref[0], other_ref=org_ref[1],
188 merge=merge or '')
188 merge=merge or '')
189
189
190 org_repo = Repository.get_by_repo_name(org_repo)
190 org_repo = Repository.get_by_repo_name(org_repo)
191 other_repo = Repository.get_by_repo_name(other_repo)
191 other_repo = Repository.get_by_repo_name(other_repo)
192
192
193 if org_repo is None:
193 if org_repo is None:
194 log.error('Could not find org repo %s' % org_repo)
194 log.error('Could not find org repo %s' % org_repo)
195 raise HTTPNotFound
195 raise HTTPNotFound
196 if other_repo is None:
196 if other_repo is None:
197 log.error('Could not find other repo %s' % other_repo)
197 log.error('Could not find other repo %s' % other_repo)
198 raise HTTPNotFound
198 raise HTTPNotFound
199
199
200 if org_repo != other_repo and h.is_git(org_repo):
200 if org_repo != other_repo and h.is_git(org_repo):
201 log.error('compare of two remote repos not available for GIT REPOS')
201 log.error('compare of two remote repos not available for GIT REPOS')
202 raise HTTPNotFound
202 raise HTTPNotFound
203
203
204 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
204 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
205 log.error('compare of two different kind of remote repos not available')
205 log.error('compare of two different kind of remote repos not available')
206 raise HTTPNotFound
206 raise HTTPNotFound
207
207
208 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
208 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
209 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
209 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
210
210
211 c.org_repo = org_repo
211 c.org_repo = org_repo
212 c.other_repo = other_repo
212 c.other_repo = other_repo
213 c.org_ref = org_ref[1]
213 c.org_ref = org_ref[1]
214 c.other_ref = other_ref[1]
214 c.other_ref = other_ref[1]
215 c.org_ref_type = org_ref[0]
215 c.org_ref_type = org_ref[0]
216 c.other_ref_type = other_ref[0]
216 c.other_ref_type = other_ref[0]
217
217
218 c.cs_ranges, c.ancestor = self._get_changesets(org_repo.scm_instance.alias,
218 c.cs_ranges, c.ancestor = self._get_changesets(org_repo.scm_instance.alias,
219 org_repo.scm_instance, org_ref,
219 org_repo.scm_instance, org_ref,
220 other_repo.scm_instance, other_ref,
220 other_repo.scm_instance, other_ref,
221 merge)
221 merge)
222
222
223 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
223 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
224 c.cs_ranges])
224 c.cs_ranges])
225 if not c.ancestor:
225 if not c.ancestor:
226 log.warning('Unable to find ancestor revision')
226 log.warning('Unable to find ancestor revision')
227
227
228 if partial:
228 if partial:
229 return render('compare/compare_cs.html')
229 return render('compare/compare_cs.html')
230
230
231 if c.ancestor:
231 if c.ancestor:
232 assert merge
232 assert merge
233 # case we want a simple diff without incoming changesets,
233 # case we want a simple diff without incoming changesets,
234 # previewing what will be merged.
234 # previewing what will be merged.
235 # Make the diff on the other repo (which is known to have other_ref)
235 # Make the diff on the other repo (which is known to have other_ref)
236 log.debug('Using ancestor %s as org_ref instead of %s'
236 log.debug('Using ancestor %s as org_ref instead of %s'
237 % (c.ancestor, org_ref))
237 % (c.ancestor, org_ref))
238 org_ref = ('rev', c.ancestor)
238 org_ref = ('rev', c.ancestor)
239 org_repo = other_repo
239 org_repo = other_repo
240
240
241 diff_limit = self.cut_off_limit if not c.fulldiff else None
241 diff_limit = self.cut_off_limit if not c.fulldiff else None
242
242
243 log.debug('running diff between %s and %s in %s'
243 log.debug('running diff between %s and %s in %s'
244 % (org_ref, other_ref, org_repo.scm_instance.path))
244 % (org_ref, other_ref, org_repo.scm_instance.path))
245 txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(org_ref[1]), rev2=safe_str(other_ref[1]))
245 txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(org_ref[1]), rev2=safe_str(other_ref[1]))
246
246
247 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
247 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
248 diff_limit=diff_limit)
248 diff_limit=diff_limit)
249 _parsed = diff_processor.prepare()
249 _parsed = diff_processor.prepare()
250
250
251 c.limited_diff = False
251 c.limited_diff = False
252 if isinstance(_parsed, LimitedDiffContainer):
252 if isinstance(_parsed, LimitedDiffContainer):
253 c.limited_diff = True
253 c.limited_diff = True
254
254
255 c.files = []
255 c.files = []
256 c.changes = {}
256 c.changes = {}
257 c.lines_added = 0
257 c.lines_added = 0
258 c.lines_deleted = 0
258 c.lines_deleted = 0
259 for f in _parsed:
259 for f in _parsed:
260 st = f['stats']
260 st = f['stats']
261 if st[0] != 'b':
261 if not st['binary']:
262 c.lines_added += st[0]
262 c.lines_added += st['added']
263 c.lines_deleted += st[1]
263 c.lines_deleted += st['deleted']
264 fid = h.FID('', f['filename'])
264 fid = h.FID('', f['filename'])
265 c.files.append([fid, f['operation'], f['filename'], f['stats']])
265 c.files.append([fid, f['operation'], f['filename'], f['stats']])
266 htmldiff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
266 htmldiff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
267 c.changes[fid] = [f['operation'], f['filename'], htmldiff]
267 c.changes[fid] = [f['operation'], f['filename'], htmldiff]
268
268
269 return render('compare/compare_diff.html')
269 return render('compare/compare_diff.html')
@@ -1,179 +1,179 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.feed
3 rhodecode.controllers.feed
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Feed controller for rhodecode
6 Feed controller for rhodecode
7
7
8 :created_on: Apr 23, 2010
8 :created_on: Apr 23, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 from pylons import url, response, tmpl_context as c
28 from pylons import url, response, tmpl_context as c
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from beaker.cache import cache_region, region_invalidate
31 from beaker.cache import cache_region, region_invalidate
32 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
32 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
33
33
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.base import BaseRepoController
36 from rhodecode.lib.base import BaseRepoController
37 from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer
37 from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer
38 from rhodecode.model.db import CacheInvalidation
38 from rhodecode.model.db import CacheInvalidation
39 from rhodecode.lib.utils2 import safe_int, str2bool, safe_unicode
39 from rhodecode.lib.utils2 import safe_int, str2bool, safe_unicode
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43
43
44 class FeedController(BaseRepoController):
44 class FeedController(BaseRepoController):
45
45
46 @LoginRequired(api_access=True)
46 @LoginRequired(api_access=True)
47 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
47 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
48 'repository.admin')
48 'repository.admin')
49 def __before__(self):
49 def __before__(self):
50 super(FeedController, self).__before__()
50 super(FeedController, self).__before__()
51 #common values for feeds
51 #common values for feeds
52 self.description = _('Changes on %s repository')
52 self.description = _('Changes on %s repository')
53 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
53 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
54 self.language = 'en-us'
54 self.language = 'en-us'
55 self.ttl = "5"
55 self.ttl = "5"
56 import rhodecode
56 import rhodecode
57 CONF = rhodecode.CONFIG
57 CONF = rhodecode.CONFIG
58 self.include_diff = str2bool(CONF.get('rss_include_diff', False))
58 self.include_diff = str2bool(CONF.get('rss_include_diff', False))
59 self.feed_nr = safe_int(CONF.get('rss_items_per_page', 20))
59 self.feed_nr = safe_int(CONF.get('rss_items_per_page', 20))
60 # we need to protect from parsing huge diffs here other way
60 # we need to protect from parsing huge diffs here other way
61 # we can kill the server
61 # we can kill the server
62 self.feed_diff_limit = safe_int(CONF.get('rss_cut_off_limit', 32 * 1024))
62 self.feed_diff_limit = safe_int(CONF.get('rss_cut_off_limit', 32 * 1024))
63
63
64 def _get_title(self, cs):
64 def _get_title(self, cs):
65 return "%s" % (
65 return "%s" % (
66 h.shorter(cs.message, 160)
66 h.shorter(cs.message, 160)
67 )
67 )
68
68
69 def __changes(self, cs):
69 def __changes(self, cs):
70 changes = []
70 changes = []
71 diff_processor = DiffProcessor(cs.diff(),
71 diff_processor = DiffProcessor(cs.diff(),
72 diff_limit=self.feed_diff_limit)
72 diff_limit=self.feed_diff_limit)
73 _parsed = diff_processor.prepare(inline_diff=False)
73 _parsed = diff_processor.prepare(inline_diff=False)
74 limited_diff = False
74 limited_diff = False
75 if isinstance(_parsed, LimitedDiffContainer):
75 if isinstance(_parsed, LimitedDiffContainer):
76 limited_diff = True
76 limited_diff = True
77
77
78 for st in _parsed:
78 for st in _parsed:
79 st.update({'added': st['stats'][0],
79 st.update({'added': st['stats']['added'],
80 'removed': st['stats'][1]})
80 'removed': st['stats']['deleted']})
81 changes.append('\n %(operation)s %(filename)s '
81 changes.append('\n %(operation)s %(filename)s '
82 '(%(added)s lines added, %(removed)s lines removed)'
82 '(%(added)s lines added, %(removed)s lines removed)'
83 % st)
83 % st)
84 if limited_diff:
84 if limited_diff:
85 changes = changes + ['\n ' +
85 changes = changes + ['\n ' +
86 _('Changeset was too big and was cut off...')]
86 _('Changeset was too big and was cut off...')]
87 return diff_processor, changes
87 return diff_processor, changes
88
88
89 def __get_desc(self, cs):
89 def __get_desc(self, cs):
90 desc_msg = []
90 desc_msg = []
91 desc_msg.append((_('%s committed on %s')
91 desc_msg.append((_('%s committed on %s')
92 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>')
92 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>')
93 #branches, tags, bookmarks
93 #branches, tags, bookmarks
94 if cs.branch:
94 if cs.branch:
95 desc_msg.append('branch: %s<br/>' % cs.branch)
95 desc_msg.append('branch: %s<br/>' % cs.branch)
96 if h.is_hg(c.rhodecode_repo):
96 if h.is_hg(c.rhodecode_repo):
97 for book in cs.bookmarks:
97 for book in cs.bookmarks:
98 desc_msg.append('bookmark: %s<br/>' % book)
98 desc_msg.append('bookmark: %s<br/>' % book)
99 for tag in cs.tags:
99 for tag in cs.tags:
100 desc_msg.append('tag: %s<br/>' % tag)
100 desc_msg.append('tag: %s<br/>' % tag)
101 diff_processor, changes = self.__changes(cs)
101 diff_processor, changes = self.__changes(cs)
102 # rev link
102 # rev link
103 _url = url('changeset_home', repo_name=cs.repository.name,
103 _url = url('changeset_home', repo_name=cs.repository.name,
104 revision=cs.raw_id, qualified=True)
104 revision=cs.raw_id, qualified=True)
105 desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8]))
105 desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8]))
106
106
107 desc_msg.append('<pre>')
107 desc_msg.append('<pre>')
108 desc_msg.append(cs.message)
108 desc_msg.append(cs.message)
109 desc_msg.append('\n')
109 desc_msg.append('\n')
110 desc_msg.extend(changes)
110 desc_msg.extend(changes)
111 if self.include_diff:
111 if self.include_diff:
112 desc_msg.append('\n\n')
112 desc_msg.append('\n\n')
113 desc_msg.append(diff_processor.as_raw())
113 desc_msg.append(diff_processor.as_raw())
114 desc_msg.append('</pre>')
114 desc_msg.append('</pre>')
115 return map(safe_unicode, desc_msg)
115 return map(safe_unicode, desc_msg)
116
116
117 def atom(self, repo_name):
117 def atom(self, repo_name):
118 """Produce an atom-1.0 feed via feedgenerator module"""
118 """Produce an atom-1.0 feed via feedgenerator module"""
119
119
120 @cache_region('long_term')
120 @cache_region('long_term')
121 def _get_feed_from_cache(key, kind):
121 def _get_feed_from_cache(key, kind):
122 feed = Atom1Feed(
122 feed = Atom1Feed(
123 title=self.title % repo_name,
123 title=self.title % repo_name,
124 link=url('summary_home', repo_name=repo_name,
124 link=url('summary_home', repo_name=repo_name,
125 qualified=True),
125 qualified=True),
126 description=self.description % repo_name,
126 description=self.description % repo_name,
127 language=self.language,
127 language=self.language,
128 ttl=self.ttl
128 ttl=self.ttl
129 )
129 )
130
130
131 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
131 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
132 feed.add_item(title=self._get_title(cs),
132 feed.add_item(title=self._get_title(cs),
133 link=url('changeset_home', repo_name=repo_name,
133 link=url('changeset_home', repo_name=repo_name,
134 revision=cs.raw_id, qualified=True),
134 revision=cs.raw_id, qualified=True),
135 author_name=cs.author,
135 author_name=cs.author,
136 description=''.join(self.__get_desc(cs)),
136 description=''.join(self.__get_desc(cs)),
137 pubdate=cs.date,
137 pubdate=cs.date,
138 )
138 )
139
139
140 response.content_type = feed.mime_type
140 response.content_type = feed.mime_type
141 return feed.writeString('utf-8')
141 return feed.writeString('utf-8')
142
142
143 kind = 'ATOM'
143 kind = 'ATOM'
144 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
144 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
145 if not valid:
145 if not valid:
146 region_invalidate(_get_feed_from_cache, None, repo_name, kind)
146 region_invalidate(_get_feed_from_cache, None, repo_name, kind)
147 return _get_feed_from_cache(repo_name, kind)
147 return _get_feed_from_cache(repo_name, kind)
148
148
149 def rss(self, repo_name):
149 def rss(self, repo_name):
150 """Produce an rss2 feed via feedgenerator module"""
150 """Produce an rss2 feed via feedgenerator module"""
151
151
152 @cache_region('long_term')
152 @cache_region('long_term')
153 def _get_feed_from_cache(key, kind):
153 def _get_feed_from_cache(key, kind):
154 feed = Rss201rev2Feed(
154 feed = Rss201rev2Feed(
155 title=self.title % repo_name,
155 title=self.title % repo_name,
156 link=url('summary_home', repo_name=repo_name,
156 link=url('summary_home', repo_name=repo_name,
157 qualified=True),
157 qualified=True),
158 description=self.description % repo_name,
158 description=self.description % repo_name,
159 language=self.language,
159 language=self.language,
160 ttl=self.ttl
160 ttl=self.ttl
161 )
161 )
162
162
163 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
163 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
164 feed.add_item(title=self._get_title(cs),
164 feed.add_item(title=self._get_title(cs),
165 link=url('changeset_home', repo_name=repo_name,
165 link=url('changeset_home', repo_name=repo_name,
166 revision=cs.raw_id, qualified=True),
166 revision=cs.raw_id, qualified=True),
167 author_name=cs.author,
167 author_name=cs.author,
168 description=''.join(self.__get_desc(cs)),
168 description=''.join(self.__get_desc(cs)),
169 pubdate=cs.date,
169 pubdate=cs.date,
170 )
170 )
171
171
172 response.content_type = feed.mime_type
172 response.content_type = feed.mime_type
173 return feed.writeString('utf-8')
173 return feed.writeString('utf-8')
174
174
175 kind = 'RSS'
175 kind = 'RSS'
176 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
176 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
177 if not valid:
177 if not valid:
178 region_invalidate(_get_feed_from_cache, None, repo_name, kind)
178 region_invalidate(_get_feed_from_cache, None, repo_name, kind)
179 return _get_feed_from_cache(repo_name, kind)
179 return _get_feed_from_cache(repo_name, kind)
@@ -1,560 +1,557 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.pullrequests
3 rhodecode.controllers.pullrequests
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull requests controller for rhodecode for initializing pull requests
6 pull requests controller for rhodecode for initializing pull requests
7
7
8 :created_on: May 7, 2012
8 :created_on: May 7, 2012
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26 import traceback
26 import traceback
27 import formencode
27 import formencode
28
28
29 from webob.exc import HTTPNotFound, HTTPForbidden
29 from webob.exc import HTTPNotFound, HTTPForbidden
30 from collections import defaultdict
30 from collections import defaultdict
31 from itertools import groupby
31 from itertools import groupby
32
32
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode.lib.compat import json
37 from rhodecode.lib.compat import json
38 from rhodecode.lib.base import BaseRepoController, render
38 from rhodecode.lib.base import BaseRepoController, render
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 NotAnonymous
40 NotAnonymous
41 from rhodecode.lib.helpers import Page
41 from rhodecode.lib.helpers import Page
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
43 from rhodecode.lib import diffs
43 from rhodecode.lib import diffs
44 from rhodecode.lib.utils import action_logger, jsonify
44 from rhodecode.lib.utils import action_logger, jsonify
45 from rhodecode.lib.vcs.utils import safe_str
45 from rhodecode.lib.vcs.utils import safe_str
46 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
46 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
48 from rhodecode.lib.diffs import LimitedDiffContainer
48 from rhodecode.lib.diffs import LimitedDiffContainer
49 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
49 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
50 ChangesetComment
50 ChangesetComment
51 from rhodecode.model.pull_request import PullRequestModel
51 from rhodecode.model.pull_request import PullRequestModel
52 from rhodecode.model.meta import Session
52 from rhodecode.model.meta import Session
53 from rhodecode.model.repo import RepoModel
53 from rhodecode.model.repo import RepoModel
54 from rhodecode.model.comment import ChangesetCommentsModel
54 from rhodecode.model.comment import ChangesetCommentsModel
55 from rhodecode.model.changeset_status import ChangesetStatusModel
55 from rhodecode.model.changeset_status import ChangesetStatusModel
56 from rhodecode.model.forms import PullRequestForm
56 from rhodecode.model.forms import PullRequestForm
57 from mercurial import scmutil
57 from mercurial import scmutil
58 from rhodecode.lib.utils2 import safe_int
58 from rhodecode.lib.utils2 import safe_int
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class PullrequestsController(BaseRepoController):
63 class PullrequestsController(BaseRepoController):
64
64
65 def __before__(self):
65 def __before__(self):
66 super(PullrequestsController, self).__before__()
66 super(PullrequestsController, self).__before__()
67 repo_model = RepoModel()
67 repo_model = RepoModel()
68 c.users_array = repo_model.get_users_js()
68 c.users_array = repo_model.get_users_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
70
70
71 def _get_repo_refs(self, repo, rev=None, branch=None, branch_rev=None):
71 def _get_repo_refs(self, repo, rev=None, branch=None, branch_rev=None):
72 """return a structure with repo's interesting changesets, suitable for
72 """return a structure with repo's interesting changesets, suitable for
73 the selectors in pullrequest.html
73 the selectors in pullrequest.html
74
74
75 rev: a revision that must be in the list somehow and selected by default
75 rev: a revision that must be in the list somehow and selected by default
76 branch: a branch that must be in the list and selected by default - even if closed
76 branch: a branch that must be in the list and selected by default - even if closed
77 branch_rev: a revision of which peers should be preferred and available."""
77 branch_rev: a revision of which peers should be preferred and available."""
78 # list named branches that has been merged to this named branch - it should probably merge back
78 # list named branches that has been merged to this named branch - it should probably merge back
79 peers = []
79 peers = []
80
80
81 if rev:
81 if rev:
82 rev = safe_str(rev)
82 rev = safe_str(rev)
83
83
84 if branch:
84 if branch:
85 branch = safe_str(branch)
85 branch = safe_str(branch)
86
86
87 if branch_rev:
87 if branch_rev:
88 branch_rev = safe_str(branch_rev)
88 branch_rev = safe_str(branch_rev)
89 # not restricting to merge() would also get branch point and be better
89 # not restricting to merge() would also get branch point and be better
90 # (especially because it would get the branch point) ... but is currently too expensive
90 # (especially because it would get the branch point) ... but is currently too expensive
91 otherbranches = {}
91 otherbranches = {}
92 for i in repo._repo.revs(
92 for i in repo._repo.revs(
93 "sort(parents(branch(id(%s)) and merge()) - branch(id(%s)))",
93 "sort(parents(branch(id(%s)) and merge()) - branch(id(%s)))",
94 branch_rev, branch_rev):
94 branch_rev, branch_rev):
95 cs = repo.get_changeset(i)
95 cs = repo.get_changeset(i)
96 otherbranches[cs.branch] = cs.raw_id
96 otherbranches[cs.branch] = cs.raw_id
97 for abranch, node in otherbranches.iteritems():
97 for abranch, node in otherbranches.iteritems():
98 selected = 'branch:%s:%s' % (abranch, node)
98 selected = 'branch:%s:%s' % (abranch, node)
99 peers.append((selected, abranch))
99 peers.append((selected, abranch))
100
100
101 selected = None
101 selected = None
102
102
103 branches = []
103 branches = []
104 for abranch, branchrev in repo.branches.iteritems():
104 for abranch, branchrev in repo.branches.iteritems():
105 n = 'branch:%s:%s' % (abranch, branchrev)
105 n = 'branch:%s:%s' % (abranch, branchrev)
106 branches.append((n, abranch))
106 branches.append((n, abranch))
107 if rev == branchrev:
107 if rev == branchrev:
108 selected = n
108 selected = n
109 if branch == abranch:
109 if branch == abranch:
110 selected = n
110 selected = n
111 branch = None
111 branch = None
112 if branch: # branch not in list - it is probably closed
112 if branch: # branch not in list - it is probably closed
113 revs = repo._repo.revs('max(branch(%s))', branch)
113 revs = repo._repo.revs('max(branch(%s))', branch)
114 if revs:
114 if revs:
115 cs = repo.get_changeset(revs[0])
115 cs = repo.get_changeset(revs[0])
116 selected = 'branch:%s:%s' % (branch, cs.raw_id)
116 selected = 'branch:%s:%s' % (branch, cs.raw_id)
117 branches.append((selected, branch))
117 branches.append((selected, branch))
118
118
119 bookmarks = []
119 bookmarks = []
120 for bookmark, bookmarkrev in repo.bookmarks.iteritems():
120 for bookmark, bookmarkrev in repo.bookmarks.iteritems():
121 n = 'book:%s:%s' % (bookmark, bookmarkrev)
121 n = 'book:%s:%s' % (bookmark, bookmarkrev)
122 bookmarks.append((n, bookmark))
122 bookmarks.append((n, bookmark))
123 if rev == bookmarkrev:
123 if rev == bookmarkrev:
124 selected = n
124 selected = n
125
125
126 tags = []
126 tags = []
127 for tag, tagrev in repo.tags.iteritems():
127 for tag, tagrev in repo.tags.iteritems():
128 n = 'tag:%s:%s' % (tag, tagrev)
128 n = 'tag:%s:%s' % (tag, tagrev)
129 tags.append((n, tag))
129 tags.append((n, tag))
130 if rev == tagrev and tag != 'tip': # tip is not a real tag - and its branch is better
130 if rev == tagrev and tag != 'tip': # tip is not a real tag - and its branch is better
131 selected = n
131 selected = n
132
132
133 # prio 1: rev was selected as existing entry above
133 # prio 1: rev was selected as existing entry above
134
134
135 # prio 2: create special entry for rev; rev _must_ be used
135 # prio 2: create special entry for rev; rev _must_ be used
136 specials = []
136 specials = []
137 if rev and selected is None:
137 if rev and selected is None:
138 selected = 'rev:%s:%s' % (rev, rev)
138 selected = 'rev:%s:%s' % (rev, rev)
139 specials = [(selected, '%s: %s' % (_("Changeset"), rev[:12]))]
139 specials = [(selected, '%s: %s' % (_("Changeset"), rev[:12]))]
140
140
141 # prio 3: most recent peer branch
141 # prio 3: most recent peer branch
142 if peers and not selected:
142 if peers and not selected:
143 selected = peers[0][0][0]
143 selected = peers[0][0][0]
144
144
145 # prio 4: tip revision
145 # prio 4: tip revision
146 if not selected:
146 if not selected:
147 selected = 'tag:tip:%s' % repo.tags['tip']
147 selected = 'tag:tip:%s' % repo.tags['tip']
148
148
149 groups = [(specials, _("Special")),
149 groups = [(specials, _("Special")),
150 (peers, _("Peer branches")),
150 (peers, _("Peer branches")),
151 (bookmarks, _("Bookmarks")),
151 (bookmarks, _("Bookmarks")),
152 (branches, _("Branches")),
152 (branches, _("Branches")),
153 (tags, _("Tags")),
153 (tags, _("Tags")),
154 ]
154 ]
155 return [g for g in groups if g[0]], selected
155 return [g for g in groups if g[0]], selected
156
156
157 def _get_is_allowed_change_status(self, pull_request):
157 def _get_is_allowed_change_status(self, pull_request):
158 owner = self.rhodecode_user.user_id == pull_request.user_id
158 owner = self.rhodecode_user.user_id == pull_request.user_id
159 reviewer = self.rhodecode_user.user_id in [x.user_id for x in
159 reviewer = self.rhodecode_user.user_id in [x.user_id for x in
160 pull_request.reviewers]
160 pull_request.reviewers]
161 return (self.rhodecode_user.admin or owner or reviewer)
161 return (self.rhodecode_user.admin or owner or reviewer)
162
162
163 def _load_compare_data(self, pull_request, enable_comments=True):
163 def _load_compare_data(self, pull_request, enable_comments=True):
164 """
164 """
165 Load context data needed for generating compare diff
165 Load context data needed for generating compare diff
166
166
167 :param pull_request:
167 :param pull_request:
168 :type pull_request:
168 :type pull_request:
169 """
169 """
170 org_repo = pull_request.org_repo
170 org_repo = pull_request.org_repo
171 (org_ref_type,
171 (org_ref_type,
172 org_ref_name,
172 org_ref_name,
173 org_ref_rev) = pull_request.org_ref.split(':')
173 org_ref_rev) = pull_request.org_ref.split(':')
174
174
175 other_repo = org_repo
175 other_repo = org_repo
176 (other_ref_type,
176 (other_ref_type,
177 other_ref_name,
177 other_ref_name,
178 other_ref_rev) = pull_request.other_ref.split(':')
178 other_ref_rev) = pull_request.other_ref.split(':')
179
179
180 # despite opening revisions for bookmarks/branches/tags, we always
180 # despite opening revisions for bookmarks/branches/tags, we always
181 # convert this to rev to prevent changes after bookmark or branch change
181 # convert this to rev to prevent changes after bookmark or branch change
182 org_ref = ('rev', org_ref_rev)
182 org_ref = ('rev', org_ref_rev)
183 other_ref = ('rev', other_ref_rev)
183 other_ref = ('rev', other_ref_rev)
184
184
185 c.org_repo = org_repo
185 c.org_repo = org_repo
186 c.other_repo = other_repo
186 c.other_repo = other_repo
187
187
188 c.fulldiff = fulldiff = request.GET.get('fulldiff')
188 c.fulldiff = fulldiff = request.GET.get('fulldiff')
189
189
190 c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
190 c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
191
191
192 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
192 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
193
193
194 c.org_ref = org_ref[1]
194 c.org_ref = org_ref[1]
195 c.org_ref_type = org_ref[0]
195 c.org_ref_type = org_ref[0]
196 c.other_ref = other_ref[1]
196 c.other_ref = other_ref[1]
197 c.other_ref_type = other_ref[0]
197 c.other_ref_type = other_ref[0]
198
198
199 diff_limit = self.cut_off_limit if not fulldiff else None
199 diff_limit = self.cut_off_limit if not fulldiff else None
200
200
201 # we swap org/other ref since we run a simple diff on one repo
201 # we swap org/other ref since we run a simple diff on one repo
202 log.debug('running diff between %s and %s in %s'
202 log.debug('running diff between %s and %s in %s'
203 % (other_ref, org_ref, org_repo.scm_instance.path))
203 % (other_ref, org_ref, org_repo.scm_instance.path))
204 txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(other_ref[1]), rev2=safe_str(org_ref[1]))
204 txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(other_ref[1]), rev2=safe_str(org_ref[1]))
205
205
206 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
206 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
207 diff_limit=diff_limit)
207 diff_limit=diff_limit)
208 _parsed = diff_processor.prepare()
208 _parsed = diff_processor.prepare()
209
209
210 c.limited_diff = False
210 c.limited_diff = False
211 if isinstance(_parsed, LimitedDiffContainer):
211 if isinstance(_parsed, LimitedDiffContainer):
212 c.limited_diff = True
212 c.limited_diff = True
213
213
214 c.files = []
214 c.files = []
215 c.changes = {}
215 c.changes = {}
216 c.lines_added = 0
217 c.lines_deleted = 0
218 for f in _parsed:
216 for f in _parsed:
219 st = f['stats']
217 st = f['stats']
220 if st[0] != 'b':
218 c.lines_added += st['added']
221 c.lines_added += st[0]
219 c.lines_deleted += st['deleted']
222 c.lines_deleted += st[1]
223 fid = h.FID('', f['filename'])
220 fid = h.FID('', f['filename'])
224 c.files.append([fid, f['operation'], f['filename'], f['stats']])
221 c.files.append([fid, f['operation'], f['filename'], f['stats']])
225 htmldiff = diff_processor.as_html(enable_comments=enable_comments,
222 htmldiff = diff_processor.as_html(enable_comments=enable_comments,
226 parsed_lines=[f])
223 parsed_lines=[f])
227 c.changes[fid] = [f['operation'], f['filename'], htmldiff]
224 c.changes[fid] = [f['operation'], f['filename'], htmldiff]
228
225
229 @LoginRequired()
226 @LoginRequired()
230 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
227 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
231 'repository.admin')
228 'repository.admin')
232 def show_all(self, repo_name):
229 def show_all(self, repo_name):
233 c.pull_requests = PullRequestModel().get_all(repo_name)
230 c.pull_requests = PullRequestModel().get_all(repo_name)
234 c.repo_name = repo_name
231 c.repo_name = repo_name
235 p = safe_int(request.GET.get('page', 1), 1)
232 p = safe_int(request.GET.get('page', 1), 1)
236
233
237 c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10)
234 c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10)
238
235
239 c.pullrequest_data = render('/pullrequests/pullrequest_data.html')
236 c.pullrequest_data = render('/pullrequests/pullrequest_data.html')
240
237
241 if request.environ.get('HTTP_X_PARTIAL_XHR'):
238 if request.environ.get('HTTP_X_PARTIAL_XHR'):
242 return c.pullrequest_data
239 return c.pullrequest_data
243
240
244 return render('/pullrequests/pullrequest_show_all.html')
241 return render('/pullrequests/pullrequest_show_all.html')
245
242
246 @LoginRequired()
243 @LoginRequired()
247 @NotAnonymous()
244 @NotAnonymous()
248 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
245 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
249 'repository.admin')
246 'repository.admin')
250 def index(self):
247 def index(self):
251 org_repo = c.rhodecode_db_repo
248 org_repo = c.rhodecode_db_repo
252
249
253 if org_repo.scm_instance.alias != 'hg':
250 if org_repo.scm_instance.alias != 'hg':
254 log.error('Review not available for GIT REPOS')
251 log.error('Review not available for GIT REPOS')
255 raise HTTPNotFound
252 raise HTTPNotFound
256
253
257 try:
254 try:
258 org_repo.scm_instance.get_changeset()
255 org_repo.scm_instance.get_changeset()
259 except EmptyRepositoryError, e:
256 except EmptyRepositoryError, e:
260 h.flash(h.literal(_('There are no changesets yet')),
257 h.flash(h.literal(_('There are no changesets yet')),
261 category='warning')
258 category='warning')
262 redirect(url('summary_home', repo_name=org_repo.repo_name))
259 redirect(url('summary_home', repo_name=org_repo.repo_name))
263
260
264 org_rev = request.GET.get('rev_end')
261 org_rev = request.GET.get('rev_end')
265 # rev_start is not directly useful - its parent could however be used
262 # rev_start is not directly useful - its parent could however be used
266 # as default for other and thus give a simple compare view
263 # as default for other and thus give a simple compare view
267 #other_rev = request.POST.get('rev_start')
264 #other_rev = request.POST.get('rev_start')
268 branch = request.GET.get('branch')
265 branch = request.GET.get('branch')
269
266
270 c.org_repos = []
267 c.org_repos = []
271 c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
268 c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
272 c.default_org_repo = org_repo.repo_name
269 c.default_org_repo = org_repo.repo_name
273 c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, rev=org_rev, branch=branch)
270 c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, rev=org_rev, branch=branch)
274
271
275 c.other_repos = []
272 c.other_repos = []
276 other_repos_info = {}
273 other_repos_info = {}
277
274
278 def add_other_repo(repo, branch_rev=None):
275 def add_other_repo(repo, branch_rev=None):
279 if repo.repo_name in other_repos_info: # shouldn't happen
276 if repo.repo_name in other_repos_info: # shouldn't happen
280 return
277 return
281 c.other_repos.append((repo.repo_name, repo.repo_name))
278 c.other_repos.append((repo.repo_name, repo.repo_name))
282 other_refs, selected_other_ref = self._get_repo_refs(repo.scm_instance, branch_rev=branch_rev)
279 other_refs, selected_other_ref = self._get_repo_refs(repo.scm_instance, branch_rev=branch_rev)
283 other_repos_info[repo.repo_name] = {
280 other_repos_info[repo.repo_name] = {
284 'user': dict(user_id=repo.user.user_id,
281 'user': dict(user_id=repo.user.user_id,
285 username=repo.user.username,
282 username=repo.user.username,
286 firstname=repo.user.firstname,
283 firstname=repo.user.firstname,
287 lastname=repo.user.lastname,
284 lastname=repo.user.lastname,
288 gravatar_link=h.gravatar_url(repo.user.email, 14)),
285 gravatar_link=h.gravatar_url(repo.user.email, 14)),
289 'description': repo.description.split('\n', 1)[0],
286 'description': repo.description.split('\n', 1)[0],
290 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs')
287 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs')
291 }
288 }
292
289
293 # add org repo to other so we can open pull request against peer branches on itself
290 # add org repo to other so we can open pull request against peer branches on itself
294 add_other_repo(org_repo, branch_rev=org_rev)
291 add_other_repo(org_repo, branch_rev=org_rev)
295 c.default_other_repo = org_repo.repo_name
292 c.default_other_repo = org_repo.repo_name
296
293
297 # gather forks and add to this list ... even though it is rare to
294 # gather forks and add to this list ... even though it is rare to
298 # request forks to pull from their parent
295 # request forks to pull from their parent
299 for fork in org_repo.forks:
296 for fork in org_repo.forks:
300 add_other_repo(fork)
297 add_other_repo(fork)
301
298
302 # add parents of this fork also, but only if it's not empty
299 # add parents of this fork also, but only if it's not empty
303 if org_repo.parent and org_repo.parent.scm_instance.revisions:
300 if org_repo.parent and org_repo.parent.scm_instance.revisions:
304 add_other_repo(org_repo.parent)
301 add_other_repo(org_repo.parent)
305 c.default_other_repo = org_repo.parent.repo_name
302 c.default_other_repo = org_repo.parent.repo_name
306
303
307 c.default_other_repo_info = other_repos_info[c.default_other_repo]
304 c.default_other_repo_info = other_repos_info[c.default_other_repo]
308 c.other_repos_info = json.dumps(other_repos_info)
305 c.other_repos_info = json.dumps(other_repos_info)
309
306
310 return render('/pullrequests/pullrequest.html')
307 return render('/pullrequests/pullrequest.html')
311
308
312 @LoginRequired()
309 @LoginRequired()
313 @NotAnonymous()
310 @NotAnonymous()
314 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
311 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
315 'repository.admin')
312 'repository.admin')
316 def create(self, repo_name):
313 def create(self, repo_name):
317 repo = RepoModel()._get_repo(repo_name)
314 repo = RepoModel()._get_repo(repo_name)
318 try:
315 try:
319 _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
316 _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
320 except formencode.Invalid, errors:
317 except formencode.Invalid, errors:
321 log.error(traceback.format_exc())
318 log.error(traceback.format_exc())
322 if errors.error_dict.get('revisions'):
319 if errors.error_dict.get('revisions'):
323 msg = 'Revisions: %s' % errors.error_dict['revisions']
320 msg = 'Revisions: %s' % errors.error_dict['revisions']
324 elif errors.error_dict.get('pullrequest_title'):
321 elif errors.error_dict.get('pullrequest_title'):
325 msg = _('Pull request requires a title with min. 3 chars')
322 msg = _('Pull request requires a title with min. 3 chars')
326 else:
323 else:
327 msg = _('Error creating pull request')
324 msg = _('Error creating pull request')
328
325
329 h.flash(msg, 'error')
326 h.flash(msg, 'error')
330 return redirect(url('pullrequest_home', repo_name=repo_name))
327 return redirect(url('pullrequest_home', repo_name=repo_name))
331
328
332 org_repo = _form['org_repo']
329 org_repo = _form['org_repo']
333 org_ref = 'rev:merge:%s' % _form['merge_rev']
330 org_ref = 'rev:merge:%s' % _form['merge_rev']
334 other_repo = _form['other_repo']
331 other_repo = _form['other_repo']
335 other_ref = 'rev:ancestor:%s' % _form['ancestor_rev']
332 other_ref = 'rev:ancestor:%s' % _form['ancestor_rev']
336 revisions = [x for x in reversed(_form['revisions'])]
333 revisions = [x for x in reversed(_form['revisions'])]
337 reviewers = _form['review_members']
334 reviewers = _form['review_members']
338
335
339 title = _form['pullrequest_title']
336 title = _form['pullrequest_title']
340 description = _form['pullrequest_desc']
337 description = _form['pullrequest_desc']
341 try:
338 try:
342 pull_request = PullRequestModel().create(
339 pull_request = PullRequestModel().create(
343 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
340 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
344 other_ref, revisions, reviewers, title, description
341 other_ref, revisions, reviewers, title, description
345 )
342 )
346 Session().commit()
343 Session().commit()
347 h.flash(_('Successfully opened new pull request'),
344 h.flash(_('Successfully opened new pull request'),
348 category='success')
345 category='success')
349 except Exception:
346 except Exception:
350 h.flash(_('Error occurred during sending pull request'),
347 h.flash(_('Error occurred during sending pull request'),
351 category='error')
348 category='error')
352 log.error(traceback.format_exc())
349 log.error(traceback.format_exc())
353 return redirect(url('pullrequest_home', repo_name=repo_name))
350 return redirect(url('pullrequest_home', repo_name=repo_name))
354
351
355 return redirect(url('pullrequest_show', repo_name=other_repo,
352 return redirect(url('pullrequest_show', repo_name=other_repo,
356 pull_request_id=pull_request.pull_request_id))
353 pull_request_id=pull_request.pull_request_id))
357
354
358 @LoginRequired()
355 @LoginRequired()
359 @NotAnonymous()
356 @NotAnonymous()
360 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
357 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
361 'repository.admin')
358 'repository.admin')
362 @jsonify
359 @jsonify
363 def update(self, repo_name, pull_request_id):
360 def update(self, repo_name, pull_request_id):
364 pull_request = PullRequest.get_or_404(pull_request_id)
361 pull_request = PullRequest.get_or_404(pull_request_id)
365 if pull_request.is_closed():
362 if pull_request.is_closed():
366 raise HTTPForbidden()
363 raise HTTPForbidden()
367 #only owner or admin can update it
364 #only owner or admin can update it
368 owner = pull_request.author.user_id == c.rhodecode_user.user_id
365 owner = pull_request.author.user_id == c.rhodecode_user.user_id
369 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
366 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
370 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
367 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
371 request.POST.get('reviewers_ids', '').split(',')))
368 request.POST.get('reviewers_ids', '').split(',')))
372
369
373 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
370 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
374 Session().commit()
371 Session().commit()
375 return True
372 return True
376 raise HTTPForbidden()
373 raise HTTPForbidden()
377
374
378 @LoginRequired()
375 @LoginRequired()
379 @NotAnonymous()
376 @NotAnonymous()
380 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
377 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
381 'repository.admin')
378 'repository.admin')
382 @jsonify
379 @jsonify
383 def delete(self, repo_name, pull_request_id):
380 def delete(self, repo_name, pull_request_id):
384 pull_request = PullRequest.get_or_404(pull_request_id)
381 pull_request = PullRequest.get_or_404(pull_request_id)
385 #only owner can delete it !
382 #only owner can delete it !
386 if pull_request.author.user_id == c.rhodecode_user.user_id:
383 if pull_request.author.user_id == c.rhodecode_user.user_id:
387 PullRequestModel().delete(pull_request)
384 PullRequestModel().delete(pull_request)
388 Session().commit()
385 Session().commit()
389 h.flash(_('Successfully deleted pull request'),
386 h.flash(_('Successfully deleted pull request'),
390 category='success')
387 category='success')
391 return redirect(url('admin_settings_my_account', anchor='pullrequests'))
388 return redirect(url('admin_settings_my_account', anchor='pullrequests'))
392 raise HTTPForbidden()
389 raise HTTPForbidden()
393
390
394 @LoginRequired()
391 @LoginRequired()
395 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
392 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
396 'repository.admin')
393 'repository.admin')
397 def show(self, repo_name, pull_request_id):
394 def show(self, repo_name, pull_request_id):
398 repo_model = RepoModel()
395 repo_model = RepoModel()
399 c.users_array = repo_model.get_users_js()
396 c.users_array = repo_model.get_users_js()
400 c.users_groups_array = repo_model.get_users_groups_js()
397 c.users_groups_array = repo_model.get_users_groups_js()
401 c.pull_request = PullRequest.get_or_404(pull_request_id)
398 c.pull_request = PullRequest.get_or_404(pull_request_id)
402 c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
399 c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
403 cc_model = ChangesetCommentsModel()
400 cc_model = ChangesetCommentsModel()
404 cs_model = ChangesetStatusModel()
401 cs_model = ChangesetStatusModel()
405 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
402 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
406 pull_request=c.pull_request,
403 pull_request=c.pull_request,
407 with_revisions=True)
404 with_revisions=True)
408
405
409 cs_statuses = defaultdict(list)
406 cs_statuses = defaultdict(list)
410 for st in _cs_statuses:
407 for st in _cs_statuses:
411 cs_statuses[st.author.username] += [st]
408 cs_statuses[st.author.username] += [st]
412
409
413 c.pull_request_reviewers = []
410 c.pull_request_reviewers = []
414 c.pull_request_pending_reviewers = []
411 c.pull_request_pending_reviewers = []
415 for o in c.pull_request.reviewers:
412 for o in c.pull_request.reviewers:
416 st = cs_statuses.get(o.user.username, None)
413 st = cs_statuses.get(o.user.username, None)
417 if st:
414 if st:
418 sorter = lambda k: k.version
415 sorter = lambda k: k.version
419 st = [(x, list(y)[0])
416 st = [(x, list(y)[0])
420 for x, y in (groupby(sorted(st, key=sorter), sorter))]
417 for x, y in (groupby(sorted(st, key=sorter), sorter))]
421 else:
418 else:
422 c.pull_request_pending_reviewers.append(o.user)
419 c.pull_request_pending_reviewers.append(o.user)
423 c.pull_request_reviewers.append([o.user, st])
420 c.pull_request_reviewers.append([o.user, st])
424
421
425 # pull_requests repo_name we opened it against
422 # pull_requests repo_name we opened it against
426 # ie. other_repo must match
423 # ie. other_repo must match
427 if repo_name != c.pull_request.other_repo.repo_name:
424 if repo_name != c.pull_request.other_repo.repo_name:
428 raise HTTPNotFound
425 raise HTTPNotFound
429
426
430 # load compare data into template context
427 # load compare data into template context
431 enable_comments = not c.pull_request.is_closed()
428 enable_comments = not c.pull_request.is_closed()
432 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
429 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
433
430
434 # inline comments
431 # inline comments
435 c.inline_cnt = 0
432 c.inline_cnt = 0
436 c.inline_comments = cc_model.get_inline_comments(
433 c.inline_comments = cc_model.get_inline_comments(
437 c.rhodecode_db_repo.repo_id,
434 c.rhodecode_db_repo.repo_id,
438 pull_request=pull_request_id)
435 pull_request=pull_request_id)
439 # count inline comments
436 # count inline comments
440 for __, lines in c.inline_comments:
437 for __, lines in c.inline_comments:
441 for comments in lines.values():
438 for comments in lines.values():
442 c.inline_cnt += len(comments)
439 c.inline_cnt += len(comments)
443 # comments
440 # comments
444 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
441 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
445 pull_request=pull_request_id)
442 pull_request=pull_request_id)
446
443
447 try:
444 try:
448 cur_status = c.statuses[c.pull_request.revisions[0]][0]
445 cur_status = c.statuses[c.pull_request.revisions[0]][0]
449 except Exception:
446 except Exception:
450 log.error(traceback.format_exc())
447 log.error(traceback.format_exc())
451 cur_status = 'undefined'
448 cur_status = 'undefined'
452 if c.pull_request.is_closed() and 0:
449 if c.pull_request.is_closed() and 0:
453 c.current_changeset_status = cur_status
450 c.current_changeset_status = cur_status
454 else:
451 else:
455 # changeset(pull-request) status calulation based on reviewers
452 # changeset(pull-request) status calulation based on reviewers
456 c.current_changeset_status = cs_model.calculate_status(
453 c.current_changeset_status = cs_model.calculate_status(
457 c.pull_request_reviewers,
454 c.pull_request_reviewers,
458 )
455 )
459 c.changeset_statuses = ChangesetStatus.STATUSES
456 c.changeset_statuses = ChangesetStatus.STATUSES
460
457
461 c.as_form = False
458 c.as_form = False
462 c.ancestor = None # there is one - but right here we don't know which
459 c.ancestor = None # there is one - but right here we don't know which
463 return render('/pullrequests/pullrequest_show.html')
460 return render('/pullrequests/pullrequest_show.html')
464
461
465 @LoginRequired()
462 @LoginRequired()
466 @NotAnonymous()
463 @NotAnonymous()
467 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
464 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
468 'repository.admin')
465 'repository.admin')
469 @jsonify
466 @jsonify
470 def comment(self, repo_name, pull_request_id):
467 def comment(self, repo_name, pull_request_id):
471 pull_request = PullRequest.get_or_404(pull_request_id)
468 pull_request = PullRequest.get_or_404(pull_request_id)
472 if pull_request.is_closed():
469 if pull_request.is_closed():
473 raise HTTPForbidden()
470 raise HTTPForbidden()
474
471
475 status = request.POST.get('changeset_status')
472 status = request.POST.get('changeset_status')
476 change_status = request.POST.get('change_changeset_status')
473 change_status = request.POST.get('change_changeset_status')
477 text = request.POST.get('text')
474 text = request.POST.get('text')
478 close_pr = request.POST.get('save_close')
475 close_pr = request.POST.get('save_close')
479
476
480 allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
477 allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
481 if status and change_status and allowed_to_change_status:
478 if status and change_status and allowed_to_change_status:
482 _def = (_('Status change -> %s')
479 _def = (_('Status change -> %s')
483 % ChangesetStatus.get_status_lbl(status))
480 % ChangesetStatus.get_status_lbl(status))
484 if close_pr:
481 if close_pr:
485 _def = _('Closing with') + ' ' + _def
482 _def = _('Closing with') + ' ' + _def
486 text = text or _def
483 text = text or _def
487 comm = ChangesetCommentsModel().create(
484 comm = ChangesetCommentsModel().create(
488 text=text,
485 text=text,
489 repo=c.rhodecode_db_repo.repo_id,
486 repo=c.rhodecode_db_repo.repo_id,
490 user=c.rhodecode_user.user_id,
487 user=c.rhodecode_user.user_id,
491 pull_request=pull_request_id,
488 pull_request=pull_request_id,
492 f_path=request.POST.get('f_path'),
489 f_path=request.POST.get('f_path'),
493 line_no=request.POST.get('line'),
490 line_no=request.POST.get('line'),
494 status_change=(ChangesetStatus.get_status_lbl(status)
491 status_change=(ChangesetStatus.get_status_lbl(status)
495 if status and change_status
492 if status and change_status
496 and allowed_to_change_status else None),
493 and allowed_to_change_status else None),
497 closing_pr=close_pr
494 closing_pr=close_pr
498 )
495 )
499
496
500 action_logger(self.rhodecode_user,
497 action_logger(self.rhodecode_user,
501 'user_commented_pull_request:%s' % pull_request_id,
498 'user_commented_pull_request:%s' % pull_request_id,
502 c.rhodecode_db_repo, self.ip_addr, self.sa)
499 c.rhodecode_db_repo, self.ip_addr, self.sa)
503
500
504 if allowed_to_change_status:
501 if allowed_to_change_status:
505 # get status if set !
502 # get status if set !
506 if status and change_status:
503 if status and change_status:
507 ChangesetStatusModel().set_status(
504 ChangesetStatusModel().set_status(
508 c.rhodecode_db_repo.repo_id,
505 c.rhodecode_db_repo.repo_id,
509 status,
506 status,
510 c.rhodecode_user.user_id,
507 c.rhodecode_user.user_id,
511 comm,
508 comm,
512 pull_request=pull_request_id
509 pull_request=pull_request_id
513 )
510 )
514
511
515 if close_pr:
512 if close_pr:
516 if status in ['rejected', 'approved']:
513 if status in ['rejected', 'approved']:
517 PullRequestModel().close_pull_request(pull_request_id)
514 PullRequestModel().close_pull_request(pull_request_id)
518 action_logger(self.rhodecode_user,
515 action_logger(self.rhodecode_user,
519 'user_closed_pull_request:%s' % pull_request_id,
516 'user_closed_pull_request:%s' % pull_request_id,
520 c.rhodecode_db_repo, self.ip_addr, self.sa)
517 c.rhodecode_db_repo, self.ip_addr, self.sa)
521 else:
518 else:
522 h.flash(_('Closing pull request on other statuses than '
519 h.flash(_('Closing pull request on other statuses than '
523 'rejected or approved forbidden'),
520 'rejected or approved forbidden'),
524 category='warning')
521 category='warning')
525
522
526 Session().commit()
523 Session().commit()
527
524
528 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
525 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
529 return redirect(h.url('pullrequest_show', repo_name=repo_name,
526 return redirect(h.url('pullrequest_show', repo_name=repo_name,
530 pull_request_id=pull_request_id))
527 pull_request_id=pull_request_id))
531
528
532 data = {
529 data = {
533 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
530 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
534 }
531 }
535 if comm:
532 if comm:
536 c.co = comm
533 c.co = comm
537 data.update(comm.get_dict())
534 data.update(comm.get_dict())
538 data.update({'rendered_text':
535 data.update({'rendered_text':
539 render('changeset/changeset_comment_block.html')})
536 render('changeset/changeset_comment_block.html')})
540
537
541 return data
538 return data
542
539
543 @LoginRequired()
540 @LoginRequired()
544 @NotAnonymous()
541 @NotAnonymous()
545 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
542 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
546 'repository.admin')
543 'repository.admin')
547 @jsonify
544 @jsonify
548 def delete_comment(self, repo_name, comment_id):
545 def delete_comment(self, repo_name, comment_id):
549 co = ChangesetComment.get(comment_id)
546 co = ChangesetComment.get(comment_id)
550 if co.pull_request.is_closed():
547 if co.pull_request.is_closed():
551 #don't allow deleting comments on closed pull request
548 #don't allow deleting comments on closed pull request
552 raise HTTPForbidden()
549 raise HTTPForbidden()
553
550
554 owner = co.author.user_id == c.rhodecode_user.user_id
551 owner = co.author.user_id == c.rhodecode_user.user_id
555 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
552 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
556 ChangesetCommentsModel().delete(comment=co)
553 ChangesetCommentsModel().delete(comment=co)
557 Session().commit()
554 Session().commit()
558 return True
555 return True
559 else:
556 else:
560 raise HTTPForbidden()
557 raise HTTPForbidden()
@@ -1,688 +1,713 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.diffs
3 rhodecode.lib.diffs
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Set of diffing helpers, previously part of vcs
6 Set of diffing helpers, previously part of vcs
7
7
8
8
9 :created_on: Dec 4, 2011
9 :created_on: Dec 4, 2011
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :original copyright: 2007-2008 by Armin Ronacher
12 :original copyright: 2007-2008 by Armin Ronacher
13 :license: GPLv3, see COPYING for more details.
13 :license: GPLv3, see COPYING for more details.
14 """
14 """
15 # This program is free software: you can redistribute it and/or modify
15 # This program is free software: you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation, either version 3 of the License, or
17 # the Free Software Foundation, either version 3 of the License, or
18 # (at your option) any later version.
18 # (at your option) any later version.
19 #
19 #
20 # This program is distributed in the hope that it will be useful,
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
23 # GNU General Public License for more details.
24 #
24 #
25 # You should have received a copy of the GNU General Public License
25 # You should have received a copy of the GNU General Public License
26 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 # along with this program. If not, see <http://www.gnu.org/licenses/>.
27
27
28 import re
28 import re
29 import difflib
29 import difflib
30 import logging
30 import logging
31
31
32 from itertools import tee, imap
32 from itertools import tee, imap
33
33
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from rhodecode.lib.vcs.exceptions import VCSError
36 from rhodecode.lib.vcs.exceptions import VCSError
37 from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode
37 from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode
38 from rhodecode.lib.vcs.backends.base import EmptyChangeset
38 from rhodecode.lib.vcs.backends.base import EmptyChangeset
39 from rhodecode.lib.helpers import escape
39 from rhodecode.lib.helpers import escape
40 from rhodecode.lib.utils2 import safe_unicode, safe_str
40 from rhodecode.lib.utils2 import safe_unicode, safe_str
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 def wrap_to_table(str_):
45 def wrap_to_table(str_):
46 return '''<table class="code-difftable">
46 return '''<table class="code-difftable">
47 <tr class="line no-comment">
47 <tr class="line no-comment">
48 <td class="lineno new"></td>
48 <td class="lineno new"></td>
49 <td class="code no-comment"><pre>%s</pre></td>
49 <td class="code no-comment"><pre>%s</pre></td>
50 </tr>
50 </tr>
51 </table>''' % str_
51 </table>''' % str_
52
52
53
53
54 def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None,
54 def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None,
55 ignore_whitespace=True, line_context=3,
55 ignore_whitespace=True, line_context=3,
56 enable_comments=False):
56 enable_comments=False):
57 """
57 """
58 returns a wrapped diff into a table, checks for cut_off_limit and presents
58 returns a wrapped diff into a table, checks for cut_off_limit and presents
59 proper message
59 proper message
60 """
60 """
61
61
62 if filenode_old is None:
62 if filenode_old is None:
63 filenode_old = FileNode(filenode_new.path, '', EmptyChangeset())
63 filenode_old = FileNode(filenode_new.path, '', EmptyChangeset())
64
64
65 if filenode_old.is_binary or filenode_new.is_binary:
65 if filenode_old.is_binary or filenode_new.is_binary:
66 diff = wrap_to_table(_('Binary file'))
66 diff = wrap_to_table(_('Binary file'))
67 stats = (0, 0)
67 stats = (0, 0)
68 size = 0
68 size = 0
69
69
70 elif cut_off_limit != -1 and (cut_off_limit is None or
70 elif cut_off_limit != -1 and (cut_off_limit is None or
71 (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)):
71 (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)):
72
72
73 f_gitdiff = get_gitdiff(filenode_old, filenode_new,
73 f_gitdiff = get_gitdiff(filenode_old, filenode_new,
74 ignore_whitespace=ignore_whitespace,
74 ignore_whitespace=ignore_whitespace,
75 context=line_context)
75 context=line_context)
76 diff_processor = DiffProcessor(f_gitdiff, format='gitdiff')
76 diff_processor = DiffProcessor(f_gitdiff, format='gitdiff')
77
77
78 diff = diff_processor.as_html(enable_comments=enable_comments)
78 diff = diff_processor.as_html(enable_comments=enable_comments)
79 stats = diff_processor.stat()
79 stats = diff_processor.stat()
80 size = len(diff or '')
80 size = len(diff or '')
81 else:
81 else:
82 diff = wrap_to_table(_('Changeset was too big and was cut off, use '
82 diff = wrap_to_table(_('Changeset was too big and was cut off, use '
83 'diff menu to display this diff'))
83 'diff menu to display this diff'))
84 stats = (0, 0)
84 stats = (0, 0)
85 size = 0
85 size = 0
86 if not diff:
86 if not diff:
87 submodules = filter(lambda o: isinstance(o, SubModuleNode),
87 submodules = filter(lambda o: isinstance(o, SubModuleNode),
88 [filenode_new, filenode_old])
88 [filenode_new, filenode_old])
89 if submodules:
89 if submodules:
90 diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
90 diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
91 else:
91 else:
92 diff = wrap_to_table(_('No changes detected'))
92 diff = wrap_to_table(_('No changes detected'))
93
93
94 cs1 = filenode_old.changeset.raw_id
94 cs1 = filenode_old.changeset.raw_id
95 cs2 = filenode_new.changeset.raw_id
95 cs2 = filenode_new.changeset.raw_id
96
96
97 return size, cs1, cs2, diff, stats
97 return size, cs1, cs2, diff, stats
98
98
99
99
100 def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3):
100 def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3):
101 """
101 """
102 Returns git style diff between given ``filenode_old`` and ``filenode_new``.
102 Returns git style diff between given ``filenode_old`` and ``filenode_new``.
103
103
104 :param ignore_whitespace: ignore whitespaces in diff
104 :param ignore_whitespace: ignore whitespaces in diff
105 """
105 """
106 # make sure we pass in default context
106 # make sure we pass in default context
107 context = context or 3
107 context = context or 3
108 submodules = filter(lambda o: isinstance(o, SubModuleNode),
108 submodules = filter(lambda o: isinstance(o, SubModuleNode),
109 [filenode_new, filenode_old])
109 [filenode_new, filenode_old])
110 if submodules:
110 if submodules:
111 return ''
111 return ''
112
112
113 for filenode in (filenode_old, filenode_new):
113 for filenode in (filenode_old, filenode_new):
114 if not isinstance(filenode, FileNode):
114 if not isinstance(filenode, FileNode):
115 raise VCSError("Given object should be FileNode object, not %s"
115 raise VCSError("Given object should be FileNode object, not %s"
116 % filenode.__class__)
116 % filenode.__class__)
117
117
118 repo = filenode_new.changeset.repository
118 repo = filenode_new.changeset.repository
119 old_raw_id = getattr(filenode_old.changeset, 'raw_id', repo.EMPTY_CHANGESET)
119 old_raw_id = getattr(filenode_old.changeset, 'raw_id', repo.EMPTY_CHANGESET)
120 new_raw_id = getattr(filenode_new.changeset, 'raw_id', repo.EMPTY_CHANGESET)
120 new_raw_id = getattr(filenode_new.changeset, 'raw_id', repo.EMPTY_CHANGESET)
121
121
122 vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path,
122 vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path,
123 ignore_whitespace, context)
123 ignore_whitespace, context)
124 return vcs_gitdiff
124 return vcs_gitdiff
125
125
126 NEW_FILENODE = 1
126 NEW_FILENODE = 1
127 DEL_FILENODE = 2
127 DEL_FILENODE = 2
128 MOD_FILENODE = 3
128 MOD_FILENODE = 3
129 RENAMED_FILENODE = 4
129 RENAMED_FILENODE = 4
130 CHMOD_FILENODE = 5
130 CHMOD_FILENODE = 5
131 BIN_FILENODE = 6
131
132
132
133
133 class DiffLimitExceeded(Exception):
134 class DiffLimitExceeded(Exception):
134 pass
135 pass
135
136
136
137
137 class LimitedDiffContainer(object):
138 class LimitedDiffContainer(object):
138
139
139 def __init__(self, diff_limit, cur_diff_size, diff):
140 def __init__(self, diff_limit, cur_diff_size, diff):
140 self.diff = diff
141 self.diff = diff
141 self.diff_limit = diff_limit
142 self.diff_limit = diff_limit
142 self.cur_diff_size = cur_diff_size
143 self.cur_diff_size = cur_diff_size
143
144
144 def __iter__(self):
145 def __iter__(self):
145 for l in self.diff:
146 for l in self.diff:
146 yield l
147 yield l
147
148
148
149
149 class DiffProcessor(object):
150 class DiffProcessor(object):
150 """
151 """
151 Give it a unified or git diff and it returns a list of the files that were
152 Give it a unified or git diff and it returns a list of the files that were
152 mentioned in the diff together with a dict of meta information that
153 mentioned in the diff together with a dict of meta information that
153 can be used to render it in a HTML template.
154 can be used to render it in a HTML template.
154 """
155 """
155 _chunk_re = re.compile(r'^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
156 _chunk_re = re.compile(r'^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
156 _newline_marker = re.compile(r'^\\ No newline at end of file')
157 _newline_marker = re.compile(r'^\\ No newline at end of file')
157 _git_header_re = re.compile(r"""
158 _git_header_re = re.compile(r"""
158 #^diff[ ]--git
159 #^diff[ ]--git
159 [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
160 [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
160 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
161 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
161 ^rename[ ]from[ ](?P<rename_from>\S+)\n
162 ^rename[ ]from[ ](?P<rename_from>\S+)\n
162 ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
163 ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
163 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
164 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
164 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
165 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
165 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
166 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
166 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
167 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
167 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
168 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
168 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
169 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
170 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
169 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
171 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
170 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
172 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
171 """, re.VERBOSE | re.MULTILINE)
173 """, re.VERBOSE | re.MULTILINE)
172 _hg_header_re = re.compile(r"""
174 _hg_header_re = re.compile(r"""
173 #^diff[ ]--git
175 #^diff[ ]--git
174 [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
176 [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
175 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
177 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
176 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
178 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
177 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
179 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
178 (?:^rename[ ]from[ ](?P<rename_from>\S+)\n
180 (?:^rename[ ]from[ ](?P<rename_from>\S+)\n
179 ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
181 ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
180 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
182 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
181 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
183 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
182 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
184 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
183 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
185 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
186 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
184 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
187 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
185 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
188 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
186 """, re.VERBOSE | re.MULTILINE)
189 """, re.VERBOSE | re.MULTILINE)
187
190
188 #used for inline highlighter word split
191 #used for inline highlighter word split
189 _token_re = re.compile(r'()(&gt;|&lt;|&amp;|\W+?)')
192 _token_re = re.compile(r'()(&gt;|&lt;|&amp;|\W+?)')
190
193
191 def __init__(self, diff, vcs='hg', format='gitdiff', diff_limit=None):
194 def __init__(self, diff, vcs='hg', format='gitdiff', diff_limit=None):
192 """
195 """
193 :param diff: a text in diff format
196 :param diff: a text in diff format
194 :param vcs: type of version controll hg or git
197 :param vcs: type of version controll hg or git
195 :param format: format of diff passed, `udiff` or `gitdiff`
198 :param format: format of diff passed, `udiff` or `gitdiff`
196 :param diff_limit: define the size of diff that is considered "big"
199 :param diff_limit: define the size of diff that is considered "big"
197 based on that parameter cut off will be triggered, set to None
200 based on that parameter cut off will be triggered, set to None
198 to show full diff
201 to show full diff
199 """
202 """
200 if not isinstance(diff, basestring):
203 if not isinstance(diff, basestring):
201 raise Exception('Diff must be a basestring got %s instead' % type(diff))
204 raise Exception('Diff must be a basestring got %s instead' % type(diff))
202
205
203 self._diff = diff
206 self._diff = diff
204 self._format = format
207 self._format = format
205 self.adds = 0
208 self.adds = 0
206 self.removes = 0
209 self.removes = 0
207 # calculate diff size
210 # calculate diff size
208 self.diff_size = len(diff)
211 self.diff_size = len(diff)
209 self.diff_limit = diff_limit
212 self.diff_limit = diff_limit
210 self.cur_diff_size = 0
213 self.cur_diff_size = 0
211 self.parsed = False
214 self.parsed = False
212 self.parsed_diff = []
215 self.parsed_diff = []
213 self.vcs = vcs
216 self.vcs = vcs
214
217
215 if format == 'gitdiff':
218 if format == 'gitdiff':
216 self.differ = self._highlight_line_difflib
219 self.differ = self._highlight_line_difflib
217 self._parser = self._parse_gitdiff
220 self._parser = self._parse_gitdiff
218 else:
221 else:
219 self.differ = self._highlight_line_udiff
222 self.differ = self._highlight_line_udiff
220 self._parser = self._parse_udiff
223 self._parser = self._parse_udiff
221
224
222 def _copy_iterator(self):
225 def _copy_iterator(self):
223 """
226 """
224 make a fresh copy of generator, we should not iterate thru
227 make a fresh copy of generator, we should not iterate thru
225 an original as it's needed for repeating operations on
228 an original as it's needed for repeating operations on
226 this instance of DiffProcessor
229 this instance of DiffProcessor
227 """
230 """
228 self.__udiff, iterator_copy = tee(self.__udiff)
231 self.__udiff, iterator_copy = tee(self.__udiff)
229 return iterator_copy
232 return iterator_copy
230
233
231 def _escaper(self, string):
234 def _escaper(self, string):
232 """
235 """
233 Escaper for diff escapes special chars and checks the diff limit
236 Escaper for diff escapes special chars and checks the diff limit
234
237
235 :param string:
238 :param string:
236 :type string:
239 :type string:
237 """
240 """
238
241
239 self.cur_diff_size += len(string)
242 self.cur_diff_size += len(string)
240
243
241 # escaper get's iterated on each .next() call and it checks if each
244 # escaper get's iterated on each .next() call and it checks if each
242 # parsed line doesn't exceed the diff limit
245 # parsed line doesn't exceed the diff limit
243 if self.diff_limit is not None and self.cur_diff_size > self.diff_limit:
246 if self.diff_limit is not None and self.cur_diff_size > self.diff_limit:
244 raise DiffLimitExceeded('Diff Limit Exceeded')
247 raise DiffLimitExceeded('Diff Limit Exceeded')
245
248
246 return safe_unicode(string).replace('&', '&amp;')\
249 return safe_unicode(string).replace('&', '&amp;')\
247 .replace('<', '&lt;')\
250 .replace('<', '&lt;')\
248 .replace('>', '&gt;')
251 .replace('>', '&gt;')
249
252
250 def _line_counter(self, l):
253 def _line_counter(self, l):
251 """
254 """
252 Checks each line and bumps total adds/removes for this diff
255 Checks each line and bumps total adds/removes for this diff
253
256
254 :param l:
257 :param l:
255 """
258 """
256 if l.startswith('+') and not l.startswith('+++'):
259 if l.startswith('+') and not l.startswith('+++'):
257 self.adds += 1
260 self.adds += 1
258 elif l.startswith('-') and not l.startswith('---'):
261 elif l.startswith('-') and not l.startswith('---'):
259 self.removes += 1
262 self.removes += 1
260 return safe_unicode(l)
263 return safe_unicode(l)
261
264
262 def _highlight_line_difflib(self, line, next_):
265 def _highlight_line_difflib(self, line, next_):
263 """
266 """
264 Highlight inline changes in both lines.
267 Highlight inline changes in both lines.
265 """
268 """
266
269
267 if line['action'] == 'del':
270 if line['action'] == 'del':
268 old, new = line, next_
271 old, new = line, next_
269 else:
272 else:
270 old, new = next_, line
273 old, new = next_, line
271
274
272 oldwords = self._token_re.split(old['line'])
275 oldwords = self._token_re.split(old['line'])
273 newwords = self._token_re.split(new['line'])
276 newwords = self._token_re.split(new['line'])
274 sequence = difflib.SequenceMatcher(None, oldwords, newwords)
277 sequence = difflib.SequenceMatcher(None, oldwords, newwords)
275
278
276 oldfragments, newfragments = [], []
279 oldfragments, newfragments = [], []
277 for tag, i1, i2, j1, j2 in sequence.get_opcodes():
280 for tag, i1, i2, j1, j2 in sequence.get_opcodes():
278 oldfrag = ''.join(oldwords[i1:i2])
281 oldfrag = ''.join(oldwords[i1:i2])
279 newfrag = ''.join(newwords[j1:j2])
282 newfrag = ''.join(newwords[j1:j2])
280 if tag != 'equal':
283 if tag != 'equal':
281 if oldfrag:
284 if oldfrag:
282 oldfrag = '<del>%s</del>' % oldfrag
285 oldfrag = '<del>%s</del>' % oldfrag
283 if newfrag:
286 if newfrag:
284 newfrag = '<ins>%s</ins>' % newfrag
287 newfrag = '<ins>%s</ins>' % newfrag
285 oldfragments.append(oldfrag)
288 oldfragments.append(oldfrag)
286 newfragments.append(newfrag)
289 newfragments.append(newfrag)
287
290
288 old['line'] = "".join(oldfragments)
291 old['line'] = "".join(oldfragments)
289 new['line'] = "".join(newfragments)
292 new['line'] = "".join(newfragments)
290
293
291 def _highlight_line_udiff(self, line, next_):
294 def _highlight_line_udiff(self, line, next_):
292 """
295 """
293 Highlight inline changes in both lines.
296 Highlight inline changes in both lines.
294 """
297 """
295 start = 0
298 start = 0
296 limit = min(len(line['line']), len(next_['line']))
299 limit = min(len(line['line']), len(next_['line']))
297 while start < limit and line['line'][start] == next_['line'][start]:
300 while start < limit and line['line'][start] == next_['line'][start]:
298 start += 1
301 start += 1
299 end = -1
302 end = -1
300 limit -= start
303 limit -= start
301 while -end <= limit and line['line'][end] == next_['line'][end]:
304 while -end <= limit and line['line'][end] == next_['line'][end]:
302 end -= 1
305 end -= 1
303 end += 1
306 end += 1
304 if start or end:
307 if start or end:
305 def do(l):
308 def do(l):
306 last = end + len(l['line'])
309 last = end + len(l['line'])
307 if l['action'] == 'add':
310 if l['action'] == 'add':
308 tag = 'ins'
311 tag = 'ins'
309 else:
312 else:
310 tag = 'del'
313 tag = 'del'
311 l['line'] = '%s<%s>%s</%s>%s' % (
314 l['line'] = '%s<%s>%s</%s>%s' % (
312 l['line'][:start],
315 l['line'][:start],
313 tag,
316 tag,
314 l['line'][start:last],
317 l['line'][start:last],
315 tag,
318 tag,
316 l['line'][last:]
319 l['line'][last:]
317 )
320 )
318 do(line)
321 do(line)
319 do(next_)
322 do(next_)
320
323
321 def _get_header(self, diff_chunk):
324 def _get_header(self, diff_chunk):
322 """
325 """
323 parses the diff header, and returns parts, and leftover diff
326 parses the diff header, and returns parts, and leftover diff
324 parts consists of 14 elements::
327 parts consists of 14 elements::
325
328
326 a_path, b_path, similarity_index, rename_from, rename_to,
329 a_path, b_path, similarity_index, rename_from, rename_to,
327 old_mode, new_mode, new_file_mode, deleted_file_mode,
330 old_mode, new_mode, new_file_mode, deleted_file_mode,
328 a_blob_id, b_blob_id, b_mode, a_file, b_file
331 a_blob_id, b_blob_id, b_mode, a_file, b_file
329
332
330 :param diff_chunk:
333 :param diff_chunk:
331 :type diff_chunk:
334 :type diff_chunk:
332 """
335 """
333
336
334 if self.vcs == 'git':
337 if self.vcs == 'git':
335 match = self._git_header_re.match(diff_chunk)
338 match = self._git_header_re.match(diff_chunk)
336 diff = diff_chunk[match.end():]
339 diff = diff_chunk[match.end():]
337 return match.groupdict(), imap(self._escaper, diff.splitlines(1))
340 return match.groupdict(), imap(self._escaper, diff.splitlines(1))
338 elif self.vcs == 'hg':
341 elif self.vcs == 'hg':
339 match = self._hg_header_re.match(diff_chunk)
342 match = self._hg_header_re.match(diff_chunk)
340 diff = diff_chunk[match.end():]
343 diff = diff_chunk[match.end():]
341 return match.groupdict(), imap(self._escaper, diff.splitlines(1))
344 return match.groupdict(), imap(self._escaper, diff.splitlines(1))
342 else:
345 else:
343 raise Exception('VCS type %s is not supported' % self.vcs)
346 raise Exception('VCS type %s is not supported' % self.vcs)
344
347
345 def _clean_line(self, line, command):
348 def _clean_line(self, line, command):
346 if command in ['+', '-', ' ']:
349 if command in ['+', '-', ' ']:
347 #only modify the line if it's actually a diff thing
350 #only modify the line if it's actually a diff thing
348 line = line[1:]
351 line = line[1:]
349 return line
352 return line
350
353
351 def _parse_gitdiff(self, inline_diff=True):
354 def _parse_gitdiff(self, inline_diff=True):
352 _files = []
355 _files = []
353 diff_container = lambda arg: arg
356 diff_container = lambda arg: arg
354
357
355 ##split the diff in chunks of separate --git a/file b/file chunks
358 ##split the diff in chunks of separate --git a/file b/file chunks
356 for raw_diff in ('\n' + self._diff).split('\ndiff --git')[1:]:
359 for raw_diff in ('\n' + self._diff).split('\ndiff --git')[1:]:
357 head, diff = self._get_header(raw_diff)
360 head, diff = self._get_header(raw_diff)
358
361
359 op = None
362 op = None
360 stats = None
363 stats = {
361 msgs = []
364 'added': 0,
365 'deleted': 0,
366 'binary': False,
367 'ops': {},
368 }
362
369
363 if head['deleted_file_mode']:
370 if head['deleted_file_mode']:
364 op = 'D'
371 op = 'D'
365 stats = ['b', DEL_FILENODE]
372 stats['binary'] = True
366 msgs.append('deleted file')
373 stats['ops'][DEL_FILENODE] = 'deleted file'
374
367 elif head['new_file_mode']:
375 elif head['new_file_mode']:
368 op = 'A'
376 op = 'A'
369 stats = ['b', NEW_FILENODE]
377 stats['binary'] = True
370 msgs.append('new file %s' % head['new_file_mode'])
378 stats['ops'][NEW_FILENODE] = 'new file %s' % head['new_file_mode']
371 else:
379 else: # modify operation, can be cp, rename, chmod
380 # CHMOD
372 if head['new_mode'] and head['old_mode']:
381 if head['new_mode'] and head['old_mode']:
373 op = 'M'
382 op = 'M'
374 stats = ['b', CHMOD_FILENODE]
383 stats['binary'] = True
375 msgs.append('modified file chmod %s => %s'
384 stats['ops'][CHMOD_FILENODE] = ('modified file chmod %s => %s'
376 % (head['old_mode'], head['new_mode']))
385 % (head['old_mode'], head['new_mode']))
386 # RENAME
377 if (head['rename_from'] and head['rename_to']
387 if (head['rename_from'] and head['rename_to']
378 and head['rename_from'] != head['rename_to']):
388 and head['rename_from'] != head['rename_to']):
379 op = 'M'
389 op = 'M'
380 stats = ['b', RENAMED_FILENODE] # might overwrite CHMOD_FILENODE
390 stats['binary'] = True
381 msgs.append('file renamed from %s to %s'
391 stats['ops'][RENAMED_FILENODE] = ('file renamed from %s to %s'
382 % (head['rename_from'], head['rename_to']))
392 % (head['rename_from'], head['rename_to']))
383 if op is None: # fall back: detect missed old style add or remove
393
394 # FALL BACK: detect missed old style add or remove
395 if op is None:
384 if not head['a_file'] and head['b_file']:
396 if not head['a_file'] and head['b_file']:
385 op = 'A'
397 op = 'A'
386 stats = ['b', NEW_FILENODE]
398 stats['binary'] = True
387 msgs.append('new file')
399 stats['ops'][NEW_FILENODE] = 'new file'
400
388 elif head['a_file'] and not head['b_file']:
401 elif head['a_file'] and not head['b_file']:
389 op = 'D'
402 op = 'D'
390 stats = ['b', DEL_FILENODE]
403 stats['binary'] = True
391 msgs.append('deleted file')
404 stats['ops'][DEL_FILENODE] = 'deleted file'
405
406 # it's not ADD not DELETE
392 if op is None:
407 if op is None:
393 op = 'M'
408 op = 'M'
394 stats = ['b', MOD_FILENODE]
409 stats['binary'] = True
410 stats['ops'][MOD_FILENODE] = 'modified file'
395
411
396 if head['a_file'] or head['b_file']: # a real diff
412 # a real non-binary diff
413 if head['a_file'] or head['b_file']:
397 try:
414 try:
398 chunks, stats = self._parse_lines(diff)
415 chunks, _stats = self._parse_lines(diff)
416 stats['binary'] = False
417 stats['added'] = _stats[0]
418 stats['deleted'] = _stats[1]
419 # explicit mark that it's a modified file
420 if op == 'M':
421 stats['ops'][MOD_FILENODE] = 'modified file'
422
399 except DiffLimitExceeded:
423 except DiffLimitExceeded:
400 diff_container = lambda _diff: LimitedDiffContainer(
424 diff_container = lambda _diff: \
401 self.diff_limit,
425 LimitedDiffContainer(self.diff_limit,
402 self.cur_diff_size,
426 self.cur_diff_size, _diff)
403 _diff)
404 break
427 break
405 else: # GIT binary patch (or empty diff)
428 else: # GIT binary patch (or empty diff)
429 # GIT Binary patch
430 if head['bin_patch']:
431 stats['ops'][BIN_FILENODE] = 'binary diff not shown'
406 chunks = []
432 chunks = []
407 msgs.append('binary diff not shown') # or no diff because it was a rename or chmod or add/remove of empty file
408
433
409 if msgs:
410 chunks.insert(0, [{
434 chunks.insert(0, [{
411 'old_lineno': '',
435 'old_lineno': '',
412 'new_lineno': '',
436 'new_lineno': '',
413 'action': 'binary',
437 'action': 'context',
414 'line': msg,
438 'line': msg,
415 } for msg in msgs])
439 } for _op, msg in stats['ops'].iteritems()
440 if _op not in [MOD_FILENODE]])
416
441
417 _files.append({
442 _files.append({
418 'filename': head['b_path'],
443 'filename': head['b_path'],
419 'old_revision': head['a_blob_id'],
444 'old_revision': head['a_blob_id'],
420 'new_revision': head['b_blob_id'],
445 'new_revision': head['b_blob_id'],
421 'chunks': chunks,
446 'chunks': chunks,
422 'operation': op,
447 'operation': op,
423 'stats': stats,
448 'stats': stats,
424 })
449 })
425
450
426 sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
451 sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
427
452
428 if not inline_diff:
453 if not inline_diff:
429 return diff_container(sorted(_files, key=sorter))
454 return diff_container(sorted(_files, key=sorter))
430
455
431 # highlight inline changes
456 # highlight inline changes
432 for diff_data in _files:
457 for diff_data in _files:
433 for chunk in diff_data['chunks']:
458 for chunk in diff_data['chunks']:
434 lineiter = iter(chunk)
459 lineiter = iter(chunk)
435 try:
460 try:
436 while 1:
461 while 1:
437 line = lineiter.next()
462 line = lineiter.next()
438 if line['action'] not in ['unmod', 'context']:
463 if line['action'] not in ['unmod', 'context']:
439 nextline = lineiter.next()
464 nextline = lineiter.next()
440 if nextline['action'] in ['unmod', 'context'] or \
465 if nextline['action'] in ['unmod', 'context'] or \
441 nextline['action'] == line['action']:
466 nextline['action'] == line['action']:
442 continue
467 continue
443 self.differ(line, nextline)
468 self.differ(line, nextline)
444 except StopIteration:
469 except StopIteration:
445 pass
470 pass
446
471
447 return diff_container(sorted(_files, key=sorter))
472 return diff_container(sorted(_files, key=sorter))
448
473
449 def _parse_udiff(self, inline_diff=True):
474 def _parse_udiff(self, inline_diff=True):
450 raise NotImplementedError()
475 raise NotImplementedError()
451
476
452 def _parse_lines(self, diff):
477 def _parse_lines(self, diff):
453 """
478 """
454 Parse the diff an return data for the template.
479 Parse the diff an return data for the template.
455 """
480 """
456
481
457 lineiter = iter(diff)
482 lineiter = iter(diff)
458 stats = [0, 0]
483 stats = [0, 0]
459
484
460 try:
485 try:
461 chunks = []
486 chunks = []
462 line = lineiter.next()
487 line = lineiter.next()
463
488
464 while line:
489 while line:
465 lines = []
490 lines = []
466 chunks.append(lines)
491 chunks.append(lines)
467
492
468 match = self._chunk_re.match(line)
493 match = self._chunk_re.match(line)
469
494
470 if not match:
495 if not match:
471 break
496 break
472
497
473 gr = match.groups()
498 gr = match.groups()
474 (old_line, old_end,
499 (old_line, old_end,
475 new_line, new_end) = [int(x or 1) for x in gr[:-1]]
500 new_line, new_end) = [int(x or 1) for x in gr[:-1]]
476 old_line -= 1
501 old_line -= 1
477 new_line -= 1
502 new_line -= 1
478
503
479 context = len(gr) == 5
504 context = len(gr) == 5
480 old_end += old_line
505 old_end += old_line
481 new_end += new_line
506 new_end += new_line
482
507
483 if context:
508 if context:
484 # skip context only if it's first line
509 # skip context only if it's first line
485 if int(gr[0]) > 1:
510 if int(gr[0]) > 1:
486 lines.append({
511 lines.append({
487 'old_lineno': '...',
512 'old_lineno': '...',
488 'new_lineno': '...',
513 'new_lineno': '...',
489 'action': 'context',
514 'action': 'context',
490 'line': line,
515 'line': line,
491 })
516 })
492
517
493 line = lineiter.next()
518 line = lineiter.next()
494
519
495 while old_line < old_end or new_line < new_end:
520 while old_line < old_end or new_line < new_end:
496 command = ' '
521 command = ' '
497 if line:
522 if line:
498 command = line[0]
523 command = line[0]
499
524
500 affects_old = affects_new = False
525 affects_old = affects_new = False
501
526
502 # ignore those if we don't expect them
527 # ignore those if we don't expect them
503 if command in '#@':
528 if command in '#@':
504 continue
529 continue
505 elif command == '+':
530 elif command == '+':
506 affects_new = True
531 affects_new = True
507 action = 'add'
532 action = 'add'
508 stats[0] += 1
533 stats[0] += 1
509 elif command == '-':
534 elif command == '-':
510 affects_old = True
535 affects_old = True
511 action = 'del'
536 action = 'del'
512 stats[1] += 1
537 stats[1] += 1
513 else:
538 else:
514 affects_old = affects_new = True
539 affects_old = affects_new = True
515 action = 'unmod'
540 action = 'unmod'
516
541
517 if not self._newline_marker.match(line):
542 if not self._newline_marker.match(line):
518 old_line += affects_old
543 old_line += affects_old
519 new_line += affects_new
544 new_line += affects_new
520 lines.append({
545 lines.append({
521 'old_lineno': affects_old and old_line or '',
546 'old_lineno': affects_old and old_line or '',
522 'new_lineno': affects_new and new_line or '',
547 'new_lineno': affects_new and new_line or '',
523 'action': action,
548 'action': action,
524 'line': self._clean_line(line, command)
549 'line': self._clean_line(line, command)
525 })
550 })
526
551
527 line = lineiter.next()
552 line = lineiter.next()
528
553
529 if self._newline_marker.match(line):
554 if self._newline_marker.match(line):
530 # we need to append to lines, since this is not
555 # we need to append to lines, since this is not
531 # counted in the line specs of diff
556 # counted in the line specs of diff
532 lines.append({
557 lines.append({
533 'old_lineno': '...',
558 'old_lineno': '...',
534 'new_lineno': '...',
559 'new_lineno': '...',
535 'action': 'context',
560 'action': 'context',
536 'line': self._clean_line(line, command)
561 'line': self._clean_line(line, command)
537 })
562 })
538
563
539 except StopIteration:
564 except StopIteration:
540 pass
565 pass
541 return chunks, stats
566 return chunks, stats
542
567
543 def _safe_id(self, idstring):
568 def _safe_id(self, idstring):
544 """Make a string safe for including in an id attribute.
569 """Make a string safe for including in an id attribute.
545
570
546 The HTML spec says that id attributes 'must begin with
571 The HTML spec says that id attributes 'must begin with
547 a letter ([A-Za-z]) and may be followed by any number
572 a letter ([A-Za-z]) and may be followed by any number
548 of letters, digits ([0-9]), hyphens ("-"), underscores
573 of letters, digits ([0-9]), hyphens ("-"), underscores
549 ("_"), colons (":"), and periods (".")'. These regexps
574 ("_"), colons (":"), and periods (".")'. These regexps
550 are slightly over-zealous, in that they remove colons
575 are slightly over-zealous, in that they remove colons
551 and periods unnecessarily.
576 and periods unnecessarily.
552
577
553 Whitespace is transformed into underscores, and then
578 Whitespace is transformed into underscores, and then
554 anything which is not a hyphen or a character that
579 anything which is not a hyphen or a character that
555 matches \w (alphanumerics and underscore) is removed.
580 matches \w (alphanumerics and underscore) is removed.
556
581
557 """
582 """
558 # Transform all whitespace to underscore
583 # Transform all whitespace to underscore
559 idstring = re.sub(r'\s', "_", '%s' % idstring)
584 idstring = re.sub(r'\s', "_", '%s' % idstring)
560 # Remove everything that is not a hyphen or a member of \w
585 # Remove everything that is not a hyphen or a member of \w
561 idstring = re.sub(r'(?!-)\W', "", idstring).lower()
586 idstring = re.sub(r'(?!-)\W', "", idstring).lower()
562 return idstring
587 return idstring
563
588
564 def prepare(self, inline_diff=True):
589 def prepare(self, inline_diff=True):
565 """
590 """
566 Prepare the passed udiff for HTML rendering. It'l return a list
591 Prepare the passed udiff for HTML rendering. It'l return a list
567 of dicts with diff information
592 of dicts with diff information
568 """
593 """
569 parsed = self._parser(inline_diff=inline_diff)
594 parsed = self._parser(inline_diff=inline_diff)
570 self.parsed = True
595 self.parsed = True
571 self.parsed_diff = parsed
596 self.parsed_diff = parsed
572 return parsed
597 return parsed
573
598
574 def as_raw(self, diff_lines=None):
599 def as_raw(self, diff_lines=None):
575 """
600 """
576 Returns raw string diff
601 Returns raw string diff
577 """
602 """
578 return self._diff
603 return self._diff
579 #return u''.join(imap(self._line_counter, self._diff.splitlines(1)))
604 #return u''.join(imap(self._line_counter, self._diff.splitlines(1)))
580
605
581 def as_html(self, table_class='code-difftable', line_class='line',
606 def as_html(self, table_class='code-difftable', line_class='line',
582 old_lineno_class='lineno old', new_lineno_class='lineno new',
607 old_lineno_class='lineno old', new_lineno_class='lineno new',
583 code_class='code', enable_comments=False, parsed_lines=None):
608 code_class='code', enable_comments=False, parsed_lines=None):
584 """
609 """
585 Return given diff as html table with customized css classes
610 Return given diff as html table with customized css classes
586 """
611 """
587 def _link_to_if(condition, label, url):
612 def _link_to_if(condition, label, url):
588 """
613 """
589 Generates a link if condition is meet or just the label if not.
614 Generates a link if condition is meet or just the label if not.
590 """
615 """
591
616
592 if condition:
617 if condition:
593 return '''<a href="%(url)s">%(label)s</a>''' % {
618 return '''<a href="%(url)s">%(label)s</a>''' % {
594 'url': url,
619 'url': url,
595 'label': label
620 'label': label
596 }
621 }
597 else:
622 else:
598 return label
623 return label
599 if not self.parsed:
624 if not self.parsed:
600 self.prepare()
625 self.prepare()
601
626
602 diff_lines = self.parsed_diff
627 diff_lines = self.parsed_diff
603 if parsed_lines:
628 if parsed_lines:
604 diff_lines = parsed_lines
629 diff_lines = parsed_lines
605
630
606 _html_empty = True
631 _html_empty = True
607 _html = []
632 _html = []
608 _html.append('''<table class="%(table_class)s">\n''' % {
633 _html.append('''<table class="%(table_class)s">\n''' % {
609 'table_class': table_class
634 'table_class': table_class
610 })
635 })
611
636
612 for diff in diff_lines:
637 for diff in diff_lines:
613 for line in diff['chunks']:
638 for line in diff['chunks']:
614 _html_empty = False
639 _html_empty = False
615 for change in line:
640 for change in line:
616 _html.append('''<tr class="%(lc)s %(action)s">\n''' % {
641 _html.append('''<tr class="%(lc)s %(action)s">\n''' % {
617 'lc': line_class,
642 'lc': line_class,
618 'action': change['action']
643 'action': change['action']
619 })
644 })
620 anchor_old_id = ''
645 anchor_old_id = ''
621 anchor_new_id = ''
646 anchor_new_id = ''
622 anchor_old = "%(filename)s_o%(oldline_no)s" % {
647 anchor_old = "%(filename)s_o%(oldline_no)s" % {
623 'filename': self._safe_id(diff['filename']),
648 'filename': self._safe_id(diff['filename']),
624 'oldline_no': change['old_lineno']
649 'oldline_no': change['old_lineno']
625 }
650 }
626 anchor_new = "%(filename)s_n%(oldline_no)s" % {
651 anchor_new = "%(filename)s_n%(oldline_no)s" % {
627 'filename': self._safe_id(diff['filename']),
652 'filename': self._safe_id(diff['filename']),
628 'oldline_no': change['new_lineno']
653 'oldline_no': change['new_lineno']
629 }
654 }
630 cond_old = (change['old_lineno'] != '...' and
655 cond_old = (change['old_lineno'] != '...' and
631 change['old_lineno'])
656 change['old_lineno'])
632 cond_new = (change['new_lineno'] != '...' and
657 cond_new = (change['new_lineno'] != '...' and
633 change['new_lineno'])
658 change['new_lineno'])
634 if cond_old:
659 if cond_old:
635 anchor_old_id = 'id="%s"' % anchor_old
660 anchor_old_id = 'id="%s"' % anchor_old
636 if cond_new:
661 if cond_new:
637 anchor_new_id = 'id="%s"' % anchor_new
662 anchor_new_id = 'id="%s"' % anchor_new
638 ###########################################################
663 ###########################################################
639 # OLD LINE NUMBER
664 # OLD LINE NUMBER
640 ###########################################################
665 ###########################################################
641 _html.append('''\t<td %(a_id)s class="%(olc)s">''' % {
666 _html.append('''\t<td %(a_id)s class="%(olc)s">''' % {
642 'a_id': anchor_old_id,
667 'a_id': anchor_old_id,
643 'olc': old_lineno_class
668 'olc': old_lineno_class
644 })
669 })
645
670
646 _html.append('''%(link)s''' % {
671 _html.append('''%(link)s''' % {
647 'link': _link_to_if(True, change['old_lineno'],
672 'link': _link_to_if(True, change['old_lineno'],
648 '#%s' % anchor_old)
673 '#%s' % anchor_old)
649 })
674 })
650 _html.append('''</td>\n''')
675 _html.append('''</td>\n''')
651 ###########################################################
676 ###########################################################
652 # NEW LINE NUMBER
677 # NEW LINE NUMBER
653 ###########################################################
678 ###########################################################
654
679
655 _html.append('''\t<td %(a_id)s class="%(nlc)s">''' % {
680 _html.append('''\t<td %(a_id)s class="%(nlc)s">''' % {
656 'a_id': anchor_new_id,
681 'a_id': anchor_new_id,
657 'nlc': new_lineno_class
682 'nlc': new_lineno_class
658 })
683 })
659
684
660 _html.append('''%(link)s''' % {
685 _html.append('''%(link)s''' % {
661 'link': _link_to_if(True, change['new_lineno'],
686 'link': _link_to_if(True, change['new_lineno'],
662 '#%s' % anchor_new)
687 '#%s' % anchor_new)
663 })
688 })
664 _html.append('''</td>\n''')
689 _html.append('''</td>\n''')
665 ###########################################################
690 ###########################################################
666 # CODE
691 # CODE
667 ###########################################################
692 ###########################################################
668 comments = '' if enable_comments else 'no-comment'
693 comments = '' if enable_comments else 'no-comment'
669 _html.append('''\t<td class="%(cc)s %(inc)s">''' % {
694 _html.append('''\t<td class="%(cc)s %(inc)s">''' % {
670 'cc': code_class,
695 'cc': code_class,
671 'inc': comments
696 'inc': comments
672 })
697 })
673 _html.append('''\n\t\t<pre>%(code)s</pre>\n''' % {
698 _html.append('''\n\t\t<pre>%(code)s</pre>\n''' % {
674 'code': change['line']
699 'code': change['line']
675 })
700 })
676
701
677 _html.append('''\t</td>''')
702 _html.append('''\t</td>''')
678 _html.append('''\n</tr>\n''')
703 _html.append('''\n</tr>\n''')
679 _html.append('''</table>''')
704 _html.append('''</table>''')
680 if _html_empty:
705 if _html_empty:
681 return None
706 return None
682 return ''.join(_html)
707 return ''.join(_html)
683
708
684 def stat(self):
709 def stat(self):
685 """
710 """
686 Returns tuple of added, and removed lines for this instance
711 Returns tuple of added, and removed lines for this instance
687 """
712 """
688 return self.adds, self.removes
713 return self.adds, self.removes
@@ -1,1343 +1,1371 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 import StringIO
8 import StringIO
9 import urllib
9 import urllib
10 import math
10 import math
11 import logging
11 import logging
12 import re
12 import re
13 import urlparse
13 import urlparse
14 import textwrap
14 import textwrap
15
15
16 from datetime import datetime
16 from datetime import datetime
17 from pygments.formatters.html import HtmlFormatter
17 from pygments.formatters.html import HtmlFormatter
18 from pygments import highlight as code_highlight
18 from pygments import highlight as code_highlight
19 from pylons import url, request, config
19 from pylons import url, request, config
20 from pylons.i18n.translation import _, ungettext
20 from pylons.i18n.translation import _, ungettext
21 from hashlib import md5
21 from hashlib import md5
22
22
23 from webhelpers.html import literal, HTML, escape
23 from webhelpers.html import literal, HTML, escape
24 from webhelpers.html.tools import *
24 from webhelpers.html.tools import *
25 from webhelpers.html.builder import make_tag
25 from webhelpers.html.builder import make_tag
26 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
26 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
27 end_form, file, form, hidden, image, javascript_link, link_to, \
27 end_form, file, form, hidden, image, javascript_link, link_to, \
28 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
28 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
29 submit, text, password, textarea, title, ul, xml_declaration, radio
29 submit, text, password, textarea, title, ul, xml_declaration, radio
30 from webhelpers.html.tools import auto_link, button_to, highlight, \
30 from webhelpers.html.tools import auto_link, button_to, highlight, \
31 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
31 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
32 from webhelpers.number import format_byte_size, format_bit_size
32 from webhelpers.number import format_byte_size, format_bit_size
33 from webhelpers.pylonslib import Flash as _Flash
33 from webhelpers.pylonslib import Flash as _Flash
34 from webhelpers.pylonslib.secure_form import secure_form
34 from webhelpers.pylonslib.secure_form import secure_form
35 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
35 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
36 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
36 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
37 replace_whitespace, urlify, truncate, wrap_paragraphs
37 replace_whitespace, urlify, truncate, wrap_paragraphs
38 from webhelpers.date import time_ago_in_words
38 from webhelpers.date import time_ago_in_words
39 from webhelpers.paginate import Page as _Page
39 from webhelpers.paginate import Page as _Page
40 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
40 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
41 convert_boolean_attrs, NotGiven, _make_safe_id_component
41 convert_boolean_attrs, NotGiven, _make_safe_id_component
42
42
43 from rhodecode.lib.annotate import annotate_highlight
43 from rhodecode.lib.annotate import annotate_highlight
44 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
44 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
45 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
45 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
46 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict,\
46 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict,\
47 safe_int
47 safe_int
48 from rhodecode.lib.markup_renderer import MarkupRenderer
48 from rhodecode.lib.markup_renderer import MarkupRenderer
49 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
49 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
50 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
50 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
51 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
51 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
52 from rhodecode.model.changeset_status import ChangesetStatusModel
52 from rhodecode.model.changeset_status import ChangesetStatusModel
53 from rhodecode.model.db import URL_SEP, Permission
53 from rhodecode.model.db import URL_SEP, Permission
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 html_escape_table = {
58 html_escape_table = {
59 "&": "&amp;",
59 "&": "&amp;",
60 '"': "&quot;",
60 '"': "&quot;",
61 "'": "&apos;",
61 "'": "&apos;",
62 ">": "&gt;",
62 ">": "&gt;",
63 "<": "&lt;",
63 "<": "&lt;",
64 }
64 }
65
65
66
66
67 def html_escape(text):
67 def html_escape(text):
68 """Produce entities within text."""
68 """Produce entities within text."""
69 return "".join(html_escape_table.get(c, c) for c in text)
69 return "".join(html_escape_table.get(c, c) for c in text)
70
70
71
71
72 def shorter(text, size=20):
72 def shorter(text, size=20):
73 postfix = '...'
73 postfix = '...'
74 if len(text) > size:
74 if len(text) > size:
75 return text[:size - len(postfix)] + postfix
75 return text[:size - len(postfix)] + postfix
76 return text
76 return text
77
77
78
78
79 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
79 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
80 """
80 """
81 Reset button
81 Reset button
82 """
82 """
83 _set_input_attrs(attrs, type, name, value)
83 _set_input_attrs(attrs, type, name, value)
84 _set_id_attr(attrs, id, name)
84 _set_id_attr(attrs, id, name)
85 convert_boolean_attrs(attrs, ["disabled"])
85 convert_boolean_attrs(attrs, ["disabled"])
86 return HTML.input(**attrs)
86 return HTML.input(**attrs)
87
87
88 reset = _reset
88 reset = _reset
89 safeid = _make_safe_id_component
89 safeid = _make_safe_id_component
90
90
91
91
92 def FID(raw_id, path):
92 def FID(raw_id, path):
93 """
93 """
94 Creates a uniqe ID for filenode based on it's hash of path and revision
94 Creates a uniqe ID for filenode based on it's hash of path and revision
95 it's safe to use in urls
95 it's safe to use in urls
96
96
97 :param raw_id:
97 :param raw_id:
98 :param path:
98 :param path:
99 """
99 """
100
100
101 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
101 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
102
102
103
103
104 def get_token():
104 def get_token():
105 """Return the current authentication token, creating one if one doesn't
105 """Return the current authentication token, creating one if one doesn't
106 already exist.
106 already exist.
107 """
107 """
108 token_key = "_authentication_token"
108 token_key = "_authentication_token"
109 from pylons import session
109 from pylons import session
110 if not token_key in session:
110 if not token_key in session:
111 try:
111 try:
112 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
112 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
113 except AttributeError: # Python < 2.4
113 except AttributeError: # Python < 2.4
114 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
114 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
115 session[token_key] = token
115 session[token_key] = token
116 if hasattr(session, 'save'):
116 if hasattr(session, 'save'):
117 session.save()
117 session.save()
118 return session[token_key]
118 return session[token_key]
119
119
120
120
121 class _GetError(object):
121 class _GetError(object):
122 """Get error from form_errors, and represent it as span wrapped error
122 """Get error from form_errors, and represent it as span wrapped error
123 message
123 message
124
124
125 :param field_name: field to fetch errors for
125 :param field_name: field to fetch errors for
126 :param form_errors: form errors dict
126 :param form_errors: form errors dict
127 """
127 """
128
128
129 def __call__(self, field_name, form_errors):
129 def __call__(self, field_name, form_errors):
130 tmpl = """<span class="error_msg">%s</span>"""
130 tmpl = """<span class="error_msg">%s</span>"""
131 if form_errors and field_name in form_errors:
131 if form_errors and field_name in form_errors:
132 return literal(tmpl % form_errors.get(field_name))
132 return literal(tmpl % form_errors.get(field_name))
133
133
134 get_error = _GetError()
134 get_error = _GetError()
135
135
136
136
137 class _ToolTip(object):
137 class _ToolTip(object):
138
138
139 def __call__(self, tooltip_title, trim_at=50):
139 def __call__(self, tooltip_title, trim_at=50):
140 """
140 """
141 Special function just to wrap our text into nice formatted
141 Special function just to wrap our text into nice formatted
142 autowrapped text
142 autowrapped text
143
143
144 :param tooltip_title:
144 :param tooltip_title:
145 """
145 """
146 tooltip_title = escape(tooltip_title)
146 tooltip_title = escape(tooltip_title)
147 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
147 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
148 return tooltip_title
148 return tooltip_title
149 tooltip = _ToolTip()
149 tooltip = _ToolTip()
150
150
151
151
152 class _FilesBreadCrumbs(object):
152 class _FilesBreadCrumbs(object):
153
153
154 def __call__(self, repo_name, rev, paths):
154 def __call__(self, repo_name, rev, paths):
155 if isinstance(paths, str):
155 if isinstance(paths, str):
156 paths = safe_unicode(paths)
156 paths = safe_unicode(paths)
157 url_l = [link_to(repo_name, url('files_home',
157 url_l = [link_to(repo_name, url('files_home',
158 repo_name=repo_name,
158 repo_name=repo_name,
159 revision=rev, f_path=''),
159 revision=rev, f_path=''),
160 class_='ypjax-link')]
160 class_='ypjax-link')]
161 paths_l = paths.split('/')
161 paths_l = paths.split('/')
162 for cnt, p in enumerate(paths_l):
162 for cnt, p in enumerate(paths_l):
163 if p != '':
163 if p != '':
164 url_l.append(link_to(p,
164 url_l.append(link_to(p,
165 url('files_home',
165 url('files_home',
166 repo_name=repo_name,
166 repo_name=repo_name,
167 revision=rev,
167 revision=rev,
168 f_path='/'.join(paths_l[:cnt + 1])
168 f_path='/'.join(paths_l[:cnt + 1])
169 ),
169 ),
170 class_='ypjax-link'
170 class_='ypjax-link'
171 )
171 )
172 )
172 )
173
173
174 return literal('/'.join(url_l))
174 return literal('/'.join(url_l))
175
175
176 files_breadcrumbs = _FilesBreadCrumbs()
176 files_breadcrumbs = _FilesBreadCrumbs()
177
177
178
178
179 class CodeHtmlFormatter(HtmlFormatter):
179 class CodeHtmlFormatter(HtmlFormatter):
180 """
180 """
181 My code Html Formatter for source codes
181 My code Html Formatter for source codes
182 """
182 """
183
183
184 def wrap(self, source, outfile):
184 def wrap(self, source, outfile):
185 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
185 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
186
186
187 def _wrap_code(self, source):
187 def _wrap_code(self, source):
188 for cnt, it in enumerate(source):
188 for cnt, it in enumerate(source):
189 i, t = it
189 i, t = it
190 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
190 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
191 yield i, t
191 yield i, t
192
192
193 def _wrap_tablelinenos(self, inner):
193 def _wrap_tablelinenos(self, inner):
194 dummyoutfile = StringIO.StringIO()
194 dummyoutfile = StringIO.StringIO()
195 lncount = 0
195 lncount = 0
196 for t, line in inner:
196 for t, line in inner:
197 if t:
197 if t:
198 lncount += 1
198 lncount += 1
199 dummyoutfile.write(line)
199 dummyoutfile.write(line)
200
200
201 fl = self.linenostart
201 fl = self.linenostart
202 mw = len(str(lncount + fl - 1))
202 mw = len(str(lncount + fl - 1))
203 sp = self.linenospecial
203 sp = self.linenospecial
204 st = self.linenostep
204 st = self.linenostep
205 la = self.lineanchors
205 la = self.lineanchors
206 aln = self.anchorlinenos
206 aln = self.anchorlinenos
207 nocls = self.noclasses
207 nocls = self.noclasses
208 if sp:
208 if sp:
209 lines = []
209 lines = []
210
210
211 for i in range(fl, fl + lncount):
211 for i in range(fl, fl + lncount):
212 if i % st == 0:
212 if i % st == 0:
213 if i % sp == 0:
213 if i % sp == 0:
214 if aln:
214 if aln:
215 lines.append('<a href="#%s%d" class="special">%*d</a>' %
215 lines.append('<a href="#%s%d" class="special">%*d</a>' %
216 (la, i, mw, i))
216 (la, i, mw, i))
217 else:
217 else:
218 lines.append('<span class="special">%*d</span>' % (mw, i))
218 lines.append('<span class="special">%*d</span>' % (mw, i))
219 else:
219 else:
220 if aln:
220 if aln:
221 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
221 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
222 else:
222 else:
223 lines.append('%*d' % (mw, i))
223 lines.append('%*d' % (mw, i))
224 else:
224 else:
225 lines.append('')
225 lines.append('')
226 ls = '\n'.join(lines)
226 ls = '\n'.join(lines)
227 else:
227 else:
228 lines = []
228 lines = []
229 for i in range(fl, fl + lncount):
229 for i in range(fl, fl + lncount):
230 if i % st == 0:
230 if i % st == 0:
231 if aln:
231 if aln:
232 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
232 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
233 else:
233 else:
234 lines.append('%*d' % (mw, i))
234 lines.append('%*d' % (mw, i))
235 else:
235 else:
236 lines.append('')
236 lines.append('')
237 ls = '\n'.join(lines)
237 ls = '\n'.join(lines)
238
238
239 # in case you wonder about the seemingly redundant <div> here: since the
239 # in case you wonder about the seemingly redundant <div> here: since the
240 # content in the other cell also is wrapped in a div, some browsers in
240 # content in the other cell also is wrapped in a div, some browsers in
241 # some configurations seem to mess up the formatting...
241 # some configurations seem to mess up the formatting...
242 if nocls:
242 if nocls:
243 yield 0, ('<table class="%stable">' % self.cssclass +
243 yield 0, ('<table class="%stable">' % self.cssclass +
244 '<tr><td><div class="linenodiv" '
244 '<tr><td><div class="linenodiv" '
245 'style="background-color: #f0f0f0; padding-right: 10px">'
245 'style="background-color: #f0f0f0; padding-right: 10px">'
246 '<pre style="line-height: 125%">' +
246 '<pre style="line-height: 125%">' +
247 ls + '</pre></div></td><td id="hlcode" class="code">')
247 ls + '</pre></div></td><td id="hlcode" class="code">')
248 else:
248 else:
249 yield 0, ('<table class="%stable">' % self.cssclass +
249 yield 0, ('<table class="%stable">' % self.cssclass +
250 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
250 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
251 ls + '</pre></div></td><td id="hlcode" class="code">')
251 ls + '</pre></div></td><td id="hlcode" class="code">')
252 yield 0, dummyoutfile.getvalue()
252 yield 0, dummyoutfile.getvalue()
253 yield 0, '</td></tr></table>'
253 yield 0, '</td></tr></table>'
254
254
255
255
256 def pygmentize(filenode, **kwargs):
256 def pygmentize(filenode, **kwargs):
257 """
257 """
258 pygmentize function using pygments
258 pygmentize function using pygments
259
259
260 :param filenode:
260 :param filenode:
261 """
261 """
262 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
262 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
263 return literal(code_highlight(filenode.content, lexer,
263 return literal(code_highlight(filenode.content, lexer,
264 CodeHtmlFormatter(**kwargs)))
264 CodeHtmlFormatter(**kwargs)))
265
265
266
266
267 def pygmentize_annotation(repo_name, filenode, **kwargs):
267 def pygmentize_annotation(repo_name, filenode, **kwargs):
268 """
268 """
269 pygmentize function for annotation
269 pygmentize function for annotation
270
270
271 :param filenode:
271 :param filenode:
272 """
272 """
273
273
274 color_dict = {}
274 color_dict = {}
275
275
276 def gen_color(n=10000):
276 def gen_color(n=10000):
277 """generator for getting n of evenly distributed colors using
277 """generator for getting n of evenly distributed colors using
278 hsv color and golden ratio. It always return same order of colors
278 hsv color and golden ratio. It always return same order of colors
279
279
280 :returns: RGB tuple
280 :returns: RGB tuple
281 """
281 """
282
282
283 def hsv_to_rgb(h, s, v):
283 def hsv_to_rgb(h, s, v):
284 if s == 0.0:
284 if s == 0.0:
285 return v, v, v
285 return v, v, v
286 i = int(h * 6.0) # XXX assume int() truncates!
286 i = int(h * 6.0) # XXX assume int() truncates!
287 f = (h * 6.0) - i
287 f = (h * 6.0) - i
288 p = v * (1.0 - s)
288 p = v * (1.0 - s)
289 q = v * (1.0 - s * f)
289 q = v * (1.0 - s * f)
290 t = v * (1.0 - s * (1.0 - f))
290 t = v * (1.0 - s * (1.0 - f))
291 i = i % 6
291 i = i % 6
292 if i == 0:
292 if i == 0:
293 return v, t, p
293 return v, t, p
294 if i == 1:
294 if i == 1:
295 return q, v, p
295 return q, v, p
296 if i == 2:
296 if i == 2:
297 return p, v, t
297 return p, v, t
298 if i == 3:
298 if i == 3:
299 return p, q, v
299 return p, q, v
300 if i == 4:
300 if i == 4:
301 return t, p, v
301 return t, p, v
302 if i == 5:
302 if i == 5:
303 return v, p, q
303 return v, p, q
304
304
305 golden_ratio = 0.618033988749895
305 golden_ratio = 0.618033988749895
306 h = 0.22717784590367374
306 h = 0.22717784590367374
307
307
308 for _ in xrange(n):
308 for _ in xrange(n):
309 h += golden_ratio
309 h += golden_ratio
310 h %= 1
310 h %= 1
311 HSV_tuple = [h, 0.95, 0.95]
311 HSV_tuple = [h, 0.95, 0.95]
312 RGB_tuple = hsv_to_rgb(*HSV_tuple)
312 RGB_tuple = hsv_to_rgb(*HSV_tuple)
313 yield map(lambda x: str(int(x * 256)), RGB_tuple)
313 yield map(lambda x: str(int(x * 256)), RGB_tuple)
314
314
315 cgenerator = gen_color()
315 cgenerator = gen_color()
316
316
317 def get_color_string(cs):
317 def get_color_string(cs):
318 if cs in color_dict:
318 if cs in color_dict:
319 col = color_dict[cs]
319 col = color_dict[cs]
320 else:
320 else:
321 col = color_dict[cs] = cgenerator.next()
321 col = color_dict[cs] = cgenerator.next()
322 return "color: rgb(%s)! important;" % (', '.join(col))
322 return "color: rgb(%s)! important;" % (', '.join(col))
323
323
324 def url_func(repo_name):
324 def url_func(repo_name):
325
325
326 def _url_func(changeset):
326 def _url_func(changeset):
327 author = changeset.author
327 author = changeset.author
328 date = changeset.date
328 date = changeset.date
329 message = tooltip(changeset.message)
329 message = tooltip(changeset.message)
330
330
331 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
331 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
332 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
332 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
333 "</b> %s<br/></div>")
333 "</b> %s<br/></div>")
334
334
335 tooltip_html = tooltip_html % (author, date, message)
335 tooltip_html = tooltip_html % (author, date, message)
336 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
336 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
337 short_id(changeset.raw_id))
337 short_id(changeset.raw_id))
338 uri = link_to(
338 uri = link_to(
339 lnk_format,
339 lnk_format,
340 url('changeset_home', repo_name=repo_name,
340 url('changeset_home', repo_name=repo_name,
341 revision=changeset.raw_id),
341 revision=changeset.raw_id),
342 style=get_color_string(changeset.raw_id),
342 style=get_color_string(changeset.raw_id),
343 class_='tooltip',
343 class_='tooltip',
344 title=tooltip_html
344 title=tooltip_html
345 )
345 )
346
346
347 uri += '\n'
347 uri += '\n'
348 return uri
348 return uri
349 return _url_func
349 return _url_func
350
350
351 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
351 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
352
352
353
353
354 def is_following_repo(repo_name, user_id):
354 def is_following_repo(repo_name, user_id):
355 from rhodecode.model.scm import ScmModel
355 from rhodecode.model.scm import ScmModel
356 return ScmModel().is_following_repo(repo_name, user_id)
356 return ScmModel().is_following_repo(repo_name, user_id)
357
357
358 flash = _Flash()
358 flash = _Flash()
359
359
360 #==============================================================================
360 #==============================================================================
361 # SCM FILTERS available via h.
361 # SCM FILTERS available via h.
362 #==============================================================================
362 #==============================================================================
363 from rhodecode.lib.vcs.utils import author_name, author_email
363 from rhodecode.lib.vcs.utils import author_name, author_email
364 from rhodecode.lib.utils2 import credentials_filter, age as _age
364 from rhodecode.lib.utils2 import credentials_filter, age as _age
365 from rhodecode.model.db import User, ChangesetStatus
365 from rhodecode.model.db import User, ChangesetStatus
366
366
367 age = lambda x, y=False: _age(x, y)
367 age = lambda x, y=False: _age(x, y)
368 capitalize = lambda x: x.capitalize()
368 capitalize = lambda x: x.capitalize()
369 email = author_email
369 email = author_email
370 short_id = lambda x: x[:12]
370 short_id = lambda x: x[:12]
371 hide_credentials = lambda x: ''.join(credentials_filter(x))
371 hide_credentials = lambda x: ''.join(credentials_filter(x))
372
372
373
373
374 def show_id(cs):
374 def show_id(cs):
375 """
375 """
376 Configurable function that shows ID
376 Configurable function that shows ID
377 by default it's r123:fffeeefffeee
377 by default it's r123:fffeeefffeee
378
378
379 :param cs: changeset instance
379 :param cs: changeset instance
380 """
380 """
381 from rhodecode import CONFIG
381 from rhodecode import CONFIG
382 def_len = safe_int(CONFIG.get('show_sha_length', 12))
382 def_len = safe_int(CONFIG.get('show_sha_length', 12))
383 show_rev = str2bool(CONFIG.get('show_revision_number', True))
383 show_rev = str2bool(CONFIG.get('show_revision_number', True))
384
384
385 raw_id = cs.raw_id[:def_len]
385 raw_id = cs.raw_id[:def_len]
386 if show_rev:
386 if show_rev:
387 return 'r%s:%s' % (cs.revision, raw_id)
387 return 'r%s:%s' % (cs.revision, raw_id)
388 else:
388 else:
389 return '%s' % (raw_id)
389 return '%s' % (raw_id)
390
390
391
391
392 def fmt_date(date):
392 def fmt_date(date):
393 if date:
393 if date:
394 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
394 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
395 return date.strftime(_fmt).decode('utf8')
395 return date.strftime(_fmt).decode('utf8')
396
396
397 return ""
397 return ""
398
398
399
399
400 def is_git(repository):
400 def is_git(repository):
401 if hasattr(repository, 'alias'):
401 if hasattr(repository, 'alias'):
402 _type = repository.alias
402 _type = repository.alias
403 elif hasattr(repository, 'repo_type'):
403 elif hasattr(repository, 'repo_type'):
404 _type = repository.repo_type
404 _type = repository.repo_type
405 else:
405 else:
406 _type = repository
406 _type = repository
407 return _type == 'git'
407 return _type == 'git'
408
408
409
409
410 def is_hg(repository):
410 def is_hg(repository):
411 if hasattr(repository, 'alias'):
411 if hasattr(repository, 'alias'):
412 _type = repository.alias
412 _type = repository.alias
413 elif hasattr(repository, 'repo_type'):
413 elif hasattr(repository, 'repo_type'):
414 _type = repository.repo_type
414 _type = repository.repo_type
415 else:
415 else:
416 _type = repository
416 _type = repository
417 return _type == 'hg'
417 return _type == 'hg'
418
418
419
419
420 def email_or_none(author):
420 def email_or_none(author):
421 # extract email from the commit string
421 # extract email from the commit string
422 _email = email(author)
422 _email = email(author)
423 if _email != '':
423 if _email != '':
424 # check it against RhodeCode database, and use the MAIN email for this
424 # check it against RhodeCode database, and use the MAIN email for this
425 # user
425 # user
426 user = User.get_by_email(_email, case_insensitive=True, cache=True)
426 user = User.get_by_email(_email, case_insensitive=True, cache=True)
427 if user is not None:
427 if user is not None:
428 return user.email
428 return user.email
429 return _email
429 return _email
430
430
431 # See if it contains a username we can get an email from
431 # See if it contains a username we can get an email from
432 user = User.get_by_username(author_name(author), case_insensitive=True,
432 user = User.get_by_username(author_name(author), case_insensitive=True,
433 cache=True)
433 cache=True)
434 if user is not None:
434 if user is not None:
435 return user.email
435 return user.email
436
436
437 # No valid email, not a valid user in the system, none!
437 # No valid email, not a valid user in the system, none!
438 return None
438 return None
439
439
440
440
441 def person(author, show_attr="username_and_name"):
441 def person(author, show_attr="username_and_name"):
442 # attr to return from fetched user
442 # attr to return from fetched user
443 person_getter = lambda usr: getattr(usr, show_attr)
443 person_getter = lambda usr: getattr(usr, show_attr)
444
444
445 # Valid email in the attribute passed, see if they're in the system
445 # Valid email in the attribute passed, see if they're in the system
446 _email = email(author)
446 _email = email(author)
447 if _email != '':
447 if _email != '':
448 user = User.get_by_email(_email, case_insensitive=True, cache=True)
448 user = User.get_by_email(_email, case_insensitive=True, cache=True)
449 if user is not None:
449 if user is not None:
450 return person_getter(user)
450 return person_getter(user)
451
451
452 # Maybe it's a username?
452 # Maybe it's a username?
453 _author = author_name(author)
453 _author = author_name(author)
454 user = User.get_by_username(_author, case_insensitive=True,
454 user = User.get_by_username(_author, case_insensitive=True,
455 cache=True)
455 cache=True)
456 if user is not None:
456 if user is not None:
457 return person_getter(user)
457 return person_getter(user)
458
458
459 # Still nothing? Just pass back the author name if any, else the email
459 # Still nothing? Just pass back the author name if any, else the email
460 return _author or _email
460 return _author or _email
461
461
462
462
463 def person_by_id(id_, show_attr="username_and_name"):
463 def person_by_id(id_, show_attr="username_and_name"):
464 # attr to return from fetched user
464 # attr to return from fetched user
465 person_getter = lambda usr: getattr(usr, show_attr)
465 person_getter = lambda usr: getattr(usr, show_attr)
466
466
467 #maybe it's an ID ?
467 #maybe it's an ID ?
468 if str(id_).isdigit() or isinstance(id_, int):
468 if str(id_).isdigit() or isinstance(id_, int):
469 id_ = int(id_)
469 id_ = int(id_)
470 user = User.get(id_)
470 user = User.get(id_)
471 if user is not None:
471 if user is not None:
472 return person_getter(user)
472 return person_getter(user)
473 return id_
473 return id_
474
474
475
475
476 def desc_stylize(value):
476 def desc_stylize(value):
477 """
477 """
478 converts tags from value into html equivalent
478 converts tags from value into html equivalent
479
479
480 :param value:
480 :param value:
481 """
481 """
482 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
482 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
483 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
483 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
484 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
484 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
485 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
485 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
486 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
486 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
487 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
487 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
488 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
488 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
489 '<div class="metatag" tag="lang">\\2</div>', value)
489 '<div class="metatag" tag="lang">\\2</div>', value)
490 value = re.sub(r'\[([a-z]+)\]',
490 value = re.sub(r'\[([a-z]+)\]',
491 '<div class="metatag" tag="\\1">\\1</div>', value)
491 '<div class="metatag" tag="\\1">\\1</div>', value)
492
492
493 return value
493 return value
494
494
495
495
496 def boolicon(value):
496 def boolicon(value):
497 """Returns boolean value of a value, represented as small html image of true/false
497 """Returns boolean value of a value, represented as small html image of true/false
498 icons
498 icons
499
499
500 :param value: value
500 :param value: value
501 """
501 """
502
502
503 if value:
503 if value:
504 return HTML.tag('img', src=url("/images/icons/accept.png"),
504 return HTML.tag('img', src=url("/images/icons/accept.png"),
505 alt=_('True'))
505 alt=_('True'))
506 else:
506 else:
507 return HTML.tag('img', src=url("/images/icons/cancel.png"),
507 return HTML.tag('img', src=url("/images/icons/cancel.png"),
508 alt=_('False'))
508 alt=_('False'))
509
509
510
510
511 def action_parser(user_log, feed=False, parse_cs=False):
511 def action_parser(user_log, feed=False, parse_cs=False):
512 """
512 """
513 This helper will action_map the specified string action into translated
513 This helper will action_map the specified string action into translated
514 fancy names with icons and links
514 fancy names with icons and links
515
515
516 :param user_log: user log instance
516 :param user_log: user log instance
517 :param feed: use output for feeds (no html and fancy icons)
517 :param feed: use output for feeds (no html and fancy icons)
518 :param parse_cs: parse Changesets into VCS instances
518 :param parse_cs: parse Changesets into VCS instances
519 """
519 """
520
520
521 action = user_log.action
521 action = user_log.action
522 action_params = ' '
522 action_params = ' '
523
523
524 x = action.split(':')
524 x = action.split(':')
525
525
526 if len(x) > 1:
526 if len(x) > 1:
527 action, action_params = x
527 action, action_params = x
528
528
529 def get_cs_links():
529 def get_cs_links():
530 revs_limit = 3 # display this amount always
530 revs_limit = 3 # display this amount always
531 revs_top_limit = 50 # show upto this amount of changesets hidden
531 revs_top_limit = 50 # show upto this amount of changesets hidden
532 revs_ids = action_params.split(',')
532 revs_ids = action_params.split(',')
533 deleted = user_log.repository is None
533 deleted = user_log.repository is None
534 if deleted:
534 if deleted:
535 return ','.join(revs_ids)
535 return ','.join(revs_ids)
536
536
537 repo_name = user_log.repository.repo_name
537 repo_name = user_log.repository.repo_name
538
538
539 def lnk(rev, repo_name):
539 def lnk(rev, repo_name):
540 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
540 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
541 lazy_cs = True
541 lazy_cs = True
542 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
542 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
543 lazy_cs = False
543 lazy_cs = False
544 lbl = '?'
544 lbl = '?'
545 if rev.op == 'delete_branch':
545 if rev.op == 'delete_branch':
546 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
546 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
547 title = ''
547 title = ''
548 elif rev.op == 'tag':
548 elif rev.op == 'tag':
549 lbl = '%s' % _('Created tag: %s') % rev.ref_name
549 lbl = '%s' % _('Created tag: %s') % rev.ref_name
550 title = ''
550 title = ''
551 _url = '#'
551 _url = '#'
552
552
553 else:
553 else:
554 lbl = '%s' % (rev.short_id[:8])
554 lbl = '%s' % (rev.short_id[:8])
555 _url = url('changeset_home', repo_name=repo_name,
555 _url = url('changeset_home', repo_name=repo_name,
556 revision=rev.raw_id)
556 revision=rev.raw_id)
557 title = tooltip(rev.message)
557 title = tooltip(rev.message)
558 else:
558 else:
559 ## changeset cannot be found/striped/removed etc.
559 ## changeset cannot be found/striped/removed etc.
560 lbl = ('%s' % rev)[:12]
560 lbl = ('%s' % rev)[:12]
561 _url = '#'
561 _url = '#'
562 title = _('Changeset not found')
562 title = _('Changeset not found')
563 if parse_cs:
563 if parse_cs:
564 return link_to(lbl, _url, title=title, class_='tooltip')
564 return link_to(lbl, _url, title=title, class_='tooltip')
565 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
565 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
566 class_='lazy-cs' if lazy_cs else '')
566 class_='lazy-cs' if lazy_cs else '')
567
567
568 def _get_op(rev_txt):
568 def _get_op(rev_txt):
569 _op = None
569 _op = None
570 _name = rev_txt
570 _name = rev_txt
571 if len(rev_txt.split('=>')) == 2:
571 if len(rev_txt.split('=>')) == 2:
572 _op, _name = rev_txt.split('=>')
572 _op, _name = rev_txt.split('=>')
573 return _op, _name
573 return _op, _name
574
574
575 revs = []
575 revs = []
576 if len(filter(lambda v: v != '', revs_ids)) > 0:
576 if len(filter(lambda v: v != '', revs_ids)) > 0:
577 repo = None
577 repo = None
578 for rev in revs_ids[:revs_top_limit]:
578 for rev in revs_ids[:revs_top_limit]:
579 _op, _name = _get_op(rev)
579 _op, _name = _get_op(rev)
580
580
581 # we want parsed changesets, or new log store format is bad
581 # we want parsed changesets, or new log store format is bad
582 if parse_cs:
582 if parse_cs:
583 try:
583 try:
584 if repo is None:
584 if repo is None:
585 repo = user_log.repository.scm_instance
585 repo = user_log.repository.scm_instance
586 _rev = repo.get_changeset(rev)
586 _rev = repo.get_changeset(rev)
587 revs.append(_rev)
587 revs.append(_rev)
588 except ChangesetDoesNotExistError:
588 except ChangesetDoesNotExistError:
589 log.error('cannot find revision %s in this repo' % rev)
589 log.error('cannot find revision %s in this repo' % rev)
590 revs.append(rev)
590 revs.append(rev)
591 continue
591 continue
592 else:
592 else:
593 _rev = AttributeDict({
593 _rev = AttributeDict({
594 'short_id': rev[:12],
594 'short_id': rev[:12],
595 'raw_id': rev,
595 'raw_id': rev,
596 'message': '',
596 'message': '',
597 'op': _op,
597 'op': _op,
598 'ref_name': _name
598 'ref_name': _name
599 })
599 })
600 revs.append(_rev)
600 revs.append(_rev)
601 cs_links = []
601 cs_links = []
602 cs_links.append(" " + ', '.join(
602 cs_links.append(" " + ', '.join(
603 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
603 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
604 )
604 )
605 )
605 )
606 _op1, _name1 = _get_op(revs_ids[0])
606 _op1, _name1 = _get_op(revs_ids[0])
607 _op2, _name2 = _get_op(revs_ids[-1])
607 _op2, _name2 = _get_op(revs_ids[-1])
608
608
609 _rev = '%s...%s' % (_name1, _name2)
609 _rev = '%s...%s' % (_name1, _name2)
610
610
611 compare_view = (
611 compare_view = (
612 ' <div class="compare_view tooltip" title="%s">'
612 ' <div class="compare_view tooltip" title="%s">'
613 '<a href="%s">%s</a> </div>' % (
613 '<a href="%s">%s</a> </div>' % (
614 _('Show all combined changesets %s->%s') % (
614 _('Show all combined changesets %s->%s') % (
615 revs_ids[0][:12], revs_ids[-1][:12]
615 revs_ids[0][:12], revs_ids[-1][:12]
616 ),
616 ),
617 url('changeset_home', repo_name=repo_name,
617 url('changeset_home', repo_name=repo_name,
618 revision=_rev
618 revision=_rev
619 ),
619 ),
620 _('compare view')
620 _('compare view')
621 )
621 )
622 )
622 )
623
623
624 # if we have exactly one more than normally displayed
624 # if we have exactly one more than normally displayed
625 # just display it, takes less space than displaying
625 # just display it, takes less space than displaying
626 # "and 1 more revisions"
626 # "and 1 more revisions"
627 if len(revs_ids) == revs_limit + 1:
627 if len(revs_ids) == revs_limit + 1:
628 rev = revs[revs_limit]
628 rev = revs[revs_limit]
629 cs_links.append(", " + lnk(rev, repo_name))
629 cs_links.append(", " + lnk(rev, repo_name))
630
630
631 # hidden-by-default ones
631 # hidden-by-default ones
632 if len(revs_ids) > revs_limit + 1:
632 if len(revs_ids) > revs_limit + 1:
633 uniq_id = revs_ids[0]
633 uniq_id = revs_ids[0]
634 html_tmpl = (
634 html_tmpl = (
635 '<span> %s <a class="show_more" id="_%s" '
635 '<span> %s <a class="show_more" id="_%s" '
636 'href="#more">%s</a> %s</span>'
636 'href="#more">%s</a> %s</span>'
637 )
637 )
638 if not feed:
638 if not feed:
639 cs_links.append(html_tmpl % (
639 cs_links.append(html_tmpl % (
640 _('and'),
640 _('and'),
641 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
641 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
642 _('revisions')
642 _('revisions')
643 )
643 )
644 )
644 )
645
645
646 if not feed:
646 if not feed:
647 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
647 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
648 else:
648 else:
649 html_tmpl = '<span id="%s"> %s </span>'
649 html_tmpl = '<span id="%s"> %s </span>'
650
650
651 morelinks = ', '.join(
651 morelinks = ', '.join(
652 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
652 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
653 )
653 )
654
654
655 if len(revs_ids) > revs_top_limit:
655 if len(revs_ids) > revs_top_limit:
656 morelinks += ', ...'
656 morelinks += ', ...'
657
657
658 cs_links.append(html_tmpl % (uniq_id, morelinks))
658 cs_links.append(html_tmpl % (uniq_id, morelinks))
659 if len(revs) > 1:
659 if len(revs) > 1:
660 cs_links.append(compare_view)
660 cs_links.append(compare_view)
661 return ''.join(cs_links)
661 return ''.join(cs_links)
662
662
663 def get_fork_name():
663 def get_fork_name():
664 repo_name = action_params
664 repo_name = action_params
665 _url = url('summary_home', repo_name=repo_name)
665 _url = url('summary_home', repo_name=repo_name)
666 return _('fork name %s') % link_to(action_params, _url)
666 return _('fork name %s') % link_to(action_params, _url)
667
667
668 def get_user_name():
668 def get_user_name():
669 user_name = action_params
669 user_name = action_params
670 return user_name
670 return user_name
671
671
672 def get_users_group():
672 def get_users_group():
673 group_name = action_params
673 group_name = action_params
674 return group_name
674 return group_name
675
675
676 def get_pull_request():
676 def get_pull_request():
677 pull_request_id = action_params
677 pull_request_id = action_params
678 deleted = user_log.repository is None
678 deleted = user_log.repository is None
679 if deleted:
679 if deleted:
680 repo_name = user_log.repository_name
680 repo_name = user_log.repository_name
681 else:
681 else:
682 repo_name = user_log.repository.repo_name
682 repo_name = user_log.repository.repo_name
683 return link_to(_('Pull request #%s') % pull_request_id,
683 return link_to(_('Pull request #%s') % pull_request_id,
684 url('pullrequest_show', repo_name=repo_name,
684 url('pullrequest_show', repo_name=repo_name,
685 pull_request_id=pull_request_id))
685 pull_request_id=pull_request_id))
686
686
687 # action : translated str, callback(extractor), icon
687 # action : translated str, callback(extractor), icon
688 action_map = {
688 action_map = {
689 'user_deleted_repo': (_('[deleted] repository'),
689 'user_deleted_repo': (_('[deleted] repository'),
690 None, 'database_delete.png'),
690 None, 'database_delete.png'),
691 'user_created_repo': (_('[created] repository'),
691 'user_created_repo': (_('[created] repository'),
692 None, 'database_add.png'),
692 None, 'database_add.png'),
693 'user_created_fork': (_('[created] repository as fork'),
693 'user_created_fork': (_('[created] repository as fork'),
694 None, 'arrow_divide.png'),
694 None, 'arrow_divide.png'),
695 'user_forked_repo': (_('[forked] repository'),
695 'user_forked_repo': (_('[forked] repository'),
696 get_fork_name, 'arrow_divide.png'),
696 get_fork_name, 'arrow_divide.png'),
697 'user_updated_repo': (_('[updated] repository'),
697 'user_updated_repo': (_('[updated] repository'),
698 None, 'database_edit.png'),
698 None, 'database_edit.png'),
699 'admin_deleted_repo': (_('[delete] repository'),
699 'admin_deleted_repo': (_('[delete] repository'),
700 None, 'database_delete.png'),
700 None, 'database_delete.png'),
701 'admin_created_repo': (_('[created] repository'),
701 'admin_created_repo': (_('[created] repository'),
702 None, 'database_add.png'),
702 None, 'database_add.png'),
703 'admin_forked_repo': (_('[forked] repository'),
703 'admin_forked_repo': (_('[forked] repository'),
704 None, 'arrow_divide.png'),
704 None, 'arrow_divide.png'),
705 'admin_updated_repo': (_('[updated] repository'),
705 'admin_updated_repo': (_('[updated] repository'),
706 None, 'database_edit.png'),
706 None, 'database_edit.png'),
707 'admin_created_user': (_('[created] user'),
707 'admin_created_user': (_('[created] user'),
708 get_user_name, 'user_add.png'),
708 get_user_name, 'user_add.png'),
709 'admin_updated_user': (_('[updated] user'),
709 'admin_updated_user': (_('[updated] user'),
710 get_user_name, 'user_edit.png'),
710 get_user_name, 'user_edit.png'),
711 'admin_created_users_group': (_('[created] user group'),
711 'admin_created_users_group': (_('[created] user group'),
712 get_users_group, 'group_add.png'),
712 get_users_group, 'group_add.png'),
713 'admin_updated_users_group': (_('[updated] user group'),
713 'admin_updated_users_group': (_('[updated] user group'),
714 get_users_group, 'group_edit.png'),
714 get_users_group, 'group_edit.png'),
715 'user_commented_revision': (_('[commented] on revision in repository'),
715 'user_commented_revision': (_('[commented] on revision in repository'),
716 get_cs_links, 'comment_add.png'),
716 get_cs_links, 'comment_add.png'),
717 'user_commented_pull_request': (_('[commented] on pull request for'),
717 'user_commented_pull_request': (_('[commented] on pull request for'),
718 get_pull_request, 'comment_add.png'),
718 get_pull_request, 'comment_add.png'),
719 'user_closed_pull_request': (_('[closed] pull request for'),
719 'user_closed_pull_request': (_('[closed] pull request for'),
720 get_pull_request, 'tick.png'),
720 get_pull_request, 'tick.png'),
721 'push': (_('[pushed] into'),
721 'push': (_('[pushed] into'),
722 get_cs_links, 'script_add.png'),
722 get_cs_links, 'script_add.png'),
723 'push_local': (_('[committed via RhodeCode] into repository'),
723 'push_local': (_('[committed via RhodeCode] into repository'),
724 get_cs_links, 'script_edit.png'),
724 get_cs_links, 'script_edit.png'),
725 'push_remote': (_('[pulled from remote] into repository'),
725 'push_remote': (_('[pulled from remote] into repository'),
726 get_cs_links, 'connect.png'),
726 get_cs_links, 'connect.png'),
727 'pull': (_('[pulled] from'),
727 'pull': (_('[pulled] from'),
728 None, 'down_16.png'),
728 None, 'down_16.png'),
729 'started_following_repo': (_('[started following] repository'),
729 'started_following_repo': (_('[started following] repository'),
730 None, 'heart_add.png'),
730 None, 'heart_add.png'),
731 'stopped_following_repo': (_('[stopped following] repository'),
731 'stopped_following_repo': (_('[stopped following] repository'),
732 None, 'heart_delete.png'),
732 None, 'heart_delete.png'),
733 }
733 }
734
734
735 action_str = action_map.get(action, action)
735 action_str = action_map.get(action, action)
736 if feed:
736 if feed:
737 action = action_str[0].replace('[', '').replace(']', '')
737 action = action_str[0].replace('[', '').replace(']', '')
738 else:
738 else:
739 action = action_str[0]\
739 action = action_str[0]\
740 .replace('[', '<span class="journal_highlight">')\
740 .replace('[', '<span class="journal_highlight">')\
741 .replace(']', '</span>')
741 .replace(']', '</span>')
742
742
743 action_params_func = lambda: ""
743 action_params_func = lambda: ""
744
744
745 if callable(action_str[1]):
745 if callable(action_str[1]):
746 action_params_func = action_str[1]
746 action_params_func = action_str[1]
747
747
748 def action_parser_icon():
748 def action_parser_icon():
749 action = user_log.action
749 action = user_log.action
750 action_params = None
750 action_params = None
751 x = action.split(':')
751 x = action.split(':')
752
752
753 if len(x) > 1:
753 if len(x) > 1:
754 action, action_params = x
754 action, action_params = x
755
755
756 tmpl = """<img src="%s%s" alt="%s"/>"""
756 tmpl = """<img src="%s%s" alt="%s"/>"""
757 ico = action_map.get(action, ['', '', ''])[2]
757 ico = action_map.get(action, ['', '', ''])[2]
758 return literal(tmpl % ((url('/images/icons/')), ico, action))
758 return literal(tmpl % ((url('/images/icons/')), ico, action))
759
759
760 # returned callbacks we need to call to get
760 # returned callbacks we need to call to get
761 return [lambda: literal(action), action_params_func, action_parser_icon]
761 return [lambda: literal(action), action_params_func, action_parser_icon]
762
762
763
763
764
764
765 #==============================================================================
765 #==============================================================================
766 # PERMS
766 # PERMS
767 #==============================================================================
767 #==============================================================================
768 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
768 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
769 HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \
769 HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \
770 HasReposGroupPermissionAny
770 HasReposGroupPermissionAny
771
771
772
772
773 #==============================================================================
773 #==============================================================================
774 # GRAVATAR URL
774 # GRAVATAR URL
775 #==============================================================================
775 #==============================================================================
776
776
777 def gravatar_url(email_address, size=30):
777 def gravatar_url(email_address, size=30):
778 from pylons import url # doh, we need to re-import url to mock it later
778 from pylons import url # doh, we need to re-import url to mock it later
779 _def = 'anonymous@rhodecode.org'
779 _def = 'anonymous@rhodecode.org'
780 use_gravatar = str2bool(config['app_conf'].get('use_gravatar'))
780 use_gravatar = str2bool(config['app_conf'].get('use_gravatar'))
781 email_address = email_address or _def
781 email_address = email_address or _def
782 if (not use_gravatar or not email_address or email_address == _def):
782 if (not use_gravatar or not email_address or email_address == _def):
783 f = lambda a, l: min(l, key=lambda x: abs(x - a))
783 f = lambda a, l: min(l, key=lambda x: abs(x - a))
784 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
784 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
785
785
786 if use_gravatar and config['app_conf'].get('alternative_gravatar_url'):
786 if use_gravatar and config['app_conf'].get('alternative_gravatar_url'):
787 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
787 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
788 parsed_url = urlparse.urlparse(url.current(qualified=True))
788 parsed_url = urlparse.urlparse(url.current(qualified=True))
789 tmpl = tmpl.replace('{email}', email_address)\
789 tmpl = tmpl.replace('{email}', email_address)\
790 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
790 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
791 .replace('{netloc}', parsed_url.netloc)\
791 .replace('{netloc}', parsed_url.netloc)\
792 .replace('{scheme}', parsed_url.scheme)\
792 .replace('{scheme}', parsed_url.scheme)\
793 .replace('{size}', str(size))
793 .replace('{size}', str(size))
794 return tmpl
794 return tmpl
795
795
796 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
796 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
797 default = 'identicon'
797 default = 'identicon'
798 baseurl_nossl = "http://www.gravatar.com/avatar/"
798 baseurl_nossl = "http://www.gravatar.com/avatar/"
799 baseurl_ssl = "https://secure.gravatar.com/avatar/"
799 baseurl_ssl = "https://secure.gravatar.com/avatar/"
800 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
800 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
801
801
802 if isinstance(email_address, unicode):
802 if isinstance(email_address, unicode):
803 #hashlib crashes on unicode items
803 #hashlib crashes on unicode items
804 email_address = safe_str(email_address)
804 email_address = safe_str(email_address)
805 # construct the url
805 # construct the url
806 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
806 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
807 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
807 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
808
808
809 return gravatar_url
809 return gravatar_url
810
810
811
811
812 class Page(_Page):
812 class Page(_Page):
813 """
813 """
814 Custom pager to match rendering style with YUI paginator
814 Custom pager to match rendering style with YUI paginator
815 """
815 """
816
816
817 def _get_pos(self, cur_page, max_page, items):
817 def _get_pos(self, cur_page, max_page, items):
818 edge = (items / 2) + 1
818 edge = (items / 2) + 1
819 if (cur_page <= edge):
819 if (cur_page <= edge):
820 radius = max(items / 2, items - cur_page)
820 radius = max(items / 2, items - cur_page)
821 elif (max_page - cur_page) < edge:
821 elif (max_page - cur_page) < edge:
822 radius = (items - 1) - (max_page - cur_page)
822 radius = (items - 1) - (max_page - cur_page)
823 else:
823 else:
824 radius = items / 2
824 radius = items / 2
825
825
826 left = max(1, (cur_page - (radius)))
826 left = max(1, (cur_page - (radius)))
827 right = min(max_page, cur_page + (radius))
827 right = min(max_page, cur_page + (radius))
828 return left, cur_page, right
828 return left, cur_page, right
829
829
830 def _range(self, regexp_match):
830 def _range(self, regexp_match):
831 """
831 """
832 Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
832 Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
833
833
834 Arguments:
834 Arguments:
835
835
836 regexp_match
836 regexp_match
837 A "re" (regular expressions) match object containing the
837 A "re" (regular expressions) match object containing the
838 radius of linked pages around the current page in
838 radius of linked pages around the current page in
839 regexp_match.group(1) as a string
839 regexp_match.group(1) as a string
840
840
841 This function is supposed to be called as a callable in
841 This function is supposed to be called as a callable in
842 re.sub.
842 re.sub.
843
843
844 """
844 """
845 radius = int(regexp_match.group(1))
845 radius = int(regexp_match.group(1))
846
846
847 # Compute the first and last page number within the radius
847 # Compute the first and last page number within the radius
848 # e.g. '1 .. 5 6 [7] 8 9 .. 12'
848 # e.g. '1 .. 5 6 [7] 8 9 .. 12'
849 # -> leftmost_page = 5
849 # -> leftmost_page = 5
850 # -> rightmost_page = 9
850 # -> rightmost_page = 9
851 leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
851 leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
852 self.last_page,
852 self.last_page,
853 (radius * 2) + 1)
853 (radius * 2) + 1)
854 nav_items = []
854 nav_items = []
855
855
856 # Create a link to the first page (unless we are on the first page
856 # Create a link to the first page (unless we are on the first page
857 # or there would be no need to insert '..' spacers)
857 # or there would be no need to insert '..' spacers)
858 if self.page != self.first_page and self.first_page < leftmost_page:
858 if self.page != self.first_page and self.first_page < leftmost_page:
859 nav_items.append(self._pagerlink(self.first_page, self.first_page))
859 nav_items.append(self._pagerlink(self.first_page, self.first_page))
860
860
861 # Insert dots if there are pages between the first page
861 # Insert dots if there are pages between the first page
862 # and the currently displayed page range
862 # and the currently displayed page range
863 if leftmost_page - self.first_page > 1:
863 if leftmost_page - self.first_page > 1:
864 # Wrap in a SPAN tag if nolink_attr is set
864 # Wrap in a SPAN tag if nolink_attr is set
865 text = '..'
865 text = '..'
866 if self.dotdot_attr:
866 if self.dotdot_attr:
867 text = HTML.span(c=text, **self.dotdot_attr)
867 text = HTML.span(c=text, **self.dotdot_attr)
868 nav_items.append(text)
868 nav_items.append(text)
869
869
870 for thispage in xrange(leftmost_page, rightmost_page + 1):
870 for thispage in xrange(leftmost_page, rightmost_page + 1):
871 # Hilight the current page number and do not use a link
871 # Hilight the current page number and do not use a link
872 if thispage == self.page:
872 if thispage == self.page:
873 text = '%s' % (thispage,)
873 text = '%s' % (thispage,)
874 # Wrap in a SPAN tag if nolink_attr is set
874 # Wrap in a SPAN tag if nolink_attr is set
875 if self.curpage_attr:
875 if self.curpage_attr:
876 text = HTML.span(c=text, **self.curpage_attr)
876 text = HTML.span(c=text, **self.curpage_attr)
877 nav_items.append(text)
877 nav_items.append(text)
878 # Otherwise create just a link to that page
878 # Otherwise create just a link to that page
879 else:
879 else:
880 text = '%s' % (thispage,)
880 text = '%s' % (thispage,)
881 nav_items.append(self._pagerlink(thispage, text))
881 nav_items.append(self._pagerlink(thispage, text))
882
882
883 # Insert dots if there are pages between the displayed
883 # Insert dots if there are pages between the displayed
884 # page numbers and the end of the page range
884 # page numbers and the end of the page range
885 if self.last_page - rightmost_page > 1:
885 if self.last_page - rightmost_page > 1:
886 text = '..'
886 text = '..'
887 # Wrap in a SPAN tag if nolink_attr is set
887 # Wrap in a SPAN tag if nolink_attr is set
888 if self.dotdot_attr:
888 if self.dotdot_attr:
889 text = HTML.span(c=text, **self.dotdot_attr)
889 text = HTML.span(c=text, **self.dotdot_attr)
890 nav_items.append(text)
890 nav_items.append(text)
891
891
892 # Create a link to the very last page (unless we are on the last
892 # Create a link to the very last page (unless we are on the last
893 # page or there would be no need to insert '..' spacers)
893 # page or there would be no need to insert '..' spacers)
894 if self.page != self.last_page and rightmost_page < self.last_page:
894 if self.page != self.last_page and rightmost_page < self.last_page:
895 nav_items.append(self._pagerlink(self.last_page, self.last_page))
895 nav_items.append(self._pagerlink(self.last_page, self.last_page))
896
896
897 return self.separator.join(nav_items)
897 return self.separator.join(nav_items)
898
898
899 def pager(self, format='~2~', page_param='page', partial_param='partial',
899 def pager(self, format='~2~', page_param='page', partial_param='partial',
900 show_if_single_page=False, separator=' ', onclick=None,
900 show_if_single_page=False, separator=' ', onclick=None,
901 symbol_first='<<', symbol_last='>>',
901 symbol_first='<<', symbol_last='>>',
902 symbol_previous='<', symbol_next='>',
902 symbol_previous='<', symbol_next='>',
903 link_attr={'class': 'pager_link'},
903 link_attr={'class': 'pager_link'},
904 curpage_attr={'class': 'pager_curpage'},
904 curpage_attr={'class': 'pager_curpage'},
905 dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
905 dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
906
906
907 self.curpage_attr = curpage_attr
907 self.curpage_attr = curpage_attr
908 self.separator = separator
908 self.separator = separator
909 self.pager_kwargs = kwargs
909 self.pager_kwargs = kwargs
910 self.page_param = page_param
910 self.page_param = page_param
911 self.partial_param = partial_param
911 self.partial_param = partial_param
912 self.onclick = onclick
912 self.onclick = onclick
913 self.link_attr = link_attr
913 self.link_attr = link_attr
914 self.dotdot_attr = dotdot_attr
914 self.dotdot_attr = dotdot_attr
915
915
916 # Don't show navigator if there is no more than one page
916 # Don't show navigator if there is no more than one page
917 if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
917 if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
918 return ''
918 return ''
919
919
920 from string import Template
920 from string import Template
921 # Replace ~...~ in token format by range of pages
921 # Replace ~...~ in token format by range of pages
922 result = re.sub(r'~(\d+)~', self._range, format)
922 result = re.sub(r'~(\d+)~', self._range, format)
923
923
924 # Interpolate '%' variables
924 # Interpolate '%' variables
925 result = Template(result).safe_substitute({
925 result = Template(result).safe_substitute({
926 'first_page': self.first_page,
926 'first_page': self.first_page,
927 'last_page': self.last_page,
927 'last_page': self.last_page,
928 'page': self.page,
928 'page': self.page,
929 'page_count': self.page_count,
929 'page_count': self.page_count,
930 'items_per_page': self.items_per_page,
930 'items_per_page': self.items_per_page,
931 'first_item': self.first_item,
931 'first_item': self.first_item,
932 'last_item': self.last_item,
932 'last_item': self.last_item,
933 'item_count': self.item_count,
933 'item_count': self.item_count,
934 'link_first': self.page > self.first_page and \
934 'link_first': self.page > self.first_page and \
935 self._pagerlink(self.first_page, symbol_first) or '',
935 self._pagerlink(self.first_page, symbol_first) or '',
936 'link_last': self.page < self.last_page and \
936 'link_last': self.page < self.last_page and \
937 self._pagerlink(self.last_page, symbol_last) or '',
937 self._pagerlink(self.last_page, symbol_last) or '',
938 'link_previous': self.previous_page and \
938 'link_previous': self.previous_page and \
939 self._pagerlink(self.previous_page, symbol_previous) \
939 self._pagerlink(self.previous_page, symbol_previous) \
940 or HTML.span(symbol_previous, class_="yui-pg-previous"),
940 or HTML.span(symbol_previous, class_="yui-pg-previous"),
941 'link_next': self.next_page and \
941 'link_next': self.next_page and \
942 self._pagerlink(self.next_page, symbol_next) \
942 self._pagerlink(self.next_page, symbol_next) \
943 or HTML.span(symbol_next, class_="yui-pg-next")
943 or HTML.span(symbol_next, class_="yui-pg-next")
944 })
944 })
945
945
946 return literal(result)
946 return literal(result)
947
947
948
948
949 #==============================================================================
949 #==============================================================================
950 # REPO PAGER, PAGER FOR REPOSITORY
950 # REPO PAGER, PAGER FOR REPOSITORY
951 #==============================================================================
951 #==============================================================================
952 class RepoPage(Page):
952 class RepoPage(Page):
953
953
954 def __init__(self, collection, page=1, items_per_page=20,
954 def __init__(self, collection, page=1, items_per_page=20,
955 item_count=None, url=None, **kwargs):
955 item_count=None, url=None, **kwargs):
956
956
957 """Create a "RepoPage" instance. special pager for paging
957 """Create a "RepoPage" instance. special pager for paging
958 repository
958 repository
959 """
959 """
960 self._url_generator = url
960 self._url_generator = url
961
961
962 # Safe the kwargs class-wide so they can be used in the pager() method
962 # Safe the kwargs class-wide so they can be used in the pager() method
963 self.kwargs = kwargs
963 self.kwargs = kwargs
964
964
965 # Save a reference to the collection
965 # Save a reference to the collection
966 self.original_collection = collection
966 self.original_collection = collection
967
967
968 self.collection = collection
968 self.collection = collection
969
969
970 # The self.page is the number of the current page.
970 # The self.page is the number of the current page.
971 # The first page has the number 1!
971 # The first page has the number 1!
972 try:
972 try:
973 self.page = int(page) # make it int() if we get it as a string
973 self.page = int(page) # make it int() if we get it as a string
974 except (ValueError, TypeError):
974 except (ValueError, TypeError):
975 self.page = 1
975 self.page = 1
976
976
977 self.items_per_page = items_per_page
977 self.items_per_page = items_per_page
978
978
979 # Unless the user tells us how many items the collections has
979 # Unless the user tells us how many items the collections has
980 # we calculate that ourselves.
980 # we calculate that ourselves.
981 if item_count is not None:
981 if item_count is not None:
982 self.item_count = item_count
982 self.item_count = item_count
983 else:
983 else:
984 self.item_count = len(self.collection)
984 self.item_count = len(self.collection)
985
985
986 # Compute the number of the first and last available page
986 # Compute the number of the first and last available page
987 if self.item_count > 0:
987 if self.item_count > 0:
988 self.first_page = 1
988 self.first_page = 1
989 self.page_count = int(math.ceil(float(self.item_count) /
989 self.page_count = int(math.ceil(float(self.item_count) /
990 self.items_per_page))
990 self.items_per_page))
991 self.last_page = self.first_page + self.page_count - 1
991 self.last_page = self.first_page + self.page_count - 1
992
992
993 # Make sure that the requested page number is the range of
993 # Make sure that the requested page number is the range of
994 # valid pages
994 # valid pages
995 if self.page > self.last_page:
995 if self.page > self.last_page:
996 self.page = self.last_page
996 self.page = self.last_page
997 elif self.page < self.first_page:
997 elif self.page < self.first_page:
998 self.page = self.first_page
998 self.page = self.first_page
999
999
1000 # Note: the number of items on this page can be less than
1000 # Note: the number of items on this page can be less than
1001 # items_per_page if the last page is not full
1001 # items_per_page if the last page is not full
1002 self.first_item = max(0, (self.item_count) - (self.page *
1002 self.first_item = max(0, (self.item_count) - (self.page *
1003 items_per_page))
1003 items_per_page))
1004 self.last_item = ((self.item_count - 1) - items_per_page *
1004 self.last_item = ((self.item_count - 1) - items_per_page *
1005 (self.page - 1))
1005 (self.page - 1))
1006
1006
1007 self.items = list(self.collection[self.first_item:self.last_item + 1])
1007 self.items = list(self.collection[self.first_item:self.last_item + 1])
1008
1008
1009 # Links to previous and next page
1009 # Links to previous and next page
1010 if self.page > self.first_page:
1010 if self.page > self.first_page:
1011 self.previous_page = self.page - 1
1011 self.previous_page = self.page - 1
1012 else:
1012 else:
1013 self.previous_page = None
1013 self.previous_page = None
1014
1014
1015 if self.page < self.last_page:
1015 if self.page < self.last_page:
1016 self.next_page = self.page + 1
1016 self.next_page = self.page + 1
1017 else:
1017 else:
1018 self.next_page = None
1018 self.next_page = None
1019
1019
1020 # No items available
1020 # No items available
1021 else:
1021 else:
1022 self.first_page = None
1022 self.first_page = None
1023 self.page_count = 0
1023 self.page_count = 0
1024 self.last_page = None
1024 self.last_page = None
1025 self.first_item = None
1025 self.first_item = None
1026 self.last_item = None
1026 self.last_item = None
1027 self.previous_page = None
1027 self.previous_page = None
1028 self.next_page = None
1028 self.next_page = None
1029 self.items = []
1029 self.items = []
1030
1030
1031 # This is a subclass of the 'list' type. Initialise the list now.
1031 # This is a subclass of the 'list' type. Initialise the list now.
1032 list.__init__(self, reversed(self.items))
1032 list.__init__(self, reversed(self.items))
1033
1033
1034
1034
1035 def changed_tooltip(nodes):
1035 def changed_tooltip(nodes):
1036 """
1036 """
1037 Generates a html string for changed nodes in changeset page.
1037 Generates a html string for changed nodes in changeset page.
1038 It limits the output to 30 entries
1038 It limits the output to 30 entries
1039
1039
1040 :param nodes: LazyNodesGenerator
1040 :param nodes: LazyNodesGenerator
1041 """
1041 """
1042 if nodes:
1042 if nodes:
1043 pref = ': <br/> '
1043 pref = ': <br/> '
1044 suf = ''
1044 suf = ''
1045 if len(nodes) > 30:
1045 if len(nodes) > 30:
1046 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
1046 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
1047 return literal(pref + '<br/> '.join([safe_unicode(x.path)
1047 return literal(pref + '<br/> '.join([safe_unicode(x.path)
1048 for x in nodes[:30]]) + suf)
1048 for x in nodes[:30]]) + suf)
1049 else:
1049 else:
1050 return ': ' + _('No Files')
1050 return ': ' + _('No Files')
1051
1051
1052
1052
1053 def repo_link(groups_and_repos):
1053 def repo_link(groups_and_repos):
1054 """
1054 """
1055 Makes a breadcrumbs link to repo within a group
1055 Makes a breadcrumbs link to repo within a group
1056 joins &raquo; on each group to create a fancy link
1056 joins &raquo; on each group to create a fancy link
1057
1057
1058 ex::
1058 ex::
1059 group >> subgroup >> repo
1059 group >> subgroup >> repo
1060
1060
1061 :param groups_and_repos:
1061 :param groups_and_repos:
1062 :param last_url:
1062 :param last_url:
1063 """
1063 """
1064 groups, just_name, repo_name = groups_and_repos
1064 groups, just_name, repo_name = groups_and_repos
1065 last_url = url('summary_home', repo_name=repo_name)
1065 last_url = url('summary_home', repo_name=repo_name)
1066 last_link = link_to(just_name, last_url)
1066 last_link = link_to(just_name, last_url)
1067
1067
1068 def make_link(group):
1068 def make_link(group):
1069 return link_to(group.name,
1069 return link_to(group.name,
1070 url('repos_group_home', group_name=group.group_name))
1070 url('repos_group_home', group_name=group.group_name))
1071 return literal(' &raquo; '.join(map(make_link, groups) + ['<span>%s</span>' % last_link]))
1071 return literal(' &raquo; '.join(map(make_link, groups) + ['<span>%s</span>' % last_link]))
1072
1072
1073
1073
1074 def fancy_file_stats(stats):
1074 def fancy_file_stats(stats):
1075 """
1075 """
1076 Displays a fancy two colored bar for number of added/deleted
1076 Displays a fancy two colored bar for number of added/deleted
1077 lines of code on file
1077 lines of code on file
1078
1078
1079 :param stats: two element list of added/deleted lines of code
1079 :param stats: two element list of added/deleted lines of code
1080 """
1080 """
1081 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
1082 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
1083
1081 def cgen(l_type, a_v, d_v):
1084 def cgen(l_type, a_v, d_v):
1082 mapping = {'tr': 'top-right-rounded-corner-mid',
1085 mapping = {'tr': 'top-right-rounded-corner-mid',
1083 'tl': 'top-left-rounded-corner-mid',
1086 'tl': 'top-left-rounded-corner-mid',
1084 'br': 'bottom-right-rounded-corner-mid',
1087 'br': 'bottom-right-rounded-corner-mid',
1085 'bl': 'bottom-left-rounded-corner-mid'}
1088 'bl': 'bottom-left-rounded-corner-mid'}
1086 map_getter = lambda x: mapping[x]
1089 map_getter = lambda x: mapping[x]
1087
1090
1088 if l_type == 'a' and d_v:
1091 if l_type == 'a' and d_v:
1089 #case when added and deleted are present
1092 #case when added and deleted are present
1090 return ' '.join(map(map_getter, ['tl', 'bl']))
1093 return ' '.join(map(map_getter, ['tl', 'bl']))
1091
1094
1092 if l_type == 'a' and not d_v:
1095 if l_type == 'a' and not d_v:
1093 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1096 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1094
1097
1095 if l_type == 'd' and a_v:
1098 if l_type == 'd' and a_v:
1096 return ' '.join(map(map_getter, ['tr', 'br']))
1099 return ' '.join(map(map_getter, ['tr', 'br']))
1097
1100
1098 if l_type == 'd' and not a_v:
1101 if l_type == 'd' and not a_v:
1099 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1102 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1100
1103
1101 a, d = stats[0], stats[1]
1104 a, d = stats['added'], stats['deleted']
1102 width = 100
1105 width = 100
1103
1106
1104 if a == 'b':
1107 if stats['binary']:
1105 #binary mode
1108 #binary mode
1106 b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
1109 lbl = ''
1107 b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
1110 bin_op = 1
1111
1112 if BIN_FILENODE in stats['ops']:
1113 lbl = 'bin+'
1114
1115 if NEW_FILENODE in stats['ops']:
1116 lbl += _('new file')
1117 bin_op = NEW_FILENODE
1118 elif MOD_FILENODE in stats['ops']:
1119 lbl += _('mod')
1120 bin_op = MOD_FILENODE
1121 elif DEL_FILENODE in stats['ops']:
1122 lbl += _('del')
1123 bin_op = DEL_FILENODE
1124 elif RENAMED_FILENODE in stats['ops']:
1125 lbl += _('rename')
1126 bin_op = RENAMED_FILENODE
1127
1128 #chmod can go with other operations
1129 if CHMOD_FILENODE in stats['ops']:
1130 _org_lbl = _('chmod')
1131 lbl += _org_lbl if lbl.endswith('+') else '+%s' % _org_lbl
1132
1133 #import ipdb;ipdb.set_trace()
1134 b_d = '<div class="bin bin%s %s" style="width:100%%">%s</div>' % (bin_op, cgen('a', a_v='', d_v=0), lbl)
1135 b_a = '<div class="bin bin1" style="width:0%%"></div>'
1108 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
1136 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
1109
1137
1110 t = stats[0] + stats[1]
1138 t = stats['added'] + stats['deleted']
1111 unit = float(width) / (t or 1)
1139 unit = float(width) / (t or 1)
1112
1140
1113 # needs > 9% of width to be visible or 0 to be hidden
1141 # needs > 9% of width to be visible or 0 to be hidden
1114 a_p = max(9, unit * a) if a > 0 else 0
1142 a_p = max(9, unit * a) if a > 0 else 0
1115 d_p = max(9, unit * d) if d > 0 else 0
1143 d_p = max(9, unit * d) if d > 0 else 0
1116 p_sum = a_p + d_p
1144 p_sum = a_p + d_p
1117
1145
1118 if p_sum > width:
1146 if p_sum > width:
1119 #adjust the percentage to be == 100% since we adjusted to 9
1147 #adjust the percentage to be == 100% since we adjusted to 9
1120 if a_p > d_p:
1148 if a_p > d_p:
1121 a_p = a_p - (p_sum - width)
1149 a_p = a_p - (p_sum - width)
1122 else:
1150 else:
1123 d_p = d_p - (p_sum - width)
1151 d_p = d_p - (p_sum - width)
1124
1152
1125 a_v = a if a > 0 else ''
1153 a_v = a if a > 0 else ''
1126 d_v = d if d > 0 else ''
1154 d_v = d if d > 0 else ''
1127
1155
1128 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
1156 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
1129 cgen('a', a_v, d_v), a_p, a_v
1157 cgen('a', a_v, d_v), a_p, a_v
1130 )
1158 )
1131 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
1159 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
1132 cgen('d', a_v, d_v), d_p, d_v
1160 cgen('d', a_v, d_v), d_p, d_v
1133 )
1161 )
1134 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
1162 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
1135
1163
1136
1164
1137 def urlify_text(text_, safe=True):
1165 def urlify_text(text_, safe=True):
1138 """
1166 """
1139 Extrac urls from text and make html links out of them
1167 Extrac urls from text and make html links out of them
1140
1168
1141 :param text_:
1169 :param text_:
1142 """
1170 """
1143
1171
1144 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
1172 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
1145 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1173 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1146
1174
1147 def url_func(match_obj):
1175 def url_func(match_obj):
1148 url_full = match_obj.groups()[0]
1176 url_full = match_obj.groups()[0]
1149 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1177 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1150 _newtext = url_pat.sub(url_func, text_)
1178 _newtext = url_pat.sub(url_func, text_)
1151 if safe:
1179 if safe:
1152 return literal(_newtext)
1180 return literal(_newtext)
1153 return _newtext
1181 return _newtext
1154
1182
1155
1183
1156 def urlify_changesets(text_, repository):
1184 def urlify_changesets(text_, repository):
1157 """
1185 """
1158 Extract revision ids from changeset and make link from them
1186 Extract revision ids from changeset and make link from them
1159
1187
1160 :param text_:
1188 :param text_:
1161 :param repository: repo name to build the URL with
1189 :param repository: repo name to build the URL with
1162 """
1190 """
1163 from pylons import url # doh, we need to re-import url to mock it later
1191 from pylons import url # doh, we need to re-import url to mock it later
1164 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1192 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1165
1193
1166 def url_func(match_obj):
1194 def url_func(match_obj):
1167 rev = match_obj.groups()[1]
1195 rev = match_obj.groups()[1]
1168 pref = match_obj.groups()[0]
1196 pref = match_obj.groups()[0]
1169 suf = match_obj.groups()[2]
1197 suf = match_obj.groups()[2]
1170
1198
1171 tmpl = (
1199 tmpl = (
1172 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1200 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1173 '%(rev)s</a>%(suf)s'
1201 '%(rev)s</a>%(suf)s'
1174 )
1202 )
1175 return tmpl % {
1203 return tmpl % {
1176 'pref': pref,
1204 'pref': pref,
1177 'cls': 'revision-link',
1205 'cls': 'revision-link',
1178 'url': url('changeset_home', repo_name=repository, revision=rev),
1206 'url': url('changeset_home', repo_name=repository, revision=rev),
1179 'rev': rev,
1207 'rev': rev,
1180 'suf': suf
1208 'suf': suf
1181 }
1209 }
1182
1210
1183 newtext = URL_PAT.sub(url_func, text_)
1211 newtext = URL_PAT.sub(url_func, text_)
1184
1212
1185 return newtext
1213 return newtext
1186
1214
1187
1215
1188 def urlify_commit(text_, repository=None, link_=None):
1216 def urlify_commit(text_, repository=None, link_=None):
1189 """
1217 """
1190 Parses given text message and makes proper links.
1218 Parses given text message and makes proper links.
1191 issues are linked to given issue-server, and rest is a changeset link
1219 issues are linked to given issue-server, and rest is a changeset link
1192 if link_ is given, in other case it's a plain text
1220 if link_ is given, in other case it's a plain text
1193
1221
1194 :param text_:
1222 :param text_:
1195 :param repository:
1223 :param repository:
1196 :param link_: changeset link
1224 :param link_: changeset link
1197 """
1225 """
1198 import traceback
1226 import traceback
1199 from pylons import url # doh, we need to re-import url to mock it later
1227 from pylons import url # doh, we need to re-import url to mock it later
1200
1228
1201 def escaper(string):
1229 def escaper(string):
1202 return string.replace('<', '&lt;').replace('>', '&gt;')
1230 return string.replace('<', '&lt;').replace('>', '&gt;')
1203
1231
1204 def linkify_others(t, l):
1232 def linkify_others(t, l):
1205 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1233 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1206 links = []
1234 links = []
1207 for e in urls.split(t):
1235 for e in urls.split(t):
1208 if not urls.match(e):
1236 if not urls.match(e):
1209 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1237 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1210 else:
1238 else:
1211 links.append(e)
1239 links.append(e)
1212
1240
1213 return ''.join(links)
1241 return ''.join(links)
1214
1242
1215 # urlify changesets - extrac revisions and make link out of them
1243 # urlify changesets - extrac revisions and make link out of them
1216 newtext = urlify_changesets(escaper(text_), repository)
1244 newtext = urlify_changesets(escaper(text_), repository)
1217
1245
1218 # extract http/https links and make them real urls
1246 # extract http/https links and make them real urls
1219 newtext = urlify_text(newtext, safe=False)
1247 newtext = urlify_text(newtext, safe=False)
1220
1248
1221 try:
1249 try:
1222 from rhodecode import CONFIG
1250 from rhodecode import CONFIG
1223 conf = CONFIG
1251 conf = CONFIG
1224
1252
1225 # allow multiple issue servers to be used
1253 # allow multiple issue servers to be used
1226 valid_indices = [
1254 valid_indices = [
1227 x.group(1)
1255 x.group(1)
1228 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1256 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1229 if x and 'issue_server_link%s' % x.group(1) in conf
1257 if x and 'issue_server_link%s' % x.group(1) in conf
1230 and 'issue_prefix%s' % x.group(1) in conf
1258 and 'issue_prefix%s' % x.group(1) in conf
1231 ]
1259 ]
1232
1260
1233 log.debug('found issue server suffixes `%s` during valuation of: %s'
1261 log.debug('found issue server suffixes `%s` during valuation of: %s'
1234 % (','.join(valid_indices), newtext))
1262 % (','.join(valid_indices), newtext))
1235
1263
1236 for pattern_index in valid_indices:
1264 for pattern_index in valid_indices:
1237 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1265 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1238 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1266 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1239 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1267 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1240
1268
1241 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1269 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1242 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1270 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1243 ISSUE_PREFIX))
1271 ISSUE_PREFIX))
1244
1272
1245 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1273 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1246
1274
1247 def url_func(match_obj):
1275 def url_func(match_obj):
1248 pref = ''
1276 pref = ''
1249 if match_obj.group().startswith(' '):
1277 if match_obj.group().startswith(' '):
1250 pref = ' '
1278 pref = ' '
1251
1279
1252 issue_id = ''.join(match_obj.groups())
1280 issue_id = ''.join(match_obj.groups())
1253 tmpl = (
1281 tmpl = (
1254 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1282 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1255 '%(issue-prefix)s%(id-repr)s'
1283 '%(issue-prefix)s%(id-repr)s'
1256 '</a>'
1284 '</a>'
1257 )
1285 )
1258 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1286 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1259 if repository:
1287 if repository:
1260 url = url.replace('{repo}', repository)
1288 url = url.replace('{repo}', repository)
1261 repo_name = repository.split(URL_SEP)[-1]
1289 repo_name = repository.split(URL_SEP)[-1]
1262 url = url.replace('{repo_name}', repo_name)
1290 url = url.replace('{repo_name}', repo_name)
1263
1291
1264 return tmpl % {
1292 return tmpl % {
1265 'pref': pref,
1293 'pref': pref,
1266 'cls': 'issue-tracker-link',
1294 'cls': 'issue-tracker-link',
1267 'url': url,
1295 'url': url,
1268 'id-repr': issue_id,
1296 'id-repr': issue_id,
1269 'issue-prefix': ISSUE_PREFIX,
1297 'issue-prefix': ISSUE_PREFIX,
1270 'serv': ISSUE_SERVER_LNK,
1298 'serv': ISSUE_SERVER_LNK,
1271 }
1299 }
1272 newtext = URL_PAT.sub(url_func, newtext)
1300 newtext = URL_PAT.sub(url_func, newtext)
1273 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1301 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1274
1302
1275 # if we actually did something above
1303 # if we actually did something above
1276 if link_:
1304 if link_:
1277 # wrap not links into final link => link_
1305 # wrap not links into final link => link_
1278 newtext = linkify_others(newtext, link_)
1306 newtext = linkify_others(newtext, link_)
1279 except Exception:
1307 except Exception:
1280 log.error(traceback.format_exc())
1308 log.error(traceback.format_exc())
1281 pass
1309 pass
1282
1310
1283 return literal(newtext)
1311 return literal(newtext)
1284
1312
1285
1313
1286 def rst(source):
1314 def rst(source):
1287 return literal('<div class="rst-block">%s</div>' %
1315 return literal('<div class="rst-block">%s</div>' %
1288 MarkupRenderer.rst(source))
1316 MarkupRenderer.rst(source))
1289
1317
1290
1318
1291 def rst_w_mentions(source):
1319 def rst_w_mentions(source):
1292 """
1320 """
1293 Wrapped rst renderer with @mention highlighting
1321 Wrapped rst renderer with @mention highlighting
1294
1322
1295 :param source:
1323 :param source:
1296 """
1324 """
1297 return literal('<div class="rst-block">%s</div>' %
1325 return literal('<div class="rst-block">%s</div>' %
1298 MarkupRenderer.rst_with_mentions(source))
1326 MarkupRenderer.rst_with_mentions(source))
1299
1327
1300
1328
1301 def changeset_status(repo, revision):
1329 def changeset_status(repo, revision):
1302 return ChangesetStatusModel().get_status(repo, revision)
1330 return ChangesetStatusModel().get_status(repo, revision)
1303
1331
1304
1332
1305 def changeset_status_lbl(changeset_status):
1333 def changeset_status_lbl(changeset_status):
1306 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1334 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1307
1335
1308
1336
1309 def get_permission_name(key):
1337 def get_permission_name(key):
1310 return dict(Permission.PERMS).get(key)
1338 return dict(Permission.PERMS).get(key)
1311
1339
1312
1340
1313 def journal_filter_help():
1341 def journal_filter_help():
1314 return _(textwrap.dedent('''
1342 return _(textwrap.dedent('''
1315 Example filter terms:
1343 Example filter terms:
1316 repository:vcs
1344 repository:vcs
1317 username:marcin
1345 username:marcin
1318 action:*push*
1346 action:*push*
1319 ip:127.0.0.1
1347 ip:127.0.0.1
1320 date:20120101
1348 date:20120101
1321 date:[20120101100000 TO 20120102]
1349 date:[20120101100000 TO 20120102]
1322
1350
1323 Generate wildcards using '*' character:
1351 Generate wildcards using '*' character:
1324 "repositroy:vcs*" - search everything starting with 'vcs'
1352 "repositroy:vcs*" - search everything starting with 'vcs'
1325 "repository:*vcs*" - search for repository containing 'vcs'
1353 "repository:*vcs*" - search for repository containing 'vcs'
1326
1354
1327 Optional AND / OR operators in queries
1355 Optional AND / OR operators in queries
1328 "repository:vcs OR repository:test"
1356 "repository:vcs OR repository:test"
1329 "username:test AND repository:test*"
1357 "username:test AND repository:test*"
1330 '''))
1358 '''))
1331
1359
1332
1360
1333 def not_mapped_error(repo_name):
1361 def not_mapped_error(repo_name):
1334 flash(_('%s repository is not mapped to db perhaps'
1362 flash(_('%s repository is not mapped to db perhaps'
1335 ' it was created or renamed from the filesystem'
1363 ' it was created or renamed from the filesystem'
1336 ' please run the application again'
1364 ' please run the application again'
1337 ' in order to rescan repositories') % repo_name, category='error')
1365 ' in order to rescan repositories') % repo_name, category='error')
1338
1366
1339
1367
1340 def ip_range(ip_addr):
1368 def ip_range(ip_addr):
1341 from rhodecode.model.db import UserIpMap
1369 from rhodecode.model.db import UserIpMap
1342 s, e = UserIpMap._get_ip_range(ip_addr)
1370 s, e = UserIpMap._get_ip_range(ip_addr)
1343 return '%s - %s' % (s, e)
1371 return '%s - %s' % (s, e)
@@ -1,4907 +1,4914 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 border: 0;
2 border: 0;
3 outline: 0;
3 outline: 0;
4 font-size: 100%;
4 font-size: 100%;
5 vertical-align: baseline;
5 vertical-align: baseline;
6 background: transparent;
6 background: transparent;
7 margin: 0;
7 margin: 0;
8 padding: 0;
8 padding: 0;
9 }
9 }
10
10
11 body {
11 body {
12 line-height: 1;
12 line-height: 1;
13 height: 100%;
13 height: 100%;
14 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
14 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
15 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
16 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
16 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
17 color: #000;
17 color: #000;
18 margin: 0;
18 margin: 0;
19 padding: 0;
19 padding: 0;
20 font-size: 12px;
20 font-size: 12px;
21 }
21 }
22
22
23 ol, ul {
23 ol, ul {
24 list-style: none;
24 list-style: none;
25 }
25 }
26
26
27 blockquote, q {
27 blockquote, q {
28 quotes: none;
28 quotes: none;
29 }
29 }
30
30
31 blockquote:before, blockquote:after, q:before, q:after {
31 blockquote:before, blockquote:after, q:before, q:after {
32 content: none;
32 content: none;
33 }
33 }
34
34
35 :focus {
35 :focus {
36 outline: 0;
36 outline: 0;
37 }
37 }
38
38
39 del {
39 del {
40 text-decoration: line-through;
40 text-decoration: line-through;
41 }
41 }
42
42
43 table {
43 table {
44 border-collapse: collapse;
44 border-collapse: collapse;
45 border-spacing: 0;
45 border-spacing: 0;
46 }
46 }
47
47
48 html {
48 html {
49 height: 100%;
49 height: 100%;
50 }
50 }
51
51
52 a {
52 a {
53 color: #003367;
53 color: #003367;
54 text-decoration: none;
54 text-decoration: none;
55 cursor: pointer;
55 cursor: pointer;
56 }
56 }
57
57
58 a:hover {
58 a:hover {
59 color: #316293;
59 color: #316293;
60 text-decoration: underline;
60 text-decoration: underline;
61 }
61 }
62
62
63 h1, h2, h3, h4, h5, h6,
63 h1, h2, h3, h4, h5, h6,
64 div.h1, div.h2, div.h3, div.h4, div.h5, div.h6 {
64 div.h1, div.h2, div.h3, div.h4, div.h5, div.h6 {
65 color: #292929;
65 color: #292929;
66 font-weight: 700;
66 font-weight: 700;
67 }
67 }
68
68
69 h1, div.h1 {
69 h1, div.h1 {
70 font-size: 22px;
70 font-size: 22px;
71 }
71 }
72
72
73 h2, div.h2 {
73 h2, div.h2 {
74 font-size: 20px;
74 font-size: 20px;
75 }
75 }
76
76
77 h3, div.h3 {
77 h3, div.h3 {
78 font-size: 18px;
78 font-size: 18px;
79 }
79 }
80
80
81 h4, div.h4 {
81 h4, div.h4 {
82 font-size: 16px;
82 font-size: 16px;
83 }
83 }
84
84
85 h5, div.h5 {
85 h5, div.h5 {
86 font-size: 14px;
86 font-size: 14px;
87 }
87 }
88
88
89 h6, div.h6 {
89 h6, div.h6 {
90 font-size: 11px;
90 font-size: 11px;
91 }
91 }
92
92
93 ul.circle {
93 ul.circle {
94 list-style-type: circle;
94 list-style-type: circle;
95 }
95 }
96
96
97 ul.disc {
97 ul.disc {
98 list-style-type: disc;
98 list-style-type: disc;
99 }
99 }
100
100
101 ul.square {
101 ul.square {
102 list-style-type: square;
102 list-style-type: square;
103 }
103 }
104
104
105 ol.lower-roman {
105 ol.lower-roman {
106 list-style-type: lower-roman;
106 list-style-type: lower-roman;
107 }
107 }
108
108
109 ol.upper-roman {
109 ol.upper-roman {
110 list-style-type: upper-roman;
110 list-style-type: upper-roman;
111 }
111 }
112
112
113 ol.lower-alpha {
113 ol.lower-alpha {
114 list-style-type: lower-alpha;
114 list-style-type: lower-alpha;
115 }
115 }
116
116
117 ol.upper-alpha {
117 ol.upper-alpha {
118 list-style-type: upper-alpha;
118 list-style-type: upper-alpha;
119 }
119 }
120
120
121 ol.decimal {
121 ol.decimal {
122 list-style-type: decimal;
122 list-style-type: decimal;
123 }
123 }
124
124
125 div.color {
125 div.color {
126 clear: both;
126 clear: both;
127 overflow: hidden;
127 overflow: hidden;
128 position: absolute;
128 position: absolute;
129 background: #FFF;
129 background: #FFF;
130 margin: 7px 0 0 60px;
130 margin: 7px 0 0 60px;
131 padding: 1px 1px 1px 0;
131 padding: 1px 1px 1px 0;
132 }
132 }
133
133
134 div.color a {
134 div.color a {
135 width: 15px;
135 width: 15px;
136 height: 15px;
136 height: 15px;
137 display: block;
137 display: block;
138 float: left;
138 float: left;
139 margin: 0 0 0 1px;
139 margin: 0 0 0 1px;
140 padding: 0;
140 padding: 0;
141 }
141 }
142
142
143 div.options {
143 div.options {
144 clear: both;
144 clear: both;
145 overflow: hidden;
145 overflow: hidden;
146 position: absolute;
146 position: absolute;
147 background: #FFF;
147 background: #FFF;
148 margin: 7px 0 0 162px;
148 margin: 7px 0 0 162px;
149 padding: 0;
149 padding: 0;
150 }
150 }
151
151
152 div.options a {
152 div.options a {
153 height: 1%;
153 height: 1%;
154 display: block;
154 display: block;
155 text-decoration: none;
155 text-decoration: none;
156 margin: 0;
156 margin: 0;
157 padding: 3px 8px;
157 padding: 3px 8px;
158 }
158 }
159
159
160 .top-left-rounded-corner {
160 .top-left-rounded-corner {
161 -webkit-border-top-left-radius: 8px;
161 -webkit-border-top-left-radius: 8px;
162 -khtml-border-radius-topleft: 8px;
162 -khtml-border-radius-topleft: 8px;
163 border-top-left-radius: 8px;
163 border-top-left-radius: 8px;
164 }
164 }
165
165
166 .top-right-rounded-corner {
166 .top-right-rounded-corner {
167 -webkit-border-top-right-radius: 8px;
167 -webkit-border-top-right-radius: 8px;
168 -khtml-border-radius-topright: 8px;
168 -khtml-border-radius-topright: 8px;
169 border-top-right-radius: 8px;
169 border-top-right-radius: 8px;
170 }
170 }
171
171
172 .bottom-left-rounded-corner {
172 .bottom-left-rounded-corner {
173 -webkit-border-bottom-left-radius: 8px;
173 -webkit-border-bottom-left-radius: 8px;
174 -khtml-border-radius-bottomleft: 8px;
174 -khtml-border-radius-bottomleft: 8px;
175 border-bottom-left-radius: 8px;
175 border-bottom-left-radius: 8px;
176 }
176 }
177
177
178 .bottom-right-rounded-corner {
178 .bottom-right-rounded-corner {
179 -webkit-border-bottom-right-radius: 8px;
179 -webkit-border-bottom-right-radius: 8px;
180 -khtml-border-radius-bottomright: 8px;
180 -khtml-border-radius-bottomright: 8px;
181 border-bottom-right-radius: 8px;
181 border-bottom-right-radius: 8px;
182 }
182 }
183
183
184 .top-left-rounded-corner-mid {
184 .top-left-rounded-corner-mid {
185 -webkit-border-top-left-radius: 4px;
185 -webkit-border-top-left-radius: 4px;
186 -khtml-border-radius-topleft: 4px;
186 -khtml-border-radius-topleft: 4px;
187 border-top-left-radius: 4px;
187 border-top-left-radius: 4px;
188 }
188 }
189
189
190 .top-right-rounded-corner-mid {
190 .top-right-rounded-corner-mid {
191 -webkit-border-top-right-radius: 4px;
191 -webkit-border-top-right-radius: 4px;
192 -khtml-border-radius-topright: 4px;
192 -khtml-border-radius-topright: 4px;
193 border-top-right-radius: 4px;
193 border-top-right-radius: 4px;
194 }
194 }
195
195
196 .bottom-left-rounded-corner-mid {
196 .bottom-left-rounded-corner-mid {
197 -webkit-border-bottom-left-radius: 4px;
197 -webkit-border-bottom-left-radius: 4px;
198 -khtml-border-radius-bottomleft: 4px;
198 -khtml-border-radius-bottomleft: 4px;
199 border-bottom-left-radius: 4px;
199 border-bottom-left-radius: 4px;
200 }
200 }
201
201
202 .bottom-right-rounded-corner-mid {
202 .bottom-right-rounded-corner-mid {
203 -webkit-border-bottom-right-radius: 4px;
203 -webkit-border-bottom-right-radius: 4px;
204 -khtml-border-radius-bottomright: 4px;
204 -khtml-border-radius-bottomright: 4px;
205 border-bottom-right-radius: 4px;
205 border-bottom-right-radius: 4px;
206 }
206 }
207
207
208 .help-block {
208 .help-block {
209 color: #999999;
209 color: #999999;
210 display: block;
210 display: block;
211 margin-bottom: 0;
211 margin-bottom: 0;
212 margin-top: 5px;
212 margin-top: 5px;
213 }
213 }
214
214
215 .empty_data {
215 .empty_data {
216 color: #B9B9B9;
216 color: #B9B9B9;
217 }
217 }
218
218
219 a.permalink {
219 a.permalink {
220 visibility: hidden;
220 visibility: hidden;
221 position: absolute;
221 position: absolute;
222 margin: 3px 4px;
222 margin: 3px 4px;
223 }
223 }
224
224
225 a.permalink:hover {
225 a.permalink:hover {
226 text-decoration: none;
226 text-decoration: none;
227 }
227 }
228
228
229 h1:hover > a.permalink,
229 h1:hover > a.permalink,
230 h2:hover > a.permalink,
230 h2:hover > a.permalink,
231 h3:hover > a.permalink,
231 h3:hover > a.permalink,
232 h4:hover > a.permalink,
232 h4:hover > a.permalink,
233 h5:hover > a.permalink,
233 h5:hover > a.permalink,
234 h6:hover > a.permalink,
234 h6:hover > a.permalink,
235 div:hover > a.permalink {
235 div:hover > a.permalink {
236 visibility: visible;
236 visibility: visible;
237 }
237 }
238
238
239 #header {
239 #header {
240 }
240 }
241 #header ul#logged-user {
241 #header ul#logged-user {
242 margin-bottom: 5px !important;
242 margin-bottom: 5px !important;
243 -webkit-border-radius: 0px 0px 8px 8px;
243 -webkit-border-radius: 0px 0px 8px 8px;
244 -khtml-border-radius: 0px 0px 8px 8px;
244 -khtml-border-radius: 0px 0px 8px 8px;
245 border-radius: 0px 0px 8px 8px;
245 border-radius: 0px 0px 8px 8px;
246 height: 37px;
246 height: 37px;
247 background-color: #003B76;
247 background-color: #003B76;
248 background-repeat: repeat-x;
248 background-repeat: repeat-x;
249 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
249 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
250 background-image: -moz-linear-gradient(top, #003b76, #00376e);
250 background-image: -moz-linear-gradient(top, #003b76, #00376e);
251 background-image: -ms-linear-gradient(top, #003b76, #00376e);
251 background-image: -ms-linear-gradient(top, #003b76, #00376e);
252 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
252 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
253 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
253 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
254 background-image: -o-linear-gradient(top, #003b76, #00376e);
254 background-image: -o-linear-gradient(top, #003b76, #00376e);
255 background-image: linear-gradient(to bottom, #003b76, #00376e);
255 background-image: linear-gradient(to bottom, #003b76, #00376e);
256 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
256 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
257 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
257 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
258 }
258 }
259
259
260 #header ul#logged-user li {
260 #header ul#logged-user li {
261 list-style: none;
261 list-style: none;
262 float: left;
262 float: left;
263 margin: 8px 0 0;
263 margin: 8px 0 0;
264 padding: 4px 12px;
264 padding: 4px 12px;
265 border-left: 1px solid #316293;
265 border-left: 1px solid #316293;
266 }
266 }
267
267
268 #header ul#logged-user li.first {
268 #header ul#logged-user li.first {
269 border-left: none;
269 border-left: none;
270 margin: 4px;
270 margin: 4px;
271 }
271 }
272
272
273 #header ul#logged-user li.first div.gravatar {
273 #header ul#logged-user li.first div.gravatar {
274 margin-top: -2px;
274 margin-top: -2px;
275 }
275 }
276
276
277 #header ul#logged-user li.first div.account {
277 #header ul#logged-user li.first div.account {
278 padding-top: 4px;
278 padding-top: 4px;
279 float: left;
279 float: left;
280 }
280 }
281
281
282 #header ul#logged-user li.last {
282 #header ul#logged-user li.last {
283 border-right: none;
283 border-right: none;
284 }
284 }
285
285
286 #header ul#logged-user li a {
286 #header ul#logged-user li a {
287 color: #fff;
287 color: #fff;
288 font-weight: 700;
288 font-weight: 700;
289 text-decoration: none;
289 text-decoration: none;
290 }
290 }
291
291
292 #header ul#logged-user li a:hover {
292 #header ul#logged-user li a:hover {
293 text-decoration: underline;
293 text-decoration: underline;
294 }
294 }
295
295
296 #header ul#logged-user li.highlight a {
296 #header ul#logged-user li.highlight a {
297 color: #fff;
297 color: #fff;
298 }
298 }
299
299
300 #header ul#logged-user li.highlight a:hover {
300 #header ul#logged-user li.highlight a:hover {
301 color: #FFF;
301 color: #FFF;
302 }
302 }
303 #header-dd {
303 #header-dd {
304 clear: both;
304 clear: both;
305 position: fixed !important;
305 position: fixed !important;
306 background-color: #003B76;
306 background-color: #003B76;
307 opacity: 0.01;
307 opacity: 0.01;
308 cursor: pointer;
308 cursor: pointer;
309 min-height: 10px;
309 min-height: 10px;
310 width: 100% !important;
310 width: 100% !important;
311 -webkit-border-radius: 0px 0px 4px 4px;
311 -webkit-border-radius: 0px 0px 4px 4px;
312 -khtml-border-radius: 0px 0px 4px 4px;
312 -khtml-border-radius: 0px 0px 4px 4px;
313 border-radius: 0px 0px 4px 4px;
313 border-radius: 0px 0px 4px 4px;
314 }
314 }
315
315
316 #header-dd:hover {
316 #header-dd:hover {
317 opacity: 0.2;
317 opacity: 0.2;
318 -webkit-transition: opacity 0.5s ease-in-out;
318 -webkit-transition: opacity 0.5s ease-in-out;
319 -moz-transition: opacity 0.5s ease-in-out;
319 -moz-transition: opacity 0.5s ease-in-out;
320 transition: opacity 0.5s ease-in-out;
320 transition: opacity 0.5s ease-in-out;
321 }
321 }
322
322
323 #header #header-inner {
323 #header #header-inner {
324 min-height: 44px;
324 min-height: 44px;
325 clear: both;
325 clear: both;
326 position: relative;
326 position: relative;
327 background-color: #003B76;
327 background-color: #003B76;
328 background-repeat: repeat-x;
328 background-repeat: repeat-x;
329 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
329 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
330 background-image: -moz-linear-gradient(top, #003b76, #00376e);
330 background-image: -moz-linear-gradient(top, #003b76, #00376e);
331 background-image: -ms-linear-gradient(top, #003b76, #00376e);
331 background-image: -ms-linear-gradient(top, #003b76, #00376e);
332 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
332 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
333 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
333 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
334 background-image: -o-linear-gradient(top, #003b76, #00376e);
334 background-image: -o-linear-gradient(top, #003b76, #00376e);
335 background-image: linear-gradient(to bottom, #003b76, #00376e);
335 background-image: linear-gradient(to bottom, #003b76, #00376e);
336 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
336 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
337 margin: 0;
337 margin: 0;
338 padding: 0;
338 padding: 0;
339 display: block;
339 display: block;
340 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
340 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
341 -webkit-border-radius: 0px 0px 4px 4px;
341 -webkit-border-radius: 0px 0px 4px 4px;
342 -khtml-border-radius: 0px 0px 4px 4px;
342 -khtml-border-radius: 0px 0px 4px 4px;
343 border-radius: 0px 0px 4px 4px;
343 border-radius: 0px 0px 4px 4px;
344 }
344 }
345 #header #header-inner.hover {
345 #header #header-inner.hover {
346 width: 100% !important;
346 width: 100% !important;
347 -webkit-border-radius: 0px 0px 0px 0px;
347 -webkit-border-radius: 0px 0px 0px 0px;
348 -khtml-border-radius: 0px 0px 0px 0px;
348 -khtml-border-radius: 0px 0px 0px 0px;
349 border-radius: 0px 0px 0px 0px;
349 border-radius: 0px 0px 0px 0px;
350 position: fixed !important;
350 position: fixed !important;
351 z-index: 10000;
351 z-index: 10000;
352 }
352 }
353
353
354 .ie7 #header #header-inner.hover,
354 .ie7 #header #header-inner.hover,
355 .ie8 #header #header-inner.hover,
355 .ie8 #header #header-inner.hover,
356 .ie9 #header #header-inner.hover
356 .ie9 #header #header-inner.hover
357 {
357 {
358 z-index: auto !important;
358 z-index: auto !important;
359 }
359 }
360
360
361 .header-pos-fix, .anchor {
361 .header-pos-fix, .anchor {
362 margin-top: -46px;
362 margin-top: -46px;
363 padding-top: 46px;
363 padding-top: 46px;
364 }
364 }
365
365
366 #header #header-inner #home a {
366 #header #header-inner #home a {
367 height: 40px;
367 height: 40px;
368 width: 46px;
368 width: 46px;
369 display: block;
369 display: block;
370 background: url("../images/button_home.png");
370 background: url("../images/button_home.png");
371 background-position: 0 0;
371 background-position: 0 0;
372 margin: 0;
372 margin: 0;
373 padding: 0;
373 padding: 0;
374 }
374 }
375
375
376 #header #header-inner #home a:hover {
376 #header #header-inner #home a:hover {
377 background-position: 0 -40px;
377 background-position: 0 -40px;
378 }
378 }
379
379
380 #header #header-inner #logo {
380 #header #header-inner #logo {
381 float: left;
381 float: left;
382 position: absolute;
382 position: absolute;
383 }
383 }
384
384
385 #header #header-inner #logo h1 {
385 #header #header-inner #logo h1 {
386 color: #FFF;
386 color: #FFF;
387 font-size: 20px;
387 font-size: 20px;
388 margin: 12px 0 0 13px;
388 margin: 12px 0 0 13px;
389 padding: 0;
389 padding: 0;
390 }
390 }
391
391
392 #header #header-inner #logo a {
392 #header #header-inner #logo a {
393 color: #fff;
393 color: #fff;
394 text-decoration: none;
394 text-decoration: none;
395 }
395 }
396
396
397 #header #header-inner #logo a:hover {
397 #header #header-inner #logo a:hover {
398 color: #bfe3ff;
398 color: #bfe3ff;
399 }
399 }
400
400
401 #header #header-inner #quick {
401 #header #header-inner #quick {
402 position: relative;
402 position: relative;
403 float: right;
403 float: right;
404 list-style-type: none;
404 list-style-type: none;
405 list-style-position: outside;
405 list-style-position: outside;
406 margin: 4px 8px 0 0;
406 margin: 4px 8px 0 0;
407 padding: 0;
407 padding: 0;
408 border-radius: 4px;
408 border-radius: 4px;
409 }
409 }
410
410
411 #header #header-inner #quick li span.short {
411 #header #header-inner #quick li span.short {
412 padding: 9px 6px 8px 6px;
412 padding: 9px 6px 8px 6px;
413 }
413 }
414
414
415 #header #header-inner #quick li span {
415 #header #header-inner #quick li span {
416 display: inline;
416 display: inline;
417 margin: 0;
417 margin: 0;
418 }
418 }
419
419
420 #header #header-inner #quick li span.normal {
420 #header #header-inner #quick li span.normal {
421 border: none;
421 border: none;
422 padding: 10px 12px 8px;
422 padding: 10px 12px 8px;
423 }
423 }
424
424
425 #header #header-inner #quick li span.icon {
425 #header #header-inner #quick li span.icon {
426 border-left: none;
426 border-left: none;
427 padding-left: 10px;
427 padding-left: 10px;
428 }
428 }
429
429
430 #header #header-inner #quick li span.icon_short {
430 #header #header-inner #quick li span.icon_short {
431 top: 0;
431 top: 0;
432 left: 0;
432 left: 0;
433 border-left: none;
433 border-left: none;
434 border-right: 1px solid #2e5c89;
434 border-right: 1px solid #2e5c89;
435 padding: 8px 6px 4px;
435 padding: 8px 6px 4px;
436 }
436 }
437
437
438 #header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
438 #header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
439 vertical-align: middle;
439 vertical-align: middle;
440 margin-bottom: 2px;
440 margin-bottom: 2px;
441 }
441 }
442
442
443 #header #header-inner #quick ul.repo_switcher {
443 #header #header-inner #quick ul.repo_switcher {
444 max-height: 275px;
444 max-height: 275px;
445 overflow-x: hidden;
445 overflow-x: hidden;
446 overflow-y: auto;
446 overflow-y: auto;
447 }
447 }
448
448
449 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
449 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
450 padding: 2px 3px;
450 padding: 2px 3px;
451 padding-right: 17px;
451 padding-right: 17px;
452 }
452 }
453
453
454 #header #header-inner #quick ul.repo_switcher li.qfilter_rs input {
454 #header #header-inner #quick ul.repo_switcher li.qfilter_rs input {
455 width: 100%;
455 width: 100%;
456 border-radius: 10px;
456 border-radius: 10px;
457 padding: 2px 7px;
457 padding: 2px 7px;
458 }
458 }
459
459
460 #header #header-inner #quick .repo_switcher_type {
460 #header #header-inner #quick .repo_switcher_type {
461 position: absolute;
461 position: absolute;
462 left: 0;
462 left: 0;
463 top: 9px;
463 top: 9px;
464 margin: 0px 2px 0px 2px;
464 margin: 0px 2px 0px 2px;
465 }
465 }
466
466
467 #header #header-inner #quick li ul li a.journal, #header #header-inner #quick li ul li a.journal:hover {
467 #header #header-inner #quick li ul li a.journal, #header #header-inner #quick li ul li a.journal:hover {
468 background-image: url("../images/icons/book.png");
468 background-image: url("../images/icons/book.png");
469 }
469 }
470
470
471 #header #header-inner #quick li ul li a.private_repo, #header #header-inner #quick li ul li a.private_repo:hover {
471 #header #header-inner #quick li ul li a.private_repo, #header #header-inner #quick li ul li a.private_repo:hover {
472 background-image: url("../images/icons/lock.png")
472 background-image: url("../images/icons/lock.png")
473 }
473 }
474
474
475 #header #header-inner #quick li ul li a.public_repo, #header #header-inner #quick li ul li a.public_repo:hover {
475 #header #header-inner #quick li ul li a.public_repo, #header #header-inner #quick li ul li a.public_repo:hover {
476 background-image: url("../images/icons/lock_open.png");
476 background-image: url("../images/icons/lock_open.png");
477 }
477 }
478
478
479 #header #header-inner #quick li ul li a.hg, #header #header-inner #quick li ul li a.hg:hover {
479 #header #header-inner #quick li ul li a.hg, #header #header-inner #quick li ul li a.hg:hover {
480 background-image: url("../images/icons/hgicon.png");
480 background-image: url("../images/icons/hgicon.png");
481 padding-left: 42px;
481 padding-left: 42px;
482 background-position: 20px 9px;
482 background-position: 20px 9px;
483 }
483 }
484
484
485 #header #header-inner #quick li ul li a.git, #header #header-inner #quick li ul li a.git:hover {
485 #header #header-inner #quick li ul li a.git, #header #header-inner #quick li ul li a.git:hover {
486 background-image: url("../images/icons/giticon.png");
486 background-image: url("../images/icons/giticon.png");
487 padding-left: 42px;
487 padding-left: 42px;
488 background-position: 20px 9px;
488 background-position: 20px 9px;
489 }
489 }
490
490
491 #header #header-inner #quick li ul li a.repos, #header #header-inner #quick li ul li a.repos:hover {
491 #header #header-inner #quick li ul li a.repos, #header #header-inner #quick li ul li a.repos:hover {
492 background-image: url("../images/icons/database_edit.png");
492 background-image: url("../images/icons/database_edit.png");
493 }
493 }
494
494
495 #header #header-inner #quick li ul li a.repos_groups, #header #header-inner #quick li ul li a.repos_groups:hover {
495 #header #header-inner #quick li ul li a.repos_groups, #header #header-inner #quick li ul li a.repos_groups:hover {
496 background-image: url("../images/icons/database_link.png");
496 background-image: url("../images/icons/database_link.png");
497 }
497 }
498
498
499 #header #header-inner #quick li ul li a.users, #header #header-inner #quick li ul li a.users:hover {
499 #header #header-inner #quick li ul li a.users, #header #header-inner #quick li ul li a.users:hover {
500 background-image: url("../images/icons/user_edit.png");
500 background-image: url("../images/icons/user_edit.png");
501 }
501 }
502
502
503 #header #header-inner #quick li ul li a.groups, #header #header-inner #quick li ul li a.groups:hover {
503 #header #header-inner #quick li ul li a.groups, #header #header-inner #quick li ul li a.groups:hover {
504 background-image: url("../images/icons/group_edit.png");
504 background-image: url("../images/icons/group_edit.png");
505 }
505 }
506
506
507 #header #header-inner #quick li ul li a.defaults, #header #header-inner #quick li ul li a.defaults:hover {
507 #header #header-inner #quick li ul li a.defaults, #header #header-inner #quick li ul li a.defaults:hover {
508 background-image: url("../images/icons/wrench.png");
508 background-image: url("../images/icons/wrench.png");
509 }
509 }
510
510
511 #header #header-inner #quick li ul li a.settings, #header #header-inner #quick li ul li a.settings:hover {
511 #header #header-inner #quick li ul li a.settings, #header #header-inner #quick li ul li a.settings:hover {
512 background-image: url("../images/icons/cog.png");
512 background-image: url("../images/icons/cog.png");
513 }
513 }
514
514
515 #header #header-inner #quick li ul li a.permissions, #header #header-inner #quick li ul li a.permissions:hover {
515 #header #header-inner #quick li ul li a.permissions, #header #header-inner #quick li ul li a.permissions:hover {
516 background-image: url("../images/icons/key.png");
516 background-image: url("../images/icons/key.png");
517 }
517 }
518
518
519 #header #header-inner #quick li ul li a.ldap, #header #header-inner #quick li ul li a.ldap:hover {
519 #header #header-inner #quick li ul li a.ldap, #header #header-inner #quick li ul li a.ldap:hover {
520 background-image: url("../images/icons/server_key.png");
520 background-image: url("../images/icons/server_key.png");
521 }
521 }
522
522
523 #header #header-inner #quick li ul li a.fork, #header #header-inner #quick li ul li a.fork:hover {
523 #header #header-inner #quick li ul li a.fork, #header #header-inner #quick li ul li a.fork:hover {
524 background-image: url("../images/icons/arrow_divide.png");
524 background-image: url("../images/icons/arrow_divide.png");
525 }
525 }
526
526
527 #header #header-inner #quick li ul li a.locking_add, #header #header-inner #quick li ul li a.locking_add:hover {
527 #header #header-inner #quick li ul li a.locking_add, #header #header-inner #quick li ul li a.locking_add:hover {
528 background-image: url("../images/icons/lock_add.png");
528 background-image: url("../images/icons/lock_add.png");
529 }
529 }
530
530
531 #header #header-inner #quick li ul li a.locking_del, #header #header-inner #quick li ul li a.locking_del:hover {
531 #header #header-inner #quick li ul li a.locking_del, #header #header-inner #quick li ul li a.locking_del:hover {
532 background-image: url("../images/icons/lock_delete.png");
532 background-image: url("../images/icons/lock_delete.png");
533 }
533 }
534
534
535 #header #header-inner #quick li ul li a.pull_request, #header #header-inner #quick li ul li a.pull_request:hover {
535 #header #header-inner #quick li ul li a.pull_request, #header #header-inner #quick li ul li a.pull_request:hover {
536 background-image: url("../images/icons/arrow_join.png") ;
536 background-image: url("../images/icons/arrow_join.png") ;
537 }
537 }
538
538
539 #header #header-inner #quick li ul li a.compare_request, #header #header-inner #quick li ul li a.compare_request:hover {
539 #header #header-inner #quick li ul li a.compare_request, #header #header-inner #quick li ul li a.compare_request:hover {
540 background-image: url("../images/icons/arrow_inout.png");
540 background-image: url("../images/icons/arrow_inout.png");
541 }
541 }
542
542
543 #header #header-inner #quick li ul li a.search, #header #header-inner #quick li ul li a.search:hover {
543 #header #header-inner #quick li ul li a.search, #header #header-inner #quick li ul li a.search:hover {
544 background-image: url("../images/icons/search_16.png");
544 background-image: url("../images/icons/search_16.png");
545 }
545 }
546
546
547 #header #header-inner #quick li ul li a.delete, #header #header-inner #quick li ul li a.delete:hover {
547 #header #header-inner #quick li ul li a.delete, #header #header-inner #quick li ul li a.delete:hover {
548 background-image: url("../images/icons/delete.png");
548 background-image: url("../images/icons/delete.png");
549 }
549 }
550
550
551 #header #header-inner #quick li ul li a.branches, #header #header-inner #quick li ul li a.branches:hover {
551 #header #header-inner #quick li ul li a.branches, #header #header-inner #quick li ul li a.branches:hover {
552 background-image: url("../images/icons/arrow_branch.png");
552 background-image: url("../images/icons/arrow_branch.png");
553 }
553 }
554
554
555 #header #header-inner #quick li ul li a.tags,
555 #header #header-inner #quick li ul li a.tags,
556 #header #header-inner #quick li ul li a.tags:hover {
556 #header #header-inner #quick li ul li a.tags:hover {
557 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
557 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
558 width: 167px;
558 width: 167px;
559 margin: 0;
559 margin: 0;
560 padding: 12px 9px 7px 24px;
560 padding: 12px 9px 7px 24px;
561 }
561 }
562
562
563 #header #header-inner #quick li ul li a.bookmarks,
563 #header #header-inner #quick li ul li a.bookmarks,
564 #header #header-inner #quick li ul li a.bookmarks:hover {
564 #header #header-inner #quick li ul li a.bookmarks:hover {
565 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
565 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
566 width: 167px;
566 width: 167px;
567 margin: 0;
567 margin: 0;
568 padding: 12px 9px 7px 24px;
568 padding: 12px 9px 7px 24px;
569 }
569 }
570
570
571 #header #header-inner #quick li ul li a.admin,
571 #header #header-inner #quick li ul li a.admin,
572 #header #header-inner #quick li ul li a.admin:hover {
572 #header #header-inner #quick li ul li a.admin:hover {
573 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
573 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
574 width: 167px;
574 width: 167px;
575 margin: 0;
575 margin: 0;
576 padding: 12px 9px 7px 24px;
576 padding: 12px 9px 7px 24px;
577 }
577 }
578
578
579 .groups_breadcrumbs a {
579 .groups_breadcrumbs a {
580 color: #fff;
580 color: #fff;
581 }
581 }
582
582
583 .groups_breadcrumbs a:hover {
583 .groups_breadcrumbs a:hover {
584 color: #bfe3ff;
584 color: #bfe3ff;
585 text-decoration: none;
585 text-decoration: none;
586 }
586 }
587
587
588 td.quick_repo_menu {
588 td.quick_repo_menu {
589 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
589 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
590 cursor: pointer;
590 cursor: pointer;
591 width: 8px;
591 width: 8px;
592 border: 1px solid transparent;
592 border: 1px solid transparent;
593 }
593 }
594
594
595 td.quick_repo_menu.active {
595 td.quick_repo_menu.active {
596 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
596 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
597 border: 1px solid #003367;
597 border: 1px solid #003367;
598 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
598 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
599 cursor: pointer;
599 cursor: pointer;
600 }
600 }
601
601
602 td.quick_repo_menu .menu_items {
602 td.quick_repo_menu .menu_items {
603 margin-top: 10px;
603 margin-top: 10px;
604 margin-left: -6px;
604 margin-left: -6px;
605 width: 150px;
605 width: 150px;
606 position: absolute;
606 position: absolute;
607 background-color: #FFF;
607 background-color: #FFF;
608 background: none repeat scroll 0 0 #FFFFFF;
608 background: none repeat scroll 0 0 #FFFFFF;
609 border-color: #003367 #666666 #666666;
609 border-color: #003367 #666666 #666666;
610 border-right: 1px solid #666666;
610 border-right: 1px solid #666666;
611 border-style: solid;
611 border-style: solid;
612 border-width: 1px;
612 border-width: 1px;
613 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
613 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
614 border-top-style: none;
614 border-top-style: none;
615 }
615 }
616
616
617 td.quick_repo_menu .menu_items li {
617 td.quick_repo_menu .menu_items li {
618 padding: 0 !important;
618 padding: 0 !important;
619 }
619 }
620
620
621 td.quick_repo_menu .menu_items a {
621 td.quick_repo_menu .menu_items a {
622 display: block;
622 display: block;
623 padding: 4px 12px 4px 8px;
623 padding: 4px 12px 4px 8px;
624 }
624 }
625
625
626 td.quick_repo_menu .menu_items a:hover {
626 td.quick_repo_menu .menu_items a:hover {
627 background-color: #EEE;
627 background-color: #EEE;
628 text-decoration: none;
628 text-decoration: none;
629 }
629 }
630
630
631 td.quick_repo_menu .menu_items .icon img {
631 td.quick_repo_menu .menu_items .icon img {
632 margin-bottom: -2px;
632 margin-bottom: -2px;
633 }
633 }
634
634
635 td.quick_repo_menu .menu_items.hidden {
635 td.quick_repo_menu .menu_items.hidden {
636 display: none;
636 display: none;
637 }
637 }
638
638
639 .yui-dt-first th {
639 .yui-dt-first th {
640 text-align: left;
640 text-align: left;
641 }
641 }
642
642
643 /*
643 /*
644 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
644 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
645 Code licensed under the BSD License:
645 Code licensed under the BSD License:
646 http://developer.yahoo.com/yui/license.html
646 http://developer.yahoo.com/yui/license.html
647 version: 2.9.0
647 version: 2.9.0
648 */
648 */
649 .yui-skin-sam .yui-dt-mask {
649 .yui-skin-sam .yui-dt-mask {
650 position: absolute;
650 position: absolute;
651 z-index: 9500;
651 z-index: 9500;
652 }
652 }
653 .yui-dt-tmp {
653 .yui-dt-tmp {
654 position: absolute;
654 position: absolute;
655 left: -9000px;
655 left: -9000px;
656 }
656 }
657 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
657 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
658 .yui-dt-scrollable .yui-dt-hd {
658 .yui-dt-scrollable .yui-dt-hd {
659 overflow: hidden;
659 overflow: hidden;
660 position: relative;
660 position: relative;
661 }
661 }
662 .yui-dt-scrollable .yui-dt-bd thead tr,
662 .yui-dt-scrollable .yui-dt-bd thead tr,
663 .yui-dt-scrollable .yui-dt-bd thead th {
663 .yui-dt-scrollable .yui-dt-bd thead th {
664 position: absolute;
664 position: absolute;
665 left: -1500px;
665 left: -1500px;
666 }
666 }
667 .yui-dt-scrollable tbody { -moz-outline: 0 }
667 .yui-dt-scrollable tbody { -moz-outline: 0 }
668 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
668 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
669 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
669 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
670 .yui-dt-coltarget {
670 .yui-dt-coltarget {
671 position: absolute;
671 position: absolute;
672 z-index: 999;
672 z-index: 999;
673 }
673 }
674 .yui-dt-hd { zoom: 1 }
674 .yui-dt-hd { zoom: 1 }
675 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
675 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
676 .yui-dt-resizer {
676 .yui-dt-resizer {
677 position: absolute;
677 position: absolute;
678 right: 0;
678 right: 0;
679 bottom: 0;
679 bottom: 0;
680 height: 100%;
680 height: 100%;
681 cursor: e-resize;
681 cursor: e-resize;
682 cursor: col-resize;
682 cursor: col-resize;
683 background-color: #CCC;
683 background-color: #CCC;
684 opacity: 0;
684 opacity: 0;
685 filter: alpha(opacity=0);
685 filter: alpha(opacity=0);
686 }
686 }
687 .yui-dt-resizerproxy {
687 .yui-dt-resizerproxy {
688 visibility: hidden;
688 visibility: hidden;
689 position: absolute;
689 position: absolute;
690 z-index: 9000;
690 z-index: 9000;
691 background-color: #CCC;
691 background-color: #CCC;
692 opacity: 0;
692 opacity: 0;
693 filter: alpha(opacity=0);
693 filter: alpha(opacity=0);
694 }
694 }
695 th.yui-dt-hidden .yui-dt-liner,
695 th.yui-dt-hidden .yui-dt-liner,
696 td.yui-dt-hidden .yui-dt-liner,
696 td.yui-dt-hidden .yui-dt-liner,
697 th.yui-dt-hidden .yui-dt-resizer { display: none }
697 th.yui-dt-hidden .yui-dt-resizer { display: none }
698 .yui-dt-editor,
698 .yui-dt-editor,
699 .yui-dt-editor-shim {
699 .yui-dt-editor-shim {
700 position: absolute;
700 position: absolute;
701 z-index: 9000;
701 z-index: 9000;
702 }
702 }
703 .yui-skin-sam .yui-dt table {
703 .yui-skin-sam .yui-dt table {
704 margin: 0;
704 margin: 0;
705 padding: 0;
705 padding: 0;
706 font-family: arial;
706 font-family: arial;
707 font-size: inherit;
707 font-size: inherit;
708 border-collapse: separate;
708 border-collapse: separate;
709 *border-collapse: collapse;
709 *border-collapse: collapse;
710 border-spacing: 0;
710 border-spacing: 0;
711 border: 1px solid #7f7f7f;
711 border: 1px solid #7f7f7f;
712 }
712 }
713 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
713 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
714 .yui-skin-sam .yui-dt caption {
714 .yui-skin-sam .yui-dt caption {
715 color: #000;
715 color: #000;
716 font-size: 85%;
716 font-size: 85%;
717 font-weight: normal;
717 font-weight: normal;
718 font-style: italic;
718 font-style: italic;
719 line-height: 1;
719 line-height: 1;
720 padding: 1em 0;
720 padding: 1em 0;
721 text-align: center;
721 text-align: center;
722 }
722 }
723 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
723 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
724 .yui-skin-sam .yui-dt th,
724 .yui-skin-sam .yui-dt th,
725 .yui-skin-sam .yui-dt th a {
725 .yui-skin-sam .yui-dt th a {
726 font-weight: normal;
726 font-weight: normal;
727 text-decoration: none;
727 text-decoration: none;
728 color: #000;
728 color: #000;
729 vertical-align: bottom;
729 vertical-align: bottom;
730 }
730 }
731 .yui-skin-sam .yui-dt th {
731 .yui-skin-sam .yui-dt th {
732 margin: 0;
732 margin: 0;
733 padding: 0;
733 padding: 0;
734 border: 0;
734 border: 0;
735 border-right: 1px solid #cbcbcb;
735 border-right: 1px solid #cbcbcb;
736 }
736 }
737 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
737 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
738 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
738 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
739 .yui-skin-sam .yui-dt-liner {
739 .yui-skin-sam .yui-dt-liner {
740 margin: 0;
740 margin: 0;
741 padding: 0;
741 padding: 0;
742 }
742 }
743 .yui-skin-sam .yui-dt-coltarget {
743 .yui-skin-sam .yui-dt-coltarget {
744 width: 5px;
744 width: 5px;
745 background-color: red;
745 background-color: red;
746 }
746 }
747 .yui-skin-sam .yui-dt td {
747 .yui-skin-sam .yui-dt td {
748 margin: 0;
748 margin: 0;
749 padding: 0;
749 padding: 0;
750 border: 0;
750 border: 0;
751 border-right: 1px solid #cbcbcb;
751 border-right: 1px solid #cbcbcb;
752 text-align: left;
752 text-align: left;
753 }
753 }
754 .yui-skin-sam .yui-dt-list td { border-right: 0 }
754 .yui-skin-sam .yui-dt-list td { border-right: 0 }
755 .yui-skin-sam .yui-dt-resizer { width: 6px }
755 .yui-skin-sam .yui-dt-resizer { width: 6px }
756 .yui-skin-sam .yui-dt-mask {
756 .yui-skin-sam .yui-dt-mask {
757 background-color: #000;
757 background-color: #000;
758 opacity: .25;
758 opacity: .25;
759 filter: alpha(opacity=25);
759 filter: alpha(opacity=25);
760 }
760 }
761 .yui-skin-sam .yui-dt-message { background-color: #FFF }
761 .yui-skin-sam .yui-dt-message { background-color: #FFF }
762 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
762 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
763 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
763 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
764 border-left: 1px solid #7f7f7f;
764 border-left: 1px solid #7f7f7f;
765 border-top: 1px solid #7f7f7f;
765 border-top: 1px solid #7f7f7f;
766 border-right: 1px solid #7f7f7f;
766 border-right: 1px solid #7f7f7f;
767 }
767 }
768 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
768 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
769 border-left: 1px solid #7f7f7f;
769 border-left: 1px solid #7f7f7f;
770 border-bottom: 1px solid #7f7f7f;
770 border-bottom: 1px solid #7f7f7f;
771 border-right: 1px solid #7f7f7f;
771 border-right: 1px solid #7f7f7f;
772 background-color: #FFF;
772 background-color: #FFF;
773 }
773 }
774 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
774 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
775 .yui-skin-sam th.yui-dt-asc,
775 .yui-skin-sam th.yui-dt-asc,
776 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
776 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
777 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
777 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
778 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
778 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
779 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
779 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
780 tbody .yui-dt-editable { cursor: pointer }
780 tbody .yui-dt-editable { cursor: pointer }
781 .yui-dt-editor {
781 .yui-dt-editor {
782 text-align: left;
782 text-align: left;
783 background-color: #f2f2f2;
783 background-color: #f2f2f2;
784 border: 1px solid #808080;
784 border: 1px solid #808080;
785 padding: 6px;
785 padding: 6px;
786 }
786 }
787 .yui-dt-editor label {
787 .yui-dt-editor label {
788 padding-left: 4px;
788 padding-left: 4px;
789 padding-right: 6px;
789 padding-right: 6px;
790 }
790 }
791 .yui-dt-editor .yui-dt-button {
791 .yui-dt-editor .yui-dt-button {
792 padding-top: 6px;
792 padding-top: 6px;
793 text-align: right;
793 text-align: right;
794 }
794 }
795 .yui-dt-editor .yui-dt-button button {
795 .yui-dt-editor .yui-dt-button button {
796 background: url(../images/sprite.png) repeat-x 0 0;
796 background: url(../images/sprite.png) repeat-x 0 0;
797 border: 1px solid #999;
797 border: 1px solid #999;
798 width: 4em;
798 width: 4em;
799 height: 1.8em;
799 height: 1.8em;
800 margin-left: 6px;
800 margin-left: 6px;
801 }
801 }
802 .yui-dt-editor .yui-dt-button button.yui-dt-default {
802 .yui-dt-editor .yui-dt-button button.yui-dt-default {
803 background: url(../images/sprite.png) repeat-x 0 -1400px;
803 background: url(../images/sprite.png) repeat-x 0 -1400px;
804 background-color: #5584e0;
804 background-color: #5584e0;
805 border: 1px solid #304369;
805 border: 1px solid #304369;
806 color: #FFF;
806 color: #FFF;
807 }
807 }
808 .yui-dt-editor .yui-dt-button button:hover {
808 .yui-dt-editor .yui-dt-button button:hover {
809 background: url(../images/sprite.png) repeat-x 0 -1300px;
809 background: url(../images/sprite.png) repeat-x 0 -1300px;
810 color: #000;
810 color: #000;
811 }
811 }
812 .yui-dt-editor .yui-dt-button button:active {
812 .yui-dt-editor .yui-dt-button button:active {
813 background: url(../images/sprite.png) repeat-x 0 -1700px;
813 background: url(../images/sprite.png) repeat-x 0 -1700px;
814 color: #000;
814 color: #000;
815 }
815 }
816 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
816 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
817 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
817 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
818 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
818 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
819 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
819 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
820 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
820 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
821 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
821 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
822 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
822 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
823 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
823 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
824 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
824 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
825 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
825 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
826 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
826 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
827 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
827 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
828 .yui-skin-sam th.yui-dt-highlighted,
828 .yui-skin-sam th.yui-dt-highlighted,
829 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
829 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
830 .yui-skin-sam tr.yui-dt-highlighted,
830 .yui-skin-sam tr.yui-dt-highlighted,
831 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
831 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
832 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
832 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
833 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
833 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
834 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
834 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
835 cursor: pointer;
835 cursor: pointer;
836 background-color: #b2d2ff;
836 background-color: #b2d2ff;
837 }
837 }
838 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
838 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
839 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
839 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
840 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
840 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
841 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
841 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
842 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
842 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
843 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
843 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
844 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
844 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
845 cursor: pointer;
845 cursor: pointer;
846 background-color: #b2d2ff;
846 background-color: #b2d2ff;
847 }
847 }
848 .yui-skin-sam th.yui-dt-selected,
848 .yui-skin-sam th.yui-dt-selected,
849 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
849 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
850 .yui-skin-sam tr.yui-dt-selected td,
850 .yui-skin-sam tr.yui-dt-selected td,
851 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
851 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
852 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
852 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
853 background-color: #426fd9;
853 background-color: #426fd9;
854 color: #FFF;
854 color: #FFF;
855 }
855 }
856 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
856 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
857 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
857 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
858 background-color: #446cd7;
858 background-color: #446cd7;
859 color: #FFF;
859 color: #FFF;
860 }
860 }
861 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
861 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
862 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
862 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
863 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
863 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
864 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
864 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
865 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
865 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
866 background-color: #426fd9;
866 background-color: #426fd9;
867 color: #FFF;
867 color: #FFF;
868 }
868 }
869 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
869 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
870 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
870 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
871 background-color: #446cd7;
871 background-color: #446cd7;
872 color: #FFF;
872 color: #FFF;
873 }
873 }
874 .yui-skin-sam .yui-dt-paginator {
874 .yui-skin-sam .yui-dt-paginator {
875 display: block;
875 display: block;
876 margin: 6px 0;
876 margin: 6px 0;
877 white-space: nowrap;
877 white-space: nowrap;
878 }
878 }
879 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
879 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
880 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
880 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
881 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
881 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
882 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
882 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
883 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
883 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
884 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
884 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
885 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
885 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
886 .yui-skin-sam a.yui-dt-page {
886 .yui-skin-sam a.yui-dt-page {
887 border: 1px solid #cbcbcb;
887 border: 1px solid #cbcbcb;
888 padding: 2px 6px;
888 padding: 2px 6px;
889 text-decoration: none;
889 text-decoration: none;
890 background-color: #fff;
890 background-color: #fff;
891 }
891 }
892 .yui-skin-sam .yui-dt-selected {
892 .yui-skin-sam .yui-dt-selected {
893 border: 1px solid #fff;
893 border: 1px solid #fff;
894 background-color: #fff;
894 background-color: #fff;
895 }
895 }
896
896
897 #content #left {
897 #content #left {
898 left: 0;
898 left: 0;
899 width: 280px;
899 width: 280px;
900 position: absolute;
900 position: absolute;
901 }
901 }
902
902
903 #content #right {
903 #content #right {
904 margin: 0 60px 10px 290px;
904 margin: 0 60px 10px 290px;
905 }
905 }
906
906
907 #content div.box {
907 #content div.box {
908 clear: both;
908 clear: both;
909 background: #fff;
909 background: #fff;
910 margin: 0 0 10px;
910 margin: 0 0 10px;
911 padding: 0 0 10px;
911 padding: 0 0 10px;
912 -webkit-border-radius: 4px 4px 4px 4px;
912 -webkit-border-radius: 4px 4px 4px 4px;
913 -khtml-border-radius: 4px 4px 4px 4px;
913 -khtml-border-radius: 4px 4px 4px 4px;
914 border-radius: 4px 4px 4px 4px;
914 border-radius: 4px 4px 4px 4px;
915 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
915 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
916 }
916 }
917
917
918 #content div.box-left {
918 #content div.box-left {
919 width: 49%;
919 width: 49%;
920 clear: none;
920 clear: none;
921 float: left;
921 float: left;
922 margin: 0 0 10px;
922 margin: 0 0 10px;
923 }
923 }
924
924
925 #content div.box-right {
925 #content div.box-right {
926 width: 49%;
926 width: 49%;
927 clear: none;
927 clear: none;
928 float: right;
928 float: right;
929 margin: 0 0 10px;
929 margin: 0 0 10px;
930 }
930 }
931
931
932 #content div.box div.title {
932 #content div.box div.title {
933 clear: both;
933 clear: both;
934 overflow: hidden;
934 overflow: hidden;
935 background-color: #003B76;
935 background-color: #003B76;
936 background-repeat: repeat-x;
936 background-repeat: repeat-x;
937 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
937 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
938 background-image: -moz-linear-gradient(top, #003b76, #00376e);
938 background-image: -moz-linear-gradient(top, #003b76, #00376e);
939 background-image: -ms-linear-gradient(top, #003b76, #00376e);
939 background-image: -ms-linear-gradient(top, #003b76, #00376e);
940 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
940 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
941 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
941 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
942 background-image: -o-linear-gradient(top, #003b76, #00376e);
942 background-image: -o-linear-gradient(top, #003b76, #00376e);
943 background-image: linear-gradient(to bottom, #003b76, #00376e);
943 background-image: linear-gradient(to bottom, #003b76, #00376e);
944 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
944 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
945 margin: 0 0 20px;
945 margin: 0 0 20px;
946 padding: 0;
946 padding: 0;
947 border-radius: 4px 4px 0 0;
947 border-radius: 4px 4px 0 0;
948 }
948 }
949
949
950 #content div.box div.title h5 {
950 #content div.box div.title h5 {
951 float: left;
951 float: left;
952 border: none;
952 border: none;
953 color: #fff;
953 color: #fff;
954 margin: 0;
954 margin: 0;
955 padding: 11px 0 11px 10px;
955 padding: 11px 0 11px 10px;
956 }
956 }
957
957
958 #content div.box div.title .link-white {
958 #content div.box div.title .link-white {
959 color: #FFFFFF;
959 color: #FFFFFF;
960 }
960 }
961
961
962 #content div.box div.title .link-white.current {
962 #content div.box div.title .link-white.current {
963 color: #BFE3FF;
963 color: #BFE3FF;
964 }
964 }
965
965
966 #content div.box div.title ul.links li {
966 #content div.box div.title ul.links li {
967 list-style: none;
967 list-style: none;
968 float: left;
968 float: left;
969 margin: 0;
969 margin: 0;
970 padding: 0;
970 padding: 0;
971 }
971 }
972
972
973 #content div.box div.title ul.links li a {
973 #content div.box div.title ul.links li a {
974 border-left: 1px solid #316293;
974 border-left: 1px solid #316293;
975 color: #FFFFFF;
975 color: #FFFFFF;
976 display: block;
976 display: block;
977 float: left;
977 float: left;
978 font-size: 13px;
978 font-size: 13px;
979 font-weight: 700;
979 font-weight: 700;
980 height: 1%;
980 height: 1%;
981 margin: 0;
981 margin: 0;
982 padding: 11px 22px 12px;
982 padding: 11px 22px 12px;
983 text-decoration: none;
983 text-decoration: none;
984 }
984 }
985
985
986 #content div.box h1, #content div.box h2, #content div.box h3, #content div.box h4, #content div.box h5, #content div.box h6,
986 #content div.box h1, #content div.box h2, #content div.box h3, #content div.box h4, #content div.box h5, #content div.box h6,
987 #content div.box div.h1, #content div.box div.h2, #content div.box div.h3, #content div.box div.h4, #content div.box div.h5, #content div.box div.h6 {
987 #content div.box div.h1, #content div.box div.h2, #content div.box div.h3, #content div.box div.h4, #content div.box div.h5, #content div.box div.h6 {
988 clear: both;
988 clear: both;
989 overflow: hidden;
989 overflow: hidden;
990 border-bottom: 1px solid #DDD;
990 border-bottom: 1px solid #DDD;
991 margin: 10px 20px;
991 margin: 10px 20px;
992 padding: 0 0 15px;
992 padding: 0 0 15px;
993 }
993 }
994
994
995 #content div.box p {
995 #content div.box p {
996 color: #5f5f5f;
996 color: #5f5f5f;
997 font-size: 12px;
997 font-size: 12px;
998 line-height: 150%;
998 line-height: 150%;
999 margin: 0 24px 10px;
999 margin: 0 24px 10px;
1000 padding: 0;
1000 padding: 0;
1001 }
1001 }
1002
1002
1003 #content div.box blockquote {
1003 #content div.box blockquote {
1004 border-left: 4px solid #DDD;
1004 border-left: 4px solid #DDD;
1005 color: #5f5f5f;
1005 color: #5f5f5f;
1006 font-size: 11px;
1006 font-size: 11px;
1007 line-height: 150%;
1007 line-height: 150%;
1008 margin: 0 34px;
1008 margin: 0 34px;
1009 padding: 0 0 0 14px;
1009 padding: 0 0 0 14px;
1010 }
1010 }
1011
1011
1012 #content div.box blockquote p {
1012 #content div.box blockquote p {
1013 margin: 10px 0;
1013 margin: 10px 0;
1014 padding: 0;
1014 padding: 0;
1015 }
1015 }
1016
1016
1017 #content div.box dl {
1017 #content div.box dl {
1018 margin: 10px 0px;
1018 margin: 10px 0px;
1019 }
1019 }
1020
1020
1021 #content div.box dt {
1021 #content div.box dt {
1022 font-size: 12px;
1022 font-size: 12px;
1023 margin: 0;
1023 margin: 0;
1024 }
1024 }
1025
1025
1026 #content div.box dd {
1026 #content div.box dd {
1027 font-size: 12px;
1027 font-size: 12px;
1028 margin: 0;
1028 margin: 0;
1029 padding: 8px 0 8px 15px;
1029 padding: 8px 0 8px 15px;
1030 }
1030 }
1031
1031
1032 #content div.box li {
1032 #content div.box li {
1033 font-size: 12px;
1033 font-size: 12px;
1034 padding: 4px 0;
1034 padding: 4px 0;
1035 }
1035 }
1036
1036
1037 #content div.box ul.disc, #content div.box ul.circle {
1037 #content div.box ul.disc, #content div.box ul.circle {
1038 margin: 10px 24px 10px 38px;
1038 margin: 10px 24px 10px 38px;
1039 }
1039 }
1040
1040
1041 #content div.box ul.square {
1041 #content div.box ul.square {
1042 margin: 10px 24px 10px 40px;
1042 margin: 10px 24px 10px 40px;
1043 }
1043 }
1044
1044
1045 #content div.box img.left {
1045 #content div.box img.left {
1046 border: none;
1046 border: none;
1047 float: left;
1047 float: left;
1048 margin: 10px 10px 10px 0;
1048 margin: 10px 10px 10px 0;
1049 }
1049 }
1050
1050
1051 #content div.box img.right {
1051 #content div.box img.right {
1052 border: none;
1052 border: none;
1053 float: right;
1053 float: right;
1054 margin: 10px 0 10px 10px;
1054 margin: 10px 0 10px 10px;
1055 }
1055 }
1056
1056
1057 #content div.box div.messages {
1057 #content div.box div.messages {
1058 clear: both;
1058 clear: both;
1059 overflow: hidden;
1059 overflow: hidden;
1060 margin: 0 20px;
1060 margin: 0 20px;
1061 padding: 0;
1061 padding: 0;
1062 }
1062 }
1063
1063
1064 #content div.box div.message {
1064 #content div.box div.message {
1065 clear: both;
1065 clear: both;
1066 overflow: hidden;
1066 overflow: hidden;
1067 margin: 0;
1067 margin: 0;
1068 padding: 5px 0;
1068 padding: 5px 0;
1069 white-space: pre-wrap;
1069 white-space: pre-wrap;
1070 }
1070 }
1071 #content div.box div.expand {
1071 #content div.box div.expand {
1072 width: 110%;
1072 width: 110%;
1073 height: 14px;
1073 height: 14px;
1074 font-size: 10px;
1074 font-size: 10px;
1075 text-align: center;
1075 text-align: center;
1076 cursor: pointer;
1076 cursor: pointer;
1077 color: #666;
1077 color: #666;
1078
1078
1079 background: -webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1079 background: -webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1080 background: -webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1080 background: -webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1081 background: -moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1081 background: -moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1082 background: -o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1082 background: -o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1083 background: -ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1083 background: -ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1084 background: linear-gradient(to bottom,rgba(255,255,255,0),rgba(64,96,128,0.1));
1084 background: linear-gradient(to bottom,rgba(255,255,255,0),rgba(64,96,128,0.1));
1085
1085
1086 display: none;
1086 display: none;
1087 overflow: hidden;
1087 overflow: hidden;
1088 }
1088 }
1089 #content div.box div.expand .expandtext {
1089 #content div.box div.expand .expandtext {
1090 background-color: #ffffff;
1090 background-color: #ffffff;
1091 padding: 2px;
1091 padding: 2px;
1092 border-radius: 2px;
1092 border-radius: 2px;
1093 }
1093 }
1094
1094
1095 #content div.box div.message a {
1095 #content div.box div.message a {
1096 font-weight: 400 !important;
1096 font-weight: 400 !important;
1097 }
1097 }
1098
1098
1099 #content div.box div.message div.image {
1099 #content div.box div.message div.image {
1100 float: left;
1100 float: left;
1101 margin: 9px 0 0 5px;
1101 margin: 9px 0 0 5px;
1102 padding: 6px;
1102 padding: 6px;
1103 }
1103 }
1104
1104
1105 #content div.box div.message div.image img {
1105 #content div.box div.message div.image img {
1106 vertical-align: middle;
1106 vertical-align: middle;
1107 margin: 0;
1107 margin: 0;
1108 }
1108 }
1109
1109
1110 #content div.box div.message div.text {
1110 #content div.box div.message div.text {
1111 float: left;
1111 float: left;
1112 margin: 0;
1112 margin: 0;
1113 padding: 9px 6px;
1113 padding: 9px 6px;
1114 }
1114 }
1115
1115
1116 #content div.box div.message div.dismiss a {
1116 #content div.box div.message div.dismiss a {
1117 height: 16px;
1117 height: 16px;
1118 width: 16px;
1118 width: 16px;
1119 display: block;
1119 display: block;
1120 background: url("../images/icons/cross.png") no-repeat;
1120 background: url("../images/icons/cross.png") no-repeat;
1121 margin: 15px 14px 0 0;
1121 margin: 15px 14px 0 0;
1122 padding: 0;
1122 padding: 0;
1123 }
1123 }
1124
1124
1125 #content div.box div.message div.text h1, #content div.box div.message div.text h2, #content div.box div.message div.text h3, #content div.box div.message div.text h4, #content div.box div.message div.text h5, #content div.box div.message div.text h6 {
1125 #content div.box div.message div.text h1, #content div.box div.message div.text h2, #content div.box div.message div.text h3, #content div.box div.message div.text h4, #content div.box div.message div.text h5, #content div.box div.message div.text h6 {
1126 border: none;
1126 border: none;
1127 margin: 0;
1127 margin: 0;
1128 padding: 0;
1128 padding: 0;
1129 }
1129 }
1130
1130
1131 #content div.box div.message div.text span {
1131 #content div.box div.message div.text span {
1132 height: 1%;
1132 height: 1%;
1133 display: block;
1133 display: block;
1134 margin: 0;
1134 margin: 0;
1135 padding: 5px 0 0;
1135 padding: 5px 0 0;
1136 }
1136 }
1137
1137
1138 #content div.box div.message-error {
1138 #content div.box div.message-error {
1139 height: 1%;
1139 height: 1%;
1140 clear: both;
1140 clear: both;
1141 overflow: hidden;
1141 overflow: hidden;
1142 background: #FBE3E4;
1142 background: #FBE3E4;
1143 border: 1px solid #FBC2C4;
1143 border: 1px solid #FBC2C4;
1144 color: #860006;
1144 color: #860006;
1145 }
1145 }
1146
1146
1147 #content div.box div.message-error h6 {
1147 #content div.box div.message-error h6 {
1148 color: #860006;
1148 color: #860006;
1149 }
1149 }
1150
1150
1151 #content div.box div.message-warning {
1151 #content div.box div.message-warning {
1152 height: 1%;
1152 height: 1%;
1153 clear: both;
1153 clear: both;
1154 overflow: hidden;
1154 overflow: hidden;
1155 background: #FFF6BF;
1155 background: #FFF6BF;
1156 border: 1px solid #FFD324;
1156 border: 1px solid #FFD324;
1157 color: #5f5200;
1157 color: #5f5200;
1158 }
1158 }
1159
1159
1160 #content div.box div.message-warning h6 {
1160 #content div.box div.message-warning h6 {
1161 color: #5f5200;
1161 color: #5f5200;
1162 }
1162 }
1163
1163
1164 #content div.box div.message-notice {
1164 #content div.box div.message-notice {
1165 height: 1%;
1165 height: 1%;
1166 clear: both;
1166 clear: both;
1167 overflow: hidden;
1167 overflow: hidden;
1168 background: #8FBDE0;
1168 background: #8FBDE0;
1169 border: 1px solid #6BACDE;
1169 border: 1px solid #6BACDE;
1170 color: #003863;
1170 color: #003863;
1171 }
1171 }
1172
1172
1173 #content div.box div.message-notice h6 {
1173 #content div.box div.message-notice h6 {
1174 color: #003863;
1174 color: #003863;
1175 }
1175 }
1176
1176
1177 #content div.box div.message-success {
1177 #content div.box div.message-success {
1178 height: 1%;
1178 height: 1%;
1179 clear: both;
1179 clear: both;
1180 overflow: hidden;
1180 overflow: hidden;
1181 background: #E6EFC2;
1181 background: #E6EFC2;
1182 border: 1px solid #C6D880;
1182 border: 1px solid #C6D880;
1183 color: #4e6100;
1183 color: #4e6100;
1184 }
1184 }
1185
1185
1186 #content div.box div.message-success h6 {
1186 #content div.box div.message-success h6 {
1187 color: #4e6100;
1187 color: #4e6100;
1188 }
1188 }
1189
1189
1190 #content div.box div.form div.fields div.field {
1190 #content div.box div.form div.fields div.field {
1191 height: 1%;
1191 height: 1%;
1192 min-height: 12px;
1192 min-height: 12px;
1193 border-bottom: 1px solid #DDD;
1193 border-bottom: 1px solid #DDD;
1194 clear: both;
1194 clear: both;
1195 margin: 0;
1195 margin: 0;
1196 padding: 10px 0;
1196 padding: 10px 0;
1197 }
1197 }
1198
1198
1199 #content div.box div.form div.fields div.field-first {
1199 #content div.box div.form div.fields div.field-first {
1200 padding: 0 0 10px;
1200 padding: 0 0 10px;
1201 }
1201 }
1202
1202
1203 #content div.box div.form div.fields div.field-noborder {
1203 #content div.box div.form div.fields div.field-noborder {
1204 border-bottom: 0 !important;
1204 border-bottom: 0 !important;
1205 }
1205 }
1206
1206
1207 #content div.box div.form div.fields div.field span.error-message {
1207 #content div.box div.form div.fields div.field span.error-message {
1208 height: 1%;
1208 height: 1%;
1209 display: inline-block;
1209 display: inline-block;
1210 color: red;
1210 color: red;
1211 margin: 8px 0 0 4px;
1211 margin: 8px 0 0 4px;
1212 padding: 0;
1212 padding: 0;
1213 }
1213 }
1214
1214
1215 #content div.box div.form div.fields div.field span.success {
1215 #content div.box div.form div.fields div.field span.success {
1216 height: 1%;
1216 height: 1%;
1217 display: block;
1217 display: block;
1218 color: #316309;
1218 color: #316309;
1219 margin: 8px 0 0;
1219 margin: 8px 0 0;
1220 padding: 0;
1220 padding: 0;
1221 }
1221 }
1222
1222
1223 #content div.box div.form div.fields div.field div.label {
1223 #content div.box div.form div.fields div.field div.label {
1224 left: 70px;
1224 left: 70px;
1225 width: 155px;
1225 width: 155px;
1226 position: absolute;
1226 position: absolute;
1227 margin: 0;
1227 margin: 0;
1228 padding: 5px 0 0 0px;
1228 padding: 5px 0 0 0px;
1229 }
1229 }
1230
1230
1231 #content div.box div.form div.fields div.field div.label-summary {
1231 #content div.box div.form div.fields div.field div.label-summary {
1232 left: 30px;
1232 left: 30px;
1233 width: 155px;
1233 width: 155px;
1234 position: absolute;
1234 position: absolute;
1235 margin: 0;
1235 margin: 0;
1236 padding: 0px 0 0 0px;
1236 padding: 0px 0 0 0px;
1237 }
1237 }
1238
1238
1239 #content div.box-left div.form div.fields div.field div.label,
1239 #content div.box-left div.form div.fields div.field div.label,
1240 #content div.box-right div.form div.fields div.field div.label,
1240 #content div.box-right div.form div.fields div.field div.label,
1241 #content div.box-left div.form div.fields div.field div.label,
1241 #content div.box-left div.form div.fields div.field div.label,
1242 #content div.box-left div.form div.fields div.field div.label-summary,
1242 #content div.box-left div.form div.fields div.field div.label-summary,
1243 #content div.box-right div.form div.fields div.field div.label-summary,
1243 #content div.box-right div.form div.fields div.field div.label-summary,
1244 #content div.box-left div.form div.fields div.field div.label-summary {
1244 #content div.box-left div.form div.fields div.field div.label-summary {
1245 clear: both;
1245 clear: both;
1246 overflow: hidden;
1246 overflow: hidden;
1247 left: 0;
1247 left: 0;
1248 width: auto;
1248 width: auto;
1249 position: relative;
1249 position: relative;
1250 margin: 0;
1250 margin: 0;
1251 padding: 0 0 8px;
1251 padding: 0 0 8px;
1252 }
1252 }
1253
1253
1254 #content div.box div.form div.fields div.field div.label-select {
1254 #content div.box div.form div.fields div.field div.label-select {
1255 padding: 5px 0 0 5px;
1255 padding: 5px 0 0 5px;
1256 }
1256 }
1257
1257
1258 #content div.box-left div.form div.fields div.field div.label-select,
1258 #content div.box-left div.form div.fields div.field div.label-select,
1259 #content div.box-right div.form div.fields div.field div.label-select {
1259 #content div.box-right div.form div.fields div.field div.label-select {
1260 padding: 0 0 8px;
1260 padding: 0 0 8px;
1261 }
1261 }
1262
1262
1263 #content div.box-left div.form div.fields div.field div.label-textarea,
1263 #content div.box-left div.form div.fields div.field div.label-textarea,
1264 #content div.box-right div.form div.fields div.field div.label-textarea {
1264 #content div.box-right div.form div.fields div.field div.label-textarea {
1265 padding: 0 0 8px !important;
1265 padding: 0 0 8px !important;
1266 }
1266 }
1267
1267
1268 #content div.box div.form div.fields div.field div.label label, div.label label {
1268 #content div.box div.form div.fields div.field div.label label, div.label label {
1269 color: #393939;
1269 color: #393939;
1270 font-weight: 700;
1270 font-weight: 700;
1271 }
1271 }
1272 #content div.box div.form div.fields div.field div.label label, div.label-summary label {
1272 #content div.box div.form div.fields div.field div.label label, div.label-summary label {
1273 color: #393939;
1273 color: #393939;
1274 font-weight: 700;
1274 font-weight: 700;
1275 }
1275 }
1276 #content div.box div.form div.fields div.field div.input {
1276 #content div.box div.form div.fields div.field div.input {
1277 margin: 0 0 0 200px;
1277 margin: 0 0 0 200px;
1278 }
1278 }
1279
1279
1280 #content div.box div.form div.fields div.field div.input.summary {
1280 #content div.box div.form div.fields div.field div.input.summary {
1281 margin: 0 0 0 110px;
1281 margin: 0 0 0 110px;
1282 }
1282 }
1283 #content div.box div.form div.fields div.field div.input.summary-short {
1283 #content div.box div.form div.fields div.field div.input.summary-short {
1284 margin: 0 0 0 110px;
1284 margin: 0 0 0 110px;
1285 }
1285 }
1286 #content div.box div.form div.fields div.field div.file {
1286 #content div.box div.form div.fields div.field div.file {
1287 margin: 0 0 0 200px;
1287 margin: 0 0 0 200px;
1288 }
1288 }
1289
1289
1290 #content div.box-left div.form div.fields div.field div.input, #content div.box-right div.form div.fields div.field div.input {
1290 #content div.box-left div.form div.fields div.field div.input, #content div.box-right div.form div.fields div.field div.input {
1291 margin: 0 0 0 0px;
1291 margin: 0 0 0 0px;
1292 }
1292 }
1293
1293
1294 #content div.box div.form div.fields div.field div.input input,
1294 #content div.box div.form div.fields div.field div.input input,
1295 .reviewer_ac input {
1295 .reviewer_ac input {
1296 background: #FFF;
1296 background: #FFF;
1297 border-top: 1px solid #b3b3b3;
1297 border-top: 1px solid #b3b3b3;
1298 border-left: 1px solid #b3b3b3;
1298 border-left: 1px solid #b3b3b3;
1299 border-right: 1px solid #eaeaea;
1299 border-right: 1px solid #eaeaea;
1300 border-bottom: 1px solid #eaeaea;
1300 border-bottom: 1px solid #eaeaea;
1301 color: #000;
1301 color: #000;
1302 font-size: 11px;
1302 font-size: 11px;
1303 margin: 0;
1303 margin: 0;
1304 padding: 7px 7px 6px;
1304 padding: 7px 7px 6px;
1305 }
1305 }
1306
1306
1307 #content div.box div.form div.fields div.field div.input input#clone_url,
1307 #content div.box div.form div.fields div.field div.input input#clone_url,
1308 #content div.box div.form div.fields div.field div.input input#clone_url_id
1308 #content div.box div.form div.fields div.field div.input input#clone_url_id
1309 {
1309 {
1310 font-size: 16px;
1310 font-size: 16px;
1311 padding: 2px;
1311 padding: 2px;
1312 }
1312 }
1313
1313
1314 #content div.box div.form div.fields div.field div.file input {
1314 #content div.box div.form div.fields div.field div.file input {
1315 background: none repeat scroll 0 0 #FFFFFF;
1315 background: none repeat scroll 0 0 #FFFFFF;
1316 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1316 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1317 border-style: solid;
1317 border-style: solid;
1318 border-width: 1px;
1318 border-width: 1px;
1319 color: #000000;
1319 color: #000000;
1320 font-size: 11px;
1320 font-size: 11px;
1321 margin: 0;
1321 margin: 0;
1322 padding: 7px 7px 6px;
1322 padding: 7px 7px 6px;
1323 }
1323 }
1324
1324
1325 input.disabled {
1325 input.disabled {
1326 background-color: #F5F5F5 !important;
1326 background-color: #F5F5F5 !important;
1327 }
1327 }
1328 #content div.box div.form div.fields div.field div.input input.small {
1328 #content div.box div.form div.fields div.field div.input input.small {
1329 width: 30%;
1329 width: 30%;
1330 }
1330 }
1331
1331
1332 #content div.box div.form div.fields div.field div.input input.medium {
1332 #content div.box div.form div.fields div.field div.input input.medium {
1333 width: 55%;
1333 width: 55%;
1334 }
1334 }
1335
1335
1336 #content div.box div.form div.fields div.field div.input input.large {
1336 #content div.box div.form div.fields div.field div.input input.large {
1337 width: 85%;
1337 width: 85%;
1338 }
1338 }
1339
1339
1340 #content div.box div.form div.fields div.field div.input input.date {
1340 #content div.box div.form div.fields div.field div.input input.date {
1341 width: 177px;
1341 width: 177px;
1342 }
1342 }
1343
1343
1344 #content div.box div.form div.fields div.field div.input input.button {
1344 #content div.box div.form div.fields div.field div.input input.button {
1345 background: #D4D0C8;
1345 background: #D4D0C8;
1346 border-top: 1px solid #FFF;
1346 border-top: 1px solid #FFF;
1347 border-left: 1px solid #FFF;
1347 border-left: 1px solid #FFF;
1348 border-right: 1px solid #404040;
1348 border-right: 1px solid #404040;
1349 border-bottom: 1px solid #404040;
1349 border-bottom: 1px solid #404040;
1350 color: #000;
1350 color: #000;
1351 margin: 0;
1351 margin: 0;
1352 padding: 4px 8px;
1352 padding: 4px 8px;
1353 }
1353 }
1354
1354
1355 #content div.box div.form div.fields div.field div.textarea {
1355 #content div.box div.form div.fields div.field div.textarea {
1356 border-top: 1px solid #b3b3b3;
1356 border-top: 1px solid #b3b3b3;
1357 border-left: 1px solid #b3b3b3;
1357 border-left: 1px solid #b3b3b3;
1358 border-right: 1px solid #eaeaea;
1358 border-right: 1px solid #eaeaea;
1359 border-bottom: 1px solid #eaeaea;
1359 border-bottom: 1px solid #eaeaea;
1360 margin: 0 0 0 200px;
1360 margin: 0 0 0 200px;
1361 padding: 10px;
1361 padding: 10px;
1362 }
1362 }
1363
1363
1364 #content div.box div.form div.fields div.field div.textarea-editor {
1364 #content div.box div.form div.fields div.field div.textarea-editor {
1365 border: 1px solid #ddd;
1365 border: 1px solid #ddd;
1366 padding: 0;
1366 padding: 0;
1367 }
1367 }
1368
1368
1369 #content div.box div.form div.fields div.field div.textarea textarea {
1369 #content div.box div.form div.fields div.field div.textarea textarea {
1370 width: 100%;
1370 width: 100%;
1371 height: 220px;
1371 height: 220px;
1372 overflow: hidden;
1372 overflow: hidden;
1373 background: #FFF;
1373 background: #FFF;
1374 color: #000;
1374 color: #000;
1375 font-size: 11px;
1375 font-size: 11px;
1376 outline: none;
1376 outline: none;
1377 border-width: 0;
1377 border-width: 0;
1378 margin: 0;
1378 margin: 0;
1379 padding: 0;
1379 padding: 0;
1380 }
1380 }
1381
1381
1382 #content div.box-left div.form div.fields div.field div.textarea textarea, #content div.box-right div.form div.fields div.field div.textarea textarea {
1382 #content div.box-left div.form div.fields div.field div.textarea textarea, #content div.box-right div.form div.fields div.field div.textarea textarea {
1383 width: 100%;
1383 width: 100%;
1384 height: 100px;
1384 height: 100px;
1385 }
1385 }
1386
1386
1387 #content div.box div.form div.fields div.field div.textarea table {
1387 #content div.box div.form div.fields div.field div.textarea table {
1388 width: 100%;
1388 width: 100%;
1389 border: none;
1389 border: none;
1390 margin: 0;
1390 margin: 0;
1391 padding: 0;
1391 padding: 0;
1392 }
1392 }
1393
1393
1394 #content div.box div.form div.fields div.field div.textarea table td {
1394 #content div.box div.form div.fields div.field div.textarea table td {
1395 background: #DDD;
1395 background: #DDD;
1396 border: none;
1396 border: none;
1397 padding: 0;
1397 padding: 0;
1398 }
1398 }
1399
1399
1400 #content div.box div.form div.fields div.field div.textarea table td table {
1400 #content div.box div.form div.fields div.field div.textarea table td table {
1401 width: auto;
1401 width: auto;
1402 border: none;
1402 border: none;
1403 margin: 0;
1403 margin: 0;
1404 padding: 0;
1404 padding: 0;
1405 }
1405 }
1406
1406
1407 #content div.box div.form div.fields div.field div.textarea table td table td {
1407 #content div.box div.form div.fields div.field div.textarea table td table td {
1408 font-size: 11px;
1408 font-size: 11px;
1409 padding: 5px 5px 5px 0;
1409 padding: 5px 5px 5px 0;
1410 }
1410 }
1411
1411
1412 #content div.box div.form div.fields div.field input[type=text]:focus,
1412 #content div.box div.form div.fields div.field input[type=text]:focus,
1413 #content div.box div.form div.fields div.field input[type=password]:focus,
1413 #content div.box div.form div.fields div.field input[type=password]:focus,
1414 #content div.box div.form div.fields div.field input[type=file]:focus,
1414 #content div.box div.form div.fields div.field input[type=file]:focus,
1415 #content div.box div.form div.fields div.field textarea:focus,
1415 #content div.box div.form div.fields div.field textarea:focus,
1416 #content div.box div.form div.fields div.field select:focus,
1416 #content div.box div.form div.fields div.field select:focus,
1417 .reviewer_ac input:focus {
1417 .reviewer_ac input:focus {
1418 background: #f6f6f6;
1418 background: #f6f6f6;
1419 border-color: #666;
1419 border-color: #666;
1420 }
1420 }
1421
1421
1422 .reviewer_ac {
1422 .reviewer_ac {
1423 padding: 10px
1423 padding: 10px
1424 }
1424 }
1425
1425
1426 div.form div.fields div.field div.button {
1426 div.form div.fields div.field div.button {
1427 margin: 0;
1427 margin: 0;
1428 padding: 0 0 0 8px;
1428 padding: 0 0 0 8px;
1429 }
1429 }
1430 #content div.box table.noborder {
1430 #content div.box table.noborder {
1431 border: 1px solid transparent;
1431 border: 1px solid transparent;
1432 }
1432 }
1433
1433
1434 #content div.box table {
1434 #content div.box table {
1435 width: 100%;
1435 width: 100%;
1436 border-collapse: separate;
1436 border-collapse: separate;
1437 margin: 0;
1437 margin: 0;
1438 padding: 0;
1438 padding: 0;
1439 border: 1px solid #eee;
1439 border: 1px solid #eee;
1440 -webkit-border-radius: 4px;
1440 -webkit-border-radius: 4px;
1441 border-radius: 4px;
1441 border-radius: 4px;
1442 }
1442 }
1443
1443
1444 #content div.box table th {
1444 #content div.box table th {
1445 background: #eee;
1445 background: #eee;
1446 border-bottom: 1px solid #ddd;
1446 border-bottom: 1px solid #ddd;
1447 padding: 5px 0px 5px 5px;
1447 padding: 5px 0px 5px 5px;
1448 text-align: left;
1448 text-align: left;
1449 }
1449 }
1450
1450
1451 #content div.box table th.left {
1451 #content div.box table th.left {
1452 text-align: left;
1452 text-align: left;
1453 }
1453 }
1454
1454
1455 #content div.box table th.right {
1455 #content div.box table th.right {
1456 text-align: right;
1456 text-align: right;
1457 }
1457 }
1458
1458
1459 #content div.box table th.center {
1459 #content div.box table th.center {
1460 text-align: center;
1460 text-align: center;
1461 }
1461 }
1462
1462
1463 #content div.box table th.selected {
1463 #content div.box table th.selected {
1464 vertical-align: middle;
1464 vertical-align: middle;
1465 padding: 0;
1465 padding: 0;
1466 }
1466 }
1467
1467
1468 #content div.box table td {
1468 #content div.box table td {
1469 background: #fff;
1469 background: #fff;
1470 border-bottom: 1px solid #cdcdcd;
1470 border-bottom: 1px solid #cdcdcd;
1471 vertical-align: middle;
1471 vertical-align: middle;
1472 padding: 5px;
1472 padding: 5px;
1473 }
1473 }
1474
1474
1475 #content div.box table tr.selected td {
1475 #content div.box table tr.selected td {
1476 background: #FFC;
1476 background: #FFC;
1477 }
1477 }
1478
1478
1479 #content div.box table td.selected {
1479 #content div.box table td.selected {
1480 width: 3%;
1480 width: 3%;
1481 text-align: center;
1481 text-align: center;
1482 vertical-align: middle;
1482 vertical-align: middle;
1483 padding: 0;
1483 padding: 0;
1484 }
1484 }
1485
1485
1486 #content div.box table td.action {
1486 #content div.box table td.action {
1487 width: 45%;
1487 width: 45%;
1488 text-align: left;
1488 text-align: left;
1489 }
1489 }
1490
1490
1491 #content div.box table td.date {
1491 #content div.box table td.date {
1492 width: 33%;
1492 width: 33%;
1493 text-align: center;
1493 text-align: center;
1494 }
1494 }
1495
1495
1496 #content div.box div.action {
1496 #content div.box div.action {
1497 float: right;
1497 float: right;
1498 background: #FFF;
1498 background: #FFF;
1499 text-align: right;
1499 text-align: right;
1500 margin: 10px 0 0;
1500 margin: 10px 0 0;
1501 padding: 0;
1501 padding: 0;
1502 }
1502 }
1503
1503
1504 #content div.box div.action select {
1504 #content div.box div.action select {
1505 font-size: 11px;
1505 font-size: 11px;
1506 margin: 0;
1506 margin: 0;
1507 }
1507 }
1508
1508
1509 #content div.box div.action .ui-selectmenu {
1509 #content div.box div.action .ui-selectmenu {
1510 margin: 0;
1510 margin: 0;
1511 padding: 0;
1511 padding: 0;
1512 }
1512 }
1513
1513
1514 #content div.box div.pagination {
1514 #content div.box div.pagination {
1515 height: 1%;
1515 height: 1%;
1516 clear: both;
1516 clear: both;
1517 overflow: hidden;
1517 overflow: hidden;
1518 margin: 10px 0 0;
1518 margin: 10px 0 0;
1519 padding: 0;
1519 padding: 0;
1520 }
1520 }
1521
1521
1522 #content div.box div.pagination ul.pager {
1522 #content div.box div.pagination ul.pager {
1523 float: right;
1523 float: right;
1524 text-align: right;
1524 text-align: right;
1525 margin: 0;
1525 margin: 0;
1526 padding: 0;
1526 padding: 0;
1527 }
1527 }
1528
1528
1529 #content div.box div.pagination ul.pager li {
1529 #content div.box div.pagination ul.pager li {
1530 height: 1%;
1530 height: 1%;
1531 float: left;
1531 float: left;
1532 list-style: none;
1532 list-style: none;
1533 background: #ebebeb url("../images/pager.png") repeat-x;
1533 background: #ebebeb url("../images/pager.png") repeat-x;
1534 border-top: 1px solid #dedede;
1534 border-top: 1px solid #dedede;
1535 border-left: 1px solid #cfcfcf;
1535 border-left: 1px solid #cfcfcf;
1536 border-right: 1px solid #c4c4c4;
1536 border-right: 1px solid #c4c4c4;
1537 border-bottom: 1px solid #c4c4c4;
1537 border-bottom: 1px solid #c4c4c4;
1538 color: #4A4A4A;
1538 color: #4A4A4A;
1539 font-weight: 700;
1539 font-weight: 700;
1540 margin: 0 0 0 4px;
1540 margin: 0 0 0 4px;
1541 padding: 0;
1541 padding: 0;
1542 }
1542 }
1543
1543
1544 #content div.box div.pagination ul.pager li.separator {
1544 #content div.box div.pagination ul.pager li.separator {
1545 padding: 6px;
1545 padding: 6px;
1546 }
1546 }
1547
1547
1548 #content div.box div.pagination ul.pager li.current {
1548 #content div.box div.pagination ul.pager li.current {
1549 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1549 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1550 border-top: 1px solid #ccc;
1550 border-top: 1px solid #ccc;
1551 border-left: 1px solid #bebebe;
1551 border-left: 1px solid #bebebe;
1552 border-right: 1px solid #b1b1b1;
1552 border-right: 1px solid #b1b1b1;
1553 border-bottom: 1px solid #afafaf;
1553 border-bottom: 1px solid #afafaf;
1554 color: #515151;
1554 color: #515151;
1555 padding: 6px;
1555 padding: 6px;
1556 }
1556 }
1557
1557
1558 #content div.box div.pagination ul.pager li a {
1558 #content div.box div.pagination ul.pager li a {
1559 height: 1%;
1559 height: 1%;
1560 display: block;
1560 display: block;
1561 float: left;
1561 float: left;
1562 color: #515151;
1562 color: #515151;
1563 text-decoration: none;
1563 text-decoration: none;
1564 margin: 0;
1564 margin: 0;
1565 padding: 6px;
1565 padding: 6px;
1566 }
1566 }
1567
1567
1568 #content div.box div.pagination ul.pager li a:hover,
1568 #content div.box div.pagination ul.pager li a:hover,
1569 #content div.box div.pagination ul.pager li a:active {
1569 #content div.box div.pagination ul.pager li a:active {
1570 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1570 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1571 border-top: 1px solid #ccc;
1571 border-top: 1px solid #ccc;
1572 border-left: 1px solid #bebebe;
1572 border-left: 1px solid #bebebe;
1573 border-right: 1px solid #b1b1b1;
1573 border-right: 1px solid #b1b1b1;
1574 border-bottom: 1px solid #afafaf;
1574 border-bottom: 1px solid #afafaf;
1575 margin: -1px;
1575 margin: -1px;
1576 }
1576 }
1577
1577
1578 #content div.box div.pagination-right {
1578 #content div.box div.pagination-right {
1579 float: right;
1579 float: right;
1580 }
1580 }
1581
1581
1582 #content div.box div.pagination-wh {
1582 #content div.box div.pagination-wh {
1583 height: 1%;
1583 height: 1%;
1584 overflow: hidden;
1584 overflow: hidden;
1585 text-align: right;
1585 text-align: right;
1586 margin: 10px 0 0;
1586 margin: 10px 0 0;
1587 padding: 0;
1587 padding: 0;
1588 }
1588 }
1589
1589
1590 #content div.box div.pagination-wh > :first-child {
1590 #content div.box div.pagination-wh > :first-child {
1591 border-radius: 4px 0px 0px 4px;
1591 border-radius: 4px 0px 0px 4px;
1592 }
1592 }
1593
1593
1594 #content div.box div.pagination-wh > :last-child {
1594 #content div.box div.pagination-wh > :last-child {
1595 border-radius: 0px 4px 4px 0px;
1595 border-radius: 0px 4px 4px 0px;
1596 border-right: 1px solid #cfcfcf;
1596 border-right: 1px solid #cfcfcf;
1597 }
1597 }
1598
1598
1599 #content div.box div.pagination-wh a,
1599 #content div.box div.pagination-wh a,
1600 #content div.box div.pagination-wh span.pager_dotdot,
1600 #content div.box div.pagination-wh span.pager_dotdot,
1601 #content div.box div.pagination-wh span.yui-pg-previous,
1601 #content div.box div.pagination-wh span.yui-pg-previous,
1602 #content div.box div.pagination-wh span.yui-pg-last,
1602 #content div.box div.pagination-wh span.yui-pg-last,
1603 #content div.box div.pagination-wh span.yui-pg-next,
1603 #content div.box div.pagination-wh span.yui-pg-next,
1604 #content div.box div.pagination-wh span.yui-pg-first {
1604 #content div.box div.pagination-wh span.yui-pg-first {
1605 height: 1%;
1605 height: 1%;
1606 float: left;
1606 float: left;
1607 background: #ebebeb url("../images/pager.png") repeat-x;
1607 background: #ebebeb url("../images/pager.png") repeat-x;
1608 border-top: 1px solid #dedede;
1608 border-top: 1px solid #dedede;
1609 border-left: 1px solid #cfcfcf;
1609 border-left: 1px solid #cfcfcf;
1610 border-bottom: 1px solid #c4c4c4;
1610 border-bottom: 1px solid #c4c4c4;
1611 color: #4A4A4A;
1611 color: #4A4A4A;
1612 font-weight: 700;
1612 font-weight: 700;
1613 padding: 6px;
1613 padding: 6px;
1614 }
1614 }
1615
1615
1616 #content div.box div.pagination-wh span.pager_curpage {
1616 #content div.box div.pagination-wh span.pager_curpage {
1617 height: 1%;
1617 height: 1%;
1618 float: left;
1618 float: left;
1619 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1619 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1620 border-top: 1px solid #ccc;
1620 border-top: 1px solid #ccc;
1621 border-left: 1px solid #bebebe;
1621 border-left: 1px solid #bebebe;
1622 border-bottom: 1px solid #afafaf;
1622 border-bottom: 1px solid #afafaf;
1623 color: #515151;
1623 color: #515151;
1624 font-weight: 700;
1624 font-weight: 700;
1625 padding: 6px;
1625 padding: 6px;
1626 }
1626 }
1627
1627
1628 #content div.box div.pagination-wh a:hover, #content div.box div.pagination-wh a:active {
1628 #content div.box div.pagination-wh a:hover, #content div.box div.pagination-wh a:active {
1629 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1629 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1630 border-top: 1px solid #ccc;
1630 border-top: 1px solid #ccc;
1631 border-left: 1px solid #bebebe;
1631 border-left: 1px solid #bebebe;
1632 border-bottom: 1px solid #afafaf;
1632 border-bottom: 1px solid #afafaf;
1633 text-decoration: none;
1633 text-decoration: none;
1634 }
1634 }
1635
1635
1636 #content div.box div.traffic div.legend {
1636 #content div.box div.traffic div.legend {
1637 clear: both;
1637 clear: both;
1638 overflow: hidden;
1638 overflow: hidden;
1639 border-bottom: 1px solid #ddd;
1639 border-bottom: 1px solid #ddd;
1640 margin: 0 0 10px;
1640 margin: 0 0 10px;
1641 padding: 0 0 10px;
1641 padding: 0 0 10px;
1642 }
1642 }
1643
1643
1644 #content div.box div.traffic div.legend h6 {
1644 #content div.box div.traffic div.legend h6 {
1645 float: left;
1645 float: left;
1646 border: none;
1646 border: none;
1647 margin: 0;
1647 margin: 0;
1648 padding: 0;
1648 padding: 0;
1649 }
1649 }
1650
1650
1651 #content div.box div.traffic div.legend li {
1651 #content div.box div.traffic div.legend li {
1652 list-style: none;
1652 list-style: none;
1653 float: left;
1653 float: left;
1654 font-size: 11px;
1654 font-size: 11px;
1655 margin: 0;
1655 margin: 0;
1656 padding: 0 8px 0 4px;
1656 padding: 0 8px 0 4px;
1657 }
1657 }
1658
1658
1659 #content div.box div.traffic div.legend li.visits {
1659 #content div.box div.traffic div.legend li.visits {
1660 border-left: 12px solid #edc240;
1660 border-left: 12px solid #edc240;
1661 }
1661 }
1662
1662
1663 #content div.box div.traffic div.legend li.pageviews {
1663 #content div.box div.traffic div.legend li.pageviews {
1664 border-left: 12px solid #afd8f8;
1664 border-left: 12px solid #afd8f8;
1665 }
1665 }
1666
1666
1667 #content div.box div.traffic table {
1667 #content div.box div.traffic table {
1668 width: auto;
1668 width: auto;
1669 }
1669 }
1670
1670
1671 #content div.box div.traffic table td {
1671 #content div.box div.traffic table td {
1672 background: transparent;
1672 background: transparent;
1673 border: none;
1673 border: none;
1674 padding: 2px 3px 3px;
1674 padding: 2px 3px 3px;
1675 }
1675 }
1676
1676
1677 #content div.box div.traffic table td.legendLabel {
1677 #content div.box div.traffic table td.legendLabel {
1678 padding: 0 3px 2px;
1678 padding: 0 3px 2px;
1679 }
1679 }
1680
1680
1681 #content div.box #summary {
1681 #content div.box #summary {
1682 margin-right: 200px;
1682 margin-right: 200px;
1683 }
1683 }
1684
1684
1685 #summary-menu-stats {
1685 #summary-menu-stats {
1686 float: left;
1686 float: left;
1687 width: 180px;
1687 width: 180px;
1688 position: absolute;
1688 position: absolute;
1689 top: 0;
1689 top: 0;
1690 right: 0;
1690 right: 0;
1691 }
1691 }
1692
1692
1693 #summary-menu-stats ul {
1693 #summary-menu-stats ul {
1694 margin: 0 10px;
1694 margin: 0 10px;
1695 display: block;
1695 display: block;
1696 background-color: #f9f9f9;
1696 background-color: #f9f9f9;
1697 border: 1px solid #d1d1d1;
1697 border: 1px solid #d1d1d1;
1698 border-radius: 4px;
1698 border-radius: 4px;
1699 }
1699 }
1700
1700
1701 #content #summary-menu-stats li {
1701 #content #summary-menu-stats li {
1702 border-top: 1px solid #d1d1d1;
1702 border-top: 1px solid #d1d1d1;
1703 padding: 0;
1703 padding: 0;
1704 }
1704 }
1705
1705
1706 #content #summary-menu-stats li:hover {
1706 #content #summary-menu-stats li:hover {
1707 background: #f0f0f0;
1707 background: #f0f0f0;
1708 }
1708 }
1709
1709
1710 #content #summary-menu-stats li:first-child {
1710 #content #summary-menu-stats li:first-child {
1711 border-top: none;
1711 border-top: none;
1712 }
1712 }
1713
1713
1714 #summary-menu-stats a.followers { background-image: url('../images/icons/heart.png')}
1714 #summary-menu-stats a.followers { background-image: url('../images/icons/heart.png')}
1715 #summary-menu-stats a.forks { background-image: url('../images/icons/arrow_divide.png')}
1715 #summary-menu-stats a.forks { background-image: url('../images/icons/arrow_divide.png')}
1716 #summary-menu-stats a.settings { background-image: url('../images/icons/cog_edit.png')}
1716 #summary-menu-stats a.settings { background-image: url('../images/icons/cog_edit.png')}
1717 #summary-menu-stats a.feed { background-image: url('../images/icons/rss_16.png')}
1717 #summary-menu-stats a.feed { background-image: url('../images/icons/rss_16.png')}
1718 #summary-menu-stats a.repo-size { background-image: url('../images/icons/server.png')}
1718 #summary-menu-stats a.repo-size { background-image: url('../images/icons/server.png')}
1719
1719
1720 #summary-menu-stats a {
1720 #summary-menu-stats a {
1721 display: block;
1721 display: block;
1722 padding: 12px 30px;
1722 padding: 12px 30px;
1723 background-repeat: no-repeat;
1723 background-repeat: no-repeat;
1724 background-position: 10px 50%;
1724 background-position: 10px 50%;
1725 padding-right: 10px;
1725 padding-right: 10px;
1726 }
1726 }
1727
1727
1728 #repo_size_2.loaded {
1728 #repo_size_2.loaded {
1729 margin-left: 30px;
1729 margin-left: 30px;
1730 display: block;
1730 display: block;
1731 padding-right: 10px;
1731 padding-right: 10px;
1732 padding-bottom: 7px;
1732 padding-bottom: 7px;
1733 }
1733 }
1734
1734
1735 #summary-menu-stats a:hover {
1735 #summary-menu-stats a:hover {
1736 text-decoration: none;
1736 text-decoration: none;
1737 }
1737 }
1738
1738
1739 #summary-menu-stats a span {
1739 #summary-menu-stats a span {
1740 background-color: #DEDEDE;
1740 background-color: #DEDEDE;
1741 color: 888 !important;
1741 color: 888 !important;
1742 border-radius: 4px;
1742 border-radius: 4px;
1743 padding: 2px 4px;
1743 padding: 2px 4px;
1744 font-size: 10px;
1744 font-size: 10px;
1745 }
1745 }
1746
1746
1747 #summary .metatag {
1747 #summary .metatag {
1748 display: inline-block;
1748 display: inline-block;
1749 padding: 3px 5px;
1749 padding: 3px 5px;
1750 margin-bottom: 3px;
1750 margin-bottom: 3px;
1751 margin-right: 1px;
1751 margin-right: 1px;
1752 border-radius: 5px;
1752 border-radius: 5px;
1753 }
1753 }
1754
1754
1755 #content div.box #summary p {
1755 #content div.box #summary p {
1756 margin-bottom: -5px;
1756 margin-bottom: -5px;
1757 width: 600px;
1757 width: 600px;
1758 white-space: pre-wrap;
1758 white-space: pre-wrap;
1759 }
1759 }
1760
1760
1761 #content div.box #summary p:last-child {
1761 #content div.box #summary p:last-child {
1762 margin-bottom: 9px;
1762 margin-bottom: 9px;
1763 }
1763 }
1764
1764
1765 #content div.box #summary p:first-of-type {
1765 #content div.box #summary p:first-of-type {
1766 margin-top: 9px;
1766 margin-top: 9px;
1767 }
1767 }
1768
1768
1769 .metatag {
1769 .metatag {
1770 display: inline-block;
1770 display: inline-block;
1771 margin-right: 1px;
1771 margin-right: 1px;
1772 -webkit-border-radius: 4px 4px 4px 4px;
1772 -webkit-border-radius: 4px 4px 4px 4px;
1773 -khtml-border-radius: 4px 4px 4px 4px;
1773 -khtml-border-radius: 4px 4px 4px 4px;
1774 border-radius: 4px 4px 4px 4px;
1774 border-radius: 4px 4px 4px 4px;
1775
1775
1776 border: solid 1px #9CF;
1776 border: solid 1px #9CF;
1777 padding: 2px 3px 2px 3px !important;
1777 padding: 2px 3px 2px 3px !important;
1778 background-color: #DEF;
1778 background-color: #DEF;
1779 }
1779 }
1780
1780
1781 .metatag[tag="dead"] {
1781 .metatag[tag="dead"] {
1782 background-color: #E44;
1782 background-color: #E44;
1783 }
1783 }
1784
1784
1785 .metatag[tag="stale"] {
1785 .metatag[tag="stale"] {
1786 background-color: #EA4;
1786 background-color: #EA4;
1787 }
1787 }
1788
1788
1789 .metatag[tag="featured"] {
1789 .metatag[tag="featured"] {
1790 background-color: #AEA;
1790 background-color: #AEA;
1791 }
1791 }
1792
1792
1793 .metatag[tag="requires"] {
1793 .metatag[tag="requires"] {
1794 background-color: #9CF;
1794 background-color: #9CF;
1795 }
1795 }
1796
1796
1797 .metatag[tag="recommends"] {
1797 .metatag[tag="recommends"] {
1798 background-color: #BDF;
1798 background-color: #BDF;
1799 }
1799 }
1800
1800
1801 .metatag[tag="lang"] {
1801 .metatag[tag="lang"] {
1802 background-color: #FAF474;
1802 background-color: #FAF474;
1803 }
1803 }
1804
1804
1805 .metatag[tag="license"] {
1805 .metatag[tag="license"] {
1806 border: solid 1px #9CF;
1806 border: solid 1px #9CF;
1807 background-color: #DEF;
1807 background-color: #DEF;
1808 target-new: tab !important;
1808 target-new: tab !important;
1809 }
1809 }
1810 .metatag[tag="see"] {
1810 .metatag[tag="see"] {
1811 border: solid 1px #CBD;
1811 border: solid 1px #CBD;
1812 background-color: #EDF;
1812 background-color: #EDF;
1813 }
1813 }
1814
1814
1815 a.metatag[tag="license"]:hover {
1815 a.metatag[tag="license"]:hover {
1816 background-color: #003367;
1816 background-color: #003367;
1817 color: #FFF;
1817 color: #FFF;
1818 text-decoration: none;
1818 text-decoration: none;
1819 }
1819 }
1820
1820
1821 #summary .desc {
1821 #summary .desc {
1822 white-space: pre;
1822 white-space: pre;
1823 width: 100%;
1823 width: 100%;
1824 }
1824 }
1825
1825
1826 #summary .repo_name {
1826 #summary .repo_name {
1827 font-size: 1.6em;
1827 font-size: 1.6em;
1828 font-weight: bold;
1828 font-weight: bold;
1829 vertical-align: baseline;
1829 vertical-align: baseline;
1830 clear: right
1830 clear: right
1831 }
1831 }
1832
1832
1833 #footer {
1833 #footer {
1834 clear: both;
1834 clear: both;
1835 overflow: hidden;
1835 overflow: hidden;
1836 text-align: right;
1836 text-align: right;
1837 margin: 0;
1837 margin: 0;
1838 padding: 0 10px 4px;
1838 padding: 0 10px 4px;
1839 margin: -10px 0 0;
1839 margin: -10px 0 0;
1840 }
1840 }
1841
1841
1842 #footer div#footer-inner {
1842 #footer div#footer-inner {
1843 background-color: #003B76;
1843 background-color: #003B76;
1844 background-repeat: repeat-x;
1844 background-repeat: repeat-x;
1845 background-image: -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1845 background-image: -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1846 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1846 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1847 background-image: -ms-linear-gradient( top, #003b76, #00376e);
1847 background-image: -ms-linear-gradient( top, #003b76, #00376e);
1848 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1848 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1849 background-image: -webkit-linear-gradient( top, #003b76, #00376e));
1849 background-image: -webkit-linear-gradient( top, #003b76, #00376e));
1850 background-image: -o-linear-gradient( top, #003b76, #00376e));
1850 background-image: -o-linear-gradient( top, #003b76, #00376e));
1851 background-image: linear-gradient(to bottom, #003b76, #00376e);
1851 background-image: linear-gradient(to bottom, #003b76, #00376e);
1852 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1852 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1853 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1853 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1854 -webkit-border-radius: 4px 4px 4px 4px;
1854 -webkit-border-radius: 4px 4px 4px 4px;
1855 -khtml-border-radius: 4px 4px 4px 4px;
1855 -khtml-border-radius: 4px 4px 4px 4px;
1856 border-radius: 4px 4px 4px 4px;
1856 border-radius: 4px 4px 4px 4px;
1857 }
1857 }
1858
1858
1859 #footer div#footer-inner p {
1859 #footer div#footer-inner p {
1860 padding: 15px 25px 15px 0;
1860 padding: 15px 25px 15px 0;
1861 color: #FFF;
1861 color: #FFF;
1862 font-weight: 700;
1862 font-weight: 700;
1863 }
1863 }
1864
1864
1865 #footer div#footer-inner .footer-link {
1865 #footer div#footer-inner .footer-link {
1866 float: left;
1866 float: left;
1867 padding-left: 10px;
1867 padding-left: 10px;
1868 }
1868 }
1869
1869
1870 #footer div#footer-inner .footer-link a, #footer div#footer-inner .footer-link-right a {
1870 #footer div#footer-inner .footer-link a, #footer div#footer-inner .footer-link-right a {
1871 color: #FFF;
1871 color: #FFF;
1872 }
1872 }
1873
1873
1874 #login div.title {
1874 #login div.title {
1875 clear: both;
1875 clear: both;
1876 overflow: hidden;
1876 overflow: hidden;
1877 position: relative;
1877 position: relative;
1878 background-color: #003B76;
1878 background-color: #003B76;
1879 background-repeat: repeat-x;
1879 background-repeat: repeat-x;
1880 background-image: -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1880 background-image: -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1881 background-image: -moz-linear-gradient( top, #003b76, #00376e);
1881 background-image: -moz-linear-gradient( top, #003b76, #00376e);
1882 background-image: -ms-linear-gradient( top, #003b76, #00376e);
1882 background-image: -ms-linear-gradient( top, #003b76, #00376e);
1883 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1883 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1884 background-image: -webkit-linear-gradient( top, #003b76, #00376e));
1884 background-image: -webkit-linear-gradient( top, #003b76, #00376e));
1885 background-image: -o-linear-gradient( top, #003b76, #00376e));
1885 background-image: -o-linear-gradient( top, #003b76, #00376e));
1886 background-image: linear-gradient(to bottom, #003b76, #00376e);
1886 background-image: linear-gradient(to bottom, #003b76, #00376e);
1887 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1887 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1888 margin: 0 auto;
1888 margin: 0 auto;
1889 padding: 0;
1889 padding: 0;
1890 }
1890 }
1891
1891
1892 #login div.inner {
1892 #login div.inner {
1893 background: #FFF url("../images/login.png") no-repeat top left;
1893 background: #FFF url("../images/login.png") no-repeat top left;
1894 border-top: none;
1894 border-top: none;
1895 border-bottom: none;
1895 border-bottom: none;
1896 margin: 0 auto;
1896 margin: 0 auto;
1897 padding: 20px;
1897 padding: 20px;
1898 }
1898 }
1899
1899
1900 #login div.form div.fields div.field div.label {
1900 #login div.form div.fields div.field div.label {
1901 width: 173px;
1901 width: 173px;
1902 float: left;
1902 float: left;
1903 text-align: right;
1903 text-align: right;
1904 margin: 2px 10px 0 0;
1904 margin: 2px 10px 0 0;
1905 padding: 5px 0 0 5px;
1905 padding: 5px 0 0 5px;
1906 }
1906 }
1907
1907
1908 #login div.form div.fields div.field div.input input {
1908 #login div.form div.fields div.field div.input input {
1909 background: #FFF;
1909 background: #FFF;
1910 border-top: 1px solid #b3b3b3;
1910 border-top: 1px solid #b3b3b3;
1911 border-left: 1px solid #b3b3b3;
1911 border-left: 1px solid #b3b3b3;
1912 border-right: 1px solid #eaeaea;
1912 border-right: 1px solid #eaeaea;
1913 border-bottom: 1px solid #eaeaea;
1913 border-bottom: 1px solid #eaeaea;
1914 color: #000;
1914 color: #000;
1915 font-size: 11px;
1915 font-size: 11px;
1916 margin: 0;
1916 margin: 0;
1917 padding: 7px 7px 6px;
1917 padding: 7px 7px 6px;
1918 }
1918 }
1919
1919
1920 #login div.form div.fields div.buttons {
1920 #login div.form div.fields div.buttons {
1921 clear: both;
1921 clear: both;
1922 overflow: hidden;
1922 overflow: hidden;
1923 border-top: 1px solid #DDD;
1923 border-top: 1px solid #DDD;
1924 text-align: right;
1924 text-align: right;
1925 margin: 0;
1925 margin: 0;
1926 padding: 10px 0 0;
1926 padding: 10px 0 0;
1927 }
1927 }
1928
1928
1929 #login div.form div.links {
1929 #login div.form div.links {
1930 clear: both;
1930 clear: both;
1931 overflow: hidden;
1931 overflow: hidden;
1932 margin: 10px 0 0;
1932 margin: 10px 0 0;
1933 padding: 0 0 2px;
1933 padding: 0 0 2px;
1934 }
1934 }
1935
1935
1936 .user-menu {
1936 .user-menu {
1937 margin: 0px !important;
1937 margin: 0px !important;
1938 float: left;
1938 float: left;
1939 }
1939 }
1940
1940
1941 .user-menu .container {
1941 .user-menu .container {
1942 padding: 0px 4px 0px 4px;
1942 padding: 0px 4px 0px 4px;
1943 margin: 0px 0px 0px 0px;
1943 margin: 0px 0px 0px 0px;
1944 }
1944 }
1945
1945
1946 .user-menu .gravatar {
1946 .user-menu .gravatar {
1947 margin: 0px 0px 0px 0px;
1947 margin: 0px 0px 0px 0px;
1948 cursor: pointer;
1948 cursor: pointer;
1949 }
1949 }
1950 .user-menu .gravatar.enabled {
1950 .user-menu .gravatar.enabled {
1951 background-color: #FDF784 !important;
1951 background-color: #FDF784 !important;
1952 }
1952 }
1953 .user-menu .gravatar:hover {
1953 .user-menu .gravatar:hover {
1954 background-color: #FDF784 !important;
1954 background-color: #FDF784 !important;
1955 }
1955 }
1956 #quick_login {
1956 #quick_login {
1957 min-height: 110px;
1957 min-height: 110px;
1958 padding: 4px;
1958 padding: 4px;
1959 position: absolute;
1959 position: absolute;
1960 right: 0;
1960 right: 0;
1961 background-color: #003B76;
1961 background-color: #003B76;
1962 background-repeat: repeat-x;
1962 background-repeat: repeat-x;
1963 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1963 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1964 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1964 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1965 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1965 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1966 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1966 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1967 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1967 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1968 background-image: -o-linear-gradient(top, #003b76, #00376e);
1968 background-image: -o-linear-gradient(top, #003b76, #00376e);
1969 background-image: linear-gradient(to bottom, #003b76, #00376e);
1969 background-image: linear-gradient(to bottom, #003b76, #00376e);
1970 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1970 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1971
1971
1972 z-index: 999;
1972 z-index: 999;
1973 -webkit-border-radius: 0px 0px 4px 4px;
1973 -webkit-border-radius: 0px 0px 4px 4px;
1974 -khtml-border-radius: 0px 0px 4px 4px;
1974 -khtml-border-radius: 0px 0px 4px 4px;
1975 border-radius: 0px 0px 4px 4px;
1975 border-radius: 0px 0px 4px 4px;
1976 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1976 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1977
1977
1978 overflow: hidden;
1978 overflow: hidden;
1979 }
1979 }
1980 #quick_login h4 {
1980 #quick_login h4 {
1981 color: #fff;
1981 color: #fff;
1982 padding: 5px 0px 5px 14px;
1982 padding: 5px 0px 5px 14px;
1983 }
1983 }
1984
1984
1985 #quick_login .password_forgoten {
1985 #quick_login .password_forgoten {
1986 padding-right: 0px;
1986 padding-right: 0px;
1987 padding-top: 0px;
1987 padding-top: 0px;
1988 text-align: left;
1988 text-align: left;
1989 }
1989 }
1990
1990
1991 #quick_login .password_forgoten a {
1991 #quick_login .password_forgoten a {
1992 font-size: 10px;
1992 font-size: 10px;
1993 color: #fff;
1993 color: #fff;
1994 padding: 0px !important;
1994 padding: 0px !important;
1995 line-height: 20px !important;
1995 line-height: 20px !important;
1996 }
1996 }
1997
1997
1998 #quick_login .register {
1998 #quick_login .register {
1999 padding-right: 10px;
1999 padding-right: 10px;
2000 padding-top: 5px;
2000 padding-top: 5px;
2001 text-align: left;
2001 text-align: left;
2002 }
2002 }
2003
2003
2004 #quick_login .register a {
2004 #quick_login .register a {
2005 font-size: 10px;
2005 font-size: 10px;
2006 color: #fff;
2006 color: #fff;
2007 padding: 0px !important;
2007 padding: 0px !important;
2008 line-height: 20px !important;
2008 line-height: 20px !important;
2009 }
2009 }
2010
2010
2011 #quick_login .submit {
2011 #quick_login .submit {
2012 margin: -20px 0 0 0px;
2012 margin: -20px 0 0 0px;
2013 position: absolute;
2013 position: absolute;
2014 right: 15px;
2014 right: 15px;
2015 }
2015 }
2016
2016
2017 #quick_login .links_left {
2017 #quick_login .links_left {
2018 float: left;
2018 float: left;
2019 margin-right: 130px;
2019 margin-right: 130px;
2020 width: 170px;
2020 width: 170px;
2021 }
2021 }
2022 #quick_login .links_right {
2022 #quick_login .links_right {
2023
2023
2024 position: absolute;
2024 position: absolute;
2025 right: 0;
2025 right: 0;
2026 }
2026 }
2027 #quick_login .full_name {
2027 #quick_login .full_name {
2028 color: #FFFFFF;
2028 color: #FFFFFF;
2029 font-weight: bold;
2029 font-weight: bold;
2030 padding: 3px 3px 3px 6px;
2030 padding: 3px 3px 3px 6px;
2031 }
2031 }
2032 #quick_login .big_gravatar {
2032 #quick_login .big_gravatar {
2033 padding: 4px 0px 0px 6px;
2033 padding: 4px 0px 0px 6px;
2034 }
2034 }
2035 #quick_login .notifications {
2035 #quick_login .notifications {
2036 padding: 2px 0px 0px 6px;
2036 padding: 2px 0px 0px 6px;
2037 color: #FFFFFF;
2037 color: #FFFFFF;
2038 font-weight: bold;
2038 font-weight: bold;
2039 line-height: 10px !important;
2039 line-height: 10px !important;
2040 }
2040 }
2041 #quick_login .notifications a,
2041 #quick_login .notifications a,
2042 #quick_login .unread a {
2042 #quick_login .unread a {
2043 color: #FFFFFF;
2043 color: #FFFFFF;
2044 display: block;
2044 display: block;
2045 padding: 0px !important;
2045 padding: 0px !important;
2046 }
2046 }
2047 #quick_login .notifications a:hover,
2047 #quick_login .notifications a:hover,
2048 #quick_login .unread a:hover {
2048 #quick_login .unread a:hover {
2049 background-color: inherit !important;
2049 background-color: inherit !important;
2050 }
2050 }
2051 #quick_login .email, #quick_login .unread {
2051 #quick_login .email, #quick_login .unread {
2052 color: #FFFFFF;
2052 color: #FFFFFF;
2053 padding: 3px 3px 3px 6px;
2053 padding: 3px 3px 3px 6px;
2054 }
2054 }
2055 #quick_login .links .logout {
2055 #quick_login .links .logout {
2056 }
2056 }
2057
2057
2058 #quick_login div.form div.fields {
2058 #quick_login div.form div.fields {
2059 padding-top: 2px;
2059 padding-top: 2px;
2060 padding-left: 10px;
2060 padding-left: 10px;
2061 }
2061 }
2062
2062
2063 #quick_login div.form div.fields div.field {
2063 #quick_login div.form div.fields div.field {
2064 padding: 5px;
2064 padding: 5px;
2065 }
2065 }
2066
2066
2067 #quick_login div.form div.fields div.field div.label label {
2067 #quick_login div.form div.fields div.field div.label label {
2068 color: #fff;
2068 color: #fff;
2069 padding-bottom: 3px;
2069 padding-bottom: 3px;
2070 }
2070 }
2071
2071
2072 #quick_login div.form div.fields div.field div.input input {
2072 #quick_login div.form div.fields div.field div.input input {
2073 width: 236px;
2073 width: 236px;
2074 background: #FFF;
2074 background: #FFF;
2075 border-top: 1px solid #b3b3b3;
2075 border-top: 1px solid #b3b3b3;
2076 border-left: 1px solid #b3b3b3;
2076 border-left: 1px solid #b3b3b3;
2077 border-right: 1px solid #eaeaea;
2077 border-right: 1px solid #eaeaea;
2078 border-bottom: 1px solid #eaeaea;
2078 border-bottom: 1px solid #eaeaea;
2079 color: #000;
2079 color: #000;
2080 font-size: 11px;
2080 font-size: 11px;
2081 margin: 0;
2081 margin: 0;
2082 padding: 5px 7px 4px;
2082 padding: 5px 7px 4px;
2083 }
2083 }
2084
2084
2085 #quick_login div.form div.fields div.buttons {
2085 #quick_login div.form div.fields div.buttons {
2086 clear: both;
2086 clear: both;
2087 overflow: hidden;
2087 overflow: hidden;
2088 text-align: right;
2088 text-align: right;
2089 margin: 0;
2089 margin: 0;
2090 padding: 5px 14px 0px 5px;
2090 padding: 5px 14px 0px 5px;
2091 }
2091 }
2092
2092
2093 #quick_login div.form div.links {
2093 #quick_login div.form div.links {
2094 clear: both;
2094 clear: both;
2095 overflow: hidden;
2095 overflow: hidden;
2096 margin: 10px 0 0;
2096 margin: 10px 0 0;
2097 padding: 0 0 2px;
2097 padding: 0 0 2px;
2098 }
2098 }
2099
2099
2100 #quick_login ol.links {
2100 #quick_login ol.links {
2101 display: block;
2101 display: block;
2102 font-weight: bold;
2102 font-weight: bold;
2103 list-style: none outside none;
2103 list-style: none outside none;
2104 text-align: right;
2104 text-align: right;
2105 }
2105 }
2106 #quick_login ol.links li {
2106 #quick_login ol.links li {
2107 line-height: 27px;
2107 line-height: 27px;
2108 margin: 0;
2108 margin: 0;
2109 padding: 0;
2109 padding: 0;
2110 color: #fff;
2110 color: #fff;
2111 display: block;
2111 display: block;
2112 float: none !important;
2112 float: none !important;
2113 }
2113 }
2114
2114
2115 #quick_login ol.links li a {
2115 #quick_login ol.links li a {
2116 color: #fff;
2116 color: #fff;
2117 display: block;
2117 display: block;
2118 padding: 2px;
2118 padding: 2px;
2119 }
2119 }
2120 #quick_login ol.links li a:HOVER {
2120 #quick_login ol.links li a:HOVER {
2121 background-color: inherit !important;
2121 background-color: inherit !important;
2122 }
2122 }
2123
2123
2124 #register div.title {
2124 #register div.title {
2125 clear: both;
2125 clear: both;
2126 overflow: hidden;
2126 overflow: hidden;
2127 position: relative;
2127 position: relative;
2128 background-color: #003B76;
2128 background-color: #003B76;
2129 background-repeat: repeat-x;
2129 background-repeat: repeat-x;
2130 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2130 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2131 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2131 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2132 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2132 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2133 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2133 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2134 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2134 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2135 background-image: -o-linear-gradient(top, #003b76, #00376e);
2135 background-image: -o-linear-gradient(top, #003b76, #00376e);
2136 background-image: linear-gradient(to bottom, #003b76, #00376e);
2136 background-image: linear-gradient(to bottom, #003b76, #00376e);
2137 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2137 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2138 endColorstr='#00376e', GradientType=0 );
2138 endColorstr='#00376e', GradientType=0 );
2139 margin: 0 auto;
2139 margin: 0 auto;
2140 padding: 0;
2140 padding: 0;
2141 }
2141 }
2142
2142
2143 #register div.inner {
2143 #register div.inner {
2144 background: #FFF;
2144 background: #FFF;
2145 border-top: none;
2145 border-top: none;
2146 border-bottom: none;
2146 border-bottom: none;
2147 margin: 0 auto;
2147 margin: 0 auto;
2148 padding: 20px;
2148 padding: 20px;
2149 }
2149 }
2150
2150
2151 #register div.form div.fields div.field div.label {
2151 #register div.form div.fields div.field div.label {
2152 width: 135px;
2152 width: 135px;
2153 float: left;
2153 float: left;
2154 text-align: right;
2154 text-align: right;
2155 margin: 2px 10px 0 0;
2155 margin: 2px 10px 0 0;
2156 padding: 5px 0 0 5px;
2156 padding: 5px 0 0 5px;
2157 }
2157 }
2158
2158
2159 #register div.form div.fields div.field div.input input {
2159 #register div.form div.fields div.field div.input input {
2160 width: 300px;
2160 width: 300px;
2161 background: #FFF;
2161 background: #FFF;
2162 border-top: 1px solid #b3b3b3;
2162 border-top: 1px solid #b3b3b3;
2163 border-left: 1px solid #b3b3b3;
2163 border-left: 1px solid #b3b3b3;
2164 border-right: 1px solid #eaeaea;
2164 border-right: 1px solid #eaeaea;
2165 border-bottom: 1px solid #eaeaea;
2165 border-bottom: 1px solid #eaeaea;
2166 color: #000;
2166 color: #000;
2167 font-size: 11px;
2167 font-size: 11px;
2168 margin: 0;
2168 margin: 0;
2169 padding: 7px 7px 6px;
2169 padding: 7px 7px 6px;
2170 }
2170 }
2171
2171
2172 #register div.form div.fields div.buttons {
2172 #register div.form div.fields div.buttons {
2173 clear: both;
2173 clear: both;
2174 overflow: hidden;
2174 overflow: hidden;
2175 border-top: 1px solid #DDD;
2175 border-top: 1px solid #DDD;
2176 text-align: left;
2176 text-align: left;
2177 margin: 0;
2177 margin: 0;
2178 padding: 10px 0 0 150px;
2178 padding: 10px 0 0 150px;
2179 }
2179 }
2180
2180
2181 #register div.form div.activation_msg {
2181 #register div.form div.activation_msg {
2182 padding-top: 4px;
2182 padding-top: 4px;
2183 padding-bottom: 4px;
2183 padding-bottom: 4px;
2184 }
2184 }
2185
2185
2186 #journal .journal_day {
2186 #journal .journal_day {
2187 font-size: 20px;
2187 font-size: 20px;
2188 padding: 10px 0px;
2188 padding: 10px 0px;
2189 border-bottom: 2px solid #DDD;
2189 border-bottom: 2px solid #DDD;
2190 margin-left: 10px;
2190 margin-left: 10px;
2191 margin-right: 10px;
2191 margin-right: 10px;
2192 }
2192 }
2193
2193
2194 #journal .journal_container {
2194 #journal .journal_container {
2195 padding: 5px;
2195 padding: 5px;
2196 clear: both;
2196 clear: both;
2197 margin: 0px 5px 0px 10px;
2197 margin: 0px 5px 0px 10px;
2198 }
2198 }
2199
2199
2200 #journal .journal_action_container {
2200 #journal .journal_action_container {
2201 padding-left: 38px;
2201 padding-left: 38px;
2202 }
2202 }
2203
2203
2204 #journal .journal_user {
2204 #journal .journal_user {
2205 color: #747474;
2205 color: #747474;
2206 font-size: 14px;
2206 font-size: 14px;
2207 font-weight: bold;
2207 font-weight: bold;
2208 height: 30px;
2208 height: 30px;
2209 }
2209 }
2210
2210
2211 #journal .journal_user.deleted {
2211 #journal .journal_user.deleted {
2212 color: #747474;
2212 color: #747474;
2213 font-size: 14px;
2213 font-size: 14px;
2214 font-weight: normal;
2214 font-weight: normal;
2215 height: 30px;
2215 height: 30px;
2216 font-style: italic;
2216 font-style: italic;
2217 }
2217 }
2218
2218
2219
2219
2220 #journal .journal_icon {
2220 #journal .journal_icon {
2221 clear: both;
2221 clear: both;
2222 float: left;
2222 float: left;
2223 padding-right: 4px;
2223 padding-right: 4px;
2224 padding-top: 3px;
2224 padding-top: 3px;
2225 }
2225 }
2226
2226
2227 #journal .journal_action {
2227 #journal .journal_action {
2228 padding-top: 4px;
2228 padding-top: 4px;
2229 min-height: 2px;
2229 min-height: 2px;
2230 float: left
2230 float: left
2231 }
2231 }
2232
2232
2233 #journal .journal_action_params {
2233 #journal .journal_action_params {
2234 clear: left;
2234 clear: left;
2235 padding-left: 22px;
2235 padding-left: 22px;
2236 }
2236 }
2237
2237
2238 #journal .journal_repo {
2238 #journal .journal_repo {
2239 float: left;
2239 float: left;
2240 margin-left: 6px;
2240 margin-left: 6px;
2241 padding-top: 3px;
2241 padding-top: 3px;
2242 }
2242 }
2243
2243
2244 #journal .date {
2244 #journal .date {
2245 clear: both;
2245 clear: both;
2246 color: #777777;
2246 color: #777777;
2247 font-size: 11px;
2247 font-size: 11px;
2248 padding-left: 22px;
2248 padding-left: 22px;
2249 }
2249 }
2250
2250
2251 #journal .journal_repo .journal_repo_name {
2251 #journal .journal_repo .journal_repo_name {
2252 font-weight: bold;
2252 font-weight: bold;
2253 font-size: 1.1em;
2253 font-size: 1.1em;
2254 }
2254 }
2255
2255
2256 #journal .compare_view {
2256 #journal .compare_view {
2257 padding: 5px 0px 5px 0px;
2257 padding: 5px 0px 5px 0px;
2258 width: 95px;
2258 width: 95px;
2259 }
2259 }
2260
2260
2261 .journal_highlight {
2261 .journal_highlight {
2262 font-weight: bold;
2262 font-weight: bold;
2263 padding: 0 2px;
2263 padding: 0 2px;
2264 vertical-align: bottom;
2264 vertical-align: bottom;
2265 }
2265 }
2266
2266
2267 .trending_language_tbl, .trending_language_tbl td {
2267 .trending_language_tbl, .trending_language_tbl td {
2268 border: 0 !important;
2268 border: 0 !important;
2269 margin: 0 !important;
2269 margin: 0 !important;
2270 padding: 0 !important;
2270 padding: 0 !important;
2271 }
2271 }
2272
2272
2273 .trending_language_tbl, .trending_language_tbl tr {
2273 .trending_language_tbl, .trending_language_tbl tr {
2274 border-spacing: 1px;
2274 border-spacing: 1px;
2275 }
2275 }
2276
2276
2277 .trending_language {
2277 .trending_language {
2278 background-color: #003367;
2278 background-color: #003367;
2279 color: #FFF;
2279 color: #FFF;
2280 display: block;
2280 display: block;
2281 min-width: 20px;
2281 min-width: 20px;
2282 text-decoration: none;
2282 text-decoration: none;
2283 height: 12px;
2283 height: 12px;
2284 margin-bottom: 0px;
2284 margin-bottom: 0px;
2285 margin-left: 5px;
2285 margin-left: 5px;
2286 white-space: pre;
2286 white-space: pre;
2287 padding: 3px;
2287 padding: 3px;
2288 }
2288 }
2289
2289
2290 h3.files_location {
2290 h3.files_location {
2291 font-size: 1.8em;
2291 font-size: 1.8em;
2292 font-weight: 700;
2292 font-weight: 700;
2293 border-bottom: none !important;
2293 border-bottom: none !important;
2294 margin: 10px 0 !important;
2294 margin: 10px 0 !important;
2295 }
2295 }
2296
2296
2297 #files_data dl dt {
2297 #files_data dl dt {
2298 float: left;
2298 float: left;
2299 width: 60px;
2299 width: 60px;
2300 margin: 0 !important;
2300 margin: 0 !important;
2301 padding: 5px;
2301 padding: 5px;
2302 }
2302 }
2303
2303
2304 #files_data dl dd {
2304 #files_data dl dd {
2305 margin: 0 !important;
2305 margin: 0 !important;
2306 padding: 5px !important;
2306 padding: 5px !important;
2307 }
2307 }
2308
2308
2309 .file_history {
2309 .file_history {
2310 padding-top: 10px;
2310 padding-top: 10px;
2311 font-size: 16px;
2311 font-size: 16px;
2312 }
2312 }
2313 .file_author {
2313 .file_author {
2314 float: left;
2314 float: left;
2315 }
2315 }
2316
2316
2317 .file_author .item {
2317 .file_author .item {
2318 float: left;
2318 float: left;
2319 padding: 5px;
2319 padding: 5px;
2320 color: #888;
2320 color: #888;
2321 }
2321 }
2322
2322
2323 .tablerow0 {
2323 .tablerow0 {
2324 background-color: #F8F8F8;
2324 background-color: #F8F8F8;
2325 }
2325 }
2326
2326
2327 .tablerow1 {
2327 .tablerow1 {
2328 background-color: #FFFFFF;
2328 background-color: #FFFFFF;
2329 }
2329 }
2330
2330
2331 .changeset_id {
2331 .changeset_id {
2332 color: #666666;
2332 color: #666666;
2333 margin-right: -3px;
2333 margin-right: -3px;
2334 }
2334 }
2335
2335
2336 .changeset_hash {
2336 .changeset_hash {
2337 color: #000000;
2337 color: #000000;
2338 }
2338 }
2339
2339
2340 #changeset_content {
2340 #changeset_content {
2341 border-left: 1px solid #CCC;
2341 border-left: 1px solid #CCC;
2342 border-right: 1px solid #CCC;
2342 border-right: 1px solid #CCC;
2343 border-bottom: 1px solid #CCC;
2343 border-bottom: 1px solid #CCC;
2344 padding: 5px;
2344 padding: 5px;
2345 }
2345 }
2346
2346
2347 #changeset_compare_view_content {
2347 #changeset_compare_view_content {
2348 border: 1px solid #CCC;
2348 border: 1px solid #CCC;
2349 padding: 5px;
2349 padding: 5px;
2350 }
2350 }
2351
2351
2352 #changeset_content .container {
2352 #changeset_content .container {
2353 min-height: 100px;
2353 min-height: 100px;
2354 font-size: 1.2em;
2354 font-size: 1.2em;
2355 overflow: hidden;
2355 overflow: hidden;
2356 }
2356 }
2357
2357
2358 #changeset_compare_view_content .compare_view_commits {
2358 #changeset_compare_view_content .compare_view_commits {
2359 width: auto !important;
2359 width: auto !important;
2360 }
2360 }
2361
2361
2362 #changeset_compare_view_content .compare_view_commits td {
2362 #changeset_compare_view_content .compare_view_commits td {
2363 padding: 0px 0px 0px 12px !important;
2363 padding: 0px 0px 0px 12px !important;
2364 }
2364 }
2365
2365
2366 #changeset_content .container .right {
2366 #changeset_content .container .right {
2367 float: right;
2367 float: right;
2368 width: 20%;
2368 width: 20%;
2369 text-align: right;
2369 text-align: right;
2370 }
2370 }
2371
2371
2372 #changeset_content .container .message {
2372 #changeset_content .container .message {
2373 white-space: pre-wrap;
2373 white-space: pre-wrap;
2374 }
2374 }
2375 #changeset_content .container .message a:hover {
2375 #changeset_content .container .message a:hover {
2376 text-decoration: none;
2376 text-decoration: none;
2377 }
2377 }
2378 .cs_files .cur_cs {
2378 .cs_files .cur_cs {
2379 margin: 10px 2px;
2379 margin: 10px 2px;
2380 font-weight: bold;
2380 font-weight: bold;
2381 }
2381 }
2382
2382
2383 .cs_files .node {
2383 .cs_files .node {
2384 float: left;
2384 float: left;
2385 }
2385 }
2386
2386
2387 .cs_files .changes {
2387 .cs_files .changes {
2388 float: right;
2388 float: right;
2389 color: #003367;
2389 color: #003367;
2390 }
2390 }
2391
2391
2392 .cs_files .changes .added {
2392 .cs_files .changes .added {
2393 background-color: #BBFFBB;
2393 background-color: #BBFFBB;
2394 float: left;
2394 float: left;
2395 text-align: center;
2395 text-align: center;
2396 font-size: 9px;
2396 font-size: 9px;
2397 padding: 2px 0px 2px 0px;
2397 padding: 2px 0px 2px 0px;
2398 }
2398 }
2399
2399
2400 .cs_files .changes .deleted {
2400 .cs_files .changes .deleted {
2401 background-color: #FF8888;
2401 background-color: #FF8888;
2402 float: left;
2402 float: left;
2403 text-align: center;
2403 text-align: center;
2404 font-size: 9px;
2404 font-size: 9px;
2405 padding: 2px 0px 2px 0px;
2405 padding: 2px 0px 2px 0px;
2406 }
2406 }
2407 /*new binary*/
2407 /*new binary
2408 .cs_files .changes .bin1 {
2408 NEW_FILENODE = 1
2409 DEL_FILENODE = 2
2410 MOD_FILENODE = 3
2411 RENAMED_FILENODE = 4
2412 CHMOD_FILENODE = 5
2413 BIN_FILENODE = 6
2414 */
2415 .cs_files .changes .bin {
2409 background-color: #BBFFBB;
2416 background-color: #BBFFBB;
2410 float: left;
2417 float: left;
2411 text-align: center;
2418 text-align: center;
2412 font-size: 9px;
2419 font-size: 9px;
2413 padding: 2px 0px 2px 0px;
2420 padding: 2px 0px 2px 0px;
2414 }
2421 }
2422 .cs_files .changes .bin.bin1 {
2423 background-color: #BBFFBB;
2424 }
2415
2425
2416 /*deleted binary*/
2426 /*deleted binary*/
2417 .cs_files .changes .bin2 {
2427 .cs_files .changes .bin.bin2 {
2418 background-color: #FF8888;
2428 background-color: #FF8888;
2419 float: left;
2420 text-align: center;
2421 font-size: 9px;
2422 padding: 2px 0px 2px 0px;
2423 }
2429 }
2424
2430
2425 /*mod binary*/
2431 /*mod binary*/
2426 .cs_files .changes .bin3 {
2432 .cs_files .changes .bin.bin3 {
2427 background-color: #DDDDDD;
2433 background-color: #DDDDDD;
2428 float: left;
2429 text-align: center;
2430 font-size: 9px;
2431 padding: 2px 0px 2px 0px;
2432 }
2434 }
2433
2435
2434 /*rename file*/
2436 /*rename file*/
2435 .cs_files .changes .bin4 {
2437 .cs_files .changes .bin.bin4 {
2438 background-color: #6D99FF;
2439 }
2440
2441 /*rename file*/
2442 .cs_files .changes .bin.bin4 {
2436 background-color: #6D99FF;
2443 background-color: #6D99FF;
2437 float: left;
2444 }
2438 text-align: center;
2445
2439 font-size: 9px;
2446 /*chmod file*/
2440 padding: 2px 0px 2px 0px;
2447 .cs_files .changes .bin.bin5 {
2441 }
2448 background-color: #6D99FF;
2442
2449 }
2443
2450
2444 .cs_files .cs_added, .cs_files .cs_A {
2451 .cs_files .cs_added, .cs_files .cs_A {
2445 background: url("../images/icons/page_white_add.png") no-repeat scroll
2452 background: url("../images/icons/page_white_add.png") no-repeat scroll
2446 3px;
2453 3px;
2447 height: 16px;
2454 height: 16px;
2448 padding-left: 20px;
2455 padding-left: 20px;
2449 margin-top: 7px;
2456 margin-top: 7px;
2450 text-align: left;
2457 text-align: left;
2451 }
2458 }
2452
2459
2453 .cs_files .cs_changed, .cs_files .cs_M {
2460 .cs_files .cs_changed, .cs_files .cs_M {
2454 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2461 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2455 3px;
2462 3px;
2456 height: 16px;
2463 height: 16px;
2457 padding-left: 20px;
2464 padding-left: 20px;
2458 margin-top: 7px;
2465 margin-top: 7px;
2459 text-align: left;
2466 text-align: left;
2460 }
2467 }
2461
2468
2462 .cs_files .cs_removed, .cs_files .cs_D {
2469 .cs_files .cs_removed, .cs_files .cs_D {
2463 background: url("../images/icons/page_white_delete.png") no-repeat
2470 background: url("../images/icons/page_white_delete.png") no-repeat
2464 scroll 3px;
2471 scroll 3px;
2465 height: 16px;
2472 height: 16px;
2466 padding-left: 20px;
2473 padding-left: 20px;
2467 margin-top: 7px;
2474 margin-top: 7px;
2468 text-align: left;
2475 text-align: left;
2469 }
2476 }
2470
2477
2471 .table {
2478 .table {
2472 position: relative;
2479 position: relative;
2473 }
2480 }
2474
2481
2475 #graph {
2482 #graph {
2476 position: relative;
2483 position: relative;
2477 overflow: hidden;
2484 overflow: hidden;
2478 }
2485 }
2479
2486
2480 #graph_nodes {
2487 #graph_nodes {
2481 position: absolute;
2488 position: absolute;
2482 }
2489 }
2483
2490
2484 #graph_content,
2491 #graph_content,
2485 #graph .info_box,
2492 #graph .info_box,
2486 #graph .container_header {
2493 #graph .container_header {
2487 margin-left: 100px;
2494 margin-left: 100px;
2488 }
2495 }
2489
2496
2490 #graph_content {
2497 #graph_content {
2491 position: relative;
2498 position: relative;
2492 }
2499 }
2493
2500
2494 #graph .container_header {
2501 #graph .container_header {
2495 padding: 10px;
2502 padding: 10px;
2496 height: 25px;
2503 height: 25px;
2497 }
2504 }
2498
2505
2499 #graph_content #rev_range_container {
2506 #graph_content #rev_range_container {
2500 float: left;
2507 float: left;
2501 margin: 0px 0px 0px 3px;
2508 margin: 0px 0px 0px 3px;
2502 }
2509 }
2503
2510
2504 #graph_content #rev_range_clear {
2511 #graph_content #rev_range_clear {
2505 float: left;
2512 float: left;
2506 margin: 0px 0px 0px 3px;
2513 margin: 0px 0px 0px 3px;
2507 }
2514 }
2508
2515
2509 #graph_content #changesets {
2516 #graph_content #changesets {
2510 table-layout: fixed;
2517 table-layout: fixed;
2511 border-collapse: collapse;
2518 border-collapse: collapse;
2512 border-left: none;
2519 border-left: none;
2513 border-right: none;
2520 border-right: none;
2514 border-color: #cdcdcd;
2521 border-color: #cdcdcd;
2515 }
2522 }
2516
2523
2517 #graph_content #changesets td {
2524 #graph_content #changesets td {
2518 overflow: hidden;
2525 overflow: hidden;
2519 text-overflow: ellipsis;
2526 text-overflow: ellipsis;
2520 white-space: nowrap;
2527 white-space: nowrap;
2521 height: 31px;
2528 height: 31px;
2522 border-color: #cdcdcd;
2529 border-color: #cdcdcd;
2523 text-align: left;
2530 text-align: left;
2524 }
2531 }
2525
2532
2526 #graph_content .container .checkbox {
2533 #graph_content .container .checkbox {
2527 width: 12px;
2534 width: 12px;
2528 font-size: 0.85em;
2535 font-size: 0.85em;
2529 }
2536 }
2530
2537
2531 #graph_content .container .status {
2538 #graph_content .container .status {
2532 width: 14px;
2539 width: 14px;
2533 font-size: 0.85em;
2540 font-size: 0.85em;
2534 }
2541 }
2535
2542
2536 #graph_content .container .author {
2543 #graph_content .container .author {
2537 width: 105px;
2544 width: 105px;
2538 }
2545 }
2539
2546
2540 #graph_content .container .hash {
2547 #graph_content .container .hash {
2541 width: 100px;
2548 width: 100px;
2542 font-size: 0.85em;
2549 font-size: 0.85em;
2543 }
2550 }
2544
2551
2545 #graph_content #changesets .container .date {
2552 #graph_content #changesets .container .date {
2546 width: 76px;
2553 width: 76px;
2547 color: #666;
2554 color: #666;
2548 font-size: 10px;
2555 font-size: 10px;
2549 }
2556 }
2550
2557
2551 #graph_content #changesets .container .right {
2558 #graph_content #changesets .container .right {
2552 width: 120px;
2559 width: 120px;
2553 padding-right: 0px;
2560 padding-right: 0px;
2554 overflow: visible;
2561 overflow: visible;
2555 position: relative;
2562 position: relative;
2556 }
2563 }
2557
2564
2558 #graph_content .container .mid {
2565 #graph_content .container .mid {
2559 padding: 0;
2566 padding: 0;
2560 }
2567 }
2561
2568
2562 #graph_content .log-container {
2569 #graph_content .log-container {
2563 position: relative;
2570 position: relative;
2564 }
2571 }
2565
2572
2566 #graph_content .container .changeset_range {
2573 #graph_content .container .changeset_range {
2567 float: left;
2574 float: left;
2568 margin: 6px 3px;
2575 margin: 6px 3px;
2569 }
2576 }
2570
2577
2571 #graph_content .container .author img {
2578 #graph_content .container .author img {
2572 vertical-align: middle;
2579 vertical-align: middle;
2573 }
2580 }
2574
2581
2575 #graph_content .container .author .user {
2582 #graph_content .container .author .user {
2576 color: #444444;
2583 color: #444444;
2577 }
2584 }
2578
2585
2579 #graph_content .container .mid .message {
2586 #graph_content .container .mid .message {
2580 white-space: pre-wrap;
2587 white-space: pre-wrap;
2581 padding: 0;
2588 padding: 0;
2582 overflow: hidden;
2589 overflow: hidden;
2583 height: 1.1em;
2590 height: 1.1em;
2584 }
2591 }
2585
2592
2586 #graph_content .container .extra-container {
2593 #graph_content .container .extra-container {
2587 display: block;
2594 display: block;
2588 position: absolute;
2595 position: absolute;
2589 top: -15px;
2596 top: -15px;
2590 right: 0;
2597 right: 0;
2591 padding-left: 5px;
2598 padding-left: 5px;
2592 background: #FFFFFF;
2599 background: #FFFFFF;
2593 height: 41px;
2600 height: 41px;
2594 }
2601 }
2595
2602
2596 #graph_content .comments-container,
2603 #graph_content .comments-container,
2597 #shortlog_data .comments-container,
2604 #shortlog_data .comments-container,
2598 #graph_content .logtags {
2605 #graph_content .logtags {
2599 display: block;
2606 display: block;
2600 float: left;
2607 float: left;
2601 overflow: hidden;
2608 overflow: hidden;
2602 padding: 0;
2609 padding: 0;
2603 margin: 0;
2610 margin: 0;
2604 }
2611 }
2605
2612
2606 #graph_content .comments-container {
2613 #graph_content .comments-container {
2607 margin: 0.8em 0;
2614 margin: 0.8em 0;
2608 margin-right: 0.5em;
2615 margin-right: 0.5em;
2609 }
2616 }
2610
2617
2611 #graph_content .tagcontainer {
2618 #graph_content .tagcontainer {
2612 width: 80px;
2619 width: 80px;
2613 position: relative;
2620 position: relative;
2614 float: right;
2621 float: right;
2615 height: 100%;
2622 height: 100%;
2616 top: 7px;
2623 top: 7px;
2617 margin-left: 0.5em;
2624 margin-left: 0.5em;
2618 }
2625 }
2619
2626
2620 #graph_content .logtags {
2627 #graph_content .logtags {
2621 min-width: 80px;
2628 min-width: 80px;
2622 height: 1.1em;
2629 height: 1.1em;
2623 position: absolute;
2630 position: absolute;
2624 left: 0px;
2631 left: 0px;
2625 width: auto;
2632 width: auto;
2626 top: 0px;
2633 top: 0px;
2627 }
2634 }
2628
2635
2629 #graph_content .logtags.tags {
2636 #graph_content .logtags.tags {
2630 top: 14px;
2637 top: 14px;
2631 }
2638 }
2632
2639
2633 #graph_content .logtags:hover {
2640 #graph_content .logtags:hover {
2634 overflow: visible;
2641 overflow: visible;
2635 position: absolute;
2642 position: absolute;
2636 width: auto;
2643 width: auto;
2637 right: 0;
2644 right: 0;
2638 left: initial;
2645 left: initial;
2639 }
2646 }
2640
2647
2641 #graph_content .logtags .booktag,
2648 #graph_content .logtags .booktag,
2642 #graph_content .logtags .tagtag {
2649 #graph_content .logtags .tagtag {
2643 float: left;
2650 float: left;
2644 line-height: 1em;
2651 line-height: 1em;
2645 margin-bottom: 1px;
2652 margin-bottom: 1px;
2646 margin-right: 1px;
2653 margin-right: 1px;
2647 padding: 1px 3px;
2654 padding: 1px 3px;
2648 font-size: 10px;
2655 font-size: 10px;
2649 }
2656 }
2650
2657
2651 #graph_content .container .mid .message a:hover {
2658 #graph_content .container .mid .message a:hover {
2652 text-decoration: none;
2659 text-decoration: none;
2653 }
2660 }
2654
2661
2655 .revision-link {
2662 .revision-link {
2656 color: #3F6F9F;
2663 color: #3F6F9F;
2657 font-weight: bold !important;
2664 font-weight: bold !important;
2658 }
2665 }
2659
2666
2660 .issue-tracker-link {
2667 .issue-tracker-link {
2661 color: #3F6F9F;
2668 color: #3F6F9F;
2662 font-weight: bold !important;
2669 font-weight: bold !important;
2663 }
2670 }
2664
2671
2665 .changeset-status-container {
2672 .changeset-status-container {
2666 padding-right: 5px;
2673 padding-right: 5px;
2667 margin-top: 1px;
2674 margin-top: 1px;
2668 float: right;
2675 float: right;
2669 height: 14px;
2676 height: 14px;
2670 }
2677 }
2671 .code-header .changeset-status-container {
2678 .code-header .changeset-status-container {
2672 float: left;
2679 float: left;
2673 padding: 2px 0px 0px 2px;
2680 padding: 2px 0px 0px 2px;
2674 }
2681 }
2675 .changeset-status-container .changeset-status-lbl {
2682 .changeset-status-container .changeset-status-lbl {
2676 color: rgb(136, 136, 136);
2683 color: rgb(136, 136, 136);
2677 float: left;
2684 float: left;
2678 padding: 3px 4px 0px 0px
2685 padding: 3px 4px 0px 0px
2679 }
2686 }
2680 .code-header .changeset-status-container .changeset-status-lbl {
2687 .code-header .changeset-status-container .changeset-status-lbl {
2681 float: left;
2688 float: left;
2682 padding: 0px 4px 0px 0px;
2689 padding: 0px 4px 0px 0px;
2683 }
2690 }
2684 .changeset-status-container .changeset-status-ico {
2691 .changeset-status-container .changeset-status-ico {
2685 float: left;
2692 float: left;
2686 }
2693 }
2687 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico {
2694 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico {
2688 float: left;
2695 float: left;
2689 }
2696 }
2690
2697
2691 #graph_content .comments-cnt {
2698 #graph_content .comments-cnt {
2692 color: rgb(136, 136, 136);
2699 color: rgb(136, 136, 136);
2693 padding: 5px 0;
2700 padding: 5px 0;
2694 }
2701 }
2695
2702
2696 #shortlog_data .comments-cnt {
2703 #shortlog_data .comments-cnt {
2697 color: rgb(136, 136, 136);
2704 color: rgb(136, 136, 136);
2698 padding: 3px 0;
2705 padding: 3px 0;
2699 }
2706 }
2700
2707
2701 #graph_content .comments-cnt a,
2708 #graph_content .comments-cnt a,
2702 #shortlog_data .comments-cnt a {
2709 #shortlog_data .comments-cnt a {
2703 background-image: url('../images/icons/comments.png');
2710 background-image: url('../images/icons/comments.png');
2704 background-repeat: no-repeat;
2711 background-repeat: no-repeat;
2705 background-position: 100% 50%;
2712 background-position: 100% 50%;
2706 padding: 5px 0;
2713 padding: 5px 0;
2707 padding-right: 20px;
2714 padding-right: 20px;
2708 }
2715 }
2709
2716
2710 .right .changes {
2717 .right .changes {
2711 clear: both;
2718 clear: both;
2712 }
2719 }
2713
2720
2714 .right .changes .changed_total {
2721 .right .changes .changed_total {
2715 display: block;
2722 display: block;
2716 float: right;
2723 float: right;
2717 text-align: center;
2724 text-align: center;
2718 min-width: 45px;
2725 min-width: 45px;
2719 cursor: pointer;
2726 cursor: pointer;
2720 color: #444444;
2727 color: #444444;
2721 background: #FEA;
2728 background: #FEA;
2722 -webkit-border-radius: 0px 0px 0px 6px;
2729 -webkit-border-radius: 0px 0px 0px 6px;
2723 border-radius: 0px 0px 0px 6px;
2730 border-radius: 0px 0px 0px 6px;
2724 padding: 1px;
2731 padding: 1px;
2725 }
2732 }
2726
2733
2727 .right .changes .added, .changed, .removed {
2734 .right .changes .added, .changed, .removed {
2728 display: block;
2735 display: block;
2729 padding: 1px;
2736 padding: 1px;
2730 color: #444444;
2737 color: #444444;
2731 float: right;
2738 float: right;
2732 text-align: center;
2739 text-align: center;
2733 min-width: 15px;
2740 min-width: 15px;
2734 }
2741 }
2735
2742
2736 .right .changes .added {
2743 .right .changes .added {
2737 background: #CFC;
2744 background: #CFC;
2738 }
2745 }
2739
2746
2740 .right .changes .changed {
2747 .right .changes .changed {
2741 background: #FEA;
2748 background: #FEA;
2742 }
2749 }
2743
2750
2744 .right .changes .removed {
2751 .right .changes .removed {
2745 background: #FAA;
2752 background: #FAA;
2746 }
2753 }
2747
2754
2748 .right .merge {
2755 .right .merge {
2749 padding: 1px 3px 1px 3px;
2756 padding: 1px 3px 1px 3px;
2750 background-color: #fca062;
2757 background-color: #fca062;
2751 font-size: 10px;
2758 font-size: 10px;
2752 color: #ffffff;
2759 color: #ffffff;
2753 text-transform: uppercase;
2760 text-transform: uppercase;
2754 white-space: nowrap;
2761 white-space: nowrap;
2755 -webkit-border-radius: 3px;
2762 -webkit-border-radius: 3px;
2756 border-radius: 3px;
2763 border-radius: 3px;
2757 margin-right: 2px;
2764 margin-right: 2px;
2758 }
2765 }
2759
2766
2760 .right .parent {
2767 .right .parent {
2761 color: #666666;
2768 color: #666666;
2762 clear: both;
2769 clear: both;
2763 }
2770 }
2764 .right .logtags {
2771 .right .logtags {
2765 line-height: 2.2em;
2772 line-height: 2.2em;
2766 }
2773 }
2767 .branchtag, .logtags .tagtag, .logtags .booktag {
2774 .branchtag, .logtags .tagtag, .logtags .booktag {
2768 margin: 0px 2px;
2775 margin: 0px 2px;
2769 }
2776 }
2770
2777
2771 .branchtag,
2778 .branchtag,
2772 .tagtag,
2779 .tagtag,
2773 .booktag,
2780 .booktag,
2774 .spantag {
2781 .spantag {
2775 padding: 1px 3px 1px 3px;
2782 padding: 1px 3px 1px 3px;
2776 font-size: 10px;
2783 font-size: 10px;
2777 color: #336699;
2784 color: #336699;
2778 white-space: nowrap;
2785 white-space: nowrap;
2779 -webkit-border-radius: 4px;
2786 -webkit-border-radius: 4px;
2780 border-radius: 4px;
2787 border-radius: 4px;
2781 border: 1px solid #d9e8f8;
2788 border: 1px solid #d9e8f8;
2782 line-height: 1.5em;
2789 line-height: 1.5em;
2783 }
2790 }
2784
2791
2785 #graph_content .branchtag,
2792 #graph_content .branchtag,
2786 #graph_content .tagtag,
2793 #graph_content .tagtag,
2787 #graph_content .booktag {
2794 #graph_content .booktag {
2788 margin: 1.1em 0;
2795 margin: 1.1em 0;
2789 margin-right: 0.5em;
2796 margin-right: 0.5em;
2790 }
2797 }
2791
2798
2792 .branchtag,
2799 .branchtag,
2793 .tagtag,
2800 .tagtag,
2794 .booktag {
2801 .booktag {
2795 float: left;
2802 float: left;
2796 }
2803 }
2797
2804
2798 .right .logtags .branchtag,
2805 .right .logtags .branchtag,
2799 .right .logtags .tagtag,
2806 .right .logtags .tagtag,
2800 .right .logtags .booktag,
2807 .right .logtags .booktag,
2801 .right .merge {
2808 .right .merge {
2802 float: right;
2809 float: right;
2803 line-height: 1em;
2810 line-height: 1em;
2804 margin: 1px 1px !important;
2811 margin: 1px 1px !important;
2805 display: block;
2812 display: block;
2806 }
2813 }
2807
2814
2808 .booktag {
2815 .booktag {
2809 border-color: #46A546;
2816 border-color: #46A546;
2810 color: #46A546;
2817 color: #46A546;
2811 }
2818 }
2812
2819
2813 .tagtag {
2820 .tagtag {
2814 border-color: #62cffc;
2821 border-color: #62cffc;
2815 color: #62cffc;
2822 color: #62cffc;
2816 }
2823 }
2817
2824
2818 .logtags .branchtag a:hover,
2825 .logtags .branchtag a:hover,
2819 .logtags .branchtag a,
2826 .logtags .branchtag a,
2820 .branchtag a,
2827 .branchtag a,
2821 .branchtag a:hover {
2828 .branchtag a:hover {
2822 text-decoration: none;
2829 text-decoration: none;
2823 color: inherit;
2830 color: inherit;
2824 }
2831 }
2825 .logtags .tagtag {
2832 .logtags .tagtag {
2826 padding: 1px 3px 1px 3px;
2833 padding: 1px 3px 1px 3px;
2827 background-color: #62cffc;
2834 background-color: #62cffc;
2828 font-size: 10px;
2835 font-size: 10px;
2829 color: #ffffff;
2836 color: #ffffff;
2830 white-space: nowrap;
2837 white-space: nowrap;
2831 -webkit-border-radius: 3px;
2838 -webkit-border-radius: 3px;
2832 border-radius: 3px;
2839 border-radius: 3px;
2833 }
2840 }
2834
2841
2835 .tagtag a,
2842 .tagtag a,
2836 .tagtag a:hover,
2843 .tagtag a:hover,
2837 .logtags .tagtag a,
2844 .logtags .tagtag a,
2838 .logtags .tagtag a:hover {
2845 .logtags .tagtag a:hover {
2839 text-decoration: none;
2846 text-decoration: none;
2840 color: inherit;
2847 color: inherit;
2841 }
2848 }
2842 .logbooks .booktag, .logbooks .booktag, .logtags .booktag, .logtags .booktag {
2849 .logbooks .booktag, .logbooks .booktag, .logtags .booktag, .logtags .booktag {
2843 padding: 1px 3px 1px 3px;
2850 padding: 1px 3px 1px 3px;
2844 background-color: #46A546;
2851 background-color: #46A546;
2845 font-size: 10px;
2852 font-size: 10px;
2846 color: #ffffff;
2853 color: #ffffff;
2847 white-space: nowrap;
2854 white-space: nowrap;
2848 -webkit-border-radius: 3px;
2855 -webkit-border-radius: 3px;
2849 border-radius: 3px;
2856 border-radius: 3px;
2850 }
2857 }
2851 .logbooks .booktag, .logbooks .booktag a, .right .logtags .booktag, .logtags .booktag a {
2858 .logbooks .booktag, .logbooks .booktag a, .right .logtags .booktag, .logtags .booktag a {
2852 color: #ffffff;
2859 color: #ffffff;
2853 }
2860 }
2854
2861
2855 .logbooks .booktag, .logbooks .booktag a:hover,
2862 .logbooks .booktag, .logbooks .booktag a:hover,
2856 .logtags .booktag, .logtags .booktag a:hover,
2863 .logtags .booktag, .logtags .booktag a:hover,
2857 .booktag a,
2864 .booktag a,
2858 .booktag a:hover {
2865 .booktag a:hover {
2859 text-decoration: none;
2866 text-decoration: none;
2860 color: inherit;
2867 color: inherit;
2861 }
2868 }
2862 div.browserblock {
2869 div.browserblock {
2863 overflow: hidden;
2870 overflow: hidden;
2864 border: 1px solid #ccc;
2871 border: 1px solid #ccc;
2865 background: #f8f8f8;
2872 background: #f8f8f8;
2866 font-size: 100%;
2873 font-size: 100%;
2867 line-height: 125%;
2874 line-height: 125%;
2868 padding: 0;
2875 padding: 0;
2869 -webkit-border-radius: 6px 6px 0px 0px;
2876 -webkit-border-radius: 6px 6px 0px 0px;
2870 border-radius: 6px 6px 0px 0px;
2877 border-radius: 6px 6px 0px 0px;
2871 }
2878 }
2872
2879
2873 div.browserblock .browser-header {
2880 div.browserblock .browser-header {
2874 background: #FFF;
2881 background: #FFF;
2875 padding: 10px 0px 15px 0px;
2882 padding: 10px 0px 15px 0px;
2876 width: 100%;
2883 width: 100%;
2877 }
2884 }
2878
2885
2879 div.browserblock .browser-nav {
2886 div.browserblock .browser-nav {
2880 float: left
2887 float: left
2881 }
2888 }
2882
2889
2883 div.browserblock .browser-branch {
2890 div.browserblock .browser-branch {
2884 float: left;
2891 float: left;
2885 }
2892 }
2886
2893
2887 div.browserblock .browser-branch label {
2894 div.browserblock .browser-branch label {
2888 color: #4A4A4A;
2895 color: #4A4A4A;
2889 vertical-align: text-top;
2896 vertical-align: text-top;
2890 }
2897 }
2891
2898
2892 div.browserblock .browser-header span {
2899 div.browserblock .browser-header span {
2893 margin-left: 5px;
2900 margin-left: 5px;
2894 font-weight: 700;
2901 font-weight: 700;
2895 }
2902 }
2896
2903
2897 div.browserblock .browser-search {
2904 div.browserblock .browser-search {
2898 clear: both;
2905 clear: both;
2899 padding: 8px 8px 0px 5px;
2906 padding: 8px 8px 0px 5px;
2900 height: 20px;
2907 height: 20px;
2901 }
2908 }
2902
2909
2903 div.browserblock #node_filter_box {
2910 div.browserblock #node_filter_box {
2904 }
2911 }
2905
2912
2906 div.browserblock .search_activate {
2913 div.browserblock .search_activate {
2907 float: left
2914 float: left
2908 }
2915 }
2909
2916
2910 div.browserblock .add_node {
2917 div.browserblock .add_node {
2911 float: left;
2918 float: left;
2912 padding-left: 5px;
2919 padding-left: 5px;
2913 }
2920 }
2914
2921
2915 div.browserblock .search_activate a:hover, div.browserblock .add_node a:hover {
2922 div.browserblock .search_activate a:hover, div.browserblock .add_node a:hover {
2916 text-decoration: none !important;
2923 text-decoration: none !important;
2917 }
2924 }
2918
2925
2919 div.browserblock .browser-body {
2926 div.browserblock .browser-body {
2920 background: #EEE;
2927 background: #EEE;
2921 border-top: 1px solid #CCC;
2928 border-top: 1px solid #CCC;
2922 }
2929 }
2923
2930
2924 table.code-browser {
2931 table.code-browser {
2925 border-collapse: collapse;
2932 border-collapse: collapse;
2926 width: 100%;
2933 width: 100%;
2927 }
2934 }
2928
2935
2929 table.code-browser tr {
2936 table.code-browser tr {
2930 margin: 3px;
2937 margin: 3px;
2931 }
2938 }
2932
2939
2933 table.code-browser thead th {
2940 table.code-browser thead th {
2934 background-color: #EEE;
2941 background-color: #EEE;
2935 height: 20px;
2942 height: 20px;
2936 font-size: 1.1em;
2943 font-size: 1.1em;
2937 font-weight: 700;
2944 font-weight: 700;
2938 text-align: left;
2945 text-align: left;
2939 padding-left: 10px;
2946 padding-left: 10px;
2940 }
2947 }
2941
2948
2942 table.code-browser tbody td {
2949 table.code-browser tbody td {
2943 padding-left: 10px;
2950 padding-left: 10px;
2944 height: 20px;
2951 height: 20px;
2945 }
2952 }
2946
2953
2947 table.code-browser .browser-file {
2954 table.code-browser .browser-file {
2948 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2955 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2949 height: 16px;
2956 height: 16px;
2950 padding-left: 20px;
2957 padding-left: 20px;
2951 text-align: left;
2958 text-align: left;
2952 }
2959 }
2953 .diffblock .changeset_header {
2960 .diffblock .changeset_header {
2954 height: 16px;
2961 height: 16px;
2955 }
2962 }
2956 .diffblock .changeset_file {
2963 .diffblock .changeset_file {
2957 background: url("../images/icons/file.png") no-repeat scroll 3px;
2964 background: url("../images/icons/file.png") no-repeat scroll 3px;
2958 text-align: left;
2965 text-align: left;
2959 float: left;
2966 float: left;
2960 padding: 2px 0px 2px 22px;
2967 padding: 2px 0px 2px 22px;
2961 }
2968 }
2962 .diffblock .diff-menu-wrapper {
2969 .diffblock .diff-menu-wrapper {
2963 float: left;
2970 float: left;
2964 }
2971 }
2965
2972
2966 .diffblock .diff-menu {
2973 .diffblock .diff-menu {
2967 position: absolute;
2974 position: absolute;
2968 background: none repeat scroll 0 0 #FFFFFF;
2975 background: none repeat scroll 0 0 #FFFFFF;
2969 border-color: #003367 #666666 #666666;
2976 border-color: #003367 #666666 #666666;
2970 border-right: 1px solid #666666;
2977 border-right: 1px solid #666666;
2971 border-style: solid solid solid;
2978 border-style: solid solid solid;
2972 border-width: 1px;
2979 border-width: 1px;
2973 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2980 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2974 margin-top: 5px;
2981 margin-top: 5px;
2975 margin-left: 1px;
2982 margin-left: 1px;
2976
2983
2977 }
2984 }
2978 .diffblock .diff-actions {
2985 .diffblock .diff-actions {
2979 padding: 2px 0px 0px 2px;
2986 padding: 2px 0px 0px 2px;
2980 float: left;
2987 float: left;
2981 }
2988 }
2982 .diffblock .diff-menu ul li {
2989 .diffblock .diff-menu ul li {
2983 padding: 0px 0px 0px 0px !important;
2990 padding: 0px 0px 0px 0px !important;
2984 }
2991 }
2985 .diffblock .diff-menu ul li a {
2992 .diffblock .diff-menu ul li a {
2986 display: block;
2993 display: block;
2987 padding: 3px 8px 3px 8px !important;
2994 padding: 3px 8px 3px 8px !important;
2988 }
2995 }
2989 .diffblock .diff-menu ul li a:hover {
2996 .diffblock .diff-menu ul li a:hover {
2990 text-decoration: none;
2997 text-decoration: none;
2991 background-color: #EEEEEE;
2998 background-color: #EEEEEE;
2992 }
2999 }
2993 table.code-browser .browser-dir {
3000 table.code-browser .browser-dir {
2994 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
3001 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2995 height: 16px;
3002 height: 16px;
2996 padding-left: 20px;
3003 padding-left: 20px;
2997 text-align: left;
3004 text-align: left;
2998 }
3005 }
2999
3006
3000 table.code-browser .submodule-dir {
3007 table.code-browser .submodule-dir {
3001 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
3008 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
3002 height: 16px;
3009 height: 16px;
3003 padding-left: 20px;
3010 padding-left: 20px;
3004 text-align: left;
3011 text-align: left;
3005 }
3012 }
3006
3013
3007
3014
3008 .box .search {
3015 .box .search {
3009 clear: both;
3016 clear: both;
3010 overflow: hidden;
3017 overflow: hidden;
3011 margin: 0;
3018 margin: 0;
3012 padding: 0 20px 10px;
3019 padding: 0 20px 10px;
3013 }
3020 }
3014
3021
3015 .box .search div.search_path {
3022 .box .search div.search_path {
3016 background: none repeat scroll 0 0 #EEE;
3023 background: none repeat scroll 0 0 #EEE;
3017 border: 1px solid #CCC;
3024 border: 1px solid #CCC;
3018 color: blue;
3025 color: blue;
3019 margin-bottom: 10px;
3026 margin-bottom: 10px;
3020 padding: 10px 0;
3027 padding: 10px 0;
3021 }
3028 }
3022
3029
3023 .box .search div.search_path div.link {
3030 .box .search div.search_path div.link {
3024 font-weight: 700;
3031 font-weight: 700;
3025 margin-left: 25px;
3032 margin-left: 25px;
3026 }
3033 }
3027
3034
3028 .box .search div.search_path div.link a {
3035 .box .search div.search_path div.link a {
3029 color: #003367;
3036 color: #003367;
3030 cursor: pointer;
3037 cursor: pointer;
3031 text-decoration: none;
3038 text-decoration: none;
3032 }
3039 }
3033
3040
3034 #path_unlock {
3041 #path_unlock {
3035 color: red;
3042 color: red;
3036 font-size: 1.2em;
3043 font-size: 1.2em;
3037 padding-left: 4px;
3044 padding-left: 4px;
3038 }
3045 }
3039
3046
3040 .info_box span {
3047 .info_box span {
3041 margin-left: 3px;
3048 margin-left: 3px;
3042 margin-right: 3px;
3049 margin-right: 3px;
3043 }
3050 }
3044
3051
3045 .info_box .rev {
3052 .info_box .rev {
3046 color: #003367;
3053 color: #003367;
3047 font-size: 1.6em;
3054 font-size: 1.6em;
3048 font-weight: bold;
3055 font-weight: bold;
3049 vertical-align: sub;
3056 vertical-align: sub;
3050 }
3057 }
3051
3058
3052 .info_box input#at_rev, .info_box input#size {
3059 .info_box input#at_rev, .info_box input#size {
3053 background: #FFF;
3060 background: #FFF;
3054 border-top: 1px solid #b3b3b3;
3061 border-top: 1px solid #b3b3b3;
3055 border-left: 1px solid #b3b3b3;
3062 border-left: 1px solid #b3b3b3;
3056 border-right: 1px solid #eaeaea;
3063 border-right: 1px solid #eaeaea;
3057 border-bottom: 1px solid #eaeaea;
3064 border-bottom: 1px solid #eaeaea;
3058 color: #000;
3065 color: #000;
3059 font-size: 12px;
3066 font-size: 12px;
3060 margin: 0;
3067 margin: 0;
3061 padding: 1px 5px 1px;
3068 padding: 1px 5px 1px;
3062 }
3069 }
3063
3070
3064 .info_box input#view {
3071 .info_box input#view {
3065 text-align: center;
3072 text-align: center;
3066 padding: 4px 3px 2px 2px;
3073 padding: 4px 3px 2px 2px;
3067 }
3074 }
3068
3075
3069 .yui-overlay, .yui-panel-container {
3076 .yui-overlay, .yui-panel-container {
3070 visibility: hidden;
3077 visibility: hidden;
3071 position: absolute;
3078 position: absolute;
3072 z-index: 2;
3079 z-index: 2;
3073 }
3080 }
3074
3081
3075 #tip-box {
3082 #tip-box {
3076 position: absolute;
3083 position: absolute;
3077
3084
3078 background-color: #FFF;
3085 background-color: #FFF;
3079 border: 2px solid #003367;
3086 border: 2px solid #003367;
3080 font: 100% sans-serif;
3087 font: 100% sans-serif;
3081 width: auto;
3088 width: auto;
3082 opacity: 1;
3089 opacity: 1;
3083 padding: 8px;
3090 padding: 8px;
3084
3091
3085 white-space: pre-wrap;
3092 white-space: pre-wrap;
3086 -webkit-border-radius: 8px 8px 8px 8px;
3093 -webkit-border-radius: 8px 8px 8px 8px;
3087 -khtml-border-radius: 8px 8px 8px 8px;
3094 -khtml-border-radius: 8px 8px 8px 8px;
3088 border-radius: 8px 8px 8px 8px;
3095 border-radius: 8px 8px 8px 8px;
3089 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3096 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3090 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3097 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3091 }
3098 }
3092
3099
3093 .hl-tip-box {
3100 .hl-tip-box {
3094 visibility: hidden;
3101 visibility: hidden;
3095 position: absolute;
3102 position: absolute;
3096 color: #666;
3103 color: #666;
3097 background-color: #FFF;
3104 background-color: #FFF;
3098 border: 2px solid #003367;
3105 border: 2px solid #003367;
3099 font: 100% sans-serif;
3106 font: 100% sans-serif;
3100 width: auto;
3107 width: auto;
3101 opacity: 1;
3108 opacity: 1;
3102 padding: 8px;
3109 padding: 8px;
3103 white-space: pre-wrap;
3110 white-space: pre-wrap;
3104 -webkit-border-radius: 8px 8px 8px 8px;
3111 -webkit-border-radius: 8px 8px 8px 8px;
3105 -khtml-border-radius: 8px 8px 8px 8px;
3112 -khtml-border-radius: 8px 8px 8px 8px;
3106 border-radius: 8px 8px 8px 8px;
3113 border-radius: 8px 8px 8px 8px;
3107 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3114 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3108 }
3115 }
3109
3116
3110
3117
3111 .mentions-container {
3118 .mentions-container {
3112 width: 90% !important;
3119 width: 90% !important;
3113 }
3120 }
3114 .mentions-container .yui-ac-content {
3121 .mentions-container .yui-ac-content {
3115 width: 100% !important;
3122 width: 100% !important;
3116 }
3123 }
3117
3124
3118 .ac {
3125 .ac {
3119 vertical-align: top;
3126 vertical-align: top;
3120 }
3127 }
3121
3128
3122 .ac .yui-ac {
3129 .ac .yui-ac {
3123 position: inherit;
3130 position: inherit;
3124 font-size: 100%;
3131 font-size: 100%;
3125 }
3132 }
3126
3133
3127 .ac .perm_ac {
3134 .ac .perm_ac {
3128 width: 20em;
3135 width: 20em;
3129 }
3136 }
3130
3137
3131 .ac .yui-ac-input {
3138 .ac .yui-ac-input {
3132 width: 100%;
3139 width: 100%;
3133 }
3140 }
3134
3141
3135 .ac .yui-ac-container {
3142 .ac .yui-ac-container {
3136 position: absolute;
3143 position: absolute;
3137 top: 1.6em;
3144 top: 1.6em;
3138 width: auto;
3145 width: auto;
3139 }
3146 }
3140
3147
3141 .ac .yui-ac-content {
3148 .ac .yui-ac-content {
3142 position: absolute;
3149 position: absolute;
3143 border: 1px solid gray;
3150 border: 1px solid gray;
3144 background: #fff;
3151 background: #fff;
3145 z-index: 9050;
3152 z-index: 9050;
3146 }
3153 }
3147
3154
3148 .ac .yui-ac-shadow {
3155 .ac .yui-ac-shadow {
3149 position: absolute;
3156 position: absolute;
3150 width: 100%;
3157 width: 100%;
3151 background: #000;
3158 background: #000;
3152 opacity: .10;
3159 opacity: .10;
3153 filter: alpha(opacity = 10);
3160 filter: alpha(opacity = 10);
3154 z-index: 9049;
3161 z-index: 9049;
3155 margin: .3em;
3162 margin: .3em;
3156 }
3163 }
3157
3164
3158 .ac .yui-ac-content ul {
3165 .ac .yui-ac-content ul {
3159 width: 100%;
3166 width: 100%;
3160 margin: 0;
3167 margin: 0;
3161 padding: 0;
3168 padding: 0;
3162 z-index: 9050;
3169 z-index: 9050;
3163 }
3170 }
3164
3171
3165 .ac .yui-ac-content li {
3172 .ac .yui-ac-content li {
3166 cursor: default;
3173 cursor: default;
3167 white-space: nowrap;
3174 white-space: nowrap;
3168 margin: 0;
3175 margin: 0;
3169 padding: 2px 5px;
3176 padding: 2px 5px;
3170 height: 18px;
3177 height: 18px;
3171 z-index: 9050;
3178 z-index: 9050;
3172 display: block;
3179 display: block;
3173 width: auto !important;
3180 width: auto !important;
3174 }
3181 }
3175
3182
3176 .ac .yui-ac-content li .ac-container-wrap {
3183 .ac .yui-ac-content li .ac-container-wrap {
3177 width: auto;
3184 width: auto;
3178 }
3185 }
3179
3186
3180 .ac .yui-ac-content li.yui-ac-prehighlight {
3187 .ac .yui-ac-content li.yui-ac-prehighlight {
3181 background: #B3D4FF;
3188 background: #B3D4FF;
3182 z-index: 9050;
3189 z-index: 9050;
3183 }
3190 }
3184
3191
3185 .ac .yui-ac-content li.yui-ac-highlight {
3192 .ac .yui-ac-content li.yui-ac-highlight {
3186 background: #556CB5;
3193 background: #556CB5;
3187 color: #FFF;
3194 color: #FFF;
3188 z-index: 9050;
3195 z-index: 9050;
3189 }
3196 }
3190 .ac .yui-ac-bd {
3197 .ac .yui-ac-bd {
3191 z-index: 9050;
3198 z-index: 9050;
3192 }
3199 }
3193
3200
3194 .reposize {
3201 .reposize {
3195 background: url("../images/icons/server.png") no-repeat scroll 3px;
3202 background: url("../images/icons/server.png") no-repeat scroll 3px;
3196 height: 16px;
3203 height: 16px;
3197 width: 20px;
3204 width: 20px;
3198 cursor: pointer;
3205 cursor: pointer;
3199 display: block;
3206 display: block;
3200 float: right;
3207 float: right;
3201 margin-top: 2px;
3208 margin-top: 2px;
3202 }
3209 }
3203
3210
3204 #repo_size {
3211 #repo_size {
3205 display: block;
3212 display: block;
3206 margin-top: 4px;
3213 margin-top: 4px;
3207 color: #666;
3214 color: #666;
3208 float: right;
3215 float: right;
3209 }
3216 }
3210
3217
3211 .locking_locked {
3218 .locking_locked {
3212 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3219 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3213 height: 16px;
3220 height: 16px;
3214 width: 20px;
3221 width: 20px;
3215 cursor: pointer;
3222 cursor: pointer;
3216 display: block;
3223 display: block;
3217 float: right;
3224 float: right;
3218 margin-top: 2px;
3225 margin-top: 2px;
3219 }
3226 }
3220
3227
3221 .locking_unlocked {
3228 .locking_unlocked {
3222 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3229 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3223 height: 16px;
3230 height: 16px;
3224 width: 20px;
3231 width: 20px;
3225 cursor: pointer;
3232 cursor: pointer;
3226 display: block;
3233 display: block;
3227 float: right;
3234 float: right;
3228 margin-top: 2px;
3235 margin-top: 2px;
3229 }
3236 }
3230
3237
3231 .currently_following {
3238 .currently_following {
3232 padding-left: 10px;
3239 padding-left: 10px;
3233 padding-bottom: 5px;
3240 padding-bottom: 5px;
3234 }
3241 }
3235
3242
3236 .add_icon {
3243 .add_icon {
3237 background: url("../images/icons/add.png") no-repeat scroll 3px;
3244 background: url("../images/icons/add.png") no-repeat scroll 3px;
3238 padding-left: 20px;
3245 padding-left: 20px;
3239 padding-top: 0px;
3246 padding-top: 0px;
3240 text-align: left;
3247 text-align: left;
3241 }
3248 }
3242
3249
3243 .accept_icon {
3250 .accept_icon {
3244 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3251 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3245 padding-left: 20px;
3252 padding-left: 20px;
3246 padding-top: 0px;
3253 padding-top: 0px;
3247 text-align: left;
3254 text-align: left;
3248 }
3255 }
3249
3256
3250 .edit_icon {
3257 .edit_icon {
3251 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3258 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3252 padding-left: 20px;
3259 padding-left: 20px;
3253 padding-top: 0px;
3260 padding-top: 0px;
3254 text-align: left;
3261 text-align: left;
3255 }
3262 }
3256
3263
3257 .delete_icon {
3264 .delete_icon {
3258 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3265 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3259 padding-left: 20px;
3266 padding-left: 20px;
3260 padding-top: 0px;
3267 padding-top: 0px;
3261 text-align: left;
3268 text-align: left;
3262 }
3269 }
3263
3270
3264 .refresh_icon {
3271 .refresh_icon {
3265 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3272 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3266 3px;
3273 3px;
3267 padding-left: 20px;
3274 padding-left: 20px;
3268 padding-top: 0px;
3275 padding-top: 0px;
3269 text-align: left;
3276 text-align: left;
3270 }
3277 }
3271
3278
3272 .pull_icon {
3279 .pull_icon {
3273 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3280 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3274 padding-left: 20px;
3281 padding-left: 20px;
3275 padding-top: 0px;
3282 padding-top: 0px;
3276 text-align: left;
3283 text-align: left;
3277 }
3284 }
3278
3285
3279 .rss_icon {
3286 .rss_icon {
3280 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3287 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3281 padding-left: 20px;
3288 padding-left: 20px;
3282 padding-top: 4px;
3289 padding-top: 4px;
3283 text-align: left;
3290 text-align: left;
3284 font-size: 8px
3291 font-size: 8px
3285 }
3292 }
3286
3293
3287 .atom_icon {
3294 .atom_icon {
3288 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3295 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3289 padding-left: 20px;
3296 padding-left: 20px;
3290 padding-top: 4px;
3297 padding-top: 4px;
3291 text-align: left;
3298 text-align: left;
3292 font-size: 8px
3299 font-size: 8px
3293 }
3300 }
3294
3301
3295 .archive_icon {
3302 .archive_icon {
3296 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3303 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3297 padding-left: 20px;
3304 padding-left: 20px;
3298 text-align: left;
3305 text-align: left;
3299 padding-top: 1px;
3306 padding-top: 1px;
3300 }
3307 }
3301
3308
3302 .start_following_icon {
3309 .start_following_icon {
3303 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3310 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3304 padding-left: 20px;
3311 padding-left: 20px;
3305 text-align: left;
3312 text-align: left;
3306 padding-top: 0px;
3313 padding-top: 0px;
3307 }
3314 }
3308
3315
3309 .stop_following_icon {
3316 .stop_following_icon {
3310 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3317 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3311 padding-left: 20px;
3318 padding-left: 20px;
3312 text-align: left;
3319 text-align: left;
3313 padding-top: 0px;
3320 padding-top: 0px;
3314 }
3321 }
3315
3322
3316 .action_button {
3323 .action_button {
3317 border: 0;
3324 border: 0;
3318 display: inline;
3325 display: inline;
3319 }
3326 }
3320
3327
3321 .action_button:hover {
3328 .action_button:hover {
3322 border: 0;
3329 border: 0;
3323 text-decoration: underline;
3330 text-decoration: underline;
3324 cursor: pointer;
3331 cursor: pointer;
3325 }
3332 }
3326
3333
3327 #switch_repos {
3334 #switch_repos {
3328 position: absolute;
3335 position: absolute;
3329 height: 25px;
3336 height: 25px;
3330 z-index: 1;
3337 z-index: 1;
3331 }
3338 }
3332
3339
3333 #switch_repos select {
3340 #switch_repos select {
3334 min-width: 150px;
3341 min-width: 150px;
3335 max-height: 250px;
3342 max-height: 250px;
3336 z-index: 1;
3343 z-index: 1;
3337 }
3344 }
3338
3345
3339 .breadcrumbs {
3346 .breadcrumbs {
3340 border: medium none;
3347 border: medium none;
3341 color: #FFF;
3348 color: #FFF;
3342 float: left;
3349 float: left;
3343 font-weight: 700;
3350 font-weight: 700;
3344 font-size: 14px;
3351 font-size: 14px;
3345 margin: 0;
3352 margin: 0;
3346 padding: 11px 0 11px 10px;
3353 padding: 11px 0 11px 10px;
3347 }
3354 }
3348
3355
3349 .breadcrumbs .hash {
3356 .breadcrumbs .hash {
3350 text-transform: none;
3357 text-transform: none;
3351 color: #fff;
3358 color: #fff;
3352 }
3359 }
3353
3360
3354 .breadcrumbs a {
3361 .breadcrumbs a {
3355 color: #FFF;
3362 color: #FFF;
3356 }
3363 }
3357
3364
3358 .flash_msg {
3365 .flash_msg {
3359 }
3366 }
3360
3367
3361 .flash_msg ul {
3368 .flash_msg ul {
3362 }
3369 }
3363
3370
3364 .error_red {
3371 .error_red {
3365 color: red;
3372 color: red;
3366 }
3373 }
3367
3374
3368 .error_msg {
3375 .error_msg {
3369 background-color: #c43c35;
3376 background-color: #c43c35;
3370 background-repeat: repeat-x;
3377 background-repeat: repeat-x;
3371 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3378 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3372 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3379 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3373 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3380 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3374 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3381 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3375 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3382 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3376 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3383 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3377 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3384 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3378 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3385 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3379 border-color: #c43c35 #c43c35 #882a25;
3386 border-color: #c43c35 #c43c35 #882a25;
3380 }
3387 }
3381
3388
3382 .error_msg a {
3389 .error_msg a {
3383 text-decoration: underline;
3390 text-decoration: underline;
3384 }
3391 }
3385
3392
3386 .warning_msg {
3393 .warning_msg {
3387 color: #404040 !important;
3394 color: #404040 !important;
3388 background-color: #eedc94;
3395 background-color: #eedc94;
3389 background-repeat: repeat-x;
3396 background-repeat: repeat-x;
3390 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3397 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3391 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3398 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3392 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3399 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3393 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3400 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3394 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3401 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3395 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3402 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3396 background-image: linear-gradient(to bottom, #fceec1, #eedc94);
3403 background-image: linear-gradient(to bottom, #fceec1, #eedc94);
3397 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3404 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3398 border-color: #eedc94 #eedc94 #e4c652;
3405 border-color: #eedc94 #eedc94 #e4c652;
3399 }
3406 }
3400
3407
3401 .warning_msg a {
3408 .warning_msg a {
3402 text-decoration: underline;
3409 text-decoration: underline;
3403 }
3410 }
3404
3411
3405 .success_msg {
3412 .success_msg {
3406 background-color: #57a957;
3413 background-color: #57a957;
3407 background-repeat: repeat-x !important;
3414 background-repeat: repeat-x !important;
3408 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3415 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3409 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3416 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3410 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3417 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3411 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3418 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3412 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3419 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3413 background-image: -o-linear-gradient(top, #62c462, #57a957);
3420 background-image: -o-linear-gradient(top, #62c462, #57a957);
3414 background-image: linear-gradient(to bottom, #62c462, #57a957);
3421 background-image: linear-gradient(to bottom, #62c462, #57a957);
3415 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3422 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3416 border-color: #57a957 #57a957 #3d773d;
3423 border-color: #57a957 #57a957 #3d773d;
3417 }
3424 }
3418
3425
3419 .success_msg a {
3426 .success_msg a {
3420 text-decoration: underline;
3427 text-decoration: underline;
3421 color: #FFF !important;
3428 color: #FFF !important;
3422 }
3429 }
3423
3430
3424 .notice_msg {
3431 .notice_msg {
3425 background-color: #339bb9;
3432 background-color: #339bb9;
3426 background-repeat: repeat-x;
3433 background-repeat: repeat-x;
3427 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3434 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3428 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3435 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3429 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3436 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3430 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3437 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3431 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3438 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3432 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3439 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3433 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3440 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3434 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3441 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3435 border-color: #339bb9 #339bb9 #22697d;
3442 border-color: #339bb9 #339bb9 #22697d;
3436 }
3443 }
3437
3444
3438 .notice_msg a {
3445 .notice_msg a {
3439 text-decoration: underline;
3446 text-decoration: underline;
3440 }
3447 }
3441
3448
3442 .success_msg, .error_msg, .notice_msg, .warning_msg {
3449 .success_msg, .error_msg, .notice_msg, .warning_msg {
3443 font-size: 12px;
3450 font-size: 12px;
3444 font-weight: 700;
3451 font-weight: 700;
3445 min-height: 14px;
3452 min-height: 14px;
3446 line-height: 14px;
3453 line-height: 14px;
3447 margin-bottom: 10px;
3454 margin-bottom: 10px;
3448 margin-top: 0;
3455 margin-top: 0;
3449 display: block;
3456 display: block;
3450 overflow: auto;
3457 overflow: auto;
3451 padding: 6px 10px 6px 10px;
3458 padding: 6px 10px 6px 10px;
3452 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3459 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3453 position: relative;
3460 position: relative;
3454 color: #FFF;
3461 color: #FFF;
3455 border-width: 1px;
3462 border-width: 1px;
3456 border-style: solid;
3463 border-style: solid;
3457 -webkit-border-radius: 4px;
3464 -webkit-border-radius: 4px;
3458 border-radius: 4px;
3465 border-radius: 4px;
3459 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3466 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3460 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3467 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3461 }
3468 }
3462
3469
3463 #msg_close {
3470 #msg_close {
3464 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3471 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3465 cursor: pointer;
3472 cursor: pointer;
3466 height: 16px;
3473 height: 16px;
3467 position: absolute;
3474 position: absolute;
3468 right: 5px;
3475 right: 5px;
3469 top: 5px;
3476 top: 5px;
3470 width: 16px;
3477 width: 16px;
3471 }
3478 }
3472 div#legend_data {
3479 div#legend_data {
3473 padding-left: 10px;
3480 padding-left: 10px;
3474 }
3481 }
3475 div#legend_container table {
3482 div#legend_container table {
3476 border: none !important;
3483 border: none !important;
3477 }
3484 }
3478 div#legend_container table, div#legend_choices table {
3485 div#legend_container table, div#legend_choices table {
3479 width: auto !important;
3486 width: auto !important;
3480 }
3487 }
3481
3488
3482 table#permissions_manage {
3489 table#permissions_manage {
3483 width: 0 !important;
3490 width: 0 !important;
3484 }
3491 }
3485
3492
3486 table#permissions_manage span.private_repo_msg {
3493 table#permissions_manage span.private_repo_msg {
3487 font-size: 0.8em;
3494 font-size: 0.8em;
3488 opacity: 0.6;
3495 opacity: 0.6;
3489 }
3496 }
3490
3497
3491 table#permissions_manage td.private_repo_msg {
3498 table#permissions_manage td.private_repo_msg {
3492 font-size: 0.8em;
3499 font-size: 0.8em;
3493 }
3500 }
3494
3501
3495 table#permissions_manage tr#add_perm_input td {
3502 table#permissions_manage tr#add_perm_input td {
3496 vertical-align: middle;
3503 vertical-align: middle;
3497 }
3504 }
3498
3505
3499 div.gravatar {
3506 div.gravatar {
3500 background-color: #FFF;
3507 background-color: #FFF;
3501 float: left;
3508 float: left;
3502 margin-right: 0.7em;
3509 margin-right: 0.7em;
3503 padding: 1px 1px 1px 1px;
3510 padding: 1px 1px 1px 1px;
3504 line-height: 0;
3511 line-height: 0;
3505 -webkit-border-radius: 3px;
3512 -webkit-border-radius: 3px;
3506 -khtml-border-radius: 3px;
3513 -khtml-border-radius: 3px;
3507 border-radius: 3px;
3514 border-radius: 3px;
3508 }
3515 }
3509
3516
3510 div.gravatar img {
3517 div.gravatar img {
3511 -webkit-border-radius: 2px;
3518 -webkit-border-radius: 2px;
3512 -khtml-border-radius: 2px;
3519 -khtml-border-radius: 2px;
3513 border-radius: 2px;
3520 border-radius: 2px;
3514 }
3521 }
3515
3522
3516 #header, #content, #footer {
3523 #header, #content, #footer {
3517 min-width: 978px;
3524 min-width: 978px;
3518 }
3525 }
3519
3526
3520 #content {
3527 #content {
3521 clear: both;
3528 clear: both;
3522 padding: 10px 10px 14px 10px;
3529 padding: 10px 10px 14px 10px;
3523 }
3530 }
3524
3531
3525 #content.hover {
3532 #content.hover {
3526 padding: 55px 10px 14px 10px !important;
3533 padding: 55px 10px 14px 10px !important;
3527 }
3534 }
3528
3535
3529 #content div.box div.title div.search {
3536 #content div.box div.title div.search {
3530 border-left: 1px solid #316293;
3537 border-left: 1px solid #316293;
3531 }
3538 }
3532
3539
3533 #content div.box div.title div.search div.input input {
3540 #content div.box div.title div.search div.input input {
3534 border: 1px solid #316293;
3541 border: 1px solid #316293;
3535 }
3542 }
3536
3543
3537 .ui-btn {
3544 .ui-btn {
3538 color: #515151;
3545 color: #515151;
3539 background-color: #DADADA;
3546 background-color: #DADADA;
3540 background-repeat: repeat-x;
3547 background-repeat: repeat-x;
3541 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3548 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3542 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3549 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3543 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3550 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3544 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3551 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3545 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3552 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3546 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3553 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3547 background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
3554 background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
3548 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3555 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3549
3556
3550 border-top: 1px solid #DDD;
3557 border-top: 1px solid #DDD;
3551 border-left: 1px solid #c6c6c6;
3558 border-left: 1px solid #c6c6c6;
3552 border-right: 1px solid #DDD;
3559 border-right: 1px solid #DDD;
3553 border-bottom: 1px solid #c6c6c6;
3560 border-bottom: 1px solid #c6c6c6;
3554 color: #515151;
3561 color: #515151;
3555 outline: none;
3562 outline: none;
3556 margin: 0px 3px 3px 0px;
3563 margin: 0px 3px 3px 0px;
3557 -webkit-border-radius: 4px 4px 4px 4px !important;
3564 -webkit-border-radius: 4px 4px 4px 4px !important;
3558 -khtml-border-radius: 4px 4px 4px 4px !important;
3565 -khtml-border-radius: 4px 4px 4px 4px !important;
3559 border-radius: 4px 4px 4px 4px !important;
3566 border-radius: 4px 4px 4px 4px !important;
3560 cursor: pointer !important;
3567 cursor: pointer !important;
3561 padding: 3px 3px 3px 3px;
3568 padding: 3px 3px 3px 3px;
3562 background-position: 0 -15px;
3569 background-position: 0 -15px;
3563
3570
3564 }
3571 }
3565
3572
3566 .ui-btn.disabled {
3573 .ui-btn.disabled {
3567 color: #999;
3574 color: #999;
3568 }
3575 }
3569
3576
3570 .ui-btn.xsmall {
3577 .ui-btn.xsmall {
3571 padding: 1px 2px 1px 1px;
3578 padding: 1px 2px 1px 1px;
3572 }
3579 }
3573
3580
3574 .ui-btn.large {
3581 .ui-btn.large {
3575 padding: 6px 12px;
3582 padding: 6px 12px;
3576 }
3583 }
3577
3584
3578 .ui-btn.clone {
3585 .ui-btn.clone {
3579 padding: 5px 2px 6px 1px;
3586 padding: 5px 2px 6px 1px;
3580 margin: 0px 0px 3px -4px;
3587 margin: 0px 0px 3px -4px;
3581 -webkit-border-radius: 0px 4px 4px 0px !important;
3588 -webkit-border-radius: 0px 4px 4px 0px !important;
3582 -khtml-border-radius: 0px 4px 4px 0px !important;
3589 -khtml-border-radius: 0px 4px 4px 0px !important;
3583 border-radius: 0px 4px 4px 0px !important;
3590 border-radius: 0px 4px 4px 0px !important;
3584 width: 100px;
3591 width: 100px;
3585 text-align: center;
3592 text-align: center;
3586 display: inline-block;
3593 display: inline-block;
3587 position: relative;
3594 position: relative;
3588 top: -2px;
3595 top: -2px;
3589 }
3596 }
3590 .ui-btn:focus {
3597 .ui-btn:focus {
3591 outline: none;
3598 outline: none;
3592 }
3599 }
3593 .ui-btn:hover {
3600 .ui-btn:hover {
3594 background-position: 0 -15px;
3601 background-position: 0 -15px;
3595 text-decoration: none;
3602 text-decoration: none;
3596 color: #515151;
3603 color: #515151;
3597 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3604 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3598 }
3605 }
3599
3606
3600 .ui-btn.disabled:hover {
3607 .ui-btn.disabled:hover {
3601 background-position: 0;
3608 background-position: 0;
3602 color: #999;
3609 color: #999;
3603 text-decoration: none;
3610 text-decoration: none;
3604 box-shadow: none !important;
3611 box-shadow: none !important;
3605 }
3612 }
3606
3613
3607 .ui-btn.red {
3614 .ui-btn.red {
3608 color: #fff;
3615 color: #fff;
3609 background-color: #c43c35;
3616 background-color: #c43c35;
3610 background-repeat: repeat-x;
3617 background-repeat: repeat-x;
3611 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3618 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3612 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3619 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3613 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3620 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3614 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3621 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3615 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3622 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3616 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3623 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3617 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3624 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3618 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3625 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3619 border-color: #c43c35 #c43c35 #882a25;
3626 border-color: #c43c35 #c43c35 #882a25;
3620 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3627 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3621 }
3628 }
3622
3629
3623
3630
3624 .ui-btn.blue {
3631 .ui-btn.blue {
3625 color: #fff;
3632 color: #fff;
3626 background-color: #339bb9;
3633 background-color: #339bb9;
3627 background-repeat: repeat-x;
3634 background-repeat: repeat-x;
3628 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3635 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3629 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3636 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3630 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3637 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3631 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3638 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3632 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3639 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3633 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3640 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3634 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3641 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3635 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3642 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3636 border-color: #339bb9 #339bb9 #22697d;
3643 border-color: #339bb9 #339bb9 #22697d;
3637 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3644 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3638 }
3645 }
3639
3646
3640 .ui-btn.green {
3647 .ui-btn.green {
3641 background-color: #57a957;
3648 background-color: #57a957;
3642 background-repeat: repeat-x;
3649 background-repeat: repeat-x;
3643 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3650 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3644 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3651 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3645 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3652 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3646 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3653 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3647 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3654 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3648 background-image: -o-linear-gradient(top, #62c462, #57a957);
3655 background-image: -o-linear-gradient(top, #62c462, #57a957);
3649 background-image: linear-gradient(to bottom, #62c462, #57a957);
3656 background-image: linear-gradient(to bottom, #62c462, #57a957);
3650 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3657 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3651 border-color: #57a957 #57a957 #3d773d;
3658 border-color: #57a957 #57a957 #3d773d;
3652 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3659 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3653 }
3660 }
3654
3661
3655 .ui-btn.blue.hidden {
3662 .ui-btn.blue.hidden {
3656 display: none;
3663 display: none;
3657 }
3664 }
3658
3665
3659 .ui-btn.active {
3666 .ui-btn.active {
3660 font-weight: bold;
3667 font-weight: bold;
3661 }
3668 }
3662
3669
3663 ins, div.options a:hover {
3670 ins, div.options a:hover {
3664 text-decoration: none;
3671 text-decoration: none;
3665 }
3672 }
3666
3673
3667 img,
3674 img,
3668 #header #header-inner #quick li a:hover span.normal,
3675 #header #header-inner #quick li a:hover span.normal,
3669 #content div.box div.form div.fields div.field div.textarea table td table td a,
3676 #content div.box div.form div.fields div.field div.textarea table td table td a,
3670 #clone_url,
3677 #clone_url,
3671 #clone_url_id
3678 #clone_url_id
3672 {
3679 {
3673 border: none;
3680 border: none;
3674 }
3681 }
3675
3682
3676 img.icon, .right .merge img {
3683 img.icon, .right .merge img {
3677 vertical-align: bottom;
3684 vertical-align: bottom;
3678 }
3685 }
3679
3686
3680 #header ul#logged-user, #content div.box div.title ul.links,
3687 #header ul#logged-user, #content div.box div.title ul.links,
3681 #content div.box div.message div.dismiss,
3688 #content div.box div.message div.dismiss,
3682 #content div.box div.traffic div.legend ul {
3689 #content div.box div.traffic div.legend ul {
3683 float: right;
3690 float: right;
3684 margin: 0;
3691 margin: 0;
3685 padding: 0;
3692 padding: 0;
3686 }
3693 }
3687
3694
3688 #header #header-inner #home, #header #header-inner #logo,
3695 #header #header-inner #home, #header #header-inner #logo,
3689 #content div.box ul.left, #content div.box ol.left,
3696 #content div.box ul.left, #content div.box ol.left,
3690 div#commit_history,
3697 div#commit_history,
3691 div#legend_data, div#legend_container, div#legend_choices {
3698 div#legend_data, div#legend_container, div#legend_choices {
3692 float: left;
3699 float: left;
3693 }
3700 }
3694
3701
3695 #header #header-inner #quick li #quick_login,
3702 #header #header-inner #quick li #quick_login,
3696 #header #header-inner #quick li:hover ul ul,
3703 #header #header-inner #quick li:hover ul ul,
3697 #header #header-inner #quick li:hover ul ul ul,
3704 #header #header-inner #quick li:hover ul ul ul,
3698 #header #header-inner #quick li:hover ul ul ul ul,
3705 #header #header-inner #quick li:hover ul ul ul ul,
3699 #content #left #menu ul.closed, #content #left #menu li ul.collapsed, .yui-tt-shadow {
3706 #content #left #menu ul.closed, #content #left #menu li ul.collapsed, .yui-tt-shadow {
3700 display: none;
3707 display: none;
3701 }
3708 }
3702
3709
3703 #header #header-inner #quick li:hover #quick_login,
3710 #header #header-inner #quick li:hover #quick_login,
3704 #header #header-inner #quick li:hover ul, #header #header-inner #quick li li:hover ul, #header #header-inner #quick li li li:hover ul, #header #header-inner #quick li li li li:hover ul, #content #left #menu ul.opened, #content #left #menu li ul.expanded {
3711 #header #header-inner #quick li:hover ul, #header #header-inner #quick li li:hover ul, #header #header-inner #quick li li li:hover ul, #header #header-inner #quick li li li li:hover ul, #content #left #menu ul.opened, #content #left #menu li ul.expanded {
3705 display: block;
3712 display: block;
3706 }
3713 }
3707
3714
3708 #content div.graph {
3715 #content div.graph {
3709 padding: 0 10px 10px;
3716 padding: 0 10px 10px;
3710 }
3717 }
3711
3718
3712 #content div.box div.title ul.links li a:hover,
3719 #content div.box div.title ul.links li a:hover,
3713 #content div.box div.title ul.links li.ui-tabs-selected a {
3720 #content div.box div.title ul.links li.ui-tabs-selected a {
3714
3721
3715 background: #6388ad; /* Old browsers */
3722 background: #6388ad; /* Old browsers */
3716 background: -moz-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
3723 background: -moz-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
3717 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
3724 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
3718 background: -webkit-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
3725 background: -webkit-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
3719 background: -o-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Opera 11.10+ */
3726 background: -o-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Opera 11.10+ */
3720 background: -ms-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* IE10+ */
3727 background: -ms-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* IE10+ */
3721 background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* W3C */
3728 background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* W3C */
3722 /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88bfe8', endColorstr='#70b0e0',GradientType=0 ); /* IE6-9 */*/
3729 /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88bfe8', endColorstr='#70b0e0',GradientType=0 ); /* IE6-9 */*/
3723 }
3730 }
3724
3731
3725 #content div.box ol.lower-roman, #content div.box ol.upper-roman, #content div.box ol.lower-alpha, #content div.box ol.upper-alpha, #content div.box ol.decimal {
3732 #content div.box ol.lower-roman, #content div.box ol.upper-roman, #content div.box ol.lower-alpha, #content div.box ol.upper-alpha, #content div.box ol.decimal {
3726 margin: 10px 24px 10px 44px;
3733 margin: 10px 24px 10px 44px;
3727 }
3734 }
3728
3735
3729 #content div.box div.form, #content div.box div.table, #content div.box div.traffic {
3736 #content div.box div.form, #content div.box div.table, #content div.box div.traffic {
3730 position: relative;
3737 position: relative;
3731 clear: both;
3738 clear: both;
3732 margin: 0;
3739 margin: 0;
3733 padding: 0 20px 10px;
3740 padding: 0 20px 10px;
3734 }
3741 }
3735
3742
3736 #content div.box div.form div.fields, #login div.form, #login div.form div.fields, #register div.form, #register div.form div.fields {
3743 #content div.box div.form div.fields, #login div.form, #login div.form div.fields, #register div.form, #register div.form div.fields {
3737 clear: both;
3744 clear: both;
3738 overflow: hidden;
3745 overflow: hidden;
3739 margin: 0;
3746 margin: 0;
3740 padding: 0;
3747 padding: 0;
3741 }
3748 }
3742
3749
3743 #content div.box div.form div.fields div.field div.label span, #login div.form div.fields div.field div.label span, #register div.form div.fields div.field div.label span {
3750 #content div.box div.form div.fields div.field div.label span, #login div.form div.fields div.field div.label span, #register div.form div.fields div.field div.label span {
3744 height: 1%;
3751 height: 1%;
3745 display: block;
3752 display: block;
3746 color: #363636;
3753 color: #363636;
3747 margin: 0;
3754 margin: 0;
3748 padding: 2px 0 0;
3755 padding: 2px 0 0;
3749 }
3756 }
3750
3757
3751 #content div.box div.form div.fields div.field div.input input.error, #login div.form div.fields div.field div.input input.error, #register div.form div.fields div.field div.input input.error {
3758 #content div.box div.form div.fields div.field div.input input.error, #login div.form div.fields div.field div.input input.error, #register div.form div.fields div.field div.input input.error {
3752 background: #FBE3E4;
3759 background: #FBE3E4;
3753 border-top: 1px solid #e1b2b3;
3760 border-top: 1px solid #e1b2b3;
3754 border-left: 1px solid #e1b2b3;
3761 border-left: 1px solid #e1b2b3;
3755 border-right: 1px solid #FBC2C4;
3762 border-right: 1px solid #FBC2C4;
3756 border-bottom: 1px solid #FBC2C4;
3763 border-bottom: 1px solid #FBC2C4;
3757 }
3764 }
3758
3765
3759 #content div.box div.form div.fields div.field div.input input.success, #login div.form div.fields div.field div.input input.success, #register div.form div.fields div.field div.input input.success {
3766 #content div.box div.form div.fields div.field div.input input.success, #login div.form div.fields div.field div.input input.success, #register div.form div.fields div.field div.input input.success {
3760 background: #E6EFC2;
3767 background: #E6EFC2;
3761 border-top: 1px solid #cebb98;
3768 border-top: 1px solid #cebb98;
3762 border-left: 1px solid #cebb98;
3769 border-left: 1px solid #cebb98;
3763 border-right: 1px solid #c6d880;
3770 border-right: 1px solid #c6d880;
3764 border-bottom: 1px solid #c6d880;
3771 border-bottom: 1px solid #c6d880;
3765 }
3772 }
3766
3773
3767 #content div.box-left div.form div.fields div.field div.textarea, #content div.box-right div.form div.fields div.field div.textarea, #content div.box div.form div.fields div.field div.select select, #content div.box table th.selected input, #content div.box table td.selected input {
3774 #content div.box-left div.form div.fields div.field div.textarea, #content div.box-right div.form div.fields div.field div.textarea, #content div.box div.form div.fields div.field div.select select, #content div.box table th.selected input, #content div.box table td.selected input {
3768 margin: 0;
3775 margin: 0;
3769 }
3776 }
3770
3777
3771 #content div.box-left div.form div.fields div.field div.select, #content div.box-left div.form div.fields div.field div.checkboxes, #content div.box-left div.form div.fields div.field div.radios, #content div.box-right div.form div.fields div.field div.select, #content div.box-right div.form div.fields div.field div.checkboxes, #content div.box-right div.form div.fields div.field div.radios {
3778 #content div.box-left div.form div.fields div.field div.select, #content div.box-left div.form div.fields div.field div.checkboxes, #content div.box-left div.form div.fields div.field div.radios, #content div.box-right div.form div.fields div.field div.select, #content div.box-right div.form div.fields div.field div.checkboxes, #content div.box-right div.form div.fields div.field div.radios {
3772 margin: 0 0 0 0px !important;
3779 margin: 0 0 0 0px !important;
3773 padding: 0;
3780 padding: 0;
3774 }
3781 }
3775
3782
3776 #content div.box div.form div.fields div.field div.select, #content div.box div.form div.fields div.field div.checkboxes, #content div.box div.form div.fields div.field div.radios {
3783 #content div.box div.form div.fields div.field div.select, #content div.box div.form div.fields div.field div.checkboxes, #content div.box div.form div.fields div.field div.radios {
3777 margin: 0 0 0 200px;
3784 margin: 0 0 0 200px;
3778 padding: 0;
3785 padding: 0;
3779 }
3786 }
3780
3787
3781 #content div.box div.form div.fields div.field div.select a:hover, #content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover, #content div.box div.action a:hover {
3788 #content div.box div.form div.fields div.field div.select a:hover, #content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover, #content div.box div.action a:hover {
3782 color: #000;
3789 color: #000;
3783 text-decoration: none;
3790 text-decoration: none;
3784 }
3791 }
3785
3792
3786 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus, #content div.box div.action a.ui-selectmenu-focus {
3793 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus, #content div.box div.action a.ui-selectmenu-focus {
3787 border: 1px solid #666;
3794 border: 1px solid #666;
3788 }
3795 }
3789
3796
3790 #content div.box div.form div.fields div.field div.checkboxes div.checkbox, #content div.box div.form div.fields div.field div.radios div.radio {
3797 #content div.box div.form div.fields div.field div.checkboxes div.checkbox, #content div.box div.form div.fields div.field div.radios div.radio {
3791 clear: both;
3798 clear: both;
3792 overflow: hidden;
3799 overflow: hidden;
3793 margin: 0;
3800 margin: 0;
3794 padding: 8px 0 2px;
3801 padding: 8px 0 2px;
3795 }
3802 }
3796
3803
3797 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input, #content div.box div.form div.fields div.field div.radios div.radio input {
3804 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input, #content div.box div.form div.fields div.field div.radios div.radio input {
3798 float: left;
3805 float: left;
3799 margin: 0;
3806 margin: 0;
3800 }
3807 }
3801
3808
3802 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label, #content div.box div.form div.fields div.field div.radios div.radio label {
3809 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label, #content div.box div.form div.fields div.field div.radios div.radio label {
3803 height: 1%;
3810 height: 1%;
3804 display: block;
3811 display: block;
3805 float: left;
3812 float: left;
3806 margin: 2px 0 0 4px;
3813 margin: 2px 0 0 4px;
3807 }
3814 }
3808
3815
3809 div.form div.fields div.field div.button input,
3816 div.form div.fields div.field div.button input,
3810 #content div.box div.form div.fields div.buttons input
3817 #content div.box div.form div.fields div.buttons input
3811 div.form div.fields div.buttons input,
3818 div.form div.fields div.buttons input,
3812 #content div.box div.action div.button input {
3819 #content div.box div.action div.button input {
3813 font-size: 11px;
3820 font-size: 11px;
3814 font-weight: 700;
3821 font-weight: 700;
3815 margin: 0;
3822 margin: 0;
3816 }
3823 }
3817
3824
3818 input.ui-button {
3825 input.ui-button {
3819 background: #e5e3e3 url("../images/button.png") repeat-x;
3826 background: #e5e3e3 url("../images/button.png") repeat-x;
3820 border-top: 1px solid #DDD;
3827 border-top: 1px solid #DDD;
3821 border-left: 1px solid #c6c6c6;
3828 border-left: 1px solid #c6c6c6;
3822 border-right: 1px solid #DDD;
3829 border-right: 1px solid #DDD;
3823 border-bottom: 1px solid #c6c6c6;
3830 border-bottom: 1px solid #c6c6c6;
3824 color: #515151 !important;
3831 color: #515151 !important;
3825 outline: none;
3832 outline: none;
3826 margin: 0;
3833 margin: 0;
3827 padding: 6px 12px;
3834 padding: 6px 12px;
3828 -webkit-border-radius: 4px 4px 4px 4px;
3835 -webkit-border-radius: 4px 4px 4px 4px;
3829 -khtml-border-radius: 4px 4px 4px 4px;
3836 -khtml-border-radius: 4px 4px 4px 4px;
3830 border-radius: 4px 4px 4px 4px;
3837 border-radius: 4px 4px 4px 4px;
3831 box-shadow: 0 1px 0 #ececec;
3838 box-shadow: 0 1px 0 #ececec;
3832 cursor: pointer;
3839 cursor: pointer;
3833 }
3840 }
3834
3841
3835 input.ui-button:hover {
3842 input.ui-button:hover {
3836 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3843 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3837 border-top: 1px solid #ccc;
3844 border-top: 1px solid #ccc;
3838 border-left: 1px solid #bebebe;
3845 border-left: 1px solid #bebebe;
3839 border-right: 1px solid #b1b1b1;
3846 border-right: 1px solid #b1b1b1;
3840 border-bottom: 1px solid #afafaf;
3847 border-bottom: 1px solid #afafaf;
3841 }
3848 }
3842
3849
3843 div.form div.fields div.field div.highlight, #content div.box div.form div.fields div.buttons div.highlight {
3850 div.form div.fields div.field div.highlight, #content div.box div.form div.fields div.buttons div.highlight {
3844 display: inline;
3851 display: inline;
3845 }
3852 }
3846
3853
3847 #content div.box div.form div.fields div.buttons, div.form div.fields div.buttons {
3854 #content div.box div.form div.fields div.buttons, div.form div.fields div.buttons {
3848 margin: 10px 0 0 200px;
3855 margin: 10px 0 0 200px;
3849 padding: 0;
3856 padding: 0;
3850 }
3857 }
3851
3858
3852 #content div.box-left div.form div.fields div.buttons, #content div.box-right div.form div.fields div.buttons, div.box-left div.form div.fields div.buttons, div.box-right div.form div.fields div.buttons {
3859 #content div.box-left div.form div.fields div.buttons, #content div.box-right div.form div.fields div.buttons, div.box-left div.form div.fields div.buttons, div.box-right div.form div.fields div.buttons {
3853 margin: 10px 0 0;
3860 margin: 10px 0 0;
3854 }
3861 }
3855
3862
3856 #content div.box table td.user, #content div.box table td.address {
3863 #content div.box table td.user, #content div.box table td.address {
3857 width: 10%;
3864 width: 10%;
3858 text-align: center;
3865 text-align: center;
3859 }
3866 }
3860
3867
3861 #content div.box div.action div.button, #login div.form div.fields div.field div.input div.link, #register div.form div.fields div.field div.input div.link {
3868 #content div.box div.action div.button, #login div.form div.fields div.field div.input div.link, #register div.form div.fields div.field div.input div.link {
3862 text-align: right;
3869 text-align: right;
3863 margin: 6px 0 0;
3870 margin: 6px 0 0;
3864 padding: 0;
3871 padding: 0;
3865 }
3872 }
3866
3873
3867 #content div.box div.action div.button input.ui-state-hover, #login div.form div.fields div.buttons input.ui-state-hover, #register div.form div.fields div.buttons input.ui-state-hover {
3874 #content div.box div.action div.button input.ui-state-hover, #login div.form div.fields div.buttons input.ui-state-hover, #register div.form div.fields div.buttons input.ui-state-hover {
3868 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3875 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3869 border-top: 1px solid #ccc;
3876 border-top: 1px solid #ccc;
3870 border-left: 1px solid #bebebe;
3877 border-left: 1px solid #bebebe;
3871 border-right: 1px solid #b1b1b1;
3878 border-right: 1px solid #b1b1b1;
3872 border-bottom: 1px solid #afafaf;
3879 border-bottom: 1px solid #afafaf;
3873 color: #515151;
3880 color: #515151;
3874 margin: 0;
3881 margin: 0;
3875 padding: 6px 12px;
3882 padding: 6px 12px;
3876 }
3883 }
3877
3884
3878 #content div.box div.pagination div.results, #content div.box div.pagination-wh div.results {
3885 #content div.box div.pagination div.results, #content div.box div.pagination-wh div.results {
3879 text-align: left;
3886 text-align: left;
3880 float: left;
3887 float: left;
3881 margin: 0;
3888 margin: 0;
3882 padding: 0;
3889 padding: 0;
3883 }
3890 }
3884
3891
3885 #content div.box div.pagination div.results span, #content div.box div.pagination-wh div.results span {
3892 #content div.box div.pagination div.results span, #content div.box div.pagination-wh div.results span {
3886 height: 1%;
3893 height: 1%;
3887 display: block;
3894 display: block;
3888 float: left;
3895 float: left;
3889 background: #ebebeb url("../images/pager.png") repeat-x;
3896 background: #ebebeb url("../images/pager.png") repeat-x;
3890 border-top: 1px solid #dedede;
3897 border-top: 1px solid #dedede;
3891 border-left: 1px solid #cfcfcf;
3898 border-left: 1px solid #cfcfcf;
3892 border-right: 1px solid #c4c4c4;
3899 border-right: 1px solid #c4c4c4;
3893 border-bottom: 1px solid #c4c4c4;
3900 border-bottom: 1px solid #c4c4c4;
3894 color: #4A4A4A;
3901 color: #4A4A4A;
3895 font-weight: 700;
3902 font-weight: 700;
3896 margin: 0;
3903 margin: 0;
3897 padding: 6px 8px;
3904 padding: 6px 8px;
3898 }
3905 }
3899
3906
3900 #content div.box div.pagination ul.pager li.disabled, #content div.box div.pagination-wh a.disabled {
3907 #content div.box div.pagination ul.pager li.disabled, #content div.box div.pagination-wh a.disabled {
3901 color: #B4B4B4;
3908 color: #B4B4B4;
3902 padding: 6px;
3909 padding: 6px;
3903 }
3910 }
3904
3911
3905 #login, #register {
3912 #login, #register {
3906 width: 520px;
3913 width: 520px;
3907 margin: 10% auto 0;
3914 margin: 10% auto 0;
3908 padding: 0;
3915 padding: 0;
3909 }
3916 }
3910
3917
3911 #login div.color, #register div.color {
3918 #login div.color, #register div.color {
3912 clear: both;
3919 clear: both;
3913 overflow: hidden;
3920 overflow: hidden;
3914 background: #FFF;
3921 background: #FFF;
3915 margin: 10px auto 0;
3922 margin: 10px auto 0;
3916 padding: 3px 3px 3px 0;
3923 padding: 3px 3px 3px 0;
3917 }
3924 }
3918
3925
3919 #login div.color a, #register div.color a {
3926 #login div.color a, #register div.color a {
3920 width: 20px;
3927 width: 20px;
3921 height: 20px;
3928 height: 20px;
3922 display: block;
3929 display: block;
3923 float: left;
3930 float: left;
3924 margin: 0 0 0 3px;
3931 margin: 0 0 0 3px;
3925 padding: 0;
3932 padding: 0;
3926 }
3933 }
3927
3934
3928 #login div.title h5, #register div.title h5 {
3935 #login div.title h5, #register div.title h5 {
3929 color: #fff;
3936 color: #fff;
3930 margin: 10px;
3937 margin: 10px;
3931 padding: 0;
3938 padding: 0;
3932 }
3939 }
3933
3940
3934 #login div.form div.fields div.field, #register div.form div.fields div.field {
3941 #login div.form div.fields div.field, #register div.form div.fields div.field {
3935 clear: both;
3942 clear: both;
3936 overflow: hidden;
3943 overflow: hidden;
3937 margin: 0;
3944 margin: 0;
3938 padding: 0 0 10px;
3945 padding: 0 0 10px;
3939 }
3946 }
3940
3947
3941 #login div.form div.fields div.field span.error-message, #register div.form div.fields div.field span.error-message {
3948 #login div.form div.fields div.field span.error-message, #register div.form div.fields div.field span.error-message {
3942 height: 1%;
3949 height: 1%;
3943 display: block;
3950 display: block;
3944 color: red;
3951 color: red;
3945 margin: 8px 0 0;
3952 margin: 8px 0 0;
3946 padding: 0;
3953 padding: 0;
3947 max-width: 320px;
3954 max-width: 320px;
3948 }
3955 }
3949
3956
3950 #login div.form div.fields div.field div.label label, #register div.form div.fields div.field div.label label {
3957 #login div.form div.fields div.field div.label label, #register div.form div.fields div.field div.label label {
3951 color: #000;
3958 color: #000;
3952 font-weight: 700;
3959 font-weight: 700;
3953 }
3960 }
3954
3961
3955 #login div.form div.fields div.field div.input, #register div.form div.fields div.field div.input {
3962 #login div.form div.fields div.field div.input, #register div.form div.fields div.field div.input {
3956 float: left;
3963 float: left;
3957 margin: 0;
3964 margin: 0;
3958 padding: 0;
3965 padding: 0;
3959 }
3966 }
3960
3967
3961 #login div.form div.fields div.field div.input input.large {
3968 #login div.form div.fields div.field div.input input.large {
3962 width: 250px;
3969 width: 250px;
3963 }
3970 }
3964
3971
3965 #login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
3972 #login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
3966 margin: 0 0 0 184px;
3973 margin: 0 0 0 184px;
3967 padding: 0;
3974 padding: 0;
3968 }
3975 }
3969
3976
3970 #login div.form div.fields div.field div.checkbox label, #register div.form div.fields div.field div.checkbox label {
3977 #login div.form div.fields div.field div.checkbox label, #register div.form div.fields div.field div.checkbox label {
3971 color: #565656;
3978 color: #565656;
3972 font-weight: 700;
3979 font-weight: 700;
3973 }
3980 }
3974
3981
3975 #login div.form div.fields div.buttons input, #register div.form div.fields div.buttons input {
3982 #login div.form div.fields div.buttons input, #register div.form div.fields div.buttons input {
3976 color: #000;
3983 color: #000;
3977 font-size: 1em;
3984 font-size: 1em;
3978 font-weight: 700;
3985 font-weight: 700;
3979 margin: 0;
3986 margin: 0;
3980 }
3987 }
3981
3988
3982 #changeset_content .container .wrapper, #graph_content .container .wrapper {
3989 #changeset_content .container .wrapper, #graph_content .container .wrapper {
3983 width: 600px;
3990 width: 600px;
3984 }
3991 }
3985
3992
3986 #changeset_content .container .date, .ac .match {
3993 #changeset_content .container .date, .ac .match {
3987 font-weight: 700;
3994 font-weight: 700;
3988 padding-top: 5px;
3995 padding-top: 5px;
3989 padding-bottom: 5px;
3996 padding-bottom: 5px;
3990 }
3997 }
3991
3998
3992 div#legend_container table td, div#legend_choices table td {
3999 div#legend_container table td, div#legend_choices table td {
3993 border: none !important;
4000 border: none !important;
3994 height: 20px !important;
4001 height: 20px !important;
3995 padding: 0 !important;
4002 padding: 0 !important;
3996 }
4003 }
3997
4004
3998 .q_filter_box {
4005 .q_filter_box {
3999 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4006 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4000 -webkit-border-radius: 4px;
4007 -webkit-border-radius: 4px;
4001 border-radius: 4px;
4008 border-radius: 4px;
4002 border: 0 none;
4009 border: 0 none;
4003 color: #AAAAAA;
4010 color: #AAAAAA;
4004 margin-bottom: -4px;
4011 margin-bottom: -4px;
4005 margin-top: -4px;
4012 margin-top: -4px;
4006 padding-left: 3px;
4013 padding-left: 3px;
4007 }
4014 }
4008
4015
4009 #node_filter {
4016 #node_filter {
4010 border: 0px solid #545454;
4017 border: 0px solid #545454;
4011 color: #AAAAAA;
4018 color: #AAAAAA;
4012 padding-left: 3px;
4019 padding-left: 3px;
4013 }
4020 }
4014
4021
4015
4022
4016 .group_members_wrap {
4023 .group_members_wrap {
4017 min-height: 85px;
4024 min-height: 85px;
4018 padding-left: 20px;
4025 padding-left: 20px;
4019 }
4026 }
4020
4027
4021 .group_members .group_member {
4028 .group_members .group_member {
4022 height: 30px;
4029 height: 30px;
4023 padding: 0px 0px 0px 0px;
4030 padding: 0px 0px 0px 0px;
4024 }
4031 }
4025
4032
4026 .reviewers_member {
4033 .reviewers_member {
4027 height: 15px;
4034 height: 15px;
4028 padding: 0px 0px 0px 10px;
4035 padding: 0px 0px 0px 10px;
4029 }
4036 }
4030
4037
4031 .emails_wrap {
4038 .emails_wrap {
4032 padding: 0px 20px;
4039 padding: 0px 20px;
4033 }
4040 }
4034
4041
4035 .emails_wrap .email_entry {
4042 .emails_wrap .email_entry {
4036 height: 30px;
4043 height: 30px;
4037 padding: 0px 0px 0px 10px;
4044 padding: 0px 0px 0px 10px;
4038 }
4045 }
4039 .emails_wrap .email_entry .email {
4046 .emails_wrap .email_entry .email {
4040 float: left
4047 float: left
4041 }
4048 }
4042 .emails_wrap .email_entry .email_action {
4049 .emails_wrap .email_entry .email_action {
4043 float: left
4050 float: left
4044 }
4051 }
4045
4052
4046 .ips_wrap {
4053 .ips_wrap {
4047 padding: 0px 20px;
4054 padding: 0px 20px;
4048 }
4055 }
4049
4056
4050 .ips_wrap .ip_entry {
4057 .ips_wrap .ip_entry {
4051 height: 30px;
4058 height: 30px;
4052 padding: 0px 0px 0px 10px;
4059 padding: 0px 0px 0px 10px;
4053 }
4060 }
4054 .ips_wrap .ip_entry .ip {
4061 .ips_wrap .ip_entry .ip {
4055 float: left
4062 float: left
4056 }
4063 }
4057 .ips_wrap .ip_entry .ip_action {
4064 .ips_wrap .ip_entry .ip_action {
4058 float: left
4065 float: left
4059 }
4066 }
4060
4067
4061
4068
4062 /*README STYLE*/
4069 /*README STYLE*/
4063
4070
4064 div.readme {
4071 div.readme {
4065 padding: 0px;
4072 padding: 0px;
4066 }
4073 }
4067
4074
4068 div.readme h2 {
4075 div.readme h2 {
4069 font-weight: normal;
4076 font-weight: normal;
4070 }
4077 }
4071
4078
4072 div.readme .readme_box {
4079 div.readme .readme_box {
4073 background-color: #fafafa;
4080 background-color: #fafafa;
4074 }
4081 }
4075
4082
4076 div.readme .readme_box {
4083 div.readme .readme_box {
4077 clear: both;
4084 clear: both;
4078 overflow: hidden;
4085 overflow: hidden;
4079 margin: 0;
4086 margin: 0;
4080 padding: 0 20px 10px;
4087 padding: 0 20px 10px;
4081 }
4088 }
4082
4089
4083 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4090 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4084 border-bottom: 0 !important;
4091 border-bottom: 0 !important;
4085 margin: 0 !important;
4092 margin: 0 !important;
4086 padding: 0 !important;
4093 padding: 0 !important;
4087 line-height: 1.5em !important;
4094 line-height: 1.5em !important;
4088 }
4095 }
4089
4096
4090
4097
4091 div.readme .readme_box h1:first-child {
4098 div.readme .readme_box h1:first-child {
4092 padding-top: .25em !important;
4099 padding-top: .25em !important;
4093 }
4100 }
4094
4101
4095 div.readme .readme_box h2, div.readme .readme_box h3 {
4102 div.readme .readme_box h2, div.readme .readme_box h3 {
4096 margin: 1em 0 !important;
4103 margin: 1em 0 !important;
4097 }
4104 }
4098
4105
4099 div.readme .readme_box h2 {
4106 div.readme .readme_box h2 {
4100 margin-top: 1.5em !important;
4107 margin-top: 1.5em !important;
4101 border-top: 4px solid #e0e0e0 !important;
4108 border-top: 4px solid #e0e0e0 !important;
4102 padding-top: .5em !important;
4109 padding-top: .5em !important;
4103 }
4110 }
4104
4111
4105 div.readme .readme_box p {
4112 div.readme .readme_box p {
4106 color: black !important;
4113 color: black !important;
4107 margin: 1em 0 !important;
4114 margin: 1em 0 !important;
4108 line-height: 1.5em !important;
4115 line-height: 1.5em !important;
4109 }
4116 }
4110
4117
4111 div.readme .readme_box ul {
4118 div.readme .readme_box ul {
4112 list-style: disc !important;
4119 list-style: disc !important;
4113 margin: 1em 0 1em 2em !important;
4120 margin: 1em 0 1em 2em !important;
4114 }
4121 }
4115
4122
4116 div.readme .readme_box ol {
4123 div.readme .readme_box ol {
4117 list-style: decimal;
4124 list-style: decimal;
4118 margin: 1em 0 1em 2em !important;
4125 margin: 1em 0 1em 2em !important;
4119 }
4126 }
4120
4127
4121 div.readme .readme_box pre, code {
4128 div.readme .readme_box pre, code {
4122 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4129 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4123 }
4130 }
4124
4131
4125 div.readme .readme_box code {
4132 div.readme .readme_box code {
4126 font-size: 12px !important;
4133 font-size: 12px !important;
4127 background-color: ghostWhite !important;
4134 background-color: ghostWhite !important;
4128 color: #444 !important;
4135 color: #444 !important;
4129 padding: 0 .2em !important;
4136 padding: 0 .2em !important;
4130 border: 1px solid #dedede !important;
4137 border: 1px solid #dedede !important;
4131 }
4138 }
4132
4139
4133 div.readme .readme_box pre code {
4140 div.readme .readme_box pre code {
4134 padding: 0 !important;
4141 padding: 0 !important;
4135 font-size: 12px !important;
4142 font-size: 12px !important;
4136 background-color: #eee !important;
4143 background-color: #eee !important;
4137 border: none !important;
4144 border: none !important;
4138 }
4145 }
4139
4146
4140 div.readme .readme_box pre {
4147 div.readme .readme_box pre {
4141 margin: 1em 0;
4148 margin: 1em 0;
4142 font-size: 12px;
4149 font-size: 12px;
4143 background-color: #eee;
4150 background-color: #eee;
4144 border: 1px solid #ddd;
4151 border: 1px solid #ddd;
4145 padding: 5px;
4152 padding: 5px;
4146 color: #444;
4153 color: #444;
4147 overflow: auto;
4154 overflow: auto;
4148 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4155 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4149 -webkit-border-radius: 3px;
4156 -webkit-border-radius: 3px;
4150 border-radius: 3px;
4157 border-radius: 3px;
4151 }
4158 }
4152
4159
4153 div.readme .readme_box table {
4160 div.readme .readme_box table {
4154 display: table;
4161 display: table;
4155 border-collapse: separate;
4162 border-collapse: separate;
4156 border-spacing: 2px;
4163 border-spacing: 2px;
4157 border-color: gray;
4164 border-color: gray;
4158 width: auto !important;
4165 width: auto !important;
4159 }
4166 }
4160
4167
4161
4168
4162 /** RST STYLE **/
4169 /** RST STYLE **/
4163
4170
4164
4171
4165 div.rst-block {
4172 div.rst-block {
4166 padding: 0px;
4173 padding: 0px;
4167 }
4174 }
4168
4175
4169 div.rst-block h2 {
4176 div.rst-block h2 {
4170 font-weight: normal;
4177 font-weight: normal;
4171 }
4178 }
4172
4179
4173 div.rst-block {
4180 div.rst-block {
4174 background-color: #fafafa;
4181 background-color: #fafafa;
4175 }
4182 }
4176
4183
4177 div.rst-block {
4184 div.rst-block {
4178 clear: both;
4185 clear: both;
4179 overflow: hidden;
4186 overflow: hidden;
4180 margin: 0;
4187 margin: 0;
4181 padding: 0 20px 10px;
4188 padding: 0 20px 10px;
4182 }
4189 }
4183
4190
4184 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4191 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4185 border-bottom: 0 !important;
4192 border-bottom: 0 !important;
4186 margin: 0 !important;
4193 margin: 0 !important;
4187 padding: 0 !important;
4194 padding: 0 !important;
4188 line-height: 1.5em !important;
4195 line-height: 1.5em !important;
4189 }
4196 }
4190
4197
4191
4198
4192 div.rst-block h1:first-child {
4199 div.rst-block h1:first-child {
4193 padding-top: .25em !important;
4200 padding-top: .25em !important;
4194 }
4201 }
4195
4202
4196 div.rst-block h2, div.rst-block h3 {
4203 div.rst-block h2, div.rst-block h3 {
4197 margin: 1em 0 !important;
4204 margin: 1em 0 !important;
4198 }
4205 }
4199
4206
4200 div.rst-block h2 {
4207 div.rst-block h2 {
4201 margin-top: 1.5em !important;
4208 margin-top: 1.5em !important;
4202 border-top: 4px solid #e0e0e0 !important;
4209 border-top: 4px solid #e0e0e0 !important;
4203 padding-top: .5em !important;
4210 padding-top: .5em !important;
4204 }
4211 }
4205
4212
4206 div.rst-block p {
4213 div.rst-block p {
4207 color: black !important;
4214 color: black !important;
4208 margin: 1em 0 !important;
4215 margin: 1em 0 !important;
4209 line-height: 1.5em !important;
4216 line-height: 1.5em !important;
4210 }
4217 }
4211
4218
4212 div.rst-block ul {
4219 div.rst-block ul {
4213 list-style: disc !important;
4220 list-style: disc !important;
4214 margin: 1em 0 1em 2em !important;
4221 margin: 1em 0 1em 2em !important;
4215 }
4222 }
4216
4223
4217 div.rst-block ol {
4224 div.rst-block ol {
4218 list-style: decimal;
4225 list-style: decimal;
4219 margin: 1em 0 1em 2em !important;
4226 margin: 1em 0 1em 2em !important;
4220 }
4227 }
4221
4228
4222 div.rst-block pre, code {
4229 div.rst-block pre, code {
4223 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4230 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4224 }
4231 }
4225
4232
4226 div.rst-block code {
4233 div.rst-block code {
4227 font-size: 12px !important;
4234 font-size: 12px !important;
4228 background-color: ghostWhite !important;
4235 background-color: ghostWhite !important;
4229 color: #444 !important;
4236 color: #444 !important;
4230 padding: 0 .2em !important;
4237 padding: 0 .2em !important;
4231 border: 1px solid #dedede !important;
4238 border: 1px solid #dedede !important;
4232 }
4239 }
4233
4240
4234 div.rst-block pre code {
4241 div.rst-block pre code {
4235 padding: 0 !important;
4242 padding: 0 !important;
4236 font-size: 12px !important;
4243 font-size: 12px !important;
4237 background-color: #eee !important;
4244 background-color: #eee !important;
4238 border: none !important;
4245 border: none !important;
4239 }
4246 }
4240
4247
4241 div.rst-block pre {
4248 div.rst-block pre {
4242 margin: 1em 0;
4249 margin: 1em 0;
4243 font-size: 12px;
4250 font-size: 12px;
4244 background-color: #eee;
4251 background-color: #eee;
4245 border: 1px solid #ddd;
4252 border: 1px solid #ddd;
4246 padding: 5px;
4253 padding: 5px;
4247 color: #444;
4254 color: #444;
4248 overflow: auto;
4255 overflow: auto;
4249 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4256 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4250 -webkit-border-radius: 3px;
4257 -webkit-border-radius: 3px;
4251 border-radius: 3px;
4258 border-radius: 3px;
4252 }
4259 }
4253
4260
4254
4261
4255 /** comment main **/
4262 /** comment main **/
4256 .comments {
4263 .comments {
4257 padding: 10px 20px;
4264 padding: 10px 20px;
4258 }
4265 }
4259
4266
4260 .comments .comment {
4267 .comments .comment {
4261 border: 1px solid #ddd;
4268 border: 1px solid #ddd;
4262 margin-top: 10px;
4269 margin-top: 10px;
4263 -webkit-border-radius: 4px;
4270 -webkit-border-radius: 4px;
4264 border-radius: 4px;
4271 border-radius: 4px;
4265 }
4272 }
4266
4273
4267 .comments .comment .meta {
4274 .comments .comment .meta {
4268 background: #f8f8f8;
4275 background: #f8f8f8;
4269 padding: 4px;
4276 padding: 4px;
4270 border-bottom: 1px solid #ddd;
4277 border-bottom: 1px solid #ddd;
4271 height: 18px;
4278 height: 18px;
4272 }
4279 }
4273
4280
4274 .comments .comment .meta img {
4281 .comments .comment .meta img {
4275 vertical-align: middle;
4282 vertical-align: middle;
4276 }
4283 }
4277
4284
4278 .comments .comment .meta .user {
4285 .comments .comment .meta .user {
4279 font-weight: bold;
4286 font-weight: bold;
4280 float: left;
4287 float: left;
4281 padding: 4px 2px 2px 2px;
4288 padding: 4px 2px 2px 2px;
4282 }
4289 }
4283
4290
4284 .comments .comment .meta .date {
4291 .comments .comment .meta .date {
4285 float: left;
4292 float: left;
4286 padding: 4px 4px 0px 4px;
4293 padding: 4px 4px 0px 4px;
4287 }
4294 }
4288
4295
4289 .comments .comment .text {
4296 .comments .comment .text {
4290 background-color: #FAFAFA;
4297 background-color: #FAFAFA;
4291 }
4298 }
4292 .comment .text div.rst-block p {
4299 .comment .text div.rst-block p {
4293 margin: 0.5em 0px !important;
4300 margin: 0.5em 0px !important;
4294 }
4301 }
4295
4302
4296 .comments .comments-number {
4303 .comments .comments-number {
4297 padding: 0px 0px 10px 0px;
4304 padding: 0px 0px 10px 0px;
4298 font-weight: bold;
4305 font-weight: bold;
4299 color: #666;
4306 color: #666;
4300 font-size: 16px;
4307 font-size: 16px;
4301 }
4308 }
4302
4309
4303 /** comment form **/
4310 /** comment form **/
4304
4311
4305 .status-block {
4312 .status-block {
4306 min-height: 80px;
4313 min-height: 80px;
4307 clear: both
4314 clear: both
4308 }
4315 }
4309
4316
4310
4317
4311 div.comment-form {
4318 div.comment-form {
4312 margin-top: 20px;
4319 margin-top: 20px;
4313 }
4320 }
4314
4321
4315 .comment-form strong {
4322 .comment-form strong {
4316 display: block;
4323 display: block;
4317 margin-bottom: 15px;
4324 margin-bottom: 15px;
4318 }
4325 }
4319
4326
4320 .comment-form textarea {
4327 .comment-form textarea {
4321 width: 100%;
4328 width: 100%;
4322 height: 100px;
4329 height: 100px;
4323 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4330 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4324 }
4331 }
4325
4332
4326 form.comment-form {
4333 form.comment-form {
4327 margin-top: 10px;
4334 margin-top: 10px;
4328 margin-left: 10px;
4335 margin-left: 10px;
4329 }
4336 }
4330
4337
4331 .comment-inline-form .comment-block-ta,
4338 .comment-inline-form .comment-block-ta,
4332 .comment-form .comment-block-ta {
4339 .comment-form .comment-block-ta {
4333 border: 1px solid #ccc;
4340 border: 1px solid #ccc;
4334 border-radius: 3px;
4341 border-radius: 3px;
4335 box-sizing: border-box;
4342 box-sizing: border-box;
4336 }
4343 }
4337
4344
4338 .comment-form-submit {
4345 .comment-form-submit {
4339 margin-top: 5px;
4346 margin-top: 5px;
4340 margin-left: 525px;
4347 margin-left: 525px;
4341 }
4348 }
4342
4349
4343 .file-comments {
4350 .file-comments {
4344 display: none;
4351 display: none;
4345 }
4352 }
4346
4353
4347 .comment-form .comment {
4354 .comment-form .comment {
4348 margin-left: 10px;
4355 margin-left: 10px;
4349 }
4356 }
4350
4357
4351 .comment-form .comment-help {
4358 .comment-form .comment-help {
4352 padding: 5px 5px 5px 5px;
4359 padding: 5px 5px 5px 5px;
4353 color: #666;
4360 color: #666;
4354 }
4361 }
4355 .comment-form .comment-help .preview-btn,
4362 .comment-form .comment-help .preview-btn,
4356 .comment-form .comment-help .edit-btn {
4363 .comment-form .comment-help .edit-btn {
4357 float: right;
4364 float: right;
4358 margin: -6px 0px 0px 0px;
4365 margin: -6px 0px 0px 0px;
4359 }
4366 }
4360
4367
4361 .comment-form .preview-box.unloaded,
4368 .comment-form .preview-box.unloaded,
4362 .comment-inline-form .preview-box.unloaded {
4369 .comment-inline-form .preview-box.unloaded {
4363 height: 50px;
4370 height: 50px;
4364 text-align: center;
4371 text-align: center;
4365 padding: 20px;
4372 padding: 20px;
4366 background-color: #fafafa;
4373 background-color: #fafafa;
4367 }
4374 }
4368
4375
4369 .comment-form .comment-button {
4376 .comment-form .comment-button {
4370 padding-top: 5px;
4377 padding-top: 5px;
4371 }
4378 }
4372
4379
4373 .add-another-button {
4380 .add-another-button {
4374 margin-left: 10px;
4381 margin-left: 10px;
4375 margin-top: 10px;
4382 margin-top: 10px;
4376 margin-bottom: 10px;
4383 margin-bottom: 10px;
4377 }
4384 }
4378
4385
4379 .comment .buttons {
4386 .comment .buttons {
4380 float: right;
4387 float: right;
4381 margin: -1px 0px 0px 0px;
4388 margin: -1px 0px 0px 0px;
4382 }
4389 }
4383
4390
4384
4391
4385 .show-inline-comments {
4392 .show-inline-comments {
4386 position: relative;
4393 position: relative;
4387 top: 1px
4394 top: 1px
4388 }
4395 }
4389
4396
4390 /** comment inline form **/
4397 /** comment inline form **/
4391 .comment-inline-form {
4398 .comment-inline-form {
4392 margin: 4px;
4399 margin: 4px;
4393 }
4400 }
4394 .comment-inline-form .overlay {
4401 .comment-inline-form .overlay {
4395 display: none;
4402 display: none;
4396 }
4403 }
4397 .comment-inline-form .overlay.submitting {
4404 .comment-inline-form .overlay.submitting {
4398 display: block;
4405 display: block;
4399 background: none repeat scroll 0 0 white;
4406 background: none repeat scroll 0 0 white;
4400 font-size: 16px;
4407 font-size: 16px;
4401 opacity: 0.5;
4408 opacity: 0.5;
4402 position: absolute;
4409 position: absolute;
4403 text-align: center;
4410 text-align: center;
4404 vertical-align: top;
4411 vertical-align: top;
4405
4412
4406 }
4413 }
4407 .comment-inline-form .overlay.submitting .overlay-text {
4414 .comment-inline-form .overlay.submitting .overlay-text {
4408 width: 100%;
4415 width: 100%;
4409 margin-top: 5%;
4416 margin-top: 5%;
4410 }
4417 }
4411
4418
4412 .comment-inline-form .clearfix,
4419 .comment-inline-form .clearfix,
4413 .comment-form .clearfix {
4420 .comment-form .clearfix {
4414 background: #EEE;
4421 background: #EEE;
4415 -webkit-border-radius: 4px;
4422 -webkit-border-radius: 4px;
4416 border-radius: 4px;
4423 border-radius: 4px;
4417 padding: 5px;
4424 padding: 5px;
4418 margin: 0px;
4425 margin: 0px;
4419 }
4426 }
4420
4427
4421 div.comment-inline-form {
4428 div.comment-inline-form {
4422 padding: 4px 0px 6px 0px;
4429 padding: 4px 0px 6px 0px;
4423 }
4430 }
4424
4431
4425 .comment-inline-form strong {
4432 .comment-inline-form strong {
4426 display: block;
4433 display: block;
4427 margin-bottom: 15px;
4434 margin-bottom: 15px;
4428 }
4435 }
4429
4436
4430 .comment-inline-form textarea {
4437 .comment-inline-form textarea {
4431 width: 100%;
4438 width: 100%;
4432 height: 100px;
4439 height: 100px;
4433 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4440 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4434 }
4441 }
4435
4442
4436 form.comment-inline-form {
4443 form.comment-inline-form {
4437 margin-top: 10px;
4444 margin-top: 10px;
4438 margin-left: 10px;
4445 margin-left: 10px;
4439 }
4446 }
4440
4447
4441 .comment-inline-form-submit {
4448 .comment-inline-form-submit {
4442 margin-top: 5px;
4449 margin-top: 5px;
4443 margin-left: 525px;
4450 margin-left: 525px;
4444 }
4451 }
4445
4452
4446 .file-comments {
4453 .file-comments {
4447 display: none;
4454 display: none;
4448 }
4455 }
4449
4456
4450 .comment-inline-form .comment {
4457 .comment-inline-form .comment {
4451 margin-left: 10px;
4458 margin-left: 10px;
4452 }
4459 }
4453
4460
4454 .comment-inline-form .comment-help {
4461 .comment-inline-form .comment-help {
4455 padding: 5px 5px 5px 5px;
4462 padding: 5px 5px 5px 5px;
4456 color: #666;
4463 color: #666;
4457 }
4464 }
4458
4465
4459 .comment-inline-form .comment-help .preview-btn,
4466 .comment-inline-form .comment-help .preview-btn,
4460 .comment-inline-form .comment-help .edit-btn {
4467 .comment-inline-form .comment-help .edit-btn {
4461 float: right;
4468 float: right;
4462 margin: -6px 0px 0px 0px;
4469 margin: -6px 0px 0px 0px;
4463 }
4470 }
4464
4471
4465 .comment-inline-form .comment-button {
4472 .comment-inline-form .comment-button {
4466 padding-top: 5px;
4473 padding-top: 5px;
4467 }
4474 }
4468
4475
4469 /** comment inline **/
4476 /** comment inline **/
4470 .inline-comments {
4477 .inline-comments {
4471 padding: 10px 20px;
4478 padding: 10px 20px;
4472 }
4479 }
4473
4480
4474 .inline-comments div.rst-block {
4481 .inline-comments div.rst-block {
4475 clear: both;
4482 clear: both;
4476 overflow: hidden;
4483 overflow: hidden;
4477 margin: 0;
4484 margin: 0;
4478 padding: 0 20px 0px;
4485 padding: 0 20px 0px;
4479 }
4486 }
4480 .inline-comments .comment {
4487 .inline-comments .comment {
4481 border: 1px solid #ddd;
4488 border: 1px solid #ddd;
4482 -webkit-border-radius: 4px;
4489 -webkit-border-radius: 4px;
4483 border-radius: 4px;
4490 border-radius: 4px;
4484 margin: 3px 3px 5px 5px;
4491 margin: 3px 3px 5px 5px;
4485 background-color: #FAFAFA;
4492 background-color: #FAFAFA;
4486 }
4493 }
4487 .inline-comments .add-comment {
4494 .inline-comments .add-comment {
4488 padding: 2px 4px 8px 5px;
4495 padding: 2px 4px 8px 5px;
4489 }
4496 }
4490
4497
4491 .inline-comments .comment-wrapp {
4498 .inline-comments .comment-wrapp {
4492 padding: 1px;
4499 padding: 1px;
4493 }
4500 }
4494 .inline-comments .comment .meta {
4501 .inline-comments .comment .meta {
4495 background: #f8f8f8;
4502 background: #f8f8f8;
4496 padding: 4px;
4503 padding: 4px;
4497 border-bottom: 1px solid #ddd;
4504 border-bottom: 1px solid #ddd;
4498 height: 20px;
4505 height: 20px;
4499 }
4506 }
4500
4507
4501 .inline-comments .comment .meta img {
4508 .inline-comments .comment .meta img {
4502 vertical-align: middle;
4509 vertical-align: middle;
4503 }
4510 }
4504
4511
4505 .inline-comments .comment .meta .user {
4512 .inline-comments .comment .meta .user {
4506 font-weight: bold;
4513 font-weight: bold;
4507 float: left;
4514 float: left;
4508 padding: 3px;
4515 padding: 3px;
4509 }
4516 }
4510
4517
4511 .inline-comments .comment .meta .date {
4518 .inline-comments .comment .meta .date {
4512 float: left;
4519 float: left;
4513 padding: 3px;
4520 padding: 3px;
4514 }
4521 }
4515
4522
4516 .inline-comments .comment .text {
4523 .inline-comments .comment .text {
4517 background-color: #FAFAFA;
4524 background-color: #FAFAFA;
4518 }
4525 }
4519
4526
4520 .inline-comments .comments-number {
4527 .inline-comments .comments-number {
4521 padding: 0px 0px 10px 0px;
4528 padding: 0px 0px 10px 0px;
4522 font-weight: bold;
4529 font-weight: bold;
4523 color: #666;
4530 color: #666;
4524 font-size: 16px;
4531 font-size: 16px;
4525 }
4532 }
4526 .inline-comments-button .add-comment {
4533 .inline-comments-button .add-comment {
4527 margin: 2px 0px 8px 5px !important
4534 margin: 2px 0px 8px 5px !important
4528 }
4535 }
4529
4536
4530 .notification-paginator {
4537 .notification-paginator {
4531 padding: 0px 0px 4px 16px;
4538 padding: 0px 0px 4px 16px;
4532 }
4539 }
4533
4540
4534 #context-pages .pull-request span,
4541 #context-pages .pull-request span,
4535 .menu_link_notifications {
4542 .menu_link_notifications {
4536 padding: 4px 4px !important;
4543 padding: 4px 4px !important;
4537 text-align: center;
4544 text-align: center;
4538 color: #888 !important;
4545 color: #888 !important;
4539 background-color: #DEDEDE !important;
4546 background-color: #DEDEDE !important;
4540 border-radius: 4px !important;
4547 border-radius: 4px !important;
4541 -webkit-border-radius: 4px !important;
4548 -webkit-border-radius: 4px !important;
4542 }
4549 }
4543
4550
4544 #context-pages .forks span,
4551 #context-pages .forks span,
4545 .menu_link_notifications {
4552 .menu_link_notifications {
4546 padding: 4px 4px !important;
4553 padding: 4px 4px !important;
4547 text-align: center;
4554 text-align: center;
4548 color: #888 !important;
4555 color: #888 !important;
4549 background-color: #DEDEDE !important;
4556 background-color: #DEDEDE !important;
4550 border-radius: 4px !important;
4557 border-radius: 4px !important;
4551 -webkit-border-radius: 4px !important;
4558 -webkit-border-radius: 4px !important;
4552 }
4559 }
4553
4560
4554
4561
4555 .notification-header {
4562 .notification-header {
4556 padding-top: 6px;
4563 padding-top: 6px;
4557 }
4564 }
4558 .notification-header .desc {
4565 .notification-header .desc {
4559 font-size: 16px;
4566 font-size: 16px;
4560 height: 24px;
4567 height: 24px;
4561 float: left
4568 float: left
4562 }
4569 }
4563 .notification-list .container.unread {
4570 .notification-list .container.unread {
4564 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4571 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4565 }
4572 }
4566 .notification-header .gravatar {
4573 .notification-header .gravatar {
4567 background: none repeat scroll 0 0 transparent;
4574 background: none repeat scroll 0 0 transparent;
4568 padding: 0px 0px 0px 8px;
4575 padding: 0px 0px 0px 8px;
4569 }
4576 }
4570 .notification-list .container .notification-header .desc {
4577 .notification-list .container .notification-header .desc {
4571 font-weight: bold;
4578 font-weight: bold;
4572 font-size: 17px;
4579 font-size: 17px;
4573 }
4580 }
4574 .notification-table {
4581 .notification-table {
4575 border: 1px solid #ccc;
4582 border: 1px solid #ccc;
4576 -webkit-border-radius: 6px 6px 6px 6px;
4583 -webkit-border-radius: 6px 6px 6px 6px;
4577 border-radius: 6px 6px 6px 6px;
4584 border-radius: 6px 6px 6px 6px;
4578 clear: both;
4585 clear: both;
4579 margin: 0px 20px 0px 20px;
4586 margin: 0px 20px 0px 20px;
4580 }
4587 }
4581 .notification-header .delete-notifications {
4588 .notification-header .delete-notifications {
4582 float: right;
4589 float: right;
4583 padding-top: 8px;
4590 padding-top: 8px;
4584 cursor: pointer;
4591 cursor: pointer;
4585 }
4592 }
4586 .notification-header .read-notifications {
4593 .notification-header .read-notifications {
4587 float: right;
4594 float: right;
4588 padding-top: 8px;
4595 padding-top: 8px;
4589 cursor: pointer;
4596 cursor: pointer;
4590 }
4597 }
4591 .notification-subject {
4598 .notification-subject {
4592 clear: both;
4599 clear: both;
4593 border-bottom: 1px solid #eee;
4600 border-bottom: 1px solid #eee;
4594 padding: 5px 0px 5px 38px;
4601 padding: 5px 0px 5px 38px;
4595 }
4602 }
4596
4603
4597 .notification-body {
4604 .notification-body {
4598 clear: both;
4605 clear: both;
4599 margin: 34px 2px 2px 8px
4606 margin: 34px 2px 2px 8px
4600 }
4607 }
4601
4608
4602 /****
4609 /****
4603 PULL REQUESTS
4610 PULL REQUESTS
4604 *****/
4611 *****/
4605 .pullrequests_section_head {
4612 .pullrequests_section_head {
4606 padding: 10px 10px 10px 0px;
4613 padding: 10px 10px 10px 0px;
4607 font-size: 16px;
4614 font-size: 16px;
4608 font-weight: bold;
4615 font-weight: bold;
4609 }
4616 }
4610
4617
4611 h3.closed,
4618 h3.closed,
4612 #pullrequests_container li.closed a
4619 #pullrequests_container li.closed a
4613 {
4620 {
4614 color: #555;
4621 color: #555;
4615 background: #eee;
4622 background: #eee;
4616 }
4623 }
4617
4624
4618 div.pr-title {
4625 div.pr-title {
4619 font-size: 1.6em;
4626 font-size: 1.6em;
4620 }
4627 }
4621
4628
4622 div.pr {
4629 div.pr {
4623 border-bottom: 1px solid #DDD;
4630 border-bottom: 1px solid #DDD;
4624 margin: 0px 20px;
4631 margin: 0px 20px;
4625 padding: 10px 4px;
4632 padding: 10px 4px;
4626 }
4633 }
4627 div.pr-closed {
4634 div.pr-closed {
4628 background-color: rgba(245,245,245,0.5);
4635 background-color: rgba(245,245,245,0.5);
4629 }
4636 }
4630
4637
4631 span.pr-closed-tag {
4638 span.pr-closed-tag {
4632 margin-bottom: 1px;
4639 margin-bottom: 1px;
4633 margin-right: 1px;
4640 margin-right: 1px;
4634 padding: 1px 3px;
4641 padding: 1px 3px;
4635 font-size: 10px;
4642 font-size: 10px;
4636 padding: 1px 3px 1px 3px;
4643 padding: 1px 3px 1px 3px;
4637 font-size: 10px;
4644 font-size: 10px;
4638 color: #336699;
4645 color: #336699;
4639 white-space: nowrap;
4646 white-space: nowrap;
4640 -webkit-border-radius: 4px;
4647 -webkit-border-radius: 4px;
4641 border-radius: 4px;
4648 border-radius: 4px;
4642 border: 1px solid #d9e8f8;
4649 border: 1px solid #d9e8f8;
4643 line-height: 1.5em;
4650 line-height: 1.5em;
4644 }
4651 }
4645
4652
4646 /****
4653 /****
4647 PERMS
4654 PERMS
4648 *****/
4655 *****/
4649 #perms .perms_section_head {
4656 #perms .perms_section_head {
4650 padding: 10px 10px 10px 0px;
4657 padding: 10px 10px 10px 0px;
4651 font-size: 16px;
4658 font-size: 16px;
4652 font-weight: bold;
4659 font-weight: bold;
4653 }
4660 }
4654
4661
4655 #perms .perm_tag {
4662 #perms .perm_tag {
4656 padding: 1px 3px 1px 3px;
4663 padding: 1px 3px 1px 3px;
4657 font-size: 10px;
4664 font-size: 10px;
4658 font-weight: bold;
4665 font-weight: bold;
4659 text-transform: uppercase;
4666 text-transform: uppercase;
4660 white-space: nowrap;
4667 white-space: nowrap;
4661 -webkit-border-radius: 3px;
4668 -webkit-border-radius: 3px;
4662 border-radius: 3px;
4669 border-radius: 3px;
4663 }
4670 }
4664
4671
4665 #perms .perm_tag.admin {
4672 #perms .perm_tag.admin {
4666 background-color: #B94A48;
4673 background-color: #B94A48;
4667 color: #ffffff;
4674 color: #ffffff;
4668 }
4675 }
4669
4676
4670 #perms .perm_tag.write {
4677 #perms .perm_tag.write {
4671 background-color: #DB7525;
4678 background-color: #DB7525;
4672 color: #ffffff;
4679 color: #ffffff;
4673 }
4680 }
4674
4681
4675 #perms .perm_tag.read {
4682 #perms .perm_tag.read {
4676 background-color: #468847;
4683 background-color: #468847;
4677 color: #ffffff;
4684 color: #ffffff;
4678 }
4685 }
4679
4686
4680 #perms .perm_tag.none {
4687 #perms .perm_tag.none {
4681 background-color: #bfbfbf;
4688 background-color: #bfbfbf;
4682 color: #ffffff;
4689 color: #ffffff;
4683 }
4690 }
4684
4691
4685 .perm-gravatar {
4692 .perm-gravatar {
4686 vertical-align: middle;
4693 vertical-align: middle;
4687 padding: 2px;
4694 padding: 2px;
4688 }
4695 }
4689 .perm-gravatar-ac {
4696 .perm-gravatar-ac {
4690 vertical-align: middle;
4697 vertical-align: middle;
4691 padding: 2px;
4698 padding: 2px;
4692 width: 14px;
4699 width: 14px;
4693 height: 14px;
4700 height: 14px;
4694 }
4701 }
4695
4702
4696 /*****************************************************************************
4703 /*****************************************************************************
4697 DIFFS CSS
4704 DIFFS CSS
4698 ******************************************************************************/
4705 ******************************************************************************/
4699 .diff-collapse {
4706 .diff-collapse {
4700 text-align: center;
4707 text-align: center;
4701 margin-bottom: -15px;
4708 margin-bottom: -15px;
4702 }
4709 }
4703 .diff-collapse-button {
4710 .diff-collapse-button {
4704 cursor: pointer;
4711 cursor: pointer;
4705 color: #666;
4712 color: #666;
4706 font-size: 16px;
4713 font-size: 16px;
4707 }
4714 }
4708 .diff-container {
4715 .diff-container {
4709
4716
4710 }
4717 }
4711
4718
4712 .diff-container.hidden {
4719 .diff-container.hidden {
4713 display: none;
4720 display: none;
4714 overflow: hidden;
4721 overflow: hidden;
4715 }
4722 }
4716
4723
4717
4724
4718 div.diffblock {
4725 div.diffblock {
4719 overflow: auto;
4726 overflow: auto;
4720 padding: 0px;
4727 padding: 0px;
4721 border: 1px solid #ccc;
4728 border: 1px solid #ccc;
4722 background: #f8f8f8;
4729 background: #f8f8f8;
4723 font-size: 100%;
4730 font-size: 100%;
4724 line-height: 100%;
4731 line-height: 100%;
4725 /* new */
4732 /* new */
4726 line-height: 125%;
4733 line-height: 125%;
4727 -webkit-border-radius: 6px 6px 0px 0px;
4734 -webkit-border-radius: 6px 6px 0px 0px;
4728 border-radius: 6px 6px 0px 0px;
4735 border-radius: 6px 6px 0px 0px;
4729 }
4736 }
4730 div.diffblock.margined {
4737 div.diffblock.margined {
4731 margin: 0px 20px 0px 20px;
4738 margin: 0px 20px 0px 20px;
4732 }
4739 }
4733 div.diffblock .code-header {
4740 div.diffblock .code-header {
4734 border-bottom: 1px solid #CCCCCC;
4741 border-bottom: 1px solid #CCCCCC;
4735 background: #EEEEEE;
4742 background: #EEEEEE;
4736 padding: 10px 0 10px 0;
4743 padding: 10px 0 10px 0;
4737 height: 14px;
4744 height: 14px;
4738 }
4745 }
4739
4746
4740 div.diffblock .code-header.banner {
4747 div.diffblock .code-header.banner {
4741 border-bottom: 1px solid #CCCCCC;
4748 border-bottom: 1px solid #CCCCCC;
4742 background: #EEEEEE;
4749 background: #EEEEEE;
4743 height: 14px;
4750 height: 14px;
4744 margin: 0px 95px 0px 95px;
4751 margin: 0px 95px 0px 95px;
4745 padding: 3px 3px 11px 3px;
4752 padding: 3px 3px 11px 3px;
4746 }
4753 }
4747
4754
4748 div.diffblock .code-header-title {
4755 div.diffblock .code-header-title {
4749 padding: 0px 0px 10px 5px !important;
4756 padding: 0px 0px 10px 5px !important;
4750 margin: 0 !important;
4757 margin: 0 !important;
4751 }
4758 }
4752 div.diffblock .code-header .hash {
4759 div.diffblock .code-header .hash {
4753 float: left;
4760 float: left;
4754 padding: 2px 0 0 2px;
4761 padding: 2px 0 0 2px;
4755 }
4762 }
4756 div.diffblock .code-header .date {
4763 div.diffblock .code-header .date {
4757 float: left;
4764 float: left;
4758 text-transform: uppercase;
4765 text-transform: uppercase;
4759 padding: 2px 0px 0px 2px;
4766 padding: 2px 0px 0px 2px;
4760 }
4767 }
4761 div.diffblock .code-header div {
4768 div.diffblock .code-header div {
4762 margin-left: 4px;
4769 margin-left: 4px;
4763 font-weight: bold;
4770 font-weight: bold;
4764 font-size: 14px;
4771 font-size: 14px;
4765 }
4772 }
4766
4773
4767 div.diffblock .parents {
4774 div.diffblock .parents {
4768 float: left;
4775 float: left;
4769 height: 26px;
4776 height: 26px;
4770 width: 100px;
4777 width: 100px;
4771 font-size: 10px;
4778 font-size: 10px;
4772 font-weight: 400;
4779 font-weight: 400;
4773 vertical-align: middle;
4780 vertical-align: middle;
4774 padding: 0px 2px 2px 2px;
4781 padding: 0px 2px 2px 2px;
4775 background-color: #eeeeee;
4782 background-color: #eeeeee;
4776 border-bottom: 1px solid #CCCCCC;
4783 border-bottom: 1px solid #CCCCCC;
4777 }
4784 }
4778
4785
4779 div.diffblock .children {
4786 div.diffblock .children {
4780 float: right;
4787 float: right;
4781 height: 26px;
4788 height: 26px;
4782 width: 100px;
4789 width: 100px;
4783 font-size: 10px;
4790 font-size: 10px;
4784 font-weight: 400;
4791 font-weight: 400;
4785 vertical-align: middle;
4792 vertical-align: middle;
4786 text-align: right;
4793 text-align: right;
4787 padding: 0px 2px 2px 2px;
4794 padding: 0px 2px 2px 2px;
4788 background-color: #eeeeee;
4795 background-color: #eeeeee;
4789 border-bottom: 1px solid #CCCCCC;
4796 border-bottom: 1px solid #CCCCCC;
4790 }
4797 }
4791
4798
4792 div.diffblock .code-body {
4799 div.diffblock .code-body {
4793 background: #FFFFFF;
4800 background: #FFFFFF;
4794 }
4801 }
4795 div.diffblock pre.raw {
4802 div.diffblock pre.raw {
4796 background: #FFFFFF;
4803 background: #FFFFFF;
4797 color: #000000;
4804 color: #000000;
4798 }
4805 }
4799 table.code-difftable {
4806 table.code-difftable {
4800 border-collapse: collapse;
4807 border-collapse: collapse;
4801 width: 99%;
4808 width: 99%;
4802 border-radius: 0px !important;
4809 border-radius: 0px !important;
4803 }
4810 }
4804 table.code-difftable td {
4811 table.code-difftable td {
4805 padding: 0 !important;
4812 padding: 0 !important;
4806 background: none !important;
4813 background: none !important;
4807 border: 0 !important;
4814 border: 0 !important;
4808 vertical-align: baseline !important
4815 vertical-align: baseline !important
4809 }
4816 }
4810 table.code-difftable .context {
4817 table.code-difftable .context {
4811 background: none repeat scroll 0 0 #DDE7EF;
4818 background: none repeat scroll 0 0 #DDE7EF;
4812 }
4819 }
4813 table.code-difftable .add {
4820 table.code-difftable .add {
4814 background: none repeat scroll 0 0 #DDFFDD;
4821 background: none repeat scroll 0 0 #DDFFDD;
4815 }
4822 }
4816 table.code-difftable .add ins {
4823 table.code-difftable .add ins {
4817 background: none repeat scroll 0 0 #AAFFAA;
4824 background: none repeat scroll 0 0 #AAFFAA;
4818 text-decoration: none;
4825 text-decoration: none;
4819 }
4826 }
4820 table.code-difftable .del {
4827 table.code-difftable .del {
4821 background: none repeat scroll 0 0 #FFDDDD;
4828 background: none repeat scroll 0 0 #FFDDDD;
4822 }
4829 }
4823 table.code-difftable .del del {
4830 table.code-difftable .del del {
4824 background: none repeat scroll 0 0 #FFAAAA;
4831 background: none repeat scroll 0 0 #FFAAAA;
4825 text-decoration: none;
4832 text-decoration: none;
4826 }
4833 }
4827
4834
4828 /** LINE NUMBERS **/
4835 /** LINE NUMBERS **/
4829 table.code-difftable .lineno {
4836 table.code-difftable .lineno {
4830
4837
4831 padding-left: 2px;
4838 padding-left: 2px;
4832 padding-right: 2px;
4839 padding-right: 2px;
4833 text-align: right;
4840 text-align: right;
4834 width: 32px;
4841 width: 32px;
4835 -moz-user-select: none;
4842 -moz-user-select: none;
4836 -webkit-user-select: none;
4843 -webkit-user-select: none;
4837 border-right: 1px solid #CCC !important;
4844 border-right: 1px solid #CCC !important;
4838 border-left: 0px solid #CCC !important;
4845 border-left: 0px solid #CCC !important;
4839 border-top: 0px solid #CCC !important;
4846 border-top: 0px solid #CCC !important;
4840 border-bottom: none !important;
4847 border-bottom: none !important;
4841 vertical-align: middle !important;
4848 vertical-align: middle !important;
4842
4849
4843 }
4850 }
4844 table.code-difftable .lineno.new {
4851 table.code-difftable .lineno.new {
4845 }
4852 }
4846 table.code-difftable .lineno.old {
4853 table.code-difftable .lineno.old {
4847 }
4854 }
4848 table.code-difftable .lineno a {
4855 table.code-difftable .lineno a {
4849 color: #747474 !important;
4856 color: #747474 !important;
4850 font: 11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4857 font: 11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4851 letter-spacing: -1px;
4858 letter-spacing: -1px;
4852 text-align: right;
4859 text-align: right;
4853 padding-right: 2px;
4860 padding-right: 2px;
4854 cursor: pointer;
4861 cursor: pointer;
4855 display: block;
4862 display: block;
4856 width: 32px;
4863 width: 32px;
4857 }
4864 }
4858
4865
4859 table.code-difftable .lineno-inline {
4866 table.code-difftable .lineno-inline {
4860 background: none repeat scroll 0 0 #FFF !important;
4867 background: none repeat scroll 0 0 #FFF !important;
4861 padding-left: 2px;
4868 padding-left: 2px;
4862 padding-right: 2px;
4869 padding-right: 2px;
4863 text-align: right;
4870 text-align: right;
4864 width: 30px;
4871 width: 30px;
4865 -moz-user-select: none;
4872 -moz-user-select: none;
4866 -webkit-user-select: none;
4873 -webkit-user-select: none;
4867 }
4874 }
4868
4875
4869 /** CODE **/
4876 /** CODE **/
4870 table.code-difftable .code {
4877 table.code-difftable .code {
4871 display: block;
4878 display: block;
4872 width: 100%;
4879 width: 100%;
4873 }
4880 }
4874 table.code-difftable .code td {
4881 table.code-difftable .code td {
4875 margin: 0;
4882 margin: 0;
4876 padding: 0;
4883 padding: 0;
4877 }
4884 }
4878 table.code-difftable .code pre {
4885 table.code-difftable .code pre {
4879 margin: 0;
4886 margin: 0;
4880 padding: 0;
4887 padding: 0;
4881 height: 17px;
4888 height: 17px;
4882 line-height: 17px;
4889 line-height: 17px;
4883 }
4890 }
4884
4891
4885
4892
4886 .diffblock.margined.comm .line .code:hover {
4893 .diffblock.margined.comm .line .code:hover {
4887 background-color: #FFFFCC !important;
4894 background-color: #FFFFCC !important;
4888 cursor: pointer !important;
4895 cursor: pointer !important;
4889 background-image: url("../images/icons/comment_add.png") !important;
4896 background-image: url("../images/icons/comment_add.png") !important;
4890 background-repeat: no-repeat !important;
4897 background-repeat: no-repeat !important;
4891 background-position: right !important;
4898 background-position: right !important;
4892 background-position: 0% 50% !important;
4899 background-position: 0% 50% !important;
4893 }
4900 }
4894 .diffblock.margined.comm .line .code.no-comment:hover {
4901 .diffblock.margined.comm .line .code.no-comment:hover {
4895 background-image: none !important;
4902 background-image: none !important;
4896 cursor: auto !important;
4903 cursor: auto !important;
4897 background-color: inherit !important;
4904 background-color: inherit !important;
4898 }
4905 }
4899
4906
4900 div.comment:target>.comment-wrapp {
4907 div.comment:target>.comment-wrapp {
4901 border: solid 2px #ee0 !important;
4908 border: solid 2px #ee0 !important;
4902 }
4909 }
4903
4910
4904 .lineno:target a {
4911 .lineno:target a {
4905 border: solid 2px #ee0 !important;
4912 border: solid 2px #ee0 !important;
4906 margin: -2px;
4913 margin: -2px;
4907 }
4914 }
@@ -1,66 +1,64 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##usage:
2 ##usage:
3 ## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
3 ## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
4 ## ${diff_block.diff_block(change)}
4 ## ${diff_block.diff_block(change)}
5 ##
5 ##
6 <%def name="diff_block(change)">
6 <%def name="diff_block(change)">
7 <div class="diff-collapse">
7 <div class="diff-collapse">
8 <span target="${'diff-container-%s' % (id(change))}" class="diff-collapse-button">&uarr; ${_('Collapse diff')} &uarr;</span>
8 <span target="${'diff-container-%s' % (id(change))}" class="diff-collapse-button">&uarr; ${_('Collapse diff')} &uarr;</span>
9 </div>
9 </div>
10 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
10 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
11 %for FID,(cs1, cs2, change, path, diff, stats) in change.iteritems():
11 %for FID,(cs1, cs2, change, path, diff, stats) in change.iteritems():
12 ##%if op !='removed':
13 <div id="${FID}_target" style="clear:both;margin-top:25px"></div>
12 <div id="${FID}_target" style="clear:both;margin-top:25px"></div>
14 <div id="${FID}" class="diffblock margined comm">
13 <div id="${FID}" class="diffblock margined comm">
15 <div class="code-header">
14 <div class="code-header">
16 <div class="changeset_header">
15 <div class="changeset_header">
17 <div class="changeset_file">
16 <div class="changeset_file">
18 ${h.link_to_if(change!='D',h.safe_unicode(path),h.url('files_home',repo_name=c.repo_name,
17 ${h.link_to_if(change!='D',h.safe_unicode(path),h.url('files_home',repo_name=c.repo_name,
19 revision=cs2,f_path=h.safe_unicode(path)))}
18 revision=cs2,f_path=h.safe_unicode(path)))}
20 </div>
19 </div>
21 <div class="diff-actions">
20 <div class="diff-actions">
22 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${h.tooltip(_('Show full diff for this file'))}"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
21 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${h.tooltip(_('Show full diff for this file'))}"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
23 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
22 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
24 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"><img class="icon" src="${h.url('/images/icons/page_save.png')}"/></a>
23 <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"><img class="icon" src="${h.url('/images/icons/page_save.png')}"/></a>
25 ${c.ignorews_url(request.GET, h.FID(cs2,path))}
24 ${c.ignorews_url(request.GET, h.FID(cs2,path))}
26 ${c.context_url(request.GET, h.FID(cs2,path))}
25 ${c.context_url(request.GET, h.FID(cs2,path))}
27 </div>
26 </div>
28 <span style="float:right;margin-top:-3px">
27 <span style="float:right;margin-top:-3px">
29 <label>
28 <label>
30 ${_('Show inline comments')}
29 ${_('Show inline comments')}
31 ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(cs2,path))}
30 ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(cs2,path))}
32 </label>
31 </label>
33 </span>
32 </span>
34 </div>
33 </div>
35 </div>
34 </div>
36 <div class="code-body">
35 <div class="code-body">
37 <div class="full_f_path" path="${h.safe_unicode(path)}"></div>
36 <div class="full_f_path" path="${h.safe_unicode(path)}"></div>
38 ${diff|n}
37 ${diff|n}
39 </div>
38 </div>
40 </div>
39 </div>
41 ##%endif
42 %endfor
40 %endfor
43 </div>
41 </div>
44 </%def>
42 </%def>
45
43
46 <%def name="diff_block_simple(change)">
44 <%def name="diff_block_simple(change)">
47
45
48 %for op,filenode_path,diff in change:
46 %for op,filenode_path,diff in change:
49 <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
47 <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
50 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm">
48 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm">
51 <div class="code-header">
49 <div class="code-header">
52 <div class="changeset_header">
50 <div class="changeset_header">
53 <div class="changeset_file">
51 <div class="changeset_file">
54 ${h.safe_unicode(filenode_path)} |
52 ${h.safe_unicode(filenode_path)} |
55 <a class="spantag" href="${h.url('files_home', repo_name=c.other_repo.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('Show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
53 <a class="spantag" href="${h.url('files_home', repo_name=c.other_repo.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('Show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
56 <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}" title="${_('Show file at initial version in this repo')}">${c.other_ref_type}@${h.short_id(c.other_ref) if c.other_ref_type=='rev' else c.other_ref}</a>
54 <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}" title="${_('Show file at initial version in this repo')}">${c.other_ref_type}@${h.short_id(c.other_ref) if c.other_ref_type=='rev' else c.other_ref}</a>
57 </div>
55 </div>
58 </div>
56 </div>
59 </div>
57 </div>
60 <div class="code-body">
58 <div class="code-body">
61 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}"></div>
59 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}"></div>
62 ${diff|n}
60 ${diff|n}
63 </div>
61 </div>
64 </div>
62 </div>
65 %endfor
63 %endfor
66 </%def>
64 </%def>
@@ -1,552 +1,556 b''
1 diff --git a/img/baseline-10px.png b/img/baseline-10px.png
1 diff --git a/img/baseline-10px.png b/img/baseline-10px.png
2 new file mode 100644
2 new file mode 100644
3 index 0000000000000000000000000000000000000000..16095dcbf5c9ea41caeb1e3e41d647d425222ed1
3 index 0000000000000000000000000000000000000000..16095dcbf5c9ea41caeb1e3e41d647d425222ed1
4 GIT binary patch
4 GIT binary patch
5 literal 152
5 literal 152
6 zc%17D@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0lw^r(L`iUdT1k0gQ7VIDN`6wR
6 zc%17D@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0lw^r(L`iUdT1k0gQ7VIDN`6wR
7 zf@f}GdTLN=VoGJ<$y6JlA}dc9$B>F!Nx%O8w`Ue+77%bXFxq5j_~-xsZV_1~1zCBH
7 zf@f}GdTLN=VoGJ<$y6JlA}dc9$B>F!Nx%O8w`Ue+77%bXFxq5j_~-xsZV_1~1zCBH
8 y)y@U((_~Lrb!=|_@`K?vV_&A58+!u-Gs6x+MGjBnI|qTLFnGH9xvX<aXaWHBd@WW0
8 y)y@U((_~Lrb!=|_@`K?vV_&A58+!u-Gs6x+MGjBnI|qTLFnGH9xvX<aXaWHBd@WW0
9
9
10 diff --git a/img/baseline-20px.png b/img/baseline-20px.png
10 diff --git a/img/baseline-20px.png b/img/baseline-20px.png
11 deleted file mode 100644
11 deleted file mode 100644
12 Binary file img/baseline-20px.png has changed
12 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000
13 GIT binary patch
14 literal 0
15 Hc$@<O00001
16
13 diff --git a/index.html b/index.html
17 diff --git a/index.html b/index.html
14 --- a/index.html
18 --- a/index.html
15 +++ b/index.html
19 +++ b/index.html
16 @@ -2,7 +2,7 @@
20 @@ -2,7 +2,7 @@
17 <html lang="en">
21 <html lang="en">
18 <head>
22 <head>
19 <meta charset="utf-8">
23 <meta charset="utf-8">
20 - <title>Baseline</title>
24 - <title>Baseline</title>
21 + <title>Twitter Baseline</title>
25 + <title>Twitter Baseline</title>
22
26
23 <!-- // Less.js at the ready! -->
27 <!-- // Less.js at the ready! -->
24 <link rel="stylesheet/less" type="text/css" media="all" href="less/baseline.less" />
28 <link rel="stylesheet/less" type="text/css" media="all" href="less/baseline.less" />
25 @@ -11,6 +11,7 @@
29 @@ -11,6 +11,7 @@
26 <!-- // jQuery! -->
30 <!-- // jQuery! -->
27 <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
31 <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
28 <script type="text/javascript" src="http://tablesorter.com/jquery.tablesorter.min.js"></script>
32 <script type="text/javascript" src="http://tablesorter.com/jquery.tablesorter.min.js"></script>
29 + <script type="text/javascript" src="js/jquery/hashgrid.js"></script>
33 + <script type="text/javascript" src="js/jquery/hashgrid.js"></script>
30 <script type="text/javascript">
34 <script type="text/javascript">
31 $(document).ready(function(){
35 $(document).ready(function(){
32 // Active state in top nav
36 // Active state in top nav
33 @@ -36,7 +37,7 @@
37 @@ -36,7 +37,7 @@
34 <!--
38 <!--
35 <style>
39 <style>
36 body {
40 body {
37 - background: url(img/baseline-20px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
41 - background: url(img/baseline-20px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
38 + background: url(img/baseline-10px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
42 + background: url(img/baseline-10px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
39 background-color: #fff;
43 background-color: #fff;
40 }
44 }
41 </style>
45 </style>
42 diff --git a/js/global.js b/js/global.js
46 diff --git a/js/global.js b/js/global.js
43 deleted file mode 100644
47 deleted file mode 100644
44 --- a/js/global.js
48 --- a/js/global.js
45 +++ /dev/null
49 +++ /dev/null
46 @@ -1,75 +0,0 @@
50 @@ -1,75 +0,0 @@
47 -$(document).ready(function(){
51 -$(document).ready(function(){
48 - // Get Heights
52 - // Get Heights
49 - windowHeight = $(window).height();
53 - windowHeight = $(window).height();
50 - documentHeight = $(document).height();
54 - documentHeight = $(document).height();
51 - sidebarHeight = windowHeight - 40;
55 - sidebarHeight = windowHeight - 40;
52 - containerHeight = windowHeight - 40;
56 - containerHeight = windowHeight - 40;
53 -
57 -
54 - // Get Widths
58 - // Get Widths
55 - windowWidth = $(window).width();
59 - windowWidth = $(window).width();
56 - containerWidth = windowWidth - 200;
60 - containerWidth = windowWidth - 200;
57 -
61 -
58 - if (windowHeight < containerHeight) {
62 - if (windowHeight < containerHeight) {
59 -
63 -
60 - // Set Dimensions for default state (before resize)
64 - // Set Dimensions for default state (before resize)
61 - $('div#sidebar').css({
65 - $('div#sidebar').css({
62 - height: sidebarHeight
66 - height: sidebarHeight
63 - });
67 - });
64 - $('div#container').css({
68 - $('div#container').css({
65 - width: containerWidth,
69 - width: containerWidth,
66 - height: containerHeight
70 - height: containerHeight
67 - });
71 - });
68 -
72 -
69 - } else {
73 - } else {
70 -
74 -
71 - // During resize, set widths
75 - // During resize, set widths
72 - $(window).resize(function() {
76 - $(window).resize(function() {
73 - console.log('Window Height: ' + $(window).height() + ', Sidebar Height:' + ($(window).height() - 40));
77 - console.log('Window Height: ' + $(window).height() + ', Sidebar Height:' + ($(window).height() - 40));
74 -
78 -
75 - // Get Heights
79 - // Get Heights
76 - windowHeight = $(window).height();
80 - windowHeight = $(window).height();
77 - sidebarHeight = windowHeight - 40;
81 - sidebarHeight = windowHeight - 40;
78 - containerHeight = windowHeight - 40;
82 - containerHeight = windowHeight - 40;
79 -
83 -
80 - // Get Widths
84 - // Get Widths
81 - windowWidth = $(window).width();
85 - windowWidth = $(window).width();
82 - containerWidth = windowWidth - 200;
86 - containerWidth = windowWidth - 200;
83 -
87 -
84 - // Set Dimensions for default state (before resize)
88 - // Set Dimensions for default state (before resize)
85 - $('div#sidebar').css({
89 - $('div#sidebar').css({
86 - height: sidebarHeight
90 - height: sidebarHeight
87 - });
91 - });
88 - $('div#container').css({
92 - $('div#container').css({
89 - width: containerWidth,
93 - width: containerWidth,
90 - height: containerHeight
94 - height: containerHeight
91 - });
95 - });
92 - });
96 - });
93 - // console.log('omgz window is less than container so... fuck.');
97 - // console.log('omgz window is less than container so... fuck.');
94 - $('div#sidebar').css({
98 - $('div#sidebar').css({
95 - height: documentHeight - 40
99 - height: documentHeight - 40
96 - });
100 - });
97 -
101 -
98 - }
102 - }
99 -
103 -
100 -
104 -
101 -
105 -
102 -/*
106 -/*
103 - // Toggle Calendars
107 - // Toggle Calendars
104 - $('div#sidebar ul li a').click(function() {
108 - $('div#sidebar ul li a').click(function() {
105 - if ($(this).is('#toggleMonthView')) {
109 - if ($(this).is('#toggleMonthView')) {
106 - console.log('toggle month');
110 - console.log('toggle month');
107 - $(this).addClass('active');
111 - $(this).addClass('active');
108 - $('#toggleListView').removeClass('active');
112 - $('#toggleListView').removeClass('active');
109 - $('table#monthView').show();
113 - $('table#monthView').show();
110 - $('table#listView').hide();
114 - $('table#listView').hide();
111 - } else {
115 - } else {
112 - console.log('toggle list');
116 - console.log('toggle list');
113 - $(this).addClass('active');
117 - $(this).addClass('active');
114 - $('#toggleMonthView').removeClass('active');
118 - $('#toggleMonthView').removeClass('active');
115 - $('table#listView').show();
119 - $('table#listView').show();
116 - $('table#monthView').hide();
120 - $('table#monthView').hide();
117 - }
121 - }
118 - return false;
122 - return false;
119 - });
123 - });
120 -*/
124 -*/
121 -});
125 -});
122 diff --git a/js/jquery/hashgrid.js b/js/jquery/hashgrid.js
126 diff --git a/js/jquery/hashgrid.js b/js/jquery/hashgrid.js
123 new file mode 100755
127 new file mode 100755
124 --- /dev/null
128 --- /dev/null
125 +++ b/js/jquery/hashgrid.js
129 +++ b/js/jquery/hashgrid.js
126 @@ -0,0 +1,340 @@
130 @@ -0,0 +1,340 @@
127 +/**
131 +/**
128 + * hashgrid (jQuery version)
132 + * hashgrid (jQuery version)
129 + * http://github.com/dotjay/hashgrid
133 + * http://github.com/dotjay/hashgrid
130 + * Version 5, 3 Nov 2010
134 + * Version 5, 3 Nov 2010
131 + * Written by Jon Gibbins, dotjay.co.uk, accessibility.co.uk
135 + * Written by Jon Gibbins, dotjay.co.uk, accessibility.co.uk
132 + * Contibutors:
136 + * Contibutors:
133 + * Sean Coates, seancoates.com
137 + * Sean Coates, seancoates.com
134 + * Phil Dokas, jetless.org
138 + * Phil Dokas, jetless.org
135 + *
139 + *
136 + * // Using a basic #grid setup
140 + * // Using a basic #grid setup
137 + * var grid = new hashgrid();
141 + * var grid = new hashgrid();
138 + *
142 + *
139 + * // Using #grid with a custom id (e.g. #mygrid)
143 + * // Using #grid with a custom id (e.g. #mygrid)
140 + * var grid = new hashgrid("mygrid");
144 + * var grid = new hashgrid("mygrid");
141 + *
145 + *
142 + * // Using #grid with additional options
146 + * // Using #grid with additional options
143 + * var grid = new hashgrid({
147 + * var grid = new hashgrid({
144 + * id: 'mygrid', // id for the grid container
148 + * id: 'mygrid', // id for the grid container
145 + * modifierKey: 'alt', // optional 'ctrl', 'alt' or 'shift'
149 + * modifierKey: 'alt', // optional 'ctrl', 'alt' or 'shift'
146 + * showGridKey: 's', // key to show the grid
150 + * showGridKey: 's', // key to show the grid
147 + * holdGridKey: 'enter', // key to hold the grid in place
151 + * holdGridKey: 'enter', // key to hold the grid in place
148 + * foregroundKey: 'f', // key to toggle foreground/background
152 + * foregroundKey: 'f', // key to toggle foreground/background
149 + * jumpGridsKey: 'd', // key to cycle through the grid classes
153 + * jumpGridsKey: 'd', // key to cycle through the grid classes
150 + * numberOfGrids: 2, // number of grid classes used
154 + * numberOfGrids: 2, // number of grid classes used
151 + * classPrefix: 'class', // prefix for the grid classes
155 + * classPrefix: 'class', // prefix for the grid classes
152 + * cookiePrefix: 'mygrid' // prefix for the cookie name
156 + * cookiePrefix: 'mygrid' // prefix for the cookie name
153 + * });
157 + * });
154 + */
158 + */
155 +if (typeof jQuery == "undefined") {
159 +if (typeof jQuery == "undefined") {
156 + alert("Hashgrid: jQuery not loaded. Make sure it's linked to your pages.");
160 + alert("Hashgrid: jQuery not loaded. Make sure it's linked to your pages.");
157 +}
161 +}
158 +
162 +
159 +
163 +
160 +/**
164 +/**
161 + * hashgrid overlay
165 + * hashgrid overlay
162 + */
166 + */
163 +var hashgrid = function(set) {
167 +var hashgrid = function(set) {
164 +
168 +
165 + var options = {
169 + var options = {
166 + id: 'grid', // id for the grid container
170 + id: 'grid', // id for the grid container
167 + modifierKey: null, // optional 'ctrl', 'alt' or 'shift'
171 + modifierKey: null, // optional 'ctrl', 'alt' or 'shift'
168 + showGridKey: 'g', // key to show the grid
172 + showGridKey: 'g', // key to show the grid
169 + holdGridKey: 'h', // key to hold the grid in place
173 + holdGridKey: 'h', // key to hold the grid in place
170 + foregroundKey: 'f', // key to toggle foreground/background
174 + foregroundKey: 'f', // key to toggle foreground/background
171 + jumpGridsKey: 'j', // key to cycle through the grid classes
175 + jumpGridsKey: 'j', // key to cycle through the grid classes
172 + numberOfGrids: 1, // number of grid classes used
176 + numberOfGrids: 1, // number of grid classes used
173 + classPrefix: 'grid-', // prefix for the grid classes
177 + classPrefix: 'grid-', // prefix for the grid classes
174 + cookiePrefix: 'hashgrid'// prefix for the cookie name
178 + cookiePrefix: 'hashgrid'// prefix for the cookie name
175 + };
179 + };
176 + var overlayOn = false,
180 + var overlayOn = false,
177 + sticky = false,
181 + sticky = false,
178 + overlayZState = 'B',
182 + overlayZState = 'B',
179 + overlayZBackground = -1,
183 + overlayZBackground = -1,
180 + overlayZForeground = 9999,
184 + overlayZForeground = 9999,
181 + classNumber = 1;
185 + classNumber = 1;
182 +
186 +
183 + // Apply options
187 + // Apply options
184 + if (typeof set == 'object') {
188 + if (typeof set == 'object') {
185 + var k;
189 + var k;
186 + for (k in set) options[k] = set[k];
190 + for (k in set) options[k] = set[k];
187 + }
191 + }
188 + else if (typeof set == 'string') {
192 + else if (typeof set == 'string') {
189 + options.id = set;
193 + options.id = set;
190 + }
194 + }
191 +
195 +
192 + // Remove any conflicting overlay
196 + // Remove any conflicting overlay
193 + if ($('#' + options.id).length > 0) {
197 + if ($('#' + options.id).length > 0) {
194 + $('#' + options.id).remove();
198 + $('#' + options.id).remove();
195 + }
199 + }
196 +
200 +
197 + // Create overlay, hidden before adding to DOM
201 + // Create overlay, hidden before adding to DOM
198 + var overlayEl = $('<div></div>');
202 + var overlayEl = $('<div></div>');
199 + overlayEl
203 + overlayEl
200 + .attr('id', options.id)
204 + .attr('id', options.id)
201 + .css({
205 + .css({
202 + display: 'none',
206 + display: 'none',
203 + 'pointer-events': 'none'
207 + 'pointer-events': 'none'
204 + });
208 + });
205 + $("body").prepend(overlayEl);
209 + $("body").prepend(overlayEl);
206 + var overlay = $('#' + options.id);
210 + var overlay = $('#' + options.id);
207 +
211 +
208 + // Unless a custom z-index is set, ensure the overlay will be behind everything
212 + // Unless a custom z-index is set, ensure the overlay will be behind everything
209 + if (overlay.css('z-index') == 'auto') overlay.css('z-index', overlayZBackground);
213 + if (overlay.css('z-index') == 'auto') overlay.css('z-index', overlayZBackground);
210 +
214 +
211 + // Override the default overlay height with the actual page height
215 + // Override the default overlay height with the actual page height
212 + var pageHeight = parseFloat($(document).height());
216 + var pageHeight = parseFloat($(document).height());
213 + overlay.height(pageHeight);
217 + overlay.height(pageHeight);
214 +
218 +
215 + // Add the first grid line so that we can measure it
219 + // Add the first grid line so that we can measure it
216 + overlay.append('<div id="' + options.id + '-horiz" class="horiz first-line">');
220 + overlay.append('<div id="' + options.id + '-horiz" class="horiz first-line">');
217 +
221 +
218 + // Position off-screen and display to calculate height
222 + // Position off-screen and display to calculate height
219 + var top = overlay.css("top");
223 + var top = overlay.css("top");
220 + overlay.css({
224 + overlay.css({
221 + top: "-999px",
225 + top: "-999px",
222 + display: "block"
226 + display: "block"
223 + });
227 + });
224 +
228 +
225 + // Calculate the number of grid lines needed
229 + // Calculate the number of grid lines needed
226 + var line = $('#' + options.id + '-horiz'),
230 + var line = $('#' + options.id + '-horiz'),
227 + lineHeight = line.outerHeight();
231 + lineHeight = line.outerHeight();
228 +
232 +
229 + // Hide and reset top
233 + // Hide and reset top
230 + overlay.css({
234 + overlay.css({
231 + display: "none",
235 + display: "none",
232 + top: top
236 + top: top
233 + });
237 + });
234 +
238 +
235 + // Break on zero line height
239 + // Break on zero line height
236 + if (lineHeight <= 0) return true;
240 + if (lineHeight <= 0) return true;
237 +
241 +
238 + // Add the remaining grid lines
242 + // Add the remaining grid lines
239 + var i, numGridLines = Math.floor(pageHeight / lineHeight);
243 + var i, numGridLines = Math.floor(pageHeight / lineHeight);
240 + for (i = numGridLines - 1; i >= 1; i--) {
244 + for (i = numGridLines - 1; i >= 1; i--) {
241 + overlay.append('<div class="horiz"></div>');
245 + overlay.append('<div class="horiz"></div>');
242 + }
246 + }
243 +
247 +
244 + // vertical grid
248 + // vertical grid
245 + overlay.append($('<div class="vert-container"></div>'));
249 + overlay.append($('<div class="vert-container"></div>'));
246 + var overlayVert = overlay.children('.vert-container');
250 + var overlayVert = overlay.children('.vert-container');
247 + var gridWidth = overlay.width();
251 + var gridWidth = overlay.width();
248 + overlayVert.css({width: gridWidth, position: 'absolute', top: 0});
252 + overlayVert.css({width: gridWidth, position: 'absolute', top: 0});
249 + overlayVert.append('<div class="vert first-line">&nbsp;</div>');
253 + overlayVert.append('<div class="vert first-line">&nbsp;</div>');
250 +
254 +
251 + // 30 is an arbitrarily large number...
255 + // 30 is an arbitrarily large number...
252 + // can't calculate the margin width properly
256 + // can't calculate the margin width properly
253 + for (i = 0; i < 30; i++) {
257 + for (i = 0; i < 30; i++) {
254 + overlayVert.append('<div class="vert">&nbsp;</div>');
258 + overlayVert.append('<div class="vert">&nbsp;</div>');
255 + }
259 + }
256 +
260 +
257 + overlayVert.children()
261 + overlayVert.children()
258 + .height(pageHeight)
262 + .height(pageHeight)
259 + .css({display: 'inline-block'});
263 + .css({display: 'inline-block'});
260 +
264 +
261 + // Check for saved state
265 + // Check for saved state
262 + var overlayCookie = readCookie(options.cookiePrefix + options.id);
266 + var overlayCookie = readCookie(options.cookiePrefix + options.id);
263 + if (typeof overlayCookie == 'string') {
267 + if (typeof overlayCookie == 'string') {
264 + var state = overlayCookie.split(',');
268 + var state = overlayCookie.split(',');
265 + state[2] = Number(state[2]);
269 + state[2] = Number(state[2]);
266 + if ((typeof state[2] == 'number') && !isNaN(state[2])) {
270 + if ((typeof state[2] == 'number') && !isNaN(state[2])) {
267 + classNumber = state[2].toFixed(0);
271 + classNumber = state[2].toFixed(0);
268 + overlay.addClass(options.classPrefix + classNumber);
272 + overlay.addClass(options.classPrefix + classNumber);
269 + }
273 + }
270 + if (state[1] == 'F') {
274 + if (state[1] == 'F') {
271 + overlayZState = 'F';
275 + overlayZState = 'F';
272 + overlay.css('z-index', overlayZForeground);
276 + overlay.css('z-index', overlayZForeground);
273 + }
277 + }
274 + if (state[0] == '1') {
278 + if (state[0] == '1') {
275 + overlayOn = true;
279 + overlayOn = true;
276 + sticky = true;
280 + sticky = true;
277 + showOverlay();
281 + showOverlay();
278 + }
282 + }
279 + }
283 + }
280 + else {
284 + else {
281 + overlay.addClass(options.classPrefix + classNumber);
285 + overlay.addClass(options.classPrefix + classNumber);
282 + }
286 + }
283 +
287 +
284 + // Keyboard controls
288 + // Keyboard controls
285 + $(document).bind('keydown', keydownHandler);
289 + $(document).bind('keydown', keydownHandler);
286 + $(document).bind('keyup', keyupHandler);
290 + $(document).bind('keyup', keyupHandler);
287 +
291 +
288 + /**
292 + /**
289 + * Helpers
293 + * Helpers
290 + */
294 + */
291 +
295 +
292 + function getModifier(e) {
296 + function getModifier(e) {
293 + if (options.modifierKey == null) return true; // Bypass by default
297 + if (options.modifierKey == null) return true; // Bypass by default
294 + var m = true;
298 + var m = true;
295 + switch(options.modifierKey) {
299 + switch(options.modifierKey) {
296 + case 'ctrl':
300 + case 'ctrl':
297 + m = (e.ctrlKey ? e.ctrlKey : false);
301 + m = (e.ctrlKey ? e.ctrlKey : false);
298 + break;
302 + break;
299 +
303 +
300 + case 'alt':
304 + case 'alt':
301 + m = (e.altKey ? e.altKey : false);
305 + m = (e.altKey ? e.altKey : false);
302 + break;
306 + break;
303 +
307 +
304 + case 'shift':
308 + case 'shift':
305 + m = (e.shiftKey ? e.shiftKey : false);
309 + m = (e.shiftKey ? e.shiftKey : false);
306 + break;
310 + break;
307 + }
311 + }
308 + return m;
312 + return m;
309 + }
313 + }
310 +
314 +
311 + function getKey(e) {
315 + function getKey(e) {
312 + var k = false, c = (e.keyCode ? e.keyCode : e.which);
316 + var k = false, c = (e.keyCode ? e.keyCode : e.which);
313 + // Handle keywords
317 + // Handle keywords
314 + if (c == 13) k = 'enter';
318 + if (c == 13) k = 'enter';
315 + // Handle letters
319 + // Handle letters
316 + else k = String.fromCharCode(c).toLowerCase();
320 + else k = String.fromCharCode(c).toLowerCase();
317 + return k;
321 + return k;
318 + }
322 + }
319 +
323 +
320 + function saveState() {
324 + function saveState() {
321 + createCookie(options.cookiePrefix + options.id, (sticky ? '1' : '0') + ',' + overlayZState + ',' + classNumber, 1);
325 + createCookie(options.cookiePrefix + options.id, (sticky ? '1' : '0') + ',' + overlayZState + ',' + classNumber, 1);
322 + }
326 + }
323 +
327 +
324 + function showOverlay() {
328 + function showOverlay() {
325 + overlay.show();
329 + overlay.show();
326 + overlayVert.css({width: overlay.width()});
330 + overlayVert.css({width: overlay.width()});
327 + // hide any vertical blocks that aren't at the top of the viewport
331 + // hide any vertical blocks that aren't at the top of the viewport
328 + overlayVert.children('.vert').each(function () {
332 + overlayVert.children('.vert').each(function () {
329 + $(this).css('display','inline-block');
333 + $(this).css('display','inline-block');
330 + if ($(this).offset().top > 0) {
334 + if ($(this).offset().top > 0) {
331 + $(this).hide();
335 + $(this).hide();
332 + }
336 + }
333 + });
337 + });
334 + }
338 + }
335 +
339 +
336 + /**
340 + /**
337 + * Event handlers
341 + * Event handlers
338 + */
342 + */
339 +
343 +
340 + function keydownHandler(e) {
344 + function keydownHandler(e) {
341 + var source = e.target.tagName.toLowerCase();
345 + var source = e.target.tagName.toLowerCase();
342 + if ((source == 'input') || (source == 'textarea') || (source == 'select')) return true;
346 + if ((source == 'input') || (source == 'textarea') || (source == 'select')) return true;
343 + var m = getModifier(e);
347 + var m = getModifier(e);
344 + if (!m) return true;
348 + if (!m) return true;
345 + var k = getKey(e);
349 + var k = getKey(e);
346 + if (!k) return true;
350 + if (!k) return true;
347 + switch(k) {
351 + switch(k) {
348 + case options.showGridKey:
352 + case options.showGridKey:
349 + if (!overlayOn) {
353 + if (!overlayOn) {
350 + showOverlay();
354 + showOverlay();
351 + overlayOn = true;
355 + overlayOn = true;
352 + }
356 + }
353 + else if (sticky) {
357 + else if (sticky) {
354 + overlay.hide();
358 + overlay.hide();
355 + overlayOn = false;
359 + overlayOn = false;
356 + sticky = false;
360 + sticky = false;
357 + saveState();
361 + saveState();
358 + }
362 + }
359 + break;
363 + break;
360 + case options.holdGridKey:
364 + case options.holdGridKey:
361 + if (overlayOn && !sticky) {
365 + if (overlayOn && !sticky) {
362 + // Turn sticky overlay on
366 + // Turn sticky overlay on
363 + sticky = true;
367 + sticky = true;
364 + saveState();
368 + saveState();
365 + }
369 + }
366 + break;
370 + break;
367 + case options.foregroundKey:
371 + case options.foregroundKey:
368 + if (overlayOn) {
372 + if (overlayOn) {
369 + // Toggle sticky overlay z-index
373 + // Toggle sticky overlay z-index
370 + if (overlay.css('z-index') == overlayZForeground) {
374 + if (overlay.css('z-index') == overlayZForeground) {
371 + overlay.css('z-index', overlayZBackground);
375 + overlay.css('z-index', overlayZBackground);
372 + overlayZState = 'B';
376 + overlayZState = 'B';
373 + }
377 + }
374 + else {
378 + else {
375 + overlay.css('z-index', overlayZForeground);
379 + overlay.css('z-index', overlayZForeground);
376 + overlayZState = 'F';
380 + overlayZState = 'F';
377 + }
381 + }
378 + saveState();
382 + saveState();
379 + }
383 + }
380 + break;
384 + break;
381 + case options.jumpGridsKey:
385 + case options.jumpGridsKey:
382 + if (overlayOn && (options.numberOfGrids > 1)) {
386 + if (overlayOn && (options.numberOfGrids > 1)) {
383 + // Cycle through the available grids
387 + // Cycle through the available grids
384 + overlay.removeClass(options.classPrefix + classNumber);
388 + overlay.removeClass(options.classPrefix + classNumber);
385 + classNumber++;
389 + classNumber++;
386 + if (classNumber > options.numberOfGrids) classNumber = 1;
390 + if (classNumber > options.numberOfGrids) classNumber = 1;
387 + overlay.addClass(options.classPrefix + classNumber);
391 + overlay.addClass(options.classPrefix + classNumber);
388 + showOverlay();
392 + showOverlay();
389 + if (/webkit/.test( navigator.userAgent.toLowerCase() )) {
393 + if (/webkit/.test( navigator.userAgent.toLowerCase() )) {
390 + forceRepaint();
394 + forceRepaint();
391 + }
395 + }
392 + saveState();
396 + saveState();
393 + }
397 + }
394 + break;
398 + break;
395 + }
399 + }
396 + }
400 + }
397 +
401 +
398 + function keyupHandler(e) {
402 + function keyupHandler(e) {
399 + var m = getModifier(e);
403 + var m = getModifier(e);
400 + if (!m) return true;
404 + if (!m) return true;
401 + var k = getKey(e);
405 + var k = getKey(e);
402 + if (!k) return true;
406 + if (!k) return true;
403 + if ((k == options.showGridKey) && !sticky) {
407 + if ((k == options.showGridKey) && !sticky) {
404 + overlay.hide();
408 + overlay.hide();
405 + overlayOn = false;
409 + overlayOn = false;
406 + }
410 + }
407 + }
411 + }
408 +
412 +
409 + /**
413 + /**
410 + * Cookie functions
414 + * Cookie functions
411 + *
415 + *
412 + * By Peter-Paul Koch:
416 + * By Peter-Paul Koch:
413 + * http://www.quirksmode.org/js/cookies.html
417 + * http://www.quirksmode.org/js/cookies.html
414 + */
418 + */
415 + function createCookie(name,value,days) {
419 + function createCookie(name,value,days) {
416 + if (days) {
420 + if (days) {
417 + var date = new Date();
421 + var date = new Date();
418 + date.setTime(date.getTime()+(days*24*60*60*1000));
422 + date.setTime(date.getTime()+(days*24*60*60*1000));
419 + var expires = "; expires="+date.toGMTString();
423 + var expires = "; expires="+date.toGMTString();
420 + }
424 + }
421 + else var expires = "";
425 + else var expires = "";
422 + document.cookie = name+"="+value+expires+"; path=/";
426 + document.cookie = name+"="+value+expires+"; path=/";
423 + }
427 + }
424 +
428 +
425 + function readCookie(name) {
429 + function readCookie(name) {
426 + var nameEQ = name + "=";
430 + var nameEQ = name + "=";
427 + var ca = document.cookie.split(';');
431 + var ca = document.cookie.split(';');
428 + for(var i=0;i < ca.length;i++) {
432 + for(var i=0;i < ca.length;i++) {
429 + var c = ca[i];
433 + var c = ca[i];
430 + while (c.charAt(0)==' ') c = c.substring(1,c.length);
434 + while (c.charAt(0)==' ') c = c.substring(1,c.length);
431 + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
435 + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
432 + }
436 + }
433 + return null;
437 + return null;
434 + }
438 + }
435 +
439 +
436 + function eraseCookie(name) {
440 + function eraseCookie(name) {
437 + createCookie(name,"",-1);
441 + createCookie(name,"",-1);
438 + }
442 + }
439 +
443 +
440 + /**
444 + /**
441 + * Forces a repaint (because WebKit has issues)
445 + * Forces a repaint (because WebKit has issues)
442 + * http://www.sitepoint.com/forums/showthread.php?p=4538763
446 + * http://www.sitepoint.com/forums/showthread.php?p=4538763
443 + * http://www.phpied.com/the-new-game-show-will-it-reflow/
447 + * http://www.phpied.com/the-new-game-show-will-it-reflow/
444 + */
448 + */
445 + function forceRepaint() {
449 + function forceRepaint() {
446 + var ss = document.styleSheets[0];
450 + var ss = document.styleSheets[0];
447 + try {
451 + try {
448 + ss.addRule('.xxxxxx', 'position: relative');
452 + ss.addRule('.xxxxxx', 'position: relative');
449 + ss.removeRule(ss.rules.length - 1);
453 + ss.removeRule(ss.rules.length - 1);
450 + } catch(e){}
454 + } catch(e){}
451 + }
455 + }
452 +
456 +
453 +}
457 +}
454 +
458 +
455 +
459 +
456 +/**
460 +/**
457 + * You can call hashgrid from your own code, but it's loaded here as
461 + * You can call hashgrid from your own code, but it's loaded here as
458 + * an example for your convenience.
462 + * an example for your convenience.
459 + */
463 + */
460 +$(document).ready(function() {
464 +$(document).ready(function() {
461 +
465 +
462 + var grid = new hashgrid({
466 + var grid = new hashgrid({
463 + numberOfGrids: 2
467 + numberOfGrids: 2
464 + });
468 + });
465 +
469 +
466 +});
470 +});
467 diff --git a/less/docs.less b/less/docs.less
471 diff --git a/less/docs.less b/less/docs.less
468 --- a/less/docs.less
472 --- a/less/docs.less
469 +++ b/less/docs.less
473 +++ b/less/docs.less
470 @@ -1,3 +1,10 @@
474 @@ -1,3 +1,10 @@
471 +body {
475 +body {
472 + #gradient > .vertical-three-colors(#eee, #fff, 0.15, #fff);
476 + #gradient > .vertical-three-colors(#eee, #fff, 0.15, #fff);
473 + background-attachment: fixed;
477 + background-attachment: fixed;
474 + background-position: 0 40px;
478 + background-position: 0 40px;
475 + position: relative;
479 + position: relative;
476 +}
480 +}
477 +
481 +
478 // Give us some love
482 // Give us some love
479 header,
483 header,
480 section,
484 section,
481 @@ -77,3 +84,30 @@
485 @@ -77,3 +84,30 @@
482 section {
486 section {
483 margin-bottom: 40px;
487 margin-bottom: 40px;
484 }
488 }
485 +
489 +
486 +// Hashgrid grid
490 +// Hashgrid grid
487 +/**
491 +/**
488 + * Grid
492 + * Grid
489 + */
493 + */
490 +#grid {
494 +#grid {
491 + width: 980px;
495 + width: 980px;
492 + position: absolute;
496 + position: absolute;
493 + top: 0;
497 + top: 0;
494 + left: 50%;
498 + left: 50%;
495 + margin-left: -490px;
499 + margin-left: -490px;
496 +}
500 +}
497 +#grid div.vert {
501 +#grid div.vert {
498 + width: 39px;
502 + width: 39px;
499 + border: solid darkturquoise;
503 + border: solid darkturquoise;
500 + border-width: 0 1px;
504 + border-width: 0 1px;
501 + margin-right: 19px;
505 + margin-right: 19px;
502 +}
506 +}
503 +#grid div.vert.first-line {
507 +#grid div.vert.first-line {
504 + margin-left: 19px;
508 + margin-left: 19px;
505 +}
509 +}
506 +#grid div.horiz {
510 +#grid div.horiz {
507 + height: 19px;
511 + height: 19px;
508 + border-bottom: 1px dotted rgba(255,0,0,.25);
512 + border-bottom: 1px dotted rgba(255,0,0,.25);
509 + margin: 0;
513 + margin: 0;
510 + padding: 0;
514 + padding: 0;
511 +}
515 +}
512 diff --git a/less/scaffolding.less b/less/scaffolding.less
516 diff --git a/less/scaffolding.less b/less/scaffolding.less
513 --- a/less/scaffolding.less
517 --- a/less/scaffolding.less
514 +++ b/less/scaffolding.less
518 +++ b/less/scaffolding.less
515 @@ -7,7 +7,7 @@
519 @@ -7,7 +7,7 @@
516 -------------------------------------------------- */
520 -------------------------------------------------- */
517
521
518 div.row {
522 div.row {
519 - .clearfix;
523 - .clearfix;
520 + .clearfix();
524 + .clearfix();
521 div.span1 { .columns(1); }
525 div.span1 { .columns(1); }
522 div.span2 { .columns(2); }
526 div.span2 { .columns(2); }
523 div.span3 { .columns(3); }
527 div.span3 { .columns(3); }
524 @@ -34,8 +34,6 @@
528 @@ -34,8 +34,6 @@
525 background-color: #fff;
529 background-color: #fff;
526 }
530 }
527 body {
531 body {
528 - #gradient > .vertical-three-colors(#eee, #fff, 0.25, #fff);
532 - #gradient > .vertical-three-colors(#eee, #fff, 0.25, #fff);
529 - background-attachment: fixed;
533 - background-attachment: fixed;
530 margin: 0;
534 margin: 0;
531 .sans-serif(normal,14px,20px);
535 .sans-serif(normal,14px,20px);
532 color: @gray;
536 color: @gray;
533 diff --git a/readme.markdown b/readme.markdown
537 diff --git a/readme.markdown b/readme.markdown
534 --- a/readme.markdown
538 --- a/readme.markdown
535 +++ b/readme.markdown
539 +++ b/readme.markdown
536 @@ -1,13 +1,4 @@
540 @@ -1,13 +1,4 @@
537 TODOS
541 TODOS
538
542
539 -* Write "Using Twitter BP" section
543 -* Write "Using Twitter BP" section
540 -** Two ways to use: LESS.js or compiled
544 -** Two ways to use: LESS.js or compiled
541 -** Not meant to be 100% bulletproof, but is 90% bulletproof (stats?)
545 -** Not meant to be 100% bulletproof, but is 90% bulletproof (stats?)
542 -** Advanced framework for fast prototyping, internal app development, bootstraping new websites
546 -** Advanced framework for fast prototyping, internal app development, bootstraping new websites
543 -** Can be easily modified to provide more legacy support
547 -** Can be easily modified to provide more legacy support
544 -
548 -
545 -* Add grid examples back in
549 -* Add grid examples back in
546 * Cross browser checks? Show this anywhere?
550 * Cross browser checks? Show this anywhere?
547 -* Add layouts section back in
551 -* Add layouts section back in
548 -
552 -
549 -* Point JS libraries to public library links instead of within the repo
553 -* Point JS libraries to public library links instead of within the repo
550 \ No newline at end of file
554 \ No newline at end of file
551 +* Add layouts section back in
555 +* Add layouts section back in
552 \ No newline at end of file
556 \ No newline at end of file
@@ -1,3 +1,6 b''
1 diff --git a/US Warszawa.jpg b/US Warszawa.jpg
1 diff --git a/US Warszawa.jpg b/US Warszawa.jpg
2 deleted file mode 100755
2 deleted file mode 100755
3 Binary file US Warszawa.jpg has changed
3 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000
4 GIT binary patch
5 literal 0
6 Hc$@<O00001
@@ -1,86 +1,251 b''
1 from __future__ import with_statement
1 from __future__ import with_statement
2 import os
2 import os
3 import unittest
3 import unittest
4 from rhodecode.tests import *
4 from rhodecode.tests import *
5 from rhodecode.lib.diffs import DiffProcessor, NEW_FILENODE, DEL_FILENODE, \
5 from rhodecode.lib.diffs import DiffProcessor, NEW_FILENODE, DEL_FILENODE, \
6 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE
6 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
7
7
8 dn = os.path.dirname
8 dn = os.path.dirname
9 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'fixtures')
9 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'fixtures')
10
10
11 DIFF_FIXTURES = {
11 DIFF_FIXTURES = {
12 'hg_diff_add_single_binary_file.diff': [
12 'hg_diff_add_single_binary_file.diff': [
13 (u'US Warszawa.jpg', 'A', ['b', NEW_FILENODE]),
13 ('US Warszawa.jpg', 'A',
14 {'added': 0,
15 'deleted': 0,
16 'binary': True,
17 'ops': {NEW_FILENODE: 'new file 100755',
18 BIN_FILENODE: 'binary diff not shown'}}),
14 ],
19 ],
15 'hg_diff_mod_single_binary_file.diff': [
20 'hg_diff_mod_single_binary_file.diff': [
16 (u'US Warszawa.jpg', 'M', ['b', MOD_FILENODE]),
21 ('US Warszawa.jpg', 'M',
22 {'added': 0,
23 'deleted': 0,
24 'binary': True,
25 'ops': {MOD_FILENODE: 'modified file',
26 BIN_FILENODE: 'binary diff not shown'}}),
27 ],
28
29 'hg_diff_mod_single_file_and_rename_and_chmod.diff': [
30 ('README', 'M',
31 {'added': 3,
32 'deleted': 0,
33 'binary': False,
34 'ops': {MOD_FILENODE: 'modified file',
35 RENAMED_FILENODE: 'file renamed from README.rst to README',
36 CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
37 ],
38 'hg_diff_rename_and_chmod_file.diff': [
39 ('README', 'M',
40 {'added': 3,
41 'deleted': 0,
42 'binary': False,
43 'ops': {MOD_FILENODE: 'modified file',
44 BIN_FILENODE: 'binary diff not shown'}}),
17 ],
45 ],
18 'hg_diff_del_single_binary_file.diff': [
46 'hg_diff_del_single_binary_file.diff': [
19 (u'US Warszawa.jpg', 'D', ['b', DEL_FILENODE]),
47 ('US Warszawa.jpg', 'D',
48 {'added': 0,
49 'deleted': 0,
50 'binary': True,
51 'ops': {DEL_FILENODE: 'deleted file',
52 BIN_FILENODE: 'binary diff not shown'}}),
53 ],
54 'hg_diff_chmod_and_mod_single_binary_file.diff': [
55 ('gravatar.png', 'M',
56 {'added': 0,
57 'deleted': 0,
58 'binary': True,
59 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
60 BIN_FILENODE: 'binary diff not shown'}}),
61 ],
62 'hg_diff_chmod.diff': [
63 ('file', 'M',
64 {'added': 0,
65 'deleted': 0,
66 'binary': True,
67 'ops': {CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
68 ],
69 'hg_diff_rename_file.diff': [
70 ('file_renamed', 'M',
71 {'added': 0,
72 'deleted': 0,
73 'binary': True,
74 'ops': {RENAMED_FILENODE: 'file renamed from file to file_renamed'}}),
75 ],
76 'hg_diff_rename_and_chmod_file.diff': [
77 ('README', 'M',
78 {'added': 0,
79 'deleted': 0,
80 'binary': True,
81 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
82 RENAMED_FILENODE: 'file renamed from README.rst to README'}}),
20 ],
83 ],
21 'hg_diff_binary_and_normal.diff': [
84 'hg_diff_binary_and_normal.diff': [
22 (u'img/baseline-10px.png', 'A', ['b', NEW_FILENODE]),
85 ('img/baseline-10px.png', 'A',
23 (u'js/jquery/hashgrid.js', 'A', [340, 0]),
86 {'added': 0,
24 (u'index.html', 'M', [3, 2]),
87 'deleted': 0,
25 (u'less/docs.less', 'M', [34, 0]),
88 'binary': True,
26 (u'less/scaffolding.less', 'M', [1, 3]),
89 'ops': {NEW_FILENODE: 'new file 100644',
27 (u'readme.markdown', 'M', [1, 10]),
90 BIN_FILENODE: 'binary diff not shown'}}),
28 (u'img/baseline-20px.png', 'D', ['b', DEL_FILENODE]),
91 ('js/jquery/hashgrid.js', 'A',
29 (u'js/global.js', 'D', [0, 75])
92 {'added': 340,
30 ],
93 'deleted': 0,
31 'hg_diff_chmod.diff': [
94 'binary': False,
32 (u'file', 'M', ['b', CHMOD_FILENODE]),
95 'ops': {NEW_FILENODE: 'new file 100755'}}),
33 ],
96 ('index.html', 'M',
34 'hg_diff_rename_file.diff': [
97 {'added': 3,
35 (u'file_renamed', 'M', ['b', RENAMED_FILENODE]),
98 'deleted': 2,
99 'binary': False,
100 'ops': {MOD_FILENODE: 'modified file'}}),
101 ('less/docs.less', 'M',
102 {'added': 34,
103 'deleted': 0,
104 'binary': False,
105 'ops': {MOD_FILENODE: 'modified file'}}),
106 ('less/scaffolding.less', 'M',
107 {'added': 1,
108 'deleted': 3,
109 'binary': False,
110 'ops': {MOD_FILENODE: 'modified file'}}),
111 ('readme.markdown', 'M',
112 {'added': 1,
113 'deleted': 10,
114 'binary': False,
115 'ops': {MOD_FILENODE: 'modified file'}}),
116 ('img/baseline-20px.png', 'D',
117 {'added': 0,
118 'deleted': 0,
119 'binary': True,
120 'ops': {DEL_FILENODE: 'deleted file',
121 BIN_FILENODE: 'binary diff not shown'}}),
122 ('js/global.js', 'D',
123 {'added': 0,
124 'deleted': 75,
125 'binary': False,
126 'ops': {DEL_FILENODE: 'deleted file'}})
36 ],
127 ],
37 'git_diff_chmod.diff': [
128 'git_diff_chmod.diff': [
38 (u'work-horus.xls', 'M', ['b', CHMOD_FILENODE]),
129 ('work-horus.xls', 'M',
130 {'added': 0,
131 'deleted': 0,
132 'binary': True,
133 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755'}})
39 ],
134 ],
40 'git_diff_rename_file.diff': [
135 'git_diff_rename_file.diff': [
41 (u'file.xls', 'M', ['b', RENAMED_FILENODE]),
136 ('file.xls', 'M',
137 {'added': 0,
138 'deleted': 0,
139 'binary': True,
140 'ops': {RENAMED_FILENODE: 'file renamed from work-horus.xls to file.xls'}})
42 ],
141 ],
43 'git_diff_mod_single_binary_file.diff': [
142 'git_diff_mod_single_binary_file.diff': [
44 ('US Warszawa.jpg', 'M', ['b', MOD_FILENODE])
143 ('US Warszawa.jpg', 'M',
45
144 {'added': 0,
145 'deleted': 0,
146 'binary': True,
147 'ops': {MOD_FILENODE: 'modified file',
148 BIN_FILENODE: 'binary diff not shown'}})
46 ],
149 ],
47 'git_diff_binary_and_normal.diff': [
150 'git_diff_binary_and_normal.diff': [
48 (u'img/baseline-10px.png', 'A', ['b', NEW_FILENODE]),
151 ('img/baseline-10px.png', 'A',
49 (u'js/jquery/hashgrid.js', 'A', [340, 0]),
152 {'added': 0,
50 (u'index.html', 'M', [3, 2]),
153 'deleted': 0,
51 (u'less/docs.less', 'M', [34, 0]),
154 'binary': True,
52 (u'less/scaffolding.less', 'M', [1, 3]),
155 'ops': {NEW_FILENODE: 'new file 100644',
53 (u'readme.markdown', 'M', [1, 10]),
156 BIN_FILENODE: 'binary diff not shown'}}),
54 (u'img/baseline-20px.png', 'D', ['b', DEL_FILENODE]),
157 ('js/jquery/hashgrid.js', 'A',
55 (u'js/global.js', 'D', [0, 75])
158 {'added': 340,
159 'deleted': 0,
160 'binary': False,
161 'ops': {NEW_FILENODE: 'new file 100755'}}),
162 ('index.html', 'M',
163 {'added': 3,
164 'deleted': 2,
165 'binary': False,
166 'ops': {MOD_FILENODE: 'modified file'}}),
167 ('less/docs.less', 'M',
168 {'added': 34,
169 'deleted': 0,
170 'binary': False,
171 'ops': {MOD_FILENODE: 'modified file'}}),
172 ('less/scaffolding.less', 'M',
173 {'added': 1,
174 'deleted': 3,
175 'binary': False,
176 'ops': {MOD_FILENODE: 'modified file'}}),
177 ('readme.markdown', 'M',
178 {'added': 1,
179 'deleted': 10,
180 'binary': False,
181 'ops': {MOD_FILENODE: 'modified file'}}),
182 ('img/baseline-20px.png', 'D',
183 {'added': 0,
184 'deleted': 0,
185 'binary': True,
186 'ops': {DEL_FILENODE: 'deleted file',
187 BIN_FILENODE: 'binary diff not shown'}}),
188 ('js/global.js', 'D',
189 {'added': 0,
190 'deleted': 75,
191 'binary': False,
192 'ops': {DEL_FILENODE: 'deleted file'}}),
56 ],
193 ],
57 'diff_with_diff_data.diff': [
194 'diff_with_diff_data.diff': [
58 (u'vcs/backends/base.py', 'M', [18, 2]),
195 ('vcs/backends/base.py', 'M',
59 (u'vcs/backends/git/repository.py', 'M', [46, 15]),
196 {'added': 18,
60 (u'vcs/backends/hg.py', 'M', [22, 3]),
197 'deleted': 2,
61 (u'vcs/tests/test_git.py', 'M', [5, 5]),
198 'binary': False,
62 (u'vcs/tests/test_repository.py', 'M', [174, 2])
199 'ops': {MOD_FILENODE: 'modified file'}}),
200 ('vcs/backends/git/repository.py', 'M',
201 {'added': 46,
202 'deleted': 15,
203 'binary': False,
204 'ops': {MOD_FILENODE: 'modified file'}}),
205 ('vcs/backends/hg.py', 'M',
206 {'added': 22,
207 'deleted': 3,
208 'binary': False,
209 'ops': {MOD_FILENODE: 'modified file'}}),
210 ('vcs/tests/test_git.py', 'M',
211 {'added': 5,
212 'deleted': 5,
213 'binary': False,
214 'ops': {MOD_FILENODE: 'modified file'}}),
215 ('vcs/tests/test_repository.py', 'M',
216 {'added': 174,
217 'deleted': 2,
218 'binary': False,
219 'ops': {MOD_FILENODE: 'modified file'}}),
63 ],
220 ],
64 # 'large_diff.diff': [
221 # 'large_diff.diff': [
65 #
222 # ('.hgignore', 'A', {'deleted': 0, 'binary': False, 'added': 3, 'ops': {1: 'new file 100644'}}),
223 # ('MANIFEST.in', 'A', {'deleted': 0, 'binary': False, 'added': 3, 'ops': {1: 'new file 100644'}}),
224 # ('README.txt', 'A', {'deleted': 0, 'binary': False, 'added': 19, 'ops': {1: 'new file 100644'}}),
225 # ('development.ini', 'A', {'deleted': 0, 'binary': False, 'added': 116, 'ops': {1: 'new file 100644'}}),
226 # ('docs/index.txt', 'A', {'deleted': 0, 'binary': False, 'added': 19, 'ops': {1: 'new file 100644'}}),
227 # ('ez_setup.py', 'A', {'deleted': 0, 'binary': False, 'added': 276, 'ops': {1: 'new file 100644'}}),
228 # ('hgapp.py', 'A', {'deleted': 0, 'binary': False, 'added': 26, 'ops': {1: 'new file 100644'}}),
229 # ('hgwebdir.config', 'A', {'deleted': 0, 'binary': False, 'added': 21, 'ops': {1: 'new file 100644'}}),
230 # ('pylons_app.egg-info/PKG-INFO', 'A', {'deleted': 0, 'binary': False, 'added': 10, 'ops': {1: 'new file 100644'}}),
231 # ('pylons_app.egg-info/SOURCES.txt', 'A', {'deleted': 0, 'binary': False, 'added': 33, 'ops': {1: 'new file 100644'}}),
232 # ('pylons_app.egg-info/dependency_links.txt', 'A', {'deleted': 0, 'binary': False, 'added': 1, 'ops': {1: 'new file 100644'}}),
233 # #TODO:
66 # ],
234 # ],
67
235
68
69 }
236 }
70
237
71
238
72 def _diff_checker(fixture):
239 class DiffLibTest(unittest.TestCase):
73 with open(os.path.join(FIXTURES, fixture)) as f:
240
241 @parameterized.expand([(x,) for x in DIFF_FIXTURES])
242 def test_diff(self, diff_fixture):
243
244 with open(os.path.join(FIXTURES, diff_fixture)) as f:
74 diff = f.read()
245 diff = f.read()
75
246
76 diff_proc = DiffProcessor(diff)
247 diff_proc = DiffProcessor(diff)
77 diff_proc_d = diff_proc.prepare()
248 diff_proc_d = diff_proc.prepare()
78 data = [(x['filename'], x['operation'], x['stats']) for x in diff_proc_d]
249 data = [(x['filename'], x['operation'], x['stats']) for x in diff_proc_d]
79 expected_data = DIFF_FIXTURES[fixture]
250 expected_data = DIFF_FIXTURES[diff_fixture]
80
251 self.assertListEqual(expected_data, data)
81 assert expected_data == data
82
83
84 def test_parse_diff():
85 for fixture in DIFF_FIXTURES:
86 yield _diff_checker, fixture
General Comments 0
You need to be logged in to leave comments. Login now