##// END OF EJS Templates
fixes few bugs...
marcink -
r671:bee56f20 rhodecode-0.0.1.0.1 default
parent child Browse files
Show More
@@ -1,36 +1,46 b''
1 1 .. _changelog:
2 2
3 3 Changelog
4 4 =========
5 5
6
7 1.0.1 (**2010-11-10**)
8 ----------------------
9
10 - fixed #53 python2.5 incompatible enumerate calls
11 - fixed #52 disable mercurial extension for web
12 - fixed #51 deleting repositories don't delete it's dependent objects
13 - small css updated
14
15
6 16 1.0.0 (**2010-11-02**)
7 17 ----------------------
8 18
9 19 - security bugfix simplehg wasn't checking for permissions on commands
10 20 other than pull or push.
11 21 - fixed doubled messages after push or pull in admin journal
12 22 - templating and css corrections, fixed repo switcher on chrome, updated titles
13 23 - admin menu accessible from options menu on repository view
14 24 - permissions cached queries
15 25
16 26 1.0.0rc4 (**2010-10-12**)
17 27 --------------------------
18 28
19 29 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
20 30 - removed cache_manager settings from sqlalchemy meta
21 31 - added sqlalchemy cache settings to ini files
22 32 - validated password length and added second try of failure on paster setup-app
23 33 - fixed setup database destroy prompt even when there was no db
24 34
25 35
26 36 1.0.0rc3 (**2010-10-11**)
27 37 -------------------------
28 38
29 39 - fixed i18n during installation.
30 40
31 41 1.0.0rc2 (**2010-10-11**)
32 42 -------------------------
33 43
34 44 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
35 45 occure. After vcs is fixed it'll be put back again.
36 46 - templating/css rewrites, optimized css.
@@ -1,89 +1,90 b''
1 1 .. _installation:
2 2
3 3 Installation
4 4 ============
5 5
6 6 ``RhodeCode`` is written entirely in Python, but in order to use it's full
7 7 potential there are some third-party requirements. When RhodeCode is used
8 together with celery You have to install some kind of message broker,
8 together with celery_ You have to install some kind of message broker,
9 9 recommended one is rabbitmq_ to make the async tasks work.
10 10
11 11 Of course RhodeCode works in sync mode also, then You don't have to install
12 12 any third party apps. Celery_ will give You large speed improvement when using
13 many big repositories. If You plan to use it for 2 or 3 small repositories, it
13 many big repositories. If You plan to use it for 5 or 10 small repositories, it
14 14 will work just fine without celery running.
15 15
16 16 After You decide to Run it with celery make sure You run celeryd and
17 17 message broker together with the application.
18 18
19 19 Requirements for Celery
20 20 -----------------------
21 21
22 22 **Message Broker**
23 23
24 24 - preferred is `RabbitMq <http://www.rabbitmq.com/>`_
25 25 - possible other is `Redis <http://code.google.com/p/redis/>`_
26 26
27 27 For installation instructions You can visit:
28 28 http://ask.github.com/celery/getting-started/index.html
29 29 It's very nice tutorial how to start celery_ with rabbitmq_
30 30
31 31 Install from Cheese Shop
32 32 ------------------------
33 33
34 34 Easiest way to install ``rhodecode`` is to run::
35 35
36 easy_install rhodecode
36 easy_install rhodecode
37 37
38 38 Or::
39 39
40 40 pip install rhodecode
41 41
42 42 If you prefer to install manually simply grab latest release from
43 43 http://pypi.python.org/pypi/rhodecode, decompres archive and run::
44 44
45 python setup.py install
45 python setup.py install
46 46
47 47
48 48 Step by step installation example
49 49 ---------------------------------
50 50
51 51
52 - Assuming You have installed virtualenv_ create one using. The `--no-site-packages`
53 will make sure non of Your system libs are linked with this virtualenv_
52 - Assuming You have installed virtualenv_ create one using.
53 The `--no-site-packages` will make sure non of Your system libs are linked
54 with this virtualenv_
54 55
55 56 ::
56 57
57 58 virtualenv --no-site-packages /var/www/rhodecode-venv
58 59
59 60 - this will install new virtualenv_ into `/var/www/rhodecode-venv`.
60 61 - Activate the virtualenv_ by running
61 62
62 63 ::
63 64
64 65 source activate /var/www/rhodecode-venv/bin/activate
65 66
66 67 - Make a folder for rhodecode somewhere on the filesystem for example
67 68
68 69 ::
69 70
70 71 mkdir /var/www/rhodecode
71 72
72 73
73 74 - Run this command to install rhodecode
74 75
75 76 ::
76 77
77 78 easy_install rhodecode
78 79
79 80 - this will install rhodecode together with pylons
80 81 and all other required python libraries
81 82
82 83
83 84 You can now proceed to :ref:`setup`
84 85
85 86 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
86 87 .. _python: http://www.python.org/
87 88 .. _mercurial: http://mercurial.selenic.com/
88 89 .. _celery: http://celeryproject.org/
89 90 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
@@ -1,129 +1,141 b''
1 1 .. _setup:
2 2
3 3 Setup
4 4 =====
5 5
6 6
7 7 Setting up the application
8 8 --------------------------
9 9
10 10 ::
11 11
12 12 paster make-config RhodeCode production.ini
13 13
14 14 - This will create `production.ini` config inside the directory
15 15 this config contain various settings for rhodecode, e.g port, email settings
16 16 static files, cache and logging.
17 17
18 18 ::
19 19
20 20 paster setup-app production.ini
21 21
22 22 - This command will create all needed tables and an admin account.
23 23 When asked for a path You can either use a new location of one with already
24 24 existing ones. RhodeCode will simply add all new found repositories to
25 25 it's database. Also make sure You specify correct path to repositories.
26 26 - Remember that the given path for mercurial_ repositories must be write
27 27 accessible for the application. It's very important since RhodeCode web interface
28 28 will work even without such an access but, when trying to do a push it'll
29 29 eventually fail with permission denied errors.
30 30 - Run
31 31
32 32 ::
33 33
34 34 paster serve production.ini
35 35
36 36 - This command runs the rhodecode server the app should be available at the
37 37 127.0.0.1:5000. This ip and port is configurable via the production.ini
38 38 file created in previous step
39 39 - Use admin account you created to login.
40 40 - Default permissions on each repository is read, and owner is admin. So
41 41 remember to update these if needed.
42 42
43 Note
44 ----
45
46 RhodeCode when running without the celery it's running all it's task in sync
47 mode, for first few times when visiting summary page You can notice few
48 slow downs, this is due the statistics building it's cache. After all changesets
49 are parsed it'll take the stats from cache and run much faster. Each summary
50 page display parse at most 250 changesets in order to not stress the cpu, so
51 the full stats are going to be loaded after total_number_of_changesets/250
52 summary page visits.
53
54
43 55
44 56 Setting up Whoosh
45 57 -----------------
46 58
47 59 - For full text search You can either put crontab entry for
48 60
49 61 ::
50 62
51 63 python /var/www/rhodecode/<rhodecode_installation_path>/lib/indexers/daemon.py incremental <put_here_path_to_repos>
52 64
53 65 When using incremental mode whoosh will check last modification date of each file
54 66 and add it to reindex if newer file is available. Also indexing daemon checks
55 67 for removed files and removes them from index. Sometime You might want to rebuild
56 index from scrach, in admin pannel You can check `build from scratch` flag
68 index from scratch, in admin panel You can check `build from scratch` flag
57 69 and in standalone daemon You can pass `full` instead on incremental to build
58 remove previos index and build new one.
70 remove previous index and build new one.
59 71
60 72 Nginx virtual host example
61 73 --------------------------
62 74
63 75 Sample config for nginx::
64 76
65 77 server {
66 78 listen 80;
67 79 server_name hg.myserver.com;
68 80 access_log /var/log/nginx/rhodecode.access.log;
69 81 error_log /var/log/nginx/rhodecode.error.log;
70 82 location / {
71 83 root /var/www/rhodecode/rhodecode/public/;
72 84 if (!-f $request_filename){
73 85 proxy_pass http://127.0.0.1:5000;
74 86 }
75 87 #this is important for https !!!
76 88 proxy_set_header X-Url-Scheme $scheme;
77 89 include /etc/nginx/proxy.conf;
78 90 }
79 91 }
80 92
81 93 Here's the proxy.conf. It's tuned so it'll not timeout on long
82 94 pushes and also on large pushes::
83 95
84 96 proxy_redirect off;
85 97 proxy_set_header Host $host;
86 98 proxy_set_header X-Host $http_host;
87 99 proxy_set_header X-Real-IP $remote_addr;
88 100 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
89 101 proxy_set_header Proxy-host $proxy_host;
90 102 client_max_body_size 400m;
91 103 client_body_buffer_size 128k;
92 104 proxy_buffering off;
93 105 proxy_connect_timeout 3600;
94 106 proxy_send_timeout 3600;
95 107 proxy_read_timeout 3600;
96 108 proxy_buffer_size 8k;
97 109 proxy_buffers 8 32k;
98 110 proxy_busy_buffers_size 64k;
99 111 proxy_temp_file_write_size 64k;
100 112
101 113 Also when using root path with nginx You might set the static files to false
102 114 in production.ini file::
103 115
104 116 [app:main]
105 117 use = egg:rhodecode
106 118 full_stack = true
107 119 static_files = false
108 120 lang=en
109 121 cache_dir = %(here)s/data
110 122
111 123 To not have the statics served by the application. And improve speed.
112 124
113 125
114 126 Other configuration files
115 127 -------------------------
116 128
117 129 Some extra configuration files and examples can be found here:
118 130 http://hg.python-works.com/rhodecode/files/tip/init.d
119 131
120 132 and also an celeryconfig file can be use from here:
121 133 http://hg.python-works.com/rhodecode/files/tip/celeryconfig.py
122 134
123 135
124 136
125 137 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
126 138 .. _python: http://www.python.org/
127 139 .. _mercurial: http://mercurial.selenic.com/
128 140 .. _celery: http://celeryproject.org/
129 141 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
@@ -1,35 +1,35 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # RhodeCode, a web based repository management based on pylons
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on April 9, 2010
22 22 RhodeCode, a web based repository management based on pylons
23 23 versioning implementation: http://semver.org/
24 24 @author: marcink
25 25 """
26 26
27 VERSION = (1, 0, 0,)
27 VERSION = (1, 0, 1,)
28 28
29 29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
30 30
31 31 def get_version():
32 32 """
33 33 Returns shorter version (digit parts only) as string.
34 34 """
35 35 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,383 +1,383 b''
1 1 """Helper functions
2 2
3 3 Consists of functions to typically be used within templates, but also
4 4 available to Controllers. This module is available to both as 'h'.
5 5 """
6 6 from pygments.formatters import HtmlFormatter
7 7 from pygments import highlight as code_highlight
8 8 from pylons import url, app_globals as g
9 9 from pylons.i18n.translation import _, ungettext
10 10 from vcs.utils.annotate import annotate_highlight
11 11 from webhelpers.html import literal, HTML, escape
12 12 from webhelpers.html.tools import *
13 13 from webhelpers.html.builder import make_tag
14 14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
15 15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
16 16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
17 17 password, textarea, title, ul, xml_declaration, radio
18 18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
19 19 mail_to, strip_links, strip_tags, tag_re
20 20 from webhelpers.number import format_byte_size, format_bit_size
21 21 from webhelpers.pylonslib import Flash as _Flash
22 22 from webhelpers.pylonslib.secure_form import secure_form
23 23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
24 24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
25 25 replace_whitespace, urlify, truncate, wrap_paragraphs
26 26
27 27 #Custom helpers here :)
28 28 class _Link(object):
29 29 '''
30 30 Make a url based on label and url with help of url_for
31 31 :param label:name of link if not defined url is used
32 32 :param url: the url for link
33 33 '''
34 34
35 35 def __call__(self, label='', *url_, **urlargs):
36 36 if label is None or '':
37 37 label = url
38 38 link_fn = link_to(label, url(*url_, **urlargs))
39 39 return link_fn
40 40
41 41 link = _Link()
42 42
43 43 class _GetError(object):
44 44
45 45 def __call__(self, field_name, form_errors):
46 46 tmpl = """<span class="error_msg">%s</span>"""
47 47 if form_errors and form_errors.has_key(field_name):
48 48 return literal(tmpl % form_errors.get(field_name))
49 49
50 50 get_error = _GetError()
51 51
52 52 def recursive_replace(str, replace=' '):
53 53 """
54 54 Recursive replace of given sign to just one instance
55 55 :param str: given string
56 56 :param replace:char to find and replace multiple instances
57 57
58 58 Examples::
59 59 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
60 60 'Mighty-Mighty-Bo-sstones'
61 61 """
62 62
63 63 if str.find(replace * 2) == -1:
64 64 return str
65 65 else:
66 66 str = str.replace(replace * 2, replace)
67 return recursive_replace(str, replace)
67 return recursive_replace(str, replace)
68 68
69 69 class _ToolTip(object):
70
70
71 71 def __call__(self, tooltip_title, trim_at=50):
72 72 """
73 73 Special function just to wrap our text into nice formatted autowrapped
74 74 text
75 75 :param tooltip_title:
76 76 """
77
77
78 78 return wrap_paragraphs(escape(tooltip_title), trim_at)\
79 79 .replace('\n', '<br/>')
80
80
81 81 def activate(self):
82 82 """
83 83 Adds tooltip mechanism to the given Html all tooltips have to have
84 84 set class tooltip and set attribute tooltip_title.
85 85 Then a tooltip will be generated based on that
86 86 All with yui js tooltip
87 87 """
88
88
89 89 js = '''
90 90 YAHOO.util.Event.onDOMReady(function(){
91 91 function toolTipsId(){
92 92 var ids = [];
93 93 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
94 94
95 95 for (var i = 0; i < tts.length; i++) {
96 96 //if element doesn not have and id autgenerate one for tooltip
97 97
98 98 if (!tts[i].id){
99 99 tts[i].id='tt'+i*100;
100 100 }
101 101 ids.push(tts[i].id);
102 102 }
103 103 return ids
104 104 };
105 105 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
106 106 context: toolTipsId(),
107 107 monitorresize:false,
108 108 xyoffset :[0,0],
109 109 autodismissdelay:300000,
110 110 hidedelay:5,
111 111 showdelay:20,
112 112 });
113 113
114 114 //Mouse Over event disabled for new repositories since they dont
115 115 //have last commit message
116 116 myToolTips.contextMouseOverEvent.subscribe(
117 117 function(type, args) {
118 118 var context = args[0];
119 119 var txt = context.getAttribute('tooltip_title');
120 120 if(txt){
121 121 return true;
122 122 }
123 123 else{
124 124 return false;
125 125 }
126 126 });
127 127
128 128
129 129 // Set the text for the tooltip just before we display it. Lazy method
130 130 myToolTips.contextTriggerEvent.subscribe(
131 131 function(type, args) {
132 132
133 133
134 134 var context = args[0];
135 135
136 136 var txt = context.getAttribute('tooltip_title');
137 137 this.cfg.setProperty("text", txt);
138 138
139 139
140 140 // positioning of tooltip
141 141 var tt_w = this.element.clientWidth;
142 142 var tt_h = this.element.clientHeight;
143 143
144 144 var context_w = context.offsetWidth;
145 145 var context_h = context.offsetHeight;
146 146
147 147 var pos_x = YAHOO.util.Dom.getX(context);
148 148 var pos_y = YAHOO.util.Dom.getY(context);
149 149
150 150 var display_strategy = 'top';
151 151 var xy_pos = [0,0];
152 152 switch (display_strategy){
153 153
154 154 case 'top':
155 155 var cur_x = (pos_x+context_w/2)-(tt_w/2);
156 156 var cur_y = pos_y-tt_h-4;
157 157 xy_pos = [cur_x,cur_y];
158 158 break;
159 159 case 'bottom':
160 160 var cur_x = (pos_x+context_w/2)-(tt_w/2);
161 161 var cur_y = pos_y+context_h+4;
162 162 xy_pos = [cur_x,cur_y];
163 163 break;
164 164 case 'left':
165 165 var cur_x = (pos_x-tt_w-4);
166 166 var cur_y = pos_y-((tt_h/2)-context_h/2);
167 167 xy_pos = [cur_x,cur_y];
168 168 break;
169 169 case 'right':
170 170 var cur_x = (pos_x+context_w+4);
171 171 var cur_y = pos_y-((tt_h/2)-context_h/2);
172 172 xy_pos = [cur_x,cur_y];
173 173 break;
174 174 default:
175 175 var cur_x = (pos_x+context_w/2)-(tt_w/2);
176 176 var cur_y = pos_y-tt_h-4;
177 177 xy_pos = [cur_x,cur_y];
178 178 break;
179 179
180 180 }
181 181
182 182 this.cfg.setProperty("xy",xy_pos);
183 183
184 184 });
185 185
186 186 //Mouse out
187 187 myToolTips.contextMouseOutEvent.subscribe(
188 188 function(type, args) {
189 189 var context = args[0];
190 190
191 191 });
192 192 });
193 '''
193 '''
194 194 return literal(js)
195 195
196 196 tooltip = _ToolTip()
197 197
198 198 class _FilesBreadCrumbs(object):
199
199
200 200 def __call__(self, repo_name, rev, paths):
201 201 url_l = [link_to(repo_name, url('files_home',
202 202 repo_name=repo_name,
203 203 revision=rev, f_path=''))]
204 204 paths_l = paths.split('/')
205
206 for cnt, p in enumerate(paths_l, 1):
205
206 for cnt, p in enumerate(paths_l):
207 207 if p != '':
208 208 url_l.append(link_to(p, url('files_home',
209 209 repo_name=repo_name,
210 210 revision=rev,
211 f_path='/'.join(paths_l[:cnt]))))
211 f_path='/'.join(paths_l[:cnt + 1]))))
212 212
213 213 return literal('/'.join(url_l))
214 214
215 215 files_breadcrumbs = _FilesBreadCrumbs()
216 216 class CodeHtmlFormatter(HtmlFormatter):
217 217
218 218 def wrap(self, source, outfile):
219 219 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
220 220
221 221 def _wrap_code(self, source):
222 for cnt, it in enumerate(source, 1):
222 for cnt, it in enumerate(source):
223 223 i, t = it
224 t = '<div id="#S-%s">%s</div>' % (cnt, t)
224 t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
225 225 yield i, t
226 226 def pygmentize(filenode, **kwargs):
227 227 """
228 228 pygmentize function using pygments
229 229 :param filenode:
230 230 """
231 231 return literal(code_highlight(filenode.content,
232 232 filenode.lexer, CodeHtmlFormatter(**kwargs)))
233 233
234 234 def pygmentize_annotation(filenode, **kwargs):
235 235 """
236 236 pygmentize function for annotation
237 237 :param filenode:
238 238 """
239
239
240 240 color_dict = {}
241 241 def gen_color():
242 242 """generator for getting 10k of evenly distibuted colors using hsv color
243 243 and golden ratio.
244 """
244 """
245 245 import colorsys
246 246 n = 10000
247 247 golden_ratio = 0.618033988749895
248 248 h = 0.22717784590367374
249 249 #generate 10k nice web friendly colors in the same order
250 250 for c in xrange(n):
251 251 h += golden_ratio
252 252 h %= 1
253 253 HSV_tuple = [h, 0.95, 0.95]
254 254 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
255 yield map(lambda x:str(int(x * 256)), RGB_tuple)
255 yield map(lambda x:str(int(x * 256)), RGB_tuple)
256 256
257 257 cgenerator = gen_color()
258
258
259 259 def get_color_string(cs):
260 260 if color_dict.has_key(cs):
261 261 col = color_dict[cs]
262 262 else:
263 263 col = color_dict[cs] = cgenerator.next()
264 264 return "color: rgb(%s)! important;" % (', '.join(col))
265
265
266 266 def url_func(changeset):
267 267 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
268 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
269
268 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
269
270 270 tooltip_html = tooltip_html % (changeset.author,
271 271 changeset.date,
272 272 tooltip(changeset.message))
273 273 lnk_format = 'r%-5s:%s' % (changeset.revision,
274 274 changeset.short_id)
275 275 uri = link_to(
276 276 lnk_format,
277 277 url('changeset_home', repo_name=changeset.repository.name,
278 278 revision=changeset.short_id),
279 279 style=get_color_string(changeset.short_id),
280 280 class_='tooltip',
281 281 tooltip_title=tooltip_html
282 282 )
283
283
284 284 uri += '\n'
285 return uri
285 return uri
286 286 return literal(annotate_highlight(filenode, url_func, **kwargs))
287
287
288 288 def repo_name_slug(value):
289 289 """Return slug of name of repository
290 290 This function is called on each creation/modification
291 291 of repository to prevent bad names in repo
292 292 """
293 293 slug = remove_formatting(value)
294 294 slug = strip_tags(slug)
295
295
296 296 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
297 297 slug = slug.replace(c, '-')
298 298 slug = recursive_replace(slug, '-')
299 299 slug = collapse(slug, '-')
300 300 return slug
301 301
302 302 def get_changeset_safe(repo, rev):
303 303 from vcs.backends.base import BaseRepository
304 304 from vcs.exceptions import RepositoryError
305 305 if not isinstance(repo, BaseRepository):
306 306 raise Exception('You must pass an Repository '
307 307 'object as first argument got %s', type(repo))
308
308
309 309 try:
310 310 cs = repo.get_changeset(rev)
311 311 except RepositoryError:
312 312 from rhodecode.lib.utils import EmptyChangeset
313 313 cs = EmptyChangeset()
314 314 return cs
315 315
316 316
317 317 flash = _Flash()
318 318
319 319
320 320 #===============================================================================
321 321 # MERCURIAL FILTERS available via h.
322 322 #===============================================================================
323 323 from mercurial import util
324 324 from mercurial.templatefilters import age as _age, person as _person
325 325
326 326 age = lambda x:_age(x)
327 327 capitalize = lambda x: x.capitalize()
328 328 date = lambda x: util.datestr(x)
329 329 email = util.email
330 330 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
331 331 person = lambda x: _person(x)
332 332 hgdate = lambda x: "%d %d" % x
333 333 isodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2')
334 334 isodatesec = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2')
335 335 localdate = lambda x: (x[0], util.makedate()[1])
336 336 rfc822date = lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2")
337 337 rfc822date_notz = lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S")
338 338 rfc3339date = lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2")
339 339 time_ago = lambda x: util.datestr(_age(x), "%a, %d %b %Y %H:%M:%S %1%2")
340 340
341 341
342 342 #===============================================================================
343 343 # PERMS
344 344 #===============================================================================
345 345 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
346 346 HasRepoPermissionAny, HasRepoPermissionAll
347 347
348 348 #===============================================================================
349 349 # GRAVATAR URL
350 350 #===============================================================================
351 351 import hashlib
352 352 import urllib
353 353 from pylons import request
354 354
355 355 def gravatar_url(email_address, size=30):
356 356 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
357 357 default = 'identicon'
358 358 baseurl_nossl = "http://www.gravatar.com/avatar/"
359 359 baseurl_ssl = "https://secure.gravatar.com/avatar/"
360 360 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
361
362
361
362
363 363 # construct the url
364 364 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
365 365 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
366 366
367 367 return gravatar_url
368 368
369 369 def safe_unicode(str):
370 370 """safe unicode function. In case of UnicodeDecode error we try to return
371 371 unicode with errors replace, if this failes we return unicode with
372 372 string_escape decoding """
373
373
374 374 try:
375 375 u_str = unicode(str)
376 376 except UnicodeDecodeError:
377 377 try:
378 378 u_str = unicode(str, 'utf-8', 'replace')
379 379 except UnicodeDecodeError:
380 380 #incase we have a decode error just represent as byte string
381 381 u_str = unicode(str(str).encode('string_escape'))
382
382
383 383 return u_str
@@ -1,507 +1,512 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # Utilities for RhodeCode
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 # This program is free software; you can redistribute it and/or
6 6 # modify it under the terms of the GNU General Public License
7 7 # as published by the Free Software Foundation; version 2
8 8 # of the License or (at your opinion) any later version of the license.
9 9 #
10 10 # This program is distributed in the hope that it will be useful,
11 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 # GNU General Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License
16 16 # along with this program; if not, write to the Free Software
17 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 18 # MA 02110-1301, USA.
19 19
20 20 """
21 21 Created on April 18, 2010
22 22 Utilities for RhodeCode
23 23 @author: marcink
24 24 """
25 25 from beaker.cache import cache_region
26 26 from mercurial import ui, config, hg
27 27 from mercurial.error import RepoError
28 28 from rhodecode.model import meta
29 29 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
30 30 from vcs.backends.base import BaseChangeset
31 31 from vcs.utils.lazy import LazyProperty
32 32 import logging
33 33 import datetime
34 34 import os
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 def get_repo_slug(request):
40 40 return request.environ['pylons.routes_dict'].get('repo_name')
41 41
42 42 def is_mercurial(environ):
43 43 """
44 44 Returns True if request's target is mercurial server - header
45 45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
46 46 """
47 47 http_accept = environ.get('HTTP_ACCEPT')
48 48 if http_accept and http_accept.startswith('application/mercurial'):
49 49 return True
50 50 return False
51 51
52 52 def is_git(environ):
53 53 """
54 54 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
55 55 then have git client version given.
56 56
57 57 :param environ:
58 58 """
59 59 http_user_agent = environ.get('HTTP_USER_AGENT')
60 60 if http_user_agent.startswith('git'):
61 61 return True
62 62 return False
63 63
64 64 def action_logger(user, action, repo, ipaddr, sa=None):
65 65 """
66 66 Action logger for various action made by users
67 67 """
68 68
69 69 if not sa:
70 70 sa = meta.Session
71 71
72 72 try:
73 73 if hasattr(user, 'user_id'):
74 74 user_id = user.user_id
75 75 elif isinstance(user, basestring):
76 76 user_id = sa.query(User).filter(User.username == user).one()
77 77 else:
78 78 raise Exception('You have to provide user object or username')
79 79
80 80 repo_name = repo.lstrip('/')
81 81 user_log = UserLog()
82 82 user_log.user_id = user_id
83 83 user_log.action = action
84 84 user_log.repository_name = repo_name
85 85 user_log.repository = sa.query(Repository)\
86 86 .filter(Repository.repo_name == repo_name).one()
87 87 user_log.action_date = datetime.datetime.now()
88 88 user_log.user_ip = ipaddr
89 89 sa.add(user_log)
90 90 sa.commit()
91 91
92 92 log.info('Adding user %s, action %s on %s',
93 93 user.username, action, repo)
94 94 except Exception, e:
95 95 sa.rollback()
96 96 log.error('could not log user action:%s', str(e))
97 97
98 98 def check_repo_dir(paths):
99 99 repos_path = paths[0][1].split('/')
100 100 if repos_path[-1] in ['*', '**']:
101 101 repos_path = repos_path[:-1]
102 102 if repos_path[0] != '/':
103 103 repos_path[0] = '/'
104 104 if not os.path.isdir(os.path.join(*repos_path)):
105 105 raise Exception('Not a valid repository in %s' % paths[0][1])
106 106
107 107 def check_repo_fast(repo_name, base_path):
108 108 if os.path.isdir(os.path.join(base_path, repo_name)):return False
109 109 return True
110 110
111 111 def check_repo(repo_name, base_path, verify=True):
112 112
113 113 repo_path = os.path.join(base_path, repo_name)
114 114
115 115 try:
116 116 if not check_repo_fast(repo_name, base_path):
117 117 return False
118 118 r = hg.repository(ui.ui(), repo_path)
119 119 if verify:
120 120 hg.verify(r)
121 121 #here we hnow that repo exists it was verified
122 122 log.info('%s repo is already created', repo_name)
123 123 return False
124 124 except RepoError:
125 125 #it means that there is no valid repo there...
126 126 log.info('%s repo is free for creation', repo_name)
127 127 return True
128 128
129 129 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
130 130 while True:
131 131 ok = raw_input(prompt)
132 132 if ok in ('y', 'ye', 'yes'): return True
133 133 if ok in ('n', 'no', 'nop', 'nope'): return False
134 134 retries = retries - 1
135 135 if retries < 0: raise IOError
136 136 print complaint
137 137
138 138 @cache_region('super_short_term', 'cached_hg_ui')
139 139 def get_hg_ui_cached():
140 140 try:
141 141 sa = meta.Session
142 142 ret = sa.query(RhodeCodeUi).all()
143 143 finally:
144 144 meta.Session.remove()
145 145 return ret
146 146
147 147
148 148 def get_hg_settings():
149 149 try:
150 150 sa = meta.Session
151 151 ret = sa.query(RhodeCodeSettings).all()
152 152 finally:
153 153 meta.Session.remove()
154 154
155 155 if not ret:
156 156 raise Exception('Could not get application settings !')
157 157 settings = {}
158 158 for each in ret:
159 159 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
160 160
161 161 return settings
162 162
163 163 def get_hg_ui_settings():
164 164 try:
165 165 sa = meta.Session
166 166 ret = sa.query(RhodeCodeUi).all()
167 167 finally:
168 168 meta.Session.remove()
169 169
170 170 if not ret:
171 171 raise Exception('Could not get application ui settings !')
172 172 settings = {}
173 173 for each in ret:
174 174 k = each.ui_key
175 175 v = each.ui_value
176 176 if k == '/':
177 177 k = 'root_path'
178 178
179 179 if k.find('.') != -1:
180 180 k = k.replace('.', '_')
181 181
182 182 if each.ui_section == 'hooks':
183 183 v = each.ui_active
184 184
185 185 settings[each.ui_section + '_' + k] = v
186 186
187 187 return settings
188 188
189 189 #propagated from mercurial documentation
190 190 ui_sections = ['alias', 'auth',
191 191 'decode/encode', 'defaults',
192 192 'diff', 'email',
193 193 'extensions', 'format',
194 194 'merge-patterns', 'merge-tools',
195 195 'hooks', 'http_proxy',
196 196 'smtp', 'patch',
197 197 'paths', 'profiling',
198 198 'server', 'trusted',
199 199 'ui', 'web', ]
200 200
201 201 def make_ui(read_from='file', path=None, checkpaths=True):
202 202 """
203 203 A function that will read python rc files or database
204 204 and make an mercurial ui object from read options
205 205
206 206 :param path: path to mercurial config file
207 207 :param checkpaths: check the path
208 208 :param read_from: read from 'file' or 'db'
209 209 """
210 210
211 211 baseui = ui.ui()
212 212
213 213 if read_from == 'file':
214 214 if not os.path.isfile(path):
215 215 log.warning('Unable to read config file %s' % path)
216 216 return False
217 217 log.debug('reading hgrc from %s', path)
218 218 cfg = config.config()
219 219 cfg.read(path)
220 220 for section in ui_sections:
221 221 for k, v in cfg.items(section):
222 222 baseui.setconfig(section, k, v)
223 223 log.debug('settings ui from file[%s]%s:%s', section, k, v)
224
225 for k, v in baseui.configitems('extensions'):
226 baseui.setconfig('extensions', k, '0')
227 #just enable mq
228 baseui.setconfig('extensions', 'mq', '1')
224 229 if checkpaths:check_repo_dir(cfg.items('paths'))
225 230
226 231
227 232 elif read_from == 'db':
228 233 hg_ui = get_hg_ui_cached()
229 234 for ui_ in hg_ui:
230 235 if ui_.ui_active:
231 236 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
232 237 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
233 238
234 239
235 240 return baseui
236 241
237 242
238 243 def set_rhodecode_config(config):
239 244 hgsettings = get_hg_settings()
240 245
241 246 for k, v in hgsettings.items():
242 247 config[k] = v
243 248
244 249 def invalidate_cache(name, *args):
245 250 """Invalidates given name cache"""
246 251
247 252 from beaker.cache import region_invalidate
248 253 log.info('INVALIDATING CACHE FOR %s', name)
249 254
250 255 """propagate our arguments to make sure invalidation works. First
251 256 argument has to be the name of cached func name give to cache decorator
252 257 without that the invalidation would not work"""
253 258 tmp = [name]
254 259 tmp.extend(args)
255 260 args = tuple(tmp)
256 261
257 262 if name == 'cached_repo_list':
258 263 from rhodecode.model.hg_model import _get_repos_cached
259 264 region_invalidate(_get_repos_cached, None, *args)
260 265
261 266 if name == 'full_changelog':
262 267 from rhodecode.model.hg_model import _full_changelog_cached
263 268 region_invalidate(_full_changelog_cached, None, *args)
264 269
265 270 class EmptyChangeset(BaseChangeset):
266 271 """
267 272 An dummy empty changeset.
268 273 """
269 274
270 275 revision = -1
271 276 message = ''
272 277 author = ''
273 278 date = ''
274 279 @LazyProperty
275 280 def raw_id(self):
276 281 """
277 282 Returns raw string identifing this changeset, useful for web
278 283 representation.
279 284 """
280 285 return '0' * 40
281 286
282 287 @LazyProperty
283 288 def short_id(self):
284 289 return self.raw_id[:12]
285 290
286 291 def get_file_changeset(self, path):
287 292 return self
288 293
289 294 def get_file_content(self, path):
290 295 return u''
291 296
292 297 def get_file_size(self, path):
293 298 return 0
294 299
295 300 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
296 301 """
297 302 maps all found repositories into db
298 303 """
299 304 from rhodecode.model.repo_model import RepoModel
300 305
301 306 sa = meta.Session
302 307 user = sa.query(User).filter(User.admin == True).first()
303 308
304 309 rm = RepoModel()
305 310
306 311 for name, repo in initial_repo_list.items():
307 312 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
308 313 log.info('repository %s not found creating default', name)
309 314
310 315 form_data = {
311 316 'repo_name':name,
312 317 'description':repo.description if repo.description != 'unknown' else \
313 318 'auto description for %s' % name,
314 319 'private':False
315 320 }
316 321 rm.create(form_data, user, just_db=True)
317 322
318 323
319 324 if remove_obsolete:
320 325 #remove from database those repositories that are not in the filesystem
321 326 for repo in sa.query(Repository).all():
322 327 if repo.repo_name not in initial_repo_list.keys():
323 328 sa.delete(repo)
324 329 sa.commit()
325 330
326 331
327 332 meta.Session.remove()
328 333
329 334 from UserDict import DictMixin
330 335
331 336 class OrderedDict(dict, DictMixin):
332 337
333 338 def __init__(self, *args, **kwds):
334 339 if len(args) > 1:
335 340 raise TypeError('expected at most 1 arguments, got %d' % len(args))
336 341 try:
337 342 self.__end
338 343 except AttributeError:
339 344 self.clear()
340 345 self.update(*args, **kwds)
341 346
342 347 def clear(self):
343 348 self.__end = end = []
344 349 end += [None, end, end] # sentinel node for doubly linked list
345 350 self.__map = {} # key --> [key, prev, next]
346 351 dict.clear(self)
347 352
348 353 def __setitem__(self, key, value):
349 354 if key not in self:
350 355 end = self.__end
351 356 curr = end[1]
352 357 curr[2] = end[1] = self.__map[key] = [key, curr, end]
353 358 dict.__setitem__(self, key, value)
354 359
355 360 def __delitem__(self, key):
356 361 dict.__delitem__(self, key)
357 362 key, prev, next = self.__map.pop(key)
358 363 prev[2] = next
359 364 next[1] = prev
360 365
361 366 def __iter__(self):
362 367 end = self.__end
363 368 curr = end[2]
364 369 while curr is not end:
365 370 yield curr[0]
366 371 curr = curr[2]
367 372
368 373 def __reversed__(self):
369 374 end = self.__end
370 375 curr = end[1]
371 376 while curr is not end:
372 377 yield curr[0]
373 378 curr = curr[1]
374 379
375 380 def popitem(self, last=True):
376 381 if not self:
377 382 raise KeyError('dictionary is empty')
378 383 if last:
379 384 key = reversed(self).next()
380 385 else:
381 386 key = iter(self).next()
382 387 value = self.pop(key)
383 388 return key, value
384 389
385 390 def __reduce__(self):
386 391 items = [[k, self[k]] for k in self]
387 392 tmp = self.__map, self.__end
388 393 del self.__map, self.__end
389 394 inst_dict = vars(self).copy()
390 395 self.__map, self.__end = tmp
391 396 if inst_dict:
392 397 return (self.__class__, (items,), inst_dict)
393 398 return self.__class__, (items,)
394 399
395 400 def keys(self):
396 401 return list(self)
397 402
398 403 setdefault = DictMixin.setdefault
399 404 update = DictMixin.update
400 405 pop = DictMixin.pop
401 406 values = DictMixin.values
402 407 items = DictMixin.items
403 408 iterkeys = DictMixin.iterkeys
404 409 itervalues = DictMixin.itervalues
405 410 iteritems = DictMixin.iteritems
406 411
407 412 def __repr__(self):
408 413 if not self:
409 414 return '%s()' % (self.__class__.__name__,)
410 415 return '%s(%r)' % (self.__class__.__name__, self.items())
411 416
412 417 def copy(self):
413 418 return self.__class__(self)
414 419
415 420 @classmethod
416 421 def fromkeys(cls, iterable, value=None):
417 422 d = cls()
418 423 for key in iterable:
419 424 d[key] = value
420 425 return d
421 426
422 427 def __eq__(self, other):
423 428 if isinstance(other, OrderedDict):
424 429 return len(self) == len(other) and self.items() == other.items()
425 430 return dict.__eq__(self, other)
426 431
427 432 def __ne__(self, other):
428 433 return not self == other
429 434
430 435
431 436 #===============================================================================
432 437 # TEST FUNCTIONS
433 438 #===============================================================================
434 439 def create_test_index(repo_location, full_index):
435 440 """Makes default test index
436 441 :param repo_location:
437 442 :param full_index:
438 443 """
439 444 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
440 445 from rhodecode.lib.pidlock import DaemonLock, LockHeld
441 446 from rhodecode.lib.indexers import IDX_LOCATION
442 447 import shutil
443 448
444 449 if os.path.exists(IDX_LOCATION):
445 450 shutil.rmtree(IDX_LOCATION)
446 451
447 452 try:
448 453 l = DaemonLock()
449 454 WhooshIndexingDaemon(repo_location=repo_location)\
450 455 .run(full_index=full_index)
451 456 l.release()
452 457 except LockHeld:
453 458 pass
454 459
455 460 def create_test_env(repos_test_path, config):
456 461 """Makes a fresh database and
457 462 install test repository into tmp dir
458 463 """
459 464 from rhodecode.lib.db_manage import DbManage
460 465 import tarfile
461 466 import shutil
462 467 from os.path import dirname as dn, join as jn, abspath
463 468 from rhodecode.tests import REPO_PATH, NEW_REPO_PATH
464 469
465 470 log = logging.getLogger('TestEnvCreator')
466 471 # create logger
467 472 log.setLevel(logging.DEBUG)
468 473 log.propagate = True
469 474 # create console handler and set level to debug
470 475 ch = logging.StreamHandler()
471 476 ch.setLevel(logging.DEBUG)
472 477
473 478 # create formatter
474 479 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
475 480
476 481 # add formatter to ch
477 482 ch.setFormatter(formatter)
478 483
479 484 # add ch to logger
480 485 log.addHandler(ch)
481 486
482 487 #PART ONE create db
483 488 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
484 489 log.debug('making test db %s', dbname)
485 490
486 491 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
487 492 tests=True)
488 493 dbmanage.create_tables(override=True)
489 494 dbmanage.config_prompt(repos_test_path)
490 495 dbmanage.create_default_user()
491 496 dbmanage.admin_prompt()
492 497 dbmanage.create_permissions()
493 498 dbmanage.populate_default_permissions()
494 499
495 500 #PART TWO make test repo
496 501 log.debug('making test vcs repo')
497 502 if os.path.isdir(REPO_PATH):
498 503 log.debug('REMOVING %s', REPO_PATH)
499 504 shutil.rmtree(REPO_PATH)
500 505 if os.path.isdir(NEW_REPO_PATH):
501 506 log.debug('REMOVING %s', NEW_REPO_PATH)
502 507 shutil.rmtree(NEW_REPO_PATH)
503 508
504 509 cur_dir = dn(dn(abspath(__file__)))
505 510 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
506 511 tar.extractall('/tmp')
507 512 tar.close()
@@ -1,139 +1,141 b''
1 1 from rhodecode.model.meta import Base
2 2 from sqlalchemy import *
3 3 from sqlalchemy.orm import relation, backref
4 4 from sqlalchemy.orm.session import Session
5 5 from vcs.utils.lazy import LazyProperty
6 6 import logging
7 7
8 8 log = logging.getLogger(__name__)
9 9
10 10 class RhodeCodeSettings(Base):
11 11 __tablename__ = 'rhodecode_settings'
12 12 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
13 13 app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
14 14 app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 15 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
16 16
17 17 class RhodeCodeUi(Base):
18 18 __tablename__ = 'rhodecode_ui'
19 19 __table_args__ = {'useexisting':True}
20 20 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
21 21 ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
22 22 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
23 23 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
24 24 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
25
26
27 class User(Base):
25
26
27 class User(Base):
28 28 __tablename__ = 'users'
29 29 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
30 30 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
31 31 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
32 32 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
33 33 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
34 34 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
35 35 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
36 36 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
37 37 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
38 38 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
39
39
40 40 user_log = relation('UserLog')
41 41 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
42
42
43 43 @LazyProperty
44 44 def full_contact(self):
45 45 return '%s %s <%s>' % (self.name, self.lastname, self.email)
46
46
47 47 def __repr__(self):
48 48 return "<User('id:%s:%s')>" % (self.user_id, self.username)
49
49
50 50 def update_lastlogin(self):
51 51 """Update user lastlogin"""
52 52 import datetime
53
53
54 54 try:
55 55 session = Session.object_session(self)
56 56 self.last_login = datetime.datetime.now()
57 57 session.add(self)
58 58 session.commit()
59 59 log.debug('updated user %s lastlogin', self.username)
60 60 except Exception:
61 session.rollback()
62
63
64 class UserLog(Base):
61 session.rollback()
62
63
64 class UserLog(Base):
65 65 __tablename__ = 'user_logs'
66 66 __table_args__ = {'useexisting':True}
67 67 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
68 68 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
69 69 repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
70 70 repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
72 72 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
73 73 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
74 74 revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
75
75
76 76 user = relation('User')
77 77 repository = relation('Repository')
78
78
79 79 class Repository(Base):
80 80 __tablename__ = 'repositories'
81 81 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
82 82 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
83 83 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
84 84 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
85 85 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
86 86 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
87 87 fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
88
88
89 89 user = relation('User')
90 90 fork = relation('Repository', remote_side=repo_id)
91 91 repo_to_perm = relation('RepoToPerm', cascade='all')
92
92 stats = relation('Statistics', cascade='all')
93
94
93 95 def __repr__(self):
94 96 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
95
97
96 98 class Permission(Base):
97 99 __tablename__ = 'permissions'
98 100 __table_args__ = {'useexisting':True}
99 101 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
100 102 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 103 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102
104
103 105 def __repr__(self):
104 106 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
105 107
106 108 class RepoToPerm(Base):
107 109 __tablename__ = 'repo_to_perm'
108 110 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
109 111 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
110 112 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
111 113 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
112 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
113
114 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
115
114 116 user = relation('User')
115 117 permission = relation('Permission')
116 118 repository = relation('Repository')
117 119
118 120 class UserToPerm(Base):
119 121 __tablename__ = 'user_to_perm'
120 122 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
121 123 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
122 124 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
123 125 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
124
126
125 127 user = relation('User')
126 128 permission = relation('Permission')
127 129
128 130 class Statistics(Base):
129 131 __tablename__ = 'statistics'
130 132 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
131 133 stat_id = Column("stat_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
132 134 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
133 135 stat_on_revision = Column("stat_on_revision", INTEGER(), nullable=False)
134 136 commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data
135 137 commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data
136 138 languages = Column("languages", BLOB(), nullable=False)#JSON data
137
138 repository = relation('Repository')
139 139
140 repository = relation('Repository', single_parent=True)
141
@@ -1,2312 +1,2313 b''
1 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 2 border:0;
3 3 outline:0;
4 4 font-size:100%;
5 5 vertical-align:baseline;
6 6 background:transparent;
7 7 margin:0;
8 8 padding:0;
9 9 }
10 10
11 11 body {
12 12 line-height:1;
13 13 height:100%;
14 14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 16 font-size:12px;
17 17 color:#000;
18 18 margin:0;
19 19 padding:0;
20 20 }
21 21
22 22 ol,ul {
23 23 list-style:none;
24 24 }
25 25
26 26 blockquote,q {
27 27 quotes:none;
28 28 }
29 29
30 30 blockquote:before,blockquote:after,q:before,q:after {
31 31 content:none;
32 32 }
33 33
34 34 :focus {
35 35 outline:0;
36 36 }
37 37
38 38 del {
39 39 text-decoration:line-through;
40 40 }
41 41
42 42 table {
43 43 border-collapse:collapse;
44 44 border-spacing:0;
45 45 }
46 46
47 47 html {
48 48 height:100%;
49 49 }
50 50
51 51 a {
52 52 color:#003367;
53 53 text-decoration:none;
54 54 cursor:pointer;
55 55 font-weight:700;
56 56 }
57 57
58 58 a:hover {
59 59 color:#316293;
60 60 text-decoration:underline;
61 61 }
62 62
63 63 h1,h2,h3,h4,h5,h6 {
64 64 color:#292929;
65 65 font-weight:700;
66 66 }
67 67
68 68 h1 {
69 69 font-size:22px;
70 70 }
71 71
72 72 h2 {
73 73 font-size:20px;
74 74 }
75 75
76 76 h3 {
77 77 font-size:18px;
78 78 }
79 79
80 80 h4 {
81 81 font-size:16px;
82 82 }
83 83
84 84 h5 {
85 85 font-size:14px;
86 86 }
87 87
88 88 h6 {
89 89 font-size:11px;
90 90 }
91 91
92 92 ul.circle {
93 93 list-style-type:circle;
94 94 }
95 95
96 96 ul.disc {
97 97 list-style-type:disc;
98 98 }
99 99
100 100 ul.square {
101 101 list-style-type:square;
102 102 }
103 103
104 104 ol.lower-roman {
105 105 list-style-type:lower-roman;
106 106 }
107 107
108 108 ol.upper-roman {
109 109 list-style-type:upper-roman;
110 110 }
111 111
112 112 ol.lower-alpha {
113 113 list-style-type:lower-alpha;
114 114 }
115 115
116 116 ol.upper-alpha {
117 117 list-style-type:upper-alpha;
118 118 }
119 119
120 120 ol.decimal {
121 121 list-style-type:decimal;
122 122 }
123 123
124 124 div.color {
125 125 clear:both;
126 126 overflow:hidden;
127 127 position:absolute;
128 128 background:#FFF;
129 129 margin:7px 0 0 60px;
130 130 padding:1px 1px 1px 0;
131 131 }
132 132
133 133 div.color a {
134 134 width:15px;
135 135 height:15px;
136 136 display:block;
137 137 float:left;
138 138 margin:0 0 0 1px;
139 139 padding:0;
140 140 }
141 141
142 142 div.options {
143 143 clear:both;
144 144 overflow:hidden;
145 145 position:absolute;
146 146 background:#FFF;
147 147 margin:7px 0 0 162px;
148 148 padding:0;
149 149 }
150 150
151 151 div.options a {
152 152 height:1%;
153 153 display:block;
154 154 text-decoration:none;
155 155 margin:0;
156 156 padding:3px 8px;
157 157 }
158 158
159 159 .top-left-rounded-corner {
160 160 -webkit-border-top-left-radius: 8px;
161 161 -khtml-border-radius-topleft: 8px;
162 162 -moz-border-radius-topleft: 8px;
163 163 border-top-left-radius: 8px;
164 164 }
165 165
166 166 .top-right-rounded-corner {
167 167 -webkit-border-top-right-radius: 8px;
168 168 -khtml-border-radius-topright: 8px;
169 169 -moz-border-radius-topright: 8px;
170 170 border-top-right-radius: 8px;
171 171 }
172 172
173 173 .bottom-left-rounded-corner {
174 174 -webkit-border-bottom-left-radius: 8px;
175 175 -khtml-border-radius-bottomleft: 8px;
176 176 -moz-border-radius-bottomleft: 8px;
177 177 border-bottom-left-radius: 8px;
178 178 }
179 179
180 180 .bottom-right-rounded-corner {
181 181 -webkit-border-bottom-right-radius: 8px;
182 182 -khtml-border-radius-bottomright: 8px;
183 183 -moz-border-radius-bottomright: 8px;
184 184 border-bottom-right-radius: 8px;
185 185 }
186 186
187 187
188 188 #header {
189 189 margin:0;
190 190 padding:0 30px;
191 191 }
192 192
193 193 #header ul#logged-user li {
194 194 list-style:none;
195 195 float:left;
196 196 border-left:1px solid #bbb;
197 197 border-right:1px solid #a5a5a5;
198 198 margin:-2px 0 0;
199 199 padding:10px 12px;
200 200 }
201 201
202 202 #header ul#logged-user li.first {
203 203 border-left:none;
204 204 margin:-6px;
205 205 }
206 206
207 207 #header ul#logged-user li.first div.account {
208 208 padding-top:4px;
209 209 float:left;
210 210 }
211 211
212 212 #header ul#logged-user li.last {
213 213 border-right:none;
214 214 }
215 215
216 216 #header ul#logged-user li a {
217 217 color:#4e4e4e;
218 218 font-weight:700;
219 219 text-decoration:none;
220 220 }
221 221
222 222 #header ul#logged-user li a:hover {
223 223 color:#376ea6;
224 224 text-decoration:underline;
225 225 }
226 226
227 227 #header ul#logged-user li.highlight a {
228 228 color:#fff;
229 229 }
230 230
231 231 #header ul#logged-user li.highlight a:hover {
232 232 color:#376ea6;
233 233 }
234 234
235 235 #header #header-inner {
236 236 height:40px;
237 237 clear:both;
238 238 position:relative;
239 239 background:#003367 url("../images/header_inner.png") repeat-x;
240 240 border-bottom:2px solid #fff;
241 241 margin:0;
242 242 padding:0;
243 243 }
244 244
245 245 #header #header-inner #home a {
246 246 height:40px;
247 247 width:46px;
248 248 display:block;
249 249 background:url("../images/button_home.png");
250 250 background-position:0 0;
251 251 margin:0;
252 252 padding:0;
253 253 }
254 254
255 255 #header #header-inner #home a:hover {
256 256 background-position:0 -40px;
257 257 }
258 258
259 259 #header #header-inner #logo h1 {
260 260 color:#FFF;
261 261 font-size:14px;
262 262 text-transform:uppercase;
263 263 margin:13px 0 0 13px;
264 264 padding:0;
265 265 }
266 266
267 267 #header #header-inner #logo a {
268 268 color:#fff;
269 269 text-decoration:none;
270 270 }
271 271
272 272 #header #header-inner #logo a:hover {
273 color:#dabf29;
273 color:#bfe3ff;
274 274 }
275 275
276 276 #header #header-inner #quick,#header #header-inner #quick ul {
277 277 position:relative;
278 278 float:right;
279 279 list-style-type:none;
280 280 list-style-position:outside;
281 281 margin:10px 5px 0 0;
282 282 padding:0;
283 283 }
284 284
285 285 #header #header-inner #quick li {
286 286 position:relative;
287 287 float:left;
288 288 margin:0 5px 0 0;
289 289 padding:0;
290 290 }
291 291
292 292 #header #header-inner #quick li a {
293 293 top:0;
294 294 left:0;
295 295 height:1%;
296 296 display:block;
297 297 clear:both;
298 298 overflow:hidden;
299 299 color:#FFF;
300 300 font-weight:700;
301 301 text-decoration:none;
302 302 background:#369 url("../../images/quick_l.png") no-repeat top left;
303 303 padding:0;
304 304 }
305 305
306 306 #header #header-inner #quick li span {
307 307 top:0;
308 308 right:0;
309 309 height:1%;
310 310 display:block;
311 311 float:left;
312 312 background:url("../../images/quick_r.png") no-repeat top right;
313 313 border-left:1px solid #3f6f9f;
314 314 margin:0;
315 315 padding:10px 12px 8px 10px;
316 316 }
317 317
318 318 #header #header-inner #quick li span.normal {
319 319 border:none;
320 320 padding:10px 12px 8px;
321 321 }
322 322
323 323 #header #header-inner #quick li span.icon {
324 324 top:0;
325 325 left:0;
326 326 border-left:none;
327 327 background:url("../../images/quick_l.png") no-repeat top left;
328 328 border-right:1px solid #2e5c89;
329 329 padding:8px 8px 4px;
330 330 }
331 331
332 332 #header #header-inner #quick li a:hover {
333 333 background:#4e4e4e url("../../images/quick_l_selected.png") no-repeat top left;
334 334 }
335 335
336 336 #header #header-inner #quick li a:hover span {
337 337 border-left:1px solid #545454;
338 338 background:url("../../images/quick_r_selected.png") no-repeat top right;
339 339 }
340 340
341 341 #header #header-inner #quick li a:hover span.icon {
342 342 border-left:none;
343 343 border-right:1px solid #464646;
344 344 background:url("../../images/quick_l_selected.png") no-repeat top left;
345 345 }
346 346
347 347 #header #header-inner #quick ul {
348 348 top:29px;
349 349 right:0;
350 350 min-width:200px;
351 351 display:none;
352 352 position:absolute;
353 353 background:#FFF;
354 354 border:1px solid #666;
355 355 border-top:1px solid #003367;
356 356 z-index:100;
357 357 margin:0;
358 358 padding:0;
359 359 }
360 360
361 361 #header #header-inner #quick ul.repo_switcher {
362 362 max-height:275px;
363 363 overflow-x:hidden;
364 364 overflow-y:auto;
365 365 }
366 366
367 367 #header #header-inner #quick li ul li {
368 368 border-bottom:1px solid #ddd;
369 369 }
370 370
371 371 #header #header-inner #quick li ul li a {
372 372 width:182px;
373 373 height:auto;
374 374 display:block;
375 375 float:left;
376 376 background:#FFF;
377 377 color:#003367;
378 378 font-weight:400;
379 379 margin:0;
380 380 padding:7px 9px;
381 381 }
382 382
383 383 #header #header-inner #quick li ul li a:hover {
384 384 color:#000;
385 385 background:#FFF;
386 386 }
387 387
388 388 #header #header-inner #quick ul ul {
389 389 top:auto;
390 390 }
391 391
392 392 #header #header-inner #quick li ul ul {
393 393 right:200px;
394 394 max-height:275px;
395 395 overflow:auto;
396 396 overflow-x:hidden;
397 397 white-space:nowrap;
398 398 }
399 399
400 400 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
401 401 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
402 402 width:167px;
403 403 margin:0;
404 404 padding:12px 9px 7px 24px;
405 405 }
406 406
407 407 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
408 408 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
409 409 min-width:167px;
410 410 margin:0;
411 411 padding:12px 9px 7px 24px;
412 412 }
413 413
414 414 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
415 415 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
416 416 min-width:167px;
417 417 margin:0;
418 418 padding:12px 9px 7px 24px;
419 419 }
420 420
421 421 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
422 background:url("../images/icons/folder_edit.png") no-repeat scroll 4px 9px #FFF;
422 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
423 423 width:167px;
424 424 margin:0;
425 425 padding:12px 9px 7px 24px;
426 426 }
427 427
428 428 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
429 429 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
430 430 width:167px;
431 431 margin:0;
432 432 padding:12px 9px 7px 24px;
433 433 }
434 434
435 435 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
436 436 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
437 437 width:167px;
438 438 margin:0;
439 439 padding:12px 9px 7px 24px;
440 440 }
441 441
442 442 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
443 443 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
444 444 width:167px;
445 445 margin:0;
446 446 padding:12px 9px 7px 24px;
447 447 }
448 448
449 449 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
450 450 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
451 451 width:167px;
452 452 margin:0;
453 453 padding:12px 9px 7px 24px;
454 454 }
455 455
456 456 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
457 457 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
458 458 width:167px;
459 459 margin:0;
460 460 padding:12px 9px 7px 24px;
461 461 }
462 462
463 463 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
464 464 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
465 465 width:167px;
466 466 margin:0;
467 467 padding:12px 9px 7px 24px;
468 468 }
469 469
470 470 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
471 471 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
472 472 width:167px;
473 473 margin:0;
474 474 padding:12px 9px 7px 24px;
475 475 }
476 476
477 477 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
478 478 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
479 479 width:167px;
480 480 margin:0;
481 481 padding:12px 9px 7px 24px;
482 482 }
483 483
484 484 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
485 485 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
486 486 width:167px;
487 487 margin:0;
488 488 padding:12px 9px 7px 24px;
489 489 }
490 490
491 491 #content #left {
492 492 left:0;
493 493 width:280px;
494 494 position:absolute;
495 495 }
496 496
497 497 #content #right {
498 498 margin:0 60px 10px 290px;
499 499 }
500 500
501 501 #content div.box {
502 502 clear:both;
503 503 overflow:hidden;
504 504 background:#fff;
505 505 margin:0 0 10px;
506 506 padding:0 0 10px;
507 507 }
508 508
509 509 #content div.box-left {
510 510 width:49%;
511 511 clear:none;
512 512 float:left;
513 513 margin:0 0 10px;
514 514 }
515 515
516 516 #content div.box-right {
517 517 width:49%;
518 518 clear:none;
519 519 float:right;
520 520 margin:0 0 10px;
521 521 }
522 522
523 523 #content div.box div.title {
524 524 clear:both;
525 525 overflow:hidden;
526 526 background:#369 url("../images/header_inner.png") repeat-x;
527 527 margin:0 0 20px;
528 528 padding:0;
529 529 }
530 530
531 531 #content div.box div.title h5 {
532 532 float:left;
533 533 border:none;
534 534 color:#fff;
535 535 text-transform:uppercase;
536 536 margin:0;
537 537 padding:11px 0 11px 10px;
538 538 }
539 539
540 540 #content div.box div.title ul.links li {
541 541 list-style:none;
542 542 float:left;
543 543 margin:0;
544 544 padding:0;
545 545 }
546 546
547 547 #content div.box div.title ul.links li a {
548 548 height:1%;
549 549 display:block;
550 550 float:left;
551 551 border-left:1px solid #316293;
552 552 color:#fff;
553 553 font-size:11px;
554 554 font-weight:700;
555 555 text-decoration:none;
556 556 margin:0;
557 557 padding:13px 16px 12px;
558 558 }
559 559
560 560 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
561 561 clear:both;
562 562 overflow:hidden;
563 563 border-bottom:1px solid #DDD;
564 564 margin:10px 20px;
565 565 padding:0 0 15px;
566 566 }
567 567
568 568 #content div.box p {
569 569 color:#5f5f5f;
570 570 font-size:12px;
571 571 line-height:150%;
572 572 margin:0 24px 10px;
573 573 padding:0;
574 574 }
575 575
576 576 #content div.box blockquote {
577 577 border-left:4px solid #DDD;
578 578 color:#5f5f5f;
579 579 font-size:11px;
580 580 line-height:150%;
581 581 margin:0 34px;
582 582 padding:0 0 0 14px;
583 583 }
584 584
585 585 #content div.box blockquote p {
586 586 margin:10px 0;
587 587 padding:0;
588 588 }
589 589
590 590 #content div.box dl {
591 591 margin:10px 24px;
592 592 }
593 593
594 594 #content div.box dt {
595 595 font-size:12px;
596 596 margin:0;
597 597 }
598 598
599 599 #content div.box dd {
600 600 font-size:12px;
601 601 margin:0;
602 602 padding:8px 0 8px 15px;
603 603 }
604 604
605 605 #content div.box li {
606 606 font-size:12px;
607 607 padding:4px 0;
608 608 }
609 609
610 610 #content div.box ul.disc,#content div.box ul.circle {
611 611 margin:10px 24px 10px 38px;
612 612 }
613 613
614 614 #content div.box ul.square {
615 615 margin:10px 24px 10px 40px;
616 616 }
617 617
618 618 #content div.box img.left {
619 619 border:none;
620 620 float:left;
621 621 margin:10px 10px 10px 0;
622 622 }
623 623
624 624 #content div.box img.right {
625 625 border:none;
626 626 float:right;
627 627 margin:10px 0 10px 10px;
628 628 }
629 629
630 630 #content div.box div.messages {
631 631 clear:both;
632 632 overflow:hidden;
633 633 margin:0 20px;
634 634 padding:0;
635 635 }
636 636
637 637 #content div.box div.message {
638 638 clear:both;
639 639 overflow:hidden;
640 640 margin:0;
641 641 padding:10px 0;
642 642 }
643 643
644 644 #content div.box div.message a {
645 645 font-weight:400 !important;
646 646 }
647 647
648 648 #content div.box div.message div.image {
649 649 float:left;
650 650 margin:9px 0 0 5px;
651 651 padding:6px;
652 652 }
653 653
654 654 #content div.box div.message div.image img {
655 655 vertical-align:middle;
656 656 margin:0;
657 657 }
658 658
659 659 #content div.box div.message div.text {
660 660 float:left;
661 661 margin:0;
662 662 padding:9px 6px;
663 663 }
664 664
665 665 #content div.box div.message div.dismiss a {
666 666 height:16px;
667 667 width:16px;
668 668 display:block;
669 669 background:url("../images/icons/cross.png") no-repeat;
670 670 margin:15px 14px 0 0;
671 671 padding:0;
672 672 }
673 673
674 674 #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 {
675 675 border:none;
676 676 margin:0;
677 677 padding:0;
678 678 }
679 679
680 680 #content div.box div.message div.text span {
681 681 height:1%;
682 682 display:block;
683 683 margin:0;
684 684 padding:5px 0 0;
685 685 }
686 686
687 687 #content div.box div.message-error {
688 688 height:1%;
689 689 clear:both;
690 690 overflow:hidden;
691 691 background:#FBE3E4;
692 692 border:1px solid #FBC2C4;
693 693 color:#860006;
694 694 }
695 695
696 696 #content div.box div.message-error h6 {
697 697 color:#860006;
698 698 }
699 699
700 700 #content div.box div.message-warning {
701 701 height:1%;
702 702 clear:both;
703 703 overflow:hidden;
704 704 background:#FFF6BF;
705 705 border:1px solid #FFD324;
706 706 color:#5f5200;
707 707 }
708 708
709 709 #content div.box div.message-warning h6 {
710 710 color:#5f5200;
711 711 }
712 712
713 713 #content div.box div.message-notice {
714 714 height:1%;
715 715 clear:both;
716 716 overflow:hidden;
717 717 background:#8FBDE0;
718 718 border:1px solid #6BACDE;
719 719 color:#003863;
720 720 }
721 721
722 722 #content div.box div.message-notice h6 {
723 723 color:#003863;
724 724 }
725 725
726 726 #content div.box div.message-success {
727 727 height:1%;
728 728 clear:both;
729 729 overflow:hidden;
730 730 background:#E6EFC2;
731 731 border:1px solid #C6D880;
732 732 color:#4e6100;
733 733 }
734 734
735 735 #content div.box div.message-success h6 {
736 736 color:#4e6100;
737 737 }
738 738
739 739 #content div.box div.form div.fields div.field {
740 740 height:1%;
741 741 border-bottom:1px solid #DDD;
742 742 clear:both;
743 743 margin:0;
744 744 padding:10px 0;
745 745 }
746 746
747 747 #content div.box div.form div.fields div.field-first {
748 748 padding:0 0 10px;
749 749 }
750 750
751 751 #content div.box div.form div.fields div.field-noborder {
752 752 border-bottom:0 !important;
753 753 }
754 754
755 755 #content div.box div.form div.fields div.field span.error-message {
756 756 height:1%;
757 757 display:inline-block;
758 758 color:red;
759 759 margin:8px 0 0 4px;
760 760 padding:0;
761 761 }
762 762
763 763 #content div.box div.form div.fields div.field span.success {
764 764 height:1%;
765 765 display:block;
766 766 color:#316309;
767 767 margin:8px 0 0;
768 768 padding:0;
769 769 }
770 770
771 771 #content div.box div.form div.fields div.field div.label {
772 772 left:80px;
773 773 width:auto;
774 774 position:absolute;
775 775 margin:0;
776 776 padding:8px 0 0 5px;
777 777 }
778 778
779 779 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
780 780 clear:both;
781 781 overflow:hidden;
782 782 left:0;
783 783 width:auto;
784 784 position:relative;
785 785 margin:0;
786 786 padding:0 0 8px;
787 787 }
788 788
789 789 #content div.box div.form div.fields div.field div.label-select {
790 790 padding:2px 0 0 5px;
791 791 }
792 792
793 793 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
794 794 padding:0 0 8px;
795 795 }
796 796
797 797 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
798 798 padding:0 0 8px !important;
799 799 }
800 800
801 801 #content div.box div.form div.fields div.field div.label label {
802 802 color:#393939;
803 803 font-weight:700;
804 804 }
805 805
806 806 #content div.box div.form div.fields div.field div.input {
807 807 margin:0 0 0 200px;
808 808 }
809 809
810 810 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
811 811 clear:both;
812 812 overflow:hidden;
813 813 border-top:1px solid #b3b3b3;
814 814 border-left:1px solid #b3b3b3;
815 815 border-right:1px solid #eaeaea;
816 816 border-bottom:1px solid #eaeaea;
817 817 margin:0;
818 818 padding:7px 7px 6px;
819 819 }
820 820
821 821 #content div.box div.form div.fields div.field div.input input {
822 822 background:#FFF;
823 823 border-top:1px solid #b3b3b3;
824 824 border-left:1px solid #b3b3b3;
825 825 border-right:1px solid #eaeaea;
826 826 border-bottom:1px solid #eaeaea;
827 827 color:#000;
828 828 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
829 829 font-size:11px;
830 830 margin:0;
831 831 padding:7px 7px 6px;
832 832 }
833 833
834 834 #content div.box-left div.form div.fields div.field div.input input,#content div.box-right div.form div.fields div.field div.input input {
835 835 width:100%;
836 836 border:none;
837 837 padding:0;
838 838 }
839 839
840 840 #content div.box div.form div.fields div.field div.input input.small {
841 841 width:30%;
842 842 }
843 843
844 844 #content div.box div.form div.fields div.field div.input input.medium {
845 845 width:55%;
846 846 }
847 847
848 848 #content div.box div.form div.fields div.field div.input input.large {
849 849 width:85%;
850 850 }
851 851
852 852 #content div.box div.form div.fields div.field div.input input.date {
853 853 width:177px;
854 854 }
855 855
856 856 #content div.box div.form div.fields div.field div.input input.button {
857 857 background:#D4D0C8;
858 858 border-top:1px solid #FFF;
859 859 border-left:1px solid #FFF;
860 860 border-right:1px solid #404040;
861 861 border-bottom:1px solid #404040;
862 862 color:#000;
863 863 margin:0;
864 864 padding:4px 8px;
865 865 }
866 866
867 867 #content div.box div.form div.fields div.field div.input a.ui-input-file {
868 868 width:28px;
869 869 height:28px;
870 870 display:inline;
871 871 position:absolute;
872 872 overflow:hidden;
873 873 cursor:pointer;
874 874 background:#e5e3e3 url("../images/button_browse.png") no-repeat;
875 875 border:none;
876 876 text-decoration:none;
877 877 margin:0 0 0 6px;
878 878 padding:0;
879 879 }
880 880
881 881 #content div.box div.form div.fields div.field div.textarea {
882 882 border-top:1px solid #b3b3b3;
883 883 border-left:1px solid #b3b3b3;
884 884 border-right:1px solid #eaeaea;
885 885 border-bottom:1px solid #eaeaea;
886 886 margin:0 0 0 200px;
887 887 padding:10px;
888 888 }
889 889
890 890 #content div.box div.form div.fields div.field div.textarea-editor {
891 891 border:1px solid #ddd;
892 892 padding:0;
893 893 }
894 894
895 895 #content div.box div.form div.fields div.field div.textarea textarea {
896 896 width:100%;
897 897 height:220px;
898 898 overflow:hidden;
899 899 background:#FFF;
900 900 color:#000;
901 901 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
902 902 font-size:11px;
903 903 outline:none;
904 904 border-width:0;
905 905 margin:0;
906 906 padding:0;
907 907 }
908 908
909 909 #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 {
910 910 width:100%;
911 911 height:100px;
912 912 }
913 913
914 914 #content div.box div.form div.fields div.field div.textarea table {
915 915 width:100%;
916 916 border:none;
917 917 margin:0;
918 918 padding:0;
919 919 }
920 920
921 921 #content div.box div.form div.fields div.field div.textarea table td {
922 922 background:#DDD;
923 923 border:none;
924 924 padding:0;
925 925 }
926 926
927 927 #content div.box div.form div.fields div.field div.textarea table td table {
928 928 width:auto;
929 929 border:none;
930 930 margin:0;
931 931 padding:0;
932 932 }
933 933
934 934 #content div.box div.form div.fields div.field div.textarea table td table td {
935 935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
936 936 font-size:11px;
937 937 padding:5px 5px 5px 0;
938 938 }
939 939
940 940 #content div.box div.form div.fields div.field div.textarea table td table td a.mceButtonActive {
941 941 background:#b1b1b1;
942 942 }
943 943
944 944 #content div.box div.form div.fields div.field div.select a.ui-selectmenu {
945 945 color:#565656;
946 946 text-decoration:none;
947 947 }
948 948
949 949 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
950 950 background:#f6f6f6;
951 951 border-color:#666;
952 952 }
953 953
954 954 div.form div.fields div.field div.button {
955 955 margin:0;
956 956 padding:0 0 0 8px;
957 957 }
958 958
959 959 div.form div.fields div.field div.highlight .ui-state-default {
960 960 background:#4e85bb url("../images/button_highlight.png") repeat-x;
961 961 border-top:1px solid #5c91a4;
962 962 border-left:1px solid #2a6f89;
963 963 border-right:1px solid #2b7089;
964 964 border-bottom:1px solid #1a6480;
965 965 color:#FFF;
966 966 margin:0;
967 967 padding:6px 12px;
968 968 }
969 969
970 970 div.form div.fields div.field div.highlight .ui-state-hover {
971 971 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
972 972 border-top:1px solid #78acbf;
973 973 border-left:1px solid #34819e;
974 974 border-right:1px solid #35829f;
975 975 border-bottom:1px solid #257897;
976 976 color:#FFF;
977 977 margin:0;
978 978 padding:6px 12px;
979 979 }
980 980
981 981 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-default {
982 982 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
983 983 border-top:1px solid #5c91a4;
984 984 border-left:1px solid #2a6f89;
985 985 border-right:1px solid #2b7089;
986 986 border-bottom:1px solid #1a6480;
987 987 color:#fff;
988 988 margin:0;
989 989 padding:6px 12px;
990 990 }
991 991
992 992 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
993 993 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
994 994 border-top:1px solid #78acbf;
995 995 border-left:1px solid #34819e;
996 996 border-right:1px solid #35829f;
997 997 border-bottom:1px solid #257897;
998 998 color:#fff;
999 999 margin:0;
1000 1000 padding:6px 12px;
1001 1001 }
1002 1002
1003 1003 #content div.box table {
1004 1004 width:100%;
1005 1005 border-collapse:collapse;
1006 1006 margin:0;
1007 1007 padding:0;
1008 1008 }
1009 1009
1010 1010 #content div.box table th {
1011 1011 background:#eee;
1012 1012 border-bottom:1px solid #ddd;
1013 padding:10px;
1013 padding:5px 0px 5px 5px;
1014 1014 }
1015 1015
1016 1016 #content div.box table th.left {
1017 1017 text-align:left;
1018 1018 }
1019 1019
1020 1020 #content div.box table th.right {
1021 1021 text-align:right;
1022 1022 }
1023 1023
1024 1024 #content div.box table th.center {
1025 1025 text-align:center;
1026 1026 }
1027 1027
1028 1028 #content div.box table th.selected {
1029 1029 vertical-align:middle;
1030 1030 padding:0;
1031 1031 }
1032 1032
1033 1033 #content div.box table td {
1034 1034 background:#fff;
1035 1035 border-bottom:1px solid #cdcdcd;
1036 1036 vertical-align:middle;
1037 1037 padding:5px;
1038 1038 }
1039 1039
1040 1040 #content div.box table tr.selected td {
1041 1041 background:#FFC;
1042 1042 }
1043 1043
1044 1044 #content div.box table td.selected {
1045 1045 width:3%;
1046 1046 text-align:center;
1047 1047 vertical-align:middle;
1048 1048 padding:0;
1049 1049 }
1050 1050
1051 1051 #content div.box table td.action {
1052 1052 width:45%;
1053 1053 text-align:left;
1054 1054 }
1055 1055
1056 1056 #content div.box table td.date {
1057 1057 width:33%;
1058 1058 text-align:center;
1059 1059 }
1060 1060
1061 1061 #content div.box div.action {
1062 1062 float:right;
1063 1063 background:#FFF;
1064 1064 text-align:right;
1065 1065 margin:10px 0 0;
1066 1066 padding:0;
1067 1067 }
1068 1068
1069 1069 #content div.box div.action select {
1070 1070 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1071 1071 font-size:11px;
1072 1072 margin:0;
1073 1073 }
1074 1074
1075 1075 #content div.box div.action .ui-selectmenu {
1076 1076 margin:0;
1077 1077 padding:0;
1078 1078 }
1079 1079
1080 1080 #content div.box div.pagination {
1081 1081 height:1%;
1082 1082 clear:both;
1083 1083 overflow:hidden;
1084 1084 margin:10px 0 0;
1085 1085 padding:0;
1086 1086 }
1087 1087
1088 1088 #content div.box div.pagination ul.pager {
1089 1089 float:right;
1090 1090 text-align:right;
1091 1091 margin:0;
1092 1092 padding:0;
1093 1093 }
1094 1094
1095 1095 #content div.box div.pagination ul.pager li {
1096 1096 height:1%;
1097 1097 float:left;
1098 1098 list-style:none;
1099 1099 background:#ebebeb url("../images/pager.png") repeat-x;
1100 1100 border-top:1px solid #dedede;
1101 1101 border-left:1px solid #cfcfcf;
1102 1102 border-right:1px solid #c4c4c4;
1103 1103 border-bottom:1px solid #c4c4c4;
1104 1104 color:#4A4A4A;
1105 1105 font-weight:700;
1106 1106 margin:0 0 0 4px;
1107 1107 padding:0;
1108 1108 }
1109 1109
1110 1110 #content div.box div.pagination ul.pager li.separator {
1111 1111 padding:6px;
1112 1112 }
1113 1113
1114 1114 #content div.box div.pagination ul.pager li.current {
1115 1115 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1116 1116 border-top:1px solid #ccc;
1117 1117 border-left:1px solid #bebebe;
1118 1118 border-right:1px solid #b1b1b1;
1119 1119 border-bottom:1px solid #afafaf;
1120 1120 color:#515151;
1121 1121 padding:6px;
1122 1122 }
1123 1123
1124 1124 #content div.box div.pagination ul.pager li a {
1125 1125 height:1%;
1126 1126 display:block;
1127 1127 float:left;
1128 1128 color:#515151;
1129 1129 text-decoration:none;
1130 1130 margin:0;
1131 1131 padding:6px;
1132 1132 }
1133 1133
1134 1134 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1135 1135 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1136 1136 border-top:1px solid #ccc;
1137 1137 border-left:1px solid #bebebe;
1138 1138 border-right:1px solid #b1b1b1;
1139 1139 border-bottom:1px solid #afafaf;
1140 1140 margin:-1px;
1141 1141 }
1142 1142
1143 1143 #content div.box div.pagination-wh {
1144 1144 height:1%;
1145 1145 clear:both;
1146 1146 overflow:hidden;
1147 1147 text-align:right;
1148 1148 margin:10px 0 0;
1149 1149 padding:0;
1150 1150 }
1151 1151
1152 1152 #content div.box div.pagination-right {
1153 1153 float:right;
1154 1154 }
1155 1155
1156 1156 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1157 1157 height:1%;
1158 1158 float:left;
1159 1159 background:#ebebeb url("../images/pager.png") repeat-x;
1160 1160 border-top:1px solid #dedede;
1161 1161 border-left:1px solid #cfcfcf;
1162 1162 border-right:1px solid #c4c4c4;
1163 1163 border-bottom:1px solid #c4c4c4;
1164 1164 color:#4A4A4A;
1165 1165 font-weight:700;
1166 1166 margin:0 0 0 4px;
1167 1167 padding:6px;
1168 1168 }
1169 1169
1170 1170 #content div.box div.pagination-wh span.pager_curpage {
1171 1171 height:1%;
1172 1172 float:left;
1173 1173 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1174 1174 border-top:1px solid #ccc;
1175 1175 border-left:1px solid #bebebe;
1176 1176 border-right:1px solid #b1b1b1;
1177 1177 border-bottom:1px solid #afafaf;
1178 1178 color:#515151;
1179 1179 font-weight:700;
1180 1180 margin:0 0 0 4px;
1181 1181 padding:6px;
1182 1182 }
1183 1183
1184 1184 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1185 1185 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1186 1186 border-top:1px solid #ccc;
1187 1187 border-left:1px solid #bebebe;
1188 1188 border-right:1px solid #b1b1b1;
1189 1189 border-bottom:1px solid #afafaf;
1190 1190 text-decoration:none;
1191 1191 }
1192 1192
1193 1193 #content div.box div.traffic div.legend {
1194 1194 clear:both;
1195 1195 overflow:hidden;
1196 1196 border-bottom:1px solid #ddd;
1197 1197 margin:0 0 10px;
1198 1198 padding:0 0 10px;
1199 1199 }
1200 1200
1201 1201 #content div.box div.traffic div.legend h6 {
1202 1202 float:left;
1203 1203 border:none;
1204 1204 margin:0;
1205 1205 padding:0;
1206 1206 }
1207 1207
1208 1208 #content div.box div.traffic div.legend li {
1209 1209 list-style:none;
1210 1210 float:left;
1211 1211 font-size:11px;
1212 1212 margin:0;
1213 1213 padding:0 8px 0 4px;
1214 1214 }
1215 1215
1216 1216 #content div.box div.traffic div.legend li.visits {
1217 1217 border-left:12px solid #edc240;
1218 1218 }
1219 1219
1220 1220 #content div.box div.traffic div.legend li.pageviews {
1221 1221 border-left:12px solid #afd8f8;
1222 1222 }
1223 1223
1224 1224 #content div.box div.traffic table {
1225 1225 width:auto;
1226 1226 }
1227 1227
1228 1228 #content div.box div.traffic table td {
1229 1229 background:transparent;
1230 1230 border:none;
1231 1231 padding:2px 3px 3px;
1232 1232 }
1233 1233
1234 1234 #content div.box div.traffic table td.legendLabel {
1235 1235 padding:0 3px 2px;
1236 1236 }
1237 1237
1238 1238 #footer {
1239 1239 clear:both;
1240 1240 overflow:hidden;
1241 1241 text-align:right;
1242 1242 margin:0;
1243 1243 padding:0 30px 4px;
1244 1244 margin:-10px 0 0;
1245 1245 }
1246 1246
1247 1247 #footer div#footer-inner {
1248 1248 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1249 1249 border-top:2px solid #FFFFFF;
1250 1250 }
1251 1251
1252 1252 #footer div#footer-inner p {
1253 1253 padding:15px 25px 15px 0;
1254 1254 color:#FFF;
1255 1255 font-weight:700;
1256 1256 }
1257 1257 #footer div#footer-inner .footer-link {
1258 1258 float:left;
1259 1259 padding-left:10px;
1260 1260 }
1261 1261 #footer div#footer-inner .footer-link a {
1262 1262 color:#FFF;
1263 1263 }
1264 1264
1265 1265 #login div.title {
1266 1266 width:420px;
1267 1267 clear:both;
1268 1268 overflow:hidden;
1269 1269 position:relative;
1270 1270 background:#003367 url("../../images/header_inner.png") repeat-x;
1271 1271 margin:0 auto;
1272 1272 padding:0;
1273 1273 }
1274 1274
1275 1275 #login div.inner {
1276 1276 width:380px;
1277 1277 background:#FFF url("../images/login.png") no-repeat top left;
1278 1278 border-top:none;
1279 1279 border-bottom:none;
1280 1280 margin:0 auto;
1281 1281 padding:20px;
1282 1282 }
1283 1283
1284 1284 #login div.form div.fields div.field div.label {
1285 1285 width:173px;
1286 1286 float:left;
1287 1287 text-align:right;
1288 1288 margin:2px 10px 0 0;
1289 1289 padding:5px 0 0 5px;
1290 1290 }
1291 1291
1292 1292 #login div.form div.fields div.field div.input input {
1293 1293 width:176px;
1294 1294 background:#FFF;
1295 1295 border-top:1px solid #b3b3b3;
1296 1296 border-left:1px solid #b3b3b3;
1297 1297 border-right:1px solid #eaeaea;
1298 1298 border-bottom:1px solid #eaeaea;
1299 1299 color:#000;
1300 1300 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1301 1301 font-size:11px;
1302 1302 margin:0;
1303 1303 padding:7px 7px 6px;
1304 1304 }
1305 1305
1306 1306 #login div.form div.fields div.buttons {
1307 1307 clear:both;
1308 1308 overflow:hidden;
1309 1309 border-top:1px solid #DDD;
1310 1310 text-align:right;
1311 1311 margin:0;
1312 1312 padding:10px 0 0;
1313 1313 }
1314 1314
1315 1315 #login div.form div.links {
1316 1316 clear:both;
1317 1317 overflow:hidden;
1318 1318 margin:10px 0 0;
1319 1319 padding:0 0 2px;
1320 1320 }
1321 1321
1322 1322 #register div.title {
1323 1323 width:420px;
1324 1324 clear:both;
1325 1325 overflow:hidden;
1326 1326 position:relative;
1327 1327 background:#003367 url("../images/header_inner.png") repeat-x;
1328 1328 margin:0 auto;
1329 1329 padding:0;
1330 1330 }
1331 1331
1332 1332 #register div.inner {
1333 1333 width:380px;
1334 1334 background:#FFF;
1335 1335 border-top:none;
1336 1336 border-bottom:none;
1337 1337 margin:0 auto;
1338 1338 padding:20px;
1339 1339 }
1340 1340
1341 1341 #register div.form div.fields div.field div.label {
1342 1342 width:100px;
1343 1343 float:left;
1344 1344 text-align:right;
1345 1345 margin:2px 10px 0 0;
1346 1346 padding:5px 0 0 5px;
1347 1347 }
1348 1348
1349 1349 #register div.form div.fields div.field div.input input {
1350 1350 width:245px;
1351 1351 background:#FFF;
1352 1352 border-top:1px solid #b3b3b3;
1353 1353 border-left:1px solid #b3b3b3;
1354 1354 border-right:1px solid #eaeaea;
1355 1355 border-bottom:1px solid #eaeaea;
1356 1356 color:#000;
1357 1357 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1358 1358 font-size:11px;
1359 1359 margin:0;
1360 1360 padding:7px 7px 6px;
1361 1361 }
1362 1362
1363 1363 #register div.form div.fields div.buttons {
1364 1364 clear:both;
1365 1365 overflow:hidden;
1366 1366 border-top:1px solid #DDD;
1367 1367 text-align:left;
1368 1368 margin:0;
1369 1369 padding:10px 0 0 114px;
1370 1370 }
1371 1371
1372 1372 #register div.form div.fields div.buttons div.highlight input.ui-state-default {
1373 1373 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1374 1374 color:#FFF;
1375 1375 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1376 1376 border-style:solid;
1377 1377 border-width:1px;
1378 1378 }
1379 1379
1380 1380 #register div.form div.activation_msg {
1381 1381 padding-top:4px;
1382 1382 padding-bottom:4px;
1383 1383 }
1384 1384
1385 1385 .trending_language_tbl,.trending_language_tbl td {
1386 1386 border:0 !important;
1387 1387 margin:0 !important;
1388 1388 padding:0 !important;
1389 1389 }
1390 1390
1391 1391 .trending_language {
1392 1392 background-color:#003367;
1393 1393 color:#FFF;
1394 1394 display:block;
1395 1395 min-width:20px;
1396 max-width:400px;
1397 1396 text-decoration:none;
1398 1397 height:12px;
1399 1398 margin-bottom:4px;
1400 1399 margin-left:5px;
1401 1400 white-space:pre;
1402 1401 padding:3px;
1403 1402 }
1404 1403
1405 1404 h3.files_location {
1406 1405 font-size:1.8em;
1407 1406 font-weight:700;
1408 1407 border-bottom:none !important;
1409 1408 margin:10px 0 !important;
1410 1409 }
1411 1410
1412 1411 #files_data dl dt {
1413 1412 float:left;
1414 1413 width:115px;
1415 1414 margin:0 !important;
1416 1415 padding:5px;
1417 1416 }
1418 1417
1419 1418 #files_data dl dd {
1420 1419 margin:0 !important;
1421 1420 padding:5px !important;
1422 1421 }
1423 1422
1424 1423 #changeset_content {
1425 1424 border:1px solid #CCC;
1426 1425 padding:5px;
1427 1426 }
1428 1427
1429 1428 #changeset_content .container {
1430 1429 min-height:120px;
1431 1430 font-size:1.2em;
1432 1431 overflow:hidden;
1433 1432 }
1434 1433
1435 1434 #changeset_content .container .right {
1436 1435 float:right;
1437 1436 width:25%;
1438 1437 text-align:right;
1439 1438 }
1440 1439
1441 1440 #changeset_content .container .left .message {
1442 1441 font-style:italic;
1443 1442 color:#556CB5;
1444 1443 white-space:pre-wrap;
1445 1444 }
1446 1445
1447 1446 .cs_files .cs_added {
1448 1447 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1449 1448 height:16px;
1450 1449 padding-left:20px;
1451 1450 margin-top:7px;
1452 1451 text-align:left;
1453 1452 }
1454 1453
1455 1454 .cs_files .cs_changed {
1456 1455 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1457 1456 height:16px;
1458 1457 padding-left:20px;
1459 1458 margin-top:7px;
1460 1459 text-align:left;
1461 1460 }
1462 1461
1463 1462 .cs_files .cs_removed {
1464 1463 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1465 1464 height:16px;
1466 1465 padding-left:20px;
1467 1466 margin-top:7px;
1468 1467 text-align:left;
1469 1468 }
1470 1469
1471 1470 #graph {
1472 1471 overflow:hidden;
1473 1472 }
1474 1473
1475 1474 #graph_nodes {
1476 1475 width:160px;
1477 1476 float:left;
1478 1477 margin-left:-50px;
1479 1478 margin-top:5px;
1480 1479 }
1481 1480
1482 1481 #graph_content {
1483 1482 width:800px;
1484 1483 float:left;
1485 1484 }
1486 1485
1487 1486 #graph_content .container_header {
1488 1487 border:1px solid #CCC;
1489 1488 padding:10px;
1490 1489 }
1491 1490
1492 1491 #graph_content .container {
1493 1492 border-bottom:1px solid #CCC;
1494 1493 border-left:1px solid #CCC;
1495 1494 border-right:1px solid #CCC;
1496 1495 min-height:80px;
1497 1496 overflow:hidden;
1498 1497 font-size:1.2em;
1499 1498 }
1500 1499
1501 1500 #graph_content .container .right {
1502 1501 float:right;
1503 1502 width:28%;
1504 1503 text-align:right;
1505 1504 padding-bottom:5px;
1506 1505 }
1507 1506
1508 1507 #graph_content .container .left .date {
1509 1508 font-weight:700;
1510 1509 padding-bottom:5px;
1511 1510 }
1512 1511
1513 1512 #graph_content .container .left .message {
1514 1513 font-size:100%;
1515 1514 padding-top:3px;
1516 1515 white-space:pre-wrap;
1517 1516 }
1518 1517
1519 1518 .right div {
1520 1519 clear:both;
1521 1520 }
1522 1521
1523 1522 .right .changes .added,.changed,.removed {
1524 1523 border:1px solid #DDD;
1525 1524 display:block;
1526 1525 float:right;
1527 1526 text-align:center;
1528 1527 min-width:15px;
1529 1528 }
1530 1529
1531 1530 .right .changes .added {
1532 1531 background:#BFB;
1533 1532 }
1534 1533
1535 1534 .right .changes .changed {
1536 1535 background:#FD8;
1537 1536 }
1538 1537
1539 1538 .right .changes .removed {
1540 1539 background:#F88;
1541 1540 }
1542 1541
1543 1542 .right .merge {
1544 1543 vertical-align:top;
1545 font-size:60%;
1544 font-size:0.75em;
1546 1545 font-weight:700;
1547 1546 }
1548 1547
1549 1548 .right .parent {
1550 1549 font-size:90%;
1551 1550 font-family:monospace;
1552 1551 }
1553 1552
1554 1553 .right .logtags .branchtag {
1555 1554 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1556 1555 display:block;
1557 padding:8px 16px 0 0;
1556 font-size:0.8em;
1557 padding:11px 16px 0 0;
1558 1558 }
1559 1559
1560 1560 .right .logtags .tagtag {
1561 1561 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1562 1562 display:block;
1563 padding:6px 18px 0 0;
1563 font-size:0.8em;
1564 padding:11px 16px 0 0;
1564 1565 }
1565 1566
1566 1567 div.browserblock {
1567 1568 overflow:hidden;
1568 1569 border:1px solid #ccc;
1569 1570 background:#f8f8f8;
1570 1571 font-size:100%;
1571 1572 line-height:125%;
1572 1573 padding:0;
1573 1574 }
1574 1575
1575 1576 div.browserblock .browser-header {
1576 1577 border-bottom:1px solid #CCC;
1577 1578 background:#FFF;
1578 1579 color:blue;
1579 1580 padding:10px 0;
1580 1581 }
1581 1582
1582 1583 div.browserblock .browser-header span {
1583 1584 margin-left:25px;
1584 1585 font-weight:700;
1585 1586 }
1586 1587
1587 1588 div.browserblock .browser-body {
1588 1589 background:#EEE;
1589 1590 }
1590 1591
1591 1592 table.code-browser {
1592 1593 border-collapse:collapse;
1593 1594 width:100%;
1594 1595 }
1595 1596
1596 1597 table.code-browser tr {
1597 1598 margin:3px;
1598 1599 }
1599 1600
1600 1601 table.code-browser thead th {
1601 1602 background-color:#EEE;
1602 1603 height:20px;
1603 1604 font-size:1.1em;
1604 1605 font-weight:700;
1605 1606 text-align:left;
1606 1607 padding-left:10px;
1607 1608 }
1608 1609
1609 1610 table.code-browser tbody td {
1610 1611 padding-left:10px;
1611 1612 height:20px;
1612 1613 }
1613 1614
1614 1615 table.code-browser .browser-file {
1615 1616 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1616 1617 height:16px;
1617 1618 padding-left:20px;
1618 1619 text-align:left;
1619 1620 }
1620 1621
1621 1622 table.code-browser .browser-dir {
1622 1623 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1623 1624 height:16px;
1624 1625 padding-left:20px;
1625 1626 text-align:left;
1626 1627 }
1627 1628
1628 1629 .box .search {
1629 1630 clear:both;
1630 1631 overflow:hidden;
1631 1632 margin:0;
1632 1633 padding:0 20px 10px;
1633 1634 }
1634 1635
1635 1636 .box .search div.search_path {
1636 1637 background:none repeat scroll 0 0 #EEE;
1637 1638 border:1px solid #CCC;
1638 1639 color:blue;
1639 1640 margin-bottom:10px;
1640 1641 padding:10px 0;
1641 1642 }
1642 1643
1643 1644 .box .search div.search_path div.link {
1644 1645 font-weight:700;
1645 1646 margin-left:25px;
1646 1647 }
1647 1648
1648 1649 .box .search div.search_path div.link a {
1649 1650 color:#003367;
1650 1651 cursor:pointer;
1651 1652 text-decoration:none;
1652 1653 }
1653 1654
1654 1655 #path_unlock {
1655 1656 color:red;
1656 1657 font-size:1.2em;
1657 1658 padding-left:4px;
1658 1659 }
1659 1660
1660 1661 .info_box * {
1661 1662 background:url("../../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
1662 1663 color:#4A4A4A;
1663 1664 font-weight:700;
1664 1665 height:1%;
1665 1666 display:inline;
1666 1667 border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
1667 1668 border-style:solid;
1668 1669 border-width:1px;
1669 1670 padding:4px 6px;
1670 1671 }
1671 1672
1672 1673 .info_box span {
1673 1674 margin-left:3px;
1674 1675 margin-right:3px;
1675 1676 }
1676 1677
1677 1678 .info_box input#at_rev {
1678 1679 text-align:center;
1679 1680 padding:5px 3px 3px 2px;
1680 1681 }
1681 1682
1682 1683 .info_box input#view {
1683 1684 text-align:center;
1684 1685 padding:4px 3px 2px 2px;
1685 1686 }
1686 1687
1687 1688 .yui-overlay,.yui-panel-container {
1688 1689 visibility:hidden;
1689 1690 position:absolute;
1690 1691 z-index:2;
1691 1692 }
1692 1693
1693 1694 .yui-tt {
1694 1695 visibility:hidden;
1695 1696 position:absolute;
1696 1697 color:#666;
1697 1698 background-color:#FFF;
1698 1699 font-family:arial, helvetica, verdana, sans-serif;
1699 1700 border:2px solid #003367;
1700 1701 font:100% sans-serif;
1701 1702 width:auto;
1702 1703 opacity:1px;
1703 1704 padding:8px;
1705 white-space: pre;
1704 1706 }
1705 1707
1706 1708 .ac {
1707 1709 vertical-align:top;
1708 1710 }
1709 1711
1710 1712 .ac .yui-ac {
1711 1713 position:relative;
1712 1714 font-family:arial;
1713 1715 font-size:100%;
1714 1716 }
1715 1717
1716 1718 .ac .perm_ac {
1717 1719 width:15em;
1718 1720 }
1719 1721
1720 1722 .ac .yui-ac-input {
1721 1723 width:100%;
1722 1724 }
1723 1725
1724 1726 .ac .yui-ac-container {
1725 1727 position:absolute;
1726 1728 top:1.6em;
1727 1729 width:100%;
1728 1730 }
1729 1731
1730 1732 .ac .yui-ac-content {
1731 1733 position:absolute;
1732 1734 width:100%;
1733 1735 border:1px solid gray;
1734 1736 background:#fff;
1735 1737 overflow:hidden;
1736 1738 z-index:9050;
1737 1739 }
1738 1740
1739 1741 .ac .yui-ac-shadow {
1740 1742 position:absolute;
1741 1743 width:100%;
1742 1744 background:#000;
1743 1745 -moz-opacity:0.1px;
1744 1746 opacity:.10;
1745 1747 filter:alpha(opacity = 10);
1746 1748 z-index:9049;
1747 1749 margin:.3em;
1748 1750 }
1749 1751
1750 1752 .ac .yui-ac-content ul {
1751 1753 width:100%;
1752 1754 margin:0;
1753 1755 padding:0;
1754 1756 }
1755 1757
1756 1758 .ac .yui-ac-content li {
1757 1759 cursor:default;
1758 1760 white-space:nowrap;
1759 1761 margin:0;
1760 1762 padding:2px 5px;
1761 1763 }
1762 1764
1763 1765 .ac .yui-ac-content li.yui-ac-prehighlight {
1764 1766 background:#B3D4FF;
1765 1767 }
1766 1768
1767 1769 .ac .yui-ac-content li.yui-ac-highlight {
1768 1770 background:#556CB5;
1769 1771 color:#FFF;
1770 1772 }
1771 1773
1772 1774 .add_icon {
1773 1775 background:url("../images/icons/add.png") no-repeat scroll 3px;
1774 1776 height:16px;
1775 1777 padding-left:20px;
1776 1778 padding-top:1px;
1777 1779 text-align:left;
1778 1780 }
1779 1781
1780 1782 .edit_icon {
1781 1783 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1782 1784 height:16px;
1783 1785 padding-left:20px;
1784 1786 padding-top:1px;
1785 1787 text-align:left;
1786 1788 }
1787 1789
1788 1790 .delete_icon {
1789 1791 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1790 1792 height:16px;
1791 1793 padding-left:20px;
1792 1794 padding-top:1px;
1793 1795 text-align:left;
1794 1796 }
1795 1797
1796 1798 .rss_icon {
1797 1799 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
1798 1800 height:16px;
1799 1801 padding-left:20px;
1800 1802 padding-top:1px;
1801 1803 text-align:left;
1802 1804 }
1803 1805
1804 1806 .atom_icon {
1805 1807 background:url("../images/icons/atom.png") no-repeat scroll 3px;
1806 1808 height:16px;
1807 1809 padding-left:20px;
1808 1810 padding-top:1px;
1809 1811 text-align:left;
1810 1812 }
1811 1813
1812 1814 .archive_icon {
1813 1815 background:url("../images/icons/compress.png") no-repeat scroll 3px;
1814 1816 height:16px;
1815 1817 padding-left:20px;
1816 1818 text-align:left;
1817 1819 padding-top:1px;
1818 1820 }
1819 1821
1820 1822 .action_button {
1821 1823 border:0;
1822 1824 display:block;
1823 1825 }
1824 1826
1825 1827 .action_button:hover {
1826 1828 border:0;
1827 1829 text-decoration:underline;
1828 1830 cursor:pointer;
1829 1831 }
1830 1832
1831 1833 #switch_repos {
1832 1834 position:absolute;
1833 1835 height:25px;
1834 1836 z-index:1;
1835 1837 }
1836 1838
1837 1839 #switch_repos select {
1838 1840 min-width:150px;
1839 1841 max-height:250px;
1840 1842 z-index:1;
1841 1843 }
1842 1844
1843 1845 .breadcrumbs {
1844 1846 border:medium none;
1845 1847 color:#FFF;
1846 1848 float:left;
1847 1849 text-transform:uppercase;
1848 1850 font-weight:700;
1849 1851 font-size:14px;
1850 1852 margin:0;
1851 1853 padding:11px 0 11px 10px;
1852 1854 }
1853 1855
1854 1856 .breadcrumbs a {
1855 1857 color:#FFF;
1856 1858 }
1857 1859
1858 1860 .flash_msg ul {
1859 1861 margin:0;
1860 1862 padding:0 0 10px;
1861 1863 }
1862 1864
1863 1865 .error_msg {
1864 1866 background-color:#FFCFCF;
1865 1867 background-image:url("../../images/icons/error_msg.png");
1866 1868 border:1px solid #FF9595;
1867 1869 color:#C30;
1868 1870 }
1869 1871
1870 1872 .warning_msg {
1871 1873 background-color:#FFFBCC;
1872 1874 background-image:url("../../images/icons/warning_msg.png");
1873 1875 border:1px solid #FFF35E;
1874 1876 color:#C69E00;
1875 1877 }
1876 1878
1877 1879 .success_msg {
1878 1880 background-color:#D5FFCF;
1879 1881 background-image:url("../../images/icons/success_msg.png");
1880 1882 border:1px solid #97FF88;
1881 1883 color:#090;
1882 1884 }
1883 1885
1884 1886 .notice_msg {
1885 1887 background-color:#DCE3FF;
1886 1888 background-image:url("../../images/icons/notice_msg.png");
1887 1889 border:1px solid #93A8FF;
1888 1890 color:#556CB5;
1889 1891 }
1890 1892
1891 1893 .success_msg,.error_msg,.notice_msg,.warning_msg {
1892 1894 background-position:10px center;
1893 1895 background-repeat:no-repeat;
1894 1896 font-size:12px;
1895 1897 font-weight:700;
1896 1898 min-height:14px;
1897 1899 line-height:14px;
1898 1900 margin-bottom:0;
1899 1901 margin-top:0;
1900 1902 display:block;
1901 1903 overflow:auto;
1902 1904 padding:6px 10px 6px 40px;
1903 1905 }
1904 1906
1905 1907 #msg_close {
1906 1908 background:transparent url("../../icons/cross_grey_small.png") no-repeat scroll 0 0;
1907 1909 cursor:pointer;
1908 1910 height:16px;
1909 1911 position:absolute;
1910 1912 right:5px;
1911 1913 top:5px;
1912 1914 width:16px;
1913 1915 }
1914 1916
1915 1917 div#legend_container table,div#legend_choices table {
1916 1918 width:auto !important;
1917 1919 }
1918 1920
1919 1921 table#permissions_manage {
1920 1922 width:0 !important;
1921 1923 }
1922 1924
1923 1925 table#permissions_manage span.private_repo_msg {
1924 1926 font-size:0.8em;
1925 1927 opacity:0.6px;
1926 1928 }
1927 1929
1928 1930 table#permissions_manage td.private_repo_msg {
1929 1931 font-size:0.8em;
1930 1932 }
1931 1933
1932 1934 table#permissions_manage tr#add_perm_input td {
1933 1935 vertical-align:middle;
1934 1936 }
1935 1937
1936 1938 div.gravatar {
1937 1939 background-color:#FFF;
1938 1940 border:1px solid #D0D0D0;
1939 1941 float:left;
1940 1942 margin-right:0.7em;
1941 1943 padding:2px 2px 0;
1942 1944 }
1943 1945
1944 1946 #header,#content,#footer {
1945 1947 min-width:1224px;
1946 1948 }
1947 1949
1948 1950 #content {
1949 1951 min-height:100%;
1950 1952 clear:both;
1951 1953 overflow:hidden;
1952 1954 padding:14px 30px;
1953 1955 }
1954 1956
1955 1957 #content div.box div.title div.search {
1956 1958 background:url("../../images/title_link.png") no-repeat top left;
1957 1959 border-left:1px solid #316293;
1958 1960 }
1959 1961
1960 1962 #content div.box div.title div.search div.input input {
1961 1963 border:1px solid #316293;
1962 1964 }
1963 1965
1964 1966 #content div.box div.title div.search div.button input.ui-state-default {
1965 1967 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1966 1968 border:1px solid #316293;
1967 1969 border-left:none;
1968 1970 color:#FFF;
1969 1971 }
1970 1972
1971 1973 #content div.box div.title div.search div.button input.ui-state-hover {
1972 1974 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1973 1975 border:1px solid #316293;
1974 1976 border-left:none;
1975 1977 color:#FFF;
1976 1978 }
1977 1979
1978 1980 #content div.box div.form div.fields div.field div.highlight .ui-state-default {
1979 1981 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1980 1982 border-top:1px solid #5c91a4;
1981 1983 border-left:1px solid #2a6f89;
1982 1984 border-right:1px solid #2b7089;
1983 1985 border-bottom:1px solid #1a6480;
1984 1986 color:#fff;
1985 1987 }
1986 1988
1987 1989 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
1988 1990 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1989 1991 border-top:1px solid #78acbf;
1990 1992 border-left:1px solid #34819e;
1991 1993 border-right:1px solid #35829f;
1992 1994 border-bottom:1px solid #257897;
1993 1995 color:#fff;
1994 1996 }
1995 1997
1996 1998 ins,div.options a:hover {
1997 1999 text-decoration:none;
1998 2000 }
1999 2001
2000 2002 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2001 2003 border:none;
2002 2004 }
2003 2005
2004 2006 img.icon,.right .merge img {
2005 2007 vertical-align:bottom;
2006 2008 }
2007 2009
2008 2010 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2009 2011 float:right;
2010 2012 margin:0;
2011 2013 padding:0;
2012 2014 }
2013 2015
2014 2016 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2015 2017 float:left;
2016 2018 }
2017 2019
2018 2020 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2019 2021 display:none;
2020 2022 }
2021 2023
2022 2024 #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 {
2023 2025 display:block;
2024 2026 }
2025 2027
2026 2028 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2027 background:url("../../images/title_tab_selected.png") no-repeat bottom center;
2028 2029 color:#bfe3ff;
2029 2030 }
2030 2031
2031 2032 #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 {
2032 2033 margin:10px 24px 10px 44px;
2033 2034 }
2034 2035
2035 2036 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2036 2037 clear:both;
2037 2038 overflow:hidden;
2038 2039 margin:0;
2039 2040 padding:0 20px 10px;
2040 2041 }
2041 2042
2042 2043 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2043 2044 clear:both;
2044 2045 overflow:hidden;
2045 2046 margin:0;
2046 2047 padding:0;
2047 2048 }
2048 2049
2049 2050 #content div.box div.form div.fields div.field div.label-checkbox,#content div.box div.form div.fields div.field div.label-radio,#content div.box div.form div.fields div.field div.label-textarea {
2050 2051 padding:0 0 0 5px !important;
2051 2052 }
2052 2053
2053 2054 #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 {
2054 2055 height:1%;
2055 2056 display:block;
2056 2057 color:#363636;
2057 2058 margin:0;
2058 2059 padding:2px 0 0;
2059 2060 }
2060 2061
2061 2062 #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 {
2062 2063 background:#FBE3E4;
2063 2064 border-top:1px solid #e1b2b3;
2064 2065 border-left:1px solid #e1b2b3;
2065 2066 border-right:1px solid #FBC2C4;
2066 2067 border-bottom:1px solid #FBC2C4;
2067 2068 }
2068 2069
2069 2070 #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 {
2070 2071 background:#E6EFC2;
2071 2072 border-top:1px solid #cebb98;
2072 2073 border-left:1px solid #cebb98;
2073 2074 border-right:1px solid #c6d880;
2074 2075 border-bottom:1px solid #c6d880;
2075 2076 }
2076 2077
2077 2078 #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 {
2078 2079 margin:0;
2079 2080 }
2080 2081
2081 2082 #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 {
2082 2083 margin:0 0 0 200px;
2083 2084 padding:0;
2084 2085 }
2085 2086
2086 2087 #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 {
2087 2088 color:#000;
2088 2089 text-decoration:none;
2089 2090 }
2090 2091
2091 2092 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2092 2093 border:1px solid #666;
2093 2094 }
2094 2095
2095 2096 #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 {
2096 2097 clear:both;
2097 2098 overflow:hidden;
2098 2099 margin:0;
2099 2100 padding:2px 0;
2100 2101 }
2101 2102
2102 2103 #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 {
2103 2104 float:left;
2104 2105 margin:0;
2105 2106 }
2106 2107
2107 2108 #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 {
2108 2109 height:1%;
2109 2110 display:block;
2110 2111 float:left;
2111 2112 margin:3px 0 0 4px;
2112 2113 }
2113 2114
2114 2115 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2115 2116 color:#000;
2116 2117 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2117 2118 font-size:11px;
2118 2119 font-weight:700;
2119 2120 margin:0;
2120 2121 }
2121 2122
2122 2123 div.form div.fields div.field div.button .ui-state-default,#content div.box div.form div.fields div.buttons input.ui-state-default {
2123 2124 background:#e5e3e3 url("../images/button.png") repeat-x;
2124 2125 border-top:1px solid #DDD;
2125 2126 border-left:1px solid #c6c6c6;
2126 2127 border-right:1px solid #DDD;
2127 2128 border-bottom:1px solid #c6c6c6;
2128 2129 color:#515151;
2129 2130 outline:none;
2130 2131 margin:0;
2131 2132 padding:6px 12px;
2132 2133 }
2133 2134
2134 2135 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2135 2136 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2136 2137 border-top:1px solid #ccc;
2137 2138 border-left:1px solid #bebebe;
2138 2139 border-right:1px solid #b1b1b1;
2139 2140 border-bottom:1px solid #afafaf;
2140 2141 color:#515151;
2141 2142 outline:none;
2142 2143 margin:0;
2143 2144 padding:6px 12px;
2144 2145 }
2145 2146
2146 2147 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2147 2148 display:inline;
2148 2149 }
2149 2150
2150 2151 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2151 2152 margin:10px 0 0 200px;
2152 2153 padding:0;
2153 2154 }
2154 2155
2155 2156 #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 {
2156 2157 margin:10px 0 0;
2157 2158 }
2158 2159
2159 2160 #content div.box table td.user,#content div.box table td.address {
2160 2161 width:10%;
2161 2162 text-align:center;
2162 2163 }
2163 2164
2164 2165 #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 {
2165 2166 text-align:right;
2166 2167 margin:6px 0 0;
2167 2168 padding:0;
2168 2169 }
2169 2170
2170 2171 #content div.box div.action div.button input.ui-state-default,#login div.form div.fields div.buttons input.ui-state-default,#register div.form div.fields div.buttons input.ui-state-default {
2171 2172 background:#e5e3e3 url("../images/button.png") repeat-x;
2172 2173 border-top:1px solid #DDD;
2173 2174 border-left:1px solid #c6c6c6;
2174 2175 border-right:1px solid #DDD;
2175 2176 border-bottom:1px solid #c6c6c6;
2176 2177 color:#515151;
2177 2178 margin:0;
2178 2179 padding:6px 12px;
2179 2180 }
2180 2181
2181 2182 #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 {
2182 2183 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2183 2184 border-top:1px solid #ccc;
2184 2185 border-left:1px solid #bebebe;
2185 2186 border-right:1px solid #b1b1b1;
2186 2187 border-bottom:1px solid #afafaf;
2187 2188 color:#515151;
2188 2189 margin:0;
2189 2190 padding:6px 12px;
2190 2191 }
2191 2192
2192 2193 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2193 2194 text-align:left;
2194 2195 float:left;
2195 2196 margin:0;
2196 2197 padding:0;
2197 2198 }
2198 2199
2199 2200 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2200 2201 height:1%;
2201 2202 display:block;
2202 2203 float:left;
2203 2204 background:#ebebeb url("../images/pager.png") repeat-x;
2204 2205 border-top:1px solid #dedede;
2205 2206 border-left:1px solid #cfcfcf;
2206 2207 border-right:1px solid #c4c4c4;
2207 2208 border-bottom:1px solid #c4c4c4;
2208 2209 color:#4A4A4A;
2209 2210 font-weight:700;
2210 2211 margin:0;
2211 2212 padding:6px 8px;
2212 2213 }
2213 2214
2214 2215 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2215 2216 color:#B4B4B4;
2216 2217 padding:6px;
2217 2218 }
2218 2219
2219 2220 #login,#register {
2220 2221 width:420px;
2221 2222 margin:10% auto 0;
2222 2223 padding:0;
2223 2224 }
2224 2225
2225 2226 #login div.color,#register div.color {
2226 2227 clear:both;
2227 2228 overflow:hidden;
2228 2229 background:#FFF;
2229 2230 margin:10px auto 0;
2230 2231 padding:3px 3px 3px 0;
2231 2232 }
2232 2233
2233 2234 #login div.color a,#register div.color a {
2234 2235 width:20px;
2235 2236 height:20px;
2236 2237 display:block;
2237 2238 float:left;
2238 2239 margin:0 0 0 3px;
2239 2240 padding:0;
2240 2241 }
2241 2242
2242 2243 #login div.title h5,#register div.title h5 {
2243 2244 color:#fff;
2244 2245 margin:10px;
2245 2246 padding:0;
2246 2247 }
2247 2248
2248 2249 #login div.form div.fields div.field,#register div.form div.fields div.field {
2249 2250 clear:both;
2250 2251 overflow:hidden;
2251 2252 margin:0;
2252 2253 padding:0 0 10px;
2253 2254 }
2254 2255
2255 2256 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2256 2257 height:1%;
2257 2258 display:block;
2258 2259 color:red;
2259 2260 margin:8px 0 0;
2260 2261 padding:0;
2261 2262 }
2262 2263
2263 2264 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2264 2265 color:#000;
2265 2266 font-weight:700;
2266 2267 }
2267 2268
2268 2269 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2269 2270 float:left;
2270 2271 margin:0;
2271 2272 padding:0;
2272 2273 }
2273 2274
2274 2275 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2275 2276 margin:0 0 0 184px;
2276 2277 padding:0;
2277 2278 }
2278 2279
2279 2280 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2280 2281 color:#565656;
2281 2282 font-weight:700;
2282 2283 }
2283 2284
2284 2285 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2285 2286 color:#000;
2286 2287 font-size:1em;
2287 2288 font-weight:700;
2288 2289 font-family:Verdana, Helvetica, Sans-Serif;
2289 2290 margin:0;
2290 2291 }
2291 2292
2292 2293 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2293 2294 width:600px;
2294 2295 }
2295 2296
2296 2297 #changeset_content .container .left,#graph_content .container .left {
2297 2298 float:left;
2298 2299 width:70%;
2299 2300 padding-left:5px;
2300 2301 }
2301 2302
2302 2303 #changeset_content .container .left .date,.ac .match {
2303 2304 font-weight:700;
2304 2305 padding-top: 5px;
2305 2306 padding-bottom:5px;
2306 2307 }
2307 2308
2308 2309 div#legend_container table td,div#legend_choices table td {
2309 2310 border:none !important;
2310 2311 height:20px !important;
2311 2312 padding:0 !important;
2312 2313 } No newline at end of file
@@ -1,80 +1,80 b''
1 1 <%def name="file_class(node)">
2 2 %if node.is_file():
3 3 <%return "browser-file" %>
4 4 %else:
5 5 <%return "browser-dir"%>
6 6 %endif
7 7 </%def>
8 8 <div id="body" class="browserblock">
9 9 <div class="browser-header">
10 10 ${h.form(h.url.current())}
11 11 <div class="info_box">
12 12 <span >${_('view')}@rev</span>
13 13 <a href="${c.url_prev}">&laquo;</a>
14 14 ${h.text('at_rev',value=c.rev_nr,size=3)}
15 15 <a href="${c.url_next}">&raquo;</a>
16 16 ${h.submit('view','view')}
17 17 </div>
18 18 ${h.end_form()}
19 19 </div>
20 20 <div class="browser-body">
21 21 <table class="code-browser">
22 22 <thead>
23 23 <tr>
24 24 <th>${_('Name')}</th>
25 25 <th>${_('Size')}</th>
26 26 <th>${_('Mimetype')}</th>
27 27 <th>${_('Revision')}</th>
28 28 <th>${_('Last modified')}</th>
29 29 <th>${_('Last commiter')}</th>
30 30 </tr>
31 31 </thead>
32 32
33 33 % if c.files_list.parent:
34 34 <tr class="parity0">
35 35 <td>
36 36 ${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.files_list.parent.path),class_="browser-dir")}
37 37 </td>
38 38 <td></td>
39 39 <td></td>
40 40 <td></td>
41 41 <td></td>
42 42 <td></td>
43 43 </tr>
44 44 %endif
45 45
46 %for cnt,node in enumerate(c.files_list,1):
47 <tr class="parity${cnt%2}">
46 %for cnt,node in enumerate(c.files_list):
47 <tr class="parity${(cnt+1)%2}">
48 48 <td>
49 49 ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=node.path),class_=file_class(node))}
50 50 </td>
51 51 <td>
52 52 %if node.is_file():
53 53 ${h.format_byte_size(node.size,binary=True)}
54 54 %endif
55 55 </td>
56 56 <td>
57 57 %if node.is_file():
58 58 ${node.mimetype}
59 59 %endif
60 60 </td>
61 61 <td>
62 %if node.is_file():
63 ${node.last_changeset.revision}
64 %endif
62 %if node.is_file():
63 ${node.last_changeset.revision}
64 %endif
65 65 </td>
66 66 <td>
67 %if node.is_file():
68 ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date}
69 %endif
67 %if node.is_file():
68 ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date}
69 %endif
70 70 </td>
71 71 <td>
72 %if node.is_file():
73 ${node.last_changeset.author}
74 %endif
72 %if node.is_file():
73 ${node.last_changeset.author}
74 %endif
75 75 </td>
76 76 </tr>
77 77 %endfor
78 78 </table>
79 79 </div>
80 80 </div> No newline at end of file
@@ -1,584 +1,586 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('summary')}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('summary')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <script type="text/javascript">
21 21 var E = YAHOO.util.Event;
22 22 var D = YAHOO.util.Dom;
23 23
24 24 E.onDOMReady(function(e){
25 25 id = 'clone_url';
26 26 E.addListener(id,'click',function(e){
27 27 D.get('clone_url').select();
28 28 })
29 29 })
30 30 </script>
31 31 <div class="box box-left">
32 32 <!-- box / title -->
33 33 <div class="title">
34 34 ${self.breadcrumbs()}
35 35 </div>
36 36 <!-- end box / title -->
37 37 <div class="form">
38 38 <div class="fields">
39 39
40 40 <div class="field">
41 41 <div class="label">
42 42 <label>${_('Name')}:</label>
43 43 </div>
44 44 <div class="input-short">
45 45 %if c.repo_info.dbrepo.private:
46 46 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private')}" src="/images/icons/lock.png"/>
47 47 %else:
48 48 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public')}" src="/images/icons/lock_open.png"/>
49 49 %endif
50 50 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
51 51 <br/>
52 52 %if c.repo_info.dbrepo.fork:
53 53 <span style="margin-top:5px">
54 54 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
55 55 <img class="icon" alt="${_('public')}"
56 56 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
57 57 src="/images/icons/arrow_divide.png"/>
58 58 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
59 59 </a>
60 60 </span>
61 61 %endif
62 62 </div>
63 63 </div>
64 64
65 65
66 66 <div class="field">
67 67 <div class="label">
68 68 <label>${_('Description')}:</label>
69 69 </div>
70 70 <div class="input-short">
71 71 ${c.repo_info.description}
72 72 </div>
73 73 </div>
74 74
75 75
76 76 <div class="field">
77 77 <div class="label">
78 78 <label>${_('Contact')}:</label>
79 79 </div>
80 80 <div class="input-short">
81 81 <div class="gravatar">
82 82 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
83 83 </div>
84 84 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
85 85 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
86 86 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
87 87 </div>
88 88 </div>
89 89
90 90 <div class="field">
91 91 <div class="label">
92 92 <label>${_('Last change')}:</label>
93 93 </div>
94 94 <div class="input-short">
95 95 ${h.age(c.repo_info.last_change)} - ${h.rfc822date_notz(c.repo_info.last_change)}
96 96 ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author}
97 97
98 98 </div>
99 99 </div>
100 100
101 101 <div class="field">
102 102 <div class="label">
103 103 <label>${_('Clone url')}:</label>
104 104 </div>
105 105 <div class="input-short">
106 106 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
107 107 </div>
108 108 </div>
109 109
110 110 <div class="field">
111 111 <div class="label">
112 112 <label>${_('Trending languages')}:</label>
113 113 </div>
114 114 <div class="input-short">
115 115 <div id="lang_stats">
116 116
117 117 </div>
118 118 <script type="text/javascript">
119 119 var data = ${c.trending_languages|n};
120 120 var total = 0;
121 121 var no_data = true;
122 122 for (k in data){
123 123 total += data[k];
124 124 no_data = false;
125 125 }
126 126 var tbl = document.createElement('table');
127 127 tbl.setAttribute('class','trending_language_tbl');
128 128 for (k in data){
129 129 var tr = document.createElement('tr');
130 130 var percentage = Math.round((data[k]/total*100),2);
131 131 var value = data[k];
132 132 var td1 = document.createElement('td');
133 133 td1.width=150;
134
134 135 var trending_language_label = document.createElement('div');
135 136 trending_language_label.innerHTML = k;
136 137 td1.appendChild(trending_language_label);
137 138
138 139 var td2 = document.createElement('td');
140 td2.setAttribute('style','padding-right: 12px ! important;');
139 141 var trending_language = document.createElement('div');
140 142 trending_language.title = k;
141 143 trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
142 144 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
143 145 trending_language.style.width=percentage+"%";
144 146 td2.appendChild(trending_language);
145 147
146 148 tr.appendChild(td1);
147 149 tr.appendChild(td2);
148 150 tbl.appendChild(tr);
149 151
150 152 }
151 153 if(no_data){
152 154 var tr = document.createElement('tr');
153 155 var td1 = document.createElement('td');
154 156 td1.innerHTML = "${_('No data loaded yet')}";
155 157 tr.appendChild(td1);
156 158 tbl.appendChild(tr);
157 159 }
158 160 YAHOO.util.Dom.get('lang_stats').appendChild(tbl);
159 161 </script>
160 162
161 163 </div>
162 164 </div>
163 165
164 166 <div class="field">
165 167 <div class="label">
166 168 <label>${_('Download')}:</label>
167 169 </div>
168 170 <div class="input-short">
169 171 %for cnt,archive in enumerate(c.repo_info._get_archives()):
170 172 %if cnt >=1:
171 173 |
172 174 %endif
173 175 ${h.link_to(c.repo_info.name+'.'+archive['type'],
174 176 h.url('files_archive_home',repo_name=c.repo_info.name,
175 177 revision='tip',fileformat=archive['extension']),class_="archive_icon")}
176 178 %endfor
177 179 </div>
178 180 </div>
179 181
180 182 <div class="field">
181 183 <div class="label">
182 184 <label>${_('Feeds')}:</label>
183 185 </div>
184 186 <div class="input-short">
185 187 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
186 188 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
187 189 </div>
188 190 </div>
189 191 </div>
190 192 </div>
191 193 </div>
192 194
193 195 <div class="box box-right" style="min-height:455px">
194 196 <!-- box / title -->
195 197 <div class="title">
196 198 <h5>${_('Commit activity by day / author')}</h5>
197 199 </div>
198 200
199 201 <div class="table">
200 202 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
201 203 <div style="clear: both;height: 10px"></div>
202 204 <div id="overview" style="width:560px;height:100px;float:left"></div>
203 205
204 206 <div id="legend_data" style="clear:both;margin-top:10px;">
205 207 <div id="legend_container"></div>
206 208 <div id="legend_choices">
207 209 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
208 210 </div>
209 211 </div>
210 212 <script type="text/javascript">
211 213 /**
212 214 * Plots summary graph
213 215 *
214 216 * @class SummaryPlot
215 217 * @param {from} initial from for detailed graph
216 218 * @param {to} initial to for detailed graph
217 219 * @param {dataset}
218 220 * @param {overview_dataset}
219 221 */
220 222 function SummaryPlot(from,to,dataset,overview_dataset) {
221 223 var initial_ranges = {
222 224 "xaxis":{
223 225 "from":from,
224 226 "to":to,
225 227 },
226 228 };
227 229 var dataset = dataset;
228 230 var overview_dataset = [overview_dataset];
229 231 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
230 232 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
231 233 var plotContainer = YAHOO.util.Dom.get('commit_history');
232 234 var overviewContainer = YAHOO.util.Dom.get('overview');
233 235
234 236 var plot_options = {
235 237 bars: {show:true,align:'center',lineWidth:4},
236 238 legend: {show:true, container:"legend_container"},
237 239 points: {show:true,radius:0,fill:false},
238 240 yaxis: {tickDecimals:0,},
239 241 xaxis: {
240 242 mode: "time",
241 243 timeformat: "%d/%m",
242 244 min:from,
243 245 max:to,
244 246 },
245 247 grid: {
246 248 hoverable: true,
247 249 clickable: true,
248 250 autoHighlight:true,
249 251 color: "#999"
250 252 },
251 253 //selection: {mode: "x"}
252 254 };
253 255 var overview_options = {
254 256 legend:{show:false},
255 257 bars: {show:true,barWidth: 2,},
256 258 shadowSize: 0,
257 259 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
258 260 yaxis: {ticks: 3, min: 0,},
259 261 grid: {color: "#999",},
260 262 selection: {mode: "x"}
261 263 };
262 264
263 265 /**
264 266 *get dummy data needed in few places
265 267 */
266 268 function getDummyData(label){
267 269 return {"label":label,
268 270 "data":[{"time":0,
269 271 "commits":0,
270 272 "added":0,
271 273 "changed":0,
272 274 "removed":0,
273 275 }],
274 276 "schema":["commits"],
275 277 "color":'#ffffff',
276 278 }
277 279 }
278 280
279 281 /**
280 282 * generate checkboxes accordindly to data
281 283 * @param keys
282 284 * @returns
283 285 */
284 286 function generateCheckboxes(data) {
285 287 //append checkboxes
286 288 var i = 0;
287 289 choiceContainerTable.innerHTML = '';
288 290 for(var pos in data) {
289 291
290 292 data[pos].color = i;
291 293 i++;
292 294 if(data[pos].label != ''){
293 295 choiceContainerTable.innerHTML += '<tr><td>'+
294 296 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
295 297 +data[pos].label+
296 298 '</td></tr>';
297 299 }
298 300 }
299 301 }
300 302
301 303 /**
302 304 * ToolTip show
303 305 */
304 306 function showTooltip(x, y, contents) {
305 307 var div=document.getElementById('tooltip');
306 308 if(!div) {
307 309 div = document.createElement('div');
308 310 div.id="tooltip";
309 311 div.style.position="absolute";
310 312 div.style.border='1px solid #fdd';
311 313 div.style.padding='2px';
312 314 div.style.backgroundColor='#fee';
313 315 document.body.appendChild(div);
314 316 }
315 317 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
316 318 div.innerHTML = contents;
317 319 div.style.top=(y + 5) + "px";
318 320 div.style.left=(x + 5) + "px";
319 321
320 322 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
321 323 anim.animate();
322 324 }
323 325
324 326 /**
325 327 * This function will detect if selected period has some changesets for this user
326 328 if it does this data is then pushed for displaying
327 329 Additionally it will only display users that are selected by the checkbox
328 330 */
329 331 function getDataAccordingToRanges(ranges) {
330 332
331 333 var data = [];
332 334 var keys = [];
333 335 for(var key in dataset){
334 336 var push = false;
335 337 //method1 slow !!
336 338 ///*
337 339 for(var ds in dataset[key].data){
338 340 commit_data = dataset[key].data[ds];
339 341 //console.log(key);
340 342 //console.log(new Date(commit_data.time*1000));
341 343 //console.log(new Date(ranges.xaxis.from*1000));
342 344 //console.log(new Date(ranges.xaxis.to*1000));
343 345 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
344 346 push = true;
345 347 break;
346 348 }
347 349 }
348 350 //*/
349 351 /*//method2 sorted commit data !!!
350 352 var first_commit = dataset[key].data[0].time;
351 353 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
352 354
353 355 console.log(first_commit);
354 356 console.log(last_commit);
355 357
356 358 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
357 359 push = true;
358 360 }
359 361 */
360 362 if(push){
361 363 data.push(dataset[key]);
362 364 }
363 365 }
364 366 if(data.length >= 1){
365 367 return data;
366 368 }
367 369 else{
368 370 //just return dummy data for graph to plot itself
369 371 return [getDummyData('')];
370 372 }
371 373
372 374 }
373 375
374 376 /**
375 377 * redraw using new checkbox data
376 378 */
377 379 function plotchoiced(e,args){
378 380 var cur_data = args[0];
379 381 var cur_ranges = args[1];
380 382
381 383 var new_data = [];
382 384 var inputs = choiceContainer.getElementsByTagName("input");
383 385
384 386 //show only checked labels
385 387 for(var i=0; i<inputs.length; i++) {
386 388 var checkbox_key = inputs[i].name;
387 389
388 390 if(inputs[i].checked){
389 391 for(var d in cur_data){
390 392 if(cur_data[d].label == checkbox_key){
391 393 new_data.push(cur_data[d]);
392 394 }
393 395 }
394 396 }
395 397 else{
396 398 //push dummy data to not hide the label
397 399 new_data.push(getDummyData(checkbox_key));
398 400 }
399 401 }
400 402
401 403 var new_options = YAHOO.lang.merge(plot_options, {
402 404 xaxis: {
403 405 min: cur_ranges.xaxis.from,
404 406 max: cur_ranges.xaxis.to,
405 407 mode:"time",
406 408 timeformat: "%d/%m",
407 409 }
408 410 });
409 411 if (!new_data){
410 412 new_data = [[0,1]];
411 413 }
412 414 // do the zooming
413 415 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
414 416
415 417 plot.subscribe("plotselected", plotselected);
416 418
417 419 //resubscribe plothover
418 420 plot.subscribe("plothover", plothover);
419 421
420 422 // don't fire event on the overview to prevent eternal loop
421 423 overview.setSelection(cur_ranges, true);
422 424
423 425 }
424 426
425 427 /**
426 428 * plot only selected items from overview
427 429 * @param ranges
428 430 * @returns
429 431 */
430 432 function plotselected(ranges,cur_data) {
431 433 //updates the data for new plot
432 434 data = getDataAccordingToRanges(ranges);
433 435 generateCheckboxes(data);
434 436
435 437 var new_options = YAHOO.lang.merge(plot_options, {
436 438 xaxis: {
437 439 min: ranges.xaxis.from,
438 440 max: ranges.xaxis.to,
439 441 mode:"time",
440 442 timeformat: "%d/%m",
441 443 }
442 444 });
443 445 // do the zooming
444 446 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
445 447
446 448 plot.subscribe("plotselected", plotselected);
447 449
448 450 //resubscribe plothover
449 451 plot.subscribe("plothover", plothover);
450 452
451 453 // don't fire event on the overview to prevent eternal loop
452 454 overview.setSelection(ranges, true);
453 455
454 456 //resubscribe choiced
455 457 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
456 458 }
457 459
458 460 var previousPoint = null;
459 461
460 462 function plothover(o) {
461 463 var pos = o.pos;
462 464 var item = o.item;
463 465
464 466 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
465 467 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
466 468 if (item) {
467 469 if (previousPoint != item.datapoint) {
468 470 previousPoint = item.datapoint;
469 471
470 472 var tooltip = YAHOO.util.Dom.get("tooltip");
471 473 if(tooltip) {
472 474 tooltip.parentNode.removeChild(tooltip);
473 475 }
474 476 var x = item.datapoint.x.toFixed(2);
475 477 var y = item.datapoint.y.toFixed(2);
476 478
477 479 if (!item.series.label){
478 480 item.series.label = 'commits';
479 481 }
480 482 var d = new Date(x*1000);
481 483 var fd = d.toDateString()
482 484 var nr_commits = parseInt(y);
483 485
484 486 var cur_data = dataset[item.series.label].data[item.dataIndex];
485 487 var added = cur_data.added;
486 488 var changed = cur_data.changed;
487 489 var removed = cur_data.removed;
488 490
489 491 var nr_commits_suffix = " ${_('commits')} ";
490 492 var added_suffix = " ${_('files added')} ";
491 493 var changed_suffix = " ${_('files changed')} ";
492 494 var removed_suffix = " ${_('files removed')} ";
493 495
494 496
495 497 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
496 498 if(added==1){added_suffix=" ${_('file added')} ";}
497 499 if(changed==1){changed_suffix=" ${_('file changed')} ";}
498 500 if(removed==1){removed_suffix=" ${_('file removed')} ";}
499 501
500 502 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
501 503 +'<br/>'+
502 504 nr_commits + nr_commits_suffix+'<br/>'+
503 505 added + added_suffix +'<br/>'+
504 506 changed + changed_suffix + '<br/>'+
505 507 removed + removed_suffix + '<br/>');
506 508 }
507 509 }
508 510 else {
509 511 var tooltip = YAHOO.util.Dom.get("tooltip");
510 512
511 513 if(tooltip) {
512 514 tooltip.parentNode.removeChild(tooltip);
513 515 }
514 516 previousPoint = null;
515 517 }
516 518 }
517 519
518 520 /**
519 521 * MAIN EXECUTION
520 522 */
521 523
522 524 var data = getDataAccordingToRanges(initial_ranges);
523 525 generateCheckboxes(data);
524 526
525 527 //main plot
526 528 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
527 529
528 530 //overview
529 531 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
530 532
531 533 //show initial selection on overview
532 534 overview.setSelection(initial_ranges);
533 535
534 536 plot.subscribe("plotselected", plotselected);
535 537
536 538 overview.subscribe("plotselected", function (ranges) {
537 539 plot.setSelection(ranges);
538 540 });
539 541
540 542 plot.subscribe("plothover", plothover);
541 543
542 544 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
543 545 }
544 546 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
545 547 </script>
546 548
547 549 </div>
548 550 </div>
549 551
550 552 <div class="box">
551 553 <div class="title">
552 554 <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('changelog_home',repo_name=c.repo_name))}</div>
553 555 </div>
554 556 <div class="table">
555 557 <%include file='../shortlog/shortlog_data.html'/>
556 558 %if c.repo_changesets:
557 559 ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
558 560 %endif
559 561 </div>
560 562 </div>
561 563 <div class="box">
562 564 <div class="title">
563 565 <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
564 566 </div>
565 567 <div class="table">
566 568 <%include file='../tags/tags_data.html'/>
567 569 %if c.repo_changesets:
568 570 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
569 571 %endif
570 572 </div>
571 573 </div>
572 574 <div class="box">
573 575 <div class="title">
574 576 <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
575 577 </div>
576 578 <div class="table">
577 579 <%include file='../branches/branches_data.html'/>
578 580 %if c.repo_changesets:
579 581 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
580 582 %endif
581 583 </div>
582 584 </div>
583 585
584 586 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now