##// END OF EJS Templates
Correct capitalization and improved English text in the UI
Na'Tosha Bard -
r4527:dacdea9f default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,587 +1,587 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # Kallithea - Development config: #
3 # Kallithea - Development config: #
4 # listening on *:5000 #
4 # listening on *:5000 #
5 # sqlite and kallithea.db #
5 # sqlite and kallithea.db #
6 # initial_repo_scan = true #
6 # initial_repo_scan = true #
7 # set debug = true #
7 # set debug = true #
8 # verbose and colorful logging #
8 # verbose and colorful logging #
9 # #
9 # #
10 # The %(here)s variable will be replaced with the parent directory of this file#
10 # The %(here)s variable will be replaced with the parent directory of this file#
11 ################################################################################
11 ################################################################################
12 ################################################################################
12 ################################################################################
13
13
14 [DEFAULT]
14 [DEFAULT]
15 debug = true
15 debug = true
16 pdebug = false
16 pdebug = false
17
17
18 ################################################################################
18 ################################################################################
19 ## Uncomment and replace with the address which should receive ##
19 ## Uncomment and replace with the address which should receive ##
20 ## any error reports after application crash ##
20 ## any error reports after application crash ##
21 ## Additionally those settings will be used by Kallithea mailing system ##
21 ## Additionally those settings will be used by Kallithea mailing system ##
22 ################################################################################
22 ################################################################################
23 #email_to = admin@localhost
23 #email_to = admin@localhost
24 #error_email_from = paste_error@localhost
24 #error_email_from = paste_error@localhost
25 #app_email_from = kallithea-noreply@localhost
25 #app_email_from = kallithea-noreply@localhost
26 #error_message =
26 #error_message =
27 #email_prefix = [Kallithea]
27 #email_prefix = [Kallithea]
28
28
29 #smtp_server = mail.server.com
29 #smtp_server = mail.server.com
30 #smtp_username =
30 #smtp_username =
31 #smtp_password =
31 #smtp_password =
32 #smtp_port =
32 #smtp_port =
33 #smtp_use_tls = false
33 #smtp_use_tls = false
34 #smtp_use_ssl = true
34 #smtp_use_ssl = true
35 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
35 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
36 #smtp_auth =
36 #smtp_auth =
37
37
38 [server:main]
38 [server:main]
39 ## PASTE ##
39 ## PASTE ##
40 #use = egg:Paste#http
40 #use = egg:Paste#http
41 ## nr of worker threads to spawn
41 ## nr of worker threads to spawn
42 #threadpool_workers = 5
42 #threadpool_workers = 5
43 ## max request before thread respawn
43 ## max request before thread respawn
44 #threadpool_max_requests = 10
44 #threadpool_max_requests = 10
45 ## option to use threads of process
45 ## option to use threads of process
46 #use_threadpool = true
46 #use_threadpool = true
47
47
48 ## WAITRESS ##
48 ## WAITRESS ##
49 use = egg:waitress#main
49 use = egg:waitress#main
50 ## number of worker threads
50 ## number of worker threads
51 threads = 5
51 threads = 5
52 ## MAX BODY SIZE 100GB
52 ## MAX BODY SIZE 100GB
53 max_request_body_size = 107374182400
53 max_request_body_size = 107374182400
54 ## use poll instead of select, fixes fd limits, may not work on old
54 ## use poll instead of select, fixes fd limits, may not work on old
55 ## windows systems.
55 ## windows systems.
56 #asyncore_use_poll = True
56 #asyncore_use_poll = True
57
57
58 ## GUNICORN ##
58 ## GUNICORN ##
59 #use = egg:gunicorn#main
59 #use = egg:gunicorn#main
60 ## number of process workers. You must set `instance_id = *` when this option
60 ## number of process workers. You must set `instance_id = *` when this option
61 ## is set to more than one worker
61 ## is set to more than one worker
62 #workers = 1
62 #workers = 1
63 ## process name
63 ## process name
64 #proc_name = kallithea
64 #proc_name = kallithea
65 ## type of worker class, one of sync, eventlet, gevent, tornado
65 ## type of worker class, one of sync, eventlet, gevent, tornado
66 ## recommended for bigger setup is using of of other than sync one
66 ## recommended for bigger setup is using of of other than sync one
67 #worker_class = sync
67 #worker_class = sync
68 #max_requests = 1000
68 #max_requests = 1000
69 ## ammount of time a worker can handle request before it gets killed and
69 ## ammount of time a worker can handle request before it gets killed and
70 ## restarted
70 ## restarted
71 #timeout = 3600
71 #timeout = 3600
72
72
73 ## UWSGI ##
73 ## UWSGI ##
74 ## run with uwsgi --ini-paste-logged <inifile.ini>
74 ## run with uwsgi --ini-paste-logged <inifile.ini>
75 #[uwsgi]
75 #[uwsgi]
76 #socket = /tmp/uwsgi.sock
76 #socket = /tmp/uwsgi.sock
77 #master = true
77 #master = true
78 #http = 127.0.0.1:5000
78 #http = 127.0.0.1:5000
79
79
80 ## set as deamon and redirect all output to file
80 ## set as deamon and redirect all output to file
81 #daemonize = ./uwsgi_kallithea.log
81 #daemonize = ./uwsgi_kallithea.log
82
82
83 ## master process PID
83 ## master process PID
84 #pidfile = ./uwsgi_kallithea.pid
84 #pidfile = ./uwsgi_kallithea.pid
85
85
86 ## stats server with workers statistics, use uwsgitop
86 ## stats server with workers statistics, use uwsgitop
87 ## for monitoring, `uwsgitop 127.0.0.1:1717`
87 ## for monitoring, `uwsgitop 127.0.0.1:1717`
88 #stats = 127.0.0.1:1717
88 #stats = 127.0.0.1:1717
89 #memory-report = true
89 #memory-report = true
90
90
91 ## log 5XX errors
91 ## log 5XX errors
92 #log-5xx = true
92 #log-5xx = true
93
93
94 ## Set the socket listen queue size.
94 ## Set the socket listen queue size.
95 #listen = 256
95 #listen = 256
96
96
97 ## Gracefully Reload workers after the specified amount of managed requests
97 ## Gracefully Reload workers after the specified amount of managed requests
98 ## (avoid memory leaks).
98 ## (avoid memory leaks).
99 #max-requests = 1000
99 #max-requests = 1000
100
100
101 ## enable large buffers
101 ## enable large buffers
102 #buffer-size=65535
102 #buffer-size=65535
103
103
104 ## socket and http timeouts ##
104 ## socket and http timeouts ##
105 #http-timeout=3600
105 #http-timeout=3600
106 #socket-timeout=3600
106 #socket-timeout=3600
107
107
108 ## Log requests slower than the specified number of milliseconds.
108 ## Log requests slower than the specified number of milliseconds.
109 #log-slow = 10
109 #log-slow = 10
110
110
111 ## Exit if no app can be loaded.
111 ## Exit if no app can be loaded.
112 #need-app = true
112 #need-app = true
113
113
114 ## Set lazy mode (load apps in workers instead of master).
114 ## Set lazy mode (load apps in workers instead of master).
115 #lazy = true
115 #lazy = true
116
116
117 ## scaling ##
117 ## scaling ##
118 ## set cheaper algorithm to use, if not set default will be used
118 ## set cheaper algorithm to use, if not set default will be used
119 #cheaper-algo = spare
119 #cheaper-algo = spare
120
120
121 ## minimum number of workers to keep at all times
121 ## minimum number of workers to keep at all times
122 #cheaper = 1
122 #cheaper = 1
123
123
124 ## number of workers to spawn at startup
124 ## number of workers to spawn at startup
125 #cheaper-initial = 1
125 #cheaper-initial = 1
126
126
127 ## maximum number of workers that can be spawned
127 ## maximum number of workers that can be spawned
128 #workers = 4
128 #workers = 4
129
129
130 ## how many workers should be spawned at a time
130 ## how many workers should be spawned at a time
131 #cheaper-step = 1
131 #cheaper-step = 1
132
132
133 ## COMMON ##
133 ## COMMON ##
134 host = 0.0.0.0
134 host = 0.0.0.0
135 port = 5000
135 port = 5000
136
136
137 ## prefix middleware for rc
137 ## prefix middleware for rc
138 #[filter:proxy-prefix]
138 #[filter:proxy-prefix]
139 #use = egg:PasteDeploy#prefix
139 #use = egg:PasteDeploy#prefix
140 #prefix = /<your-prefix>
140 #prefix = /<your-prefix>
141
141
142 [app:main]
142 [app:main]
143 use = egg:kallithea
143 use = egg:kallithea
144 ## enable proxy prefix middleware
144 ## enable proxy prefix middleware
145 #filter-with = proxy-prefix
145 #filter-with = proxy-prefix
146
146
147 full_stack = true
147 full_stack = true
148 static_files = true
148 static_files = true
149 ## Available Languages:
149 ## Available Languages:
150 ## de en fr ja pl pt_BR ru zh_CN zh_TW
150 ## de en fr ja pl pt_BR ru zh_CN zh_TW
151 lang = en
151 lang = en
152 cache_dir = %(here)s/data
152 cache_dir = %(here)s/data
153 index_dir = %(here)s/data/index
153 index_dir = %(here)s/data/index
154
154
155 ## perform a full repository scan on each server start, this should be
155 ## perform a full repository scan on each server start, this should be
156 ## set to false after first startup, to allow faster server restarts.
156 ## set to false after first startup, to allow faster server restarts.
157 #initial_repo_scan = false
157 #initial_repo_scan = false
158 initial_repo_scan = true
158 initial_repo_scan = true
159
159
160 ## uncomment and set this path to use archive download cache
160 ## uncomment and set this path to use archive download cache
161 archive_cache_dir = %(here)s/tarballcache
161 archive_cache_dir = %(here)s/tarballcache
162
162
163 ## change this to unique ID for security
163 ## change this to unique ID for security
164 app_instance_uuid = development-not-secret
164 app_instance_uuid = development-not-secret
165
165
166 ## cut off limit for large diffs (size in bytes)
166 ## cut off limit for large diffs (size in bytes)
167 cut_off_limit = 256000
167 cut_off_limit = 256000
168
168
169 ## use cache version of scm repo everywhere
169 ## use cache version of scm repo everywhere
170 vcs_full_cache = true
170 vcs_full_cache = true
171
171
172 ## force https in Kallithea, fixes https redirects, assumes it's always https
172 ## force https in Kallithea, fixes https redirects, assumes it's always https
173 force_https = false
173 force_https = false
174
174
175 ## use Strict-Transport-Security headers
175 ## use Strict-Transport-Security headers
176 use_htsts = false
176 use_htsts = false
177
177
178 ## number of commits stats will parse on each iteration
178 ## number of commits stats will parse on each iteration
179 commit_parse_limit = 25
179 commit_parse_limit = 25
180
180
181 ## path to git executable
181 ## path to git executable
182 git_path = git
182 git_path = git
183
183
184 ## git rev filter option, --all is the default filter, if you need to
184 ## git rev filter option, --all is the default filter, if you need to
185 ## hide all refs in changelog switch this to --branches --tags
185 ## hide all refs in changelog switch this to --branches --tags
186 #git_rev_filter = --branches --tags
186 #git_rev_filter = --branches --tags
187
187
188 ## RSS feed options
188 ## RSS feed options
189 rss_cut_off_limit = 256000
189 rss_cut_off_limit = 256000
190 rss_items_per_page = 10
190 rss_items_per_page = 10
191 rss_include_diff = false
191 rss_include_diff = false
192
192
193 ## options for showing and identifying changesets
193 ## options for showing and identifying changesets
194 show_sha_length = 12
194 show_sha_length = 12
195 show_revision_number = true
195 show_revision_number = true
196
196
197 ## gist URL alias, used to create nicer urls for gist. This should be an
197 ## gist URL alias, used to create nicer urls for gist. This should be an
198 ## url that does rewrites to _admin/gists/<gistid>.
198 ## url that does rewrites to _admin/gists/<gistid>.
199 ## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
199 ## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
200 ## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
200 ## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
201 gist_alias_url =
201 gist_alias_url =
202
202
203 ## white list of API enabled controllers. This allows to add list of
203 ## white list of API enabled controllers. This allows to add list of
204 ## controllers to which access will be enabled by api_key. eg: to enable
204 ## controllers to which access will be enabled by api_key. eg: to enable
205 ## api access to raw_files put `FilesController:raw`, to enable access to patches
205 ## api access to raw_files put `FilesController:raw`, to enable access to patches
206 ## add `ChangesetController:changeset_patch`. This list should be "," separated
206 ## add `ChangesetController:changeset_patch`. This list should be "," separated
207 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
207 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
208 ## Recommended settings below are commented out:
208 ## Recommended settings below are commented out:
209 api_access_controllers_whitelist =
209 api_access_controllers_whitelist =
210 # ChangesetController:changeset_patch,
210 # ChangesetController:changeset_patch,
211 # ChangesetController:changeset_raw,
211 # ChangesetController:changeset_raw,
212 # FilesController:raw,
212 # FilesController:raw,
213 # FilesController:archivefile
213 # FilesController:archivefile
214
214
215 ## default encoding used to convert from and to unicode
215 ## default encoding used to convert from and to unicode
216 ## can be also a comma seperated list of encoding in case of mixed encodings
216 ## can be also a comma seperated list of encoding in case of mixed encodings
217 default_encoding = utf8
217 default_encoding = utf8
218
218
219 ## issue tracker for Kallithea (leave blank to disable, absent for default)
219 ## issue tracker for Kallithea (leave blank to disable, absent for default)
220 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
220 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
221
221
222 ## issue tracking mapping for commits messages
222 ## issue tracking mapping for commits messages
223 ## comment out issue_pat, issue_server, issue_prefix to enable
223 ## comment out issue_pat, issue_server, issue_prefix to enable
224
224
225 ## pattern to get the issues from commit messages
225 ## pattern to get the issues from commit messages
226 ## default one used here is #<numbers> with a regex passive group for `#`
226 ## default one used here is #<numbers> with a regex passive group for `#`
227 ## {id} will be all groups matched from this pattern
227 ## {id} will be all groups matched from this pattern
228
228
229 issue_pat = (?:\s*#)(\d+)
229 issue_pat = (?:\s*#)(\d+)
230
230
231 ## server url to the issue, each {id} will be replaced with match
231 ## server url to the issue, each {id} will be replaced with match
232 ## fetched from the regex and {repo} is replaced with full repository name
232 ## fetched from the regex and {repo} is replaced with full repository name
233 ## including groups {repo_name} is replaced with just name of repo
233 ## including groups {repo_name} is replaced with just name of repo
234
234
235 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
235 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
236
236
237 ## prefix to add to link to indicate it's an url
237 ## prefix to add to link to indicate it's an url
238 ## #314 will be replaced by <issue_prefix><id>
238 ## #314 will be replaced by <issue_prefix><id>
239
239
240 issue_prefix = #
240 issue_prefix = #
241
241
242 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
242 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
243 ## multiple patterns, to other issues server, wiki or others
243 ## multiple patterns, to other issues server, wiki or others
244 ## below an example how to create a wiki pattern
244 ## below an example how to create a wiki pattern
245 # wiki-some-id -> https://mywiki.com/some-id
245 # wiki-some-id -> https://mywiki.com/some-id
246
246
247 #issue_pat_wiki = (?:wiki-)(.+)
247 #issue_pat_wiki = (?:wiki-)(.+)
248 #issue_server_link_wiki = https://mywiki.com/{id}
248 #issue_server_link_wiki = https://mywiki.com/{id}
249 #issue_prefix_wiki = WIKI-
249 #issue_prefix_wiki = WIKI-
250
250
251
251
252 ## instance-id prefix
252 ## instance-id prefix
253 ## a prefix key for this instance used for cache invalidation when running
253 ## a prefix key for this instance used for cache invalidation when running
254 ## multiple instances of kallithea, make sure it's globally unique for
254 ## multiple instances of kallithea, make sure it's globally unique for
255 ## all running kallithea instances. Leave empty if you don't use it
255 ## all running kallithea instances. Leave empty if you don't use it
256 instance_id =
256 instance_id =
257
257
258 ## alternative return HTTP header for failed authentication. Default HTTP
258 ## alternative return HTTP header for failed authentication. Default HTTP
259 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
259 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
260 ## handling that. Set this variable to 403 to return HTTPForbidden
260 ## handling that. Set this variable to 403 to return HTTPForbidden
261 auth_ret_code =
261 auth_ret_code =
262
262
263 ## locking return code. When repository is locked return this HTTP code. 2XX
263 ## locking return code. When repository is locked return this HTTP code. 2XX
264 ## codes don't break the transactions while 4XX codes do
264 ## codes don't break the transactions while 4XX codes do
265 lock_ret_code = 423
265 lock_ret_code = 423
266
266
267 ## allows to change the repository location in settings page
267 ## allows to change the repository location in settings page
268 allow_repo_location_change = True
268 allow_repo_location_change = True
269
269
270 ## allows to setup custom hooks in settings page
270 ## allows to setup custom hooks in settings page
271 allow_custom_hooks_settings = True
271 allow_custom_hooks_settings = True
272
272
273
273
274 ####################################
274 ####################################
275 ### CELERY CONFIG ####
275 ### CELERY CONFIG ####
276 ####################################
276 ####################################
277
277
278 use_celery = false
278 use_celery = false
279 broker.host = localhost
279 broker.host = localhost
280 broker.vhost = rabbitmqhost
280 broker.vhost = rabbitmqhost
281 broker.port = 5672
281 broker.port = 5672
282 broker.user = rabbitmq
282 broker.user = rabbitmq
283 broker.password = qweqwe
283 broker.password = qweqwe
284
284
285 celery.imports = kallithea.lib.celerylib.tasks
285 celery.imports = kallithea.lib.celerylib.tasks
286
286
287 celery.result.backend = amqp
287 celery.result.backend = amqp
288 celery.result.dburi = amqp://
288 celery.result.dburi = amqp://
289 celery.result.serialier = json
289 celery.result.serialier = json
290
290
291 #celery.send.task.error.emails = true
291 #celery.send.task.error.emails = true
292 #celery.amqp.task.result.expires = 18000
292 #celery.amqp.task.result.expires = 18000
293
293
294 celeryd.concurrency = 2
294 celeryd.concurrency = 2
295 #celeryd.log.file = celeryd.log
295 #celeryd.log.file = celeryd.log
296 celeryd.log.level = debug
296 celeryd.log.level = debug
297 celeryd.max.tasks.per.child = 1
297 celeryd.max.tasks.per.child = 1
298
298
299 ## tasks will never be sent to the queue, but executed locally instead.
299 ## tasks will never be sent to the queue, but executed locally instead.
300 celery.always.eager = false
300 celery.always.eager = false
301
301
302 ####################################
302 ####################################
303 ### BEAKER CACHE ####
303 ### BEAKER CACHE ####
304 ####################################
304 ####################################
305
305
306 beaker.cache.data_dir=%(here)s/data/cache/data
306 beaker.cache.data_dir=%(here)s/data/cache/data
307 beaker.cache.lock_dir=%(here)s/data/cache/lock
307 beaker.cache.lock_dir=%(here)s/data/cache/lock
308
308
309 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
309 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
310
310
311 beaker.cache.super_short_term.type=memory
311 beaker.cache.super_short_term.type=memory
312 beaker.cache.super_short_term.expire=10
312 beaker.cache.super_short_term.expire=10
313 beaker.cache.super_short_term.key_length = 256
313 beaker.cache.super_short_term.key_length = 256
314
314
315 beaker.cache.short_term.type=memory
315 beaker.cache.short_term.type=memory
316 beaker.cache.short_term.expire=60
316 beaker.cache.short_term.expire=60
317 beaker.cache.short_term.key_length = 256
317 beaker.cache.short_term.key_length = 256
318
318
319 beaker.cache.long_term.type=memory
319 beaker.cache.long_term.type=memory
320 beaker.cache.long_term.expire=36000
320 beaker.cache.long_term.expire=36000
321 beaker.cache.long_term.key_length = 256
321 beaker.cache.long_term.key_length = 256
322
322
323 beaker.cache.sql_cache_short.type=memory
323 beaker.cache.sql_cache_short.type=memory
324 beaker.cache.sql_cache_short.expire=10
324 beaker.cache.sql_cache_short.expire=10
325 beaker.cache.sql_cache_short.key_length = 256
325 beaker.cache.sql_cache_short.key_length = 256
326
326
327 beaker.cache.sql_cache_med.type=memory
327 beaker.cache.sql_cache_med.type=memory
328 beaker.cache.sql_cache_med.expire=360
328 beaker.cache.sql_cache_med.expire=360
329 beaker.cache.sql_cache_med.key_length = 256
329 beaker.cache.sql_cache_med.key_length = 256
330
330
331 beaker.cache.sql_cache_long.type=file
331 beaker.cache.sql_cache_long.type=file
332 beaker.cache.sql_cache_long.expire=3600
332 beaker.cache.sql_cache_long.expire=3600
333 beaker.cache.sql_cache_long.key_length = 256
333 beaker.cache.sql_cache_long.key_length = 256
334
334
335 ####################################
335 ####################################
336 ### BEAKER SESSION ####
336 ### BEAKER SESSION ####
337 ####################################
337 ####################################
338 ## Type of storage used for the session, current types are
338 ## Type of storage used for the session, current types are
339 ## dbm, file, memcached, database, and memory.
339 ## dbm, file, memcached, database, and memory.
340 ## The storage uses the Container API
340 ## The storage uses the Container API
341 ## that is also used by the cache system.
341 ## that is also used by the cache system.
342
342
343 ## db session ##
343 ## db session ##
344 #beaker.session.type = ext:database
344 #beaker.session.type = ext:database
345 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
345 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
346 #beaker.session.table_name = db_session
346 #beaker.session.table_name = db_session
347
347
348 ## encrypted cookie client side session, good for many instances ##
348 ## encrypted cookie client side session, good for many instances ##
349 #beaker.session.type = cookie
349 #beaker.session.type = cookie
350
350
351 ## file based cookies (default) ##
351 ## file based cookies (default) ##
352 #beaker.session.type = file
352 #beaker.session.type = file
353
353
354 beaker.session.key = kallithea
354 beaker.session.key = kallithea
355 beaker.session.secret = development-not-secret
355 beaker.session.secret = development-not-secret
356
356
357 ## Secure encrypted cookie. Requires AES and AES python libraries
357 ## Secure encrypted cookie. Requires AES and AES python libraries
358 ## you must disable beaker.session.secret to use this
358 ## you must disable beaker.session.secret to use this
359 #beaker.session.encrypt_key = <key_for_encryption>
359 #beaker.session.encrypt_key = <key_for_encryption>
360 #beaker.session.validate_key = <validation_key>
360 #beaker.session.validate_key = <validation_key>
361
361
362 ## sets session as invalid if it haven't been accessed for given amount of time
362 ## sets session as invalid if it haven't been accessed for given amount of time
363 beaker.session.timeout = 2592000
363 beaker.session.timeout = 2592000
364 beaker.session.httponly = true
364 beaker.session.httponly = true
365 #beaker.session.cookie_path = /<your-prefix>
365 #beaker.session.cookie_path = /<your-prefix>
366
366
367 ## uncomment for https secure cookie
367 ## uncomment for https secure cookie
368 beaker.session.secure = false
368 beaker.session.secure = false
369
369
370 ## auto save the session to not to use .save()
370 ## auto save the session to not to use .save()
371 beaker.session.auto = False
371 beaker.session.auto = False
372
372
373 ## default cookie expiration time in seconds `true` expire at browser close ##
373 ## default cookie expiration time in seconds `true` expire at browser close ##
374 #beaker.session.cookie_expires = 3600
374 #beaker.session.cookie_expires = 3600
375
375
376
376
377 ############################
377 ############################
378 ## ERROR HANDLING SYSTEMS ##
378 ## ERROR HANDLING SYSTEMS ##
379 ############################
379 ############################
380
380
381 ####################
381 ####################
382 ### [errormator] ###
382 ### [errormator] ###
383 ####################
383 ####################
384
384
385 ## Errormator is tailored to work with Kallithea, see
385 ## Errormator is tailored to work with Kallithea, see
386 ## http://errormator.com for details how to obtain an account
386 ## http://errormator.com for details how to obtain an account
387 ## you must install python package `errormator_client` to make it work
387 ## you must install python package `errormator_client` to make it work
388
388
389 ## errormator enabled
389 ## errormator enabled
390 errormator = false
390 errormator = false
391
391
392 errormator.server_url = https://api.errormator.com
392 errormator.server_url = https://api.errormator.com
393 errormator.api_key = YOUR_API_KEY
393 errormator.api_key = YOUR_API_KEY
394
394
395 ## TWEAK AMOUNT OF INFO SENT HERE
395 ## TWEAK AMOUNT OF INFO SENT HERE
396
396
397 ## enables 404 error logging (default False)
397 ## enables 404 error logging (default False)
398 errormator.report_404 = false
398 errormator.report_404 = false
399
399
400 ## time in seconds after request is considered being slow (default 1)
400 ## time in seconds after request is considered being slow (default 1)
401 errormator.slow_request_time = 1
401 errormator.slow_request_time = 1
402
402
403 ## record slow requests in application
403 ## record slow requests in application
404 ## (needs to be enabled for slow datastore recording and time tracking)
404 ## (needs to be enabled for slow datastore recording and time tracking)
405 errormator.slow_requests = true
405 errormator.slow_requests = true
406
406
407 ## enable hooking to application loggers
407 ## enable hooking to application loggers
408 # errormator.logging = true
408 # errormator.logging = true
409
409
410 ## minimum log level for log capture
410 ## minimum log level for log capture
411 # errormator.logging.level = WARNING
411 # errormator.logging.level = WARNING
412
412
413 ## send logs only from erroneous/slow requests
413 ## send logs only from erroneous/slow requests
414 ## (saves API quota for intensive logging)
414 ## (saves API quota for intensive logging)
415 errormator.logging_on_error = false
415 errormator.logging_on_error = false
416
416
417 ## list of additonal keywords that should be grabbed from environ object
417 ## list of additonal keywords that should be grabbed from environ object
418 ## can be string with comma separated list of words in lowercase
418 ## can be string with comma separated list of words in lowercase
419 ## (by default client will always send following info:
419 ## (by default client will always send following info:
420 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
420 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
421 ## start with HTTP* this list be extended with additional keywords here
421 ## start with HTTP* this list be extended with additional keywords here
422 errormator.environ_keys_whitelist =
422 errormator.environ_keys_whitelist =
423
423
424
424
425 ## list of keywords that should be blanked from request object
425 ## list of keywords that should be blanked from request object
426 ## can be string with comma separated list of words in lowercase
426 ## can be string with comma separated list of words in lowercase
427 ## (by default client will always blank keys that contain following words
427 ## (by default client will always blank keys that contain following words
428 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
428 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
429 ## this list be extended with additional keywords set here
429 ## this list be extended with additional keywords set here
430 errormator.request_keys_blacklist =
430 errormator.request_keys_blacklist =
431
431
432
432
433 ## list of namespaces that should be ignores when gathering log entries
433 ## list of namespaces that should be ignores when gathering log entries
434 ## can be string with comma separated list of namespaces
434 ## can be string with comma separated list of namespaces
435 ## (by default the client ignores own entries: errormator_client.client)
435 ## (by default the client ignores own entries: errormator_client.client)
436 errormator.log_namespace_blacklist =
436 errormator.log_namespace_blacklist =
437
437
438
438
439 ################
439 ################
440 ### [sentry] ###
440 ### [sentry] ###
441 ################
441 ################
442
442
443 ## sentry is a alternative open source error aggregator
443 ## sentry is a alternative open source error aggregator
444 ## you must install python packages `sentry` and `raven` to enable
444 ## you must install python packages `sentry` and `raven` to enable
445
445
446 sentry.dsn = YOUR_DNS
446 sentry.dsn = YOUR_DNS
447 sentry.servers =
447 sentry.servers =
448 sentry.name =
448 sentry.name =
449 sentry.key =
449 sentry.key =
450 sentry.public_key =
450 sentry.public_key =
451 sentry.secret_key =
451 sentry.secret_key =
452 sentry.project =
452 sentry.project =
453 sentry.site =
453 sentry.site =
454 sentry.include_paths =
454 sentry.include_paths =
455 sentry.exclude_paths =
455 sentry.exclude_paths =
456
456
457
457
458 ################################################################################
458 ################################################################################
459 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
459 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
460 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
460 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
461 ## execute malicious code after an exception is raised. ##
461 ## execute malicious code after an exception is raised. ##
462 ################################################################################
462 ################################################################################
463 #set debug = false
463 #set debug = false
464 set debug = true
464 set debug = true
465
465
466 ##################################
466 ##################################
467 ### LOGVIEW CONFIG ###
467 ### LOGVIEW CONFIG ###
468 ##################################
468 ##################################
469
469
470 logview.sqlalchemy = #faa
470 logview.sqlalchemy = #faa
471 logview.pylons.templating = #bfb
471 logview.pylons.templating = #bfb
472 logview.pylons.util = #eee
472 logview.pylons.util = #eee
473
473
474 #########################################################
474 #########################################################
475 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
475 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
476 #########################################################
476 #########################################################
477
477
478 # SQLITE [default]
478 # SQLITE [default]
479 sqlalchemy.db1.url = sqlite:///%(here)s/kallithea.db?timeout=60
479 sqlalchemy.db1.url = sqlite:///%(here)s/kallithea.db?timeout=60
480
480
481 # POSTGRESQL
481 # POSTGRESQL
482 # sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
482 # sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
483
483
484 # MySQL
484 # MySQL
485 # sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
485 # sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
486
486
487 # see sqlalchemy docs for others
487 # see sqlalchemy docs for others
488
488
489 sqlalchemy.db1.echo = false
489 sqlalchemy.db1.echo = false
490 sqlalchemy.db1.pool_recycle = 3600
490 sqlalchemy.db1.pool_recycle = 3600
491 sqlalchemy.db1.convert_unicode = true
491 sqlalchemy.db1.convert_unicode = true
492
492
493 ################################
493 ################################
494 ### LOGGING CONFIGURATION ####
494 ### LOGGING CONFIGURATION ####
495 ################################
495 ################################
496
496
497 [loggers]
497 [loggers]
498 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
498 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
499
499
500 [handlers]
500 [handlers]
501 keys = console, console_sql
501 keys = console, console_sql
502
502
503 [formatters]
503 [formatters]
504 keys = generic, color_formatter, color_formatter_sql
504 keys = generic, color_formatter, color_formatter_sql
505
505
506 #############
506 #############
507 ## LOGGERS ##
507 ## LOGGERS ##
508 #############
508 #############
509
509
510 [logger_root]
510 [logger_root]
511 level = NOTSET
511 level = NOTSET
512 handlers = console
512 handlers = console
513
513
514 [logger_routes]
514 [logger_routes]
515 level = DEBUG
515 level = DEBUG
516 handlers =
516 handlers =
517 qualname = routes.middleware
517 qualname = routes.middleware
518 ## "level = DEBUG" logs the route matched and routing variables.
518 ## "level = DEBUG" logs the route matched and routing variables.
519 propagate = 1
519 propagate = 1
520
520
521 [logger_beaker]
521 [logger_beaker]
522 level = DEBUG
522 level = DEBUG
523 handlers =
523 handlers =
524 qualname = beaker.container
524 qualname = beaker.container
525 propagate = 1
525 propagate = 1
526
526
527 [logger_templates]
527 [logger_templates]
528 level = INFO
528 level = INFO
529 handlers =
529 handlers =
530 qualname = pylons.templating
530 qualname = pylons.templating
531 propagate = 1
531 propagate = 1
532
532
533 [logger_kallithea]
533 [logger_kallithea]
534 level = DEBUG
534 level = DEBUG
535 handlers =
535 handlers =
536 qualname = kallithea
536 qualname = kallithea
537 propagate = 1
537 propagate = 1
538
538
539 [logger_sqlalchemy]
539 [logger_sqlalchemy]
540 level = INFO
540 level = INFO
541 handlers = console_sql
541 handlers = console_sql
542 qualname = sqlalchemy.engine
542 qualname = sqlalchemy.engine
543 propagate = 0
543 propagate = 0
544
544
545 [logger_whoosh_indexer]
545 [logger_whoosh_indexer]
546 level = DEBUG
546 level = DEBUG
547 handlers =
547 handlers =
548 qualname = whoosh_indexer
548 qualname = whoosh_indexer
549 propagate = 1
549 propagate = 1
550
550
551 ##############
551 ##############
552 ## HANDLERS ##
552 ## HANDLERS ##
553 ##############
553 ##############
554
554
555 [handler_console]
555 [handler_console]
556 class = StreamHandler
556 class = StreamHandler
557 args = (sys.stderr,)
557 args = (sys.stderr,)
558 #level = INFO
558 #level = INFO
559 #formatter = generic
559 #formatter = generic
560 level = DEBUG
560 level = DEBUG
561 formatter = color_formatter
561 formatter = color_formatter
562
562
563 [handler_console_sql]
563 [handler_console_sql]
564 class = StreamHandler
564 class = StreamHandler
565 args = (sys.stderr,)
565 args = (sys.stderr,)
566 #level = WARN
566 #level = WARN
567 #formatter = generic
567 #formatter = generic
568 level = DEBUG
568 level = DEBUG
569 formatter = color_formatter_sql
569 formatter = color_formatter_sql
570
570
571 ################
571 ################
572 ## FORMATTERS ##
572 ## FORMATTERS ##
573 ################
573 ################
574
574
575 [formatter_generic]
575 [formatter_generic]
576 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
576 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
577 datefmt = %Y-%m-%d %H:%M:%S
577 datefmt = %Y-%m-%d %H:%M:%S
578
578
579 [formatter_color_formatter]
579 [formatter_color_formatter]
580 class=kallithea.lib.colored_formatter.ColorFormatter
580 class=kallithea.lib.colored_formatter.ColorFormatter
581 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
581 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
582 datefmt = %Y-%m-%d %H:%M:%S
582 datefmt = %Y-%m-%d %H:%M:%S
583
583
584 [formatter_color_formatter_sql]
584 [formatter_color_formatter_sql]
585 class=kallithea.lib.colored_formatter.ColorFormatterSql
585 class=kallithea.lib.colored_formatter.ColorFormatterSql
586 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
586 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
587 datefmt = %Y-%m-%d %H:%M:%S
587 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,581 +1,581 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%text>################################################################################
2 <%text>################################################################################
3 ################################################################################
3 ################################################################################
4 # Kallithea - config file generated with kallithea-config #
4 # Kallithea - config file generated with kallithea-config #
5 ################################################################################
5 ################################################################################
6 ################################################################################
6 ################################################################################
7 </%text>
7 </%text>
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 <%text>
11 <%text>
12 ################################################################################
12 ################################################################################
13 ## Uncomment and replace with the address which should receive ##
13 ## Uncomment and replace with the address which should receive ##
14 ## any error reports after application crash ##
14 ## any error reports after application crash ##
15 ## Additionally those settings will be used by Kallithea mailing system ##
15 ## Additionally those settings will be used by Kallithea mailing system ##
16 ################################################################################</%text>
16 ################################################################################</%text>
17 #email_to = admin@localhost
17 #email_to = admin@localhost
18 #error_email_from = paste_error@localhost
18 #error_email_from = paste_error@localhost
19 #app_email_from = kallithea-noreply@localhost
19 #app_email_from = kallithea-noreply@localhost
20 #error_message =
20 #error_message =
21 #email_prefix = [Kallithea]
21 #email_prefix = [Kallithea]
22
22
23 #smtp_server = mail.server.com
23 #smtp_server = mail.server.com
24 #smtp_username =
24 #smtp_username =
25 #smtp_password =
25 #smtp_password =
26 #smtp_port =
26 #smtp_port =
27 #smtp_use_tls = false
27 #smtp_use_tls = false
28 #smtp_use_ssl = true
28 #smtp_use_ssl = true
29 <%text>## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)</%text>
29 <%text>## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)</%text>
30 #smtp_auth =
30 #smtp_auth =
31
31
32 [server:main]
32 [server:main]
33 %if http_server == 'paste':
33 %if http_server == 'paste':
34 <%text>## PASTE ##</%text>
34 <%text>## PASTE ##</%text>
35 use = egg:Paste#http
35 use = egg:Paste#http
36 <%text>## nr of worker threads to spawn</%text>
36 <%text>## nr of worker threads to spawn</%text>
37 threadpool_workers = 5
37 threadpool_workers = 5
38 <%text>## max request before thread respawn</%text>
38 <%text>## max request before thread respawn</%text>
39 threadpool_max_requests = 10
39 threadpool_max_requests = 10
40 <%text>## option to use threads of process</%text>
40 <%text>## option to use threads of process</%text>
41 use_threadpool = true
41 use_threadpool = true
42 %endif
42 %endif
43 %if http_server == 'waitress':
43 %if http_server == 'waitress':
44 <%text>## WAITRESS ##</%text>
44 <%text>## WAITRESS ##</%text>
45 use = egg:waitress#main
45 use = egg:waitress#main
46 <%text>## number of worker threads</%text>
46 <%text>## number of worker threads</%text>
47 threads = 5
47 threads = 5
48 <%text>## MAX BODY SIZE 100GB</%text>
48 <%text>## MAX BODY SIZE 100GB</%text>
49 max_request_body_size = 107374182400
49 max_request_body_size = 107374182400
50 <%text>## use poll instead of select, fixes fd limits, may not work on old</%text>
50 <%text>## use poll instead of select, fixes fd limits, may not work on old</%text>
51 <%text>## windows systems.</%text>
51 <%text>## windows systems.</%text>
52 #asyncore_use_poll = True
52 #asyncore_use_poll = True
53 %endif
53 %endif
54 %if http_server == 'gunicorn':
54 %if http_server == 'gunicorn':
55 <%text>## GUNICORN ##</%text>
55 <%text>## GUNICORN ##</%text>
56 use = egg:gunicorn#main
56 use = egg:gunicorn#main
57 <%text>## number of process workers. You must set `instance_id = *` when this option</%text>
57 <%text>## number of process workers. You must set `instance_id = *` when this option</%text>
58 <%text>## is set to more than one worker</%text>
58 <%text>## is set to more than one worker</%text>
59 workers = 1
59 workers = 1
60 <%text>## process name</%text>
60 <%text>## process name</%text>
61 proc_name = kallithea
61 proc_name = kallithea
62 <%text>## type of worker class, one of sync, eventlet, gevent, tornado</%text>
62 <%text>## type of worker class, one of sync, eventlet, gevent, tornado</%text>
63 <%text>## recommended for bigger setup is using of of other than sync one</%text>
63 <%text>## recommended for bigger setup is using of of other than sync one</%text>
64 worker_class = sync
64 worker_class = sync
65 max_requests = 1000
65 max_requests = 1000
66 <%text>## ammount of time a worker can handle request before it gets killed and</%text>
66 <%text>## ammount of time a worker can handle request before it gets killed and</%text>
67 <%text>## restarted</%text>
67 <%text>## restarted</%text>
68 timeout = 3600
68 timeout = 3600
69 %endif
69 %endif
70 %if http_server == 'uwsgi':
70 %if http_server == 'uwsgi':
71 <%text>## UWSGI ##</%text>
71 <%text>## UWSGI ##</%text>
72 <%text>## run with uwsgi --ini-paste-logged <inifile.ini></%text>
72 <%text>## run with uwsgi --ini-paste-logged <inifile.ini></%text>
73 [uwsgi]
73 [uwsgi]
74 socket = /tmp/uwsgi.sock
74 socket = /tmp/uwsgi.sock
75 master = true
75 master = true
76 http = 127.0.0.1:5000
76 http = 127.0.0.1:5000
77
77
78 <%text>## set as deamon and redirect all output to file</%text>
78 <%text>## set as deamon and redirect all output to file</%text>
79 #daemonize = ./uwsgi_kallithea.log
79 #daemonize = ./uwsgi_kallithea.log
80
80
81 <%text>## master process PID</%text>
81 <%text>## master process PID</%text>
82 pidfile = ./uwsgi_kallithea.pid
82 pidfile = ./uwsgi_kallithea.pid
83
83
84 <%text>## stats server with workers statistics, use uwsgitop</%text>
84 <%text>## stats server with workers statistics, use uwsgitop</%text>
85 <%text>## for monitoring, `uwsgitop 127.0.0.1:1717`</%text>
85 <%text>## for monitoring, `uwsgitop 127.0.0.1:1717`</%text>
86 stats = 127.0.0.1:1717
86 stats = 127.0.0.1:1717
87 memory-report = true
87 memory-report = true
88
88
89 <%text>## log 5XX errors</%text>
89 <%text>## log 5XX errors</%text>
90 log-5xx = true
90 log-5xx = true
91
91
92 <%text>## Set the socket listen queue size.</%text>
92 <%text>## Set the socket listen queue size.</%text>
93 listen = 256
93 listen = 256
94
94
95 <%text>## Gracefully Reload workers after the specified amount of managed requests</%text>
95 <%text>## Gracefully Reload workers after the specified amount of managed requests</%text>
96 <%text>## (avoid memory leaks).</%text>
96 <%text>## (avoid memory leaks).</%text>
97 max-requests = 1000
97 max-requests = 1000
98
98
99 <%text>## enable large buffers</%text>
99 <%text>## enable large buffers</%text>
100 buffer-size=65535
100 buffer-size=65535
101
101
102 <%text>## socket and http timeouts ##</%text>
102 <%text>## socket and http timeouts ##</%text>
103 http-timeout=3600
103 http-timeout=3600
104 socket-timeout=3600
104 socket-timeout=3600
105
105
106 <%text>## Log requests slower than the specified number of milliseconds.</%text>
106 <%text>## Log requests slower than the specified number of milliseconds.</%text>
107 log-slow = 10
107 log-slow = 10
108
108
109 <%text>## Exit if no app can be loaded.</%text>
109 <%text>## Exit if no app can be loaded.</%text>
110 need-app = true
110 need-app = true
111
111
112 <%text>## Set lazy mode (load apps in workers instead of master).</%text>
112 <%text>## Set lazy mode (load apps in workers instead of master).</%text>
113 lazy = true
113 lazy = true
114
114
115 <%text>## scaling ##</%text>
115 <%text>## scaling ##</%text>
116 <%text>## set cheaper algorithm to use, if not set default will be used</%text>
116 <%text>## set cheaper algorithm to use, if not set default will be used</%text>
117 cheaper-algo = spare
117 cheaper-algo = spare
118
118
119 <%text>## minimum number of workers to keep at all times</%text>
119 <%text>## minimum number of workers to keep at all times</%text>
120 cheaper = 1
120 cheaper = 1
121
121
122 <%text>## number of workers to spawn at startup</%text>
122 <%text>## number of workers to spawn at startup</%text>
123 cheaper-initial = 1
123 cheaper-initial = 1
124
124
125 <%text>## maximum number of workers that can be spawned</%text>
125 <%text>## maximum number of workers that can be spawned</%text>
126 workers = 4
126 workers = 4
127
127
128 <%text>## how many workers should be spawned at a time</%text>
128 <%text>## how many workers should be spawned at a time</%text>
129 cheaper-step = 1
129 cheaper-step = 1
130 %endif
130 %endif
131 <%text>## COMMON ##</%text>
131 <%text>## COMMON ##</%text>
132 host = ${host}
132 host = ${host}
133 port = ${port}
133 port = ${port}
134
134
135 <%text>## prefix middleware for rc</%text>
135 <%text>## prefix middleware for rc</%text>
136 #[filter:proxy-prefix]
136 #[filter:proxy-prefix]
137 #use = egg:PasteDeploy#prefix
137 #use = egg:PasteDeploy#prefix
138 #prefix = /<your-prefix>
138 #prefix = /<your-prefix>
139
139
140 [app:main]
140 [app:main]
141 use = egg:kallithea
141 use = egg:kallithea
142 <%text>## enable proxy prefix middleware</%text>
142 <%text>## enable proxy prefix middleware</%text>
143 #filter-with = proxy-prefix
143 #filter-with = proxy-prefix
144
144
145 full_stack = true
145 full_stack = true
146 static_files = true
146 static_files = true
147 <%text>## Available Languages:</%text>
147 <%text>## Available Languages:</%text>
148 <%text>## de en fr ja pl pt_BR ru zh_CN zh_TW</%text>
148 <%text>## de en fr ja pl pt_BR ru zh_CN zh_TW</%text>
149 lang = ${lang}
149 lang = ${lang}
150 cache_dir = ${here}/data
150 cache_dir = ${here}/data
151 index_dir = ${here}/data/index
151 index_dir = ${here}/data/index
152
152
153 <%text>## perform a full repository scan on each server start, this should be</%text>
153 <%text>## perform a full repository scan on each server start, this should be</%text>
154 <%text>## set to false after first startup, to allow faster server restarts.</%text>
154 <%text>## set to false after first startup, to allow faster server restarts.</%text>
155 initial_repo_scan = false
155 initial_repo_scan = false
156
156
157 <%text>## uncomment and set this path to use archive download cache</%text>
157 <%text>## uncomment and set this path to use archive download cache</%text>
158 archive_cache_dir = ${here}/tarballcache
158 archive_cache_dir = ${here}/tarballcache
159
159
160 <%text>## change this to unique ID for security</%text>
160 <%text>## change this to unique ID for security</%text>
161 app_instance_uuid = ${uuid()}
161 app_instance_uuid = ${uuid()}
162
162
163 <%text>## cut off limit for large diffs (size in bytes)</%text>
163 <%text>## cut off limit for large diffs (size in bytes)</%text>
164 cut_off_limit = 256000
164 cut_off_limit = 256000
165
165
166 <%text>## use cache version of scm repo everywhere</%text>
166 <%text>## use cache version of scm repo everywhere</%text>
167 vcs_full_cache = true
167 vcs_full_cache = true
168
168
169 <%text>## force https in Kallithea, fixes https redirects, assumes it's always https</%text>
169 <%text>## force https in Kallithea, fixes https redirects, assumes it's always https</%text>
170 force_https = false
170 force_https = false
171
171
172 <%text>## use Strict-Transport-Security headers</%text>
172 <%text>## use Strict-Transport-Security headers</%text>
173 use_htsts = false
173 use_htsts = false
174
174
175 <%text>## number of commits stats will parse on each iteration</%text>
175 <%text>## number of commits stats will parse on each iteration</%text>
176 commit_parse_limit = 25
176 commit_parse_limit = 25
177
177
178 <%text>## path to git executable</%text>
178 <%text>## path to git executable</%text>
179 git_path = git
179 git_path = git
180
180
181 <%text>## git rev filter option, --all is the default filter, if you need to</%text>
181 <%text>## git rev filter option, --all is the default filter, if you need to</%text>
182 <%text>## hide all refs in changelog switch this to --branches --tags</%text>
182 <%text>## hide all refs in changelog switch this to --branches --tags</%text>
183 #git_rev_filter = --branches --tags
183 #git_rev_filter = --branches --tags
184
184
185 <%text>## RSS feed options</%text>
185 <%text>## RSS feed options</%text>
186 rss_cut_off_limit = 256000
186 rss_cut_off_limit = 256000
187 rss_items_per_page = 10
187 rss_items_per_page = 10
188 rss_include_diff = false
188 rss_include_diff = false
189
189
190 <%text>## options for showing and identifying changesets</%text>
190 <%text>## options for showing and identifying changesets</%text>
191 show_sha_length = 12
191 show_sha_length = 12
192 show_revision_number = true
192 show_revision_number = true
193
193
194 <%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
194 <%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
195 <%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
195 <%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
196 <%text>## example: http://gist.kallithea.server/{gistid}. Empty means use the internal</%text>
196 <%text>## example: http://gist.kallithea.server/{gistid}. Empty means use the internal</%text>
197 <%text>## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid></%text>
197 <%text>## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid></%text>
198 gist_alias_url =
198 gist_alias_url =
199
199
200 <%text>## white list of API enabled controllers. This allows to add list of</%text>
200 <%text>## white list of API enabled controllers. This allows to add list of</%text>
201 <%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
201 <%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
202 <%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
202 <%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
203 <%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
203 <%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
204 <%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
204 <%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
205 <%text>## Recommended settings below are commented out:</%text>
205 <%text>## Recommended settings below are commented out:</%text>
206 api_access_controllers_whitelist =
206 api_access_controllers_whitelist =
207 # ChangesetController:changeset_patch,
207 # ChangesetController:changeset_patch,
208 # ChangesetController:changeset_raw,
208 # ChangesetController:changeset_raw,
209 # FilesController:raw,
209 # FilesController:raw,
210 # FilesController:archivefile
210 # FilesController:archivefile
211
211
212 <%text>## default encoding used to convert from and to unicode</%text>
212 <%text>## default encoding used to convert from and to unicode</%text>
213 <%text>## can be also a comma seperated list of encoding in case of mixed encodings</%text>
213 <%text>## can be also a comma seperated list of encoding in case of mixed encodings</%text>
214 default_encoding = utf8
214 default_encoding = utf8
215
215
216 <%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
216 <%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
217 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
217 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
218
218
219 <%text>## issue tracking mapping for commits messages</%text>
219 <%text>## issue tracking mapping for commits messages</%text>
220 <%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
220 <%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
221
221
222 <%text>## pattern to get the issues from commit messages</%text>
222 <%text>## pattern to get the issues from commit messages</%text>
223 <%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
223 <%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
224 <%text>## {id} will be all groups matched from this pattern</%text>
224 <%text>## {id} will be all groups matched from this pattern</%text>
225
225
226 issue_pat = (?:\s*#)(\d+)
226 issue_pat = (?:\s*#)(\d+)
227
227
228 <%text>## server url to the issue, each {id} will be replaced with match</%text>
228 <%text>## server url to the issue, each {id} will be replaced with match</%text>
229 <%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
229 <%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
230 <%text>## including groups {repo_name} is replaced with just name of repo</%text>
230 <%text>## including groups {repo_name} is replaced with just name of repo</%text>
231
231
232 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
232 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
233
233
234 <%text>## prefix to add to link to indicate it's an url</%text>
234 <%text>## prefix to add to link to indicate it's an url</%text>
235 <%text>## #314 will be replaced by <issue_prefix><id></%text>
235 <%text>## #314 will be replaced by <issue_prefix><id></%text>
236
236
237 issue_prefix = #
237 issue_prefix = #
238
238
239 <%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
239 <%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
240 <%text>## multiple patterns, to other issues server, wiki or others</%text>
240 <%text>## multiple patterns, to other issues server, wiki or others</%text>
241 <%text>## below an example how to create a wiki pattern</%text>
241 <%text>## below an example how to create a wiki pattern</%text>
242 # wiki-some-id -> https://mywiki.com/some-id
242 # wiki-some-id -> https://mywiki.com/some-id
243
243
244 #issue_pat_wiki = (?:wiki-)(.+)
244 #issue_pat_wiki = (?:wiki-)(.+)
245 #issue_server_link_wiki = https://mywiki.com/{id}
245 #issue_server_link_wiki = https://mywiki.com/{id}
246 #issue_prefix_wiki = WIKI-
246 #issue_prefix_wiki = WIKI-
247
247
248
248
249 <%text>## instance-id prefix</%text>
249 <%text>## instance-id prefix</%text>
250 <%text>## a prefix key for this instance used for cache invalidation when running</%text>
250 <%text>## a prefix key for this instance used for cache invalidation when running</%text>
251 <%text>## multiple instances of kallithea, make sure it's globally unique for</%text>
251 <%text>## multiple instances of kallithea, make sure it's globally unique for</%text>
252 <%text>## all running kallithea instances. Leave empty if you don't use it</%text>
252 <%text>## all running kallithea instances. Leave empty if you don't use it</%text>
253 instance_id =
253 instance_id =
254
254
255 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
255 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
256 <%text>## response is 401 HTTPUnauthorized. Currently HG clients have troubles with</%text>
256 <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
257 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
257 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
258 auth_ret_code =
258 auth_ret_code =
259
259
260 <%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
260 <%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
261 <%text>## codes don't break the transactions while 4XX codes do</%text>
261 <%text>## codes don't break the transactions while 4XX codes do</%text>
262 lock_ret_code = 423
262 lock_ret_code = 423
263
263
264 <%text>## allows to change the repository location in settings page</%text>
264 <%text>## allows to change the repository location in settings page</%text>
265 allow_repo_location_change = True
265 allow_repo_location_change = True
266
266
267 <%text>## allows to setup custom hooks in settings page</%text>
267 <%text>## allows to setup custom hooks in settings page</%text>
268 allow_custom_hooks_settings = True
268 allow_custom_hooks_settings = True
269
269
270 <%text>
270 <%text>
271 ####################################
271 ####################################
272 ### CELERY CONFIG ####
272 ### CELERY CONFIG ####
273 ####################################
273 ####################################
274 </%text>
274 </%text>
275 use_celery = false
275 use_celery = false
276 broker.host = localhost
276 broker.host = localhost
277 broker.vhost = rabbitmqhost
277 broker.vhost = rabbitmqhost
278 broker.port = 5672
278 broker.port = 5672
279 broker.user = rabbitmq
279 broker.user = rabbitmq
280 broker.password = qweqwe
280 broker.password = qweqwe
281
281
282 celery.imports = kallithea.lib.celerylib.tasks
282 celery.imports = kallithea.lib.celerylib.tasks
283
283
284 celery.result.backend = amqp
284 celery.result.backend = amqp
285 celery.result.dburi = amqp://
285 celery.result.dburi = amqp://
286 celery.result.serialier = json
286 celery.result.serialier = json
287
287
288 #celery.send.task.error.emails = true
288 #celery.send.task.error.emails = true
289 #celery.amqp.task.result.expires = 18000
289 #celery.amqp.task.result.expires = 18000
290
290
291 celeryd.concurrency = 2
291 celeryd.concurrency = 2
292 #celeryd.log.file = celeryd.log
292 #celeryd.log.file = celeryd.log
293 celeryd.log.level = debug
293 celeryd.log.level = debug
294 celeryd.max.tasks.per.child = 1
294 celeryd.max.tasks.per.child = 1
295
295
296 <%text>## tasks will never be sent to the queue, but executed locally instead.</%text>
296 <%text>## tasks will never be sent to the queue, but executed locally instead.</%text>
297 celery.always.eager = false
297 celery.always.eager = false
298 <%text>
298 <%text>
299 ####################################
299 ####################################
300 ### BEAKER CACHE ####
300 ### BEAKER CACHE ####
301 ####################################
301 ####################################
302 </%text>
302 </%text>
303 beaker.cache.data_dir=${here}/data/cache/data
303 beaker.cache.data_dir=${here}/data/cache/data
304 beaker.cache.lock_dir=${here}/data/cache/lock
304 beaker.cache.lock_dir=${here}/data/cache/lock
305
305
306 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
306 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
307
307
308 beaker.cache.super_short_term.type=memory
308 beaker.cache.super_short_term.type=memory
309 beaker.cache.super_short_term.expire=10
309 beaker.cache.super_short_term.expire=10
310 beaker.cache.super_short_term.key_length = 256
310 beaker.cache.super_short_term.key_length = 256
311
311
312 beaker.cache.short_term.type=memory
312 beaker.cache.short_term.type=memory
313 beaker.cache.short_term.expire=60
313 beaker.cache.short_term.expire=60
314 beaker.cache.short_term.key_length = 256
314 beaker.cache.short_term.key_length = 256
315
315
316 beaker.cache.long_term.type=memory
316 beaker.cache.long_term.type=memory
317 beaker.cache.long_term.expire=36000
317 beaker.cache.long_term.expire=36000
318 beaker.cache.long_term.key_length = 256
318 beaker.cache.long_term.key_length = 256
319
319
320 beaker.cache.sql_cache_short.type=memory
320 beaker.cache.sql_cache_short.type=memory
321 beaker.cache.sql_cache_short.expire=10
321 beaker.cache.sql_cache_short.expire=10
322 beaker.cache.sql_cache_short.key_length = 256
322 beaker.cache.sql_cache_short.key_length = 256
323
323
324 beaker.cache.sql_cache_med.type=memory
324 beaker.cache.sql_cache_med.type=memory
325 beaker.cache.sql_cache_med.expire=360
325 beaker.cache.sql_cache_med.expire=360
326 beaker.cache.sql_cache_med.key_length = 256
326 beaker.cache.sql_cache_med.key_length = 256
327
327
328 beaker.cache.sql_cache_long.type=file
328 beaker.cache.sql_cache_long.type=file
329 beaker.cache.sql_cache_long.expire=3600
329 beaker.cache.sql_cache_long.expire=3600
330 beaker.cache.sql_cache_long.key_length = 256
330 beaker.cache.sql_cache_long.key_length = 256
331 <%text>
331 <%text>
332 ####################################
332 ####################################
333 ### BEAKER SESSION ####
333 ### BEAKER SESSION ####
334 ####################################
334 ####################################
335 ## Type of storage used for the session, current types are
335 ## Type of storage used for the session, current types are
336 ## dbm, file, memcached, database, and memory.
336 ## dbm, file, memcached, database, and memory.
337 ## The storage uses the Container API
337 ## The storage uses the Container API
338 ## that is also used by the cache system.
338 ## that is also used by the cache system.
339 </%text>
339 </%text>
340 <%text>## db session ##</%text>
340 <%text>## db session ##</%text>
341 #beaker.session.type = ext:database
341 #beaker.session.type = ext:database
342 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
342 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
343 #beaker.session.table_name = db_session
343 #beaker.session.table_name = db_session
344
344
345 <%text>## encrypted cookie client side session, good for many instances ##</%text>
345 <%text>## encrypted cookie client side session, good for many instances ##</%text>
346 #beaker.session.type = cookie
346 #beaker.session.type = cookie
347
347
348 <%text>## file based cookies (default) ##</%text>
348 <%text>## file based cookies (default) ##</%text>
349 #beaker.session.type = file
349 #beaker.session.type = file
350
350
351 beaker.session.key = kallithea
351 beaker.session.key = kallithea
352 beaker.session.secret = ${uuid()}
352 beaker.session.secret = ${uuid()}
353
353
354 <%text>## Secure encrypted cookie. Requires AES and AES python libraries</%text>
354 <%text>## Secure encrypted cookie. Requires AES and AES python libraries</%text>
355 <%text>## you must disable beaker.session.secret to use this</%text>
355 <%text>## you must disable beaker.session.secret to use this</%text>
356 #beaker.session.encrypt_key = <key_for_encryption>
356 #beaker.session.encrypt_key = <key_for_encryption>
357 #beaker.session.validate_key = <validation_key>
357 #beaker.session.validate_key = <validation_key>
358
358
359 <%text>## sets session as invalid if it haven't been accessed for given amount of time</%text>
359 <%text>## sets session as invalid if it haven't been accessed for given amount of time</%text>
360 beaker.session.timeout = 2592000
360 beaker.session.timeout = 2592000
361 beaker.session.httponly = true
361 beaker.session.httponly = true
362 #beaker.session.cookie_path = /<your-prefix>
362 #beaker.session.cookie_path = /<your-prefix>
363
363
364 <%text>## uncomment for https secure cookie</%text>
364 <%text>## uncomment for https secure cookie</%text>
365 beaker.session.secure = false
365 beaker.session.secure = false
366
366
367 <%text>## auto save the session to not to use .save()</%text>
367 <%text>## auto save the session to not to use .save()</%text>
368 beaker.session.auto = False
368 beaker.session.auto = False
369
369
370 <%text>## default cookie expiration time in seconds `true` expire at browser close ##</%text>
370 <%text>## default cookie expiration time in seconds `true` expire at browser close ##</%text>
371 #beaker.session.cookie_expires = 3600
371 #beaker.session.cookie_expires = 3600
372
372
373 %if error_aggregation_service == 'errormator':
373 %if error_aggregation_service == 'errormator':
374 <%text>
374 <%text>
375 ############################
375 ############################
376 ## ERROR HANDLING SYSTEMS ##
376 ## ERROR HANDLING SYSTEMS ##
377 ############################
377 ############################
378
378
379 ####################
379 ####################
380 ### [errormator] ###
380 ### [errormator] ###
381 ####################
381 ####################
382
382
383 ## Errormator is tailored to work with Kallithea, see
383 ## Errormator is tailored to work with Kallithea, see
384 ## http://errormator.com for details how to obtain an account
384 ## http://errormator.com for details how to obtain an account
385 ## you must install python package `errormator_client` to make it work
385 ## you must install python package `errormator_client` to make it work
386 </%text>
386 </%text>
387 <%text>## errormator enabled</%text>
387 <%text>## errormator enabled</%text>
388 errormator = false
388 errormator = false
389
389
390 errormator.server_url = https://api.errormator.com
390 errormator.server_url = https://api.errormator.com
391 errormator.api_key = YOUR_API_KEY
391 errormator.api_key = YOUR_API_KEY
392
392
393 <%text>## TWEAK AMOUNT OF INFO SENT HERE</%text>
393 <%text>## TWEAK AMOUNT OF INFO SENT HERE</%text>
394
394
395 <%text>## enables 404 error logging (default False)</%text>
395 <%text>## enables 404 error logging (default False)</%text>
396 errormator.report_404 = false
396 errormator.report_404 = false
397
397
398 <%text>## time in seconds after request is considered being slow (default 1)</%text>
398 <%text>## time in seconds after request is considered being slow (default 1)</%text>
399 errormator.slow_request_time = 1
399 errormator.slow_request_time = 1
400
400
401 <%text>## record slow requests in application</%text>
401 <%text>## record slow requests in application</%text>
402 <%text>## (needs to be enabled for slow datastore recording and time tracking)</%text>
402 <%text>## (needs to be enabled for slow datastore recording and time tracking)</%text>
403 errormator.slow_requests = true
403 errormator.slow_requests = true
404
404
405 <%text>## enable hooking to application loggers</%text>
405 <%text>## enable hooking to application loggers</%text>
406 # errormator.logging = true
406 # errormator.logging = true
407
407
408 <%text>## minimum log level for log capture</%text>
408 <%text>## minimum log level for log capture</%text>
409 # errormator.logging.level = WARNING
409 # errormator.logging.level = WARNING
410
410
411 <%text>## send logs only from erroneous/slow requests</%text>
411 <%text>## send logs only from erroneous/slow requests</%text>
412 <%text>## (saves API quota for intensive logging)</%text>
412 <%text>## (saves API quota for intensive logging)</%text>
413 errormator.logging_on_error = false
413 errormator.logging_on_error = false
414
414
415 <%text>## list of additonal keywords that should be grabbed from environ object</%text>
415 <%text>## list of additonal keywords that should be grabbed from environ object</%text>
416 <%text>## can be string with comma separated list of words in lowercase</%text>
416 <%text>## can be string with comma separated list of words in lowercase</%text>
417 <%text>## (by default client will always send following info:</%text>
417 <%text>## (by default client will always send following info:</%text>
418 <%text>## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that</%text>
418 <%text>## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that</%text>
419 <%text>## start with HTTP* this list be extended with additional keywords here</%text>
419 <%text>## start with HTTP* this list be extended with additional keywords here</%text>
420 errormator.environ_keys_whitelist =
420 errormator.environ_keys_whitelist =
421
421
422
422
423 <%text>## list of keywords that should be blanked from request object</%text>
423 <%text>## list of keywords that should be blanked from request object</%text>
424 <%text>## can be string with comma separated list of words in lowercase</%text>
424 <%text>## can be string with comma separated list of words in lowercase</%text>
425 <%text>## (by default client will always blank keys that contain following words</%text>
425 <%text>## (by default client will always blank keys that contain following words</%text>
426 <%text>## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'</%text>
426 <%text>## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'</%text>
427 <%text>## this list be extended with additional keywords set here</%text>
427 <%text>## this list be extended with additional keywords set here</%text>
428 errormator.request_keys_blacklist =
428 errormator.request_keys_blacklist =
429
429
430
430
431 <%text>## list of namespaces that should be ignores when gathering log entries</%text>
431 <%text>## list of namespaces that should be ignores when gathering log entries</%text>
432 <%text>## can be string with comma separated list of namespaces</%text>
432 <%text>## can be string with comma separated list of namespaces</%text>
433 <%text>## (by default the client ignores own entries: errormator_client.client)</%text>
433 <%text>## (by default the client ignores own entries: errormator_client.client)</%text>
434 errormator.log_namespace_blacklist =
434 errormator.log_namespace_blacklist =
435 %elif error_aggregation_service == 'sentry':
435 %elif error_aggregation_service == 'sentry':
436 <%text>
436 <%text>
437 ################
437 ################
438 ### [sentry] ###
438 ### [sentry] ###
439 ################
439 ################
440
440
441 ## sentry is a alternative open source error aggregator
441 ## sentry is a alternative open source error aggregator
442 ## you must install python packages `sentry` and `raven` to enable
442 ## you must install python packages `sentry` and `raven` to enable
443 </%text>
443 </%text>
444 sentry.dsn = YOUR_DNS
444 sentry.dsn = YOUR_DNS
445 sentry.servers =
445 sentry.servers =
446 sentry.name =
446 sentry.name =
447 sentry.key =
447 sentry.key =
448 sentry.public_key =
448 sentry.public_key =
449 sentry.secret_key =
449 sentry.secret_key =
450 sentry.project =
450 sentry.project =
451 sentry.site =
451 sentry.site =
452 sentry.include_paths =
452 sentry.include_paths =
453 sentry.exclude_paths =
453 sentry.exclude_paths =
454 %endif
454 %endif
455 <%text>
455 <%text>
456 ################################################################################
456 ################################################################################
457 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
457 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
458 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
458 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
459 ## execute malicious code after an exception is raised. ##
459 ## execute malicious code after an exception is raised. ##
460 ################################################################################</%text>
460 ################################################################################</%text>
461 set debug = false
461 set debug = false
462 <%text>
462 <%text>
463 ##################################
463 ##################################
464 ### LOGVIEW CONFIG ###
464 ### LOGVIEW CONFIG ###
465 ##################################
465 ##################################
466 </%text>
466 </%text>
467 logview.sqlalchemy = #faa
467 logview.sqlalchemy = #faa
468 logview.pylons.templating = #bfb
468 logview.pylons.templating = #bfb
469 logview.pylons.util = #eee
469 logview.pylons.util = #eee
470 <%text>
470 <%text>
471 #########################################################
471 #########################################################
472 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
472 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
473 #########################################################
473 #########################################################
474 </%text>
474 </%text>
475 %if database_engine == 'sqlite':
475 %if database_engine == 'sqlite':
476 # SQLITE [default]
476 # SQLITE [default]
477 sqlalchemy.db1.url = sqlite:///${here}/kallithea.db?timeout=60
477 sqlalchemy.db1.url = sqlite:///${here}/kallithea.db?timeout=60
478 %elif database_engine == 'postgres':
478 %elif database_engine == 'postgres':
479 # POSTGRESQL
479 # POSTGRESQL
480 sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
480 sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
481 %elif database_engine == 'mysql':
481 %elif database_engine == 'mysql':
482 # MySQL
482 # MySQL
483 sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
483 sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
484 %endif
484 %endif
485 # see sqlalchemy docs for others
485 # see sqlalchemy docs for others
486
486
487 sqlalchemy.db1.echo = false
487 sqlalchemy.db1.echo = false
488 sqlalchemy.db1.pool_recycle = 3600
488 sqlalchemy.db1.pool_recycle = 3600
489 sqlalchemy.db1.convert_unicode = true
489 sqlalchemy.db1.convert_unicode = true
490 <%text>
490 <%text>
491 ################################
491 ################################
492 ### LOGGING CONFIGURATION ####
492 ### LOGGING CONFIGURATION ####
493 ################################
493 ################################
494 </%text>
494 </%text>
495 [loggers]
495 [loggers]
496 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
496 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
497
497
498 [handlers]
498 [handlers]
499 keys = console, console_sql
499 keys = console, console_sql
500
500
501 [formatters]
501 [formatters]
502 keys = generic, color_formatter, color_formatter_sql
502 keys = generic, color_formatter, color_formatter_sql
503 <%text>
503 <%text>
504 #############
504 #############
505 ## LOGGERS ##
505 ## LOGGERS ##
506 #############
506 #############
507 </%text>
507 </%text>
508 [logger_root]
508 [logger_root]
509 level = NOTSET
509 level = NOTSET
510 handlers = console
510 handlers = console
511
511
512 [logger_routes]
512 [logger_routes]
513 level = DEBUG
513 level = DEBUG
514 handlers =
514 handlers =
515 qualname = routes.middleware
515 qualname = routes.middleware
516 <%text>## "level = DEBUG" logs the route matched and routing variables.</%text>
516 <%text>## "level = DEBUG" logs the route matched and routing variables.</%text>
517 propagate = 1
517 propagate = 1
518
518
519 [logger_beaker]
519 [logger_beaker]
520 level = DEBUG
520 level = DEBUG
521 handlers =
521 handlers =
522 qualname = beaker.container
522 qualname = beaker.container
523 propagate = 1
523 propagate = 1
524
524
525 [logger_templates]
525 [logger_templates]
526 level = INFO
526 level = INFO
527 handlers =
527 handlers =
528 qualname = pylons.templating
528 qualname = pylons.templating
529 propagate = 1
529 propagate = 1
530
530
531 [logger_kallithea]
531 [logger_kallithea]
532 level = DEBUG
532 level = DEBUG
533 handlers =
533 handlers =
534 qualname = kallithea
534 qualname = kallithea
535 propagate = 1
535 propagate = 1
536
536
537 [logger_sqlalchemy]
537 [logger_sqlalchemy]
538 level = INFO
538 level = INFO
539 handlers = console_sql
539 handlers = console_sql
540 qualname = sqlalchemy.engine
540 qualname = sqlalchemy.engine
541 propagate = 0
541 propagate = 0
542
542
543 [logger_whoosh_indexer]
543 [logger_whoosh_indexer]
544 level = DEBUG
544 level = DEBUG
545 handlers =
545 handlers =
546 qualname = whoosh_indexer
546 qualname = whoosh_indexer
547 propagate = 1
547 propagate = 1
548 <%text>
548 <%text>
549 ##############
549 ##############
550 ## HANDLERS ##
550 ## HANDLERS ##
551 ##############
551 ##############
552 </%text>
552 </%text>
553 [handler_console]
553 [handler_console]
554 class = StreamHandler
554 class = StreamHandler
555 args = (sys.stderr,)
555 args = (sys.stderr,)
556 level = INFO
556 level = INFO
557 formatter = generic
557 formatter = generic
558
558
559 [handler_console_sql]
559 [handler_console_sql]
560 class = StreamHandler
560 class = StreamHandler
561 args = (sys.stderr,)
561 args = (sys.stderr,)
562 level = WARN
562 level = WARN
563 formatter = generic
563 formatter = generic
564 <%text>
564 <%text>
565 ################
565 ################
566 ## FORMATTERS ##
566 ## FORMATTERS ##
567 ################
567 ################
568 </%text>
568 </%text>
569 [formatter_generic]
569 [formatter_generic]
570 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
570 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
571 datefmt = %Y-%m-%d %H:%M:%S
571 datefmt = %Y-%m-%d %H:%M:%S
572
572
573 [formatter_color_formatter]
573 [formatter_color_formatter]
574 class=kallithea.lib.colored_formatter.ColorFormatter
574 class=kallithea.lib.colored_formatter.ColorFormatter
575 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
575 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
576 datefmt = %Y-%m-%d %H:%M:%S
576 datefmt = %Y-%m-%d %H:%M:%S
577
577
578 [formatter_color_formatter_sql]
578 [formatter_color_formatter_sql]
579 class=kallithea.lib.colored_formatter.ColorFormatterSql
579 class=kallithea.lib.colored_formatter.ColorFormatterSql
580 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
580 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
581 datefmt = %Y-%m-%d %H:%M:%S
581 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,576 +1,576 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # Kallithea - Example config #
3 # Kallithea - Example config #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7 ################################################################################
7 ################################################################################
8
8
9 [DEFAULT]
9 [DEFAULT]
10 debug = true
10 debug = true
11 pdebug = false
11 pdebug = false
12
12
13 ################################################################################
13 ################################################################################
14 ## Uncomment and replace with the address which should receive ##
14 ## Uncomment and replace with the address which should receive ##
15 ## any error reports after application crash ##
15 ## any error reports after application crash ##
16 ## Additionally those settings will be used by Kallithea mailing system ##
16 ## Additionally those settings will be used by Kallithea mailing system ##
17 ################################################################################
17 ################################################################################
18 #email_to = admin@localhost
18 #email_to = admin@localhost
19 #error_email_from = paste_error@localhost
19 #error_email_from = paste_error@localhost
20 #app_email_from = kallithea-noreply@localhost
20 #app_email_from = kallithea-noreply@localhost
21 #error_message =
21 #error_message =
22 #email_prefix = [Kallithea]
22 #email_prefix = [Kallithea]
23
23
24 #smtp_server = mail.server.com
24 #smtp_server = mail.server.com
25 #smtp_username =
25 #smtp_username =
26 #smtp_password =
26 #smtp_password =
27 #smtp_port =
27 #smtp_port =
28 #smtp_use_tls = false
28 #smtp_use_tls = false
29 #smtp_use_ssl = true
29 #smtp_use_ssl = true
30 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
30 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
31 #smtp_auth =
31 #smtp_auth =
32
32
33 [server:main]
33 [server:main]
34 ## PASTE ##
34 ## PASTE ##
35 #use = egg:Paste#http
35 #use = egg:Paste#http
36 ## nr of worker threads to spawn
36 ## nr of worker threads to spawn
37 #threadpool_workers = 5
37 #threadpool_workers = 5
38 ## max request before thread respawn
38 ## max request before thread respawn
39 #threadpool_max_requests = 10
39 #threadpool_max_requests = 10
40 ## option to use threads of process
40 ## option to use threads of process
41 #use_threadpool = true
41 #use_threadpool = true
42
42
43 ## WAITRESS ##
43 ## WAITRESS ##
44 use = egg:waitress#main
44 use = egg:waitress#main
45 ## number of worker threads
45 ## number of worker threads
46 threads = 5
46 threads = 5
47 ## MAX BODY SIZE 100GB
47 ## MAX BODY SIZE 100GB
48 max_request_body_size = 107374182400
48 max_request_body_size = 107374182400
49 ## use poll instead of select, fixes fd limits, may not work on old
49 ## use poll instead of select, fixes fd limits, may not work on old
50 ## windows systems.
50 ## windows systems.
51 #asyncore_use_poll = True
51 #asyncore_use_poll = True
52
52
53 ## GUNICORN ##
53 ## GUNICORN ##
54 #use = egg:gunicorn#main
54 #use = egg:gunicorn#main
55 ## number of process workers. You must set `instance_id = *` when this option
55 ## number of process workers. You must set `instance_id = *` when this option
56 ## is set to more than one worker
56 ## is set to more than one worker
57 #workers = 1
57 #workers = 1
58 ## process name
58 ## process name
59 #proc_name = kallithea
59 #proc_name = kallithea
60 ## type of worker class, one of sync, eventlet, gevent, tornado
60 ## type of worker class, one of sync, eventlet, gevent, tornado
61 ## recommended for bigger setup is using of of other than sync one
61 ## recommended for bigger setup is using of of other than sync one
62 #worker_class = sync
62 #worker_class = sync
63 #max_requests = 1000
63 #max_requests = 1000
64 ## ammount of time a worker can handle request before it gets killed and
64 ## ammount of time a worker can handle request before it gets killed and
65 ## restarted
65 ## restarted
66 #timeout = 3600
66 #timeout = 3600
67
67
68 ## UWSGI ##
68 ## UWSGI ##
69 ## run with uwsgi --ini-paste-logged <inifile.ini>
69 ## run with uwsgi --ini-paste-logged <inifile.ini>
70 #[uwsgi]
70 #[uwsgi]
71 #socket = /tmp/uwsgi.sock
71 #socket = /tmp/uwsgi.sock
72 #master = true
72 #master = true
73 #http = 127.0.0.1:5000
73 #http = 127.0.0.1:5000
74
74
75 ## set as deamon and redirect all output to file
75 ## set as deamon and redirect all output to file
76 #daemonize = ./uwsgi_kallithea.log
76 #daemonize = ./uwsgi_kallithea.log
77
77
78 ## master process PID
78 ## master process PID
79 #pidfile = ./uwsgi_kallithea.pid
79 #pidfile = ./uwsgi_kallithea.pid
80
80
81 ## stats server with workers statistics, use uwsgitop
81 ## stats server with workers statistics, use uwsgitop
82 ## for monitoring, `uwsgitop 127.0.0.1:1717`
82 ## for monitoring, `uwsgitop 127.0.0.1:1717`
83 #stats = 127.0.0.1:1717
83 #stats = 127.0.0.1:1717
84 #memory-report = true
84 #memory-report = true
85
85
86 ## log 5XX errors
86 ## log 5XX errors
87 #log-5xx = true
87 #log-5xx = true
88
88
89 ## Set the socket listen queue size.
89 ## Set the socket listen queue size.
90 #listen = 256
90 #listen = 256
91
91
92 ## Gracefully Reload workers after the specified amount of managed requests
92 ## Gracefully Reload workers after the specified amount of managed requests
93 ## (avoid memory leaks).
93 ## (avoid memory leaks).
94 #max-requests = 1000
94 #max-requests = 1000
95
95
96 ## enable large buffers
96 ## enable large buffers
97 #buffer-size=65535
97 #buffer-size=65535
98
98
99 ## socket and http timeouts ##
99 ## socket and http timeouts ##
100 #http-timeout=3600
100 #http-timeout=3600
101 #socket-timeout=3600
101 #socket-timeout=3600
102
102
103 ## Log requests slower than the specified number of milliseconds.
103 ## Log requests slower than the specified number of milliseconds.
104 #log-slow = 10
104 #log-slow = 10
105
105
106 ## Exit if no app can be loaded.
106 ## Exit if no app can be loaded.
107 #need-app = true
107 #need-app = true
108
108
109 ## Set lazy mode (load apps in workers instead of master).
109 ## Set lazy mode (load apps in workers instead of master).
110 #lazy = true
110 #lazy = true
111
111
112 ## scaling ##
112 ## scaling ##
113 ## set cheaper algorithm to use, if not set default will be used
113 ## set cheaper algorithm to use, if not set default will be used
114 #cheaper-algo = spare
114 #cheaper-algo = spare
115
115
116 ## minimum number of workers to keep at all times
116 ## minimum number of workers to keep at all times
117 #cheaper = 1
117 #cheaper = 1
118
118
119 ## number of workers to spawn at startup
119 ## number of workers to spawn at startup
120 #cheaper-initial = 1
120 #cheaper-initial = 1
121
121
122 ## maximum number of workers that can be spawned
122 ## maximum number of workers that can be spawned
123 #workers = 4
123 #workers = 4
124
124
125 ## how many workers should be spawned at a time
125 ## how many workers should be spawned at a time
126 #cheaper-step = 1
126 #cheaper-step = 1
127
127
128 ## COMMON ##
128 ## COMMON ##
129 host = 127.0.0.1
129 host = 127.0.0.1
130 port = 5000
130 port = 5000
131
131
132 ## prefix middleware for rc
132 ## prefix middleware for rc
133 #[filter:proxy-prefix]
133 #[filter:proxy-prefix]
134 #use = egg:PasteDeploy#prefix
134 #use = egg:PasteDeploy#prefix
135 #prefix = /<your-prefix>
135 #prefix = /<your-prefix>
136
136
137 [app:main]
137 [app:main]
138 use = egg:kallithea
138 use = egg:kallithea
139 ## enable proxy prefix middleware
139 ## enable proxy prefix middleware
140 #filter-with = proxy-prefix
140 #filter-with = proxy-prefix
141
141
142 full_stack = true
142 full_stack = true
143 static_files = true
143 static_files = true
144 ## Available Languages:
144 ## Available Languages:
145 ## de en fr ja pl pt_BR ru zh_CN zh_TW
145 ## de en fr ja pl pt_BR ru zh_CN zh_TW
146 lang = en
146 lang = en
147 cache_dir = %(here)s/data
147 cache_dir = %(here)s/data
148 index_dir = %(here)s/data/index
148 index_dir = %(here)s/data/index
149
149
150 ## perform a full repository scan on each server start, this should be
150 ## perform a full repository scan on each server start, this should be
151 ## set to false after first startup, to allow faster server restarts.
151 ## set to false after first startup, to allow faster server restarts.
152 initial_repo_scan = false
152 initial_repo_scan = false
153
153
154 ## uncomment and set this path to use archive download cache
154 ## uncomment and set this path to use archive download cache
155 archive_cache_dir = %(here)s/tarballcache
155 archive_cache_dir = %(here)s/tarballcache
156
156
157 ## change this to unique ID for security
157 ## change this to unique ID for security
158 app_instance_uuid = ${app_instance_uuid}
158 app_instance_uuid = ${app_instance_uuid}
159
159
160 ## cut off limit for large diffs (size in bytes)
160 ## cut off limit for large diffs (size in bytes)
161 cut_off_limit = 256000
161 cut_off_limit = 256000
162
162
163 ## use cache version of scm repo everywhere
163 ## use cache version of scm repo everywhere
164 vcs_full_cache = true
164 vcs_full_cache = true
165
165
166 ## force https in Kallithea, fixes https redirects, assumes it's always https
166 ## force https in Kallithea, fixes https redirects, assumes it's always https
167 force_https = false
167 force_https = false
168
168
169 ## use Strict-Transport-Security headers
169 ## use Strict-Transport-Security headers
170 use_htsts = false
170 use_htsts = false
171
171
172 ## number of commits stats will parse on each iteration
172 ## number of commits stats will parse on each iteration
173 commit_parse_limit = 25
173 commit_parse_limit = 25
174
174
175 ## path to git executable
175 ## path to git executable
176 git_path = git
176 git_path = git
177
177
178 ## git rev filter option, --all is the default filter, if you need to
178 ## git rev filter option, --all is the default filter, if you need to
179 ## hide all refs in changelog switch this to --branches --tags
179 ## hide all refs in changelog switch this to --branches --tags
180 #git_rev_filter = --branches --tags
180 #git_rev_filter = --branches --tags
181
181
182 ## RSS feed options
182 ## RSS feed options
183 rss_cut_off_limit = 256000
183 rss_cut_off_limit = 256000
184 rss_items_per_page = 10
184 rss_items_per_page = 10
185 rss_include_diff = false
185 rss_include_diff = false
186
186
187 ## options for showing and identifying changesets
187 ## options for showing and identifying changesets
188 show_sha_length = 12
188 show_sha_length = 12
189 show_revision_number = true
189 show_revision_number = true
190
190
191 ## gist URL alias, used to create nicer urls for gist. This should be an
191 ## gist URL alias, used to create nicer urls for gist. This should be an
192 ## url that does rewrites to _admin/gists/<gistid>.
192 ## url that does rewrites to _admin/gists/<gistid>.
193 ## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
193 ## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
194 ## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
194 ## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
195 gist_alias_url =
195 gist_alias_url =
196
196
197 ## white list of API enabled controllers. This allows to add list of
197 ## white list of API enabled controllers. This allows to add list of
198 ## controllers to which access will be enabled by api_key. eg: to enable
198 ## controllers to which access will be enabled by api_key. eg: to enable
199 ## api access to raw_files put `FilesController:raw`, to enable access to patches
199 ## api access to raw_files put `FilesController:raw`, to enable access to patches
200 ## add `ChangesetController:changeset_patch`. This list should be "," separated
200 ## add `ChangesetController:changeset_patch`. This list should be "," separated
201 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
201 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
202 ## Recommended settings below are commented out:
202 ## Recommended settings below are commented out:
203 api_access_controllers_whitelist =
203 api_access_controllers_whitelist =
204 # ChangesetController:changeset_patch,
204 # ChangesetController:changeset_patch,
205 # ChangesetController:changeset_raw,
205 # ChangesetController:changeset_raw,
206 # FilesController:raw,
206 # FilesController:raw,
207 # FilesController:archivefile
207 # FilesController:archivefile
208
208
209 ## default encoding used to convert from and to unicode
209 ## default encoding used to convert from and to unicode
210 ## can be also a comma seperated list of encoding in case of mixed encodings
210 ## can be also a comma seperated list of encoding in case of mixed encodings
211 default_encoding = utf8
211 default_encoding = utf8
212
212
213 ## issue tracker for Kallithea (leave blank to disable, absent for default)
213 ## issue tracker for Kallithea (leave blank to disable, absent for default)
214 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
214 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
215
215
216 ## issue tracking mapping for commits messages
216 ## issue tracking mapping for commits messages
217 ## comment out issue_pat, issue_server, issue_prefix to enable
217 ## comment out issue_pat, issue_server, issue_prefix to enable
218
218
219 ## pattern to get the issues from commit messages
219 ## pattern to get the issues from commit messages
220 ## default one used here is #<numbers> with a regex passive group for `#`
220 ## default one used here is #<numbers> with a regex passive group for `#`
221 ## {id} will be all groups matched from this pattern
221 ## {id} will be all groups matched from this pattern
222
222
223 issue_pat = (?:\s*#)(\d+)
223 issue_pat = (?:\s*#)(\d+)
224
224
225 ## server url to the issue, each {id} will be replaced with match
225 ## server url to the issue, each {id} will be replaced with match
226 ## fetched from the regex and {repo} is replaced with full repository name
226 ## fetched from the regex and {repo} is replaced with full repository name
227 ## including groups {repo_name} is replaced with just name of repo
227 ## including groups {repo_name} is replaced with just name of repo
228
228
229 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
229 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
230
230
231 ## prefix to add to link to indicate it's an url
231 ## prefix to add to link to indicate it's an url
232 ## #314 will be replaced by <issue_prefix><id>
232 ## #314 will be replaced by <issue_prefix><id>
233
233
234 issue_prefix = #
234 issue_prefix = #
235
235
236 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
236 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
237 ## multiple patterns, to other issues server, wiki or others
237 ## multiple patterns, to other issues server, wiki or others
238 ## below an example how to create a wiki pattern
238 ## below an example how to create a wiki pattern
239 # wiki-some-id -> https://mywiki.com/some-id
239 # wiki-some-id -> https://mywiki.com/some-id
240
240
241 #issue_pat_wiki = (?:wiki-)(.+)
241 #issue_pat_wiki = (?:wiki-)(.+)
242 #issue_server_link_wiki = https://mywiki.com/{id}
242 #issue_server_link_wiki = https://mywiki.com/{id}
243 #issue_prefix_wiki = WIKI-
243 #issue_prefix_wiki = WIKI-
244
244
245
245
246 ## instance-id prefix
246 ## instance-id prefix
247 ## a prefix key for this instance used for cache invalidation when running
247 ## a prefix key for this instance used for cache invalidation when running
248 ## multiple instances of kallithea, make sure it's globally unique for
248 ## multiple instances of kallithea, make sure it's globally unique for
249 ## all running kallithea instances. Leave empty if you don't use it
249 ## all running kallithea instances. Leave empty if you don't use it
250 instance_id =
250 instance_id =
251
251
252 ## alternative return HTTP header for failed authentication. Default HTTP
252 ## alternative return HTTP header for failed authentication. Default HTTP
253 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
253 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
254 ## handling that. Set this variable to 403 to return HTTPForbidden
254 ## handling that. Set this variable to 403 to return HTTPForbidden
255 auth_ret_code =
255 auth_ret_code =
256
256
257 ## locking return code. When repository is locked return this HTTP code. 2XX
257 ## locking return code. When repository is locked return this HTTP code. 2XX
258 ## codes don't break the transactions while 4XX codes do
258 ## codes don't break the transactions while 4XX codes do
259 lock_ret_code = 423
259 lock_ret_code = 423
260
260
261 ## allows to change the repository location in settings page
261 ## allows to change the repository location in settings page
262 allow_repo_location_change = True
262 allow_repo_location_change = True
263
263
264 ## allows to setup custom hooks in settings page
264 ## allows to setup custom hooks in settings page
265 allow_custom_hooks_settings = True
265 allow_custom_hooks_settings = True
266
266
267
267
268 ####################################
268 ####################################
269 ### CELERY CONFIG ####
269 ### CELERY CONFIG ####
270 ####################################
270 ####################################
271
271
272 use_celery = false
272 use_celery = false
273 broker.host = localhost
273 broker.host = localhost
274 broker.vhost = rabbitmqhost
274 broker.vhost = rabbitmqhost
275 broker.port = 5672
275 broker.port = 5672
276 broker.user = rabbitmq
276 broker.user = rabbitmq
277 broker.password = qweqwe
277 broker.password = qweqwe
278
278
279 celery.imports = kallithea.lib.celerylib.tasks
279 celery.imports = kallithea.lib.celerylib.tasks
280
280
281 celery.result.backend = amqp
281 celery.result.backend = amqp
282 celery.result.dburi = amqp://
282 celery.result.dburi = amqp://
283 celery.result.serialier = json
283 celery.result.serialier = json
284
284
285 #celery.send.task.error.emails = true
285 #celery.send.task.error.emails = true
286 #celery.amqp.task.result.expires = 18000
286 #celery.amqp.task.result.expires = 18000
287
287
288 celeryd.concurrency = 2
288 celeryd.concurrency = 2
289 #celeryd.log.file = celeryd.log
289 #celeryd.log.file = celeryd.log
290 celeryd.log.level = debug
290 celeryd.log.level = debug
291 celeryd.max.tasks.per.child = 1
291 celeryd.max.tasks.per.child = 1
292
292
293 ## tasks will never be sent to the queue, but executed locally instead.
293 ## tasks will never be sent to the queue, but executed locally instead.
294 celery.always.eager = false
294 celery.always.eager = false
295
295
296 ####################################
296 ####################################
297 ### BEAKER CACHE ####
297 ### BEAKER CACHE ####
298 ####################################
298 ####################################
299
299
300 beaker.cache.data_dir=%(here)s/data/cache/data
300 beaker.cache.data_dir=%(here)s/data/cache/data
301 beaker.cache.lock_dir=%(here)s/data/cache/lock
301 beaker.cache.lock_dir=%(here)s/data/cache/lock
302
302
303 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
303 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
304
304
305 beaker.cache.super_short_term.type=memory
305 beaker.cache.super_short_term.type=memory
306 beaker.cache.super_short_term.expire=10
306 beaker.cache.super_short_term.expire=10
307 beaker.cache.super_short_term.key_length = 256
307 beaker.cache.super_short_term.key_length = 256
308
308
309 beaker.cache.short_term.type=memory
309 beaker.cache.short_term.type=memory
310 beaker.cache.short_term.expire=60
310 beaker.cache.short_term.expire=60
311 beaker.cache.short_term.key_length = 256
311 beaker.cache.short_term.key_length = 256
312
312
313 beaker.cache.long_term.type=memory
313 beaker.cache.long_term.type=memory
314 beaker.cache.long_term.expire=36000
314 beaker.cache.long_term.expire=36000
315 beaker.cache.long_term.key_length = 256
315 beaker.cache.long_term.key_length = 256
316
316
317 beaker.cache.sql_cache_short.type=memory
317 beaker.cache.sql_cache_short.type=memory
318 beaker.cache.sql_cache_short.expire=10
318 beaker.cache.sql_cache_short.expire=10
319 beaker.cache.sql_cache_short.key_length = 256
319 beaker.cache.sql_cache_short.key_length = 256
320
320
321 beaker.cache.sql_cache_med.type=memory
321 beaker.cache.sql_cache_med.type=memory
322 beaker.cache.sql_cache_med.expire=360
322 beaker.cache.sql_cache_med.expire=360
323 beaker.cache.sql_cache_med.key_length = 256
323 beaker.cache.sql_cache_med.key_length = 256
324
324
325 beaker.cache.sql_cache_long.type=file
325 beaker.cache.sql_cache_long.type=file
326 beaker.cache.sql_cache_long.expire=3600
326 beaker.cache.sql_cache_long.expire=3600
327 beaker.cache.sql_cache_long.key_length = 256
327 beaker.cache.sql_cache_long.key_length = 256
328
328
329 ####################################
329 ####################################
330 ### BEAKER SESSION ####
330 ### BEAKER SESSION ####
331 ####################################
331 ####################################
332 ## Type of storage used for the session, current types are
332 ## Type of storage used for the session, current types are
333 ## dbm, file, memcached, database, and memory.
333 ## dbm, file, memcached, database, and memory.
334 ## The storage uses the Container API
334 ## The storage uses the Container API
335 ## that is also used by the cache system.
335 ## that is also used by the cache system.
336
336
337 ## db session ##
337 ## db session ##
338 #beaker.session.type = ext:database
338 #beaker.session.type = ext:database
339 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
339 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
340 #beaker.session.table_name = db_session
340 #beaker.session.table_name = db_session
341
341
342 ## encrypted cookie client side session, good for many instances ##
342 ## encrypted cookie client side session, good for many instances ##
343 #beaker.session.type = cookie
343 #beaker.session.type = cookie
344
344
345 ## file based cookies (default) ##
345 ## file based cookies (default) ##
346 #beaker.session.type = file
346 #beaker.session.type = file
347
347
348 beaker.session.key = kallithea
348 beaker.session.key = kallithea
349 beaker.session.secret = ${app_instance_uuid}
349 beaker.session.secret = ${app_instance_uuid}
350
350
351 ## Secure encrypted cookie. Requires AES and AES python libraries
351 ## Secure encrypted cookie. Requires AES and AES python libraries
352 ## you must disable beaker.session.secret to use this
352 ## you must disable beaker.session.secret to use this
353 #beaker.session.encrypt_key = <key_for_encryption>
353 #beaker.session.encrypt_key = <key_for_encryption>
354 #beaker.session.validate_key = <validation_key>
354 #beaker.session.validate_key = <validation_key>
355
355
356 ## sets session as invalid if it haven't been accessed for given amount of time
356 ## sets session as invalid if it haven't been accessed for given amount of time
357 beaker.session.timeout = 2592000
357 beaker.session.timeout = 2592000
358 beaker.session.httponly = true
358 beaker.session.httponly = true
359 #beaker.session.cookie_path = /<your-prefix>
359 #beaker.session.cookie_path = /<your-prefix>
360
360
361 ## uncomment for https secure cookie
361 ## uncomment for https secure cookie
362 beaker.session.secure = false
362 beaker.session.secure = false
363
363
364 ## auto save the session to not to use .save()
364 ## auto save the session to not to use .save()
365 beaker.session.auto = False
365 beaker.session.auto = False
366
366
367 ## default cookie expiration time in seconds `true` expire at browser close ##
367 ## default cookie expiration time in seconds `true` expire at browser close ##
368 #beaker.session.cookie_expires = 3600
368 #beaker.session.cookie_expires = 3600
369
369
370
370
371 ############################
371 ############################
372 ## ERROR HANDLING SYSTEMS ##
372 ## ERROR HANDLING SYSTEMS ##
373 ############################
373 ############################
374
374
375 ####################
375 ####################
376 ### [errormator] ###
376 ### [errormator] ###
377 ####################
377 ####################
378
378
379 ## Errormator is tailored to work with Kallithea, see
379 ## Errormator is tailored to work with Kallithea, see
380 ## http://errormator.com for details how to obtain an account
380 ## http://errormator.com for details how to obtain an account
381 ## you must install python package `errormator_client` to make it work
381 ## you must install python package `errormator_client` to make it work
382
382
383 ## errormator enabled
383 ## errormator enabled
384 errormator = false
384 errormator = false
385
385
386 errormator.server_url = https://api.errormator.com
386 errormator.server_url = https://api.errormator.com
387 errormator.api_key = YOUR_API_KEY
387 errormator.api_key = YOUR_API_KEY
388
388
389 ## TWEAK AMOUNT OF INFO SENT HERE
389 ## TWEAK AMOUNT OF INFO SENT HERE
390
390
391 ## enables 404 error logging (default False)
391 ## enables 404 error logging (default False)
392 errormator.report_404 = false
392 errormator.report_404 = false
393
393
394 ## time in seconds after request is considered being slow (default 1)
394 ## time in seconds after request is considered being slow (default 1)
395 errormator.slow_request_time = 1
395 errormator.slow_request_time = 1
396
396
397 ## record slow requests in application
397 ## record slow requests in application
398 ## (needs to be enabled for slow datastore recording and time tracking)
398 ## (needs to be enabled for slow datastore recording and time tracking)
399 errormator.slow_requests = true
399 errormator.slow_requests = true
400
400
401 ## enable hooking to application loggers
401 ## enable hooking to application loggers
402 # errormator.logging = true
402 # errormator.logging = true
403
403
404 ## minimum log level for log capture
404 ## minimum log level for log capture
405 # errormator.logging.level = WARNING
405 # errormator.logging.level = WARNING
406
406
407 ## send logs only from erroneous/slow requests
407 ## send logs only from erroneous/slow requests
408 ## (saves API quota for intensive logging)
408 ## (saves API quota for intensive logging)
409 errormator.logging_on_error = false
409 errormator.logging_on_error = false
410
410
411 ## list of additonal keywords that should be grabbed from environ object
411 ## list of additonal keywords that should be grabbed from environ object
412 ## can be string with comma separated list of words in lowercase
412 ## can be string with comma separated list of words in lowercase
413 ## (by default client will always send following info:
413 ## (by default client will always send following info:
414 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
414 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
415 ## start with HTTP* this list be extended with additional keywords here
415 ## start with HTTP* this list be extended with additional keywords here
416 errormator.environ_keys_whitelist =
416 errormator.environ_keys_whitelist =
417
417
418
418
419 ## list of keywords that should be blanked from request object
419 ## list of keywords that should be blanked from request object
420 ## can be string with comma separated list of words in lowercase
420 ## can be string with comma separated list of words in lowercase
421 ## (by default client will always blank keys that contain following words
421 ## (by default client will always blank keys that contain following words
422 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
422 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
423 ## this list be extended with additional keywords set here
423 ## this list be extended with additional keywords set here
424 errormator.request_keys_blacklist =
424 errormator.request_keys_blacklist =
425
425
426
426
427 ## list of namespaces that should be ignores when gathering log entries
427 ## list of namespaces that should be ignores when gathering log entries
428 ## can be string with comma separated list of namespaces
428 ## can be string with comma separated list of namespaces
429 ## (by default the client ignores own entries: errormator_client.client)
429 ## (by default the client ignores own entries: errormator_client.client)
430 errormator.log_namespace_blacklist =
430 errormator.log_namespace_blacklist =
431
431
432
432
433 ################
433 ################
434 ### [sentry] ###
434 ### [sentry] ###
435 ################
435 ################
436
436
437 ## sentry is a alternative open source error aggregator
437 ## sentry is a alternative open source error aggregator
438 ## you must install python packages `sentry` and `raven` to enable
438 ## you must install python packages `sentry` and `raven` to enable
439
439
440 sentry.dsn = YOUR_DNS
440 sentry.dsn = YOUR_DNS
441 sentry.servers =
441 sentry.servers =
442 sentry.name =
442 sentry.name =
443 sentry.key =
443 sentry.key =
444 sentry.public_key =
444 sentry.public_key =
445 sentry.secret_key =
445 sentry.secret_key =
446 sentry.project =
446 sentry.project =
447 sentry.site =
447 sentry.site =
448 sentry.include_paths =
448 sentry.include_paths =
449 sentry.exclude_paths =
449 sentry.exclude_paths =
450
450
451
451
452 ################################################################################
452 ################################################################################
453 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
453 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
454 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
454 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
455 ## execute malicious code after an exception is raised. ##
455 ## execute malicious code after an exception is raised. ##
456 ################################################################################
456 ################################################################################
457 set debug = false
457 set debug = false
458
458
459 ##################################
459 ##################################
460 ### LOGVIEW CONFIG ###
460 ### LOGVIEW CONFIG ###
461 ##################################
461 ##################################
462
462
463 logview.sqlalchemy = #faa
463 logview.sqlalchemy = #faa
464 logview.pylons.templating = #bfb
464 logview.pylons.templating = #bfb
465 logview.pylons.util = #eee
465 logview.pylons.util = #eee
466
466
467 #########################################################
467 #########################################################
468 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
468 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
469 #########################################################
469 #########################################################
470
470
471 # SQLITE [default]
471 # SQLITE [default]
472 sqlalchemy.db1.url = sqlite:///%(here)s/kallithea.db?timeout=60
472 sqlalchemy.db1.url = sqlite:///%(here)s/kallithea.db?timeout=60
473
473
474 # POSTGRESQL
474 # POSTGRESQL
475 # sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
475 # sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
476
476
477 # MySQL
477 # MySQL
478 # sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
478 # sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
479
479
480 # see sqlalchemy docs for others
480 # see sqlalchemy docs for others
481
481
482 sqlalchemy.db1.echo = false
482 sqlalchemy.db1.echo = false
483 sqlalchemy.db1.pool_recycle = 3600
483 sqlalchemy.db1.pool_recycle = 3600
484 sqlalchemy.db1.convert_unicode = true
484 sqlalchemy.db1.convert_unicode = true
485
485
486 ################################
486 ################################
487 ### LOGGING CONFIGURATION ####
487 ### LOGGING CONFIGURATION ####
488 ################################
488 ################################
489
489
490 [loggers]
490 [loggers]
491 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
491 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
492
492
493 [handlers]
493 [handlers]
494 keys = console, console_sql
494 keys = console, console_sql
495
495
496 [formatters]
496 [formatters]
497 keys = generic, color_formatter, color_formatter_sql
497 keys = generic, color_formatter, color_formatter_sql
498
498
499 #############
499 #############
500 ## LOGGERS ##
500 ## LOGGERS ##
501 #############
501 #############
502
502
503 [logger_root]
503 [logger_root]
504 level = NOTSET
504 level = NOTSET
505 handlers = console
505 handlers = console
506
506
507 [logger_routes]
507 [logger_routes]
508 level = DEBUG
508 level = DEBUG
509 handlers =
509 handlers =
510 qualname = routes.middleware
510 qualname = routes.middleware
511 ## "level = DEBUG" logs the route matched and routing variables.
511 ## "level = DEBUG" logs the route matched and routing variables.
512 propagate = 1
512 propagate = 1
513
513
514 [logger_beaker]
514 [logger_beaker]
515 level = DEBUG
515 level = DEBUG
516 handlers =
516 handlers =
517 qualname = beaker.container
517 qualname = beaker.container
518 propagate = 1
518 propagate = 1
519
519
520 [logger_templates]
520 [logger_templates]
521 level = INFO
521 level = INFO
522 handlers =
522 handlers =
523 qualname = pylons.templating
523 qualname = pylons.templating
524 propagate = 1
524 propagate = 1
525
525
526 [logger_kallithea]
526 [logger_kallithea]
527 level = DEBUG
527 level = DEBUG
528 handlers =
528 handlers =
529 qualname = kallithea
529 qualname = kallithea
530 propagate = 1
530 propagate = 1
531
531
532 [logger_sqlalchemy]
532 [logger_sqlalchemy]
533 level = INFO
533 level = INFO
534 handlers = console_sql
534 handlers = console_sql
535 qualname = sqlalchemy.engine
535 qualname = sqlalchemy.engine
536 propagate = 0
536 propagate = 0
537
537
538 [logger_whoosh_indexer]
538 [logger_whoosh_indexer]
539 level = DEBUG
539 level = DEBUG
540 handlers =
540 handlers =
541 qualname = whoosh_indexer
541 qualname = whoosh_indexer
542 propagate = 1
542 propagate = 1
543
543
544 ##############
544 ##############
545 ## HANDLERS ##
545 ## HANDLERS ##
546 ##############
546 ##############
547
547
548 [handler_console]
548 [handler_console]
549 class = StreamHandler
549 class = StreamHandler
550 args = (sys.stderr,)
550 args = (sys.stderr,)
551 level = INFO
551 level = INFO
552 formatter = generic
552 formatter = generic
553
553
554 [handler_console_sql]
554 [handler_console_sql]
555 class = StreamHandler
555 class = StreamHandler
556 args = (sys.stderr,)
556 args = (sys.stderr,)
557 level = WARN
557 level = WARN
558 formatter = generic
558 formatter = generic
559
559
560 ################
560 ################
561 ## FORMATTERS ##
561 ## FORMATTERS ##
562 ################
562 ################
563
563
564 [formatter_generic]
564 [formatter_generic]
565 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
565 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
566 datefmt = %Y-%m-%d %H:%M:%S
566 datefmt = %Y-%m-%d %H:%M:%S
567
567
568 [formatter_color_formatter]
568 [formatter_color_formatter]
569 class=kallithea.lib.colored_formatter.ColorFormatter
569 class=kallithea.lib.colored_formatter.ColorFormatter
570 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
570 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
571 datefmt = %Y-%m-%d %H:%M:%S
571 datefmt = %Y-%m-%d %H:%M:%S
572
572
573 [formatter_color_formatter_sql]
573 [formatter_color_formatter_sql]
574 class=kallithea.lib.colored_formatter.ColorFormatterSql
574 class=kallithea.lib.colored_formatter.ColorFormatterSql
575 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
575 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
576 datefmt = %Y-%m-%d %H:%M:%S
576 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,147 +1,147 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.controllers.search
15 kallithea.controllers.search
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Search controller for Kallithea
18 Search controller for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Aug 7, 2010
22 :created_on: Aug 7, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import urllib
30 import urllib
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons import request, config, tmpl_context as c
32 from pylons import request, config, tmpl_context as c
33
33
34 from whoosh.index import open_dir, EmptyIndexError
34 from whoosh.index import open_dir, EmptyIndexError
35 from whoosh.qparser import QueryParser, QueryParserError
35 from whoosh.qparser import QueryParser, QueryParserError
36 from whoosh.query import Phrase, Prefix
36 from whoosh.query import Phrase, Prefix
37 from webhelpers.util import update_params
37 from webhelpers.util import update_params
38
38
39 from kallithea.lib.auth import LoginRequired
39 from kallithea.lib.auth import LoginRequired
40 from kallithea.lib.base import BaseRepoController, render
40 from kallithea.lib.base import BaseRepoController, render
41 from kallithea.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
41 from kallithea.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
42 IDX_NAME, WhooshResultWrapper
42 IDX_NAME, WhooshResultWrapper
43 from kallithea.model.repo import RepoModel
43 from kallithea.model.repo import RepoModel
44 from kallithea.lib.utils2 import safe_str, safe_int
44 from kallithea.lib.utils2 import safe_str, safe_int
45 from kallithea.lib.helpers import Page
45 from kallithea.lib.helpers import Page
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 class SearchController(BaseRepoController):
50 class SearchController(BaseRepoController):
51
51
52 def __before__(self):
52 def __before__(self):
53 super(SearchController, self).__before__()
53 super(SearchController, self).__before__()
54
54
55 @LoginRequired()
55 @LoginRequired()
56 def index(self, repo_name=None):
56 def index(self, repo_name=None):
57 c.repo_name = repo_name
57 c.repo_name = repo_name
58 c.formated_results = []
58 c.formated_results = []
59 c.runtime = ''
59 c.runtime = ''
60 c.cur_query = request.GET.get('q', None)
60 c.cur_query = request.GET.get('q', None)
61 c.cur_type = request.GET.get('type', 'content')
61 c.cur_type = request.GET.get('type', 'content')
62 c.cur_search = search_type = {'content': 'content',
62 c.cur_search = search_type = {'content': 'content',
63 'commit': 'message',
63 'commit': 'message',
64 'path': 'path',
64 'path': 'path',
65 'repository': 'repository'
65 'repository': 'repository'
66 }.get(c.cur_type, 'content')
66 }.get(c.cur_type, 'content')
67
67
68 index_name = {
68 index_name = {
69 'content': IDX_NAME,
69 'content': IDX_NAME,
70 'commit': CHGSET_IDX_NAME,
70 'commit': CHGSET_IDX_NAME,
71 'path': IDX_NAME
71 'path': IDX_NAME
72 }.get(c.cur_type, IDX_NAME)
72 }.get(c.cur_type, IDX_NAME)
73
73
74 schema_defn = {
74 schema_defn = {
75 'content': SCHEMA,
75 'content': SCHEMA,
76 'commit': CHGSETS_SCHEMA,
76 'commit': CHGSETS_SCHEMA,
77 'path': SCHEMA
77 'path': SCHEMA
78 }.get(c.cur_type, SCHEMA)
78 }.get(c.cur_type, SCHEMA)
79
79
80 log.debug('IDX: %s' % index_name)
80 log.debug('IDX: %s' % index_name)
81 log.debug('SCHEMA: %s' % schema_defn)
81 log.debug('SCHEMA: %s' % schema_defn)
82
82
83 if c.cur_query:
83 if c.cur_query:
84 cur_query = c.cur_query.lower()
84 cur_query = c.cur_query.lower()
85 log.debug(cur_query)
85 log.debug(cur_query)
86
86
87 if c.cur_query:
87 if c.cur_query:
88 p = safe_int(request.GET.get('page', 1), 1)
88 p = safe_int(request.GET.get('page', 1), 1)
89 highlight_items = set()
89 highlight_items = set()
90 try:
90 try:
91 idx = open_dir(config['app_conf']['index_dir'],
91 idx = open_dir(config['app_conf']['index_dir'],
92 indexname=index_name)
92 indexname=index_name)
93 searcher = idx.searcher()
93 searcher = idx.searcher()
94
94
95 qp = QueryParser(search_type, schema=schema_defn)
95 qp = QueryParser(search_type, schema=schema_defn)
96 if c.repo_name:
96 if c.repo_name:
97 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
97 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
98 try:
98 try:
99 query = qp.parse(unicode(cur_query))
99 query = qp.parse(unicode(cur_query))
100 # extract words for highlight
100 # extract words for highlight
101 if isinstance(query, Phrase):
101 if isinstance(query, Phrase):
102 highlight_items.update(query.words)
102 highlight_items.update(query.words)
103 elif isinstance(query, Prefix):
103 elif isinstance(query, Prefix):
104 highlight_items.add(query.text)
104 highlight_items.add(query.text)
105 else:
105 else:
106 for i in query.all_terms():
106 for i in query.all_terms():
107 if i[0] in ['content', 'message']:
107 if i[0] in ['content', 'message']:
108 highlight_items.add(i[1])
108 highlight_items.add(i[1])
109
109
110 matcher = query.matcher(searcher)
110 matcher = query.matcher(searcher)
111
111
112 log.debug('query: %s' % query)
112 log.debug('query: %s' % query)
113 log.debug('hl terms: %s' % highlight_items)
113 log.debug('hl terms: %s' % highlight_items)
114 results = searcher.search(query)
114 results = searcher.search(query)
115 res_ln = len(results)
115 res_ln = len(results)
116 c.runtime = '%s results (%.3f seconds)' % (
116 c.runtime = '%s results (%.3f seconds)' % (
117 res_ln, results.runtime
117 res_ln, results.runtime
118 )
118 )
119
119
120 def url_generator(**kw):
120 def url_generator(**kw):
121 q = urllib.quote(safe_str(c.cur_query))
121 q = urllib.quote(safe_str(c.cur_query))
122 return update_params("?q=%s&type=%s" \
122 return update_params("?q=%s&type=%s" \
123 % (q, safe_str(c.cur_type)), **kw)
123 % (q, safe_str(c.cur_type)), **kw)
124 repo_location = RepoModel().repos_path
124 repo_location = RepoModel().repos_path
125 c.formated_results = Page(
125 c.formated_results = Page(
126 WhooshResultWrapper(search_type, searcher, matcher,
126 WhooshResultWrapper(search_type, searcher, matcher,
127 highlight_items, repo_location),
127 highlight_items, repo_location),
128 page=p,
128 page=p,
129 item_count=res_ln,
129 item_count=res_ln,
130 items_per_page=10,
130 items_per_page=10,
131 url=url_generator
131 url=url_generator
132 )
132 )
133
133
134 except QueryParserError:
134 except QueryParserError:
135 c.runtime = _('Invalid search query. Try quoting it.')
135 c.runtime = _('Invalid search query. Try quoting it.')
136 searcher.close()
136 searcher.close()
137 except (EmptyIndexError, IOError):
137 except (EmptyIndexError, IOError):
138 log.error(traceback.format_exc())
138 log.error(traceback.format_exc())
139 log.error('Empty Index data')
139 log.error('Empty Index data')
140 c.runtime = _('There is no index to search in. '
140 c.runtime = _('There is no index to search in. '
141 'Please run whoosh indexer')
141 'Please run whoosh indexer')
142 except (Exception):
142 except (Exception):
143 log.error(traceback.format_exc())
143 log.error(traceback.format_exc())
144 c.runtime = _('An error occurred during this search operation')
144 c.runtime = _('An error occurred during search operation.')
145
145
146 # Return a rendered template
146 # Return a rendered template
147 return render('/search/search.html')
147 return render('/search/search.html')
@@ -1,305 +1,305 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.middleware.simplegit
15 kallithea.lib.middleware.simplegit
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 SimpleGit middleware for handling git protocol request (push/clone etc.)
18 SimpleGit middleware for handling git protocol request (push/clone etc.)
19 It's implemented with basic auth function
19 It's implemented with basic auth function
20
20
21 This file was forked by the Kallithea project in July 2014.
21 This file was forked by the Kallithea project in July 2014.
22 Original author and date, and relevant copyright and licensing information is below:
22 Original author and date, and relevant copyright and licensing information is below:
23 :created_on: Apr 28, 2010
23 :created_on: Apr 28, 2010
24 :author: marcink
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 :license: GPLv3, see LICENSE.md for more details.
26 :license: GPLv3, see LICENSE.md for more details.
27
27
28 """
28 """
29
29
30
30
31 import os
31 import os
32 import re
32 import re
33 import logging
33 import logging
34 import traceback
34 import traceback
35
35
36 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
36 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
37 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
37 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
38 HTTPNotAcceptable
38 HTTPNotAcceptable
39 from kallithea.model.db import User, Ui
39 from kallithea.model.db import User, Ui
40
40
41 from kallithea.lib.utils2 import safe_str, fix_PATH, get_server_url,\
41 from kallithea.lib.utils2 import safe_str, fix_PATH, get_server_url,\
42 _set_extras
42 _set_extras
43 from kallithea.lib.base import BaseVCSController
43 from kallithea.lib.base import BaseVCSController
44 from kallithea.lib.utils import make_ui, is_valid_repo
44 from kallithea.lib.utils import make_ui, is_valid_repo
45 from kallithea.lib.exceptions import HTTPLockedRC
45 from kallithea.lib.exceptions import HTTPLockedRC
46 from kallithea.lib.hooks import pre_pull
46 from kallithea.lib.hooks import pre_pull
47 from kallithea.lib import auth_modules
47 from kallithea.lib import auth_modules
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
52 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
53
53
54
54
55 def is_git(environ):
55 def is_git(environ):
56 path_info = environ['PATH_INFO']
56 path_info = environ['PATH_INFO']
57 isgit_path = GIT_PROTO_PAT.match(path_info)
57 isgit_path = GIT_PROTO_PAT.match(path_info)
58 log.debug('pathinfo: %s detected as GIT %s' % (
58 log.debug('pathinfo: %s detected as Git %s' % (
59 path_info, isgit_path is not None)
59 path_info, isgit_path is not None)
60 )
60 )
61 return isgit_path
61 return isgit_path
62
62
63
63
64 class SimpleGit(BaseVCSController):
64 class SimpleGit(BaseVCSController):
65
65
66 def _handle_request(self, environ, start_response):
66 def _handle_request(self, environ, start_response):
67 if not is_git(environ):
67 if not is_git(environ):
68 return self.application(environ, start_response)
68 return self.application(environ, start_response)
69 if not self._check_ssl(environ):
69 if not self._check_ssl(environ):
70 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
70 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
71
71
72 ip_addr = self._get_ip_addr(environ)
72 ip_addr = self._get_ip_addr(environ)
73 username = None
73 username = None
74 self._git_first_op = False
74 self._git_first_op = False
75 # skip passing error to error controller
75 # skip passing error to error controller
76 environ['pylons.status_code_redirect'] = True
76 environ['pylons.status_code_redirect'] = True
77
77
78 #======================================================================
78 #======================================================================
79 # EXTRACT REPOSITORY NAME FROM ENV
79 # EXTRACT REPOSITORY NAME FROM ENV
80 #======================================================================
80 #======================================================================
81 try:
81 try:
82 repo_name = self.__get_repository(environ)
82 repo_name = self.__get_repository(environ)
83 log.debug('Extracted repo name is %s' % repo_name)
83 log.debug('Extracted repo name is %s' % repo_name)
84 except Exception:
84 except Exception:
85 return HTTPInternalServerError()(environ, start_response)
85 return HTTPInternalServerError()(environ, start_response)
86
86
87 # quick check if that dir exists...
87 # quick check if that dir exists...
88 if not is_valid_repo(repo_name, self.basepath, 'git'):
88 if not is_valid_repo(repo_name, self.basepath, 'git'):
89 return HTTPNotFound()(environ, start_response)
89 return HTTPNotFound()(environ, start_response)
90
90
91 #======================================================================
91 #======================================================================
92 # GET ACTION PULL or PUSH
92 # GET ACTION PULL or PUSH
93 #======================================================================
93 #======================================================================
94 action = self.__get_action(environ)
94 action = self.__get_action(environ)
95
95
96 #======================================================================
96 #======================================================================
97 # CHECK ANONYMOUS PERMISSION
97 # CHECK ANONYMOUS PERMISSION
98 #======================================================================
98 #======================================================================
99 if action in ['pull', 'push']:
99 if action in ['pull', 'push']:
100 anonymous_user = self.__get_user('default')
100 anonymous_user = self.__get_user('default')
101 username = anonymous_user.username
101 username = anonymous_user.username
102 if anonymous_user.active:
102 if anonymous_user.active:
103 # ONLY check permissions if the user is activated
103 # ONLY check permissions if the user is activated
104 anonymous_perm = self._check_permission(action, anonymous_user,
104 anonymous_perm = self._check_permission(action, anonymous_user,
105 repo_name, ip_addr)
105 repo_name, ip_addr)
106 else:
106 else:
107 anonymous_perm = False
107 anonymous_perm = False
108
108
109 if not anonymous_user.active or not anonymous_perm:
109 if not anonymous_user.active or not anonymous_perm:
110 if not anonymous_user.active:
110 if not anonymous_user.active:
111 log.debug('Anonymous access is disabled, running '
111 log.debug('Anonymous access is disabled, running '
112 'authentication')
112 'authentication')
113
113
114 if not anonymous_perm:
114 if not anonymous_perm:
115 log.debug('Not enough credentials to access this '
115 log.debug('Not enough credentials to access this '
116 'repository as anonymous user')
116 'repository as anonymous user')
117
117
118 username = None
118 username = None
119 #==============================================================
119 #==============================================================
120 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
120 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
121 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
121 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
122 #==============================================================
122 #==============================================================
123
123
124 # try to auth based on environ, container auth methods
124 # try to auth based on environ, container auth methods
125 log.debug('Running PRE-AUTH for container based authentication')
125 log.debug('Running PRE-AUTH for container based authentication')
126 pre_auth = auth_modules.authenticate('', '', environ)
126 pre_auth = auth_modules.authenticate('', '', environ)
127 if pre_auth and pre_auth.get('username'):
127 if pre_auth and pre_auth.get('username'):
128 username = pre_auth['username']
128 username = pre_auth['username']
129 log.debug('PRE-AUTH got %s as username' % username)
129 log.debug('PRE-AUTH got %s as username' % username)
130
130
131 # If not authenticated by the container, running basic auth
131 # If not authenticated by the container, running basic auth
132 if not username:
132 if not username:
133 self.authenticate.realm = \
133 self.authenticate.realm = \
134 safe_str(self.config['realm'])
134 safe_str(self.config['realm'])
135 result = self.authenticate(environ)
135 result = self.authenticate(environ)
136 if isinstance(result, str):
136 if isinstance(result, str):
137 AUTH_TYPE.update(environ, 'basic')
137 AUTH_TYPE.update(environ, 'basic')
138 REMOTE_USER.update(environ, result)
138 REMOTE_USER.update(environ, result)
139 username = result
139 username = result
140 else:
140 else:
141 return result.wsgi_application(environ, start_response)
141 return result.wsgi_application(environ, start_response)
142
142
143 #==============================================================
143 #==============================================================
144 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
144 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
145 #==============================================================
145 #==============================================================
146 try:
146 try:
147 user = self.__get_user(username)
147 user = self.__get_user(username)
148 if user is None or not user.active:
148 if user is None or not user.active:
149 return HTTPForbidden()(environ, start_response)
149 return HTTPForbidden()(environ, start_response)
150 username = user.username
150 username = user.username
151 except Exception:
151 except Exception:
152 log.error(traceback.format_exc())
152 log.error(traceback.format_exc())
153 return HTTPInternalServerError()(environ, start_response)
153 return HTTPInternalServerError()(environ, start_response)
154
154
155 #check permissions for this repository
155 #check permissions for this repository
156 perm = self._check_permission(action, user, repo_name, ip_addr)
156 perm = self._check_permission(action, user, repo_name, ip_addr)
157 if not perm:
157 if not perm:
158 return HTTPForbidden()(environ, start_response)
158 return HTTPForbidden()(environ, start_response)
159
159
160 # extras are injected into UI object and later available
160 # extras are injected into UI object and later available
161 # in hooks executed by kallithea
161 # in hooks executed by kallithea
162 from kallithea import CONFIG
162 from kallithea import CONFIG
163 server_url = get_server_url(environ)
163 server_url = get_server_url(environ)
164 extras = {
164 extras = {
165 'ip': ip_addr,
165 'ip': ip_addr,
166 'username': username,
166 'username': username,
167 'action': action,
167 'action': action,
168 'repository': repo_name,
168 'repository': repo_name,
169 'scm': 'git',
169 'scm': 'git',
170 'config': CONFIG['__file__'],
170 'config': CONFIG['__file__'],
171 'server_url': server_url,
171 'server_url': server_url,
172 'make_lock': None,
172 'make_lock': None,
173 'locked_by': [None, None]
173 'locked_by': [None, None]
174 }
174 }
175
175
176 #===================================================================
176 #===================================================================
177 # GIT REQUEST HANDLING
177 # GIT REQUEST HANDLING
178 #===================================================================
178 #===================================================================
179 str_repo_name = safe_str(repo_name)
179 str_repo_name = safe_str(repo_name)
180 repo_path = os.path.join(safe_str(self.basepath),str_repo_name)
180 repo_path = os.path.join(safe_str(self.basepath),str_repo_name)
181 log.debug('Repository path is %s' % repo_path)
181 log.debug('Repository path is %s' % repo_path)
182
182
183 # CHECK LOCKING only if it's not ANONYMOUS USER
183 # CHECK LOCKING only if it's not ANONYMOUS USER
184 if username != User.DEFAULT_USER:
184 if username != User.DEFAULT_USER:
185 log.debug('Checking locking on repository')
185 log.debug('Checking locking on repository')
186 (make_lock,
186 (make_lock,
187 locked,
187 locked,
188 locked_by) = self._check_locking_state(
188 locked_by) = self._check_locking_state(
189 environ=environ, action=action,
189 environ=environ, action=action,
190 repo=repo_name, user_id=user.user_id
190 repo=repo_name, user_id=user.user_id
191 )
191 )
192 # store the make_lock for later evaluation in hooks
192 # store the make_lock for later evaluation in hooks
193 extras.update({'make_lock': make_lock,
193 extras.update({'make_lock': make_lock,
194 'locked_by': locked_by})
194 'locked_by': locked_by})
195
195
196 fix_PATH()
196 fix_PATH()
197 log.debug('HOOKS extras is %s' % extras)
197 log.debug('HOOKS extras is %s' % extras)
198 baseui = make_ui('db')
198 baseui = make_ui('db')
199 self.__inject_extras(repo_path, baseui, extras)
199 self.__inject_extras(repo_path, baseui, extras)
200
200
201 try:
201 try:
202 self._handle_githooks(repo_name, action, baseui, environ)
202 self._handle_githooks(repo_name, action, baseui, environ)
203 log.info('%s action on GIT repo "%s" by "%s" from %s' %
203 log.info('%s action on Git repo "%s" by "%s" from %s' %
204 (action, str_repo_name, safe_str(username), ip_addr))
204 (action, str_repo_name, safe_str(username), ip_addr))
205 app = self.__make_app(repo_name, repo_path, extras)
205 app = self.__make_app(repo_name, repo_path, extras)
206 return app(environ, start_response)
206 return app(environ, start_response)
207 except HTTPLockedRC, e:
207 except HTTPLockedRC, e:
208 _code = CONFIG.get('lock_ret_code')
208 _code = CONFIG.get('lock_ret_code')
209 log.debug('Repository LOCKED ret code %s!' % (_code))
209 log.debug('Repository LOCKED ret code %s!' % (_code))
210 return e(environ, start_response)
210 return e(environ, start_response)
211 except Exception:
211 except Exception:
212 log.error(traceback.format_exc())
212 log.error(traceback.format_exc())
213 return HTTPInternalServerError()(environ, start_response)
213 return HTTPInternalServerError()(environ, start_response)
214 finally:
214 finally:
215 # invalidate cache on push
215 # invalidate cache on push
216 if action == 'push':
216 if action == 'push':
217 self._invalidate_cache(repo_name)
217 self._invalidate_cache(repo_name)
218
218
219 def __make_app(self, repo_name, repo_path, extras):
219 def __make_app(self, repo_name, repo_path, extras):
220 """
220 """
221 Make an wsgi application using dulserver
221 Make an wsgi application using dulserver
222
222
223 :param repo_name: name of the repository
223 :param repo_name: name of the repository
224 :param repo_path: full path to the repository
224 :param repo_path: full path to the repository
225 """
225 """
226
226
227 from kallithea.lib.middleware.pygrack import make_wsgi_app
227 from kallithea.lib.middleware.pygrack import make_wsgi_app
228 app = make_wsgi_app(
228 app = make_wsgi_app(
229 repo_root=safe_str(self.basepath),
229 repo_root=safe_str(self.basepath),
230 repo_name=repo_name,
230 repo_name=repo_name,
231 extras=extras,
231 extras=extras,
232 )
232 )
233 return app
233 return app
234
234
235 def __get_repository(self, environ):
235 def __get_repository(self, environ):
236 """
236 """
237 Gets repository name out of PATH_INFO header
237 Gets repository name out of PATH_INFO header
238
238
239 :param environ: environ where PATH_INFO is stored
239 :param environ: environ where PATH_INFO is stored
240 """
240 """
241 try:
241 try:
242 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
242 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
243 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
243 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
244 except Exception:
244 except Exception:
245 log.error(traceback.format_exc())
245 log.error(traceback.format_exc())
246 raise
246 raise
247
247
248 return repo_name
248 return repo_name
249
249
250 def __get_user(self, username):
250 def __get_user(self, username):
251 return User.get_by_username(username)
251 return User.get_by_username(username)
252
252
253 def __get_action(self, environ):
253 def __get_action(self, environ):
254 """
254 """
255 Maps git request commands into a pull or push command.
255 Maps git request commands into a pull or push command.
256
256
257 :param environ:
257 :param environ:
258 """
258 """
259 service = environ['QUERY_STRING'].split('=')
259 service = environ['QUERY_STRING'].split('=')
260
260
261 if len(service) > 1:
261 if len(service) > 1:
262 service_cmd = service[1]
262 service_cmd = service[1]
263 mapping = {
263 mapping = {
264 'git-receive-pack': 'push',
264 'git-receive-pack': 'push',
265 'git-upload-pack': 'pull',
265 'git-upload-pack': 'pull',
266 }
266 }
267 op = mapping[service_cmd]
267 op = mapping[service_cmd]
268 self._git_stored_op = op
268 self._git_stored_op = op
269 return op
269 return op
270 else:
270 else:
271 # try to fallback to stored variable as we don't know if the last
271 # try to fallback to stored variable as we don't know if the last
272 # operation is pull/push
272 # operation is pull/push
273 op = getattr(self, '_git_stored_op', 'pull')
273 op = getattr(self, '_git_stored_op', 'pull')
274 return op
274 return op
275
275
276 def _handle_githooks(self, repo_name, action, baseui, environ):
276 def _handle_githooks(self, repo_name, action, baseui, environ):
277 """
277 """
278 Handles pull action, push is handled by post-receive hook
278 Handles pull action, push is handled by post-receive hook
279 """
279 """
280 from kallithea.lib.hooks import log_pull_action
280 from kallithea.lib.hooks import log_pull_action
281 service = environ['QUERY_STRING'].split('=')
281 service = environ['QUERY_STRING'].split('=')
282
282
283 if len(service) < 2:
283 if len(service) < 2:
284 return
284 return
285
285
286 from kallithea.model.db import Repository
286 from kallithea.model.db import Repository
287 _repo = Repository.get_by_repo_name(repo_name)
287 _repo = Repository.get_by_repo_name(repo_name)
288 _repo = _repo.scm_instance
288 _repo = _repo.scm_instance
289
289
290 _hooks = dict(baseui.configitems('hooks')) or {}
290 _hooks = dict(baseui.configitems('hooks')) or {}
291 if action == 'pull':
291 if action == 'pull':
292 # stupid git, emulate pre-pull hook !
292 # stupid git, emulate pre-pull hook !
293 pre_pull(ui=baseui, repo=_repo._repo)
293 pre_pull(ui=baseui, repo=_repo._repo)
294 if action == 'pull' and _hooks.get(Ui.HOOK_PULL):
294 if action == 'pull' and _hooks.get(Ui.HOOK_PULL):
295 log_pull_action(ui=baseui, repo=_repo._repo)
295 log_pull_action(ui=baseui, repo=_repo._repo)
296
296
297 def __inject_extras(self, repo_path, baseui, extras={}):
297 def __inject_extras(self, repo_path, baseui, extras={}):
298 """
298 """
299 Injects some extra params into baseui instance
299 Injects some extra params into baseui instance
300
300
301 :param baseui: baseui instance
301 :param baseui: baseui instance
302 :param extras: dict with extra params to put into baseui
302 :param extras: dict with extra params to put into baseui
303 """
303 """
304
304
305 _set_extras(extras)
305 _set_extras(extras)
@@ -1,297 +1,297 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.middleware.simplehg
15 kallithea.lib.middleware.simplehg
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 SimpleHG middleware for handling mercurial protocol request
18 SimpleHg middleware for handling mercurial protocol request
19 (push/clone etc.). It's implemented with basic auth function
19 (push/clone etc.). It's implemented with basic auth function
20
20
21 This file was forked by the Kallithea project in July 2014.
21 This file was forked by the Kallithea project in July 2014.
22 Original author and date, and relevant copyright and licensing information is below:
22 Original author and date, and relevant copyright and licensing information is below:
23 :created_on: Apr 28, 2010
23 :created_on: Apr 28, 2010
24 :author: marcink
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 :license: GPLv3, see LICENSE.md for more details.
26 :license: GPLv3, see LICENSE.md for more details.
27
27
28 """
28 """
29
29
30
30
31 import os
31 import os
32 import logging
32 import logging
33 import traceback
33 import traceback
34
34
35 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
35 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
37 HTTPNotAcceptable
37 HTTPNotAcceptable
38 from kallithea.model.db import User
38 from kallithea.model.db import User
39
39
40 from kallithea.lib.utils2 import safe_str, fix_PATH, get_server_url,\
40 from kallithea.lib.utils2 import safe_str, fix_PATH, get_server_url,\
41 _set_extras
41 _set_extras
42 from kallithea.lib.base import BaseVCSController
42 from kallithea.lib.base import BaseVCSController
43 from kallithea.lib.utils import make_ui, is_valid_repo, ui_sections
43 from kallithea.lib.utils import make_ui, is_valid_repo, ui_sections
44 from kallithea.lib.vcs.utils.hgcompat import RepoError, hgweb_mod
44 from kallithea.lib.vcs.utils.hgcompat import RepoError, hgweb_mod
45 from kallithea.lib.exceptions import HTTPLockedRC
45 from kallithea.lib.exceptions import HTTPLockedRC
46 from kallithea.lib import auth_modules
46 from kallithea.lib import auth_modules
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 def is_mercurial(environ):
51 def is_mercurial(environ):
52 """
52 """
53 Returns True if request's target is mercurial server - header
53 Returns True if request's target is mercurial server - header
54 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
54 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
55 """
55 """
56 http_accept = environ.get('HTTP_ACCEPT')
56 http_accept = environ.get('HTTP_ACCEPT')
57 path_info = environ['PATH_INFO']
57 path_info = environ['PATH_INFO']
58 if http_accept and http_accept.startswith('application/mercurial'):
58 if http_accept and http_accept.startswith('application/mercurial'):
59 ishg_path = True
59 ishg_path = True
60 else:
60 else:
61 ishg_path = False
61 ishg_path = False
62
62
63 log.debug('pathinfo: %s detected as HG %s' % (
63 log.debug('pathinfo: %s detected as Mercurial %s' % (
64 path_info, ishg_path)
64 path_info, ishg_path)
65 )
65 )
66 return ishg_path
66 return ishg_path
67
67
68
68
69 class SimpleHg(BaseVCSController):
69 class SimpleHg(BaseVCSController):
70
70
71 def _handle_request(self, environ, start_response):
71 def _handle_request(self, environ, start_response):
72 if not is_mercurial(environ):
72 if not is_mercurial(environ):
73 return self.application(environ, start_response)
73 return self.application(environ, start_response)
74 if not self._check_ssl(environ):
74 if not self._check_ssl(environ):
75 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
75 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
76
76
77 ip_addr = self._get_ip_addr(environ)
77 ip_addr = self._get_ip_addr(environ)
78 username = None
78 username = None
79 # skip passing error to error controller
79 # skip passing error to error controller
80 environ['pylons.status_code_redirect'] = True
80 environ['pylons.status_code_redirect'] = True
81
81
82 #======================================================================
82 #======================================================================
83 # EXTRACT REPOSITORY NAME FROM ENV
83 # EXTRACT REPOSITORY NAME FROM ENV
84 #======================================================================
84 #======================================================================
85 try:
85 try:
86 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
86 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
87 log.debug('Extracted repo name is %s' % repo_name)
87 log.debug('Extracted repo name is %s' % repo_name)
88 except Exception:
88 except Exception:
89 return HTTPInternalServerError()(environ, start_response)
89 return HTTPInternalServerError()(environ, start_response)
90
90
91 # quick check if that dir exists...
91 # quick check if that dir exists...
92 if not is_valid_repo(repo_name, self.basepath, 'hg'):
92 if not is_valid_repo(repo_name, self.basepath, 'hg'):
93 return HTTPNotFound()(environ, start_response)
93 return HTTPNotFound()(environ, start_response)
94
94
95 #======================================================================
95 #======================================================================
96 # GET ACTION PULL or PUSH
96 # GET ACTION PULL or PUSH
97 #======================================================================
97 #======================================================================
98 action = self.__get_action(environ)
98 action = self.__get_action(environ)
99
99
100 #======================================================================
100 #======================================================================
101 # CHECK ANONYMOUS PERMISSION
101 # CHECK ANONYMOUS PERMISSION
102 #======================================================================
102 #======================================================================
103 if action in ['pull', 'push']:
103 if action in ['pull', 'push']:
104 anonymous_user = self.__get_user('default')
104 anonymous_user = self.__get_user('default')
105 username = anonymous_user.username
105 username = anonymous_user.username
106 if anonymous_user.active:
106 if anonymous_user.active:
107 # ONLY check permissions if the user is activated
107 # ONLY check permissions if the user is activated
108 anonymous_perm = self._check_permission(action, anonymous_user,
108 anonymous_perm = self._check_permission(action, anonymous_user,
109 repo_name, ip_addr)
109 repo_name, ip_addr)
110 else:
110 else:
111 anonymous_perm = False
111 anonymous_perm = False
112
112
113 if not anonymous_user.active or not anonymous_perm:
113 if not anonymous_user.active or not anonymous_perm:
114 if not anonymous_user.active:
114 if not anonymous_user.active:
115 log.debug('Anonymous access is disabled, running '
115 log.debug('Anonymous access is disabled, running '
116 'authentication')
116 'authentication')
117
117
118 if not anonymous_perm:
118 if not anonymous_perm:
119 log.debug('Not enough credentials to access this '
119 log.debug('Not enough credentials to access this '
120 'repository as anonymous user')
120 'repository as anonymous user')
121
121
122 username = None
122 username = None
123 #==============================================================
123 #==============================================================
124 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
124 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
125 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
125 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
126 #==============================================================
126 #==============================================================
127
127
128 # try to auth based on environ, container auth methods
128 # try to auth based on environ, container auth methods
129 log.debug('Running PRE-AUTH for container based authentication')
129 log.debug('Running PRE-AUTH for container based authentication')
130 pre_auth = auth_modules.authenticate('', '', environ)
130 pre_auth = auth_modules.authenticate('', '', environ)
131 if pre_auth and pre_auth.get('username'):
131 if pre_auth and pre_auth.get('username'):
132 username = pre_auth['username']
132 username = pre_auth['username']
133 log.debug('PRE-AUTH got %s as username' % username)
133 log.debug('PRE-AUTH got %s as username' % username)
134
134
135 # If not authenticated by the container, running basic auth
135 # If not authenticated by the container, running basic auth
136 if not username:
136 if not username:
137 self.authenticate.realm = \
137 self.authenticate.realm = \
138 safe_str(self.config['realm'])
138 safe_str(self.config['realm'])
139 result = self.authenticate(environ)
139 result = self.authenticate(environ)
140 if isinstance(result, str):
140 if isinstance(result, str):
141 AUTH_TYPE.update(environ, 'basic')
141 AUTH_TYPE.update(environ, 'basic')
142 REMOTE_USER.update(environ, result)
142 REMOTE_USER.update(environ, result)
143 username = result
143 username = result
144 else:
144 else:
145 return result.wsgi_application(environ, start_response)
145 return result.wsgi_application(environ, start_response)
146
146
147 #==============================================================
147 #==============================================================
148 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
148 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
149 #==============================================================
149 #==============================================================
150 try:
150 try:
151 user = self.__get_user(username)
151 user = self.__get_user(username)
152 if user is None or not user.active:
152 if user is None or not user.active:
153 return HTTPForbidden()(environ, start_response)
153 return HTTPForbidden()(environ, start_response)
154 username = user.username
154 username = user.username
155 except Exception:
155 except Exception:
156 log.error(traceback.format_exc())
156 log.error(traceback.format_exc())
157 return HTTPInternalServerError()(environ, start_response)
157 return HTTPInternalServerError()(environ, start_response)
158
158
159 #check permissions for this repository
159 #check permissions for this repository
160 perm = self._check_permission(action, user, repo_name, ip_addr)
160 perm = self._check_permission(action, user, repo_name, ip_addr)
161 if not perm:
161 if not perm:
162 return HTTPForbidden()(environ, start_response)
162 return HTTPForbidden()(environ, start_response)
163
163
164 # extras are injected into mercurial UI object and later available
164 # extras are injected into mercurial UI object and later available
165 # in hg hooks executed by kallithea
165 # in hg hooks executed by kallithea
166 from kallithea import CONFIG
166 from kallithea import CONFIG
167 server_url = get_server_url(environ)
167 server_url = get_server_url(environ)
168 extras = {
168 extras = {
169 'ip': ip_addr,
169 'ip': ip_addr,
170 'username': username,
170 'username': username,
171 'action': action,
171 'action': action,
172 'repository': repo_name,
172 'repository': repo_name,
173 'scm': 'hg',
173 'scm': 'hg',
174 'config': CONFIG['__file__'],
174 'config': CONFIG['__file__'],
175 'server_url': server_url,
175 'server_url': server_url,
176 'make_lock': None,
176 'make_lock': None,
177 'locked_by': [None, None]
177 'locked_by': [None, None]
178 }
178 }
179 #======================================================================
179 #======================================================================
180 # MERCURIAL REQUEST HANDLING
180 # MERCURIAL REQUEST HANDLING
181 #======================================================================
181 #======================================================================
182 str_repo_name = safe_str(repo_name)
182 str_repo_name = safe_str(repo_name)
183 repo_path = os.path.join(safe_str(self.basepath), str_repo_name)
183 repo_path = os.path.join(safe_str(self.basepath), str_repo_name)
184 log.debug('Repository path is %s' % repo_path)
184 log.debug('Repository path is %s' % repo_path)
185
185
186 # CHECK LOCKING only if it's not ANONYMOUS USER
186 # CHECK LOCKING only if it's not ANONYMOUS USER
187 if username != User.DEFAULT_USER:
187 if username != User.DEFAULT_USER:
188 log.debug('Checking locking on repository')
188 log.debug('Checking locking on repository')
189 (make_lock,
189 (make_lock,
190 locked,
190 locked,
191 locked_by) = self._check_locking_state(
191 locked_by) = self._check_locking_state(
192 environ=environ, action=action,
192 environ=environ, action=action,
193 repo=repo_name, user_id=user.user_id
193 repo=repo_name, user_id=user.user_id
194 )
194 )
195 # store the make_lock for later evaluation in hooks
195 # store the make_lock for later evaluation in hooks
196 extras.update({'make_lock': make_lock,
196 extras.update({'make_lock': make_lock,
197 'locked_by': locked_by})
197 'locked_by': locked_by})
198
198
199 fix_PATH()
199 fix_PATH()
200 log.debug('HOOKS extras is %s' % extras)
200 log.debug('HOOKS extras is %s' % extras)
201 baseui = make_ui('db')
201 baseui = make_ui('db')
202 self.__inject_extras(repo_path, baseui, extras)
202 self.__inject_extras(repo_path, baseui, extras)
203
203
204 try:
204 try:
205 log.info('%s action on HG repo "%s" by "%s" from %s' %
205 log.info('%s action on Mercurial repo "%s" by "%s" from %s' %
206 (action, str_repo_name, safe_str(username), ip_addr))
206 (action, str_repo_name, safe_str(username), ip_addr))
207 app = self.__make_app(repo_path, baseui, extras)
207 app = self.__make_app(repo_path, baseui, extras)
208 return app(environ, start_response)
208 return app(environ, start_response)
209 except RepoError, e:
209 except RepoError, e:
210 if str(e).find('not found') != -1:
210 if str(e).find('not found') != -1:
211 return HTTPNotFound()(environ, start_response)
211 return HTTPNotFound()(environ, start_response)
212 except HTTPLockedRC, e:
212 except HTTPLockedRC, e:
213 _code = CONFIG.get('lock_ret_code')
213 _code = CONFIG.get('lock_ret_code')
214 log.debug('Repository LOCKED ret code %s!' % (_code))
214 log.debug('Repository LOCKED ret code %s!' % (_code))
215 return e(environ, start_response)
215 return e(environ, start_response)
216 except Exception:
216 except Exception:
217 log.error(traceback.format_exc())
217 log.error(traceback.format_exc())
218 return HTTPInternalServerError()(environ, start_response)
218 return HTTPInternalServerError()(environ, start_response)
219 finally:
219 finally:
220 # invalidate cache on push
220 # invalidate cache on push
221 if action == 'push':
221 if action == 'push':
222 self._invalidate_cache(repo_name)
222 self._invalidate_cache(repo_name)
223
223
224 def __make_app(self, repo_name, baseui, extras):
224 def __make_app(self, repo_name, baseui, extras):
225 """
225 """
226 Make an wsgi application using hgweb, and inject generated baseui
226 Make an wsgi application using hgweb, and inject generated baseui
227 instance, additionally inject some extras into ui object
227 instance, additionally inject some extras into ui object
228 """
228 """
229 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
229 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
230
230
231 def __get_repository(self, environ):
231 def __get_repository(self, environ):
232 """
232 """
233 Gets repository name out of PATH_INFO header
233 Gets repository name out of PATH_INFO header
234
234
235 :param environ: environ where PATH_INFO is stored
235 :param environ: environ where PATH_INFO is stored
236 """
236 """
237 try:
237 try:
238 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
238 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
239 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
239 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
240 if repo_name.endswith('/'):
240 if repo_name.endswith('/'):
241 repo_name = repo_name.rstrip('/')
241 repo_name = repo_name.rstrip('/')
242 except Exception:
242 except Exception:
243 log.error(traceback.format_exc())
243 log.error(traceback.format_exc())
244 raise
244 raise
245
245
246 return repo_name
246 return repo_name
247
247
248 def __get_user(self, username):
248 def __get_user(self, username):
249 return User.get_by_username(username)
249 return User.get_by_username(username)
250
250
251 def __get_action(self, environ):
251 def __get_action(self, environ):
252 """
252 """
253 Maps mercurial request commands into a clone,pull or push command.
253 Maps mercurial request commands into a clone,pull or push command.
254 This should always return a valid command string
254 This should always return a valid command string
255
255
256 :param environ:
256 :param environ:
257 """
257 """
258 mapping = {'changegroup': 'pull',
258 mapping = {'changegroup': 'pull',
259 'changegroupsubset': 'pull',
259 'changegroupsubset': 'pull',
260 'stream_out': 'pull',
260 'stream_out': 'pull',
261 'listkeys': 'pull',
261 'listkeys': 'pull',
262 'unbundle': 'push',
262 'unbundle': 'push',
263 'pushkey': 'push', }
263 'pushkey': 'push', }
264 for qry in environ['QUERY_STRING'].split('&'):
264 for qry in environ['QUERY_STRING'].split('&'):
265 if qry.startswith('cmd'):
265 if qry.startswith('cmd'):
266 cmd = qry.split('=')[-1]
266 cmd = qry.split('=')[-1]
267 if cmd in mapping:
267 if cmd in mapping:
268 return mapping[cmd]
268 return mapping[cmd]
269
269
270 return 'pull'
270 return 'pull'
271
271
272 raise Exception('Unable to detect pull/push action !!'
272 raise Exception('Unable to detect pull/push action !!'
273 'Are you using non standard command or client ?')
273 'Are you using non standard command or client ?')
274
274
275 def __inject_extras(self, repo_path, baseui, extras={}):
275 def __inject_extras(self, repo_path, baseui, extras={}):
276 """
276 """
277 Injects some extra params into baseui instance
277 Injects some extra params into baseui instance
278
278
279 also overwrites global settings with those takes from local hgrc file
279 also overwrites global settings with those takes from local hgrc file
280
280
281 :param baseui: baseui instance
281 :param baseui: baseui instance
282 :param extras: dict with extra params to put into baseui
282 :param extras: dict with extra params to put into baseui
283 """
283 """
284
284
285 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
285 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
286
286
287 # make our hgweb quiet so it doesn't print output
287 # make our hgweb quiet so it doesn't print output
288 baseui.setconfig('ui', 'quiet', 'true')
288 baseui.setconfig('ui', 'quiet', 'true')
289
289
290 repoui = make_ui('file', hgrc, False)
290 repoui = make_ui('file', hgrc, False)
291
291
292 if repoui:
292 if repoui:
293 #overwrite our ui instance with the section from hgrc file
293 #overwrite our ui instance with the section from hgrc file
294 for section in ui_sections:
294 for section in ui_sections:
295 for k, v in repoui.configitems(section):
295 for k, v in repoui.configitems(section):
296 baseui.setconfig(section, k, v)
296 baseui.setconfig(section, k, v)
297 _set_extras(extras)
297 _set_extras(extras)
@@ -1,887 +1,887 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.utils
15 kallithea.lib.utils
16 ~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~
17
17
18 Utilities library for Kallithea
18 Utilities library for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 18, 2010
22 :created_on: Apr 18, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import os
28 import os
29 import re
29 import re
30 import logging
30 import logging
31 import datetime
31 import datetime
32 import traceback
32 import traceback
33 import paste
33 import paste
34 import beaker
34 import beaker
35 import tarfile
35 import tarfile
36 import shutil
36 import shutil
37 import decorator
37 import decorator
38 import warnings
38 import warnings
39 from os.path import abspath
39 from os.path import abspath
40 from os.path import dirname as dn, join as jn
40 from os.path import dirname as dn, join as jn
41
41
42 from paste.script.command import Command, BadCommand
42 from paste.script.command import Command, BadCommand
43
43
44 from webhelpers.text import collapse, remove_formatting, strip_tags
44 from webhelpers.text import collapse, remove_formatting, strip_tags
45 from beaker.cache import _cache_decorate
45 from beaker.cache import _cache_decorate
46
46
47 from kallithea import BRAND
47 from kallithea import BRAND
48
48
49 from kallithea.lib.vcs.utils.hgcompat import ui, config
49 from kallithea.lib.vcs.utils.hgcompat import ui, config
50 from kallithea.lib.vcs.utils.helpers import get_scm
50 from kallithea.lib.vcs.utils.helpers import get_scm
51 from kallithea.lib.vcs.exceptions import VCSError
51 from kallithea.lib.vcs.exceptions import VCSError
52
52
53 from kallithea.lib.caching_query import FromCache
53 from kallithea.lib.caching_query import FromCache
54
54
55 from kallithea.model import meta
55 from kallithea.model import meta
56 from kallithea.model.db import Repository, User, Ui, \
56 from kallithea.model.db import Repository, User, Ui, \
57 UserLog, RepoGroup, Setting, CacheInvalidation, UserGroup
57 UserLog, RepoGroup, Setting, CacheInvalidation, UserGroup
58 from kallithea.model.meta import Session
58 from kallithea.model.meta import Session
59 from kallithea.model.repo_group import RepoGroupModel
59 from kallithea.model.repo_group import RepoGroupModel
60 from kallithea.lib.utils2 import safe_str, safe_unicode, get_current_authuser
60 from kallithea.lib.utils2 import safe_str, safe_unicode, get_current_authuser
61 from kallithea.lib.vcs.utils.fakemod import create_module
61 from kallithea.lib.vcs.utils.fakemod import create_module
62
62
63 log = logging.getLogger(__name__)
63 log = logging.getLogger(__name__)
64
64
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
66
66
67
67
68 def recursive_replace(str_, replace=' '):
68 def recursive_replace(str_, replace=' '):
69 """
69 """
70 Recursive replace of given sign to just one instance
70 Recursive replace of given sign to just one instance
71
71
72 :param str_: given string
72 :param str_: given string
73 :param replace: char to find and replace multiple instances
73 :param replace: char to find and replace multiple instances
74
74
75 Examples::
75 Examples::
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
77 'Mighty-Mighty-Bo-sstones'
77 'Mighty-Mighty-Bo-sstones'
78 """
78 """
79
79
80 if str_.find(replace * 2) == -1:
80 if str_.find(replace * 2) == -1:
81 return str_
81 return str_
82 else:
82 else:
83 str_ = str_.replace(replace * 2, replace)
83 str_ = str_.replace(replace * 2, replace)
84 return recursive_replace(str_, replace)
84 return recursive_replace(str_, replace)
85
85
86
86
87 def repo_name_slug(value):
87 def repo_name_slug(value):
88 """
88 """
89 Return slug of name of repository
89 Return slug of name of repository
90 This function is called on each creation/modification
90 This function is called on each creation/modification
91 of repository to prevent bad names in repo
91 of repository to prevent bad names in repo
92 """
92 """
93
93
94 slug = remove_formatting(value)
94 slug = remove_formatting(value)
95 slug = strip_tags(slug)
95 slug = strip_tags(slug)
96
96
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
98 slug = slug.replace(c, '-')
98 slug = slug.replace(c, '-')
99 slug = recursive_replace(slug, '-')
99 slug = recursive_replace(slug, '-')
100 slug = collapse(slug, '-')
100 slug = collapse(slug, '-')
101 return slug
101 return slug
102
102
103
103
104 #==============================================================================
104 #==============================================================================
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
106 #==============================================================================
106 #==============================================================================
107 def get_repo_slug(request):
107 def get_repo_slug(request):
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
109 if _repo:
109 if _repo:
110 _repo = _repo.rstrip('/')
110 _repo = _repo.rstrip('/')
111 return _repo
111 return _repo
112
112
113
113
114 def get_repo_group_slug(request):
114 def get_repo_group_slug(request):
115 _group = request.environ['pylons.routes_dict'].get('group_name')
115 _group = request.environ['pylons.routes_dict'].get('group_name')
116 if _group:
116 if _group:
117 _group = _group.rstrip('/')
117 _group = _group.rstrip('/')
118 return _group
118 return _group
119
119
120
120
121 def get_user_group_slug(request):
121 def get_user_group_slug(request):
122 _group = request.environ['pylons.routes_dict'].get('id')
122 _group = request.environ['pylons.routes_dict'].get('id')
123 try:
123 try:
124 _group = UserGroup.get(_group)
124 _group = UserGroup.get(_group)
125 if _group:
125 if _group:
126 _group = _group.users_group_name
126 _group = _group.users_group_name
127 except Exception:
127 except Exception:
128 log.debug(traceback.format_exc())
128 log.debug(traceback.format_exc())
129 #catch all failures here
129 #catch all failures here
130 pass
130 pass
131
131
132 return _group
132 return _group
133
133
134
134
135 def _extract_id_from_repo_name(repo_name):
135 def _extract_id_from_repo_name(repo_name):
136 if repo_name.startswith('/'):
136 if repo_name.startswith('/'):
137 repo_name = repo_name.lstrip('/')
137 repo_name = repo_name.lstrip('/')
138 by_id_match = re.match(r'^_(\d{1,})', repo_name)
138 by_id_match = re.match(r'^_(\d{1,})', repo_name)
139 if by_id_match:
139 if by_id_match:
140 return by_id_match.groups()[0]
140 return by_id_match.groups()[0]
141
141
142
142
143 def get_repo_by_id(repo_name):
143 def get_repo_by_id(repo_name):
144 """
144 """
145 Extracts repo_name by id from special urls. Example url is _11/repo_name
145 Extracts repo_name by id from special urls. Example url is _11/repo_name
146
146
147 :param repo_name:
147 :param repo_name:
148 :return: repo_name if matched else None
148 :return: repo_name if matched else None
149 """
149 """
150 try:
150 try:
151 _repo_id = _extract_id_from_repo_name(repo_name)
151 _repo_id = _extract_id_from_repo_name(repo_name)
152 if _repo_id:
152 if _repo_id:
153 from kallithea.model.db import Repository
153 from kallithea.model.db import Repository
154 return Repository.get(_repo_id).repo_name
154 return Repository.get(_repo_id).repo_name
155 except Exception:
155 except Exception:
156 log.debug('Failed to extract repo_name from URL %s' % (
156 log.debug('Failed to extract repo_name from URL %s' % (
157 traceback.format_exc()))
157 traceback.format_exc()))
158 return
158 return
159
159
160
160
161 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
161 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
162 """
162 """
163 Action logger for various actions made by users
163 Action logger for various actions made by users
164
164
165 :param user: user that made this action, can be a unique username string or
165 :param user: user that made this action, can be a unique username string or
166 object containing user_id attribute
166 object containing user_id attribute
167 :param action: action to log, should be on of predefined unique actions for
167 :param action: action to log, should be on of predefined unique actions for
168 easy translations
168 easy translations
169 :param repo: string name of repository or object containing repo_id,
169 :param repo: string name of repository or object containing repo_id,
170 that action was made on
170 that action was made on
171 :param ipaddr: optional ip address from what the action was made
171 :param ipaddr: optional ip address from what the action was made
172 :param sa: optional sqlalchemy session
172 :param sa: optional sqlalchemy session
173
173
174 """
174 """
175
175
176 if not sa:
176 if not sa:
177 sa = meta.Session()
177 sa = meta.Session()
178 # if we don't get explicit IP address try to get one from registered user
178 # if we don't get explicit IP address try to get one from registered user
179 # in tmpl context var
179 # in tmpl context var
180 if not ipaddr:
180 if not ipaddr:
181 ipaddr = getattr(get_current_authuser(), 'ip_addr', '')
181 ipaddr = getattr(get_current_authuser(), 'ip_addr', '')
182
182
183 try:
183 try:
184 if getattr(user, 'user_id', None):
184 if getattr(user, 'user_id', None):
185 user_obj = User.get(user.user_id)
185 user_obj = User.get(user.user_id)
186 elif isinstance(user, basestring):
186 elif isinstance(user, basestring):
187 user_obj = User.get_by_username(user)
187 user_obj = User.get_by_username(user)
188 else:
188 else:
189 raise Exception('You have to provide a user object or a username')
189 raise Exception('You have to provide a user object or a username')
190
190
191 if getattr(repo, 'repo_id', None):
191 if getattr(repo, 'repo_id', None):
192 repo_obj = Repository.get(repo.repo_id)
192 repo_obj = Repository.get(repo.repo_id)
193 repo_name = repo_obj.repo_name
193 repo_name = repo_obj.repo_name
194 elif isinstance(repo, basestring):
194 elif isinstance(repo, basestring):
195 repo_name = repo.lstrip('/')
195 repo_name = repo.lstrip('/')
196 repo_obj = Repository.get_by_repo_name(repo_name)
196 repo_obj = Repository.get_by_repo_name(repo_name)
197 else:
197 else:
198 repo_obj = None
198 repo_obj = None
199 repo_name = ''
199 repo_name = ''
200
200
201 user_log = UserLog()
201 user_log = UserLog()
202 user_log.user_id = user_obj.user_id
202 user_log.user_id = user_obj.user_id
203 user_log.username = user_obj.username
203 user_log.username = user_obj.username
204 user_log.action = safe_unicode(action)
204 user_log.action = safe_unicode(action)
205
205
206 user_log.repository = repo_obj
206 user_log.repository = repo_obj
207 user_log.repository_name = repo_name
207 user_log.repository_name = repo_name
208
208
209 user_log.action_date = datetime.datetime.now()
209 user_log.action_date = datetime.datetime.now()
210 user_log.user_ip = ipaddr
210 user_log.user_ip = ipaddr
211 sa.add(user_log)
211 sa.add(user_log)
212
212
213 log.info('Logging action:%s on %s by user:%s ip:%s' %
213 log.info('Logging action:%s on %s by user:%s ip:%s' %
214 (action, safe_unicode(repo), user_obj, ipaddr))
214 (action, safe_unicode(repo), user_obj, ipaddr))
215 if commit:
215 if commit:
216 sa.commit()
216 sa.commit()
217 except Exception:
217 except Exception:
218 log.error(traceback.format_exc())
218 log.error(traceback.format_exc())
219 raise
219 raise
220
220
221
221
222 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
222 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
223 """
223 """
224 Scans given path for repos and return (name,(type,path)) tuple
224 Scans given path for repos and return (name,(type,path)) tuple
225
225
226 :param path: path to scan for repositories
226 :param path: path to scan for repositories
227 :param recursive: recursive search and return names with subdirs in front
227 :param recursive: recursive search and return names with subdirs in front
228 """
228 """
229
229
230 # remove ending slash for better results
230 # remove ending slash for better results
231 path = path.rstrip(os.sep)
231 path = path.rstrip(os.sep)
232 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
232 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
233
233
234 def _get_repos(p):
234 def _get_repos(p):
235 if not os.access(p, os.R_OK) or not os.access(p, os.X_OK):
235 if not os.access(p, os.R_OK) or not os.access(p, os.X_OK):
236 log.warning('ignoring repo path without access: %s' % (p,))
236 log.warning('ignoring repo path without access: %s' % (p,))
237 return
237 return
238 if not os.access(p, os.W_OK):
238 if not os.access(p, os.W_OK):
239 log.warning('repo path without write access: %s' % (p,))
239 log.warning('repo path without write access: %s' % (p,))
240 for dirpath in os.listdir(p):
240 for dirpath in os.listdir(p):
241 if os.path.isfile(os.path.join(p, dirpath)):
241 if os.path.isfile(os.path.join(p, dirpath)):
242 continue
242 continue
243 cur_path = os.path.join(p, dirpath)
243 cur_path = os.path.join(p, dirpath)
244
244
245 # skip removed repos
245 # skip removed repos
246 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
246 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
247 continue
247 continue
248
248
249 #skip .<somethin> dirs
249 #skip .<somethin> dirs
250 if dirpath.startswith('.'):
250 if dirpath.startswith('.'):
251 continue
251 continue
252
252
253 try:
253 try:
254 scm_info = get_scm(cur_path)
254 scm_info = get_scm(cur_path)
255 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
255 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
256 except VCSError:
256 except VCSError:
257 if not recursive:
257 if not recursive:
258 continue
258 continue
259 #check if this dir containts other repos for recursive scan
259 #check if this dir containts other repos for recursive scan
260 rec_path = os.path.join(p, dirpath)
260 rec_path = os.path.join(p, dirpath)
261 if os.path.isdir(rec_path):
261 if os.path.isdir(rec_path):
262 for inner_scm in _get_repos(rec_path):
262 for inner_scm in _get_repos(rec_path):
263 yield inner_scm
263 yield inner_scm
264
264
265 return _get_repos(path)
265 return _get_repos(path)
266
266
267
267
268 def is_valid_repo(repo_name, base_path, scm=None):
268 def is_valid_repo(repo_name, base_path, scm=None):
269 """
269 """
270 Returns True if given path is a valid repository False otherwise.
270 Returns True if given path is a valid repository False otherwise.
271 If scm param is given also compare if given scm is the same as expected
271 If scm param is given also compare if given scm is the same as expected
272 from scm parameter
272 from scm parameter
273
273
274 :param repo_name:
274 :param repo_name:
275 :param base_path:
275 :param base_path:
276 :param scm:
276 :param scm:
277
277
278 :return True: if given path is a valid repository
278 :return True: if given path is a valid repository
279 """
279 """
280 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
280 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
281
281
282 try:
282 try:
283 scm_ = get_scm(full_path)
283 scm_ = get_scm(full_path)
284 if scm:
284 if scm:
285 return scm_[0] == scm
285 return scm_[0] == scm
286 return True
286 return True
287 except VCSError:
287 except VCSError:
288 return False
288 return False
289
289
290
290
291 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
291 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
292 """
292 """
293 Returns True if given path is a repository group False otherwise
293 Returns True if given path is a repository group False otherwise
294
294
295 :param repo_name:
295 :param repo_name:
296 :param base_path:
296 :param base_path:
297 """
297 """
298 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
298 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
299
299
300 # check if it's not a repo
300 # check if it's not a repo
301 if is_valid_repo(repo_group_name, base_path):
301 if is_valid_repo(repo_group_name, base_path):
302 return False
302 return False
303
303
304 try:
304 try:
305 # we need to check bare git repos at higher level
305 # we need to check bare git repos at higher level
306 # since we might match branches/hooks/info/objects or possible
306 # since we might match branches/hooks/info/objects or possible
307 # other things inside bare git repo
307 # other things inside bare git repo
308 get_scm(os.path.dirname(full_path))
308 get_scm(os.path.dirname(full_path))
309 return False
309 return False
310 except VCSError:
310 except VCSError:
311 pass
311 pass
312
312
313 # check if it's a valid path
313 # check if it's a valid path
314 if skip_path_check or os.path.isdir(full_path):
314 if skip_path_check or os.path.isdir(full_path):
315 return True
315 return True
316
316
317 return False
317 return False
318
318
319
319
320 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
320 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
321 while True:
321 while True:
322 ok = raw_input(prompt)
322 ok = raw_input(prompt)
323 if ok in ('y', 'ye', 'yes'):
323 if ok in ('y', 'ye', 'yes'):
324 return True
324 return True
325 if ok in ('n', 'no', 'nop', 'nope'):
325 if ok in ('n', 'no', 'nop', 'nope'):
326 return False
326 return False
327 retries = retries - 1
327 retries = retries - 1
328 if retries < 0:
328 if retries < 0:
329 raise IOError
329 raise IOError
330 print complaint
330 print complaint
331
331
332 #propagated from mercurial documentation
332 #propagated from mercurial documentation
333 ui_sections = ['alias', 'auth',
333 ui_sections = ['alias', 'auth',
334 'decode/encode', 'defaults',
334 'decode/encode', 'defaults',
335 'diff', 'email',
335 'diff', 'email',
336 'extensions', 'format',
336 'extensions', 'format',
337 'merge-patterns', 'merge-tools',
337 'merge-patterns', 'merge-tools',
338 'hooks', 'http_proxy',
338 'hooks', 'http_proxy',
339 'smtp', 'patch',
339 'smtp', 'patch',
340 'paths', 'profiling',
340 'paths', 'profiling',
341 'server', 'trusted',
341 'server', 'trusted',
342 'ui', 'web', ]
342 'ui', 'web', ]
343
343
344
344
345 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
345 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
346 """
346 """
347 A function that will read python rc files or database
347 A function that will read python rc files or database
348 and make an mercurial ui object from read options
348 and make an mercurial ui object from read options
349
349
350 :param path: path to mercurial config file
350 :param path: path to mercurial config file
351 :param checkpaths: check the path
351 :param checkpaths: check the path
352 :param read_from: read from 'file' or 'db'
352 :param read_from: read from 'file' or 'db'
353 """
353 """
354
354
355 baseui = ui.ui()
355 baseui = ui.ui()
356
356
357 # clean the baseui object
357 # clean the baseui object
358 baseui._ocfg = config.config()
358 baseui._ocfg = config.config()
359 baseui._ucfg = config.config()
359 baseui._ucfg = config.config()
360 baseui._tcfg = config.config()
360 baseui._tcfg = config.config()
361
361
362 if read_from == 'file':
362 if read_from == 'file':
363 if not os.path.isfile(path):
363 if not os.path.isfile(path):
364 log.debug('hgrc file is not present at %s, skipping...' % path)
364 log.debug('hgrc file is not present at %s, skipping...' % path)
365 return False
365 return False
366 log.debug('reading hgrc from %s' % path)
366 log.debug('reading hgrc from %s' % path)
367 cfg = config.config()
367 cfg = config.config()
368 cfg.read(path)
368 cfg.read(path)
369 for section in ui_sections:
369 for section in ui_sections:
370 for k, v in cfg.items(section):
370 for k, v in cfg.items(section):
371 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
371 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
372 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
372 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
373
373
374 elif read_from == 'db':
374 elif read_from == 'db':
375 sa = meta.Session()
375 sa = meta.Session()
376 ret = sa.query(Ui)\
376 ret = sa.query(Ui)\
377 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
377 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
378 .all()
378 .all()
379
379
380 hg_ui = ret
380 hg_ui = ret
381 for ui_ in hg_ui:
381 for ui_ in hg_ui:
382 if ui_.ui_active:
382 if ui_.ui_active:
383 ui_val = safe_str(ui_.ui_value)
383 ui_val = safe_str(ui_.ui_value)
384 if ui_.ui_section == 'hooks' and BRAND != 'kallithea' and ui_val.startswith('python:' + BRAND + '.lib.hooks.'):
384 if ui_.ui_section == 'hooks' and BRAND != 'kallithea' and ui_val.startswith('python:' + BRAND + '.lib.hooks.'):
385 ui_val = ui_val.replace('python:' + BRAND + '.lib.hooks.', 'python:kallithea.lib.hooks.')
385 ui_val = ui_val.replace('python:' + BRAND + '.lib.hooks.', 'python:kallithea.lib.hooks.')
386 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
386 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
387 ui_.ui_key, ui_val)
387 ui_.ui_key, ui_val)
388 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
388 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
389 ui_val)
389 ui_val)
390 if ui_.ui_key == 'push_ssl':
390 if ui_.ui_key == 'push_ssl':
391 # force set push_ssl requirement to False, kallithea
391 # force set push_ssl requirement to False, kallithea
392 # handles that
392 # handles that
393 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
393 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
394 False)
394 False)
395 if clear_session:
395 if clear_session:
396 meta.Session.remove()
396 meta.Session.remove()
397 return baseui
397 return baseui
398
398
399
399
400 def set_app_settings(config):
400 def set_app_settings(config):
401 """
401 """
402 Updates pylons config with new settings from database
402 Updates pylons config with new settings from database
403
403
404 :param config:
404 :param config:
405 """
405 """
406 hgsettings = Setting.get_app_settings()
406 hgsettings = Setting.get_app_settings()
407
407
408 for k, v in hgsettings.items():
408 for k, v in hgsettings.items():
409 config[k] = v
409 config[k] = v
410
410
411
411
412 def set_vcs_config(config):
412 def set_vcs_config(config):
413 """
413 """
414 Patch VCS config with some Kallithea specific stuff
414 Patch VCS config with some Kallithea specific stuff
415
415
416 :param config: kallithea.CONFIG
416 :param config: kallithea.CONFIG
417 """
417 """
418 import kallithea
418 import kallithea
419 from kallithea.lib.vcs import conf
419 from kallithea.lib.vcs import conf
420 from kallithea.lib.utils2 import aslist
420 from kallithea.lib.utils2 import aslist
421 conf.settings.BACKENDS = {
421 conf.settings.BACKENDS = {
422 'hg': 'kallithea.lib.vcs.backends.hg.MercurialRepository',
422 'hg': 'kallithea.lib.vcs.backends.hg.MercurialRepository',
423 'git': 'kallithea.lib.vcs.backends.git.GitRepository',
423 'git': 'kallithea.lib.vcs.backends.git.GitRepository',
424 }
424 }
425
425
426 conf.settings.GIT_EXECUTABLE_PATH = config.get('git_path', 'git')
426 conf.settings.GIT_EXECUTABLE_PATH = config.get('git_path', 'git')
427 conf.settings.GIT_REV_FILTER = config.get('git_rev_filter', '--all').strip()
427 conf.settings.GIT_REV_FILTER = config.get('git_rev_filter', '--all').strip()
428 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
428 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
429 'utf8'), sep=',')
429 'utf8'), sep=',')
430
430
431
431
432 def map_groups(path):
432 def map_groups(path):
433 """
433 """
434 Given a full path to a repository, create all nested groups that this
434 Given a full path to a repository, create all nested groups that this
435 repo is inside. This function creates parent-child relationships between
435 repo is inside. This function creates parent-child relationships between
436 groups and creates default perms for all new groups.
436 groups and creates default perms for all new groups.
437
437
438 :param paths: full path to repository
438 :param paths: full path to repository
439 """
439 """
440 sa = meta.Session()
440 sa = meta.Session()
441 groups = path.split(Repository.url_sep())
441 groups = path.split(Repository.url_sep())
442 parent = None
442 parent = None
443 group = None
443 group = None
444
444
445 # last element is repo in nested groups structure
445 # last element is repo in nested groups structure
446 groups = groups[:-1]
446 groups = groups[:-1]
447 rgm = RepoGroupModel(sa)
447 rgm = RepoGroupModel(sa)
448 owner = User.get_first_admin()
448 owner = User.get_first_admin()
449 for lvl, group_name in enumerate(groups):
449 for lvl, group_name in enumerate(groups):
450 group_name = '/'.join(groups[:lvl] + [group_name])
450 group_name = '/'.join(groups[:lvl] + [group_name])
451 group = RepoGroup.get_by_group_name(group_name)
451 group = RepoGroup.get_by_group_name(group_name)
452 desc = '%s group' % group_name
452 desc = '%s group' % group_name
453
453
454 # skip folders that are now removed repos
454 # skip folders that are now removed repos
455 if REMOVED_REPO_PAT.match(group_name):
455 if REMOVED_REPO_PAT.match(group_name):
456 break
456 break
457
457
458 if group is None:
458 if group is None:
459 log.debug('creating group level: %s group_name: %s'
459 log.debug('creating group level: %s group_name: %s'
460 % (lvl, group_name))
460 % (lvl, group_name))
461 group = RepoGroup(group_name, parent)
461 group = RepoGroup(group_name, parent)
462 group.group_description = desc
462 group.group_description = desc
463 group.user = owner
463 group.user = owner
464 sa.add(group)
464 sa.add(group)
465 perm_obj = rgm._create_default_perms(group)
465 perm_obj = rgm._create_default_perms(group)
466 sa.add(perm_obj)
466 sa.add(perm_obj)
467 sa.flush()
467 sa.flush()
468
468
469 parent = group
469 parent = group
470 return group
470 return group
471
471
472
472
473 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
473 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
474 install_git_hook=False):
474 install_git_hook=False):
475 """
475 """
476 maps all repos given in initial_repo_list, non existing repositories
476 maps all repos given in initial_repo_list, non existing repositories
477 are created, if remove_obsolete is True it also check for db entries
477 are created, if remove_obsolete is True it also check for db entries
478 that are not in initial_repo_list and removes them.
478 that are not in initial_repo_list and removes them.
479
479
480 :param initial_repo_list: list of repositories found by scanning methods
480 :param initial_repo_list: list of repositories found by scanning methods
481 :param remove_obsolete: check for obsolete entries in database
481 :param remove_obsolete: check for obsolete entries in database
482 :param install_git_hook: if this is True, also check and install githook
482 :param install_git_hook: if this is True, also check and install githook
483 for a repo if missing
483 for a repo if missing
484 """
484 """
485 from kallithea.model.repo import RepoModel
485 from kallithea.model.repo import RepoModel
486 from kallithea.model.scm import ScmModel
486 from kallithea.model.scm import ScmModel
487 sa = meta.Session()
487 sa = meta.Session()
488 repo_model = RepoModel()
488 repo_model = RepoModel()
489 user = User.get_first_admin()
489 user = User.get_first_admin()
490 added = []
490 added = []
491
491
492 ##creation defaults
492 ##creation defaults
493 defs = Setting.get_default_repo_settings(strip_prefix=True)
493 defs = Setting.get_default_repo_settings(strip_prefix=True)
494 enable_statistics = defs.get('repo_enable_statistics')
494 enable_statistics = defs.get('repo_enable_statistics')
495 enable_locking = defs.get('repo_enable_locking')
495 enable_locking = defs.get('repo_enable_locking')
496 enable_downloads = defs.get('repo_enable_downloads')
496 enable_downloads = defs.get('repo_enable_downloads')
497 private = defs.get('repo_private')
497 private = defs.get('repo_private')
498
498
499 for name, repo in initial_repo_list.items():
499 for name, repo in initial_repo_list.items():
500 group = map_groups(name)
500 group = map_groups(name)
501 unicode_name = safe_unicode(name)
501 unicode_name = safe_unicode(name)
502 db_repo = repo_model.get_by_repo_name(unicode_name)
502 db_repo = repo_model.get_by_repo_name(unicode_name)
503 # found repo that is on filesystem not in Kallithea database
503 # found repo that is on filesystem not in Kallithea database
504 if not db_repo:
504 if not db_repo:
505 log.info('repository %s not found, creating now' % name)
505 log.info('repository %s not found, creating now' % name)
506 added.append(name)
506 added.append(name)
507 desc = (repo.description
507 desc = (repo.description
508 if repo.description != 'unknown'
508 if repo.description != 'unknown'
509 else '%s repository' % name)
509 else '%s repository' % name)
510
510
511 new_repo = repo_model._create_repo(
511 new_repo = repo_model._create_repo(
512 repo_name=name,
512 repo_name=name,
513 repo_type=repo.alias,
513 repo_type=repo.alias,
514 description=desc,
514 description=desc,
515 repo_group=getattr(group, 'group_id', None),
515 repo_group=getattr(group, 'group_id', None),
516 owner=user,
516 owner=user,
517 enable_locking=enable_locking,
517 enable_locking=enable_locking,
518 enable_downloads=enable_downloads,
518 enable_downloads=enable_downloads,
519 enable_statistics=enable_statistics,
519 enable_statistics=enable_statistics,
520 private=private,
520 private=private,
521 state=Repository.STATE_CREATED
521 state=Repository.STATE_CREATED
522 )
522 )
523 sa.commit()
523 sa.commit()
524 # we added that repo just now, and make sure it has githook
524 # we added that repo just now, and make sure it has githook
525 # installed, and updated server info
525 # installed, and updated server info
526 if new_repo.repo_type == 'git':
526 if new_repo.repo_type == 'git':
527 git_repo = new_repo.scm_instance
527 git_repo = new_repo.scm_instance
528 ScmModel().install_git_hook(git_repo)
528 ScmModel().install_git_hook(git_repo)
529 # update repository server-info
529 # update repository server-info
530 log.debug('Running update server info')
530 log.debug('Running update server info')
531 git_repo._update_server_info()
531 git_repo._update_server_info()
532 new_repo.update_changeset_cache()
532 new_repo.update_changeset_cache()
533 elif install_git_hook:
533 elif install_git_hook:
534 if db_repo.repo_type == 'git':
534 if db_repo.repo_type == 'git':
535 ScmModel().install_git_hook(db_repo.scm_instance)
535 ScmModel().install_git_hook(db_repo.scm_instance)
536
536
537 removed = []
537 removed = []
538 if remove_obsolete:
538 if remove_obsolete:
539 # remove from database those repositories that are not in the filesystem
539 # remove from database those repositories that are not in the filesystem
540 for repo in sa.query(Repository).all():
540 for repo in sa.query(Repository).all():
541 if repo.repo_name not in initial_repo_list.keys():
541 if repo.repo_name not in initial_repo_list.keys():
542 log.debug("Removing non-existing repository found in db `%s`" %
542 log.debug("Removing non-existing repository found in db `%s`" %
543 repo.repo_name)
543 repo.repo_name)
544 try:
544 try:
545 removed.append(repo.repo_name)
545 removed.append(repo.repo_name)
546 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
546 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
547 sa.commit()
547 sa.commit()
548 except Exception:
548 except Exception:
549 #don't hold further removals on error
549 #don't hold further removals on error
550 log.error(traceback.format_exc())
550 log.error(traceback.format_exc())
551 sa.rollback()
551 sa.rollback()
552 return added, removed
552 return added, removed
553
553
554
554
555 # set cache regions for beaker so celery can utilise it
555 # set cache regions for beaker so celery can utilise it
556 def add_cache(settings):
556 def add_cache(settings):
557 cache_settings = {'regions': None}
557 cache_settings = {'regions': None}
558 for key in settings.keys():
558 for key in settings.keys():
559 for prefix in ['beaker.cache.', 'cache.']:
559 for prefix in ['beaker.cache.', 'cache.']:
560 if key.startswith(prefix):
560 if key.startswith(prefix):
561 name = key.split(prefix)[1].strip()
561 name = key.split(prefix)[1].strip()
562 cache_settings[name] = settings[key].strip()
562 cache_settings[name] = settings[key].strip()
563 if cache_settings['regions']:
563 if cache_settings['regions']:
564 for region in cache_settings['regions'].split(','):
564 for region in cache_settings['regions'].split(','):
565 region = region.strip()
565 region = region.strip()
566 region_settings = {}
566 region_settings = {}
567 for key, value in cache_settings.items():
567 for key, value in cache_settings.items():
568 if key.startswith(region):
568 if key.startswith(region):
569 region_settings[key.split('.')[1]] = value
569 region_settings[key.split('.')[1]] = value
570 region_settings['expire'] = int(region_settings.get('expire',
570 region_settings['expire'] = int(region_settings.get('expire',
571 60))
571 60))
572 region_settings.setdefault('lock_dir',
572 region_settings.setdefault('lock_dir',
573 cache_settings.get('lock_dir'))
573 cache_settings.get('lock_dir'))
574 region_settings.setdefault('data_dir',
574 region_settings.setdefault('data_dir',
575 cache_settings.get('data_dir'))
575 cache_settings.get('data_dir'))
576
576
577 if 'type' not in region_settings:
577 if 'type' not in region_settings:
578 region_settings['type'] = cache_settings.get('type',
578 region_settings['type'] = cache_settings.get('type',
579 'memory')
579 'memory')
580 beaker.cache.cache_regions[region] = region_settings
580 beaker.cache.cache_regions[region] = region_settings
581
581
582
582
583 def load_rcextensions(root_path):
583 def load_rcextensions(root_path):
584 import kallithea
584 import kallithea
585 from kallithea.config import conf
585 from kallithea.config import conf
586
586
587 path = os.path.join(root_path, 'rcextensions', '__init__.py')
587 path = os.path.join(root_path, 'rcextensions', '__init__.py')
588 if os.path.isfile(path):
588 if os.path.isfile(path):
589 rcext = create_module('rc', path)
589 rcext = create_module('rc', path)
590 EXT = kallithea.EXTENSIONS = rcext
590 EXT = kallithea.EXTENSIONS = rcext
591 log.debug('Found rcextensions now loading %s...' % rcext)
591 log.debug('Found rcextensions now loading %s...' % rcext)
592
592
593 # Additional mappings that are not present in the pygments lexers
593 # Additional mappings that are not present in the pygments lexers
594 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
594 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
595
595
596 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
596 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
597
597
598 if getattr(EXT, 'INDEX_EXTENSIONS', []):
598 if getattr(EXT, 'INDEX_EXTENSIONS', []):
599 log.debug('settings custom INDEX_EXTENSIONS')
599 log.debug('settings custom INDEX_EXTENSIONS')
600 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
600 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
601
601
602 #ADDITIONAL MAPPINGS
602 #ADDITIONAL MAPPINGS
603 log.debug('adding extra into INDEX_EXTENSIONS')
603 log.debug('adding extra into INDEX_EXTENSIONS')
604 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
604 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
605
605
606 # auto check if the module is not missing any data, set to default if is
606 # auto check if the module is not missing any data, set to default if is
607 # this will help autoupdate new feature of rcext module
607 # this will help autoupdate new feature of rcext module
608 #from kallithea.config import rcextensions
608 #from kallithea.config import rcextensions
609 #for k in dir(rcextensions):
609 #for k in dir(rcextensions):
610 # if not k.startswith('_') and not hasattr(EXT, k):
610 # if not k.startswith('_') and not hasattr(EXT, k):
611 # setattr(EXT, k, getattr(rcextensions, k))
611 # setattr(EXT, k, getattr(rcextensions, k))
612
612
613
613
614 def get_custom_lexer(extension):
614 def get_custom_lexer(extension):
615 """
615 """
616 returns a custom lexer if it's defined in rcextensions module, or None
616 returns a custom lexer if it's defined in rcextensions module, or None
617 if there's no custom lexer defined
617 if there's no custom lexer defined
618 """
618 """
619 import kallithea
619 import kallithea
620 from pygments import lexers
620 from pygments import lexers
621 #check if we didn't define this extension as other lexer
621 #check if we didn't define this extension as other lexer
622 if kallithea.EXTENSIONS and extension in kallithea.EXTENSIONS.EXTRA_LEXERS:
622 if kallithea.EXTENSIONS and extension in kallithea.EXTENSIONS.EXTRA_LEXERS:
623 _lexer_name = kallithea.EXTENSIONS.EXTRA_LEXERS[extension]
623 _lexer_name = kallithea.EXTENSIONS.EXTRA_LEXERS[extension]
624 return lexers.get_lexer_by_name(_lexer_name)
624 return lexers.get_lexer_by_name(_lexer_name)
625
625
626
626
627 #==============================================================================
627 #==============================================================================
628 # TEST FUNCTIONS AND CREATORS
628 # TEST FUNCTIONS AND CREATORS
629 #==============================================================================
629 #==============================================================================
630 def create_test_index(repo_location, config, full_index):
630 def create_test_index(repo_location, config, full_index):
631 """
631 """
632 Makes default test index
632 Makes default test index
633
633
634 :param config: test config
634 :param config: test config
635 :param full_index:
635 :param full_index:
636 """
636 """
637
637
638 from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
638 from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
639 from kallithea.lib.pidlock import DaemonLock, LockHeld
639 from kallithea.lib.pidlock import DaemonLock, LockHeld
640
640
641 repo_location = repo_location
641 repo_location = repo_location
642
642
643 index_location = os.path.join(config['app_conf']['index_dir'])
643 index_location = os.path.join(config['app_conf']['index_dir'])
644 if not os.path.exists(index_location):
644 if not os.path.exists(index_location):
645 os.makedirs(index_location)
645 os.makedirs(index_location)
646
646
647 try:
647 try:
648 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
648 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
649 WhooshIndexingDaemon(index_location=index_location,
649 WhooshIndexingDaemon(index_location=index_location,
650 repo_location=repo_location)\
650 repo_location=repo_location)\
651 .run(full_index=full_index)
651 .run(full_index=full_index)
652 l.release()
652 l.release()
653 except LockHeld:
653 except LockHeld:
654 pass
654 pass
655
655
656
656
657 def create_test_env(repos_test_path, config):
657 def create_test_env(repos_test_path, config):
658 """
658 """
659 Makes a fresh database and
659 Makes a fresh database and
660 install test repository into tmp dir
660 install test repository into tmp dir
661 """
661 """
662 from kallithea.lib.db_manage import DbManage
662 from kallithea.lib.db_manage import DbManage
663 from kallithea.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
663 from kallithea.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
664
664
665 # PART ONE create db
665 # PART ONE create db
666 dbconf = config['sqlalchemy.db1.url']
666 dbconf = config['sqlalchemy.db1.url']
667 log.debug('making test db %s' % dbconf)
667 log.debug('making test db %s' % dbconf)
668
668
669 # create test dir if it doesn't exist
669 # create test dir if it doesn't exist
670 if not os.path.isdir(repos_test_path):
670 if not os.path.isdir(repos_test_path):
671 log.debug('Creating testdir %s' % repos_test_path)
671 log.debug('Creating testdir %s' % repos_test_path)
672 os.makedirs(repos_test_path)
672 os.makedirs(repos_test_path)
673
673
674 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
674 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
675 tests=True)
675 tests=True)
676 dbmanage.create_tables(override=True)
676 dbmanage.create_tables(override=True)
677 # for tests dynamically set new root paths based on generated content
677 # for tests dynamically set new root paths based on generated content
678 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
678 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
679 dbmanage.create_default_user()
679 dbmanage.create_default_user()
680 dbmanage.admin_prompt()
680 dbmanage.admin_prompt()
681 dbmanage.create_permissions()
681 dbmanage.create_permissions()
682 dbmanage.populate_default_permissions()
682 dbmanage.populate_default_permissions()
683 Session().commit()
683 Session().commit()
684 # PART TWO make test repo
684 # PART TWO make test repo
685 log.debug('making test vcs repositories')
685 log.debug('making test vcs repositories')
686
686
687 idx_path = config['app_conf']['index_dir']
687 idx_path = config['app_conf']['index_dir']
688 data_path = config['app_conf']['cache_dir']
688 data_path = config['app_conf']['cache_dir']
689
689
690 #clean index and data
690 #clean index and data
691 if idx_path and os.path.exists(idx_path):
691 if idx_path and os.path.exists(idx_path):
692 log.debug('remove %s' % idx_path)
692 log.debug('remove %s' % idx_path)
693 shutil.rmtree(idx_path)
693 shutil.rmtree(idx_path)
694
694
695 if data_path and os.path.exists(data_path):
695 if data_path and os.path.exists(data_path):
696 log.debug('remove %s' % data_path)
696 log.debug('remove %s' % data_path)
697 shutil.rmtree(data_path)
697 shutil.rmtree(data_path)
698
698
699 #CREATE DEFAULT TEST REPOS
699 #CREATE DEFAULT TEST REPOS
700 cur_dir = dn(dn(abspath(__file__)))
700 cur_dir = dn(dn(abspath(__file__)))
701 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_hg.tar.gz"))
701 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_hg.tar.gz"))
702 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
702 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
703 tar.close()
703 tar.close()
704
704
705 cur_dir = dn(dn(abspath(__file__)))
705 cur_dir = dn(dn(abspath(__file__)))
706 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_git.tar.gz"))
706 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_git.tar.gz"))
707 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
707 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
708 tar.close()
708 tar.close()
709
709
710 #LOAD VCS test stuff
710 #LOAD VCS test stuff
711 from kallithea.tests.vcs import setup_package
711 from kallithea.tests.vcs import setup_package
712 setup_package()
712 setup_package()
713
713
714
714
715 #==============================================================================
715 #==============================================================================
716 # PASTER COMMANDS
716 # PASTER COMMANDS
717 #==============================================================================
717 #==============================================================================
718 class BasePasterCommand(Command):
718 class BasePasterCommand(Command):
719 """
719 """
720 Abstract Base Class for paster commands.
720 Abstract Base Class for paster commands.
721
721
722 The celery commands are somewhat aggressive about loading
722 The celery commands are somewhat aggressive about loading
723 celery.conf, and since our module sets the `CELERY_LOADER`
723 celery.conf, and since our module sets the `CELERY_LOADER`
724 environment variable to our loader, we have to bootstrap a bit and
724 environment variable to our loader, we have to bootstrap a bit and
725 make sure we've had a chance to load the pylons config off of the
725 make sure we've had a chance to load the pylons config off of the
726 command line, otherwise everything fails.
726 command line, otherwise everything fails.
727 """
727 """
728 min_args = 1
728 min_args = 1
729 min_args_error = "Please provide a paster config file as an argument."
729 min_args_error = "Please provide a paster config file as an argument."
730 takes_config_file = 1
730 takes_config_file = 1
731 requires_config_file = True
731 requires_config_file = True
732
732
733 def notify_msg(self, msg, log=False):
733 def notify_msg(self, msg, log=False):
734 """Make a notification to user, additionally if logger is passed
734 """Make a notification to user, additionally if logger is passed
735 it logs this action using given logger
735 it logs this action using given logger
736
736
737 :param msg: message that will be printed to user
737 :param msg: message that will be printed to user
738 :param log: logging instance, to use to additionally log this message
738 :param log: logging instance, to use to additionally log this message
739
739
740 """
740 """
741 if log and isinstance(log, logging):
741 if log and isinstance(log, logging):
742 log(msg)
742 log(msg)
743
743
744 def run(self, args):
744 def run(self, args):
745 """
745 """
746 Overrides Command.run
746 Overrides Command.run
747
747
748 Checks for a config file argument and loads it.
748 Checks for a config file argument and loads it.
749 """
749 """
750 if len(args) < self.min_args:
750 if len(args) < self.min_args:
751 raise BadCommand(
751 raise BadCommand(
752 self.min_args_error % {'min_args': self.min_args,
752 self.min_args_error % {'min_args': self.min_args,
753 'actual_args': len(args)})
753 'actual_args': len(args)})
754
754
755 # Decrement because we're going to lob off the first argument.
755 # Decrement because we're going to lob off the first argument.
756 # @@ This is hacky
756 # @@ This is hacky
757 self.min_args -= 1
757 self.min_args -= 1
758 self.bootstrap_config(args[0])
758 self.bootstrap_config(args[0])
759 self.update_parser()
759 self.update_parser()
760 return super(BasePasterCommand, self).run(args[1:])
760 return super(BasePasterCommand, self).run(args[1:])
761
761
762 def update_parser(self):
762 def update_parser(self):
763 """
763 """
764 Abstract method. Allows for the class's parser to be updated
764 Abstract method. Allows for the class's parser to be updated
765 before the superclass's `run` method is called. Necessary to
765 before the superclass's `run` method is called. Necessary to
766 allow options/arguments to be passed through to the underlying
766 allow options/arguments to be passed through to the underlying
767 celery command.
767 celery command.
768 """
768 """
769 raise NotImplementedError("Abstract Method.")
769 raise NotImplementedError("Abstract Method.")
770
770
771 def bootstrap_config(self, conf):
771 def bootstrap_config(self, conf):
772 """
772 """
773 Loads the pylons configuration.
773 Loads the pylons configuration.
774 """
774 """
775 from pylons import config as pylonsconfig
775 from pylons import config as pylonsconfig
776
776
777 self.path_to_ini_file = os.path.realpath(conf)
777 self.path_to_ini_file = os.path.realpath(conf)
778 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
778 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
779 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
779 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
780
780
781 def _init_session(self):
781 def _init_session(self):
782 """
782 """
783 Inits SqlAlchemy Session
783 Inits SqlAlchemy Session
784 """
784 """
785 logging.config.fileConfig(self.path_to_ini_file)
785 logging.config.fileConfig(self.path_to_ini_file)
786 from pylons import config
786 from pylons import config
787 from kallithea.model import init_model
787 from kallithea.model import init_model
788 from kallithea.lib.utils2 import engine_from_config
788 from kallithea.lib.utils2 import engine_from_config
789
789
790 #get to remove repos !!
790 #get to remove repos !!
791 add_cache(config)
791 add_cache(config)
792 engine = engine_from_config(config, 'sqlalchemy.db1.')
792 engine = engine_from_config(config, 'sqlalchemy.db1.')
793 init_model(engine)
793 init_model(engine)
794
794
795
795
796 def check_git_version():
796 def check_git_version():
797 """
797 """
798 Checks what version of git is installed in system, and issues a warning
798 Checks what version of git is installed in system, and issues a warning
799 if it's too old for Kallithea to properly work.
799 if it's too old for Kallithea to properly work.
800 """
800 """
801 from kallithea import BACKENDS
801 from kallithea import BACKENDS
802 from kallithea.lib.vcs.backends.git.repository import GitRepository
802 from kallithea.lib.vcs.backends.git.repository import GitRepository
803 from kallithea.lib.vcs.conf import settings
803 from kallithea.lib.vcs.conf import settings
804 from distutils.version import StrictVersion
804 from distutils.version import StrictVersion
805
805
806 if 'git' not in BACKENDS:
806 if 'git' not in BACKENDS:
807 return None
807 return None
808
808
809 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
809 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
810 _safe=True)
810 _safe=True)
811
811
812 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
812 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
813 if len(ver.split('.')) > 3:
813 if len(ver.split('.')) > 3:
814 #StrictVersion needs to be only 3 element type
814 #StrictVersion needs to be only 3 element type
815 ver = '.'.join(ver.split('.')[:3])
815 ver = '.'.join(ver.split('.')[:3])
816 try:
816 try:
817 _ver = StrictVersion(ver)
817 _ver = StrictVersion(ver)
818 except Exception:
818 except Exception:
819 _ver = StrictVersion('0.0.0')
819 _ver = StrictVersion('0.0.0')
820 stderr = traceback.format_exc()
820 stderr = traceback.format_exc()
821
821
822 req_ver = '1.7.4'
822 req_ver = '1.7.4'
823 to_old_git = False
823 to_old_git = False
824 if _ver < StrictVersion(req_ver):
824 if _ver < StrictVersion(req_ver):
825 to_old_git = True
825 to_old_git = True
826
826
827 if 'git' in BACKENDS:
827 if 'git' in BACKENDS:
828 log.debug('GIT executable: "%s" version detected: %s'
828 log.debug('Git executable: "%s" version detected: %s'
829 % (settings.GIT_EXECUTABLE_PATH, stdout))
829 % (settings.GIT_EXECUTABLE_PATH, stdout))
830 if stderr:
830 if stderr:
831 log.warning('Unable to detect git version, org error was: %r' % stderr)
831 log.warning('Unable to detect git version, org error was: %r' % stderr)
832 elif to_old_git:
832 elif to_old_git:
833 log.warning('Kallithea detected git version %s, which is too old '
833 log.warning('Kallithea detected git version %s, which is too old '
834 'for the system to function properly. Make sure '
834 'for the system to function properly. Make sure '
835 'its version is at least %s' % (ver, req_ver))
835 'its version is at least %s' % (ver, req_ver))
836 return _ver
836 return _ver
837
837
838
838
839 @decorator.decorator
839 @decorator.decorator
840 def jsonify(func, *args, **kwargs):
840 def jsonify(func, *args, **kwargs):
841 """Action decorator that formats output for JSON
841 """Action decorator that formats output for JSON
842
842
843 Given a function that will return content, this decorator will turn
843 Given a function that will return content, this decorator will turn
844 the result into JSON, with a content-type of 'application/json' and
844 the result into JSON, with a content-type of 'application/json' and
845 output it.
845 output it.
846
846
847 """
847 """
848 from pylons.decorators.util import get_pylons
848 from pylons.decorators.util import get_pylons
849 from kallithea.lib.compat import json
849 from kallithea.lib.compat import json
850 pylons = get_pylons(args)
850 pylons = get_pylons(args)
851 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
851 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
852 data = func(*args, **kwargs)
852 data = func(*args, **kwargs)
853 if isinstance(data, (list, tuple)):
853 if isinstance(data, (list, tuple)):
854 msg = "JSON responses with Array envelopes are susceptible to " \
854 msg = "JSON responses with Array envelopes are susceptible to " \
855 "cross-site data leak attacks, see " \
855 "cross-site data leak attacks, see " \
856 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
856 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
857 warnings.warn(msg, Warning, 2)
857 warnings.warn(msg, Warning, 2)
858 log.warning(msg)
858 log.warning(msg)
859 log.debug("Returning JSON wrapped action output")
859 log.debug("Returning JSON wrapped action output")
860 return json.dumps(data, encoding='utf-8')
860 return json.dumps(data, encoding='utf-8')
861
861
862
862
863 def conditional_cache(region, prefix, condition, func):
863 def conditional_cache(region, prefix, condition, func):
864 """
864 """
865
865
866 Conditional caching function use like::
866 Conditional caching function use like::
867 def _c(arg):
867 def _c(arg):
868 #heavy computation function
868 #heavy computation function
869 return data
869 return data
870
870
871 # denpending from condition the compute is wrapped in cache or not
871 # denpending from condition the compute is wrapped in cache or not
872 compute = conditional_cache('short_term', 'cache_desc', codnition=True, func=func)
872 compute = conditional_cache('short_term', 'cache_desc', codnition=True, func=func)
873 return compute(arg)
873 return compute(arg)
874
874
875 :param region: name of cache region
875 :param region: name of cache region
876 :param prefix: cache region prefix
876 :param prefix: cache region prefix
877 :param condition: condition for cache to be triggered, and return data cached
877 :param condition: condition for cache to be triggered, and return data cached
878 :param func: wrapped heavy function to compute
878 :param func: wrapped heavy function to compute
879
879
880 """
880 """
881 wrapped = func
881 wrapped = func
882 if condition:
882 if condition:
883 log.debug('conditional_cache: True, wrapping call of '
883 log.debug('conditional_cache: True, wrapping call of '
884 'func: %s into %s region cache' % (region, func))
884 'func: %s into %s region cache' % (region, func))
885 wrapped = _cache_decorate((prefix,), None, None, region)(func)
885 wrapped = _cache_decorate((prefix,), None, None, region)(func)
886
886
887 return wrapped
887 return wrapped
@@ -1,5162 +1,5163 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 border: 0;
2 border: 0;
3 outline: 0;
3 outline: 0;
4 font-size: 100%;
4 font-size: 100%;
5 vertical-align: baseline;
5 vertical-align: baseline;
6 background: transparent;
6 background: transparent;
7 margin: 0;
7 margin: 0;
8 padding: 0;
8 padding: 0;
9 }
9 }
10
10
11 body {
11 body {
12 line-height: 1;
12 line-height: 1;
13 height: 100%;
13 height: 100%;
14 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
14 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 font-family: Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
15 font-family: Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 color: #000;
16 color: #000;
17 margin: 0;
17 margin: 0;
18 padding: 0;
18 padding: 0;
19 font-size: 12px;
19 font-size: 12px;
20 }
20 }
21
21
22 ol, ul {
22 ol, ul {
23 list-style: none;
23 list-style: none;
24 }
24 }
25
25
26 blockquote, q {
26 blockquote, q {
27 quotes: none;
27 quotes: none;
28 }
28 }
29
29
30 blockquote:before, blockquote:after, q:before, q:after {
30 blockquote:before, blockquote:after, q:before, q:after {
31 content: none;
31 content: none;
32 }
32 }
33
33
34 :focus {
34 :focus {
35 outline: 0;
35 outline: 0;
36 }
36 }
37
37
38 del {
38 del {
39 text-decoration: line-through;
39 text-decoration: line-through;
40 }
40 }
41
41
42 table {
42 table {
43 border-collapse: collapse;
43 border-collapse: collapse;
44 border-spacing: 0;
44 border-spacing: 0;
45 }
45 }
46
46
47 html {
47 html {
48 height: 100%;
48 height: 100%;
49 }
49 }
50
50
51 a {
51 a {
52 color: #577632;
52 color: #577632;
53 text-decoration: none;
53 text-decoration: none;
54 cursor: pointer;
54 cursor: pointer;
55 }
55 }
56
56
57 a:hover {
57 a:hover {
58 color: #576622;
58 color: #576622;
59 text-decoration: underline;
59 text-decoration: underline;
60 }
60 }
61
61
62 h1, h2, h3, h4, h5, h6,
62 h1, h2, h3, h4, h5, h6,
63 div.h1, div.h2, div.h3, div.h4, div.h5, div.h6 {
63 div.h1, div.h2, div.h3, div.h4, div.h5, div.h6 {
64 color: #292929;
64 color: #292929;
65 font-weight: 700;
65 font-weight: 700;
66 }
66 }
67
67
68 h1, div.h1 {
68 h1, div.h1 {
69 font-size: 22px;
69 font-size: 22px;
70 }
70 }
71
71
72 h2, div.h2 {
72 h2, div.h2 {
73 font-size: 20px;
73 font-size: 20px;
74 }
74 }
75
75
76 h3, div.h3 {
76 h3, div.h3 {
77 font-size: 18px;
77 font-size: 18px;
78 }
78 }
79
79
80 h4, div.h4 {
80 h4, div.h4 {
81 font-size: 16px;
81 font-size: 16px;
82 }
82 }
83
83
84 h5, div.h5 {
84 h5, div.h5 {
85 font-size: 14px;
85 font-size: 14px;
86 }
86 }
87
87
88 h6, div.h6 {
88 h6, div.h6 {
89 font-size: 11px;
89 font-size: 11px;
90 }
90 }
91
91
92 ul.circle {
92 ul.circle {
93 list-style-type: circle;
93 list-style-type: circle;
94 }
94 }
95
95
96 ul.disc {
96 ul.disc {
97 list-style-type: disc;
97 list-style-type: disc;
98 }
98 }
99
99
100 ul.square {
100 ul.square {
101 list-style-type: square;
101 list-style-type: square;
102 }
102 }
103
103
104 ol.lower-roman {
104 ol.lower-roman {
105 list-style-type: lower-roman;
105 list-style-type: lower-roman;
106 }
106 }
107
107
108 ol.upper-roman {
108 ol.upper-roman {
109 list-style-type: upper-roman;
109 list-style-type: upper-roman;
110 }
110 }
111
111
112 ol.lower-alpha {
112 ol.lower-alpha {
113 list-style-type: lower-alpha;
113 list-style-type: lower-alpha;
114 }
114 }
115
115
116 ol.upper-alpha {
116 ol.upper-alpha {
117 list-style-type: upper-alpha;
117 list-style-type: upper-alpha;
118 }
118 }
119
119
120 ol.decimal {
120 ol.decimal {
121 list-style-type: decimal;
121 list-style-type: decimal;
122 }
122 }
123
123
124 div.color {
124 div.color {
125 clear: both;
125 clear: both;
126 overflow: hidden;
126 overflow: hidden;
127 position: absolute;
127 position: absolute;
128 background: #FFF;
128 background: #FFF;
129 margin: 7px 0 0 60px;
129 margin: 7px 0 0 60px;
130 padding: 1px 1px 1px 0;
130 padding: 1px 1px 1px 0;
131 }
131 }
132
132
133 div.color a {
133 div.color a {
134 width: 15px;
134 width: 15px;
135 height: 15px;
135 height: 15px;
136 display: block;
136 display: block;
137 float: left;
137 float: left;
138 margin: 0 0 0 1px;
138 margin: 0 0 0 1px;
139 padding: 0;
139 padding: 0;
140 }
140 }
141
141
142 div.options {
142 div.options {
143 clear: both;
143 clear: both;
144 overflow: hidden;
144 overflow: hidden;
145 position: absolute;
145 position: absolute;
146 background: #FFF;
146 background: #FFF;
147 margin: 7px 0 0 162px;
147 margin: 7px 0 0 162px;
148 padding: 0;
148 padding: 0;
149 }
149 }
150
150
151 div.options a {
151 div.options a {
152 height: 1%;
152 height: 1%;
153 display: block;
153 display: block;
154 text-decoration: none;
154 text-decoration: none;
155 margin: 0;
155 margin: 0;
156 padding: 3px 8px;
156 padding: 3px 8px;
157 }
157 }
158
158
159 code,
159 code,
160 .code pre,
160 .code pre,
161 div.readme .readme_box pre,
161 div.readme .readme_box pre,
162 div.rst-block pre,
162 div.rst-block pre,
163 .CodeMirror .CodeMirror-code pre {
163 .CodeMirror .CodeMirror-code pre {
164 font-size: 12px;
164 font-size: 12px;
165 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
165 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
166 }
166 }
167
167
168 .top-left-rounded-corner {
168 .top-left-rounded-corner {
169 -webkit-border-top-left-radius: 8px;
169 -webkit-border-top-left-radius: 8px;
170 -khtml-border-radius-topleft: 8px;
170 -khtml-border-radius-topleft: 8px;
171 border-top-left-radius: 8px;
171 border-top-left-radius: 8px;
172 }
172 }
173
173
174 .top-right-rounded-corner {
174 .top-right-rounded-corner {
175 -webkit-border-top-right-radius: 8px;
175 -webkit-border-top-right-radius: 8px;
176 -khtml-border-radius-topright: 8px;
176 -khtml-border-radius-topright: 8px;
177 border-top-right-radius: 8px;
177 border-top-right-radius: 8px;
178 }
178 }
179
179
180 .bottom-left-rounded-corner {
180 .bottom-left-rounded-corner {
181 -webkit-border-bottom-left-radius: 8px;
181 -webkit-border-bottom-left-radius: 8px;
182 -khtml-border-radius-bottomleft: 8px;
182 -khtml-border-radius-bottomleft: 8px;
183 border-bottom-left-radius: 8px;
183 border-bottom-left-radius: 8px;
184 }
184 }
185
185
186 .bottom-right-rounded-corner {
186 .bottom-right-rounded-corner {
187 -webkit-border-bottom-right-radius: 8px;
187 -webkit-border-bottom-right-radius: 8px;
188 -khtml-border-radius-bottomright: 8px;
188 -khtml-border-radius-bottomright: 8px;
189 border-bottom-right-radius: 8px;
189 border-bottom-right-radius: 8px;
190 }
190 }
191
191
192 .top-left-rounded-corner-mid {
192 .top-left-rounded-corner-mid {
193 -webkit-border-top-left-radius: 4px;
193 -webkit-border-top-left-radius: 4px;
194 -khtml-border-radius-topleft: 4px;
194 -khtml-border-radius-topleft: 4px;
195 border-top-left-radius: 4px;
195 border-top-left-radius: 4px;
196 }
196 }
197
197
198 .top-right-rounded-corner-mid {
198 .top-right-rounded-corner-mid {
199 -webkit-border-top-right-radius: 4px;
199 -webkit-border-top-right-radius: 4px;
200 -khtml-border-radius-topright: 4px;
200 -khtml-border-radius-topright: 4px;
201 border-top-right-radius: 4px;
201 border-top-right-radius: 4px;
202 }
202 }
203
203
204 .bottom-left-rounded-corner-mid {
204 .bottom-left-rounded-corner-mid {
205 -webkit-border-bottom-left-radius: 4px;
205 -webkit-border-bottom-left-radius: 4px;
206 -khtml-border-radius-bottomleft: 4px;
206 -khtml-border-radius-bottomleft: 4px;
207 border-bottom-left-radius: 4px;
207 border-bottom-left-radius: 4px;
208 }
208 }
209
209
210 .bottom-right-rounded-corner-mid {
210 .bottom-right-rounded-corner-mid {
211 -webkit-border-bottom-right-radius: 4px;
211 -webkit-border-bottom-right-radius: 4px;
212 -khtml-border-radius-bottomright: 4px;
212 -khtml-border-radius-bottomright: 4px;
213 border-bottom-right-radius: 4px;
213 border-bottom-right-radius: 4px;
214 }
214 }
215
215
216 .help-block {
216 .help-block {
217 color: #999999;
217 color: #999999;
218 display: block;
218 display: block;
219 margin-bottom: 0;
219 margin-bottom: 0;
220 margin-top: 5px;
220 margin-top: 5px;
221 }
221 }
222
222
223 .empty_data {
223 .empty_data {
224 color: #B9B9B9;
224 color: #B9B9B9;
225 }
225 }
226
226
227 .truncate {
227 .truncate {
228 white-space: nowrap;
228 white-space: nowrap;
229 overflow: hidden;
229 overflow: hidden;
230 text-overflow: ellipsis;
230 text-overflow: ellipsis;
231 -o-text-overflow: ellipsis;
231 -o-text-overflow: ellipsis;
232 -ms-text-overflow: ellipsis;
232 -ms-text-overflow: ellipsis;
233 }
233 }
234
234
235 .truncate.autoexpand:hover {
235 .truncate.autoexpand:hover {
236 text-overflow: none;
236 text-overflow: none;
237 overflow: visible;
237 overflow: visible;
238 }
238 }
239
239
240 a.permalink {
240 a.permalink {
241 visibility: hidden;
241 visibility: hidden;
242 position: absolute;
242 position: absolute;
243 margin: 3px 4px;
243 margin: 3px 4px;
244 }
244 }
245
245
246 a.permalink:hover {
246 a.permalink:hover {
247 text-decoration: none;
247 text-decoration: none;
248 }
248 }
249
249
250 h1:hover > a.permalink,
250 h1:hover > a.permalink,
251 h2:hover > a.permalink,
251 h2:hover > a.permalink,
252 h3:hover > a.permalink,
252 h3:hover > a.permalink,
253 h4:hover > a.permalink,
253 h4:hover > a.permalink,
254 h5:hover > a.permalink,
254 h5:hover > a.permalink,
255 h6:hover > a.permalink,
255 h6:hover > a.permalink,
256 div:hover > a.permalink {
256 div:hover > a.permalink {
257 visibility: visible;
257 visibility: visible;
258 }
258 }
259
259
260 #header #logo {
260 #header #logo {
261 padding-left: 10px;
261 padding-left: 10px;
262 }
262 }
263
263
264 div.header img {
264 div.header img {
265 padding-top: 5px;
265 padding-top: 5px;
266 }
266 }
267
267
268 #header #logo div.header,
268 #header #logo div.header,
269 #header #logo div.branding {
269 #header #logo div.branding {
270 font-size: 20px;
270 font-size: 20px;
271 color: white;
271 color: white;
272 float: left;
272 float: left;
273 height: 44px;
273 height: 44px;
274 line-height: 44px;
274 line-height: 44px;
275 margin-right: 5px;
275 margin-right: 5px;
276 }
276 }
277
277
278 #header ul#logged-user {
278 #header ul#logged-user {
279 margin-bottom: 5px !important;
279 margin-bottom: 5px !important;
280 -webkit-border-radius: 0px 0px 8px 8px;
280 -webkit-border-radius: 0px 0px 8px 8px;
281 -khtml-border-radius: 0px 0px 8px 8px;
281 -khtml-border-radius: 0px 0px 8px 8px;
282 border-radius: 0px 0px 8px 8px;
282 border-radius: 0px 0px 8px 8px;
283 height: 37px;
283 height: 37px;
284 background-color: #577632;
284 background-color: #577632;
285 background-repeat: repeat-x;
285 background-repeat: repeat-x;
286 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
286 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
287 background-image: -moz-linear-gradient(top, #577632, #577632);
287 background-image: -moz-linear-gradient(top, #577632, #577632);
288 background-image: -ms-linear-gradient(top, #577632, #577632);
288 background-image: -ms-linear-gradient(top, #577632, #577632);
289 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
289 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
290 background-image: -webkit-linear-gradient(top, #577632, #577632);
290 background-image: -webkit-linear-gradient(top, #577632, #577632);
291 background-image: -o-linear-gradient(top, #577632, #577632);
291 background-image: -o-linear-gradient(top, #577632, #577632);
292 background-image: linear-gradient(to bottom, #577632, #577632);
292 background-image: linear-gradient(to bottom, #577632, #577632);
293 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',endColorstr='#577632', GradientType=0 );
293 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',endColorstr='#577632', GradientType=0 );
294 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
294 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
295 }
295 }
296
296
297 #header ul#logged-user li {
297 #header ul#logged-user li {
298 list-style: none;
298 list-style: none;
299 float: left;
299 float: left;
300 margin: 8px 0 0;
300 margin: 8px 0 0;
301 padding: 4px 12px;
301 padding: 4px 12px;
302 border-left: 1px solid #576622;
302 border-left: 1px solid #576622;
303 }
303 }
304
304
305 #header ul#logged-user li.first {
305 #header ul#logged-user li.first {
306 border-left: none;
306 border-left: none;
307 margin: 4px;
307 margin: 4px;
308 }
308 }
309
309
310 #header ul#logged-user li.first div.gravatar {
310 #header ul#logged-user li.first div.gravatar {
311 margin-top: -2px;
311 margin-top: -2px;
312 }
312 }
313
313
314 #header ul#logged-user li.first div.account {
314 #header ul#logged-user li.first div.account {
315 padding-top: 4px;
315 padding-top: 4px;
316 float: left;
316 float: left;
317 }
317 }
318
318
319 #header ul#logged-user li.last {
319 #header ul#logged-user li.last {
320 border-right: none;
320 border-right: none;
321 }
321 }
322
322
323 #header ul#logged-user li a {
323 #header ul#logged-user li a {
324 color: #fff;
324 color: #fff;
325 font-weight: 700;
325 font-weight: 700;
326 text-decoration: none;
326 text-decoration: none;
327 }
327 }
328
328
329 #header ul#logged-user li a:hover {
329 #header ul#logged-user li a:hover {
330 text-decoration: underline;
330 text-decoration: underline;
331 }
331 }
332
332
333 #header ul#logged-user li.highlight a {
333 #header ul#logged-user li.highlight a {
334 color: #fff;
334 color: #fff;
335 }
335 }
336
336
337 #header ul#logged-user li.highlight a:hover {
337 #header ul#logged-user li.highlight a:hover {
338 color: #FFF;
338 color: #FFF;
339 }
339 }
340 #header-dd {
340 #header-dd {
341 clear: both;
341 clear: both;
342 position: fixed !important;
342 position: fixed !important;
343 background-color: #577632;
343 background-color: #577632;
344 opacity: 0.01;
344 opacity: 0.01;
345 cursor: pointer;
345 cursor: pointer;
346 min-height: 10px;
346 min-height: 10px;
347 width: 100% !important;
347 width: 100% !important;
348 -webkit-border-radius: 0px 0px 4px 4px;
348 -webkit-border-radius: 0px 0px 4px 4px;
349 -khtml-border-radius: 0px 0px 4px 4px;
349 -khtml-border-radius: 0px 0px 4px 4px;
350 border-radius: 0px 0px 4px 4px;
350 border-radius: 0px 0px 4px 4px;
351 }
351 }
352
352
353 #header-dd:hover {
353 #header-dd:hover {
354 opacity: 0.2;
354 opacity: 0.2;
355 -webkit-transition: opacity 0.5s ease-in-out;
355 -webkit-transition: opacity 0.5s ease-in-out;
356 -moz-transition: opacity 0.5s ease-in-out;
356 -moz-transition: opacity 0.5s ease-in-out;
357 transition: opacity 0.5s ease-in-out;
357 transition: opacity 0.5s ease-in-out;
358 }
358 }
359
359
360 #header #header-inner {
360 #header #header-inner {
361 min-height: 44px;
361 min-height: 44px;
362 clear: both;
362 clear: both;
363 position: relative;
363 position: relative;
364 background-color: #577632;
364 background-color: #577632;
365 background-repeat: repeat-x;
365 background-repeat: repeat-x;
366 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
366 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
367 background-image: -moz-linear-gradient(top, #577632, #577632);
367 background-image: -moz-linear-gradient(top, #577632, #577632);
368 background-image: -ms-linear-gradient(top, #577632, #577632);
368 background-image: -ms-linear-gradient(top, #577632, #577632);
369 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632),color-stop(100%, #577632) );
369 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632),color-stop(100%, #577632) );
370 background-image: -webkit-linear-gradient(top, #577632, #577632);
370 background-image: -webkit-linear-gradient(top, #577632, #577632);
371 background-image: -o-linear-gradient(top, #577632, #577632);
371 background-image: -o-linear-gradient(top, #577632, #577632);
372 background-image: linear-gradient(to bottom, #577632, #577632);
372 background-image: linear-gradient(to bottom, #577632, #577632);
373 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',endColorstr='#577632', GradientType=0 );
373 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',endColorstr='#577632', GradientType=0 );
374 margin: 0;
374 margin: 0;
375 padding: 0;
375 padding: 0;
376 display: block;
376 display: block;
377 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
377 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
378 -webkit-border-radius: 0px 0px 4px 4px;
378 -webkit-border-radius: 0px 0px 4px 4px;
379 -khtml-border-radius: 0px 0px 4px 4px;
379 -khtml-border-radius: 0px 0px 4px 4px;
380 border-radius: 0px 0px 4px 4px;
380 border-radius: 0px 0px 4px 4px;
381 }
381 }
382 #header #header-inner.hover {
382 #header #header-inner.hover {
383 width: 100% !important;
383 width: 100% !important;
384 -webkit-border-radius: 0px 0px 0px 0px;
384 -webkit-border-radius: 0px 0px 0px 0px;
385 -khtml-border-radius: 0px 0px 0px 0px;
385 -khtml-border-radius: 0px 0px 0px 0px;
386 border-radius: 0px 0px 0px 0px;
386 border-radius: 0px 0px 0px 0px;
387 position: fixed !important;
387 position: fixed !important;
388 z-index: 10000;
388 z-index: 10000;
389 }
389 }
390
390
391 .ie7 #header #header-inner.hover,
391 .ie7 #header #header-inner.hover,
392 .ie8 #header #header-inner.hover,
392 .ie8 #header #header-inner.hover,
393 .ie9 #header #header-inner.hover
393 .ie9 #header #header-inner.hover
394 {
394 {
395 z-index: auto !important;
395 z-index: auto !important;
396 }
396 }
397
397
398 .header-pos-fix, .anchor {
398 .header-pos-fix, .anchor {
399 margin-top: -46px;
399 margin-top: -46px;
400 padding-top: 46px;
400 padding-top: 46px;
401 }
401 }
402
402
403 #header #header-inner #home a {
403 #header #header-inner #home a {
404 height: 40px;
404 height: 40px;
405 width: 46px;
405 width: 46px;
406 display: block;
406 display: block;
407 background-position: 0 0;
407 background-position: 0 0;
408 margin: 0;
408 margin: 0;
409 padding: 0;
409 padding: 0;
410 }
410 }
411
411
412 #header #header-inner #home a:hover {
412 #header #header-inner #home a:hover {
413 background-position: 0 -40px;
413 background-position: 0 -40px;
414 }
414 }
415
415
416 #header #header-inner #logo {
416 #header #header-inner #logo {
417 float: left;
417 float: left;
418 position: absolute;
418 position: absolute;
419 }
419 }
420
420
421 #header #header-inner #logo h1 {
421 #header #header-inner #logo h1 {
422 color: #FFF;
422 color: #FFF;
423 font-size: 20px;
423 font-size: 20px;
424 margin: 12px 0 0 13px;
424 margin: 12px 0 0 13px;
425 padding: 0;
425 padding: 0;
426 }
426 }
427
427
428 #header #header-inner #logo a {
428 #header #header-inner #logo a {
429 color: #fff;
429 color: #fff;
430 text-decoration: none;
430 text-decoration: none;
431 }
431 }
432
432
433 #header #header-inner #logo a:hover {
433 #header #header-inner #logo a:hover {
434 color: #bfe3ff;
434 color: #bfe3ff;
435 }
435 }
436
436
437 #header #header-inner #quick {
437 #header #header-inner #quick {
438 position: relative;
438 position: relative;
439 float: right;
439 float: right;
440 list-style-type: none;
440 list-style-type: none;
441 list-style-position: outside;
441 list-style-position: outside;
442 margin: 4px 8px 0 0;
442 margin: 4px 8px 0 0;
443 padding: 0;
443 padding: 0;
444 border-radius: 4px;
444 border-radius: 4px;
445 }
445 }
446
446
447 #header #header-inner #quick li span.short {
447 #header #header-inner #quick li span.short {
448 padding: 9px 6px 8px 6px;
448 padding: 9px 6px 8px 6px;
449 }
449 }
450
450
451 #header #header-inner #quick li span {
451 #header #header-inner #quick li span {
452 display: inline;
452 display: inline;
453 margin: 0;
453 margin: 0;
454 }
454 }
455
455
456 #header #header-inner #quick li span.normal {
456 #header #header-inner #quick li span.normal {
457 border: none;
457 border: none;
458 padding: 10px 12px 8px;
458 padding: 10px 12px 8px;
459 }
459 }
460
460
461 #header #header-inner #quick li span.icon {
461 #header #header-inner #quick li span.icon {
462 border-left: none;
462 border-left: none;
463 padding-left: 10px;
463 padding-left: 10px;
464 }
464 }
465
465
466 #header #header-inner #quick li span.icon_short {
466 #header #header-inner #quick li span.icon_short {
467 top: 0;
467 top: 0;
468 left: 0;
468 left: 0;
469 border-left: none;
469 border-left: none;
470 border-right: 1px solid #2e5c89;
470 border-right: 1px solid #2e5c89;
471 padding: 8px 6px 4px;
471 padding: 8px 6px 4px;
472 }
472 }
473
473
474 #header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
474 #header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
475 vertical-align: middle;
475 vertical-align: middle;
476 margin-bottom: 2px;
476 margin-bottom: 2px;
477 }
477 }
478
478
479 #header #header-inner #quick ul.repo_switcher {
479 #header #header-inner #quick ul.repo_switcher {
480 max-height: 275px;
480 max-height: 275px;
481 overflow-x: hidden;
481 overflow-x: hidden;
482 overflow-y: auto;
482 overflow-y: auto;
483 }
483 }
484
484
485 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
485 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
486 padding: 2px 3px;
486 padding: 2px 3px;
487 padding-right: 17px;
487 padding-right: 17px;
488 }
488 }
489
489
490 #header #header-inner #quick ul.repo_switcher li.qfilter_rs input {
490 #header #header-inner #quick ul.repo_switcher li.qfilter_rs input {
491 width: 100%;
491 width: 100%;
492 border-radius: 10px;
492 border-radius: 10px;
493 padding: 2px 7px;
493 padding: 2px 7px;
494 }
494 }
495
495
496 #header #header-inner #quick .repo_switcher_type {
496 #header #header-inner #quick .repo_switcher_type {
497 position: absolute;
497 position: absolute;
498 left: 0;
498 left: 0;
499 top: 9px;
499 top: 9px;
500 margin: 0px 2px 0px 2px;
500 margin: 0px 2px 0px 2px;
501 }
501 }
502
502
503 #header #header-inner #quick li ul li a.journal, #header #header-inner #quick li ul li a.journal:hover {
503 #header #header-inner #quick li ul li a.journal, #header #header-inner #quick li ul li a.journal:hover {
504 background-image: url("../images/icons/book.png");
504 background-image: url("../images/icons/book.png");
505 }
505 }
506
506
507 #header #header-inner #quick li ul li a.private_repo, #header #header-inner #quick li ul li a.private_repo:hover {
507 #header #header-inner #quick li ul li a.private_repo, #header #header-inner #quick li ul li a.private_repo:hover {
508 background-image: url("../images/icons/private_repo.png")
508 background-image: url("../images/icons/private_repo.png")
509 }
509 }
510
510
511 #header #header-inner #quick li ul li a.public_repo, #header #header-inner #quick li ul li a.public_repo:hover {
511 #header #header-inner #quick li ul li a.public_repo, #header #header-inner #quick li ul li a.public_repo:hover {
512 background-image: url("../images/icons/public_repo.png");
512 background-image: url("../images/icons/public_repo.png");
513 }
513 }
514
514
515 #header #header-inner #quick li ul li a.hg, #header #header-inner #quick li ul li a.hg:hover {
515 #header #header-inner #quick li ul li a.hg, #header #header-inner #quick li ul li a.hg:hover {
516 background-image: url("../images/icons/hgicon.png");
516 background-image: url("../images/icons/hgicon.png");
517 padding-left: 42px;
517 padding-left: 42px;
518 background-position: 20px 9px;
518 background-position: 20px 9px;
519 }
519 }
520
520
521 #header #header-inner #quick li ul li a.git, #header #header-inner #quick li ul li a.git:hover {
521 #header #header-inner #quick li ul li a.git, #header #header-inner #quick li ul li a.git:hover {
522 background-image: url("../images/icons/giticon.png");
522 background-image: url("../images/icons/giticon.png");
523 padding-left: 42px;
523 padding-left: 42px;
524 background-position: 20px 9px;
524 background-position: 20px 9px;
525 }
525 }
526
526
527 #header #header-inner #quick li ul li a.repos, #header #header-inner #quick li ul li a.repos:hover {
527 #header #header-inner #quick li ul li a.repos, #header #header-inner #quick li ul li a.repos:hover {
528 background-image: url("../images/icons/database_edit.png");
528 background-image: url("../images/icons/database_edit.png");
529 }
529 }
530
530
531 #header #header-inner #quick li ul li a.repos_groups, #header #header-inner #quick li ul li a.repos_groups:hover {
531 #header #header-inner #quick li ul li a.repos_groups, #header #header-inner #quick li ul li a.repos_groups:hover {
532 background-image: url("../images/icons/database_link.png");
532 background-image: url("../images/icons/database_link.png");
533 }
533 }
534
534
535 #header #header-inner #quick li ul li a.users, #header #header-inner #quick li ul li a.users:hover {
535 #header #header-inner #quick li ul li a.users, #header #header-inner #quick li ul li a.users:hover {
536 background-image: url("../images/icons/user_edit.png");
536 background-image: url("../images/icons/user_edit.png");
537 }
537 }
538
538
539 #header #header-inner #quick li ul li a.groups, #header #header-inner #quick li ul li a.groups:hover {
539 #header #header-inner #quick li ul li a.groups, #header #header-inner #quick li ul li a.groups:hover {
540 background-image: url("../images/icons/group_edit.png");
540 background-image: url("../images/icons/group_edit.png");
541 }
541 }
542
542
543 #header #header-inner #quick li ul li a.defaults, #header #header-inner #quick li ul li a.defaults:hover {
543 #header #header-inner #quick li ul li a.defaults, #header #header-inner #quick li ul li a.defaults:hover {
544 background-image: url("../images/icons/wrench.png");
544 background-image: url("../images/icons/wrench.png");
545 }
545 }
546
546
547 #header #header-inner #quick li ul li a.settings, #header #header-inner #quick li ul li a.settings:hover {
547 #header #header-inner #quick li ul li a.settings, #header #header-inner #quick li ul li a.settings:hover {
548 background-image: url("../images/icons/cog.png");
548 background-image: url("../images/icons/cog.png");
549 }
549 }
550
550
551 #header #header-inner #quick li ul li a.permissions, #header #header-inner #quick li ul li a.permissions:hover {
551 #header #header-inner #quick li ul li a.permissions, #header #header-inner #quick li ul li a.permissions:hover {
552 background-image: url("../images/icons/key.png");
552 background-image: url("../images/icons/key.png");
553 }
553 }
554
554
555 #header #header-inner #quick li ul li a.ldap, #header #header-inner #quick li ul li a.ldap:hover {
555 #header #header-inner #quick li ul li a.ldap, #header #header-inner #quick li ul li a.ldap:hover {
556 background-image: url("../images/icons/server_key.png");
556 background-image: url("../images/icons/server_key.png");
557 }
557 }
558
558
559 #header #header-inner #quick li ul li a.fork, #header #header-inner #quick li ul li a.fork:hover {
559 #header #header-inner #quick li ul li a.fork, #header #header-inner #quick li ul li a.fork:hover {
560 background-image: url("../images/icons/arrow_divide.png");
560 background-image: url("../images/icons/arrow_divide.png");
561 }
561 }
562
562
563 #header #header-inner #quick li ul li a.locking_add, #header #header-inner #quick li ul li a.locking_add:hover {
563 #header #header-inner #quick li ul li a.locking_add, #header #header-inner #quick li ul li a.locking_add:hover {
564 background-image: url("../images/icons/lock_add.png");
564 background-image: url("../images/icons/lock_add.png");
565 }
565 }
566
566
567 #header #header-inner #quick li ul li a.locking_del, #header #header-inner #quick li ul li a.locking_del:hover {
567 #header #header-inner #quick li ul li a.locking_del, #header #header-inner #quick li ul li a.locking_del:hover {
568 background-image: url("../images/icons/lock_delete.png");
568 background-image: url("../images/icons/lock_delete.png");
569 }
569 }
570
570
571 #header #header-inner #quick li ul li a.pull_request, #header #header-inner #quick li ul li a.pull_request:hover {
571 #header #header-inner #quick li ul li a.pull_request, #header #header-inner #quick li ul li a.pull_request:hover {
572 background-image: url("../images/icons/arrow_join.png") ;
572 background-image: url("../images/icons/arrow_join.png") ;
573 }
573 }
574
574
575 #header #header-inner #quick li ul li a.compare_request, #header #header-inner #quick li ul li a.compare_request:hover {
575 #header #header-inner #quick li ul li a.compare_request, #header #header-inner #quick li ul li a.compare_request:hover {
576 background-image: url("../images/icons/arrow_inout.png");
576 background-image: url("../images/icons/arrow_inout.png");
577 }
577 }
578
578
579 #header #header-inner #quick li ul li a.search, #header #header-inner #quick li ul li a.search:hover {
579 #header #header-inner #quick li ul li a.search, #header #header-inner #quick li ul li a.search:hover {
580 background-image: url("../images/icons/search_16.png");
580 background-image: url("../images/icons/search_16.png");
581 }
581 }
582
582
583 #header #header-inner #quick li ul li a.delete, #header #header-inner #quick li ul li a.delete:hover {
583 #header #header-inner #quick li ul li a.delete, #header #header-inner #quick li ul li a.delete:hover {
584 background-image: url("../images/icons/delete.png");
584 background-image: url("../images/icons/delete.png");
585 }
585 }
586
586
587 #header #header-inner #quick li ul li a.branches, #header #header-inner #quick li ul li a.branches:hover {
587 #header #header-inner #quick li ul li a.branches, #header #header-inner #quick li ul li a.branches:hover {
588 background-image: url("../images/icons/arrow_branch.png");
588 background-image: url("../images/icons/arrow_branch.png");
589 }
589 }
590
590
591 #header #header-inner #quick li ul li a.tags,
591 #header #header-inner #quick li ul li a.tags,
592 #header #header-inner #quick li ul li a.tags:hover {
592 #header #header-inner #quick li ul li a.tags:hover {
593 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
593 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
594 width: 167px;
594 width: 167px;
595 margin: 0;
595 margin: 0;
596 padding: 12px 9px 7px 24px;
596 padding: 12px 9px 7px 24px;
597 }
597 }
598
598
599 #header #header-inner #quick li ul li a.bookmarks,
599 #header #header-inner #quick li ul li a.bookmarks,
600 #header #header-inner #quick li ul li a.bookmarks:hover {
600 #header #header-inner #quick li ul li a.bookmarks:hover {
601 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
601 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
602 width: 167px;
602 width: 167px;
603 margin: 0;
603 margin: 0;
604 padding: 12px 9px 7px 24px;
604 padding: 12px 9px 7px 24px;
605 }
605 }
606
606
607 #header #header-inner #quick li ul li a.admin,
607 #header #header-inner #quick li ul li a.admin,
608 #header #header-inner #quick li ul li a.admin:hover {
608 #header #header-inner #quick li ul li a.admin:hover {
609 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
609 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
610 width: 167px;
610 width: 167px;
611 margin: 0;
611 margin: 0;
612 padding: 12px 9px 7px 24px;
612 padding: 12px 9px 7px 24px;
613 }
613 }
614
614
615 .groups_breadcrumbs a {
615 .groups_breadcrumbs a {
616 color: #fff;
616 color: #fff;
617 }
617 }
618
618
619 .groups_breadcrumbs a:hover {
619 .groups_breadcrumbs a:hover {
620 color: #bfe3ff;
620 color: #bfe3ff;
621 text-decoration: none;
621 text-decoration: none;
622 }
622 }
623
623
624 td.quick_repo_menu {
624 td.quick_repo_menu {
625 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
625 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
626 cursor: pointer;
626 cursor: pointer;
627 width: 8px;
627 width: 8px;
628 border: 1px solid transparent;
628 border: 1px solid transparent;
629 }
629 }
630
630
631 td.quick_repo_menu.active {
631 td.quick_repo_menu.active {
632 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
632 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
633 border: 1px solid #577632;
633 border: 1px solid #577632;
634 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
634 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
635 cursor: pointer;
635 cursor: pointer;
636 }
636 }
637
637
638 td.quick_repo_menu .menu_items {
638 td.quick_repo_menu .menu_items {
639 margin-top: 10px;
639 margin-top: 10px;
640 margin-left: -6px;
640 margin-left: -6px;
641 width: 150px;
641 width: 150px;
642 position: absolute;
642 position: absolute;
643 background-color: #FFF;
643 background-color: #FFF;
644 background: none repeat scroll 0 0 #FFFFFF;
644 background: none repeat scroll 0 0 #FFFFFF;
645 border-color: #577632 #666666 #666666;
645 border-color: #577632 #666666 #666666;
646 border-right: 1px solid #666666;
646 border-right: 1px solid #666666;
647 border-style: solid;
647 border-style: solid;
648 border-width: 1px;
648 border-width: 1px;
649 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
649 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
650 border-top-style: none;
650 border-top-style: none;
651 }
651 }
652
652
653 td.quick_repo_menu .menu_items li {
653 td.quick_repo_menu .menu_items li {
654 padding: 0 !important;
654 padding: 0 !important;
655 }
655 }
656
656
657 td.quick_repo_menu .menu_items a {
657 td.quick_repo_menu .menu_items a {
658 display: block;
658 display: block;
659 padding: 4px 12px 4px 8px;
659 padding: 4px 12px 4px 8px;
660 }
660 }
661
661
662 td.quick_repo_menu .menu_items a:hover {
662 td.quick_repo_menu .menu_items a:hover {
663 background-color: #EEE;
663 background-color: #EEE;
664 text-decoration: none;
664 text-decoration: none;
665 }
665 }
666
666
667 td.quick_repo_menu .menu_items .icon img {
667 td.quick_repo_menu .menu_items .icon img {
668 margin-bottom: -2px;
668 margin-bottom: -2px;
669 }
669 }
670
670
671 td.quick_repo_menu .menu_items.hidden {
671 td.quick_repo_menu .menu_items.hidden {
672 display: none;
672 display: none;
673 }
673 }
674
674
675 .yui-dt-first th {
675 .yui-dt-first th {
676 text-align: left;
676 text-align: left;
677 }
677 }
678
678
679 /*
679 /*
680 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
680 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
681 Code licensed under the BSD License:
681 Code licensed under the BSD License:
682 http://developer.yahoo.com/yui/license.html
682 http://developer.yahoo.com/yui/license.html
683 version: 2.9.0
683 version: 2.9.0
684 */
684 */
685 .yui-skin-sam .yui-dt-mask {
685 .yui-skin-sam .yui-dt-mask {
686 position: absolute;
686 position: absolute;
687 z-index: 9500;
687 z-index: 9500;
688 }
688 }
689 .yui-dt-tmp {
689 .yui-dt-tmp {
690 position: absolute;
690 position: absolute;
691 left: -9000px;
691 left: -9000px;
692 }
692 }
693 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
693 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
694 .yui-dt-scrollable .yui-dt-hd {
694 .yui-dt-scrollable .yui-dt-hd {
695 overflow: hidden;
695 overflow: hidden;
696 position: relative;
696 position: relative;
697 }
697 }
698 .yui-dt-scrollable .yui-dt-bd thead tr,
698 .yui-dt-scrollable .yui-dt-bd thead tr,
699 .yui-dt-scrollable .yui-dt-bd thead th {
699 .yui-dt-scrollable .yui-dt-bd thead th {
700 position: absolute;
700 position: absolute;
701 left: -1500px;
701 left: -1500px;
702 }
702 }
703 .yui-dt-scrollable tbody { -moz-outline: 0 }
703 .yui-dt-scrollable tbody { -moz-outline: 0 }
704 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
704 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
705 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
705 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
706 .yui-dt-coltarget {
706 .yui-dt-coltarget {
707 position: absolute;
707 position: absolute;
708 z-index: 999;
708 z-index: 999;
709 }
709 }
710 .yui-dt-hd { zoom: 1 }
710 .yui-dt-hd { zoom: 1 }
711 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
711 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
712 .yui-dt-resizer {
712 .yui-dt-resizer {
713 position: absolute;
713 position: absolute;
714 right: 0;
714 right: 0;
715 bottom: 0;
715 bottom: 0;
716 height: 100%;
716 height: 100%;
717 cursor: e-resize;
717 cursor: e-resize;
718 cursor: col-resize;
718 cursor: col-resize;
719 background-color: #CCC;
719 background-color: #CCC;
720 opacity: 0;
720 opacity: 0;
721 filter: alpha(opacity=0);
721 filter: alpha(opacity=0);
722 }
722 }
723 .yui-dt-resizerproxy {
723 .yui-dt-resizerproxy {
724 visibility: hidden;
724 visibility: hidden;
725 position: absolute;
725 position: absolute;
726 z-index: 9000;
726 z-index: 9000;
727 background-color: #CCC;
727 background-color: #CCC;
728 opacity: 0;
728 opacity: 0;
729 filter: alpha(opacity=0);
729 filter: alpha(opacity=0);
730 }
730 }
731 th.yui-dt-hidden .yui-dt-liner,
731 th.yui-dt-hidden .yui-dt-liner,
732 td.yui-dt-hidden .yui-dt-liner,
732 td.yui-dt-hidden .yui-dt-liner,
733 th.yui-dt-hidden .yui-dt-resizer { display: none }
733 th.yui-dt-hidden .yui-dt-resizer { display: none }
734 .yui-dt-editor,
734 .yui-dt-editor,
735 .yui-dt-editor-shim {
735 .yui-dt-editor-shim {
736 position: absolute;
736 position: absolute;
737 z-index: 9000;
737 z-index: 9000;
738 }
738 }
739 .yui-skin-sam .yui-dt table {
739 .yui-skin-sam .yui-dt table {
740 margin: 0;
740 margin: 0;
741 padding: 0;
741 padding: 0;
742 font-family: arial;
742 font-family: arial;
743 font-size: inherit;
743 font-size: inherit;
744 border-collapse: separate;
744 border-collapse: separate;
745 *border-collapse: collapse;
745 *border-collapse: collapse;
746 border-spacing: 0;
746 border-spacing: 0;
747 border: 1px solid #7f7f7f;
747 border: 1px solid #7f7f7f;
748 }
748 }
749 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
749 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
750 .yui-skin-sam .yui-dt caption {
750 .yui-skin-sam .yui-dt caption {
751 color: #000;
751 color: #000;
752 font-size: 85%;
752 font-size: 85%;
753 font-weight: normal;
753 font-weight: normal;
754 font-style: italic;
754 font-style: italic;
755 line-height: 1;
755 line-height: 1;
756 padding: 1em 0;
756 padding: 1em 0;
757 text-align: center;
757 text-align: center;
758 }
758 }
759 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
759 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
760 .yui-skin-sam .yui-dt th,
760 .yui-skin-sam .yui-dt th,
761 .yui-skin-sam .yui-dt th a {
761 .yui-skin-sam .yui-dt th a {
762 font-weight: normal;
762 font-weight: normal;
763 text-decoration: none;
763 text-decoration: none;
764 color: #000;
764 color: #000;
765 vertical-align: bottom;
765 vertical-align: bottom;
766 }
766 }
767 .yui-skin-sam .yui-dt th {
767 .yui-skin-sam .yui-dt th {
768 margin: 0;
768 margin: 0;
769 padding: 0;
769 padding: 0;
770 border: 0;
770 border: 0;
771 border-right: 1px solid #cbcbcb;
771 border-right: 1px solid #cbcbcb;
772 }
772 }
773 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
773 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
774 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
774 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
775 .yui-skin-sam .yui-dt-liner {
775 .yui-skin-sam .yui-dt-liner {
776 margin: 0;
776 margin: 0;
777 padding: 0;
777 padding: 0;
778 }
778 }
779 .yui-skin-sam .yui-dt-coltarget {
779 .yui-skin-sam .yui-dt-coltarget {
780 width: 5px;
780 width: 5px;
781 background-color: red;
781 background-color: red;
782 }
782 }
783 .yui-skin-sam .yui-dt td {
783 .yui-skin-sam .yui-dt td {
784 margin: 0;
784 margin: 0;
785 padding: 0;
785 padding: 0;
786 border: 0;
786 border: 0;
787 border-right: 1px solid #cbcbcb;
787 border-right: 1px solid #cbcbcb;
788 text-align: left;
788 text-align: left;
789 }
789 }
790 .yui-skin-sam .yui-dt-list td { border-right: 0 }
790 .yui-skin-sam .yui-dt-list td { border-right: 0 }
791 .yui-skin-sam .yui-dt-resizer { width: 6px }
791 .yui-skin-sam .yui-dt-resizer { width: 6px }
792 .yui-skin-sam .yui-dt-mask {
792 .yui-skin-sam .yui-dt-mask {
793 background-color: #000;
793 background-color: #000;
794 opacity: .25;
794 opacity: .25;
795 filter: alpha(opacity=25);
795 filter: alpha(opacity=25);
796 }
796 }
797 .yui-skin-sam .yui-dt-message { background-color: #FFF }
797 .yui-skin-sam .yui-dt-message { background-color: #FFF }
798 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
798 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
799 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
799 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
800 border-left: 1px solid #7f7f7f;
800 border-left: 1px solid #7f7f7f;
801 border-top: 1px solid #7f7f7f;
801 border-top: 1px solid #7f7f7f;
802 border-right: 1px solid #7f7f7f;
802 border-right: 1px solid #7f7f7f;
803 }
803 }
804 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
804 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
805 border-left: 1px solid #7f7f7f;
805 border-left: 1px solid #7f7f7f;
806 border-bottom: 1px solid #7f7f7f;
806 border-bottom: 1px solid #7f7f7f;
807 border-right: 1px solid #7f7f7f;
807 border-right: 1px solid #7f7f7f;
808 background-color: #FFF;
808 background-color: #FFF;
809 }
809 }
810 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
810 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
811 .yui-skin-sam th.yui-dt-asc,
811 .yui-skin-sam th.yui-dt-asc,
812 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
812 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
813 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
813 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
814 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
814 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
815 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
815 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
816 tbody .yui-dt-editable { cursor: pointer }
816 tbody .yui-dt-editable { cursor: pointer }
817 .yui-dt-editor {
817 .yui-dt-editor {
818 text-align: left;
818 text-align: left;
819 background-color: #f2f2f2;
819 background-color: #f2f2f2;
820 border: 1px solid #808080;
820 border: 1px solid #808080;
821 padding: 6px;
821 padding: 6px;
822 }
822 }
823 .yui-dt-editor label {
823 .yui-dt-editor label {
824 padding-left: 4px;
824 padding-left: 4px;
825 padding-right: 6px;
825 padding-right: 6px;
826 }
826 }
827 .yui-dt-editor .yui-dt-button {
827 .yui-dt-editor .yui-dt-button {
828 padding-top: 6px;
828 padding-top: 6px;
829 text-align: right;
829 text-align: right;
830 }
830 }
831 .yui-dt-editor .yui-dt-button button {
831 .yui-dt-editor .yui-dt-button button {
832 background: url(../images/sprite.png) repeat-x 0 0;
832 background: url(../images/sprite.png) repeat-x 0 0;
833 border: 1px solid #999;
833 border: 1px solid #999;
834 width: 4em;
834 width: 4em;
835 height: 1.8em;
835 height: 1.8em;
836 margin-left: 6px;
836 margin-left: 6px;
837 }
837 }
838 .yui-dt-editor .yui-dt-button button.yui-dt-default {
838 .yui-dt-editor .yui-dt-button button.yui-dt-default {
839 background: url(../images/sprite.png) repeat-x 0 -1400px;
839 background: url(../images/sprite.png) repeat-x 0 -1400px;
840 background-color: #5584e0;
840 background-color: #5584e0;
841 border: 1px solid #304369;
841 border: 1px solid #304369;
842 color: #FFF;
842 color: #FFF;
843 }
843 }
844 .yui-dt-editor .yui-dt-button button:hover {
844 .yui-dt-editor .yui-dt-button button:hover {
845 background: url(../images/sprite.png) repeat-x 0 -1300px;
845 background: url(../images/sprite.png) repeat-x 0 -1300px;
846 color: #000;
846 color: #000;
847 }
847 }
848 .yui-dt-editor .yui-dt-button button:active {
848 .yui-dt-editor .yui-dt-button button:active {
849 background: url(../images/sprite.png) repeat-x 0 -1700px;
849 background: url(../images/sprite.png) repeat-x 0 -1700px;
850 color: #000;
850 color: #000;
851 }
851 }
852 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
852 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
853 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
853 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
854 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
854 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
855 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
855 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
856 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
856 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
857 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
857 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
858 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
858 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
859 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
859 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
860 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
860 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
861 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
861 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
862 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
862 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
863 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
863 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
864 .yui-skin-sam th.yui-dt-highlighted,
864 .yui-skin-sam th.yui-dt-highlighted,
865 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
865 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
866 .yui-skin-sam tr.yui-dt-highlighted,
866 .yui-skin-sam tr.yui-dt-highlighted,
867 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
867 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
868 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
868 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
869 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
869 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
870 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
870 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
871 cursor: pointer;
871 cursor: pointer;
872 background-color: #b2d2ff;
872 background-color: #b2d2ff;
873 }
873 }
874 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
874 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
875 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
875 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
876 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
876 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
877 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
877 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
878 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
878 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
879 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
879 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
880 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
880 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
881 cursor: pointer;
881 cursor: pointer;
882 background-color: #b2d2ff;
882 background-color: #b2d2ff;
883 }
883 }
884 .yui-skin-sam th.yui-dt-selected,
884 .yui-skin-sam th.yui-dt-selected,
885 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
885 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
886 .yui-skin-sam tr.yui-dt-selected td,
886 .yui-skin-sam tr.yui-dt-selected td,
887 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
887 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
888 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
888 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
889 background-color: #426fd9;
889 background-color: #426fd9;
890 color: #FFF;
890 color: #FFF;
891 }
891 }
892 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
892 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
893 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
893 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
894 background-color: #446cd7;
894 background-color: #446cd7;
895 color: #FFF;
895 color: #FFF;
896 }
896 }
897 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
897 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
898 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
898 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
899 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
899 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
900 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
900 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
901 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
901 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
902 background-color: #426fd9;
902 background-color: #426fd9;
903 color: #FFF;
903 color: #FFF;
904 }
904 }
905 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
905 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
906 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
906 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
907 background-color: #446cd7;
907 background-color: #446cd7;
908 color: #FFF;
908 color: #FFF;
909 }
909 }
910 .yui-skin-sam .yui-dt-paginator {
910 .yui-skin-sam .yui-dt-paginator {
911 display: block;
911 display: block;
912 margin: 6px 0;
912 margin: 6px 0;
913 white-space: nowrap;
913 white-space: nowrap;
914 }
914 }
915 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
915 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
916 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
916 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
917 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
917 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
918 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
918 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
919 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
919 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
920 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
920 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
921 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
921 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
922 .yui-skin-sam a.yui-dt-page {
922 .yui-skin-sam a.yui-dt-page {
923 border: 1px solid #cbcbcb;
923 border: 1px solid #cbcbcb;
924 padding: 2px 6px;
924 padding: 2px 6px;
925 text-decoration: none;
925 text-decoration: none;
926 background-color: #fff;
926 background-color: #fff;
927 }
927 }
928 .yui-skin-sam .yui-dt-selected {
928 .yui-skin-sam .yui-dt-selected {
929 border: 1px solid #fff;
929 border: 1px solid #fff;
930 background-color: #fff;
930 background-color: #fff;
931 }
931 }
932
932
933 #content #left {
933 #content #left {
934 left: 0;
934 left: 0;
935 width: 280px;
935 width: 280px;
936 position: absolute;
936 position: absolute;
937 }
937 }
938
938
939 #content #right {
939 #content #right {
940 margin: 0 60px 10px 290px;
940 margin: 0 60px 10px 290px;
941 }
941 }
942
942
943 #content div.box {
943 #content div.box {
944 clear: both;
944 clear: both;
945 background: #fff;
945 background: #fff;
946 margin: 0 0 10px;
946 margin: 0 0 10px;
947 padding: 0 0 10px;
947 padding: 0 0 10px;
948 -webkit-border-radius: 4px 4px 4px 4px;
948 -webkit-border-radius: 4px 4px 4px 4px;
949 -khtml-border-radius: 4px 4px 4px 4px;
949 -khtml-border-radius: 4px 4px 4px 4px;
950 border-radius: 4px 4px 4px 4px;
950 border-radius: 4px 4px 4px 4px;
951 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
951 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
952 }
952 }
953
953
954 #content div.box-left {
954 #content div.box-left {
955 width: 49%;
955 width: 49%;
956 clear: none;
956 clear: none;
957 float: left;
957 float: left;
958 margin: 0 0 10px;
958 margin: 0 0 10px;
959 }
959 }
960
960
961 #content div.box-right {
961 #content div.box-right {
962 width: 49%;
962 width: 49%;
963 clear: none;
963 clear: none;
964 float: right;
964 float: right;
965 margin: 0 0 10px;
965 margin: 0 0 10px;
966 }
966 }
967
967
968 #content div.box div.title {
968 #content div.box div.title {
969 clear: both;
969 clear: both;
970 overflow: hidden;
970 overflow: hidden;
971 background-color: #577632;
971 background-color: #577632;
972 background-repeat: repeat-x;
972 background-repeat: repeat-x;
973 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
973 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
974 background-image: -moz-linear-gradient(top, #577632, #577632);
974 background-image: -moz-linear-gradient(top, #577632, #577632);
975 background-image: -ms-linear-gradient(top, #577632, #577632);
975 background-image: -ms-linear-gradient(top, #577632, #577632);
976 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
976 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
977 background-image: -webkit-linear-gradient(top, #577632, #577632);
977 background-image: -webkit-linear-gradient(top, #577632, #577632);
978 background-image: -o-linear-gradient(top, #577632, #577632);
978 background-image: -o-linear-gradient(top, #577632, #577632);
979 background-image: linear-gradient(to bottom, #577632, #577632);
979 background-image: linear-gradient(to bottom, #577632, #577632);
980 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632', endColorstr='#577632', GradientType=0 );
980 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632', endColorstr='#577632', GradientType=0 );
981 margin: 0 0 20px;
981 margin: 0 0 20px;
982 padding: 0;
982 padding: 0;
983 border-radius: 4px 4px 0 0;
983 border-radius: 4px 4px 0 0;
984 }
984 }
985
985
986 #content div.box div.title h5 {
986 #content div.box div.title h5 {
987 float: left;
987 float: left;
988 border: none;
988 border: none;
989 color: #fff;
989 color: #fff;
990 margin: 0;
990 margin: 0;
991 padding: 11px 0 11px 10px;
991 padding: 11px 0 11px 10px;
992 }
992 }
993
993
994 #content div.box div.title .link-white {
994 #content div.box div.title .link-white {
995 color: #FFFFFF;
995 color: #FFFFFF;
996 }
996 }
997
997
998 #content div.box div.title .link-white.current {
998 #content div.box div.title .link-white.current {
999 color: #BFE3FF;
999 color: #BFE3FF;
1000 }
1000 }
1001
1001
1002 #content div.box div.title ul.links li {
1002 #content div.box div.title ul.links li {
1003 list-style: none;
1003 list-style: none;
1004 float: left;
1004 float: left;
1005 margin: 0;
1005 margin: 0;
1006 padding: 0;
1006 padding: 0;
1007 }
1007 }
1008
1008
1009 #content div.box div.title ul.links li a {
1009 #content div.box div.title ul.links li a {
1010 font-size: 13px;
1010 font-size: 13px;
1011 font-weight: 700;
1011 font-weight: 700;
1012 height: 1%;
1012 height: 1%;
1013 margin: 4px;
1013 margin: 4px;
1014 text-decoration: none;
1014 text-decoration: none;
1015 }
1015 }
1016
1016
1017 #content div.box h1, #content div.box h2, #content div.box h3, #content div.box h4, #content div.box h5, #content div.box h6,
1017 #content div.box h1, #content div.box h2, #content div.box h3, #content div.box h4, #content div.box h5, #content div.box h6,
1018 #content div.box div.h1, #content div.box div.h2, #content div.box div.h3, #content div.box div.h4, #content div.box div.h5, #content div.box div.h6 {
1018 #content div.box div.h1, #content div.box div.h2, #content div.box div.h3, #content div.box div.h4, #content div.box div.h5, #content div.box div.h6 {
1019 clear: both;
1019 clear: both;
1020 overflow: hidden;
1020 overflow: hidden;
1021 margin: 8px 20px 5px;
1021 margin: 8px 20px 5px;
1022 }
1022 }
1023
1023
1024 #content div.box p {
1024 #content div.box p {
1025 color: #5f5f5f;
1025 color: #5f5f5f;
1026 font-size: 12px;
1026 font-size: 12px;
1027 line-height: 150%;
1027 line-height: 150%;
1028 margin: 0 24px 10px;
1028 margin: 0 24px 10px;
1029 padding: 0;
1029 padding: 0;
1030 }
1030 }
1031
1031
1032 #content div.box blockquote {
1032 #content div.box blockquote {
1033 border-left: 4px solid #DDD;
1033 border-left: 4px solid #DDD;
1034 color: #5f5f5f;
1034 color: #5f5f5f;
1035 font-size: 11px;
1035 font-size: 11px;
1036 line-height: 150%;
1036 line-height: 150%;
1037 margin: 0 34px;
1037 margin: 0 34px;
1038 padding: 0 0 0 14px;
1038 padding: 0 0 0 14px;
1039 }
1039 }
1040
1040
1041 #content div.box blockquote p {
1041 #content div.box blockquote p {
1042 margin: 10px 0;
1042 margin: 10px 0;
1043 padding: 0;
1043 padding: 0;
1044 }
1044 }
1045
1045
1046 #content div.box dl {
1046 #content div.box dl {
1047 margin: 10px 0px;
1047 margin: 10px 0px;
1048 }
1048 }
1049
1049
1050 #content div.box dt {
1050 #content div.box dt {
1051 font-size: 12px;
1051 font-size: 12px;
1052 margin: 0;
1052 margin: 0;
1053 }
1053 }
1054
1054
1055 #content div.box dd {
1055 #content div.box dd {
1056 font-size: 12px;
1056 font-size: 12px;
1057 margin: 0;
1057 margin: 0;
1058 padding: 8px 0 8px 15px;
1058 padding: 8px 0 8px 15px;
1059 }
1059 }
1060
1060
1061 #content div.box li {
1061 #content div.box li {
1062 font-size: 12px;
1062 font-size: 12px;
1063 padding: 4px 0;
1063 padding: 4px 0;
1064 }
1064 }
1065
1065
1066 #content div.box ul.disc, #content div.box ul.circle {
1066 #content div.box ul.disc, #content div.box ul.circle {
1067 margin: 10px 24px 10px 38px;
1067 margin: 10px 24px 10px 38px;
1068 }
1068 }
1069
1069
1070 #content div.box ul.square {
1070 #content div.box ul.square {
1071 margin: 10px 24px 10px 40px;
1071 margin: 10px 24px 10px 40px;
1072 }
1072 }
1073
1073
1074 #content div.box img.left {
1074 #content div.box img.left {
1075 border: none;
1075 border: none;
1076 float: left;
1076 float: left;
1077 margin: 10px 10px 10px 0;
1077 margin: 10px 10px 10px 0;
1078 }
1078 }
1079
1079
1080 #content div.box img.right {
1080 #content div.box img.right {
1081 border: none;
1081 border: none;
1082 float: right;
1082 float: right;
1083 margin: 10px 0 10px 10px;
1083 margin: 10px 0 10px 10px;
1084 }
1084 }
1085
1085
1086 #content div.box div.messages {
1086 #content div.box div.messages {
1087 clear: both;
1087 clear: both;
1088 overflow: hidden;
1088 overflow: hidden;
1089 margin: 0 20px;
1089 margin: 0 20px;
1090 padding: 0;
1090 padding: 0;
1091 }
1091 }
1092
1092
1093 #content div.box div.message {
1093 #content div.box div.message {
1094 clear: both;
1094 clear: both;
1095 overflow: hidden;
1095 overflow: hidden;
1096 margin: 0;
1096 margin: 0;
1097 padding: 5px 0;
1097 padding: 5px 0;
1098 white-space: pre-wrap;
1098 white-space: pre-wrap;
1099 }
1099 }
1100 #content div.box div.expand {
1100 #content div.box div.expand {
1101 width: 110%;
1101 width: 110%;
1102 height: 14px;
1102 height: 14px;
1103 font-size: 10px;
1103 font-size: 10px;
1104 text-align: center;
1104 text-align: center;
1105 cursor: pointer;
1105 cursor: pointer;
1106 color: #666;
1106 color: #666;
1107
1107
1108 background: -webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1108 background: -webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1109 background: -webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1109 background: -webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1110 background: -moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1110 background: -moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1111 background: -o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1111 background: -o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1112 background: -ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1112 background: -ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1113 background: linear-gradient(to bottom,rgba(255,255,255,0),rgba(64,96,128,0.1));
1113 background: linear-gradient(to bottom,rgba(255,255,255,0),rgba(64,96,128,0.1));
1114
1114
1115 display: none;
1115 display: none;
1116 overflow: hidden;
1116 overflow: hidden;
1117 }
1117 }
1118 #content div.box div.expand .expandtext {
1118 #content div.box div.expand .expandtext {
1119 background-color: #ffffff;
1119 background-color: #ffffff;
1120 padding: 2px;
1120 padding: 2px;
1121 border-radius: 2px;
1121 border-radius: 2px;
1122 }
1122 }
1123
1123
1124 #content div.box div.message a {
1124 #content div.box div.message a {
1125 font-weight: 400 !important;
1125 font-weight: 400 !important;
1126 }
1126 }
1127
1127
1128 #content div.box div.message div.image {
1128 #content div.box div.message div.image {
1129 float: left;
1129 float: left;
1130 margin: 9px 0 0 5px;
1130 margin: 9px 0 0 5px;
1131 padding: 6px;
1131 padding: 6px;
1132 }
1132 }
1133
1133
1134 #content div.box div.message div.image img {
1134 #content div.box div.message div.image img {
1135 vertical-align: middle;
1135 vertical-align: middle;
1136 margin: 0;
1136 margin: 0;
1137 }
1137 }
1138
1138
1139 #content div.box div.message div.text {
1139 #content div.box div.message div.text {
1140 float: left;
1140 float: left;
1141 margin: 0;
1141 margin: 0;
1142 padding: 9px 6px;
1142 padding: 9px 6px;
1143 }
1143 }
1144
1144
1145 #content div.box div.message div.dismiss a {
1145 #content div.box div.message div.dismiss a {
1146 height: 16px;
1146 height: 16px;
1147 width: 16px;
1147 width: 16px;
1148 display: block;
1148 display: block;
1149 background: url("../images/icons/cross.png") no-repeat;
1149 background: url("../images/icons/cross.png") no-repeat;
1150 margin: 15px 14px 0 0;
1150 margin: 15px 14px 0 0;
1151 padding: 0;
1151 padding: 0;
1152 }
1152 }
1153
1153
1154 #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 {
1154 #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 {
1155 border: none;
1155 border: none;
1156 margin: 0;
1156 margin: 0;
1157 padding: 0;
1157 padding: 0;
1158 }
1158 }
1159
1159
1160 #content div.box div.message div.text span {
1160 #content div.box div.message div.text span {
1161 height: 1%;
1161 height: 1%;
1162 display: block;
1162 display: block;
1163 margin: 0;
1163 margin: 0;
1164 padding: 5px 0 0;
1164 padding: 5px 0 0;
1165 }
1165 }
1166
1166
1167 #content div.box div.message-error {
1167 #content div.box div.message-error {
1168 height: 1%;
1168 height: 1%;
1169 clear: both;
1169 clear: both;
1170 overflow: hidden;
1170 overflow: hidden;
1171 background: #FBE3E4;
1171 background: #FBE3E4;
1172 border: 1px solid #FBC2C4;
1172 border: 1px solid #FBC2C4;
1173 color: #860006;
1173 color: #860006;
1174 }
1174 }
1175
1175
1176 #content div.box div.message-error h6 {
1176 #content div.box div.message-error h6 {
1177 color: #860006;
1177 color: #860006;
1178 }
1178 }
1179
1179
1180 #content div.box div.message-warning {
1180 #content div.box div.message-warning {
1181 height: 1%;
1181 height: 1%;
1182 clear: both;
1182 clear: both;
1183 overflow: hidden;
1183 overflow: hidden;
1184 background: #FFF6BF;
1184 background: #FFF6BF;
1185 border: 1px solid #FFD324;
1185 border: 1px solid #FFD324;
1186 color: #5f5200;
1186 color: #5f5200;
1187 }
1187 }
1188
1188
1189 #content div.box div.message-warning h6 {
1189 #content div.box div.message-warning h6 {
1190 color: #5f5200;
1190 color: #5f5200;
1191 }
1191 }
1192
1192
1193 #content div.box div.message-notice {
1193 #content div.box div.message-notice {
1194 height: 1%;
1194 height: 1%;
1195 clear: both;
1195 clear: both;
1196 overflow: hidden;
1196 overflow: hidden;
1197 background: #8FBDE0;
1197 background: #8FBDE0;
1198 border: 1px solid #6BACDE;
1198 border: 1px solid #6BACDE;
1199 color: #003863;
1199 color: #003863;
1200 }
1200 }
1201
1201
1202 #content div.box div.message-notice h6 {
1202 #content div.box div.message-notice h6 {
1203 color: #003863;
1203 color: #003863;
1204 }
1204 }
1205
1205
1206 #content div.box div.message-success {
1206 #content div.box div.message-success {
1207 height: 1%;
1207 height: 1%;
1208 clear: both;
1208 clear: both;
1209 overflow: hidden;
1209 overflow: hidden;
1210 background: #E6EFC2;
1210 background: #E6EFC2;
1211 border: 1px solid #C6D880;
1211 border: 1px solid #C6D880;
1212 color: #4e6100;
1212 color: #4e6100;
1213 }
1213 }
1214
1214
1215 #content div.box div.message-success h6 {
1215 #content div.box div.message-success h6 {
1216 color: #4e6100;
1216 color: #4e6100;
1217 }
1217 }
1218
1218
1219 #content div.box div.form div.fields div.field {
1219 #content div.box div.form div.fields div.field {
1220 height: 1%;
1220 height: 1%;
1221 min-height: 12px;
1221 min-height: 12px;
1222 border-bottom: 1px solid #DDD;
1222 border-bottom: 1px solid #DDD;
1223 clear: both;
1223 clear: both;
1224 margin: 0;
1224 margin: 0;
1225 padding: 10px 0;
1225 padding: 10px 0;
1226 }
1226 }
1227
1227
1228 #content div.box div.form div.fields div.field-first {
1228 #content div.box div.form div.fields div.field-first {
1229 padding: 0 0 10px;
1229 padding: 0 0 10px;
1230 }
1230 }
1231
1231
1232 #content div.box div.form div.fields div.field-noborder {
1232 #content div.box div.form div.fields div.field-noborder {
1233 border-bottom: 0 !important;
1233 border-bottom: 0 !important;
1234 }
1234 }
1235
1235
1236 #content div.box div.form div.fields div.field span.error-message {
1236 #content div.box div.form div.fields div.field span.error-message {
1237 height: 1%;
1237 height: 1%;
1238 display: inline-block;
1238 display: inline-block;
1239 color: red;
1239 color: red;
1240 margin: 8px 0 0 4px;
1240 margin: 8px 0 0 4px;
1241 padding: 0;
1241 padding: 0;
1242 }
1242 }
1243
1243
1244 #content div.box div.form div.fields div.field span.success {
1244 #content div.box div.form div.fields div.field span.success {
1245 height: 1%;
1245 height: 1%;
1246 display: block;
1246 display: block;
1247 color: #316309;
1247 color: #316309;
1248 margin: 8px 0 0;
1248 margin: 8px 0 0;
1249 padding: 0;
1249 padding: 0;
1250 }
1250 }
1251
1251
1252 #content div.box div.form div.fields div.field div.label {
1252 #content div.box div.form div.fields div.field div.label {
1253 left: 70px;
1253 left: 70px;
1254 width: 155px;
1254 width: 155px;
1255 position: absolute;
1255 position: absolute;
1256 margin: 0;
1256 margin: 0;
1257 padding: 5px 0 0 0px;
1257 padding: 5px 0 0 0px;
1258 }
1258 }
1259
1259
1260 #content div.box div.form div.fields div.field div.label-summary {
1260 #content div.box div.form div.fields div.field div.label-summary {
1261 left: 30px;
1261 left: 30px;
1262 width: 155px;
1262 width: 155px;
1263 position: absolute;
1263 position: absolute;
1264 margin: 0;
1264 margin: 0;
1265 padding: 0px 0 0 0px;
1265 padding: 0px 0 0 0px;
1266 }
1266 }
1267
1267
1268 #content div.box-left div.form div.fields div.field div.label,
1268 #content div.box-left div.form div.fields div.field div.label,
1269 #content div.box-right div.form div.fields div.field div.label,
1269 #content div.box-right div.form div.fields div.field div.label,
1270 #content div.box-left div.form div.fields div.field div.label,
1270 #content div.box-left div.form div.fields div.field div.label,
1271 #content div.box-left div.form div.fields div.field div.label-summary,
1271 #content div.box-left div.form div.fields div.field div.label-summary,
1272 #content div.box-right div.form div.fields div.field div.label-summary,
1272 #content div.box-right div.form div.fields div.field div.label-summary,
1273 #content div.box-left div.form div.fields div.field div.label-summary {
1273 #content div.box-left div.form div.fields div.field div.label-summary {
1274 clear: both;
1274 clear: both;
1275 overflow: hidden;
1275 overflow: hidden;
1276 left: 0;
1276 left: 0;
1277 width: auto;
1277 width: auto;
1278 position: relative;
1278 position: relative;
1279 margin: 0;
1279 margin: 0;
1280 padding: 0 0 8px;
1280 padding: 0 0 8px;
1281 }
1281 }
1282
1282
1283 #content div.box div.form div.fields div.field div.label-select {
1283 #content div.box div.form div.fields div.field div.label-select {
1284 padding: 5px 0 0 5px;
1284 padding: 5px 0 0 5px;
1285 }
1285 }
1286
1286
1287 #content div.box-left div.form div.fields div.field div.label-select,
1287 #content div.box-left div.form div.fields div.field div.label-select,
1288 #content div.box-right div.form div.fields div.field div.label-select {
1288 #content div.box-right div.form div.fields div.field div.label-select {
1289 padding: 0 0 8px;
1289 padding: 0 0 8px;
1290 }
1290 }
1291
1291
1292 #content div.box-left div.form div.fields div.field div.label-textarea,
1292 #content div.box-left div.form div.fields div.field div.label-textarea,
1293 #content div.box-right div.form div.fields div.field div.label-textarea {
1293 #content div.box-right div.form div.fields div.field div.label-textarea {
1294 padding: 0 0 8px !important;
1294 padding: 0 0 8px !important;
1295 }
1295 }
1296
1296
1297 #content div.box div.form div.fields div.field div.label label, div.label label {
1297 #content div.box div.form div.fields div.field div.label label, div.label label {
1298 color: #393939;
1298 color: #393939;
1299 font-weight: 700;
1299 font-weight: 700;
1300 }
1300 }
1301 #content div.box div.form div.fields div.field div.label label, div.label-summary label {
1301 #content div.box div.form div.fields div.field div.label label, div.label-summary label {
1302 color: #393939;
1302 color: #393939;
1303 font-weight: 700;
1303 font-weight: 700;
1304 }
1304 }
1305 #content div.box div.form div.fields div.field div.input {
1305 #content div.box div.form div.fields div.field div.input {
1306 margin: 0 0 0 200px;
1306 margin: 0 0 0 200px;
1307 }
1307 }
1308
1308
1309 #content div.box div.form div.fields div.field div.input.summary {
1309 #content div.box div.form div.fields div.field div.input.summary {
1310 margin: 0 0 0 110px;
1310 margin: 0 0 0 110px;
1311 }
1311 }
1312 #content div.box div.form div.fields div.field div.input.summary-short {
1312 #content div.box div.form div.fields div.field div.input.summary-short {
1313 margin: 0 0 0 110px;
1313 margin: 0 0 0 110px;
1314 }
1314 }
1315 #content div.box div.form div.fields div.field div.file {
1315 #content div.box div.form div.fields div.field div.file {
1316 margin: 0 0 0 200px;
1316 margin: 0 0 0 200px;
1317 }
1317 }
1318 #content div.box div.form div.fields div.field div.editor {
1318 #content div.box div.form div.fields div.field div.editor {
1319 margin: 0 0 0 200px;
1319 margin: 0 0 0 200px;
1320 }
1320 }
1321
1321
1322 #content div.box-left div.form div.fields div.field div.input, #content div.box-right div.form div.fields div.field div.input {
1322 #content div.box-left div.form div.fields div.field div.input, #content div.box-right div.form div.fields div.field div.input {
1323 margin: 0 0 0 0px;
1323 margin: 0 0 0 0px;
1324 }
1324 }
1325
1325
1326 #content div.box div.form div.fields div.field div.input input,
1326 #content div.box div.form div.fields div.field div.input input,
1327 .reviewer_ac input {
1327 .reviewer_ac input {
1328 background: #FFF;
1328 background: #FFF;
1329 border-top: 1px solid #b3b3b3;
1329 border-top: 1px solid #b3b3b3;
1330 border-left: 1px solid #b3b3b3;
1330 border-left: 1px solid #b3b3b3;
1331 border-right: 1px solid #eaeaea;
1331 border-right: 1px solid #eaeaea;
1332 border-bottom: 1px solid #eaeaea;
1332 border-bottom: 1px solid #eaeaea;
1333 color: #000;
1333 color: #000;
1334 font-size: 12px;
1334 font-size: 12px;
1335 margin: 0;
1335 margin: 0;
1336 padding: 7px 7px 6px;
1336 padding: 7px 7px 6px;
1337 }
1337 }
1338
1338
1339 #content div.box div.form div.fields div.field div.input input#clone_url,
1339 #content div.box div.form div.fields div.field div.input input#clone_url,
1340 #content div.box div.form div.fields div.field div.input input#clone_url_id
1340 #content div.box div.form div.fields div.field div.input input#clone_url_id
1341 {
1341 {
1342 font-size: 16px;
1342 font-size: 16px;
1343 padding: 2px;
1343 padding: 2px;
1344 }
1344 }
1345
1345
1346 #content div.box div.form div.fields div.field div.file input {
1346 #content div.box div.form div.fields div.field div.file input {
1347 background: none repeat scroll 0 0 #FFFFFF;
1347 background: none repeat scroll 0 0 #FFFFFF;
1348 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1348 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1349 border-style: solid;
1349 border-style: solid;
1350 border-width: 1px;
1350 border-width: 1px;
1351 color: #000000;
1351 color: #000000;
1352 font-size: 12px;
1352 font-size: 12px;
1353 margin: 0;
1353 margin: 0;
1354 padding: 7px 7px 6px;
1354 padding: 7px 7px 6px;
1355 }
1355 }
1356
1356
1357 input.disabled {
1357 input.disabled {
1358 background-color: #F5F5F5 !important;
1358 background-color: #F5F5F5 !important;
1359 }
1359 }
1360 #content div.box div.form div.fields div.field div.input input.small {
1360 #content div.box div.form div.fields div.field div.input input.small {
1361 width: 30%;
1361 width: 30%;
1362 }
1362 }
1363
1363
1364 #content div.box div.form div.fields div.field div.input input.medium {
1364 #content div.box div.form div.fields div.field div.input input.medium {
1365 width: 55%;
1365 width: 55%;
1366 }
1366 }
1367
1367
1368 #content div.box div.form div.fields div.field div.input input.large {
1368 #content div.box div.form div.fields div.field div.input input.large {
1369 width: 85%;
1369 width: 85%;
1370 }
1370 }
1371
1371
1372 #content div.box div.form div.fields div.field div.input input.date {
1372 #content div.box div.form div.fields div.field div.input input.date {
1373 width: 177px;
1373 width: 177px;
1374 }
1374 }
1375
1375
1376 #content div.box div.form div.fields div.field div.input input.button {
1376 #content div.box div.form div.fields div.field div.input input.button {
1377 background: #D4D0C8;
1377 background: #D4D0C8;
1378 border-top: 1px solid #FFF;
1378 border-top: 1px solid #FFF;
1379 border-left: 1px solid #FFF;
1379 border-left: 1px solid #FFF;
1380 border-right: 1px solid #404040;
1380 border-right: 1px solid #404040;
1381 border-bottom: 1px solid #404040;
1381 border-bottom: 1px solid #404040;
1382 color: #000;
1382 color: #000;
1383 margin: 0;
1383 margin: 0;
1384 padding: 4px 8px;
1384 padding: 4px 8px;
1385 }
1385 }
1386
1386
1387 #content div.box div.form div.fields div.field div.textarea {
1387 #content div.box div.form div.fields div.field div.textarea {
1388 border-top: 1px solid #b3b3b3;
1388 border-top: 1px solid #b3b3b3;
1389 border-left: 1px solid #b3b3b3;
1389 border-left: 1px solid #b3b3b3;
1390 border-right: 1px solid #eaeaea;
1390 border-right: 1px solid #eaeaea;
1391 border-bottom: 1px solid #eaeaea;
1391 border-bottom: 1px solid #eaeaea;
1392 margin: 0 0 0 200px;
1392 margin: 0 0 0 200px;
1393 padding: 7px 7px 6px;
1393 padding: 7px 7px 6px;
1394 }
1394 }
1395
1395
1396 #content div.box div.form div.fields div.field div.textarea-editor {
1396 #content div.box div.form div.fields div.field div.textarea-editor {
1397 border: 1px solid #ddd;
1397 border: 1px solid #ddd;
1398 padding: 0;
1398 padding: 0;
1399 }
1399 }
1400
1400
1401 #content div.box div.form div.fields div.field div.textarea textarea {
1401 #content div.box div.form div.fields div.field div.textarea textarea {
1402 width: 100%;
1402 width: 100%;
1403 height: 220px;
1403 height: 220px;
1404 overflow-y: auto;
1404 overflow-y: auto;
1405 background: #FFF;
1405 background: #FFF;
1406 color: #000;
1406 color: #000;
1407 font-size: 12px;
1407 font-size: 12px;
1408 outline: none;
1408 outline: none;
1409 border-width: 0;
1409 border-width: 0;
1410 margin: 0;
1410 margin: 0;
1411 padding: 0;
1411 padding: 0;
1412 }
1412 }
1413
1413
1414 #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 {
1414 #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 {
1415 width: 100%;
1415 width: 100%;
1416 height: 100px;
1416 height: 100px;
1417 }
1417 }
1418
1418
1419 #content div.box div.form div.fields div.field div.textarea table {
1419 #content div.box div.form div.fields div.field div.textarea table {
1420 width: 100%;
1420 width: 100%;
1421 border: none;
1421 border: none;
1422 margin: 0;
1422 margin: 0;
1423 padding: 0;
1423 padding: 0;
1424 }
1424 }
1425
1425
1426 #content div.box div.form div.fields div.field div.textarea table td {
1426 #content div.box div.form div.fields div.field div.textarea table td {
1427 background: #DDD;
1427 background: #DDD;
1428 border: none;
1428 border: none;
1429 padding: 0;
1429 padding: 0;
1430 }
1430 }
1431
1431
1432 #content div.box div.form div.fields div.field div.textarea table td table {
1432 #content div.box div.form div.fields div.field div.textarea table td table {
1433 width: auto;
1433 width: auto;
1434 border: none;
1434 border: none;
1435 margin: 0;
1435 margin: 0;
1436 padding: 0;
1436 padding: 0;
1437 }
1437 }
1438
1438
1439 #content div.box div.form div.fields div.field div.textarea table td table td {
1439 #content div.box div.form div.fields div.field div.textarea table td table td {
1440 font-size: 11px;
1440 font-size: 11px;
1441 padding: 5px 5px 5px 0;
1441 padding: 5px 5px 5px 0;
1442 }
1442 }
1443
1443
1444 #content div.box div.form div.fields div.field input[type=text]:focus,
1444 #content div.box div.form div.fields div.field input[type=text]:focus,
1445 #content div.box div.form div.fields div.field input[type=password]:focus,
1445 #content div.box div.form div.fields div.field input[type=password]:focus,
1446 #content div.box div.form div.fields div.field input[type=file]:focus,
1446 #content div.box div.form div.fields div.field input[type=file]:focus,
1447 #content div.box div.form div.fields div.field textarea:focus,
1447 #content div.box div.form div.fields div.field textarea:focus,
1448 #content div.box div.form div.fields div.field select:focus,
1448 #content div.box div.form div.fields div.field select:focus,
1449 .reviewer_ac input:focus {
1449 .reviewer_ac input:focus {
1450 background: #f6f6f6;
1450 background: #f6f6f6;
1451 border-color: #666;
1451 border-color: #666;
1452 }
1452 }
1453
1453
1454 .reviewer_ac {
1454 .reviewer_ac {
1455 padding: 10px
1455 padding: 10px
1456 }
1456 }
1457
1457
1458 div.form div.fields div.field div.button {
1458 div.form div.fields div.field div.button {
1459 margin: 0;
1459 margin: 0;
1460 padding: 0 0 0 8px;
1460 padding: 0 0 0 8px;
1461 }
1461 }
1462 #content div.box table.noborder {
1462 #content div.box table.noborder {
1463 border: 1px solid transparent;
1463 border: 1px solid transparent;
1464 }
1464 }
1465
1465
1466 #content div.box table {
1466 #content div.box table {
1467 width: 100%;
1467 width: 100%;
1468 border-collapse: separate;
1468 border-collapse: separate;
1469 margin: 0;
1469 margin: 0;
1470 padding: 0;
1470 padding: 0;
1471 border: 1px solid #eee;
1471 border: 1px solid #eee;
1472 -webkit-border-radius: 4px;
1472 -webkit-border-radius: 4px;
1473 border-radius: 4px;
1473 border-radius: 4px;
1474 }
1474 }
1475
1475
1476 #content div.box table th {
1476 #content div.box table th {
1477 background: #eee;
1477 background: #eee;
1478 border-bottom: 1px solid #ddd;
1478 border-bottom: 1px solid #ddd;
1479 padding: 5px 0px 5px 5px;
1479 padding: 5px 0px 5px 5px;
1480 text-align: left;
1480 text-align: left;
1481 }
1481 }
1482
1482
1483 #content div.box table th.left {
1483 #content div.box table th.left {
1484 text-align: left;
1484 text-align: left;
1485 }
1485 }
1486
1486
1487 #content div.box table th.right {
1487 #content div.box table th.right {
1488 text-align: right;
1488 text-align: right;
1489 }
1489 }
1490
1490
1491 #content div.box table th.center {
1491 #content div.box table th.center {
1492 text-align: center;
1492 text-align: center;
1493 }
1493 }
1494
1494
1495 #content div.box table th.selected {
1495 #content div.box table th.selected {
1496 vertical-align: middle;
1496 vertical-align: middle;
1497 padding: 0;
1497 padding: 0;
1498 }
1498 }
1499
1499
1500 #content div.box table td {
1500 #content div.box table td {
1501 background: #fff;
1501 background: #fff;
1502 border-bottom: 1px solid #cdcdcd;
1502 border-bottom: 1px solid #cdcdcd;
1503 vertical-align: middle;
1503 vertical-align: middle;
1504 padding: 5px;
1504 padding: 5px;
1505 }
1505 }
1506
1506
1507 #content div.box table tr.selected td {
1507 #content div.box table tr.selected td {
1508 background: #FFC;
1508 background: #FFC;
1509 }
1509 }
1510
1510
1511 #content div.box table td.selected {
1511 #content div.box table td.selected {
1512 width: 3%;
1512 width: 3%;
1513 text-align: center;
1513 text-align: center;
1514 vertical-align: middle;
1514 vertical-align: middle;
1515 padding: 0;
1515 padding: 0;
1516 }
1516 }
1517
1517
1518 #content div.box table td.action {
1518 #content div.box table td.action {
1519 width: 45%;
1519 width: 45%;
1520 text-align: left;
1520 text-align: left;
1521 }
1521 }
1522
1522
1523 #content div.box table td.date {
1523 #content div.box table td.date {
1524 width: 33%;
1524 width: 33%;
1525 text-align: center;
1525 text-align: center;
1526 }
1526 }
1527
1527
1528 #content div.box div.action {
1528 #content div.box div.action {
1529 float: right;
1529 float: right;
1530 background: #FFF;
1530 background: #FFF;
1531 text-align: right;
1531 text-align: right;
1532 margin: 10px 0 0;
1532 margin: 10px 0 0;
1533 padding: 0;
1533 padding: 0;
1534 }
1534 }
1535
1535
1536 #content div.box div.action select {
1536 #content div.box div.action select {
1537 font-size: 11px;
1537 font-size: 11px;
1538 margin: 0;
1538 margin: 0;
1539 }
1539 }
1540
1540
1541 #content div.box div.action .ui-selectmenu {
1541 #content div.box div.action .ui-selectmenu {
1542 margin: 0;
1542 margin: 0;
1543 padding: 0;
1543 padding: 0;
1544 }
1544 }
1545
1545
1546 #content div.box div.pagination {
1546 #content div.box div.pagination {
1547 height: 1%;
1547 height: 1%;
1548 clear: both;
1548 clear: both;
1549 overflow: hidden;
1549 overflow: hidden;
1550 margin: 10px 0 0;
1550 margin: 10px 0 0;
1551 padding: 0;
1551 padding: 0;
1552 }
1552 }
1553
1553
1554 #content div.box div.pagination ul.pager {
1554 #content div.box div.pagination ul.pager {
1555 float: right;
1555 float: right;
1556 text-align: right;
1556 text-align: right;
1557 margin: 0;
1557 margin: 0;
1558 padding: 0;
1558 padding: 0;
1559 }
1559 }
1560
1560
1561 #content div.box div.pagination ul.pager li {
1561 #content div.box div.pagination ul.pager li {
1562 height: 1%;
1562 height: 1%;
1563 float: left;
1563 float: left;
1564 list-style: none;
1564 list-style: none;
1565 background: #ebebeb url("../images/pager.png") repeat-x;
1565 background: #ebebeb url("../images/pager.png") repeat-x;
1566 border-top: 1px solid #dedede;
1566 border-top: 1px solid #dedede;
1567 border-left: 1px solid #cfcfcf;
1567 border-left: 1px solid #cfcfcf;
1568 border-right: 1px solid #c4c4c4;
1568 border-right: 1px solid #c4c4c4;
1569 border-bottom: 1px solid #c4c4c4;
1569 border-bottom: 1px solid #c4c4c4;
1570 color: #4A4A4A;
1570 color: #4A4A4A;
1571 font-weight: 700;
1571 font-weight: 700;
1572 margin: 0 0 0 4px;
1572 margin: 0 0 0 4px;
1573 padding: 0;
1573 padding: 0;
1574 }
1574 }
1575
1575
1576 #content div.box div.pagination ul.pager li.separator {
1576 #content div.box div.pagination ul.pager li.separator {
1577 padding: 6px;
1577 padding: 6px;
1578 }
1578 }
1579
1579
1580 #content div.box div.pagination ul.pager li.current {
1580 #content div.box div.pagination ul.pager li.current {
1581 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1581 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1582 border-top: 1px solid #ccc;
1582 border-top: 1px solid #ccc;
1583 border-left: 1px solid #bebebe;
1583 border-left: 1px solid #bebebe;
1584 border-right: 1px solid #b1b1b1;
1584 border-right: 1px solid #b1b1b1;
1585 border-bottom: 1px solid #afafaf;
1585 border-bottom: 1px solid #afafaf;
1586 color: #515151;
1586 color: #515151;
1587 padding: 6px;
1587 padding: 6px;
1588 }
1588 }
1589
1589
1590 #content div.box div.pagination ul.pager li a {
1590 #content div.box div.pagination ul.pager li a {
1591 height: 1%;
1591 height: 1%;
1592 display: block;
1592 display: block;
1593 float: left;
1593 float: left;
1594 color: #515151;
1594 color: #515151;
1595 text-decoration: none;
1595 text-decoration: none;
1596 margin: 0;
1596 margin: 0;
1597 padding: 6px;
1597 padding: 6px;
1598 }
1598 }
1599
1599
1600 #content div.box div.pagination ul.pager li a:hover,
1600 #content div.box div.pagination ul.pager li a:hover,
1601 #content div.box div.pagination ul.pager li a:active {
1601 #content div.box div.pagination ul.pager li a:active {
1602 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1602 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1603 border-top: 1px solid #ccc;
1603 border-top: 1px solid #ccc;
1604 border-left: 1px solid #bebebe;
1604 border-left: 1px solid #bebebe;
1605 border-right: 1px solid #b1b1b1;
1605 border-right: 1px solid #b1b1b1;
1606 border-bottom: 1px solid #afafaf;
1606 border-bottom: 1px solid #afafaf;
1607 margin: -1px;
1607 margin: -1px;
1608 }
1608 }
1609
1609
1610 #content div.box div.pagination-right {
1610 #content div.box div.pagination-right {
1611 float: right;
1611 float: right;
1612 }
1612 }
1613
1613
1614 #content div.box div.pagination-wh {
1614 #content div.box div.pagination-wh {
1615 height: 1%;
1615 height: 1%;
1616 overflow: hidden;
1616 overflow: hidden;
1617 text-align: right;
1617 text-align: right;
1618 margin: 10px 0 0;
1618 margin: 10px 0 0;
1619 padding: 0;
1619 padding: 0;
1620 }
1620 }
1621
1621
1622 #content div.box div.pagination-wh > :first-child {
1622 #content div.box div.pagination-wh > :first-child {
1623 border-radius: 4px 0px 0px 4px;
1623 border-radius: 4px 0px 0px 4px;
1624 }
1624 }
1625
1625
1626 #content div.box div.pagination-wh > :last-child {
1626 #content div.box div.pagination-wh > :last-child {
1627 border-radius: 0px 4px 4px 0px;
1627 border-radius: 0px 4px 4px 0px;
1628 border-right: 1px solid #cfcfcf;
1628 border-right: 1px solid #cfcfcf;
1629 }
1629 }
1630
1630
1631 #content div.box div.pagination-wh a,
1631 #content div.box div.pagination-wh a,
1632 #content div.box div.pagination-wh span.pager_dotdot,
1632 #content div.box div.pagination-wh span.pager_dotdot,
1633 #content div.box div.pagination-wh span.yui-pg-previous,
1633 #content div.box div.pagination-wh span.yui-pg-previous,
1634 #content div.box div.pagination-wh span.yui-pg-last,
1634 #content div.box div.pagination-wh span.yui-pg-last,
1635 #content div.box div.pagination-wh span.yui-pg-next,
1635 #content div.box div.pagination-wh span.yui-pg-next,
1636 #content div.box div.pagination-wh span.yui-pg-first {
1636 #content div.box div.pagination-wh span.yui-pg-first {
1637 height: 1%;
1637 height: 1%;
1638 float: left;
1638 float: left;
1639 background: #ebebeb url("../images/pager.png") repeat-x;
1639 background: #ebebeb url("../images/pager.png") repeat-x;
1640 border-top: 1px solid #dedede;
1640 border-top: 1px solid #dedede;
1641 border-left: 1px solid #cfcfcf;
1641 border-left: 1px solid #cfcfcf;
1642 border-bottom: 1px solid #c4c4c4;
1642 border-bottom: 1px solid #c4c4c4;
1643 color: #4A4A4A;
1643 color: #4A4A4A;
1644 font-weight: 700;
1644 font-weight: 700;
1645 padding: 6px;
1645 padding: 6px;
1646 }
1646 }
1647
1647
1648 #content div.box div.pagination-wh span.pager_curpage {
1648 #content div.box div.pagination-wh span.pager_curpage {
1649 height: 1%;
1649 height: 1%;
1650 float: left;
1650 float: left;
1651 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1651 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1652 border-top: 1px solid #ccc;
1652 border-top: 1px solid #ccc;
1653 border-left: 1px solid #bebebe;
1653 border-left: 1px solid #bebebe;
1654 border-bottom: 1px solid #afafaf;
1654 border-bottom: 1px solid #afafaf;
1655 color: #515151;
1655 color: #515151;
1656 font-weight: 700;
1656 font-weight: 700;
1657 padding: 6px;
1657 padding: 6px;
1658 }
1658 }
1659
1659
1660 #content div.box div.pagination-wh a:hover, #content div.box div.pagination-wh a:active {
1660 #content div.box div.pagination-wh a:hover, #content div.box div.pagination-wh a:active {
1661 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1661 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1662 border-top: 1px solid #ccc;
1662 border-top: 1px solid #ccc;
1663 border-left: 1px solid #bebebe;
1663 border-left: 1px solid #bebebe;
1664 border-bottom: 1px solid #afafaf;
1664 border-bottom: 1px solid #afafaf;
1665 text-decoration: none;
1665 text-decoration: none;
1666 }
1666 }
1667
1667
1668 #content div.box div.traffic div.legend {
1668 #content div.box div.traffic div.legend {
1669 clear: both;
1669 clear: both;
1670 overflow: hidden;
1670 overflow: hidden;
1671 border-bottom: 1px solid #ddd;
1671 border-bottom: 1px solid #ddd;
1672 margin: 0 0 10px;
1672 margin: 0 0 10px;
1673 padding: 0 0 10px;
1673 padding: 0 0 10px;
1674 }
1674 }
1675
1675
1676 #content div.box div.traffic div.legend h6 {
1676 #content div.box div.traffic div.legend h6 {
1677 float: left;
1677 float: left;
1678 border: none;
1678 border: none;
1679 margin: 0;
1679 margin: 0;
1680 padding: 0;
1680 padding: 0;
1681 }
1681 }
1682
1682
1683 #content div.box div.traffic div.legend li {
1683 #content div.box div.traffic div.legend li {
1684 list-style: none;
1684 list-style: none;
1685 float: left;
1685 float: left;
1686 font-size: 11px;
1686 font-size: 11px;
1687 margin: 0;
1687 margin: 0;
1688 padding: 0 8px 0 4px;
1688 padding: 0 8px 0 4px;
1689 }
1689 }
1690
1690
1691 #content div.box div.traffic div.legend li.visits {
1691 #content div.box div.traffic div.legend li.visits {
1692 border-left: 12px solid #edc240;
1692 border-left: 12px solid #edc240;
1693 }
1693 }
1694
1694
1695 #content div.box div.traffic div.legend li.pageviews {
1695 #content div.box div.traffic div.legend li.pageviews {
1696 border-left: 12px solid #afd8f8;
1696 border-left: 12px solid #afd8f8;
1697 }
1697 }
1698
1698
1699 #content div.box div.traffic table {
1699 #content div.box div.traffic table {
1700 width: auto;
1700 width: auto;
1701 }
1701 }
1702
1702
1703 #content div.box div.traffic table td {
1703 #content div.box div.traffic table td {
1704 background: transparent;
1704 background: transparent;
1705 border: none;
1705 border: none;
1706 padding: 2px 3px 3px;
1706 padding: 2px 3px 3px;
1707 }
1707 }
1708
1708
1709 #content div.box div.traffic table td.legendLabel {
1709 #content div.box div.traffic table td.legendLabel {
1710 padding: 0 3px 2px;
1710 padding: 0 3px 2px;
1711 }
1711 }
1712
1712
1713 #content div.box #summary {
1713 #content div.box #summary {
1714 margin-right: 200px;
1714 margin-right: 200px;
1715 min-height: 240px;
1715 min-height: 240px;
1716 }
1716 }
1717
1717
1718 #summary-menu-stats {
1718 #summary-menu-stats {
1719 float: left;
1719 float: left;
1720 width: 180px;
1720 width: 180px;
1721 position: absolute;
1721 position: absolute;
1722 top: 0;
1722 top: 0;
1723 right: 0;
1723 right: 0;
1724 }
1724 }
1725
1725
1726 #summary-menu-stats ul {
1726 #summary-menu-stats ul {
1727 margin: 0 10px;
1727 margin: 0 10px;
1728 display: block;
1728 display: block;
1729 background-color: #f9f9f9;
1729 background-color: #f9f9f9;
1730 border: 1px solid #d1d1d1;
1730 border: 1px solid #d1d1d1;
1731 border-radius: 4px;
1731 border-radius: 4px;
1732 }
1732 }
1733
1733
1734 #content #summary-menu-stats li {
1734 #content #summary-menu-stats li {
1735 border-top: 1px solid #d1d1d1;
1735 border-top: 1px solid #d1d1d1;
1736 padding: 0;
1736 padding: 0;
1737 }
1737 }
1738
1738
1739 #content #summary-menu-stats li:hover {
1739 #content #summary-menu-stats li:hover {
1740 background: #f0f0f0;
1740 background: #f0f0f0;
1741 }
1741 }
1742
1742
1743 #content #summary-menu-stats li:first-child {
1743 #content #summary-menu-stats li:first-child {
1744 border-top: none;
1744 border-top: none;
1745 }
1745 }
1746
1746
1747 #summary-menu-stats a.followers { background-image: url('../images/icons/heart.png')}
1747 #summary-menu-stats a.followers { background-image: url('../images/icons/heart.png')}
1748 #summary-menu-stats a.forks { background-image: url('../images/icons/arrow_divide.png')}
1748 #summary-menu-stats a.forks { background-image: url('../images/icons/arrow_divide.png')}
1749 #summary-menu-stats a.settings { background-image: url('../images/icons/cog_edit.png')}
1749 #summary-menu-stats a.settings { background-image: url('../images/icons/cog_edit.png')}
1750 #summary-menu-stats a.feed { background-image: url('../images/icons/rss_16.png')}
1750 #summary-menu-stats a.feed { background-image: url('../images/icons/rss_16.png')}
1751 #summary-menu-stats a.repo-size { background-image: url('../images/icons/server.png')}
1751 #summary-menu-stats a.repo-size { background-image: url('../images/icons/server.png')}
1752
1752
1753 #summary-menu-stats a {
1753 #summary-menu-stats a {
1754 display: block;
1754 display: block;
1755 padding: 12px 10px;
1755 padding: 12px 10px;
1756 background-repeat: no-repeat;
1756 background-repeat: no-repeat;
1757 background-position: 10px 50%;
1757 background-position: 10px 50%;
1758 padding-right: 10px;
1758 padding-right: 10px;
1759 }
1759 }
1760
1760
1761 #repo_size_2.loaded {
1761 #repo_size_2.loaded {
1762 margin-left: 30px;
1762 margin-left: 30px;
1763 display: block;
1763 display: block;
1764 padding-right: 10px;
1764 padding-right: 10px;
1765 padding-bottom: 7px;
1765 padding-bottom: 7px;
1766 }
1766 }
1767
1767
1768 #summary-menu-stats a:hover {
1768 #summary-menu-stats a:hover {
1769 text-decoration: none;
1769 text-decoration: none;
1770 }
1770 }
1771
1771
1772 #summary-menu-stats a span {
1772 #summary-menu-stats a span {
1773 background-color: #DEDEDE;
1773 background-color: #DEDEDE;
1774 color: #888 !important;
1774 color: #888 !important;
1775 border-radius: 4px;
1775 border-radius: 4px;
1776 padding: 2px 4px;
1776 padding: 2px 4px;
1777 font-size: 10px;
1777 font-size: 10px;
1778 }
1778 }
1779
1779
1780 #summary .metatag {
1780 #summary .metatag {
1781 display: inline-block;
1781 display: inline-block;
1782 padding: 3px 5px;
1782 padding: 3px 5px;
1783 margin-bottom: 3px;
1783 margin-bottom: 3px;
1784 margin-right: 1px;
1784 margin-right: 1px;
1785 border-radius: 5px;
1785 border-radius: 5px;
1786 }
1786 }
1787
1787
1788 #content div.box #summary p {
1788 #content div.box #summary p {
1789 margin-bottom: -5px;
1789 margin-bottom: -5px;
1790 width: 600px;
1790 width: 600px;
1791 white-space: pre-wrap;
1791 white-space: pre-wrap;
1792 }
1792 }
1793
1793
1794 #content div.box #summary p:last-child {
1794 #content div.box #summary p:last-child {
1795 margin-bottom: 9px;
1795 margin-bottom: 9px;
1796 }
1796 }
1797
1797
1798 #content div.box #summary p:first-of-type {
1798 #content div.box #summary p:first-of-type {
1799 margin-top: 9px;
1799 margin-top: 9px;
1800 }
1800 }
1801
1801
1802 .metatag {
1802 .metatag {
1803 display: inline-block;
1803 display: inline-block;
1804 margin-right: 1px;
1804 margin-right: 1px;
1805 -webkit-border-radius: 4px 4px 4px 4px;
1805 -webkit-border-radius: 4px 4px 4px 4px;
1806 -khtml-border-radius: 4px 4px 4px 4px;
1806 -khtml-border-radius: 4px 4px 4px 4px;
1807 border-radius: 4px 4px 4px 4px;
1807 border-radius: 4px 4px 4px 4px;
1808
1808
1809 border: solid 1px #9CF;
1809 border: solid 1px #9CF;
1810 padding: 2px 3px 2px 3px !important;
1810 padding: 2px 3px 2px 3px !important;
1811 background-color: #DEF;
1811 background-color: #DEF;
1812 }
1812 }
1813
1813
1814 .metatag[tag="dead"] {
1814 .metatag[tag="dead"] {
1815 background-color: #E44;
1815 background-color: #E44;
1816 }
1816 }
1817
1817
1818 .metatag[tag="stale"] {
1818 .metatag[tag="stale"] {
1819 background-color: #EA4;
1819 background-color: #EA4;
1820 }
1820 }
1821
1821
1822 .metatag[tag="featured"] {
1822 .metatag[tag="featured"] {
1823 background-color: #AEA;
1823 background-color: #AEA;
1824 }
1824 }
1825
1825
1826 .metatag[tag="requires"] {
1826 .metatag[tag="requires"] {
1827 background-color: #9CF;
1827 background-color: #9CF;
1828 }
1828 }
1829
1829
1830 .metatag[tag="recommends"] {
1830 .metatag[tag="recommends"] {
1831 background-color: #BDF;
1831 background-color: #BDF;
1832 }
1832 }
1833
1833
1834 .metatag[tag="lang"] {
1834 .metatag[tag="lang"] {
1835 background-color: #FAF474;
1835 background-color: #FAF474;
1836 }
1836 }
1837
1837
1838 .metatag[tag="license"] {
1838 .metatag[tag="license"] {
1839 border: solid 1px #9CF;
1839 border: solid 1px #9CF;
1840 background-color: #DEF;
1840 background-color: #DEF;
1841 target-new: tab !important;
1841 target-new: tab !important;
1842 }
1842 }
1843 .metatag[tag="see"] {
1843 .metatag[tag="see"] {
1844 border: solid 1px #CBD;
1844 border: solid 1px #CBD;
1845 background-color: #EDF;
1845 background-color: #EDF;
1846 }
1846 }
1847
1847
1848 a.metatag[tag="license"]:hover {
1848 a.metatag[tag="license"]:hover {
1849 background-color: #577632;
1849 background-color: #577632;
1850 color: #FFF;
1850 color: #FFF;
1851 text-decoration: none;
1851 text-decoration: none;
1852 }
1852 }
1853
1853
1854 #summary .desc {
1854 #summary .desc {
1855 white-space: pre;
1855 white-space: pre;
1856 width: 100%;
1856 width: 100%;
1857 }
1857 }
1858
1858
1859 #summary .repo_name {
1859 #summary .repo_name {
1860 font-size: 1.6em;
1860 font-size: 1.6em;
1861 font-weight: bold;
1861 font-weight: bold;
1862 vertical-align: baseline;
1862 vertical-align: baseline;
1863 clear: right
1863 clear: right
1864 }
1864 }
1865
1865
1866 #footer {
1866 #footer {
1867 clear: both;
1867 clear: both;
1868 overflow: hidden;
1868 overflow: hidden;
1869 text-align: right;
1869 text-align: right;
1870 margin: 0;
1870 margin: 0;
1871 padding: 0 10px 4px;
1871 padding: 0 10px 4px;
1872 margin: -10px 0 0;
1872 margin: -10px 0 0;
1873 }
1873 }
1874
1874
1875 #footer div#footer-inner {
1875 #footer div#footer-inner {
1876 background-color: #577632;
1876 background-color: #577632;
1877 background-repeat: repeat-x;
1877 background-repeat: repeat-x;
1878 background-image: -khtml-gradient( linear, left top, left bottom, from(#577632), to(#577632));
1878 background-image: -khtml-gradient( linear, left top, left bottom, from(#577632), to(#577632));
1879 background-image: -moz-linear-gradient(top, #577632, #577632);
1879 background-image: -moz-linear-gradient(top, #577632, #577632);
1880 background-image: -ms-linear-gradient( top, #577632, #577632);
1880 background-image: -ms-linear-gradient( top, #577632, #577632);
1881 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #577632), color-stop( 100%, #577632));
1881 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #577632), color-stop( 100%, #577632));
1882 background-image: -webkit-linear-gradient( top, #577632, #577632));
1882 background-image: -webkit-linear-gradient( top, #577632, #577632));
1883 background-image: -o-linear-gradient( top, #577632, #577632));
1883 background-image: -o-linear-gradient( top, #577632, #577632));
1884 background-image: linear-gradient(to bottom, #577632, #577632);
1884 background-image: linear-gradient(to bottom, #577632, #577632);
1885 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#577632', endColorstr = '#577632', GradientType = 0);
1885 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#577632', endColorstr = '#577632', GradientType = 0);
1886 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1886 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1887 -webkit-border-radius: 4px 4px 4px 4px;
1887 -webkit-border-radius: 4px 4px 4px 4px;
1888 -khtml-border-radius: 4px 4px 4px 4px;
1888 -khtml-border-radius: 4px 4px 4px 4px;
1889 border-radius: 4px 4px 4px 4px;
1889 border-radius: 4px 4px 4px 4px;
1890 }
1890 }
1891
1891
1892 #footer div#footer-inner p {
1892 #footer div#footer-inner p {
1893 padding: 15px 25px 15px 0;
1893 padding: 15px 25px 15px 0;
1894 color: #FFF;
1894 color: #FFF;
1895 font-weight: 700;
1895 font-weight: 700;
1896 }
1896 }
1897
1897
1898 #footer div#footer-inner .footer-link {
1898 #footer div#footer-inner .footer-link {
1899 float: left;
1899 float: left;
1900 padding-left: 10px;
1900 padding-left: 10px;
1901 }
1901 }
1902
1902
1903 #footer div#footer-inner .footer-link a, #footer div#footer-inner .footer-link-right a {
1903 #footer div#footer-inner .footer-link a, #footer div#footer-inner .footer-link-right a {
1904 color: #FFF;
1904 color: #FFF;
1905 }
1905 }
1906
1906
1907 #login div.title {
1907 #login div.title {
1908 clear: both;
1908 clear: both;
1909 overflow: hidden;
1909 overflow: hidden;
1910 position: relative;
1910 position: relative;
1911 background-color: #577632;
1911 background-color: #577632;
1912 background-repeat: repeat-x;
1912 background-repeat: repeat-x;
1913 background-image: -khtml-gradient( linear, left top, left bottom, from(#577632), to(#577632));
1913 background-image: -khtml-gradient( linear, left top, left bottom, from(#577632), to(#577632));
1914 background-image: -moz-linear-gradient( top, #577632, #577632);
1914 background-image: -moz-linear-gradient( top, #577632, #577632);
1915 background-image: -ms-linear-gradient( top, #577632, #577632);
1915 background-image: -ms-linear-gradient( top, #577632, #577632);
1916 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #577632), color-stop( 100%, #577632));
1916 background-image: -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #577632), color-stop( 100%, #577632));
1917 background-image: -webkit-linear-gradient( top, #577632, #577632));
1917 background-image: -webkit-linear-gradient( top, #577632, #577632));
1918 background-image: -o-linear-gradient( top, #577632, #577632));
1918 background-image: -o-linear-gradient( top, #577632, #577632));
1919 background-image: linear-gradient(to bottom, #577632, #577632);
1919 background-image: linear-gradient(to bottom, #577632, #577632);
1920 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#577632', endColorstr = '#577632', GradientType = 0);
1920 filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#577632', endColorstr = '#577632', GradientType = 0);
1921 margin: 0 auto;
1921 margin: 0 auto;
1922 padding: 0;
1922 padding: 0;
1923 }
1923 }
1924
1924
1925 #login div.inner {
1925 #login div.inner {
1926 background: #FFF url("../images/login.png") no-repeat top left;
1926 background: #FFF url("../images/login.png") no-repeat top left;
1927 border-top: none;
1927 border-top: none;
1928 border-bottom: none;
1928 border-bottom: none;
1929 margin: 0 auto;
1929 margin: 0 auto;
1930 padding: 20px;
1930 padding: 20px;
1931 }
1931 }
1932
1932
1933 #login div.form div.fields div.field div.label {
1933 #login div.form div.fields div.field div.label {
1934 width: 173px;
1934 width: 173px;
1935 float: left;
1935 float: left;
1936 text-align: right;
1936 text-align: right;
1937 margin: 2px 10px 0 0;
1937 margin: 2px 10px 0 0;
1938 padding: 5px 0 0 5px;
1938 padding: 5px 0 0 5px;
1939 }
1939 }
1940
1940
1941 #login div.form div.fields div.field div.input input {
1941 #login div.form div.fields div.field div.input input {
1942 background: #FFF;
1942 background: #FFF;
1943 border-top: 1px solid #b3b3b3;
1943 border-top: 1px solid #b3b3b3;
1944 border-left: 1px solid #b3b3b3;
1944 border-left: 1px solid #b3b3b3;
1945 border-right: 1px solid #eaeaea;
1945 border-right: 1px solid #eaeaea;
1946 border-bottom: 1px solid #eaeaea;
1946 border-bottom: 1px solid #eaeaea;
1947 color: #000;
1947 color: #000;
1948 font-size: 11px;
1948 font-size: 11px;
1949 margin: 0;
1949 margin: 0;
1950 padding: 7px 7px 6px;
1950 padding: 7px 7px 6px;
1951 }
1951 }
1952
1952
1953 #login div.form div.fields div.buttons {
1953 #login div.form div.fields div.buttons {
1954 clear: both;
1954 clear: both;
1955 overflow: hidden;
1955 overflow: hidden;
1956 border-top: 1px solid #DDD;
1956 border-top: 1px solid #DDD;
1957 text-align: right;
1957 text-align: right;
1958 margin: 0;
1958 margin: 0;
1959 padding: 10px 0 0;
1959 padding: 10px 0 0;
1960 }
1960 }
1961
1961
1962 #login div.form div.links {
1962 #login div.form div.links {
1963 clear: both;
1963 clear: both;
1964 overflow: hidden;
1964 overflow: hidden;
1965 margin: 10px 0 0;
1965 margin: 10px 0 0;
1966 padding: 0 0 2px;
1966 padding: 0 0 2px;
1967 }
1967 }
1968
1968
1969 .user-menu {
1969 .user-menu {
1970 margin: 0px !important;
1970 margin: 0px !important;
1971 float: left;
1971 float: left;
1972 }
1972 }
1973
1973
1974 .user-menu .container {
1974 .user-menu .container {
1975 padding: 0px 4px 0px 4px;
1975 padding: 0px 4px 0px 4px;
1976 margin: 0px 0px 0px 0px;
1976 margin: 0px 0px 0px 0px;
1977 }
1977 }
1978
1978
1979 .user-menu .gravatar {
1979 .user-menu .gravatar {
1980 margin: 0px 0px 0px 0px;
1980 margin: 0px 0px 0px 0px;
1981 cursor: pointer;
1981 cursor: pointer;
1982 }
1982 }
1983 .user-menu .gravatar.enabled {
1983 .user-menu .gravatar.enabled {
1984 background-color: #FDF784 !important;
1984 background-color: #FDF784 !important;
1985 }
1985 }
1986 .user-menu .gravatar:hover {
1986 .user-menu .gravatar:hover {
1987 background-color: #FDF784 !important;
1987 background-color: #FDF784 !important;
1988 }
1988 }
1989 #quick_login {
1989 #quick_login {
1990 min-height: 110px;
1990 min-height: 110px;
1991 padding: 4px;
1991 padding: 4px;
1992 position: absolute;
1992 position: absolute;
1993 right: 0;
1993 right: 0;
1994 background-color: #577632;
1994 background-color: #577632;
1995 background-repeat: repeat-x;
1995 background-repeat: repeat-x;
1996 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
1996 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
1997 background-image: -moz-linear-gradient(top, #577632, #577632);
1997 background-image: -moz-linear-gradient(top, #577632, #577632);
1998 background-image: -ms-linear-gradient(top, #577632, #577632);
1998 background-image: -ms-linear-gradient(top, #577632, #577632);
1999 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
1999 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
2000 background-image: -webkit-linear-gradient(top, #577632, #577632);
2000 background-image: -webkit-linear-gradient(top, #577632, #577632);
2001 background-image: -o-linear-gradient(top, #577632, #577632);
2001 background-image: -o-linear-gradient(top, #577632, #577632);
2002 background-image: linear-gradient(to bottom, #577632, #577632);
2002 background-image: linear-gradient(to bottom, #577632, #577632);
2003 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632', endColorstr='#577632', GradientType=0 );
2003 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632', endColorstr='#577632', GradientType=0 );
2004
2004
2005 z-index: 999;
2005 z-index: 999;
2006 -webkit-border-radius: 0px 0px 4px 4px;
2006 -webkit-border-radius: 0px 0px 4px 4px;
2007 -khtml-border-radius: 0px 0px 4px 4px;
2007 -khtml-border-radius: 0px 0px 4px 4px;
2008 border-radius: 0px 0px 4px 4px;
2008 border-radius: 0px 0px 4px 4px;
2009 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2009 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2010
2010
2011 overflow: hidden;
2011 overflow: hidden;
2012 }
2012 }
2013 #quick_login h4 {
2013 #quick_login h4 {
2014 color: #fff;
2014 color: #fff;
2015 padding: 5px 0px 5px 14px;
2015 padding: 5px 0px 5px 14px;
2016 }
2016 }
2017
2017
2018 #quick_login .password_forgoten {
2018 #quick_login .password_forgoten {
2019 padding-right: 0px;
2019 padding-right: 0px;
2020 padding-top: 0px;
2020 padding-top: 0px;
2021 text-align: left;
2021 text-align: left;
2022 }
2022 }
2023
2023
2024 #quick_login .password_forgoten a {
2024 #quick_login .password_forgoten a {
2025 font-size: 10px;
2025 font-size: 10px;
2026 color: #fff;
2026 color: #fff;
2027 padding: 0px !important;
2027 padding: 0px !important;
2028 line-height: 20px !important;
2028 line-height: 20px !important;
2029 }
2029 }
2030
2030
2031 #quick_login .register {
2031 #quick_login .register {
2032 padding-right: 10px;
2032 padding-right: 10px;
2033 padding-top: 5px;
2033 padding-top: 5px;
2034 text-align: left;
2034 text-align: left;
2035 }
2035 }
2036
2036
2037 #quick_login .register a {
2037 #quick_login .register a {
2038 font-size: 10px;
2038 font-size: 10px;
2039 color: #fff;
2039 color: #fff;
2040 padding: 0px !important;
2040 padding: 0px !important;
2041 line-height: 20px !important;
2041 line-height: 20px !important;
2042 }
2042 }
2043
2043
2044 #quick_login .submit {
2044 #quick_login .submit {
2045 margin: -20px 0 0 0px;
2045 margin: -20px 0 0 0px;
2046 position: absolute;
2046 position: absolute;
2047 right: 15px;
2047 right: 15px;
2048 }
2048 }
2049
2049
2050 #quick_login .links_left {
2050 #quick_login .links_left {
2051 float: left;
2051 float: left;
2052 margin-right: 130px;
2052 margin-right: 130px;
2053 width: 170px;
2053 width: 170px;
2054 }
2054 }
2055 #quick_login .links_right {
2055 #quick_login .links_right {
2056
2056
2057 position: absolute;
2057 position: absolute;
2058 right: 0;
2058 right: 0;
2059 }
2059 }
2060 #quick_login .full_name {
2060 #quick_login .full_name {
2061 color: #FFFFFF;
2061 color: #FFFFFF;
2062 font-weight: bold;
2062 font-weight: bold;
2063 padding: 3px 3px 3px 6px;
2063 padding: 3px 3px 3px 6px;
2064 }
2064 }
2065 #quick_login .big_gravatar {
2065 #quick_login .big_gravatar {
2066 padding: 4px 0px 0px 6px;
2066 padding: 4px 0px 0px 6px;
2067 }
2067 }
2068 #quick_login .notifications {
2068 #quick_login .notifications {
2069 padding: 2px 0px 0px 6px;
2069 padding: 2px 0px 0px 6px;
2070 color: #FFFFFF;
2070 color: #FFFFFF;
2071 font-weight: bold;
2071 font-weight: bold;
2072 line-height: 10px !important;
2072 line-height: 10px !important;
2073 }
2073 }
2074 #quick_login .notifications a,
2074 #quick_login .notifications a,
2075 #quick_login .unread a {
2075 #quick_login .unread a {
2076 color: #FFFFFF;
2076 color: #FFFFFF;
2077 display: block;
2077 display: block;
2078 padding: 0px !important;
2078 padding: 0px !important;
2079 }
2079 }
2080 #quick_login .notifications a:hover,
2080 #quick_login .notifications a:hover,
2081 #quick_login .unread a:hover {
2081 #quick_login .unread a:hover {
2082 background-color: inherit !important;
2082 background-color: inherit !important;
2083 }
2083 }
2084 #quick_login .email, #quick_login .unread {
2084 #quick_login .email, #quick_login .unread {
2085 color: #FFFFFF;
2085 color: #FFFFFF;
2086 padding: 3px 3px 3px 6px;
2086 padding: 3px 3px 3px 6px;
2087 }
2087 }
2088 #quick_login .links .logout {
2088 #quick_login .links .logout {
2089 }
2089 }
2090
2090
2091 #quick_login div.form div.fields {
2091 #quick_login div.form div.fields {
2092 padding-top: 2px;
2092 padding-top: 2px;
2093 padding-left: 10px;
2093 padding-left: 10px;
2094 }
2094 }
2095
2095
2096 #quick_login div.form div.fields div.field {
2096 #quick_login div.form div.fields div.field {
2097 padding: 5px;
2097 padding: 5px;
2098 }
2098 }
2099
2099
2100 #quick_login div.form div.fields div.field div.label label {
2100 #quick_login div.form div.fields div.field div.label label {
2101 color: #fff;
2101 color: #fff;
2102 padding-bottom: 3px;
2102 padding-bottom: 3px;
2103 }
2103 }
2104
2104
2105 #quick_login div.form div.fields div.field div.input input {
2105 #quick_login div.form div.fields div.field div.input input {
2106 width: 236px;
2106 width: 236px;
2107 background: #FFF;
2107 background: #FFF;
2108 border-top: 1px solid #b3b3b3;
2108 border-top: 1px solid #b3b3b3;
2109 border-left: 1px solid #b3b3b3;
2109 border-left: 1px solid #b3b3b3;
2110 border-right: 1px solid #eaeaea;
2110 border-right: 1px solid #eaeaea;
2111 border-bottom: 1px solid #eaeaea;
2111 border-bottom: 1px solid #eaeaea;
2112 color: #000;
2112 color: #000;
2113 font-size: 11px;
2113 font-size: 11px;
2114 margin: 0;
2114 margin: 0;
2115 padding: 5px 7px 4px;
2115 padding: 5px 7px 4px;
2116 }
2116 }
2117
2117
2118 #quick_login div.form div.fields div.buttons {
2118 #quick_login div.form div.fields div.buttons {
2119 clear: both;
2119 clear: both;
2120 overflow: hidden;
2120 overflow: hidden;
2121 text-align: right;
2121 text-align: right;
2122 margin: 0;
2122 margin: 0;
2123 padding: 5px 14px 0px 5px;
2123 padding: 5px 14px 0px 5px;
2124 }
2124 }
2125
2125
2126 #quick_login div.form div.links {
2126 #quick_login div.form div.links {
2127 clear: both;
2127 clear: both;
2128 overflow: hidden;
2128 overflow: hidden;
2129 margin: 10px 0 0;
2129 margin: 10px 0 0;
2130 padding: 0 0 2px;
2130 padding: 0 0 2px;
2131 }
2131 }
2132
2132
2133 #quick_login ol.links {
2133 #quick_login ol.links {
2134 display: block;
2134 display: block;
2135 font-weight: bold;
2135 font-weight: bold;
2136 list-style: none outside none;
2136 list-style: none outside none;
2137 text-align: right;
2137 text-align: right;
2138 }
2138 }
2139 #quick_login ol.links li {
2139 #quick_login ol.links li {
2140 line-height: 27px;
2140 line-height: 27px;
2141 margin: 0;
2141 margin: 0;
2142 padding: 0;
2142 padding: 0;
2143 color: #fff;
2143 color: #fff;
2144 display: block;
2144 display: block;
2145 float: none !important;
2145 float: none !important;
2146 }
2146 }
2147
2147
2148 #quick_login ol.links li a {
2148 #quick_login ol.links li a {
2149 color: #fff;
2149 color: #fff;
2150 display: block;
2150 display: block;
2151 padding: 2px;
2151 padding: 2px;
2152 }
2152 }
2153 #quick_login ol.links li a:HOVER {
2153 #quick_login ol.links li a:HOVER {
2154 background-color: inherit !important;
2154 background-color: inherit !important;
2155 }
2155 }
2156
2156
2157 #register div.title {
2157 #register div.title {
2158 clear: both;
2158 clear: both;
2159 overflow: hidden;
2159 overflow: hidden;
2160 position: relative;
2160 position: relative;
2161 background-color: #577632;
2161 background-color: #577632;
2162 background-repeat: repeat-x;
2162 background-repeat: repeat-x;
2163 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
2163 background-image: -khtml-gradient(linear, left top, left bottom, from(#577632), to(#577632) );
2164 background-image: -moz-linear-gradient(top, #577632, #577632);
2164 background-image: -moz-linear-gradient(top, #577632, #577632);
2165 background-image: -ms-linear-gradient(top, #577632, #577632);
2165 background-image: -ms-linear-gradient(top, #577632, #577632);
2166 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
2166 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #577632), color-stop(100%, #577632) );
2167 background-image: -webkit-linear-gradient(top, #577632, #577632);
2167 background-image: -webkit-linear-gradient(top, #577632, #577632);
2168 background-image: -o-linear-gradient(top, #577632, #577632);
2168 background-image: -o-linear-gradient(top, #577632, #577632);
2169 background-image: linear-gradient(to bottom, #577632, #577632);
2169 background-image: linear-gradient(to bottom, #577632, #577632);
2170 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',
2170 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#577632',
2171 endColorstr='#577632', GradientType=0 );
2171 endColorstr='#577632', GradientType=0 );
2172 margin: 0 auto;
2172 margin: 0 auto;
2173 padding: 0;
2173 padding: 0;
2174 }
2174 }
2175
2175
2176 #register div.inner {
2176 #register div.inner {
2177 background: #FFF;
2177 background: #FFF;
2178 border-top: none;
2178 border-top: none;
2179 border-bottom: none;
2179 border-bottom: none;
2180 margin: 0 auto;
2180 margin: 0 auto;
2181 padding: 20px;
2181 padding: 20px;
2182 }
2182 }
2183
2183
2184 #register div.form div.fields div.field div.label {
2184 #register div.form div.fields div.field div.label {
2185 width: 135px;
2185 width: 135px;
2186 float: left;
2186 float: left;
2187 text-align: right;
2187 text-align: right;
2188 margin: 2px 10px 0 0;
2188 margin: 2px 10px 0 0;
2189 padding: 5px 0 0 5px;
2189 padding: 5px 0 0 5px;
2190 }
2190 }
2191
2191
2192 #register div.form div.fields div.field div.input input {
2192 #register div.form div.fields div.field div.input input {
2193 width: 300px;
2193 width: 300px;
2194 background: #FFF;
2194 background: #FFF;
2195 border-top: 1px solid #b3b3b3;
2195 border-top: 1px solid #b3b3b3;
2196 border-left: 1px solid #b3b3b3;
2196 border-left: 1px solid #b3b3b3;
2197 border-right: 1px solid #eaeaea;
2197 border-right: 1px solid #eaeaea;
2198 border-bottom: 1px solid #eaeaea;
2198 border-bottom: 1px solid #eaeaea;
2199 color: #000;
2199 color: #000;
2200 font-size: 11px;
2200 font-size: 11px;
2201 margin: 0;
2201 margin: 0;
2202 padding: 7px 7px 6px;
2202 padding: 7px 7px 6px;
2203 }
2203 }
2204
2204
2205 #register div.form div.fields div.buttons {
2205 #register div.form div.fields div.buttons {
2206 clear: both;
2206 clear: both;
2207 overflow: hidden;
2207 overflow: hidden;
2208 border-top: 1px solid #DDD;
2208 border-top: 1px solid #DDD;
2209 text-align: left;
2209 text-align: left;
2210 margin: 0;
2210 margin: 0;
2211 padding: 10px 0 0 150px;
2211 padding: 10px 0 0 150px;
2212 }
2212 }
2213
2213
2214 #register div.form div.activation_msg {
2214 #register div.form div.activation_msg {
2215 padding-top: 4px;
2215 padding-top: 4px;
2216 padding-bottom: 4px;
2216 padding-bottom: 4px;
2217 }
2217 }
2218
2218
2219 #journal .journal_day {
2219 #journal .journal_day {
2220 font-size: 20px;
2220 font-size: 20px;
2221 padding: 10px 0px;
2221 padding: 10px 0px;
2222 border-bottom: 2px solid #DDD;
2222 border-bottom: 2px solid #DDD;
2223 margin-left: 10px;
2223 margin-left: 10px;
2224 margin-right: 10px;
2224 margin-right: 10px;
2225 }
2225 }
2226
2226
2227 #journal .journal_container {
2227 #journal .journal_container {
2228 padding: 5px;
2228 padding: 5px;
2229 clear: both;
2229 clear: both;
2230 margin: 0px 5px 0px 10px;
2230 margin: 0px 5px 0px 10px;
2231 }
2231 }
2232
2232
2233 #journal .journal_action_container {
2233 #journal .journal_action_container {
2234 padding-left: 38px;
2234 padding-left: 38px;
2235 }
2235 }
2236
2236
2237 #journal .journal_user {
2237 #journal .journal_user {
2238 color: #747474;
2238 color: #747474;
2239 font-size: 14px;
2239 font-size: 14px;
2240 font-weight: bold;
2240 font-weight: bold;
2241 height: 30px;
2241 height: 30px;
2242 }
2242 }
2243
2243
2244 #journal .journal_user.deleted {
2244 #journal .journal_user.deleted {
2245 color: #747474;
2245 color: #747474;
2246 font-size: 14px;
2246 font-size: 14px;
2247 font-weight: normal;
2247 font-weight: normal;
2248 height: 30px;
2248 height: 30px;
2249 font-style: italic;
2249 font-style: italic;
2250 }
2250 }
2251
2251
2252
2252
2253 #journal .journal_icon {
2253 #journal .journal_icon {
2254 clear: both;
2254 clear: both;
2255 float: left;
2255 float: left;
2256 padding-right: 4px;
2256 padding-right: 4px;
2257 padding-top: 3px;
2257 padding-top: 3px;
2258 }
2258 }
2259
2259
2260 #journal .journal_action {
2260 #journal .journal_action {
2261 padding-top: 4px;
2261 padding-top: 4px;
2262 min-height: 2px;
2262 min-height: 2px;
2263 float: left
2263 float: left
2264 }
2264 }
2265
2265
2266 #journal .journal_action_params {
2266 #journal .journal_action_params {
2267 clear: left;
2267 clear: left;
2268 padding-left: 22px;
2268 padding-left: 22px;
2269 }
2269 }
2270
2270
2271 #journal .journal_repo {
2271 #journal .journal_repo {
2272 float: left;
2272 float: left;
2273 margin-left: 6px;
2273 margin-left: 6px;
2274 padding-top: 3px;
2274 padding-top: 3px;
2275 }
2275 }
2276
2276
2277 #journal .date {
2277 #journal .date {
2278 clear: both;
2278 clear: both;
2279 color: #777777;
2279 color: #777777;
2280 font-size: 11px;
2280 font-size: 11px;
2281 padding-left: 22px;
2281 padding-left: 22px;
2282 }
2282 }
2283
2283
2284 #journal .journal_repo .journal_repo_name {
2284 #journal .journal_repo .journal_repo_name {
2285 font-weight: bold;
2285 font-weight: bold;
2286 font-size: 1.1em;
2286 font-size: 1.1em;
2287 }
2287 }
2288
2288
2289 #journal .compare_view {
2289 #journal .compare_view {
2290 padding: 5px 0px 5px 0px;
2290 padding: 5px 0px 5px 0px;
2291 width: 95px;
2291 width: 95px;
2292 }
2292 }
2293
2293
2294 .journal_highlight {
2294 .journal_highlight {
2295 font-weight: bold;
2295 font-weight: bold;
2296 padding: 0 2px;
2296 padding: 0 2px;
2297 vertical-align: bottom;
2297 vertical-align: bottom;
2298 }
2298 }
2299
2299
2300 .trending_language_tbl, .trending_language_tbl td {
2300 .trending_language_tbl, .trending_language_tbl td {
2301 border: 0 !important;
2301 border: 0 !important;
2302 margin: 0 !important;
2302 margin: 0 !important;
2303 padding: 0 !important;
2303 padding: 0 !important;
2304 }
2304 }
2305
2305
2306 .trending_language_tbl, .trending_language_tbl tr {
2306 .trending_language_tbl, .trending_language_tbl tr {
2307 border-spacing: 1px;
2307 border-spacing: 1px;
2308 }
2308 }
2309
2309
2310 .trending_language {
2310 .trending_language {
2311 background-color: #577632;
2311 background-color: #577632;
2312 color: #FFF;
2312 color: #FFF;
2313 display: block;
2313 display: block;
2314 min-width: 20px;
2314 min-width: 20px;
2315 text-decoration: none;
2315 text-decoration: none;
2316 height: 12px;
2316 height: 12px;
2317 margin-bottom: 0px;
2317 margin-bottom: 0px;
2318 margin-left: 5px;
2318 margin-left: 5px;
2319 white-space: pre;
2319 white-space: pre;
2320 padding: 3px;
2320 padding: 3px;
2321 }
2321 }
2322
2322
2323 h3.files_location {
2323 h3.files_location {
2324 font-size: 1.8em;
2324 font-size: 1.8em;
2325 font-weight: 700;
2325 font-weight: 700;
2326 border-bottom: none !important;
2326 border-bottom: none !important;
2327 margin: 10px 0 !important;
2327 margin: 10px 0 !important;
2328 }
2328 }
2329
2329
2330 #files_data dl dt {
2330 #files_data dl dt {
2331 float: left;
2331 float: left;
2332 width: 60px;
2332 width: 60px;
2333 margin: 0 !important;
2333 margin: 0 !important;
2334 padding: 5px;
2334 padding: 5px;
2335 }
2335 }
2336
2336
2337 #files_data dl dd {
2337 #files_data dl dd {
2338 margin: 0 !important;
2338 margin: 0 !important;
2339 padding: 5px !important;
2339 padding: 5px !important;
2340 }
2340 }
2341
2341
2342 #files_data .codeblock #editor_container .error-message {
2342 #files_data .codeblock #editor_container .error-message {
2343 color: red;
2343 color: red;
2344 padding: 10px 10px 10px 26px
2344 padding: 10px 10px 10px 26px
2345 }
2345 }
2346
2346
2347 .file_history {
2347 .file_history {
2348 padding-top: 10px;
2348 padding-top: 10px;
2349 font-size: 16px;
2349 font-size: 16px;
2350 }
2350 }
2351 .file_author {
2351 .file_author {
2352 float: left;
2352 float: left;
2353 }
2353 }
2354
2354
2355 .file_author .item {
2355 .file_author .item {
2356 float: left;
2356 float: left;
2357 padding: 5px;
2357 padding: 5px;
2358 color: #888;
2358 color: #888;
2359 }
2359 }
2360
2360
2361 .tablerow0 {
2361 .tablerow0 {
2362 background-color: #F8F8F8;
2362 background-color: #F8F8F8;
2363 }
2363 }
2364
2364
2365 .tablerow1 {
2365 .tablerow1 {
2366 background-color: #FFFFFF;
2366 background-color: #FFFFFF;
2367 }
2367 }
2368
2368
2369 .changeset_id {
2369 .changeset_id {
2370 color: #666666;
2370 color: #666666;
2371 margin-right: -3px;
2371 margin-right: -3px;
2372 }
2372 }
2373
2373
2374 .changeset_hash {
2374 .changeset_hash {
2375 color: #000000;
2375 color: #000000;
2376 }
2376 }
2377
2377
2378 #changeset_content {
2378 #changeset_content {
2379 border-left: 1px solid #CCC;
2379 border-left: 1px solid #CCC;
2380 border-right: 1px solid #CCC;
2380 border-right: 1px solid #CCC;
2381 border-bottom: 1px solid #CCC;
2381 border-bottom: 1px solid #CCC;
2382 padding: 5px;
2382 padding: 5px;
2383 }
2383 }
2384
2384
2385 #changeset_compare_view_content {
2385 #changeset_compare_view_content {
2386 border: 1px solid #CCC;
2386 border: 1px solid #CCC;
2387 padding: 5px;
2387 padding: 5px;
2388 }
2388 }
2389
2389
2390 #changeset_content .container {
2390 #changeset_content .container {
2391 min-height: 100px;
2391 min-height: 100px;
2392 font-size: 1.2em;
2392 font-size: 1.2em;
2393 overflow: hidden;
2393 overflow: hidden;
2394 }
2394 }
2395
2395
2396 #changeset_compare_view_content .compare_view_commits {
2396 #changeset_compare_view_content .compare_view_commits {
2397 width: auto !important;
2397 width: auto !important;
2398 }
2398 }
2399
2399
2400 #changeset_compare_view_content .compare_view_commits td {
2400 #changeset_compare_view_content .compare_view_commits td {
2401 padding: 0px 0px 0px 12px !important;
2401 padding: 0px 0px 0px 12px !important;
2402 }
2402 }
2403
2403
2404 #changeset_content .container .right {
2404 #changeset_content .container .right {
2405 float: right;
2405 float: right;
2406 width: 20%;
2406 width: 20%;
2407 text-align: right;
2407 text-align: right;
2408 }
2408 }
2409
2409
2410 #changeset_content .container .message {
2410 #changeset_content .container .message {
2411 white-space: pre-wrap;
2411 white-space: pre-wrap;
2412 }
2412 }
2413 #changeset_content .container .message a:hover {
2413 #changeset_content .container .message a:hover {
2414 text-decoration: none;
2414 text-decoration: none;
2415 }
2415 }
2416 .cs_files .cur_cs {
2416 .cs_files .cur_cs {
2417 margin: 10px 2px;
2417 margin: 10px 2px;
2418 font-weight: bold;
2418 font-weight: bold;
2419 }
2419 }
2420
2420
2421 .cs_files .node {
2421 .cs_files .node {
2422 float: left;
2422 float: left;
2423 }
2423 }
2424
2424
2425 .cs_files .changes {
2425 .cs_files .changes {
2426 float: right;
2426 float: right;
2427 color: #577632;
2427 color: #577632;
2428 }
2428 }
2429
2429
2430 .cs_files .changes .added {
2430 .cs_files .changes .added {
2431 background-color: #BBFFBB;
2431 background-color: #BBFFBB;
2432 float: left;
2432 float: left;
2433 text-align: center;
2433 text-align: center;
2434 font-size: 9px;
2434 font-size: 9px;
2435 padding: 2px 0px 2px 0px;
2435 padding: 2px 0px 2px 0px;
2436 }
2436 }
2437
2437
2438 .cs_files .changes .deleted {
2438 .cs_files .changes .deleted {
2439 background-color: #FF8888;
2439 background-color: #FF8888;
2440 float: left;
2440 float: left;
2441 text-align: center;
2441 text-align: center;
2442 font-size: 9px;
2442 font-size: 9px;
2443 padding: 2px 0px 2px 0px;
2443 padding: 2px 0px 2px 0px;
2444 }
2444 }
2445 /*new binary
2445 /*new binary
2446 NEW_FILENODE = 1
2446 NEW_FILENODE = 1
2447 DEL_FILENODE = 2
2447 DEL_FILENODE = 2
2448 MOD_FILENODE = 3
2448 MOD_FILENODE = 3
2449 RENAMED_FILENODE = 4
2449 RENAMED_FILENODE = 4
2450 CHMOD_FILENODE = 5
2450 CHMOD_FILENODE = 5
2451 BIN_FILENODE = 6
2451 BIN_FILENODE = 6
2452 */
2452 */
2453 .cs_files .changes .bin {
2453 .cs_files .changes .bin {
2454 background-color: #BBFFBB;
2454 background-color: #BBFFBB;
2455 float: left;
2455 float: left;
2456 text-align: center;
2456 text-align: center;
2457 font-size: 9px;
2457 font-size: 9px;
2458 padding: 2px 0px 2px 0px;
2458 padding: 2px 0px 2px 0px;
2459 }
2459 }
2460 .cs_files .changes .bin.bin1 {
2460 .cs_files .changes .bin.bin1 {
2461 background-color: #BBFFBB;
2461 background-color: #BBFFBB;
2462 }
2462 }
2463
2463
2464 /*deleted binary*/
2464 /*deleted binary*/
2465 .cs_files .changes .bin.bin2 {
2465 .cs_files .changes .bin.bin2 {
2466 background-color: #FF8888;
2466 background-color: #FF8888;
2467 }
2467 }
2468
2468
2469 /*mod binary*/
2469 /*mod binary*/
2470 .cs_files .changes .bin.bin3 {
2470 .cs_files .changes .bin.bin3 {
2471 background-color: #DDDDDD;
2471 background-color: #DDDDDD;
2472 }
2472 }
2473
2473
2474 /*rename file*/
2474 /*rename file*/
2475 .cs_files .changes .bin.bin4 {
2475 .cs_files .changes .bin.bin4 {
2476 background-color: #6D99FF;
2476 background-color: #6D99FF;
2477 }
2477 }
2478
2478
2479 /*rename file*/
2479 /*rename file*/
2480 .cs_files .changes .bin.bin4 {
2480 .cs_files .changes .bin.bin4 {
2481 background-color: #6D99FF;
2481 background-color: #6D99FF;
2482 }
2482 }
2483
2483
2484 /*chmod file*/
2484 /*chmod file*/
2485 .cs_files .changes .bin.bin5 {
2485 .cs_files .changes .bin.bin5 {
2486 background-color: #6D99FF;
2486 background-color: #6D99FF;
2487 }
2487 }
2488
2488
2489 .cs_files .cs_added, .cs_files .cs_A {
2489 .cs_files .cs_added, .cs_files .cs_A {
2490 background: url("../images/icons/page_white_add.png") no-repeat scroll
2490 background: url("../images/icons/page_white_add.png") no-repeat scroll
2491 3px;
2491 3px;
2492 height: 16px;
2492 height: 16px;
2493 padding-left: 20px;
2493 padding-left: 20px;
2494 margin-top: 7px;
2494 margin-top: 7px;
2495 text-align: left;
2495 text-align: left;
2496 }
2496 }
2497
2497
2498 .cs_files .cs_changed, .cs_files .cs_M {
2498 .cs_files .cs_changed, .cs_files .cs_M {
2499 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2499 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2500 3px;
2500 3px;
2501 height: 16px;
2501 height: 16px;
2502 padding-left: 20px;
2502 padding-left: 20px;
2503 margin-top: 7px;
2503 margin-top: 7px;
2504 text-align: left;
2504 text-align: left;
2505 }
2505 }
2506
2506
2507 .cs_files .cs_removed, .cs_files .cs_D {
2507 .cs_files .cs_removed, .cs_files .cs_D {
2508 background: url("../images/icons/page_white_delete.png") no-repeat
2508 background: url("../images/icons/page_white_delete.png") no-repeat
2509 scroll 3px;
2509 scroll 3px;
2510 height: 16px;
2510 height: 16px;
2511 padding-left: 20px;
2511 padding-left: 20px;
2512 margin-top: 7px;
2512 margin-top: 7px;
2513 text-align: left;
2513 text-align: left;
2514 }
2514 }
2515
2515
2516 .table {
2516 .table {
2517 position: relative;
2517 position: relative;
2518 }
2518 }
2519
2519
2520 #graph {
2520 #graph {
2521 position: relative;
2521 position: relative;
2522 overflow: hidden;
2522 overflow: hidden;
2523 }
2523 }
2524
2524
2525 #graph_nodes {
2525 #graph_nodes {
2526 position: absolute;
2526 position: absolute;
2527 }
2527 }
2528
2528
2529 #graph_content,
2529 #graph_content,
2530 #graph .info_box,
2530 #graph .info_box,
2531 #graph .container_header {
2531 #graph .container_header {
2532 margin-left: 100px;
2532 margin-left: 100px;
2533 }
2533 }
2534
2534
2535 #graph_content {
2535 #graph_content {
2536 position: relative;
2536 position: relative;
2537 }
2537 }
2538
2538
2539 #graph .container_header {
2539 #graph .container_header {
2540 padding: 10px;
2540 padding: 10px;
2541 height: 25px;
2541 height: 25px;
2542 }
2542 }
2543
2543
2544 #graph_content #rev_range_container {
2544 #graph_content #rev_range_container {
2545 float: left;
2545 float: left;
2546 margin: 0px 0px 0px 3px;
2546 margin: 0px 0px 0px 3px;
2547 }
2547 }
2548
2548
2549 #graph_content #rev_range_clear {
2549 #graph_content #rev_range_clear {
2550 float: left;
2550 float: left;
2551 margin: 0px 0px 0px 3px;
2551 margin: 0px 0px 0px 3px;
2552 }
2552 }
2553
2553
2554 #graph_content #changesets {
2554 #graph_content #changesets {
2555 table-layout: fixed;
2555 table-layout: fixed;
2556 border-collapse: collapse;
2556 border-collapse: collapse;
2557 border-left: none;
2557 border-left: none;
2558 border-right: none;
2558 border-right: none;
2559 border-color: #cdcdcd;
2559 border-color: #cdcdcd;
2560 }
2560 }
2561
2561
2562 #graph_content #changesets td {
2562 #graph_content #changesets td {
2563 overflow: hidden;
2563 overflow: hidden;
2564 text-overflow: ellipsis;
2564 text-overflow: ellipsis;
2565 white-space: nowrap;
2565 white-space: nowrap;
2566 height: 31px;
2566 height: 31px;
2567 border-color: #cdcdcd;
2567 border-color: #cdcdcd;
2568 text-align: left;
2568 text-align: left;
2569 }
2569 }
2570
2570
2571 #graph_content .container .checkbox {
2571 #graph_content .container .checkbox {
2572 width: 12px;
2572 width: 12px;
2573 font-size: 0.85em;
2573 font-size: 0.85em;
2574 }
2574 }
2575
2575
2576 #graph_content .container .status {
2576 #graph_content .container .status {
2577 width: 14px;
2577 width: 14px;
2578 font-size: 0.85em;
2578 font-size: 0.85em;
2579 }
2579 }
2580
2580
2581 #graph_content .container .author {
2581 #graph_content .container .author {
2582 width: 105px;
2582 width: 105px;
2583 }
2583 }
2584
2584
2585 #graph_content .container .hash {
2585 #graph_content .container .hash {
2586 width: 100px;
2586 width: 100px;
2587 font-size: 0.85em;
2587 font-size: 0.85em;
2588 }
2588 }
2589
2589
2590 #graph_content #changesets .container .date {
2590 #graph_content #changesets .container .date {
2591 width: 76px;
2591 width: 76px;
2592 color: #666;
2592 color: #666;
2593 font-size: 10px;
2593 font-size: 10px;
2594 }
2594 }
2595
2595
2596 #graph_content_pr .compare_view_commits .expand_commit,
2596 #graph_content_pr .compare_view_commits .expand_commit,
2597 #graph_content .container .expand_commit {
2597 #graph_content .container .expand_commit {
2598 width: 24px;
2598 width: 24px;
2599 cursor: pointer;
2599 cursor: pointer;
2600 }
2600 }
2601
2601
2602 #graph_content #changesets .container .right {
2602 #graph_content #changesets .container .right {
2603 width: 120px;
2603 width: 120px;
2604 padding-right: 0px;
2604 padding-right: 0px;
2605 overflow: visible;
2605 overflow: visible;
2606 position: relative;
2606 position: relative;
2607 }
2607 }
2608
2608
2609 #graph_content .container .mid {
2609 #graph_content .container .mid {
2610 padding: 0;
2610 padding: 0;
2611 }
2611 }
2612
2612
2613 #graph_content .log-container {
2613 #graph_content .log-container {
2614 position: relative;
2614 position: relative;
2615 }
2615 }
2616
2616
2617 #graph_content .container .changeset_range {
2617 #graph_content .container .changeset_range {
2618 float: left;
2618 float: left;
2619 margin: 6px 3px;
2619 margin: 6px 3px;
2620 }
2620 }
2621
2621
2622 #graph_content .container .author img {
2622 #graph_content .container .author img {
2623 vertical-align: middle;
2623 vertical-align: middle;
2624 }
2624 }
2625
2625
2626 #graph_content .container .author .user {
2626 #graph_content .container .author .user {
2627 color: #444444;
2627 color: #444444;
2628 }
2628 }
2629
2629
2630 #graph_content .container .mid .message {
2630 #graph_content .container .mid .message {
2631 white-space: pre-wrap;
2631 white-space: pre-wrap;
2632 padding: 0;
2632 padding: 0;
2633 overflow: hidden;
2633 overflow: hidden;
2634 height: 1.1em;
2634 height: 1.1em;
2635 }
2635 }
2636
2636
2637 #graph_content_pr .compare_view_commits .message {
2637 #graph_content_pr .compare_view_commits .message {
2638 white-space: normal !important;
2638 white-space: normal !important;
2639 padding: 0 !important;
2639 padding: 0 !important;
2640 height: 1.1em;
2640 height: 1.1em;
2641 }
2641 }
2642
2642
2643 #graph_content .container .mid .message.expanded,
2643 #graph_content .container .mid .message.expanded,
2644 #graph_content_pr .compare_view_commits .message.expanded {
2644 #graph_content_pr .compare_view_commits .message.expanded {
2645 height: auto;
2645 height: auto;
2646 margin: 4px 0px 4px 0px;
2646 margin: 4px 0px 4px 0px;
2647 }
2647 }
2648
2648
2649 #graph_content .container .extra-container {
2649 #graph_content .container .extra-container {
2650 display: block;
2650 display: block;
2651 position: absolute;
2651 position: absolute;
2652 top: -15px;
2652 top: -15px;
2653 right: 0;
2653 right: 0;
2654 padding-left: 5px;
2654 padding-left: 5px;
2655 background: #FFFFFF;
2655 background: #FFFFFF;
2656 height: 41px;
2656 height: 41px;
2657 }
2657 }
2658
2658
2659 #pull_request_overview .comments-container,
2659 #pull_request_overview .comments-container,
2660 #changeset_compare_view_content .comments-container,
2660 #changeset_compare_view_content .comments-container,
2661 #graph_content .comments-container,
2661 #graph_content .comments-container,
2662 #shortlog_data .comments-container,
2662 #shortlog_data .comments-container,
2663 #graph_content .logtags {
2663 #graph_content .logtags {
2664 display: block;
2664 display: block;
2665 float: left;
2665 float: left;
2666 overflow: hidden;
2666 overflow: hidden;
2667 padding: 0;
2667 padding: 0;
2668 margin: 0;
2668 margin: 0;
2669 }
2669 }
2670
2670
2671 #graph_content .comments-container {
2671 #graph_content .comments-container {
2672 margin: 0.8em 0;
2672 margin: 0.8em 0;
2673 margin-right: 0.5em;
2673 margin-right: 0.5em;
2674 }
2674 }
2675
2675
2676 #graph_content .tagcontainer {
2676 #graph_content .tagcontainer {
2677 width: 80px;
2677 width: 80px;
2678 position: relative;
2678 position: relative;
2679 float: right;
2679 float: right;
2680 height: 100%;
2680 height: 100%;
2681 top: 7px;
2681 top: 7px;
2682 margin-left: 0.5em;
2682 margin-left: 0.5em;
2683 }
2683 }
2684
2684
2685 #graph_content .logtags {
2685 #graph_content .logtags {
2686 min-width: 80px;
2686 min-width: 80px;
2687 height: 1.1em;
2687 height: 1.1em;
2688 position: absolute;
2688 position: absolute;
2689 left: 0px;
2689 left: 0px;
2690 width: auto;
2690 width: auto;
2691 top: 0px;
2691 top: 0px;
2692 }
2692 }
2693
2693
2694 #graph_content .logtags.tags {
2694 #graph_content .logtags.tags {
2695 top: 14px;
2695 top: 14px;
2696 }
2696 }
2697
2697
2698 #graph_content .logtags:hover {
2698 #graph_content .logtags:hover {
2699 overflow: visible;
2699 overflow: visible;
2700 position: absolute;
2700 position: absolute;
2701 width: auto;
2701 width: auto;
2702 right: 0;
2702 right: 0;
2703 left: initial;
2703 left: initial;
2704 }
2704 }
2705
2705
2706 #graph_content .logtags .booktag,
2706 #graph_content .logtags .booktag,
2707 #graph_content .logtags .tagtag {
2707 #graph_content .logtags .tagtag {
2708 float: left;
2708 float: left;
2709 line-height: 1em;
2709 line-height: 1em;
2710 margin-bottom: 1px;
2710 margin-bottom: 1px;
2711 margin-right: 1px;
2711 margin-right: 1px;
2712 padding: 1px 3px;
2712 padding: 1px 3px;
2713 font-size: 10px;
2713 font-size: 10px;
2714 }
2714 }
2715
2715
2716 #graph_content .container .mid .message a:hover {
2716 #graph_content .container .mid .message a:hover {
2717 text-decoration: none;
2717 text-decoration: none;
2718 }
2718 }
2719
2719
2720 .revision-link {
2720 .revision-link {
2721 color: #3F6F9F;
2721 color: #3F6F9F;
2722 font-weight: bold !important;
2722 font-weight: bold !important;
2723 }
2723 }
2724
2724
2725 .issue-tracker-link {
2725 .issue-tracker-link {
2726 color: #3F6F9F;
2726 color: #3F6F9F;
2727 font-weight: bold !important;
2727 font-weight: bold !important;
2728 }
2728 }
2729
2729
2730 .changeset-status-container {
2730 .changeset-status-container {
2731 padding-right: 5px;
2731 padding-right: 5px;
2732 margin-top: 1px;
2732 margin-top: 1px;
2733 float: right;
2733 float: right;
2734 height: 14px;
2734 height: 14px;
2735 }
2735 }
2736 .code-header .changeset-status-container {
2736 .code-header .changeset-status-container {
2737 float: left;
2737 float: left;
2738 padding: 2px 0px 0px 2px;
2738 padding: 2px 0px 0px 2px;
2739 }
2739 }
2740 .changeset-status-container .changeset-status-lbl {
2740 .changeset-status-container .changeset-status-lbl {
2741 float: left;
2741 float: left;
2742 padding: 3px 4px 0px 0px
2742 padding: 3px 4px 0px 0px
2743 }
2743 }
2744 .code-header .changeset-status-container .changeset-status-lbl {
2744 .code-header .changeset-status-container .changeset-status-lbl {
2745 float: left;
2745 float: left;
2746 padding: 0px 4px 0px 0px;
2746 padding: 0px 4px 0px 0px;
2747 }
2747 }
2748 .changeset-status-container .changeset-status-ico {
2748 .changeset-status-container .changeset-status-ico {
2749 float: left;
2749 float: left;
2750 }
2750 }
2751 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico {
2751 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico {
2752 float: left;
2752 float: left;
2753 }
2753 }
2754
2754
2755 #graph_content .comments-cnt {
2755 #graph_content .comments-cnt {
2756 color: rgb(136, 136, 136);
2756 color: rgb(136, 136, 136);
2757 padding: 5px 0;
2757 padding: 5px 0;
2758 }
2758 }
2759
2759
2760 #shortlog_data .comments-cnt {
2760 #shortlog_data .comments-cnt {
2761 color: rgb(136, 136, 136);
2761 color: rgb(136, 136, 136);
2762 padding: 3px 0;
2762 padding: 3px 0;
2763 }
2763 }
2764
2764
2765 #pull_request_overview .comments-cnt a,
2765 #pull_request_overview .comments-cnt a,
2766 #changeset_compare_view_content .comments-cnt a,
2766 #changeset_compare_view_content .comments-cnt a,
2767 #graph_content .comments-cnt a,
2767 #graph_content .comments-cnt a,
2768 #shortlog_data .comments-cnt a {
2768 #shortlog_data .comments-cnt a {
2769 background-image: url('../images/icons/comments.png');
2769 background-image: url('../images/icons/comments.png');
2770 background-repeat: no-repeat;
2770 background-repeat: no-repeat;
2771 background-position: 100% 50%;
2771 background-position: 100% 50%;
2772 padding: 5px 0;
2772 padding: 5px 0;
2773 }
2773 }
2774
2774
2775 .right .changes {
2775 .right .changes {
2776 clear: both;
2776 clear: both;
2777 }
2777 }
2778
2778
2779 .right .changes .changed_total {
2779 .right .changes .changed_total {
2780 display: block;
2780 display: block;
2781 float: right;
2781 float: right;
2782 text-align: center;
2782 text-align: center;
2783 min-width: 45px;
2783 min-width: 45px;
2784 cursor: pointer;
2784 cursor: pointer;
2785 color: #444444;
2785 color: #444444;
2786 background: #FEA;
2786 background: #FEA;
2787 -webkit-border-radius: 0px 0px 0px 6px;
2787 -webkit-border-radius: 0px 0px 0px 6px;
2788 border-radius: 0px 0px 0px 6px;
2788 border-radius: 0px 0px 0px 6px;
2789 padding: 1px;
2789 padding: 1px;
2790 }
2790 }
2791
2791
2792 .right .changes .added, .changed, .removed {
2792 .right .changes .added, .changed, .removed {
2793 display: block;
2793 display: block;
2794 padding: 1px;
2794 padding: 1px;
2795 color: #444444;
2795 color: #444444;
2796 float: right;
2796 float: right;
2797 text-align: center;
2797 text-align: center;
2798 min-width: 15px;
2798 min-width: 15px;
2799 }
2799 }
2800
2800
2801 .right .changes .added {
2801 .right .changes .added {
2802 background: #CFC;
2802 background: #CFC;
2803 }
2803 }
2804
2804
2805 .right .changes .changed {
2805 .right .changes .changed {
2806 background: #FEA;
2806 background: #FEA;
2807 }
2807 }
2808
2808
2809 .right .changes .removed {
2809 .right .changes .removed {
2810 background: #FAA;
2810 background: #FAA;
2811 }
2811 }
2812
2812
2813 .right .merge {
2813 .right .merge {
2814 padding: 1px 3px 1px 3px;
2814 padding: 1px 3px 1px 3px;
2815 background-color: #fca062;
2815 background-color: #fca062;
2816 font-size: 10px;
2816 font-size: 10px;
2817 color: #ffffff;
2817 color: #ffffff;
2818 text-transform: uppercase;
2818 text-transform: uppercase;
2819 white-space: nowrap;
2819 white-space: nowrap;
2820 -webkit-border-radius: 3px;
2820 -webkit-border-radius: 3px;
2821 border-radius: 3px;
2821 border-radius: 3px;
2822 margin-right: 2px;
2822 margin-right: 2px;
2823 }
2823 }
2824
2824
2825 .right .parent {
2825 .right .parent {
2826 color: #666666;
2826 color: #666666;
2827 clear: both;
2827 clear: both;
2828 }
2828 }
2829 .right .logtags {
2829 .right .logtags {
2830 line-height: 2.2em;
2830 line-height: 2.2em;
2831 }
2831 }
2832 .branchtag, .logtags .tagtag, .logtags .booktag {
2832 .branchtag, .logtags .tagtag, .logtags .booktag {
2833 margin: 0px 2px;
2833 margin: 0px 2px;
2834 }
2834 }
2835
2835
2836 .branchtag,
2836 .branchtag,
2837 .tagtag,
2837 .tagtag,
2838 .booktag,
2838 .booktag,
2839 .spantag {
2839 .spantag {
2840 padding: 1px 3px 1px 3px;
2840 padding: 1px 3px 1px 3px;
2841 font-size: 10px;
2841 font-size: 10px;
2842 color: #577632;
2842 color: #577632;
2843 white-space: nowrap;
2843 white-space: nowrap;
2844 -webkit-border-radius: 4px;
2844 -webkit-border-radius: 4px;
2845 border-radius: 4px;
2845 border-radius: 4px;
2846 border: 1px solid #d9e8f8;
2846 border: 1px solid #d9e8f8;
2847 line-height: 1.5em;
2847 line-height: 1.5em;
2848 }
2848 }
2849
2849
2850 #graph_content .branchtag,
2850 #graph_content .branchtag,
2851 #graph_content .tagtag,
2851 #graph_content .tagtag,
2852 #graph_content .booktag {
2852 #graph_content .booktag {
2853 margin: 1.1em 0;
2853 margin: 1.1em 0;
2854 margin-right: 0.5em;
2854 margin-right: 0.5em;
2855 }
2855 }
2856
2856
2857 .branchtag,
2857 .branchtag,
2858 .tagtag,
2858 .tagtag,
2859 .booktag {
2859 .booktag {
2860 float: left;
2860 float: left;
2861 }
2861 }
2862
2862
2863 .right .logtags .branchtag,
2863 .right .logtags .branchtag,
2864 .right .logtags .tagtag,
2864 .right .logtags .tagtag,
2865 .right .logtags .booktag,
2865 .right .logtags .booktag,
2866 .right .merge {
2866 .right .merge {
2867 float: right;
2867 float: right;
2868 line-height: 1em;
2868 line-height: 1em;
2869 margin: 1px 1px !important;
2869 margin: 1px 1px !important;
2870 display: block;
2870 display: block;
2871 }
2871 }
2872
2872
2873 .booktag {
2873 .booktag {
2874 border-color: #46A546;
2874 border-color: #46A546;
2875 color: #46A546;
2875 color: #46A546;
2876 }
2876 }
2877
2877
2878 .tagtag {
2878 .tagtag {
2879 border-color: #62cffc;
2879 border-color: #62cffc;
2880 color: #62cffc;
2880 color: #62cffc;
2881 }
2881 }
2882
2882
2883 .logtags .branchtag a:hover,
2883 .logtags .branchtag a:hover,
2884 .logtags .branchtag a,
2884 .logtags .branchtag a,
2885 .branchtag a,
2885 .branchtag a,
2886 .branchtag a:hover {
2886 .branchtag a:hover {
2887 text-decoration: none;
2887 text-decoration: none;
2888 color: inherit;
2888 color: inherit;
2889 }
2889 }
2890 .logtags .tagtag {
2890 .logtags .tagtag {
2891 padding: 1px 3px 1px 3px;
2891 padding: 1px 3px 1px 3px;
2892 background-color: #62cffc;
2892 background-color: #62cffc;
2893 font-size: 10px;
2893 font-size: 10px;
2894 color: #ffffff;
2894 color: #ffffff;
2895 white-space: nowrap;
2895 white-space: nowrap;
2896 -webkit-border-radius: 3px;
2896 -webkit-border-radius: 3px;
2897 border-radius: 3px;
2897 border-radius: 3px;
2898 }
2898 }
2899
2899
2900 .tagtag a,
2900 .tagtag a,
2901 .tagtag a:hover,
2901 .tagtag a:hover,
2902 .logtags .tagtag a,
2902 .logtags .tagtag a,
2903 .logtags .tagtag a:hover {
2903 .logtags .tagtag a:hover {
2904 text-decoration: none;
2904 text-decoration: none;
2905 color: inherit;
2905 color: inherit;
2906 }
2906 }
2907 .logbooks .booktag, .logbooks .booktag, .logtags .booktag, .logtags .booktag {
2907 .logbooks .booktag, .logbooks .booktag, .logtags .booktag, .logtags .booktag {
2908 padding: 1px 3px 1px 3px;
2908 padding: 1px 3px 1px 3px;
2909 background-color: #46A546;
2909 background-color: #46A546;
2910 font-size: 10px;
2910 font-size: 10px;
2911 color: #ffffff;
2911 color: #ffffff;
2912 white-space: nowrap;
2912 white-space: nowrap;
2913 -webkit-border-radius: 3px;
2913 -webkit-border-radius: 3px;
2914 border-radius: 3px;
2914 border-radius: 3px;
2915 }
2915 }
2916 .logbooks .booktag, .logbooks .booktag a, .right .logtags .booktag, .logtags .booktag a {
2916 .logbooks .booktag, .logbooks .booktag a, .right .logtags .booktag, .logtags .booktag a {
2917 color: #ffffff;
2917 color: #ffffff;
2918 }
2918 }
2919
2919
2920 .logbooks .booktag, .logbooks .booktag a:hover,
2920 .logbooks .booktag, .logbooks .booktag a:hover,
2921 .logtags .booktag, .logtags .booktag a:hover,
2921 .logtags .booktag, .logtags .booktag a:hover,
2922 .booktag a,
2922 .booktag a,
2923 .booktag a:hover {
2923 .booktag a:hover {
2924 text-decoration: none;
2924 text-decoration: none;
2925 color: inherit;
2925 color: inherit;
2926 }
2926 }
2927 div.browserblock {
2927 div.browserblock {
2928 overflow: hidden;
2928 overflow: hidden;
2929 border: 1px solid #ccc;
2929 border: 1px solid #ccc;
2930 background: #f8f8f8;
2930 background: #f8f8f8;
2931 font-size: 100%;
2931 font-size: 100%;
2932 line-height: 125%;
2932 line-height: 125%;
2933 padding: 0;
2933 padding: 0;
2934 -webkit-border-radius: 6px 6px 0px 0px;
2934 -webkit-border-radius: 6px 6px 0px 0px;
2935 border-radius: 6px 6px 0px 0px;
2935 border-radius: 6px 6px 0px 0px;
2936 }
2936 }
2937
2937
2938 div.browserblock .browser-header {
2938 div.browserblock .browser-header {
2939 background: #FFF;
2939 background: #FFF;
2940 padding: 10px 0px 15px 0px;
2940 padding: 10px 0px 15px 0px;
2941 width: 100%;
2941 width: 100%;
2942 }
2942 }
2943
2943
2944 div.browserblock .browser-nav {
2944 div.browserblock .browser-nav {
2945 float: left
2945 float: left
2946 }
2946 }
2947
2947
2948 div.browserblock .browser-branch {
2948 div.browserblock .browser-branch {
2949 float: left;
2949 float: left;
2950 }
2950 }
2951
2951
2952 div.browserblock .browser-branch label {
2952 div.browserblock .browser-branch label {
2953 color: #4A4A4A;
2953 color: #4A4A4A;
2954 vertical-align: text-top;
2954 vertical-align: text-top;
2955 }
2955 }
2956
2956
2957 div.browserblock .browser-header span {
2957 div.browserblock .browser-header span {
2958 margin-left: 5px;
2958 margin-left: 5px;
2959 font-weight: 700;
2959 font-weight: 700;
2960 }
2960 }
2961
2961
2962 div.browserblock .browser-search {
2962 div.browserblock .browser-search {
2963 clear: both;
2963 clear: both;
2964 padding: 8px 8px 0px 5px;
2964 padding: 8px 8px 0px 5px;
2965 height: 20px;
2965 height: 20px;
2966 }
2966 }
2967
2967
2968 div.browserblock #node_filter_box {
2968 div.browserblock #node_filter_box {
2969 }
2969 }
2970
2970
2971 div.browserblock .search_activate {
2971 div.browserblock .search_activate {
2972 float: left
2972 float: left
2973 }
2973 }
2974
2974
2975 div.browserblock .add_node {
2975 div.browserblock .add_node {
2976 float: left;
2976 float: left;
2977 padding-left: 5px;
2977 padding-left: 5px;
2978 }
2978 }
2979
2979
2980 div.browserblock .search_activate a:hover, div.browserblock .add_node a:hover {
2980 div.browserblock .search_activate a:hover, div.browserblock .add_node a:hover {
2981 text-decoration: none !important;
2981 text-decoration: none !important;
2982 }
2982 }
2983
2983
2984 div.browserblock .browser-body {
2984 div.browserblock .browser-body {
2985 background: #EEE;
2985 background: #EEE;
2986 border-top: 1px solid #CCC;
2986 border-top: 1px solid #CCC;
2987 }
2987 }
2988
2988
2989 table.code-browser {
2989 table.code-browser {
2990 border-collapse: collapse;
2990 border-collapse: collapse;
2991 width: 100%;
2991 width: 100%;
2992 }
2992 }
2993
2993
2994 table.code-browser tr {
2994 table.code-browser tr {
2995 margin: 3px;
2995 margin: 3px;
2996 }
2996 }
2997
2997
2998 table.code-browser thead th {
2998 table.code-browser thead th {
2999 background-color: #EEE;
2999 background-color: #EEE;
3000 height: 20px;
3000 height: 20px;
3001 font-size: 1.1em;
3001 font-size: 1.1em;
3002 font-weight: 700;
3002 font-weight: 700;
3003 text-align: left;
3003 text-align: left;
3004 padding-left: 10px;
3004 padding-left: 10px;
3005 }
3005 }
3006
3006
3007 table.code-browser tbody td {
3007 table.code-browser tbody td {
3008 padding-left: 10px;
3008 padding-left: 10px;
3009 height: 20px;
3009 height: 20px;
3010 }
3010 }
3011
3011
3012 table.code-browser .browser-file {
3012 table.code-browser .browser-file {
3013 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
3013 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
3014 height: 16px;
3014 height: 16px;
3015 padding-left: 20px;
3015 padding-left: 20px;
3016 text-align: left;
3016 text-align: left;
3017 }
3017 }
3018 .diffblock .changeset_header {
3018 .diffblock .changeset_header {
3019 height: 16px;
3019 height: 16px;
3020 }
3020 }
3021 .diffblock .changeset_file {
3021 .diffblock .changeset_file {
3022 float: left;
3022 float: left;
3023 }
3023 }
3024 .diffblock .diff-menu-wrapper {
3024 .diffblock .diff-menu-wrapper {
3025 float: left;
3025 float: left;
3026 }
3026 }
3027
3027
3028 .diffblock .diff-menu {
3028 .diffblock .diff-menu {
3029 position: absolute;
3029 position: absolute;
3030 background: none repeat scroll 0 0 #FFFFFF;
3030 background: none repeat scroll 0 0 #FFFFFF;
3031 border-color: #577632 #666666 #666666;
3031 border-color: #577632 #666666 #666666;
3032 border-right: 1px solid #666666;
3032 border-right: 1px solid #666666;
3033 border-style: solid solid solid;
3033 border-style: solid solid solid;
3034 border-width: 1px;
3034 border-width: 1px;
3035 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
3035 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
3036 margin-top: 5px;
3036 margin-top: 5px;
3037 margin-left: 1px;
3037 margin-left: 1px;
3038
3038
3039 }
3039 }
3040 .diffblock .diff-actions {
3040 .diffblock .diff-actions {
3041 padding: 2px 0px 0px 2px;
3041 padding: 2px 0px 0px 2px;
3042 float: left;
3042 float: left;
3043 }
3043 }
3044 .diffblock .diff-menu ul li {
3044 .diffblock .diff-menu ul li {
3045 padding: 0px 0px 0px 0px !important;
3045 padding: 0px 0px 0px 0px !important;
3046 }
3046 }
3047 .diffblock .diff-menu ul li a {
3047 .diffblock .diff-menu ul li a {
3048 display: block;
3048 display: block;
3049 padding: 3px 8px 3px 8px !important;
3049 padding: 3px 8px 3px 8px !important;
3050 }
3050 }
3051 .diffblock .diff-menu ul li a:hover {
3051 .diffblock .diff-menu ul li a:hover {
3052 text-decoration: none;
3052 text-decoration: none;
3053 background-color: #EEEEEE;
3053 background-color: #EEEEEE;
3054 }
3054 }
3055 table.code-browser .browser-dir {
3055 table.code-browser .browser-dir {
3056 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
3056 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
3057 height: 16px;
3057 height: 16px;
3058 padding-left: 20px;
3058 padding-left: 20px;
3059 text-align: left;
3059 text-align: left;
3060 }
3060 }
3061
3061
3062 table.code-browser .submodule-dir {
3062 table.code-browser .submodule-dir {
3063 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
3063 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
3064 height: 16px;
3064 height: 16px;
3065 padding-left: 20px;
3065 padding-left: 20px;
3066 text-align: left;
3066 text-align: left;
3067 }
3067 }
3068
3068
3069
3069
3070 .box .search {
3070 .box .search {
3071 clear: both;
3071 clear: both;
3072 overflow: hidden;
3072 overflow: hidden;
3073 margin: 0;
3073 margin: 0;
3074 padding: 0 20px 10px;
3074 padding: 0 20px 10px;
3075 }
3075 }
3076
3076
3077 .box .search div.search_path {
3077 .box .search div.search_path {
3078 background: none repeat scroll 0 0 #EEE;
3078 background: none repeat scroll 0 0 #EEE;
3079 border: 1px solid #CCC;
3079 border: 1px solid #CCC;
3080 color: blue;
3080 color: blue;
3081 margin-bottom: 10px;
3081 margin-bottom: 10px;
3082 padding: 10px 0;
3082 padding: 10px 0;
3083 }
3083 }
3084
3084
3085 .box .search div.search_path div.link {
3085 .box .search div.search_path div.link {
3086 font-weight: 700;
3086 font-weight: 700;
3087 margin-left: 25px;
3087 margin-left: 25px;
3088 }
3088 }
3089
3089
3090 .box .search div.search_path div.link a {
3090 .box .search div.search_path div.link a {
3091 color: #577632;
3091 color: #577632;
3092 cursor: pointer;
3092 cursor: pointer;
3093 text-decoration: none;
3093 text-decoration: none;
3094 }
3094 }
3095
3095
3096 #path_unlock {
3096 #path_unlock {
3097 color: red;
3097 color: red;
3098 font-size: 1.2em;
3098 font-size: 1.2em;
3099 padding-left: 4px;
3099 padding-left: 4px;
3100 }
3100 }
3101
3101
3102 .info_box span {
3102 .info_box span {
3103 margin-left: 3px;
3103 margin-left: 3px;
3104 margin-right: 3px;
3104 margin-right: 3px;
3105 }
3105 }
3106
3106
3107 .info_box .rev {
3107 .info_box .rev {
3108 color: #577632;
3108 color: #577632;
3109 font-size: 1.6em;
3109 font-size: 1.6em;
3110 font-weight: bold;
3110 font-weight: bold;
3111 vertical-align: sub;
3111 vertical-align: sub;
3112 }
3112 }
3113
3113
3114 .info_box input#at_rev, .info_box input#size {
3114 .info_box input#at_rev, .info_box input#size {
3115 background: #FFF;
3115 background: #FFF;
3116 border-top: 1px solid #b3b3b3;
3116 border-top: 1px solid #b3b3b3;
3117 border-left: 1px solid #b3b3b3;
3117 border-left: 1px solid #b3b3b3;
3118 border-right: 1px solid #eaeaea;
3118 border-right: 1px solid #eaeaea;
3119 border-bottom: 1px solid #eaeaea;
3119 border-bottom: 1px solid #eaeaea;
3120 color: #000;
3120 color: #000;
3121 font-size: 12px;
3121 font-size: 12px;
3122 margin: 0;
3122 margin: 0;
3123 padding: 1px 5px 1px;
3123 padding: 1px 5px 1px;
3124 }
3124 }
3125
3125
3126 .info_box input#view {
3126 .info_box input#view {
3127 text-align: center;
3127 text-align: center;
3128 padding: 4px 3px 2px 2px;
3128 padding: 4px 3px 2px 2px;
3129 }
3129 }
3130
3130
3131 .info_box_elem {
3131 .info_box_elem {
3132 display: inline-block;
3132 display: inline-block;
3133 padding: 0 2px;
3133 padding: 0 2px;
3134 }
3134 }
3135
3135
3136 .yui-overlay, .yui-panel-container {
3136 .yui-overlay, .yui-panel-container {
3137 visibility: hidden;
3137 visibility: hidden;
3138 position: absolute;
3138 position: absolute;
3139 z-index: 2;
3139 z-index: 2;
3140 }
3140 }
3141
3141
3142 #tip-box {
3142 #tip-box {
3143 position: absolute;
3143 position: absolute;
3144
3144
3145 background-color: #FFF;
3145 background-color: #FFF;
3146 border: 2px solid #577632;
3146 border: 2px solid #577632;
3147 font: 100% sans-serif;
3147 font: 100% sans-serif;
3148 width: auto;
3148 width: auto;
3149 opacity: 1;
3149 opacity: 1;
3150 padding: 8px;
3150 padding: 8px;
3151
3151
3152 white-space: pre-wrap;
3152 white-space: pre-wrap;
3153 -webkit-border-radius: 8px 8px 8px 8px;
3153 -webkit-border-radius: 8px 8px 8px 8px;
3154 -khtml-border-radius: 8px 8px 8px 8px;
3154 -khtml-border-radius: 8px 8px 8px 8px;
3155 border-radius: 8px 8px 8px 8px;
3155 border-radius: 8px 8px 8px 8px;
3156 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3156 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3157 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3157 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3158 z-index: 100000;
3158 z-index: 100000;
3159 }
3159 }
3160
3160
3161 .hl-tip-box {
3161 .hl-tip-box {
3162 z-index: 1;
3162 z-index: 1;
3163 position: absolute;
3163 position: absolute;
3164 color: #666;
3164 color: #666;
3165 background-color: #FFF;
3165 background-color: #FFF;
3166 border: 2px solid #577632;
3166 border: 2px solid #577632;
3167 font: 100% sans-serif;
3167 font: 100% sans-serif;
3168 width: auto;
3168 width: auto;
3169 opacity: 1;
3169 opacity: 1;
3170 padding: 8px;
3170 padding: 8px;
3171 white-space: pre-wrap;
3171 white-space: pre-wrap;
3172 -webkit-border-radius: 8px 8px 8px 8px;
3172 -webkit-border-radius: 8px 8px 8px 8px;
3173 -khtml-border-radius: 8px 8px 8px 8px;
3173 -khtml-border-radius: 8px 8px 8px 8px;
3174 border-radius: 8px 8px 8px 8px;
3174 border-radius: 8px 8px 8px 8px;
3175 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3175 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3176 }
3176 }
3177
3177
3178
3178
3179 .mentions-container {
3179 .mentions-container {
3180 width: 90% !important;
3180 width: 90% !important;
3181 }
3181 }
3182 .mentions-container .yui-ac-content {
3182 .mentions-container .yui-ac-content {
3183 width: 100% !important;
3183 width: 100% !important;
3184 }
3184 }
3185
3185
3186 .ac {
3186 .ac {
3187 vertical-align: top;
3187 vertical-align: top;
3188 }
3188 }
3189
3189
3190 .ac .yui-ac {
3190 .ac .yui-ac {
3191 position: inherit;
3191 position: inherit;
3192 font-size: 100%;
3192 font-size: 100%;
3193 }
3193 }
3194
3194
3195 .ac .perm_ac {
3195 .ac .perm_ac {
3196 width: 20em;
3196 width: 20em;
3197 }
3197 }
3198
3198
3199 .ac .yui-ac-input {
3199 .ac .yui-ac-input {
3200 width: 100%;
3200 width: 100%;
3201 }
3201 }
3202
3202
3203 .ac .yui-ac-container {
3203 .ac .yui-ac-container {
3204 position: absolute;
3204 position: absolute;
3205 top: 1.6em;
3205 top: 1.6em;
3206 width: auto;
3206 width: auto;
3207 }
3207 }
3208
3208
3209 .ac .yui-ac-content {
3209 .ac .yui-ac-content {
3210 position: absolute;
3210 position: absolute;
3211 border: 1px solid gray;
3211 border: 1px solid gray;
3212 background: #fff;
3212 background: #fff;
3213 z-index: 9050;
3213 z-index: 9050;
3214 }
3214 }
3215
3215
3216 .ac .yui-ac-shadow {
3216 .ac .yui-ac-shadow {
3217 position: absolute;
3217 position: absolute;
3218 width: 100%;
3218 width: 100%;
3219 background: #000;
3219 background: #000;
3220 opacity: .10;
3220 opacity: .10;
3221 filter: alpha(opacity = 10);
3221 filter: alpha(opacity = 10);
3222 z-index: 9049;
3222 z-index: 9049;
3223 margin: .3em;
3223 margin: .3em;
3224 }
3224 }
3225
3225
3226 .ac .yui-ac-content ul {
3226 .ac .yui-ac-content ul {
3227 width: 100%;
3227 width: 100%;
3228 margin: 0;
3228 margin: 0;
3229 padding: 0;
3229 padding: 0;
3230 z-index: 9050;
3230 z-index: 9050;
3231 }
3231 }
3232
3232
3233 .ac .yui-ac-content li {
3233 .ac .yui-ac-content li {
3234 cursor: default;
3234 cursor: default;
3235 white-space: nowrap;
3235 white-space: nowrap;
3236 margin: 0;
3236 margin: 0;
3237 padding: 2px 5px;
3237 padding: 2px 5px;
3238 height: 18px;
3238 height: 18px;
3239 z-index: 9050;
3239 z-index: 9050;
3240 display: block;
3240 display: block;
3241 width: auto !important;
3241 width: auto !important;
3242 }
3242 }
3243
3243
3244 .ac .yui-ac-content li .ac-container-wrap {
3244 .ac .yui-ac-content li .ac-container-wrap {
3245 width: auto;
3245 width: auto;
3246 }
3246 }
3247
3247
3248 .ac .yui-ac-content li.yui-ac-prehighlight {
3248 .ac .yui-ac-content li.yui-ac-prehighlight {
3249 background: #B3D4FF;
3249 background: #B3D4FF;
3250 z-index: 9050;
3250 z-index: 9050;
3251 }
3251 }
3252
3252
3253 .ac .yui-ac-content li.yui-ac-highlight {
3253 .ac .yui-ac-content li.yui-ac-highlight {
3254 background: #556CB5;
3254 background: #556CB5;
3255 color: #FFF;
3255 color: #FFF;
3256 z-index: 9050;
3256 z-index: 9050;
3257 }
3257 }
3258 .ac .yui-ac-bd {
3258 .ac .yui-ac-bd {
3259 z-index: 9050;
3259 z-index: 9050;
3260 }
3260 }
3261
3261
3262 .reposize {
3262 .reposize {
3263 background: url("../images/icons/server.png") no-repeat scroll 3px;
3263 background: url("../images/icons/server.png") no-repeat scroll 3px;
3264 height: 16px;
3264 height: 16px;
3265 width: 20px;
3265 width: 20px;
3266 cursor: pointer;
3266 cursor: pointer;
3267 display: block;
3267 display: block;
3268 float: right;
3268 float: right;
3269 margin-top: 2px;
3269 margin-top: 2px;
3270 }
3270 }
3271
3271
3272 #repo_size {
3272 #repo_size {
3273 display: block;
3273 display: block;
3274 margin-top: 4px;
3274 margin-top: 4px;
3275 color: #666;
3275 color: #666;
3276 float: right;
3276 float: right;
3277 }
3277 }
3278
3278
3279 .locking_locked {
3279 .locking_locked {
3280 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3280 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3281 height: 16px;
3281 height: 16px;
3282 width: 20px;
3282 width: 20px;
3283 cursor: pointer;
3283 cursor: pointer;
3284 display: block;
3284 display: block;
3285 float: right;
3285 float: right;
3286 margin-top: 2px;
3286 margin-top: 2px;
3287 }
3287 }
3288
3288
3289 .locking_unlocked {
3289 .locking_unlocked {
3290 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3290 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3291 height: 16px;
3291 height: 16px;
3292 width: 20px;
3292 width: 20px;
3293 cursor: pointer;
3293 cursor: pointer;
3294 display: block;
3294 display: block;
3295 float: right;
3295 float: right;
3296 margin-top: 2px;
3296 margin-top: 2px;
3297 }
3297 }
3298
3298
3299 .currently_following {
3299 .currently_following {
3300 padding-left: 10px;
3300 padding-left: 10px;
3301 padding-bottom: 5px;
3301 padding-bottom: 5px;
3302 }
3302 }
3303
3303
3304 .add_icon {
3304 .add_icon {
3305 background: url("../images/icons/add.png") no-repeat scroll 3px;
3305 background: url("../images/icons/add.png") no-repeat scroll 3px;
3306 padding-left: 20px;
3306 padding-left: 20px;
3307 padding-top: 0px;
3307 padding-top: 0px;
3308 text-align: left;
3308 text-align: left;
3309 }
3309 }
3310
3310
3311 .accept_icon {
3311 .accept_icon {
3312 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3312 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3313 padding-left: 20px;
3313 padding-left: 20px;
3314 padding-top: 0px;
3314 padding-top: 0px;
3315 text-align: left;
3315 text-align: left;
3316 }
3316 }
3317
3317
3318 .edit_icon {
3318 .edit_icon {
3319 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3319 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3320 padding-left: 20px;
3320 padding-left: 20px;
3321 padding-top: 0px;
3321 padding-top: 0px;
3322 text-align: left;
3322 text-align: left;
3323 }
3323 }
3324
3324
3325 .delete_icon {
3325 .delete_icon {
3326 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3326 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3327 padding-left: 20px;
3327 padding-left: 20px;
3328 padding-top: 0px;
3328 padding-top: 0px;
3329 text-align: left;
3329 text-align: left;
3330 }
3330 }
3331
3331
3332 .refresh_icon {
3332 .refresh_icon {
3333 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3333 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3334 3px;
3334 3px;
3335 padding-left: 20px;
3335 padding-left: 20px;
3336 padding-top: 0px;
3336 padding-top: 0px;
3337 text-align: left;
3337 text-align: left;
3338 }
3338 }
3339
3339
3340 .pull_icon {
3340 .pull_icon {
3341 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3341 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3342 padding-left: 20px;
3342 padding-left: 20px;
3343 padding-top: 0px;
3343 padding-top: 0px;
3344 text-align: left;
3344 text-align: left;
3345 }
3345 }
3346
3346
3347 .rss_icon {
3347 .rss_icon {
3348 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3348 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3349 padding-left: 20px;
3349 padding-left: 20px;
3350 padding-top: 4px;
3350 padding-top: 4px;
3351 text-align: left;
3351 text-align: left;
3352 font-size: 8px
3352 font-size: 8px
3353 }
3353 }
3354
3354
3355 .atom_icon {
3355 .atom_icon {
3356 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3356 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3357 padding-left: 20px;
3357 padding-left: 20px;
3358 padding-top: 4px;
3358 padding-top: 4px;
3359 text-align: left;
3359 text-align: left;
3360 font-size: 8px
3360 font-size: 8px
3361 }
3361 }
3362
3362
3363 .archive_icon {
3363 .archive_icon {
3364 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3364 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3365 padding-left: 20px;
3365 padding-left: 20px;
3366 text-align: left;
3366 text-align: left;
3367 padding-top: 1px;
3367 padding-top: 1px;
3368 }
3368 }
3369
3369
3370 .start_following_icon {
3370 .start_following_icon {
3371 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3371 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3372 padding-left: 20px;
3372 padding-left: 20px;
3373 text-align: left;
3373 text-align: left;
3374 padding-top: 0px;
3374 padding-top: 0px;
3375 }
3375 }
3376
3376
3377 .stop_following_icon {
3377 .stop_following_icon {
3378 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3378 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3379 padding-left: 20px;
3379 padding-left: 20px;
3380 text-align: left;
3380 text-align: left;
3381 padding-top: 0px;
3381 padding-top: 0px;
3382 }
3382 }
3383
3383
3384 .action_button {
3384 .action_button {
3385 border: 0;
3385 border: 0;
3386 display: inline;
3386 display: inline;
3387 }
3387 }
3388
3388
3389 .action_button:hover {
3389 .action_button:hover {
3390 border: 0;
3390 border: 0;
3391 text-decoration: underline;
3391 text-decoration: underline;
3392 cursor: pointer;
3392 cursor: pointer;
3393 }
3393 }
3394
3394
3395 #switch_repos {
3395 #switch_repos {
3396 position: absolute;
3396 position: absolute;
3397 height: 25px;
3397 height: 25px;
3398 z-index: 1;
3398 z-index: 1;
3399 }
3399 }
3400
3400
3401 #switch_repos select {
3401 #switch_repos select {
3402 min-width: 150px;
3402 min-width: 150px;
3403 max-height: 250px;
3403 max-height: 250px;
3404 z-index: 1;
3404 z-index: 1;
3405 }
3405 }
3406
3406
3407 .breadcrumbs {
3407 .breadcrumbs {
3408 border: medium none;
3408 border: medium none;
3409 color: #FFF;
3409 color: #FFF;
3410 float: left;
3410 float: left;
3411 font-weight: 700;
3411 font-weight: 700;
3412 font-size: 14px;
3412 font-size: 14px;
3413 margin: 0;
3413 margin: 0;
3414 padding: 11px 0 11px 10px;
3414 padding: 11px 0 11px 10px;
3415 }
3415 }
3416
3416
3417 .breadcrumbs .hash {
3417 .breadcrumbs .hash {
3418 text-transform: none;
3418 text-transform: none;
3419 color: #fff;
3419 color: #fff;
3420 }
3420 }
3421
3421
3422 .breadcrumbs a {
3422 .breadcrumbs a {
3423 color: #FFF;
3423 color: #FFF;
3424 }
3424 }
3425
3425
3426 .flash_msg {
3426 .flash_msg {
3427 }
3427 }
3428
3428
3429 .flash_msg ul {
3429 .flash_msg ul {
3430 }
3430 }
3431
3431
3432 .error_red {
3432 .error_red {
3433 color: red;
3433 color: red;
3434 }
3434 }
3435
3435
3436 .flash_msg .alert-error {
3436 .flash_msg .alert-error {
3437 background-color: #c43c35;
3437 background-color: #c43c35;
3438 background-repeat: repeat-x;
3438 background-repeat: repeat-x;
3439 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3439 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3440 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3440 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3441 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3441 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3442 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3442 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3443 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3443 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3444 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3444 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3445 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3445 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3446 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3446 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3447 border-color: #c43c35 #c43c35 #882a25;
3447 border-color: #c43c35 #c43c35 #882a25;
3448 }
3448 }
3449
3449
3450 .flash_msg .alert-error a {
3450 .flash_msg .alert-error a {
3451 text-decoration: underline;
3451 text-decoration: underline;
3452 }
3452 }
3453
3453
3454 .flash_msg .alert-warning {
3454 .flash_msg .alert-warning {
3455 color: #404040 !important;
3455 color: #404040 !important;
3456 background-color: #eedc94;
3456 background-color: #eedc94;
3457 background-repeat: repeat-x;
3457 background-repeat: repeat-x;
3458 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3458 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3459 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3459 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3460 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3460 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3461 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3461 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3462 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3462 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3463 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3463 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3464 background-image: linear-gradient(to bottom, #fceec1, #eedc94);
3464 background-image: linear-gradient(to bottom, #fceec1, #eedc94);
3465 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3465 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3466 border-color: #eedc94 #eedc94 #e4c652;
3466 border-color: #eedc94 #eedc94 #e4c652;
3467 }
3467 }
3468
3468
3469 .flash_msg .alert-warning a {
3469 .flash_msg .alert-warning a {
3470 text-decoration: underline;
3470 text-decoration: underline;
3471 }
3471 }
3472
3472
3473 .flash_msg .alert-success {
3473 .flash_msg .alert-success {
3474 background-color: #57a957;
3474 background-color: #57a957;
3475 background-repeat: repeat-x !important;
3475 background-repeat: repeat-x !important;
3476 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3476 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3477 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3477 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3478 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3478 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3479 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3479 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3480 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3480 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3481 background-image: -o-linear-gradient(top, #62c462, #57a957);
3481 background-image: -o-linear-gradient(top, #62c462, #57a957);
3482 background-image: linear-gradient(to bottom, #62c462, #57a957);
3482 background-image: linear-gradient(to bottom, #62c462, #57a957);
3483 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3483 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3484 border-color: #57a957 #57a957 #3d773d;
3484 border-color: #57a957 #57a957 #3d773d;
3485 }
3485 }
3486
3486
3487 .flash_msg .alert-success a {
3487 .flash_msg .alert-success a {
3488 text-decoration: underline;
3488 text-decoration: underline;
3489 color: #FFF !important;
3489 color: #FFF !important;
3490 }
3490 }
3491
3491
3492 .flash_msg .alert-info {
3492 .flash_msg .alert-info {
3493 background-color: #339bb9;
3493 background-color: #339bb9;
3494 background-repeat: repeat-x;
3494 background-repeat: repeat-x;
3495 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3495 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3496 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3496 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3497 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3497 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3498 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3498 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3499 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3499 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3500 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3500 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3501 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3501 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3502 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3502 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3503 border-color: #339bb9 #339bb9 #22697d;
3503 border-color: #339bb9 #339bb9 #22697d;
3504 }
3504 }
3505
3505
3506 .flash_msg .alert-info a {
3506 .flash_msg .alert-info a {
3507 text-decoration: underline;
3507 text-decoration: underline;
3508 }
3508 }
3509
3509
3510 .flash_msg .alert-error,
3510 .flash_msg .alert-error,
3511 .flash_msg .alert-warning,
3511 .flash_msg .alert-warning,
3512 .flash_msg .alert-success,
3512 .flash_msg .alert-success,
3513 .flash_msg .alert-info {
3513 .flash_msg .alert-info {
3514 font-size: 12px;
3514 font-size: 12px;
3515 font-weight: 700;
3515 font-weight: 700;
3516 min-height: 14px;
3516 min-height: 14px;
3517 line-height: 14px;
3517 line-height: 14px;
3518 margin-bottom: 10px;
3518 margin-bottom: 10px;
3519 margin-top: 0;
3519 margin-top: 0;
3520 display: block;
3520 display: block;
3521 overflow: auto;
3521 overflow: auto;
3522 padding: 6px 10px 6px 10px;
3522 padding: 6px 10px 6px 10px;
3523 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3523 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3524 position: relative;
3524 position: relative;
3525 color: #FFF;
3525 color: #FFF;
3526 border-width: 1px;
3526 border-width: 1px;
3527 border-style: solid;
3527 border-style: solid;
3528 -webkit-border-radius: 4px;
3528 -webkit-border-radius: 4px;
3529 border-radius: 4px;
3529 border-radius: 4px;
3530 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3530 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3531 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3531 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3532 }
3532 }
3533
3533
3534 #msg_close {
3534 #msg_close {
3535 background: transparent url("../images/cross_grey_small.png") no-repeat scroll 0 0;
3535 background: transparent url("../images/cross_grey_small.png") no-repeat scroll 0 0;
3536 cursor: pointer;
3536 cursor: pointer;
3537 height: 16px;
3537 height: 16px;
3538 position: absolute;
3538 position: absolute;
3539 right: 5px;
3539 right: 5px;
3540 top: 5px;
3540 top: 5px;
3541 width: 16px;
3541 width: 16px;
3542 }
3542 }
3543 div#legend_data {
3543 div#legend_data {
3544 padding-left: 10px;
3544 padding-left: 10px;
3545 }
3545 }
3546 div#legend_container table {
3546 div#legend_container table {
3547 border: none !important;
3547 border: none !important;
3548 }
3548 }
3549 div#legend_container table, div#legend_choices table {
3549 div#legend_container table, div#legend_choices table {
3550 width: auto !important;
3550 width: auto !important;
3551 }
3551 }
3552
3552
3553 table#permissions_manage {
3553 table#permissions_manage {
3554 width: 0 !important;
3554 width: 0 !important;
3555 }
3555 }
3556
3556
3557 table#permissions_manage span.private_repo_msg {
3557 table#permissions_manage span.private_repo_msg {
3558 font-size: 0.8em;
3558 font-size: 0.8em;
3559 opacity: 0.6;
3559 opacity: 0.6;
3560 }
3560 }
3561
3561
3562 table#permissions_manage td.private_repo_msg {
3562 table#permissions_manage td.private_repo_msg {
3563 font-size: 0.8em;
3563 font-size: 0.8em;
3564 }
3564 }
3565
3565
3566 table#permissions_manage tr#add_perm_input td {
3566 table#permissions_manage tr#add_perm_input td {
3567 vertical-align: middle;
3567 vertical-align: middle;
3568 }
3568 }
3569
3569
3570 div.gravatar {
3570 div.gravatar {
3571 background-color: #FFF;
3571 background-color: #FFF;
3572 float: left;
3572 float: left;
3573 margin-right: 0.7em;
3573 margin-right: 0.7em;
3574 padding: 1px 1px 1px 1px;
3574 padding: 1px 1px 1px 1px;
3575 line-height: 0;
3575 line-height: 0;
3576 -webkit-border-radius: 3px;
3576 -webkit-border-radius: 3px;
3577 -khtml-border-radius: 3px;
3577 -khtml-border-radius: 3px;
3578 border-radius: 3px;
3578 border-radius: 3px;
3579 }
3579 }
3580
3580
3581 div.gravatar img {
3581 div.gravatar img {
3582 -webkit-border-radius: 2px;
3582 -webkit-border-radius: 2px;
3583 -khtml-border-radius: 2px;
3583 -khtml-border-radius: 2px;
3584 border-radius: 2px;
3584 border-radius: 2px;
3585 }
3585 }
3586
3586
3587 #header, #content, #footer {
3587 #header, #content, #footer {
3588 min-width: 978px;
3588 min-width: 978px;
3589 }
3589 }
3590
3590
3591 #content {
3591 #content {
3592 clear: both;
3592 clear: both;
3593 padding: 10px 10px 14px 10px;
3593 padding: 10px 10px 14px 10px;
3594 }
3594 }
3595
3595
3596 #content.hover {
3596 #content.hover {
3597 padding: 55px 10px 14px 10px !important;
3597 padding: 55px 10px 14px 10px !important;
3598 }
3598 }
3599
3599
3600 #content div.box div.title div.search {
3600 #content div.box div.title div.search {
3601 border-left: 1px solid #576622;
3601 border-left: 1px solid #576622;
3602 }
3602 }
3603
3603
3604 #content div.box div.title div.search div.input input {
3604 #content div.box div.title div.search div.input input {
3605 border: 1px solid #576622;
3605 border: 1px solid #576622;
3606 }
3606 }
3607
3607
3608 .btn {
3608 .btn {
3609 color: #515151;
3609 color: #515151;
3610 background-color: #DADADA;
3610 background-color: #DADADA;
3611 background-repeat: repeat-x;
3611 background-repeat: repeat-x;
3612 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3612 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3613 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3613 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3614 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3614 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3615 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3615 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3616 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3616 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3617 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3617 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3618 background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
3618 background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
3619 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3619 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3620
3620
3621 border-top: 1px solid #DDD;
3621 border-top: 1px solid #DDD;
3622 border-left: 1px solid #c6c6c6;
3622 border-left: 1px solid #c6c6c6;
3623 border-right: 1px solid #DDD;
3623 border-right: 1px solid #DDD;
3624 border-bottom: 1px solid #c6c6c6;
3624 border-bottom: 1px solid #c6c6c6;
3625 color: #515151;
3625 color: #515151;
3626 outline: none;
3626 outline: none;
3627 margin: 0px 3px 3px 0px;
3627 margin: 0px 3px 3px 0px;
3628 -webkit-border-radius: 4px 4px 4px 4px !important;
3628 -webkit-border-radius: 4px 4px 4px 4px !important;
3629 -khtml-border-radius: 4px 4px 4px 4px !important;
3629 -khtml-border-radius: 4px 4px 4px 4px !important;
3630 border-radius: 4px 4px 4px 4px !important;
3630 border-radius: 4px 4px 4px 4px !important;
3631 cursor: pointer !important;
3631 cursor: pointer !important;
3632 padding: 3px 3px 3px 3px;
3632 padding: 3px 3px 3px 3px;
3633 background-position: 0 -100px;
3633 background-position: 0 -100px;
3634 display: inline-block;
3634 display: inline-block;
3635 }
3635 }
3636
3636
3637 ul.nav-stacked {
3637 ul.nav-stacked {
3638 margin: 20px;
3638 margin: 20px;
3639 color: #393939;
3639 color: #393939;
3640 font-weight: 700;
3640 font-weight: 700;
3641 }
3641 }
3642
3642
3643 ul.nav-stacked a {
3643 ul.nav-stacked a {
3644 color: inherit;
3644 color: inherit;
3645 }
3645 }
3646
3646
3647 /* make .btn inputs and buttons and divs look the same */
3647 /* make .btn inputs and buttons and divs look the same */
3648 button.btn,
3648 button.btn,
3649 input.btn {
3649 input.btn {
3650 font-family: inherit;
3650 font-family: inherit;
3651 font-size: inherit;
3651 font-size: inherit;
3652 line-height: inherit;
3652 line-height: inherit;
3653 }
3653 }
3654
3654
3655 .btn::-moz-focus-inner {
3655 .btn::-moz-focus-inner {
3656 border: 0;
3656 border: 0;
3657 padding: 0;
3657 padding: 0;
3658 }
3658 }
3659
3659
3660 /* make .btn inputs and buttons and divs look the same */
3660 /* make .btn inputs and buttons and divs look the same */
3661 button.btn,
3661 button.btn,
3662 input.btn {
3662 input.btn {
3663 font-family: inherit;
3663 font-family: inherit;
3664 font-size: inherit;
3664 font-size: inherit;
3665 line-height: inherit;
3665 line-height: inherit;
3666 }
3666 }
3667
3667
3668 .btn::-moz-focus-inner {
3668 .btn::-moz-focus-inner {
3669 border: 0;
3669 border: 0;
3670 padding: 0;
3670 padding: 0;
3671 }
3671 }
3672
3672
3673 .btn.badge {
3673 .btn.badge {
3674 cursor: default !important;
3674 cursor: default !important;
3675 }
3675 }
3676
3676
3677 .btn.disabled {
3677 .btn.disabled {
3678 color: #999;
3678 color: #999;
3679 }
3679 }
3680
3680
3681 .btn.btn-danger.disabled {
3681 .btn.btn-danger.disabled {
3682 color: #eee;
3682 color: #eee;
3683 background-color: #c77;
3683 background-color: #c77;
3684 border-color: #b66
3684 border-color: #b66
3685 }
3685 }
3686
3686
3687 .btn.btn-small {
3687 .btn.btn-small {
3688 padding: 2px 6px;
3688 padding: 2px 6px;
3689 }
3689 }
3690
3690
3691 .btn.btn-mini {
3691 .btn.btn-mini {
3692 padding: 0px 4px;
3692 padding: 0px 4px;
3693 }
3693 }
3694
3694
3695 .btn.clone {
3695 .btn.clone {
3696 padding: 5px 2px 6px 1px;
3696 padding: 5px 2px 6px 1px;
3697 margin: 0px 0px 3px -4px;
3697 margin: 0px 0px 3px -4px;
3698 -webkit-border-radius: 0px 4px 4px 0px !important;
3698 -webkit-border-radius: 0px 4px 4px 0px !important;
3699 -khtml-border-radius: 0px 4px 4px 0px !important;
3699 -khtml-border-radius: 0px 4px 4px 0px !important;
3700 border-radius: 0px 4px 4px 0px !important;
3700 border-radius: 0px 4px 4px 0px !important;
3701 width: 100px;
3701 width: 100px;
3702 text-align: center;
3702 text-align: center;
3703 display: inline-block;
3703 display: inline-block;
3704 position: relative;
3704 position: relative;
3705 top: -2px;
3705 top: -2px;
3706 }
3706 }
3707 .btn:focus {
3707 .btn:focus {
3708 outline: none;
3708 outline: none;
3709 }
3709 }
3710 .btn:hover {
3710 .btn:hover {
3711 background-position: 0 -100px;
3711 background-position: 0 -100px;
3712 text-decoration: none;
3712 text-decoration: none;
3713 color: #515151;
3713 color: #515151;
3714 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3714 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3715 }
3715 }
3716 .btn.badge:hover {
3716 .btn.badge:hover {
3717 box-shadow: none !important;
3717 box-shadow: none !important;
3718 }
3718 }
3719 .btn.disabled:hover {
3719 .btn.disabled:hover {
3720 background-position: 0;
3720 background-position: 0;
3721 color: #999;
3721 color: #999;
3722 text-decoration: none;
3722 text-decoration: none;
3723 box-shadow: none !important;
3723 box-shadow: none !important;
3724 }
3724 }
3725
3725
3726 .btn.red {
3726 .btn.red {
3727 color: #fff;
3727 color: #fff;
3728 background-color: #c43c35;
3728 background-color: #c43c35;
3729 background-repeat: repeat-x;
3729 background-repeat: repeat-x;
3730 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3730 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3731 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3731 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3732 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3732 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3733 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3733 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3734 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3734 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3735 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3735 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3736 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3736 background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
3737 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3737 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3738 border-color: #c43c35 #c43c35 #882a25;
3738 border-color: #c43c35 #c43c35 #882a25;
3739 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3739 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3740 }
3740 }
3741
3741
3742
3742
3743 .btn.blue {
3743 .btn.blue {
3744 color: #fff;
3744 color: #fff;
3745 background-color: #339bb9;
3745 background-color: #339bb9;
3746 background-repeat: repeat-x;
3746 background-repeat: repeat-x;
3747 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3747 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3748 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3748 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3749 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3749 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3750 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3750 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3751 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3751 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3752 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3752 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3753 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3753 background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
3754 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3754 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3755 border-color: #339bb9 #339bb9 #22697d;
3755 border-color: #339bb9 #339bb9 #22697d;
3756 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3756 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3757 }
3757 }
3758
3758
3759 .btn.green {
3759 .btn.green {
3760 color: #fff;
3760 color: #fff;
3761 background-color: #57a957;
3761 background-color: #57a957;
3762 background-repeat: repeat-x;
3762 background-repeat: repeat-x;
3763 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3763 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3764 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3764 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3765 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3765 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3766 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3766 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3767 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3767 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3768 background-image: -o-linear-gradient(top, #62c462, #57a957);
3768 background-image: -o-linear-gradient(top, #62c462, #57a957);
3769 background-image: linear-gradient(to bottom, #62c462, #57a957);
3769 background-image: linear-gradient(to bottom, #62c462, #57a957);
3770 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3770 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3771 border-color: #57a957 #57a957 #3d773d;
3771 border-color: #57a957 #57a957 #3d773d;
3772 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3772 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3773 }
3773 }
3774
3774
3775 .btn.yellow {
3775 .btn.yellow {
3776 color: #fff;
3776 color: #fff;
3777 background-color: #faa732;
3777 background-color: #faa732;
3778 background-repeat: repeat-x;
3778 background-repeat: repeat-x;
3779 background-image: -khtml-gradient(linear, left top, left bottom, from(#fbb450), to(#f89406));
3779 background-image: -khtml-gradient(linear, left top, left bottom, from(#fbb450), to(#f89406));
3780 background-image: -moz-linear-gradient(top, #fbb450, #f89406);
3780 background-image: -moz-linear-gradient(top, #fbb450, #f89406);
3781 background-image: -ms-linear-gradient(top, #fbb450, #f89406);
3781 background-image: -ms-linear-gradient(top, #fbb450, #f89406);
3782 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fbb450), color-stop(100%, #f89406));
3782 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fbb450), color-stop(100%, #f89406));
3783 background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
3783 background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
3784 background-image: -o-linear-gradient(top, #fbb450, #f89406);
3784 background-image: -o-linear-gradient(top, #fbb450, #f89406);
3785 background-image: linear-gradient(to bottom, #fbb450, #f89406);
3785 background-image: linear-gradient(to bottom, #fbb450, #f89406);
3786 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
3786 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
3787 border-color: #f89406 #f89406 #ad6704;
3787 border-color: #f89406 #f89406 #ad6704;
3788 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3788 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3789 }
3789 }
3790
3790
3791 label.disabled {
3791 label.disabled {
3792 color: #aaa;
3792 color: #aaa;
3793 }
3793 }
3794
3794
3795 .btn.blue.hidden {
3795 .btn.blue.hidden {
3796 display: none;
3796 display: none;
3797 }
3797 }
3798
3798
3799 .btn.active {
3799 .btn.active {
3800 font-weight: bold;
3800 font-weight: bold;
3801 }
3801 }
3802
3802
3803 ins, div.options a:hover {
3803 ins, div.options a:hover {
3804 text-decoration: none;
3804 text-decoration: none;
3805 }
3805 }
3806
3806
3807 img,
3807 img,
3808 #header #header-inner #quick li a:hover span.normal,
3808 #header #header-inner #quick li a:hover span.normal,
3809 #content div.box div.form div.fields div.field div.textarea table td table td a,
3809 #content div.box div.form div.fields div.field div.textarea table td table td a,
3810 #clone_url,
3810 #clone_url,
3811 #clone_url_id
3811 #clone_url_id
3812 {
3812 {
3813 border: none;
3813 border: none;
3814 }
3814 }
3815
3815
3816 img.icon, .right .merge img {
3816 img.icon, .right .merge img {
3817 vertical-align: bottom;
3817 vertical-align: bottom;
3818 }
3818 }
3819
3819
3820 #header ul#logged-user, #content div.box div.title ul.links,
3820 #header ul#logged-user, #content div.box div.title ul.links,
3821 #content div.box div.message div.dismiss,
3821 #content div.box div.message div.dismiss,
3822 #content div.box div.traffic div.legend ul {
3822 #content div.box div.traffic div.legend ul {
3823 float: right;
3823 float: right;
3824 margin: 0;
3824 margin: 0;
3825 padding: 0;
3825 padding: 0;
3826 }
3826 }
3827
3827
3828 #header #header-inner #home, #header #header-inner #logo,
3828 #header #header-inner #home, #header #header-inner #logo,
3829 #content div.box ul.left, #content div.box ol.left,
3829 #content div.box ul.left, #content div.box ol.left,
3830 div#commit_history,
3830 div#commit_history,
3831 div#legend_data, div#legend_container, div#legend_choices {
3831 div#legend_data, div#legend_container, div#legend_choices {
3832 float: left;
3832 float: left;
3833 }
3833 }
3834
3834
3835 #header #header-inner #quick li #quick_login,
3835 #header #header-inner #quick li #quick_login,
3836 #header #header-inner #quick li:hover ul ul,
3836 #header #header-inner #quick li:hover ul ul,
3837 #header #header-inner #quick li:hover ul ul ul,
3837 #header #header-inner #quick li:hover ul ul ul,
3838 #header #header-inner #quick li:hover ul ul ul ul,
3838 #header #header-inner #quick li:hover ul ul ul ul,
3839 #content #left #menu ul.closed, #content #left #menu li ul.collapsed, .yui-tt-shadow {
3839 #content #left #menu ul.closed, #content #left #menu li ul.collapsed, .yui-tt-shadow {
3840 display: none;
3840 display: none;
3841 }
3841 }
3842
3842
3843 #header #header-inner #quick li:hover #quick_login,
3843 #header #header-inner #quick li:hover #quick_login,
3844 #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 {
3844 #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 {
3845 display: block;
3845 display: block;
3846 }
3846 }
3847
3847
3848 .repo-switcher .select2-choice {
3848 .repo-switcher .select2-choice {
3849 padding: 0px 8px 1px !important;
3849 padding: 0px 8px 1px !important;
3850 display: block;
3850 display: block;
3851 height: 100%;
3851 height: 100%;
3852 }
3852 }
3853
3853
3854 .repo-switcher .select2-container,
3854 .repo-switcher .select2-container,
3855 .repo-switcher .select2-choice,
3855 .repo-switcher .select2-choice,
3856 .repo-switcher .select2-choice span {
3856 .repo-switcher .select2-choice span {
3857 background: transparent !important;
3857 background: transparent !important;
3858 border: 0 !important;
3858 border: 0 !important;
3859 box-shadow: none !important;
3859 box-shadow: none !important;
3860 color: #FFFFFF !important;
3860 color: #FFFFFF !important;
3861 }
3861 }
3862
3862
3863 .repo-switcher .select2-arrow {
3863 .repo-switcher .select2-arrow {
3864 display: none !important;
3864 display: none !important;
3865 }
3865 }
3866
3866
3867 .repo-switcher .select2-chosen:after {
3867 .repo-switcher .select2-chosen:after {
3868 content: ' \25BE';
3868 content: ' \25BE';
3869 }
3869 }
3870
3870
3871 .repo-switcher-dropdown.select2-drop.select2-drop-active {
3871 .repo-switcher-dropdown.select2-drop.select2-drop-active {
3872 xborder-color: black;
3872 xborder-color: black;
3873 -webkit-box-shadow: none;
3873 -webkit-box-shadow: none;
3874 -moz-box-shadow: none;
3874 -moz-box-shadow: none;
3875 box-shadow: none;
3875 box-shadow: none;
3876 color: #fff;
3876 color: #fff;
3877 background-color: #576622;
3877 background-color: #576622;
3878 }
3878 }
3879
3879
3880 .repo-switcher-dropdown.select2-drop.select2-drop-active .select2-results .select2-highlighted {
3880 .repo-switcher-dropdown.select2-drop.select2-drop-active .select2-results .select2-highlighted {
3881 background-color: #6388ad;
3881 background-color: #6388ad;
3882 }
3882 }
3883
3883
3884 #content div.graph {
3884 #content div.graph {
3885 padding: 0 10px 10px;
3885 padding: 0 10px 10px;
3886 }
3886 }
3887
3887
3888 #content div.box div.title ul.links li a:hover,
3888 #content div.box div.title ul.links li a:hover,
3889 #content div.box div.title ul.links li.ui-tabs-selected a {
3889 #content div.box div.title ul.links li.ui-tabs-selected a {
3890
3890
3891 background: #6388ad; /* Old browsers */
3891 background: #6388ad; /* Old browsers */
3892 background: -moz-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
3892 background: -moz-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
3893 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
3893 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
3894 background: -webkit-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
3894 background: -webkit-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
3895 background: -o-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Opera 11.10+ */
3895 background: -o-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Opera 11.10+ */
3896 background: -ms-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* IE10+ */
3896 background: -ms-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* IE10+ */
3897 background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* W3C */
3897 background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* W3C */
3898 /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88bfe8', endColorstr='#70b0e0',GradientType=0 ); /* IE6-9 */
3898 /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88bfe8', endColorstr='#70b0e0',GradientType=0 ); /* IE6-9 */
3899 }
3899 }
3900
3900
3901 #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 {
3901 #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 {
3902 margin: 10px 24px 10px 44px;
3902 margin: 10px 24px 10px 44px;
3903 }
3903 }
3904
3904
3905 #content div.box div.form, #content div.box div.table, #content div.box div.traffic {
3905 #content div.box div.form, #content div.box div.table, #content div.box div.traffic {
3906 position: relative;
3906 position: relative;
3907 clear: both;
3907 clear: both;
3908 margin: 0;
3908 margin: 0;
3909 padding: 0 20px 10px;
3909 padding: 0 20px 10px;
3910 }
3910 }
3911
3911
3912 #content div.box div.form div.fields, #login div.form, #login div.form div.fields, #register div.form, #register div.form div.fields {
3912 #content div.box div.form div.fields, #login div.form, #login div.form div.fields, #register div.form, #register div.form div.fields {
3913 clear: both;
3913 clear: both;
3914 overflow: hidden;
3914 overflow: hidden;
3915 margin: 0;
3915 margin: 0;
3916 padding: 0;
3916 padding: 0;
3917 }
3917 }
3918
3918
3919 #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 {
3919 #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 {
3920 height: 1%;
3920 height: 1%;
3921 display: block;
3921 display: block;
3922 color: #363636;
3922 color: #363636;
3923 margin: 0;
3923 margin: 0;
3924 padding: 2px 0 0;
3924 padding: 2px 0 0;
3925 }
3925 }
3926
3926
3927 #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 {
3927 #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 {
3928 background: #FBE3E4;
3928 background: #FBE3E4;
3929 border-top: 1px solid #e1b2b3;
3929 border-top: 1px solid #e1b2b3;
3930 border-left: 1px solid #e1b2b3;
3930 border-left: 1px solid #e1b2b3;
3931 border-right: 1px solid #FBC2C4;
3931 border-right: 1px solid #FBC2C4;
3932 border-bottom: 1px solid #FBC2C4;
3932 border-bottom: 1px solid #FBC2C4;
3933 }
3933 }
3934
3934
3935 #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 {
3935 #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 {
3936 background: #E6EFC2;
3936 background: #E6EFC2;
3937 border-top: 1px solid #cebb98;
3937 border-top: 1px solid #cebb98;
3938 border-left: 1px solid #cebb98;
3938 border-left: 1px solid #cebb98;
3939 border-right: 1px solid #c6d880;
3939 border-right: 1px solid #c6d880;
3940 border-bottom: 1px solid #c6d880;
3940 border-bottom: 1px solid #c6d880;
3941 }
3941 }
3942
3942
3943 #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 {
3943 #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 {
3944 margin: 0;
3944 margin: 0;
3945 }
3945 }
3946
3946
3947 #content div.box-left div.form div.fields div.field div.select, #content div.box-left div.form div.fields div.field div.checkboxes, #content div.box-left div.form div.fields div.field div.radios, #content div.box-right div.form div.fields div.field div.select, #content div.box-right div.form div.fields div.field div.checkboxes, #content div.box-right div.form div.fields div.field div.radios {
3947 #content div.box-left div.form div.fields div.field div.select, #content div.box-left div.form div.fields div.field div.checkboxes, #content div.box-left div.form div.fields div.field div.radios, #content div.box-right div.form div.fields div.field div.select, #content div.box-right div.form div.fields div.field div.checkboxes, #content div.box-right div.form div.fields div.field div.radios {
3948 margin: 0 0 0 0px !important;
3948 margin: 0 0 0 0px !important;
3949 padding: 0;
3949 padding: 0;
3950 }
3950 }
3951
3951
3952 #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 {
3952 #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 {
3953 margin: 0 0 0 200px;
3953 margin: 0 0 0 200px;
3954 padding: 0;
3954 padding: 0;
3955 }
3955 }
3956
3956
3957 #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 {
3957 #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 {
3958 color: #000;
3958 color: #000;
3959 text-decoration: none;
3959 text-decoration: none;
3960 }
3960 }
3961
3961
3962 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus, #content div.box div.action a.ui-selectmenu-focus {
3962 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus, #content div.box div.action a.ui-selectmenu-focus {
3963 border: 1px solid #666;
3963 border: 1px solid #666;
3964 }
3964 }
3965
3965
3966 #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 {
3966 #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 {
3967 clear: both;
3967 clear: both;
3968 overflow: hidden;
3968 overflow: hidden;
3969 margin: 0;
3969 margin: 0;
3970 padding: 8px 0 2px;
3970 padding: 8px 0 2px;
3971 }
3971 }
3972
3972
3973 #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 {
3973 #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 {
3974 float: left;
3974 float: left;
3975 margin: 0;
3975 margin: 0;
3976 }
3976 }
3977
3977
3978 #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 {
3978 #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 {
3979 height: 1%;
3979 height: 1%;
3980 display: block;
3980 display: block;
3981 float: left;
3981 float: left;
3982 margin: 2px 0 0 4px;
3982 margin: 2px 0 0 4px;
3983 }
3983 }
3984
3984
3985 div.form div.fields div.field div.button input,
3985 div.form div.fields div.field div.button input,
3986 #content div.box div.form div.fields div.buttons input
3986 #content div.box div.form div.fields div.buttons input
3987 div.form div.fields div.buttons input,
3987 div.form div.fields div.buttons input,
3988 #content div.box div.action div.button input {
3988 #content div.box div.action div.button input {
3989 font-size: 11px;
3989 font-size: 11px;
3990 font-weight: 700;
3990 font-weight: 700;
3991 margin: 0;
3991 margin: 0;
3992 }
3992 }
3993
3993
3994 input.ui-button {
3994 input.ui-button {
3995 background: #e5e3e3 url("../images/button.png") repeat-x;
3995 background: #e5e3e3 url("../images/button.png") repeat-x;
3996 border-top: 1px solid #DDD;
3996 border-top: 1px solid #DDD;
3997 border-left: 1px solid #c6c6c6;
3997 border-left: 1px solid #c6c6c6;
3998 border-right: 1px solid #DDD;
3998 border-right: 1px solid #DDD;
3999 border-bottom: 1px solid #c6c6c6;
3999 border-bottom: 1px solid #c6c6c6;
4000 color: #515151 !important;
4000 color: #515151 !important;
4001 outline: none;
4001 outline: none;
4002 margin: 0;
4002 margin: 0;
4003 padding: 6px 12px;
4003 padding: 6px 12px;
4004 -webkit-border-radius: 4px 4px 4px 4px;
4004 -webkit-border-radius: 4px 4px 4px 4px;
4005 -khtml-border-radius: 4px 4px 4px 4px;
4005 -khtml-border-radius: 4px 4px 4px 4px;
4006 border-radius: 4px 4px 4px 4px;
4006 border-radius: 4px 4px 4px 4px;
4007 box-shadow: 0 1px 0 #ececec;
4007 box-shadow: 0 1px 0 #ececec;
4008 cursor: pointer;
4008 cursor: pointer;
4009 }
4009 }
4010
4010
4011 input.ui-button:hover {
4011 input.ui-button:hover {
4012 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
4012 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
4013 border-top: 1px solid #ccc;
4013 border-top: 1px solid #ccc;
4014 border-left: 1px solid #bebebe;
4014 border-left: 1px solid #bebebe;
4015 border-right: 1px solid #b1b1b1;
4015 border-right: 1px solid #b1b1b1;
4016 border-bottom: 1px solid #afafaf;
4016 border-bottom: 1px solid #afafaf;
4017 }
4017 }
4018
4018
4019 div.form div.fields div.field div.highlight, #content div.box div.form div.fields div.buttons div.highlight {
4019 div.form div.fields div.field div.highlight, #content div.box div.form div.fields div.buttons div.highlight {
4020 display: inline;
4020 display: inline;
4021 }
4021 }
4022
4022
4023 #content div.box div.form div.fields div.buttons, div.form div.fields div.buttons {
4023 #content div.box div.form div.fields div.buttons, div.form div.fields div.buttons {
4024 margin: 10px 0 0 200px;
4024 margin: 10px 0 0 200px;
4025 padding: 0;
4025 padding: 0;
4026 }
4026 }
4027
4027
4028 #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 {
4028 #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 {
4029 margin: 10px 0 0;
4029 margin: 10px 0 0;
4030 }
4030 }
4031
4031
4032 #content div.box table td.user, #content div.box table td.address {
4032 #content div.box table td.user, #content div.box table td.address {
4033 width: 10%;
4033 width: 10%;
4034 text-align: center;
4034 text-align: center;
4035 }
4035 }
4036
4036
4037 #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 {
4037 #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 {
4038 text-align: right;
4038 text-align: right;
4039 margin: 6px 0 0;
4039 margin: 6px 0 0;
4040 padding: 0;
4040 padding: 0;
4041 }
4041 }
4042
4042
4043 #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 {
4043 #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 {
4044 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
4044 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
4045 border-top: 1px solid #ccc;
4045 border-top: 1px solid #ccc;
4046 border-left: 1px solid #bebebe;
4046 border-left: 1px solid #bebebe;
4047 border-right: 1px solid #b1b1b1;
4047 border-right: 1px solid #b1b1b1;
4048 border-bottom: 1px solid #afafaf;
4048 border-bottom: 1px solid #afafaf;
4049 color: #515151;
4049 color: #515151;
4050 margin: 0;
4050 margin: 0;
4051 padding: 6px 12px;
4051 padding: 6px 12px;
4052 }
4052 }
4053
4053
4054 #content div.box div.pagination div.results, #content div.box div.pagination-wh div.results {
4054 #content div.box div.pagination div.results, #content div.box div.pagination-wh div.results {
4055 text-align: left;
4055 text-align: left;
4056 float: left;
4056 float: left;
4057 margin: 0;
4057 margin: 0;
4058 padding: 0;
4058 padding: 0;
4059 }
4059 }
4060
4060
4061 #content div.box div.pagination div.results span, #content div.box div.pagination-wh div.results span {
4061 #content div.box div.pagination div.results span, #content div.box div.pagination-wh div.results span {
4062 height: 1%;
4062 height: 1%;
4063 display: block;
4063 display: block;
4064 float: left;
4064 float: left;
4065 background: #ebebeb url("../images/pager.png") repeat-x;
4065 background: #ebebeb url("../images/pager.png") repeat-x;
4066 border-top: 1px solid #dedede;
4066 border-top: 1px solid #dedede;
4067 border-left: 1px solid #cfcfcf;
4067 border-left: 1px solid #cfcfcf;
4068 border-right: 1px solid #c4c4c4;
4068 border-right: 1px solid #c4c4c4;
4069 border-bottom: 1px solid #c4c4c4;
4069 border-bottom: 1px solid #c4c4c4;
4070 color: #4A4A4A;
4070 color: #4A4A4A;
4071 font-weight: 700;
4071 font-weight: 700;
4072 margin: 0;
4072 margin: 0;
4073 padding: 6px 8px;
4073 padding: 6px 8px;
4074 }
4074 }
4075
4075
4076 #content div.box div.pagination ul.pager li.disabled, #content div.box div.pagination-wh a.disabled {
4076 #content div.box div.pagination ul.pager li.disabled, #content div.box div.pagination-wh a.disabled {
4077 color: #B4B4B4;
4077 color: #B4B4B4;
4078 padding: 6px;
4078 padding: 6px;
4079 }
4079 }
4080
4080
4081 #login, #register {
4081 #login, #register {
4082 width: 520px;
4082 width: 520px;
4083 margin: 10% auto 0;
4083 margin: 10% auto 0;
4084 padding: 0;
4084 padding: 0;
4085 }
4085 }
4086
4086
4087 #login div.color, #register div.color {
4087 #login div.color, #register div.color {
4088 clear: both;
4088 clear: both;
4089 overflow: hidden;
4089 overflow: hidden;
4090 background: #FFF;
4090 background: #FFF;
4091 margin: 10px auto 0;
4091 margin: 10px auto 0;
4092 padding: 3px 3px 3px 0;
4092 padding: 3px 3px 3px 0;
4093 }
4093 }
4094
4094
4095 #login div.color a, #register div.color a {
4095 #login div.color a, #register div.color a {
4096 width: 20px;
4096 width: 20px;
4097 height: 20px;
4097 height: 20px;
4098 display: block;
4098 display: block;
4099 float: left;
4099 float: left;
4100 margin: 0 0 0 3px;
4100 margin: 0 0 0 3px;
4101 padding: 0;
4101 padding: 0;
4102 }
4102 }
4103
4103
4104 #login div.title h5, #register div.title h5 {
4104 #login div.title h5, #register div.title h5 {
4105 color: #fff;
4105 color: #fff;
4106 margin: 10px;
4106 margin: 10px;
4107 padding: 0;
4107 padding: 0;
4108 }
4108 }
4109
4109
4110 #login div.form div.fields div.field, #register div.form div.fields div.field {
4110 #login div.form div.fields div.field, #register div.form div.fields div.field {
4111 clear: both;
4111 clear: both;
4112 overflow: hidden;
4112 overflow: hidden;
4113 margin: 0;
4113 margin: 0;
4114 padding: 0 0 10px;
4114 padding: 0 0 10px;
4115 }
4115 }
4116
4116
4117 #login div.form div.fields div.field span.error-message, #register div.form div.fields div.field span.error-message {
4117 #login div.form div.fields div.field span.error-message, #register div.form div.fields div.field span.error-message {
4118 height: 1%;
4118 height: 1%;
4119 display: block;
4119 display: block;
4120 color: red;
4120 color: red;
4121 margin: 8px 0 0;
4121 margin: 8px 0 0;
4122 padding: 0;
4122 padding: 0;
4123 max-width: 320px;
4123 max-width: 320px;
4124 }
4124 }
4125
4125
4126 #login div.form div.fields div.field div.label label, #register div.form div.fields div.field div.label label {
4126 #login div.form div.fields div.field div.label label, #register div.form div.fields div.field div.label label {
4127 color: #000;
4127 color: #000;
4128 font-weight: 700;
4128 font-weight: 700;
4129 }
4129 }
4130
4130
4131 #login div.form div.fields div.field div.input, #register div.form div.fields div.field div.input {
4131 #login div.form div.fields div.field div.input, #register div.form div.fields div.field div.input {
4132 float: left;
4132 float: left;
4133 margin: 0;
4133 margin: 0;
4134 padding: 0;
4134 padding: 0;
4135 }
4135 }
4136
4136
4137 #login div.form div.fields div.field div.input input.large {
4137 #login div.form div.fields div.field div.input input.large {
4138 width: 250px;
4138 width: 250px;
4139 }
4139 }
4140
4140
4141 #login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
4141 #login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
4142 margin: 0 0 0 184px;
4142 margin: 0 0 0 184px;
4143 padding: 0;
4143 padding: 0;
4144 }
4144 }
4145
4145
4146 #login div.form div.fields div.field div.checkbox label, #register div.form div.fields div.field div.checkbox label {
4146 #login div.form div.fields div.field div.checkbox label, #register div.form div.fields div.field div.checkbox label {
4147 color: #565656;
4147 color: #565656;
4148 font-weight: 700;
4148 font-weight: 700;
4149 }
4149 }
4150
4150
4151 #login div.form div.fields div.buttons input, #register div.form div.fields div.buttons input {
4151 #login div.form div.fields div.buttons input, #register div.form div.fields div.buttons input {
4152 color: #000;
4152 color: #000;
4153 font-size: 1em;
4153 font-size: 1em;
4154 font-weight: 700;
4154 font-weight: 700;
4155 margin: 0;
4155 margin: 0;
4156 }
4156 }
4157
4157
4158 #changeset_content .container .wrapper, #graph_content .container .wrapper {
4158 #changeset_content .container .wrapper, #graph_content .container .wrapper {
4159 width: 600px;
4159 width: 600px;
4160 }
4160 }
4161
4161
4162 #changeset_content .container .date, .ac .match {
4162 #changeset_content .container .date, .ac .match {
4163 font-weight: 700;
4163 font-weight: 700;
4164 padding-top: 5px;
4164 padding-top: 5px;
4165 padding-bottom: 5px;
4165 padding-bottom: 5px;
4166 }
4166 }
4167
4167
4168 div#legend_container table td, div#legend_choices table td {
4168 div#legend_container table td, div#legend_choices table td {
4169 border: none !important;
4169 border: none !important;
4170 height: 20px !important;
4170 height: 20px !important;
4171 padding: 0 !important;
4171 padding: 0 !important;
4172 }
4172 }
4173
4173
4174 .q_filter_box {
4174 .q_filter_box {
4175 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4175 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4176 -webkit-border-radius: 4px;
4176 -webkit-border-radius: 4px;
4177 border-radius: 4px;
4177 border-radius: 4px;
4178 border: 0 none;
4178 border: 0 none;
4179 margin-bottom: -4px;
4179 margin-bottom: -4px;
4180 margin-top: -4px;
4180 margin-top: -4px;
4181 padding-left: 3px;
4181 padding-left: 3px;
4182 }
4182 }
4183
4183
4184 #node_filter {
4184 #node_filter {
4185 border: 0px solid #545454;
4185 border: 0px solid #545454;
4186 color: #AAAAAA;
4186 color: #AAAAAA;
4187 padding-left: 3px;
4187 padding-left: 3px;
4188 }
4188 }
4189
4189
4190
4190
4191 .group_members_wrap {
4191 .group_members_wrap {
4192 min-height: 85px;
4192 min-height: 85px;
4193 padding-left: 20px;
4193 padding-left: 20px;
4194 }
4194 }
4195
4195
4196 .group_members .group_member {
4196 .group_members .group_member {
4197 height: 30px;
4197 height: 30px;
4198 padding: 0px 0px 0px 0px;
4198 padding: 0px 0px 0px 0px;
4199 }
4199 }
4200
4200
4201 .reviewer_status {
4201 .reviewer_status {
4202 float: left;
4202 float: left;
4203 }
4203 }
4204
4204
4205 .reviewers_member {
4205 .reviewers_member {
4206 height: 15px;
4206 height: 15px;
4207 padding: 0px 0px 0px 10px;
4207 padding: 0px 0px 0px 10px;
4208 }
4208 }
4209
4209
4210 .emails_wrap {
4210 .emails_wrap {
4211 padding: 0px 20px;
4211 padding: 0px 20px;
4212 }
4212 }
4213
4213
4214 .emails_wrap .email_entry {
4214 .emails_wrap .email_entry {
4215 height: 30px;
4215 height: 30px;
4216 padding: 0px 0px 0px 10px;
4216 padding: 0px 0px 0px 10px;
4217 }
4217 }
4218 .emails_wrap .email_entry .email {
4218 .emails_wrap .email_entry .email {
4219 float: left
4219 float: left
4220 }
4220 }
4221 .emails_wrap .email_entry .email_action {
4221 .emails_wrap .email_entry .email_action {
4222 float: left
4222 float: left
4223 }
4223 }
4224
4224
4225 .ips_wrap {
4225 .ips_wrap {
4226 padding: 0px 20px;
4226 padding: 0px 20px;
4227 }
4227 }
4228
4228
4229 .ips_wrap .ip_entry {
4229 .ips_wrap .ip_entry {
4230 height: 30px;
4230 height: 30px;
4231 padding: 0px 0px 0px 10px;
4231 padding: 0px 0px 0px 10px;
4232 }
4232 }
4233 .ips_wrap .ip_entry .ip {
4233 .ips_wrap .ip_entry .ip {
4234 float: left
4234 float: left
4235 }
4235 }
4236 .ips_wrap .ip_entry .ip_action {
4236 .ips_wrap .ip_entry .ip_action {
4237 float: left
4237 float: left
4238 }
4238 }
4239
4239
4240
4240
4241 /*README STYLE*/
4241 /*README STYLE*/
4242
4242
4243 div.readme {
4243 div.readme {
4244 padding: 0px;
4244 padding: 0px;
4245 }
4245 }
4246
4246
4247 div.readme h2 {
4247 div.readme h2 {
4248 font-weight: normal;
4248 font-weight: normal;
4249 }
4249 }
4250
4250
4251 div.readme .readme_box {
4251 div.readme .readme_box {
4252 background-color: #fafafa;
4252 background-color: #fafafa;
4253 }
4253 }
4254
4254
4255 div.readme .readme_box {
4255 div.readme .readme_box {
4256 clear: both;
4256 clear: both;
4257 overflow: hidden;
4257 overflow: hidden;
4258 margin: 0;
4258 margin: 0;
4259 padding: 0 20px 10px;
4259 padding: 0 20px 10px;
4260 }
4260 }
4261
4261
4262 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4262 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4263 border-bottom: 0 !important;
4263 border-bottom: 0 !important;
4264 margin: 0 !important;
4264 margin: 0 !important;
4265 padding: 0 !important;
4265 padding: 0 !important;
4266 line-height: 1.5em !important;
4266 line-height: 1.5em !important;
4267 }
4267 }
4268
4268
4269
4269
4270 div.readme .readme_box h1:first-child {
4270 div.readme .readme_box h1:first-child {
4271 padding-top: .25em !important;
4271 padding-top: .25em !important;
4272 }
4272 }
4273
4273
4274 div.readme .readme_box h2, div.readme .readme_box h3 {
4274 div.readme .readme_box h2, div.readme .readme_box h3 {
4275 margin: 1em 0 !important;
4275 margin: 1em 0 !important;
4276 }
4276 }
4277
4277
4278 div.readme .readme_box h2 {
4278 div.readme .readme_box h2 {
4279 margin-top: 1.5em !important;
4279 margin-top: 1.5em !important;
4280 border-top: 4px solid #e0e0e0 !important;
4280 border-top: 4px solid #e0e0e0 !important;
4281 padding-top: .5em !important;
4281 padding-top: .5em !important;
4282 }
4282 }
4283
4283
4284 div.readme .readme_box p {
4284 div.readme .readme_box p {
4285 color: black !important;
4285 color: black !important;
4286 margin: 1em 0 !important;
4286 margin: 1em 0 !important;
4287 line-height: 1.5em !important;
4287 line-height: 1.5em !important;
4288 }
4288 }
4289
4289
4290 div.readme .readme_box ul {
4290 div.readme .readme_box ul {
4291 list-style: disc !important;
4291 list-style: disc !important;
4292 margin: 1em 0 1em 2em !important;
4292 margin: 1em 0 1em 2em !important;
4293 }
4293 }
4294
4294
4295 div.readme .readme_box ol {
4295 div.readme .readme_box ol {
4296 list-style: decimal;
4296 list-style: decimal;
4297 margin: 1em 0 1em 2em !important;
4297 margin: 1em 0 1em 2em !important;
4298 }
4298 }
4299
4299
4300 div.readme .readme_box code {
4300 div.readme .readme_box code {
4301 font-size: 12px !important;
4301 font-size: 12px !important;
4302 background-color: ghostWhite !important;
4302 background-color: ghostWhite !important;
4303 color: #444 !important;
4303 color: #444 !important;
4304 padding: 0 .2em !important;
4304 padding: 0 .2em !important;
4305 border: 1px solid #dedede !important;
4305 border: 1px solid #dedede !important;
4306 }
4306 }
4307
4307
4308 div.readme .readme_box pre code {
4308 div.readme .readme_box pre code {
4309 padding: 0 !important;
4309 padding: 0 !important;
4310 font-size: 12px !important;
4310 font-size: 12px !important;
4311 background-color: #eee !important;
4311 background-color: #eee !important;
4312 border: none !important;
4312 border: none !important;
4313 }
4313 }
4314
4314
4315 div.readme .readme_box pre {
4315 div.readme .readme_box pre {
4316 margin: 1em 0;
4316 margin: 1em 0;
4317 font-size: 12px;
4317 font-size: 12px;
4318 background-color: #eee;
4318 background-color: #eee;
4319 border: 1px solid #ddd;
4319 border: 1px solid #ddd;
4320 padding: 5px;
4320 padding: 5px;
4321 color: #444;
4321 color: #444;
4322 overflow: auto;
4322 overflow: auto;
4323 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4323 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4324 -webkit-border-radius: 3px;
4324 -webkit-border-radius: 3px;
4325 border-radius: 3px;
4325 border-radius: 3px;
4326 }
4326 }
4327
4327
4328 div.readme .readme_box table {
4328 div.readme .readme_box table {
4329 display: table;
4329 display: table;
4330 border-collapse: separate;
4330 border-collapse: separate;
4331 border-spacing: 2px;
4331 border-spacing: 2px;
4332 border-color: gray;
4332 border-color: gray;
4333 width: auto !important;
4333 width: auto !important;
4334 }
4334 }
4335
4335
4336
4336
4337 /** RST STYLE **/
4337 /** RST STYLE **/
4338
4338
4339
4339
4340 div.rst-block {
4340 div.rst-block {
4341 padding: 0px;
4341 padding: 0px;
4342 }
4342 }
4343
4343
4344 div.rst-block h2 {
4344 div.rst-block h2 {
4345 font-weight: normal;
4345 font-weight: normal;
4346 }
4346 }
4347
4347
4348 div.rst-block {
4348 div.rst-block {
4349 background-color: #fafafa;
4349 background-color: #fafafa;
4350 }
4350 }
4351
4351
4352 div.rst-block {
4352 div.rst-block {
4353 clear: both;
4353 clear: both;
4354 overflow: hidden;
4354 overflow: hidden;
4355 margin: 0;
4355 margin: 0;
4356 padding: 0 20px 10px;
4356 padding: 0 20px 10px;
4357 }
4357 }
4358
4358
4359 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4359 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4360 border-bottom: 0 !important;
4360 border-bottom: 0 !important;
4361 margin: 0 !important;
4361 margin: 0 !important;
4362 padding: 0 !important;
4362 padding: 0 !important;
4363 line-height: 1.5em !important;
4363 line-height: 1.5em !important;
4364 }
4364 }
4365
4365
4366
4366
4367 div.rst-block h1:first-child {
4367 div.rst-block h1:first-child {
4368 padding-top: .25em !important;
4368 padding-top: .25em !important;
4369 }
4369 }
4370
4370
4371 div.rst-block h2, div.rst-block h3 {
4371 div.rst-block h2, div.rst-block h3 {
4372 margin: 1em 0 !important;
4372 margin: 1em 0 !important;
4373 }
4373 }
4374
4374
4375 div.rst-block h2 {
4375 div.rst-block h2 {
4376 margin-top: 1.5em !important;
4376 margin-top: 1.5em !important;
4377 border-top: 4px solid #e0e0e0 !important;
4377 border-top: 4px solid #e0e0e0 !important;
4378 padding-top: .5em !important;
4378 padding-top: .5em !important;
4379 }
4379 }
4380
4380
4381 div.rst-block p {
4381 div.rst-block p {
4382 color: black !important;
4382 color: black !important;
4383 margin: 1em 0 !important;
4383 margin: 1em 0 !important;
4384 line-height: 1.5em !important;
4384 line-height: 1.5em !important;
4385 }
4385 }
4386
4386
4387 div.rst-block ul {
4387 div.rst-block ul {
4388 list-style: disc !important;
4388 list-style: disc !important;
4389 margin: 1em 0 1em 2em !important;
4389 margin: 1em 0 1em 2em !important;
4390 }
4390 }
4391
4391
4392 div.rst-block ol {
4392 div.rst-block ol {
4393 list-style: decimal;
4393 list-style: decimal;
4394 margin: 1em 0 1em 2em !important;
4394 margin: 1em 0 1em 2em !important;
4395 }
4395 }
4396
4396
4397 div.rst-block code {
4397 div.rst-block code {
4398 font-size: 12px !important;
4398 font-size: 12px !important;
4399 background-color: ghostWhite !important;
4399 background-color: ghostWhite !important;
4400 color: #444 !important;
4400 color: #444 !important;
4401 padding: 0 .2em !important;
4401 padding: 0 .2em !important;
4402 border: 1px solid #dedede !important;
4402 border: 1px solid #dedede !important;
4403 }
4403 }
4404
4404
4405 div.rst-block pre code {
4405 div.rst-block pre code {
4406 padding: 0 !important;
4406 padding: 0 !important;
4407 font-size: 12px !important;
4407 font-size: 12px !important;
4408 background-color: #eee !important;
4408 background-color: #eee !important;
4409 border: none !important;
4409 border: none !important;
4410 }
4410 }
4411
4411
4412 div.rst-block pre {
4412 div.rst-block pre {
4413 margin: 1em 0;
4413 margin: 1em 0;
4414 font-size: 12px;
4414 font-size: 12px;
4415 background-color: #eee;
4415 background-color: #eee;
4416 border: 1px solid #ddd;
4416 border: 1px solid #ddd;
4417 padding: 5px;
4417 padding: 5px;
4418 color: #444;
4418 color: #444;
4419 overflow: auto;
4419 overflow: auto;
4420 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4420 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4421 -webkit-border-radius: 3px;
4421 -webkit-border-radius: 3px;
4422 border-radius: 3px;
4422 border-radius: 3px;
4423 }
4423 }
4424
4424
4425
4425
4426 /** comment main **/
4426 /** comment main **/
4427 .comments {
4427 .comments {
4428 padding: 10px 20px;
4428 padding: 10px 20px;
4429 max-width: 978px;
4429 max-width: 978px;
4430 }
4430 }
4431
4431
4432 .comments .comment {
4432 .comments .comment {
4433 border: 1px solid #ddd;
4433 border: 1px solid #ddd;
4434 margin-top: 10px;
4434 margin-top: 10px;
4435 -webkit-border-radius: 4px;
4435 -webkit-border-radius: 4px;
4436 border-radius: 4px;
4436 border-radius: 4px;
4437 }
4437 }
4438
4438
4439 .comments .comment .meta {
4439 .comments .comment .meta {
4440 background: #f8f8f8;
4440 background: #f8f8f8;
4441 padding: 4px;
4441 padding: 4px;
4442 border-bottom: 1px solid #ddd;
4442 border-bottom: 1px solid #ddd;
4443 min-height: 18px;
4443 min-height: 18px;
4444 overflow: auto;
4444 overflow: auto;
4445 }
4445 }
4446
4446
4447 .comments .comment .meta img {
4447 .comments .comment .meta img {
4448 vertical-align: middle;
4448 vertical-align: middle;
4449 }
4449 }
4450
4450
4451 .comments .comment .meta .user {
4451 .comments .comment .meta .user {
4452 font-weight: bold;
4452 font-weight: bold;
4453 float: left;
4453 float: left;
4454 padding: 4px 2px 2px 2px;
4454 padding: 4px 2px 2px 2px;
4455 }
4455 }
4456
4456
4457 .comments .comment .meta .date {
4457 .comments .comment .meta .date {
4458 float: left;
4458 float: left;
4459 padding: 4px 4px 0px 4px;
4459 padding: 4px 4px 0px 4px;
4460 }
4460 }
4461
4461
4462 .comments .comment .text {
4462 .comments .comment .text {
4463 background-color: #FAFAFA;
4463 background-color: #FAFAFA;
4464 }
4464 }
4465 .comment .text div.rst-block p {
4465 .comment .text div.rst-block p {
4466 margin: 0.5em 0px !important;
4466 margin: 0.5em 0px !important;
4467 }
4467 }
4468
4468
4469 .comments .comments-number,
4469 .comments .comments-number,
4470 .pr-comments-number {
4470 .pr-comments-number {
4471 margin: 5px;
4471 margin: 5px;
4472 padding: 0px 0px 10px 0px;
4472 padding: 0px 0px 10px 0px;
4473 font-weight: bold;
4473 font-weight: bold;
4474 color: #666;
4474 color: #666;
4475 font-size: 16px;
4475 font-size: 16px;
4476 }
4476 }
4477
4477
4478 /** comment form **/
4478 /** comment form **/
4479
4479
4480 .status-block {
4480 .status-block {
4481 margin: 5px;
4481 margin: 5px;
4482 clear: both
4482 clear: both
4483 }
4483 }
4484
4484
4485
4485
4486 div.comment-form {
4486 div.comment-form {
4487 margin-top: 20px;
4487 margin-top: 20px;
4488 }
4488 }
4489
4489
4490 .comment-form strong {
4490 .comment-form strong {
4491 display: block;
4491 display: block;
4492 margin-bottom: 15px;
4492 margin-bottom: 15px;
4493 }
4493 }
4494
4494
4495 .comment-form textarea {
4495 .comment-form textarea {
4496 width: 100%;
4496 width: 100%;
4497 height: 100px;
4497 height: 100px;
4498 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
4498 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
4499 }
4499 }
4500
4500
4501 form.comment-form {
4501 form.comment-form {
4502 margin-top: 10px;
4502 margin-top: 10px;
4503 margin-left: 10px;
4503 margin-left: 10px;
4504 }
4504 }
4505
4505
4506 .comment-inline-form .comment-block-ta,
4506 .comment-inline-form .comment-block-ta,
4507 .comment-form .comment-block-ta {
4507 .comment-form .comment-block-ta {
4508 border: 1px solid #ccc;
4508 border: 1px solid #ccc;
4509 border-radius: 3px;
4509 border-radius: 3px;
4510 box-sizing: border-box;
4510 box-sizing: border-box;
4511 }
4511 }
4512
4512
4513 .comment-form-submit {
4513 .comment-form-submit {
4514 margin-top: 5px;
4514 margin-top: 5px;
4515 margin-left: 525px;
4515 margin-left: 525px;
4516 }
4516 }
4517
4517
4518 .file-comments {
4518 .file-comments {
4519 display: none;
4519 display: none;
4520 }
4520 }
4521
4521
4522 .comment-form .comment {
4522 .comment-form .comment {
4523 margin-left: 10px;
4523 margin-left: 10px;
4524 }
4524 }
4525
4525
4526 .comment-form .comment-help {
4526 .comment-form .comment-help {
4527 padding: 5px 5px 5px 5px;
4527 padding: 5px 5px 5px 5px;
4528 color: #666;
4528 color: #666;
4529 }
4529 }
4530 .comment-form .comment-help .preview-btn,
4530 .comment-form .comment-help .preview-btn,
4531 .comment-form .comment-help .edit-btn {
4531 .comment-form .comment-help .edit-btn {
4532 float: right;
4532 float: right;
4533 margin: -6px 0px 0px 0px;
4533 margin: -6px 0px 0px 0px;
4534 }
4534 }
4535
4535
4536 .comment-form .preview-box.unloaded,
4536 .comment-form .preview-box.unloaded,
4537 .comment-inline-form .preview-box.unloaded {
4537 .comment-inline-form .preview-box.unloaded {
4538 height: 50px;
4538 height: 50px;
4539 text-align: center;
4539 text-align: center;
4540 padding: 20px;
4540 padding: 20px;
4541 background-color: #fafafa;
4541 background-color: #fafafa;
4542 }
4542 }
4543
4543
4544 .comment-form .comment-button {
4544 .comment-form .comment-button {
4545 padding-top: 5px;
4545 padding-top: 5px;
4546 }
4546 }
4547
4547
4548 .add-another-button {
4548 .add-another-button {
4549 margin-left: 10px;
4549 margin-left: 10px;
4550 margin-top: 10px;
4550 margin-top: 10px;
4551 margin-bottom: 10px;
4551 margin-bottom: 10px;
4552 }
4552 }
4553
4553
4554 .comment .buttons {
4554 .comment .buttons {
4555 float: right;
4555 float: right;
4556 margin: -1px 0px 0px 0px;
4556 margin: -1px 0px 0px 0px;
4557 }
4557 }
4558
4558
4559
4559
4560 .show-inline-comments {
4560 .show-inline-comments {
4561 position: relative;
4561 position: relative;
4562 top: 1px
4562 top: 1px
4563 }
4563 }
4564
4564
4565 /** comment inline form **/
4565 /** comment inline form **/
4566 .comment-inline-form {
4566 .comment-inline-form {
4567 margin: 4px;
4567 margin: 4px;
4568 max-width: 978px;
4568 max-width: 978px;
4569 }
4569 }
4570 .comment-inline-form .submitting-overlay {
4570 .comment-inline-form .submitting-overlay {
4571 display: none;
4571 display: none;
4572 height: 0;
4572 height: 0;
4573 text-align: center;
4573 text-align: center;
4574 font-size: 16px;
4574 font-size: 16px;
4575 opacity: 0.5;
4575 opacity: 0.5;
4576 }
4576 }
4577
4577
4578 .comment-inline-form .clearfix,
4578 .comment-inline-form .clearfix,
4579 .comment-form .clearfix {
4579 .comment-form .clearfix {
4580 background: #EEE;
4580 background: #EEE;
4581 -webkit-border-radius: 4px;
4581 -webkit-border-radius: 4px;
4582 border-radius: 4px;
4582 border-radius: 4px;
4583 padding: 5px;
4583 padding: 5px;
4584 margin: 0px;
4584 margin: 0px;
4585 }
4585 }
4586
4586
4587 div.comment-inline-form {
4587 div.comment-inline-form {
4588 padding: 4px 0px 6px 0px;
4588 padding: 4px 0px 6px 0px;
4589 }
4589 }
4590
4590
4591 .comment-inline-form strong {
4591 .comment-inline-form strong {
4592 display: block;
4592 display: block;
4593 margin-bottom: 15px;
4593 margin-bottom: 15px;
4594 }
4594 }
4595
4595
4596 .comment-inline-form textarea {
4596 .comment-inline-form textarea {
4597 width: 100%;
4597 width: 100%;
4598 height: 100px;
4598 height: 100px;
4599 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
4599 font-family: Consolas, Monaco, Inconsolata, Liberation Mono, monospace;
4600 }
4600 }
4601
4601
4602 form.comment-inline-form {
4602 form.comment-inline-form {
4603 margin-top: 10px;
4603 margin-top: 10px;
4604 margin-left: 10px;
4604 margin-left: 10px;
4605 }
4605 }
4606
4606
4607 .comment-inline-form-submit {
4607 .comment-inline-form-submit {
4608 margin-top: 5px;
4608 margin-top: 5px;
4609 margin-left: 525px;
4609 margin-left: 525px;
4610 }
4610 }
4611
4611
4612 .file-comments {
4612 .file-comments {
4613 display: none;
4613 display: none;
4614 }
4614 }
4615
4615
4616 .comment-inline-form .comment {
4616 .comment-inline-form .comment {
4617 margin-left: 10px;
4617 margin-left: 10px;
4618 }
4618 }
4619
4619
4620 .comment-inline-form .comment-help {
4620 .comment-inline-form .comment-help {
4621 padding: 5px 5px 5px 5px;
4621 padding: 5px 5px 5px 5px;
4622 color: #666;
4622 color: #666;
4623 }
4623 }
4624
4624
4625 .comment-inline-form .comment-help .preview-btn,
4625 .comment-inline-form .comment-help .preview-btn,
4626 .comment-inline-form .comment-help .edit-btn {
4626 .comment-inline-form .comment-help .edit-btn {
4627 float: right;
4627 float: right;
4628 margin: -6px 0px 0px 0px;
4628 margin: -6px 0px 0px 0px;
4629 }
4629 }
4630
4630
4631 .comment-inline-form .comment-button {
4631 .comment-inline-form .comment-button {
4632 padding-top: 5px;
4632 padding-top: 5px;
4633 }
4633 }
4634
4634
4635 /** comment inline **/
4635 /** comment inline **/
4636 .inline-comments {
4636 .inline-comments {
4637 padding: 10px 20px;
4637 padding: 10px 20px;
4638 }
4638 }
4639
4639
4640 .inline-comments div.rst-block {
4640 .inline-comments div.rst-block {
4641 clear: both;
4641 clear: both;
4642 overflow: hidden;
4642 overflow: hidden;
4643 margin: 0;
4643 margin: 0;
4644 padding: 0 20px 0px;
4644 padding: 0 20px 0px;
4645 }
4645 }
4646 .inline-comments .comment {
4646 .inline-comments .comment {
4647 max-width: 978px;
4647 max-width: 978px;
4648 border: 1px solid #ddd;
4648 border: 1px solid #ddd;
4649 -webkit-border-radius: 4px;
4649 -webkit-border-radius: 4px;
4650 border-radius: 4px;
4650 border-radius: 4px;
4651 margin: 3px 3px 5px 5px;
4651 margin: 3px 3px 5px 5px;
4652 background-color: #FAFAFA;
4652 background-color: #FAFAFA;
4653 }
4653 }
4654 .inline-comments .add-comment {
4654 .inline-comments .add-comment {
4655 padding: 2px 4px 8px 5px;
4655 padding: 2px 4px 8px 5px;
4656 }
4656 }
4657
4657
4658 .inline-comments .comment-wrapp {
4658 .inline-comments .comment-wrapp {
4659 padding: 1px;
4659 padding: 1px;
4660 }
4660 }
4661 .inline-comments .comment .meta {
4661 .inline-comments .comment .meta {
4662 background: #f8f8f8;
4662 background: #f8f8f8;
4663 padding: 4px;
4663 padding: 4px;
4664 border-bottom: 1px solid #ddd;
4664 border-bottom: 1px solid #ddd;
4665 min-height: 20px;
4665 min-height: 20px;
4666 overflow: auto;
4666 overflow: auto;
4667 }
4667 }
4668
4668
4669 .inline-comments .comment .meta img {
4669 .inline-comments .comment .meta img {
4670 vertical-align: middle;
4670 vertical-align: middle;
4671 }
4671 }
4672
4672
4673 .inline-comments .comment .meta .user {
4673 .inline-comments .comment .meta .user {
4674 font-weight: bold;
4674 font-weight: bold;
4675 float: left;
4675 float: left;
4676 padding: 3px;
4676 padding: 3px;
4677 }
4677 }
4678
4678
4679 .inline-comments .comment .meta .date {
4679 .inline-comments .comment .meta .date {
4680 float: left;
4680 float: left;
4681 padding: 3px;
4681 padding: 3px;
4682 }
4682 }
4683
4683
4684 .inline-comments .comment .text {
4684 .inline-comments .comment .text {
4685 background-color: #FAFAFA;
4685 background-color: #FAFAFA;
4686 }
4686 }
4687
4687
4688 .inline-comments .comments-number {
4688 .inline-comments .comments-number {
4689 padding: 0px 0px 10px 0px;
4689 padding: 0px 0px 10px 0px;
4690 font-weight: bold;
4690 font-weight: bold;
4691 color: #666;
4691 color: #666;
4692 font-size: 16px;
4692 font-size: 16px;
4693 }
4693 }
4694 .inline-comments-button .add-comment {
4694 .inline-comments-button .add-comment {
4695 margin: 2px 0px 8px 5px !important
4695 margin: 2px 0px 8px 5px !important
4696 }
4696 }
4697
4697
4698 .notification-paginator {
4698 .notification-paginator {
4699 padding: 0px 0px 4px 16px;
4699 padding: 0px 0px 4px 16px;
4700 }
4700 }
4701
4701
4702 #context-pages .pull-request span,
4702 #context-pages .pull-request span,
4703 .menu_link_notifications {
4703 .menu_link_notifications {
4704 padding: 4px 4px !important;
4704 padding: 4px 4px !important;
4705 text-align: center;
4705 text-align: center;
4706 color: #888 !important;
4706 color: #888 !important;
4707 background-color: #DEDEDE !important;
4707 background-color: #DEDEDE !important;
4708 border-radius: 4px !important;
4708 border-radius: 4px !important;
4709 -webkit-border-radius: 4px !important;
4709 -webkit-border-radius: 4px !important;
4710 }
4710 }
4711
4711
4712 #context-pages .forks span,
4712 #context-pages .forks span,
4713 .menu_link_notifications {
4713 .menu_link_notifications {
4714 padding: 4px 4px !important;
4714 padding: 4px 4px !important;
4715 text-align: center;
4715 text-align: center;
4716 color: #888 !important;
4716 color: #888 !important;
4717 background-color: #DEDEDE !important;
4717 background-color: #DEDEDE !important;
4718 border-radius: 4px !important;
4718 border-radius: 4px !important;
4719 -webkit-border-radius: 4px !important;
4719 -webkit-border-radius: 4px !important;
4720 }
4720 }
4721
4721
4722
4722
4723 .notification-header {
4723 .notification-header {
4724 padding-top: 6px;
4724 padding-top: 6px;
4725 }
4725 }
4726 .notification-header .desc {
4726 .notification-header .desc {
4727 font-size: 16px;
4727 font-size: 16px;
4728 height: 24px;
4728 height: 24px;
4729 float: left
4729 float: left
4730 }
4730 }
4731 .notification-list .container.unread {
4731 .notification-list .container.unread {
4732 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4732 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4733 }
4733 }
4734 .notification-header .gravatar {
4734 .notification-header .gravatar {
4735 background: none repeat scroll 0 0 transparent;
4735 background: none repeat scroll 0 0 transparent;
4736 padding: 0px 0px 0px 8px;
4736 padding: 0px 0px 0px 8px;
4737 }
4737 }
4738 .notification-list .container .notification-header .desc {
4738 .notification-list .container .notification-header .desc {
4739 font-weight: bold;
4739 font-weight: bold;
4740 font-size: 17px;
4740 font-size: 17px;
4741 }
4741 }
4742 .notification-table {
4742 .notification-table {
4743 border: 1px solid #ccc;
4743 border: 1px solid #ccc;
4744 -webkit-border-radius: 6px 6px 6px 6px;
4744 -webkit-border-radius: 6px 6px 6px 6px;
4745 border-radius: 6px 6px 6px 6px;
4745 border-radius: 6px 6px 6px 6px;
4746 clear: both;
4746 clear: both;
4747 margin: 0px 20px 0px 20px;
4747 margin: 0px 20px 0px 20px;
4748 }
4748 }
4749 .notification-header .delete-notifications {
4749 .notification-header .delete-notifications {
4750 float: right;
4750 float: right;
4751 padding-top: 8px;
4751 padding-top: 8px;
4752 cursor: pointer;
4752 cursor: pointer;
4753 }
4753 }
4754 .notification-header .read-notifications {
4754 .notification-header .read-notifications {
4755 float: right;
4755 float: right;
4756 padding-top: 8px;
4756 padding-top: 8px;
4757 cursor: pointer;
4757 cursor: pointer;
4758 }
4758 }
4759 .notification-subject {
4759 .notification-subject {
4760 clear: both;
4760 clear: both;
4761 border-bottom: 1px solid #eee;
4761 border-bottom: 1px solid #eee;
4762 padding: 5px 0px 5px 38px;
4762 padding: 5px 0px 5px 38px;
4763 }
4763 }
4764
4764
4765 .notification-body {
4765 .notification-body {
4766 clear: both;
4766 clear: both;
4767 margin: 34px 2px 2px 8px
4767 margin: 34px 2px 2px 8px
4768 }
4768 }
4769
4769
4770 /****
4770 /****
4771 PULL REQUESTS
4771 PULL REQUESTS
4772 *****/
4772 *****/
4773 .pullrequests_section_head {
4773 .pullrequests_section_head {
4774 padding: 10px 10px 10px 0px;
4774 padding: 10px 10px 10px 0px;
4775 font-size: 16px;
4775 font-size: 16px;
4776 font-weight: bold;
4776 font-weight: bold;
4777 }
4777 }
4778
4778
4779 div.pr-details-title.closed,
4779 div.pr-details-title.closed,
4780 #pullrequests_container li.closed div div
4780 #pullrequests_container li.closed div div
4781 {
4781 {
4782 color: #555;
4782 color: #555;
4783 background: #eee;
4783 background: #eee;
4784 }
4784 }
4785
4785
4786 div.pr-title {
4786 div.pr-title {
4787 font-size: 1.6em;
4787 font-size: 1.6em;
4788 }
4788 }
4789 div.pr-details-title {
4789 div.pr-details-title {
4790 font-size: 1.6em;
4790 font-size: 1.6em;
4791 padding: 5px 0px 5px 10px;
4791 padding: 5px 0px 5px 10px;
4792 }
4792 }
4793
4793
4794 div.pr {
4794 div.pr {
4795 margin: 0px 20px;
4795 margin: 0px 20px;
4796 padding: 4px 4px;
4796 padding: 4px 4px;
4797 }
4797 }
4798 div.pr-desc {
4798 div.pr-desc {
4799 margin: 0px 20px;
4799 margin: 0px 20px;
4800 }
4800 }
4801 div.pr-closed {
4801 div.pr-closed {
4802 background-color: #eee;
4802 background-color: #eee;
4803 }
4803 }
4804
4804
4805 span.pr-closed-tag {
4805 span.pr-closed-tag {
4806 margin-bottom: 1px;
4806 margin-bottom: 1px;
4807 margin-right: 1px;
4807 margin-right: 1px;
4808 padding: 1px 3px;
4808 padding: 1px 3px;
4809 font-size: 10px;
4809 font-size: 10px;
4810 padding: 1px 3px 1px 3px;
4810 padding: 1px 3px 1px 3px;
4811 font-size: 10px;
4811 font-size: 10px;
4812 color: #577632;
4812 color: #577632;
4813 white-space: nowrap;
4813 white-space: nowrap;
4814 -webkit-border-radius: 4px;
4814 -webkit-border-radius: 4px;
4815 border-radius: 4px;
4815 border-radius: 4px;
4816 border: 1px solid #d9e8f8;
4816 border: 1px solid #d9e8f8;
4817 line-height: 1.5em;
4817 line-height: 1.5em;
4818 }
4818 }
4819
4819
4820 .pr-box {
4820 .pr-box {
4821 max-width: 978px;
4821 max-width: 978px;
4822 }
4822 }
4823
4823
4824 #s2id_org_ref,
4824 #s2id_org_ref,
4825 #s2id_other_ref,
4825 #s2id_other_ref,
4826 #s2id_org_repo,
4826 #s2id_org_repo,
4827 #s2id_other_repo {
4827 #s2id_other_repo {
4828 min-width: 150px;
4828 min-width: 150px;
4829 margin: 5px;
4829 margin: 5px;
4830 }
4830 }
4831
4831
4832 #pr-summary .msg-div {
4832 #pr-summary .msg-div {
4833 margin: 5px 0;
4833 margin: 5px 0;
4834 }
4834 }
4835
4835
4836 /****
4836 /****
4837 PERMS
4837 PERMS
4838 *****/
4838 *****/
4839 #perms .perms_section_head {
4839 #perms .perms_section_head {
4840 padding: 10px 10px 10px 0px;
4840 padding: 10px 10px 10px 0px;
4841 font-size: 16px;
4841 font-size: 16px;
4842 font-weight: bold;
4842 font-weight: bold;
4843 text-transform: capitalize;
4843 }
4844 }
4844
4845
4845 #perms .perm_tag {
4846 #perms .perm_tag {
4846 padding: 1px 3px 1px 3px;
4847 padding: 1px 3px 1px 3px;
4847 font-size: 10px;
4848 font-size: 10px;
4848 font-weight: bold;
4849 font-weight: bold;
4849 text-transform: uppercase;
4850 text-transform: uppercase;
4850 white-space: nowrap;
4851 white-space: nowrap;
4851 -webkit-border-radius: 3px;
4852 -webkit-border-radius: 3px;
4852 border-radius: 3px;
4853 border-radius: 3px;
4853 }
4854 }
4854
4855
4855 #perms .perm_tag.admin {
4856 #perms .perm_tag.admin {
4856 background-color: #B94A48;
4857 background-color: #B94A48;
4857 color: #ffffff;
4858 color: #ffffff;
4858 }
4859 }
4859
4860
4860 #perms .perm_tag.write {
4861 #perms .perm_tag.write {
4861 background-color: #DB7525;
4862 background-color: #DB7525;
4862 color: #ffffff;
4863 color: #ffffff;
4863 }
4864 }
4864
4865
4865 #perms .perm_tag.read {
4866 #perms .perm_tag.read {
4866 background-color: #468847;
4867 background-color: #468847;
4867 color: #ffffff;
4868 color: #ffffff;
4868 }
4869 }
4869
4870
4870 #perms .perm_tag.none {
4871 #perms .perm_tag.none {
4871 background-color: #bfbfbf;
4872 background-color: #bfbfbf;
4872 color: #ffffff;
4873 color: #ffffff;
4873 }
4874 }
4874
4875
4875 .perm-gravatar {
4876 .perm-gravatar {
4876 vertical-align: middle;
4877 vertical-align: middle;
4877 padding: 2px;
4878 padding: 2px;
4878 }
4879 }
4879 .perm-gravatar-ac {
4880 .perm-gravatar-ac {
4880 vertical-align: middle;
4881 vertical-align: middle;
4881 padding: 2px;
4882 padding: 2px;
4882 width: 14px;
4883 width: 14px;
4883 height: 14px;
4884 height: 14px;
4884 }
4885 }
4885
4886
4886 /*****************************************************************************
4887 /*****************************************************************************
4887 DIFFS CSS
4888 DIFFS CSS
4888 ******************************************************************************/
4889 ******************************************************************************/
4889 .diff-collapse {
4890 .diff-collapse {
4890 text-align: center;
4891 text-align: center;
4891 margin-bottom: -15px;
4892 margin-bottom: -15px;
4892 }
4893 }
4893 .diff-collapse-button {
4894 .diff-collapse-button {
4894 cursor: pointer;
4895 cursor: pointer;
4895 color: #666;
4896 color: #666;
4896 font-size: 16px;
4897 font-size: 16px;
4897 }
4898 }
4898 .diff-container {
4899 .diff-container {
4899
4900
4900 }
4901 }
4901
4902
4902 .diff-container.hidden {
4903 .diff-container.hidden {
4903 display: none;
4904 display: none;
4904 overflow: hidden;
4905 overflow: hidden;
4905 }
4906 }
4906
4907
4907
4908
4908 div.diffblock {
4909 div.diffblock {
4909 overflow: auto;
4910 overflow: auto;
4910 padding: 0px;
4911 padding: 0px;
4911 border: 1px solid #ccc;
4912 border: 1px solid #ccc;
4912 background: #f8f8f8;
4913 background: #f8f8f8;
4913 font-size: 100%;
4914 font-size: 100%;
4914 line-height: 100%;
4915 line-height: 100%;
4915 /* new */
4916 /* new */
4916 line-height: 125%;
4917 line-height: 125%;
4917 -webkit-border-radius: 6px 6px 0px 0px;
4918 -webkit-border-radius: 6px 6px 0px 0px;
4918 border-radius: 6px 6px 0px 0px;
4919 border-radius: 6px 6px 0px 0px;
4919 }
4920 }
4920 div.diffblock.margined {
4921 div.diffblock.margined {
4921 margin: 0px 20px 0px 20px;
4922 margin: 0px 20px 0px 20px;
4922 overflow: hidden;
4923 overflow: hidden;
4923 }
4924 }
4924 div.diffblock .code-header {
4925 div.diffblock .code-header {
4925 border-bottom: 1px solid #CCCCCC;
4926 border-bottom: 1px solid #CCCCCC;
4926 background: #EEEEEE;
4927 background: #EEEEEE;
4927 padding: 10px 0 10px 0;
4928 padding: 10px 0 10px 0;
4928 min-height: 14px;
4929 min-height: 14px;
4929 }
4930 }
4930
4931
4931 div.diffblock .code-header.banner {
4932 div.diffblock .code-header.banner {
4932 border-bottom: 1px solid #CCCCCC;
4933 border-bottom: 1px solid #CCCCCC;
4933 background: #EEEEEE;
4934 background: #EEEEEE;
4934 height: 14px;
4935 height: 14px;
4935 margin: 0;
4936 margin: 0;
4936 padding: 3px 100px 11px 100px;
4937 padding: 3px 100px 11px 100px;
4937 }
4938 }
4938
4939
4939 div.diffblock .code-header-title {
4940 div.diffblock .code-header-title {
4940 padding: 0px 0px 10px 5px !important;
4941 padding: 0px 0px 10px 5px !important;
4941 margin: 0 !important;
4942 margin: 0 !important;
4942 }
4943 }
4943 div.diffblock .code-header .hash {
4944 div.diffblock .code-header .hash {
4944 float: left;
4945 float: left;
4945 padding: 2px 0 0 2px;
4946 padding: 2px 0 0 2px;
4946 }
4947 }
4947 div.diffblock .code-header .date {
4948 div.diffblock .code-header .date {
4948 float: left;
4949 float: left;
4949 text-transform: uppercase;
4950 text-transform: uppercase;
4950 padding: 2px 0px 0px 2px;
4951 padding: 2px 0px 0px 2px;
4951 }
4952 }
4952 div.diffblock .code-header div {
4953 div.diffblock .code-header div {
4953 margin-left: 4px;
4954 margin-left: 4px;
4954 font-weight: bold;
4955 font-weight: bold;
4955 font-size: 14px;
4956 font-size: 14px;
4956 }
4957 }
4957
4958
4958 div.diffblock .parents {
4959 div.diffblock .parents {
4959 float: left;
4960 float: left;
4960 min-height: 26px;
4961 min-height: 26px;
4961 font-size: 10px;
4962 font-size: 10px;
4962 font-weight: 400;
4963 font-weight: 400;
4963 vertical-align: middle;
4964 vertical-align: middle;
4964 padding: 0px 2px 2px 2px;
4965 padding: 0px 2px 2px 2px;
4965 background-color: #eeeeee;
4966 background-color: #eeeeee;
4966 border-bottom: 1px solid #CCCCCC;
4967 border-bottom: 1px solid #CCCCCC;
4967 }
4968 }
4968
4969
4969 div.diffblock .children {
4970 div.diffblock .children {
4970 float: right;
4971 float: right;
4971 min-height: 26px;
4972 min-height: 26px;
4972 font-size: 10px;
4973 font-size: 10px;
4973 font-weight: 400;
4974 font-weight: 400;
4974 vertical-align: middle;
4975 vertical-align: middle;
4975 text-align: right;
4976 text-align: right;
4976 padding: 0px 2px 2px 2px;
4977 padding: 0px 2px 2px 2px;
4977 background-color: #eeeeee;
4978 background-color: #eeeeee;
4978 border-bottom: 1px solid #CCCCCC;
4979 border-bottom: 1px solid #CCCCCC;
4979 }
4980 }
4980
4981
4981 div.diffblock .code-body {
4982 div.diffblock .code-body {
4982 background: #FFFFFF;
4983 background: #FFFFFF;
4983 clear: both;
4984 clear: both;
4984 }
4985 }
4985 div.diffblock pre.raw {
4986 div.diffblock pre.raw {
4986 background: #FFFFFF;
4987 background: #FFFFFF;
4987 color: #000000;
4988 color: #000000;
4988 }
4989 }
4989 table.code-difftable {
4990 table.code-difftable {
4990 border-collapse: collapse;
4991 border-collapse: collapse;
4991 width: 99%;
4992 width: 99%;
4992 border-radius: 0px !important;
4993 border-radius: 0px !important;
4993 }
4994 }
4994 table.code-difftable td {
4995 table.code-difftable td {
4995 padding: 0 !important;
4996 padding: 0 !important;
4996 background: none !important;
4997 background: none !important;
4997 border: 0 !important;
4998 border: 0 !important;
4998 vertical-align: baseline !important
4999 vertical-align: baseline !important
4999 }
5000 }
5000 table.code-difftable .context {
5001 table.code-difftable .context {
5001 background: none repeat scroll 0 0 #DDE7EF;
5002 background: none repeat scroll 0 0 #DDE7EF;
5002 color: #999;
5003 color: #999;
5003 }
5004 }
5004 table.code-difftable .add {
5005 table.code-difftable .add {
5005 background: none repeat scroll 0 0 #DDFFDD;
5006 background: none repeat scroll 0 0 #DDFFDD;
5006 }
5007 }
5007 table.code-difftable .add ins {
5008 table.code-difftable .add ins {
5008 background: none repeat scroll 0 0 #AAFFAA;
5009 background: none repeat scroll 0 0 #AAFFAA;
5009 text-decoration: none;
5010 text-decoration: none;
5010 }
5011 }
5011 table.code-difftable .del {
5012 table.code-difftable .del {
5012 background: none repeat scroll 0 0 #FFDDDD;
5013 background: none repeat scroll 0 0 #FFDDDD;
5013 }
5014 }
5014 table.code-difftable .del del {
5015 table.code-difftable .del del {
5015 background: none repeat scroll 0 0 #FFAAAA;
5016 background: none repeat scroll 0 0 #FFAAAA;
5016 text-decoration: none;
5017 text-decoration: none;
5017 }
5018 }
5018
5019
5019 table.code-highlighttable div.code-highlight pre u:before,
5020 table.code-highlighttable div.code-highlight pre u:before,
5020 table.code-difftable td.code pre u:before {
5021 table.code-difftable td.code pre u:before {
5021 content: "\21a6";
5022 content: "\21a6";
5022 display: inline-block;
5023 display: inline-block;
5023 width: 0;
5024 width: 0;
5024 }
5025 }
5025 table.code-highlighttable div.code-highlight pre u,
5026 table.code-highlighttable div.code-highlight pre u,
5026 table.code-difftable td.code pre u {
5027 table.code-difftable td.code pre u {
5027 color: rgba(0,0,0,0.15);
5028 color: rgba(0,0,0,0.15);
5028 }
5029 }
5029 table.code-highlighttable div.code-highlight pre i,
5030 table.code-highlighttable div.code-highlight pre i,
5030 table.code-difftable td.code pre i {
5031 table.code-difftable td.code pre i {
5031 border-style: solid;
5032 border-style: solid;
5032 border-left-width: 1px;
5033 border-left-width: 1px;
5033 color: rgba(0,0,0,0.15);
5034 color: rgba(0,0,0,0.15);
5034 }
5035 }
5035
5036
5036 /** LINE NUMBERS **/
5037 /** LINE NUMBERS **/
5037 table.code-difftable .lineno {
5038 table.code-difftable .lineno {
5038 padding-left: 2px;
5039 padding-left: 2px;
5039 padding-right: 2px !important;
5040 padding-right: 2px !important;
5040 text-align: right;
5041 text-align: right;
5041 width: 30px;
5042 width: 30px;
5042 -moz-user-select: none;
5043 -moz-user-select: none;
5043 -webkit-user-select: none;
5044 -webkit-user-select: none;
5044 border-right: 1px solid #CCC !important;
5045 border-right: 1px solid #CCC !important;
5045 border-left: 0px solid #CCC !important;
5046 border-left: 0px solid #CCC !important;
5046 border-top: 0px solid #CCC !important;
5047 border-top: 0px solid #CCC !important;
5047 border-bottom: none !important;
5048 border-bottom: none !important;
5048 vertical-align: middle !important;
5049 vertical-align: middle !important;
5049 }
5050 }
5050 table.code-difftable .lineno.new {
5051 table.code-difftable .lineno.new {
5051 }
5052 }
5052 table.code-difftable .lineno.old {
5053 table.code-difftable .lineno.old {
5053 }
5054 }
5054 table.code-difftable .lineno a {
5055 table.code-difftable .lineno a {
5055 color: #aaa !important;
5056 color: #aaa !important;
5056 font: 11px Consolas, Monaco, Inconsolata, Liberation Mono, monospace !important;
5057 font: 11px Consolas, Monaco, Inconsolata, Liberation Mono, monospace !important;
5057 letter-spacing: -1px;
5058 letter-spacing: -1px;
5058 text-align: right;
5059 text-align: right;
5059 padding-right: 2px;
5060 padding-right: 2px;
5060 cursor: pointer;
5061 cursor: pointer;
5061 display: block;
5062 display: block;
5062 width: 30px;
5063 width: 30px;
5063 }
5064 }
5064
5065
5065 table.code-difftable .lineno-inline {
5066 table.code-difftable .lineno-inline {
5066 background: none repeat scroll 0 0 #FFF !important;
5067 background: none repeat scroll 0 0 #FFF !important;
5067 padding-left: 2px;
5068 padding-left: 2px;
5068 padding-right: 2px;
5069 padding-right: 2px;
5069 text-align: right;
5070 text-align: right;
5070 width: 30px;
5071 width: 30px;
5071 -moz-user-select: none;
5072 -moz-user-select: none;
5072 -webkit-user-select: none;
5073 -webkit-user-select: none;
5073 }
5074 }
5074
5075
5075 /** CODE **/
5076 /** CODE **/
5076 table.code-difftable .code {
5077 table.code-difftable .code {
5077 display: block;
5078 display: block;
5078 width: 100%;
5079 width: 100%;
5079 }
5080 }
5080 table.code-difftable .code td {
5081 table.code-difftable .code td {
5081 margin: 0;
5082 margin: 0;
5082 padding: 0;
5083 padding: 0;
5083 }
5084 }
5084 table.code-difftable .code pre {
5085 table.code-difftable .code pre {
5085 margin: 0;
5086 margin: 0;
5086 padding: 0;
5087 padding: 0;
5087 min-height: 17px;
5088 min-height: 17px;
5088 line-height: 17px;
5089 line-height: 17px;
5089 white-space: pre-wrap;
5090 white-space: pre-wrap;
5090 }
5091 }
5091
5092
5092 .add-bubble {
5093 .add-bubble {
5093 display: none;
5094 display: none;
5094 float: left;
5095 float: left;
5095 width: 0px;
5096 width: 0px;
5096 height: 0px;
5097 height: 0px;
5097 }
5098 }
5098
5099
5099 tr.line.add td.code:hover .add-bubble,
5100 tr.line.add td.code:hover .add-bubble,
5100 tr.line.del td.code:hover .add-bubble,
5101 tr.line.del td.code:hover .add-bubble,
5101 tr.line.unmod td.code:hover .add-bubble {
5102 tr.line.unmod td.code:hover .add-bubble {
5102 display: inherit;
5103 display: inherit;
5103 }
5104 }
5104
5105
5105 .add-bubble div {
5106 .add-bubble div {
5106 position: relative;
5107 position: relative;
5107 left: -32px;
5108 left: -32px;
5108 width: 32px;
5109 width: 32px;
5109 top: -8px;
5110 top: -8px;
5110 height: 32px;
5111 height: 32px;
5111 background: url("../images/icons/comment_add.png") no-repeat 100% 50%;
5112 background: url("../images/icons/comment_add.png") no-repeat 100% 50%;
5112 cursor: pointer;
5113 cursor: pointer;
5113 }
5114 }
5114
5115
5115 div.comment:target>.comment-wrapp {
5116 div.comment:target>.comment-wrapp {
5116 border: solid 2px #ee0 !important;
5117 border: solid 2px #ee0 !important;
5117 }
5118 }
5118
5119
5119 .lineno:target a {
5120 .lineno:target a {
5120 border: solid 2px #ee0 !important;
5121 border: solid 2px #ee0 !important;
5121 margin: -2px;
5122 margin: -2px;
5122 }
5123 }
5123
5124
5124 .btn-image-diff-show,
5125 .btn-image-diff-show,
5125 .btn-image-diff-swap {
5126 .btn-image-diff-swap {
5126 margin: 5px;
5127 margin: 5px;
5127 }
5128 }
5128
5129
5129 .img-diff {
5130 .img-diff {
5130 max-width: 45%;
5131 max-width: 45%;
5131 height: auto;
5132 height: auto;
5132 margin: 5px;
5133 margin: 5px;
5133 /* http://lea.verou.me/demos/css3-patterns.html */
5134 /* http://lea.verou.me/demos/css3-patterns.html */
5134 background-image:
5135 background-image:
5135 linear-gradient(45deg, #888 25%, transparent 25%, transparent),
5136 linear-gradient(45deg, #888 25%, transparent 25%, transparent),
5136 linear-gradient(-45deg, #888 25%, transparent 25%, transparent),
5137 linear-gradient(-45deg, #888 25%, transparent 25%, transparent),
5137 linear-gradient(45deg, transparent 75%, #888 75%),
5138 linear-gradient(45deg, transparent 75%, #888 75%),
5138 linear-gradient(-45deg, transparent 75%, #888 75%);
5139 linear-gradient(-45deg, transparent 75%, #888 75%);
5139 background-size: 10px 10px;
5140 background-size: 10px 10px;
5140 background-color: #999;
5141 background-color: #999;
5141 }
5142 }
5142
5143
5143 .img-preview {
5144 .img-preview {
5144 max-width: 100%;
5145 max-width: 100%;
5145 height: auto;
5146 height: auto;
5146 margin: 5px;
5147 margin: 5px;
5147 }
5148 }
5148
5149
5149 div.prev-next-comment div.prev-comment,
5150 div.prev-next-comment div.prev-comment,
5150 div.prev-next-comment div.next-comment {
5151 div.prev-next-comment div.next-comment {
5151 display: inline-block;
5152 display: inline-block;
5152 min-width: 150px;
5153 min-width: 150px;
5153 margin: 3px 6px;
5154 margin: 3px 6px;
5154 }
5155 }
5155
5156
5156 #help_kb {
5157 #help_kb {
5157 display: none;
5158 display: none;
5158 }
5159 }
5159
5160
5160 .repo-switcher-dropdown .select2-result-label span.repo-icons {
5161 .repo-switcher-dropdown .select2-result-label span.repo-icons {
5161 margin-left: -12px;
5162 margin-left: -12px;
5162 }
5163 }
@@ -1,2178 +1,2178 b''
1 /**
1 /**
2 Kallithea JS Files
2 Kallithea JS Files
3 **/
3 **/
4
4
5 if (typeof console == "undefined" || typeof console.log == "undefined"){
5 if (typeof console == "undefined" || typeof console.log == "undefined"){
6 console = { log: function() {} }
6 console = { log: function() {} }
7 }
7 }
8
8
9 /**
9 /**
10 * INJECT .format function into String
10 * INJECT .format function into String
11 * Usage: "My name is {0} {1}".format("Johny","Bravo")
11 * Usage: "My name is {0} {1}".format("Johny","Bravo")
12 * Return "My name is Johny Bravo"
12 * Return "My name is Johny Bravo"
13 * Inspired by https://gist.github.com/1049426
13 * Inspired by https://gist.github.com/1049426
14 */
14 */
15 String.prototype.format = function() {
15 String.prototype.format = function() {
16 function format() {
16 function format() {
17 var str = this;
17 var str = this;
18 var len = arguments.length+1;
18 var len = arguments.length+1;
19 var safe = undefined;
19 var safe = undefined;
20 var arg = undefined;
20 var arg = undefined;
21
21
22 // For each {0} {1} {n...} replace with the argument in that position. If
22 // For each {0} {1} {n...} replace with the argument in that position. If
23 // the argument is an object or an array it will be stringified to JSON.
23 // the argument is an object or an array it will be stringified to JSON.
24 for (var i=0; i < len; arg = arguments[i++]) {
24 for (var i=0; i < len; arg = arguments[i++]) {
25 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
25 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
26 str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
26 str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
27 }
27 }
28 return str;
28 return str;
29 }
29 }
30
30
31 // Save a reference of what may already exist under the property native.
31 // Save a reference of what may already exist under the property native.
32 // Allows for doing something like: if("".format.native) { /* use native */ }
32 // Allows for doing something like: if("".format.native) { /* use native */ }
33 format.native = String.prototype.format;
33 format.native = String.prototype.format;
34
34
35 // Replace the prototype property
35 // Replace the prototype property
36 return format;
36 return format;
37
37
38 }();
38 }();
39
39
40 String.prototype.strip = function(char) {
40 String.prototype.strip = function(char) {
41 if(char === undefined){
41 if(char === undefined){
42 char = '\\s';
42 char = '\\s';
43 }
43 }
44 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
44 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
45 }
45 }
46
46
47 String.prototype.lstrip = function(char) {
47 String.prototype.lstrip = function(char) {
48 if(char === undefined){
48 if(char === undefined){
49 char = '\\s';
49 char = '\\s';
50 }
50 }
51 return this.replace(new RegExp('^'+char+'+'),'');
51 return this.replace(new RegExp('^'+char+'+'),'');
52 }
52 }
53
53
54 String.prototype.rstrip = function(char) {
54 String.prototype.rstrip = function(char) {
55 if(char === undefined){
55 if(char === undefined){
56 char = '\\s';
56 char = '\\s';
57 }
57 }
58 return this.replace(new RegExp(''+char+'+$'),'');
58 return this.replace(new RegExp(''+char+'+$'),'');
59 }
59 }
60
60
61 /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
61 /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
62 under MIT license / public domain, see
62 under MIT license / public domain, see
63 https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
63 https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
64 if(!Array.prototype.indexOf) {
64 if(!Array.prototype.indexOf) {
65 Array.prototype.indexOf = function (searchElement, fromIndex) {
65 Array.prototype.indexOf = function (searchElement, fromIndex) {
66 if ( this === undefined || this === null ) {
66 if ( this === undefined || this === null ) {
67 throw new TypeError( '"this" is null or not defined' );
67 throw new TypeError( '"this" is null or not defined' );
68 }
68 }
69
69
70 var length = this.length >>> 0; // Hack to convert object.length to a UInt32
70 var length = this.length >>> 0; // Hack to convert object.length to a UInt32
71
71
72 fromIndex = +fromIndex || 0;
72 fromIndex = +fromIndex || 0;
73
73
74 if (Math.abs(fromIndex) === Infinity) {
74 if (Math.abs(fromIndex) === Infinity) {
75 fromIndex = 0;
75 fromIndex = 0;
76 }
76 }
77
77
78 if (fromIndex < 0) {
78 if (fromIndex < 0) {
79 fromIndex += length;
79 fromIndex += length;
80 if (fromIndex < 0) {
80 if (fromIndex < 0) {
81 fromIndex = 0;
81 fromIndex = 0;
82 }
82 }
83 }
83 }
84
84
85 for (;fromIndex < length; fromIndex++) {
85 for (;fromIndex < length; fromIndex++) {
86 if (this[fromIndex] === searchElement) {
86 if (this[fromIndex] === searchElement) {
87 return fromIndex;
87 return fromIndex;
88 }
88 }
89 }
89 }
90
90
91 return -1;
91 return -1;
92 };
92 };
93 }
93 }
94
94
95 /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
95 /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
96 under MIT license / public domain, see
96 under MIT license / public domain, see
97 https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
97 https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
98 if (!Array.prototype.filter)
98 if (!Array.prototype.filter)
99 {
99 {
100 Array.prototype.filter = function(fun /*, thisArg */)
100 Array.prototype.filter = function(fun /*, thisArg */)
101 {
101 {
102 "use strict";
102 "use strict";
103
103
104 if (this === void 0 || this === null)
104 if (this === void 0 || this === null)
105 throw new TypeError();
105 throw new TypeError();
106
106
107 var t = Object(this);
107 var t = Object(this);
108 var len = t.length >>> 0;
108 var len = t.length >>> 0;
109 if (typeof fun !== "function")
109 if (typeof fun !== "function")
110 throw new TypeError();
110 throw new TypeError();
111
111
112 var res = [];
112 var res = [];
113 var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
113 var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
114 for (var i = 0; i < len; i++)
114 for (var i = 0; i < len; i++)
115 {
115 {
116 if (i in t)
116 if (i in t)
117 {
117 {
118 var val = t[i];
118 var val = t[i];
119
119
120 // NOTE: Technically this should Object.defineProperty at
120 // NOTE: Technically this should Object.defineProperty at
121 // the next index, as push can be affected by
121 // the next index, as push can be affected by
122 // properties on Object.prototype and Array.prototype.
122 // properties on Object.prototype and Array.prototype.
123 // But that method's new, and collisions should be
123 // But that method's new, and collisions should be
124 // rare, so use the more-compatible alternative.
124 // rare, so use the more-compatible alternative.
125 if (fun.call(thisArg, val, i, t))
125 if (fun.call(thisArg, val, i, t))
126 res.push(val);
126 res.push(val);
127 }
127 }
128 }
128 }
129
129
130 return res;
130 return res;
131 };
131 };
132 }
132 }
133
133
134 /**
134 /**
135 * A customized version of PyRoutes.JS from https://pypi.python.org/pypi/pyroutes.js/
135 * A customized version of PyRoutes.JS from https://pypi.python.org/pypi/pyroutes.js/
136 * which is copyright Stephane Klein and was made available under the BSD License.
136 * which is copyright Stephane Klein and was made available under the BSD License.
137 *
137 *
138 * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id>
138 * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id>
139 */
139 */
140 var pyroutes = (function() {
140 var pyroutes = (function() {
141 // access global map defined in special file pyroutes
141 // access global map defined in special file pyroutes
142 var matchlist = PROUTES_MAP;
142 var matchlist = PROUTES_MAP;
143 var sprintf = (function() {
143 var sprintf = (function() {
144 function get_type(variable) {
144 function get_type(variable) {
145 return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
145 return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
146 }
146 }
147 function str_repeat(input, multiplier) {
147 function str_repeat(input, multiplier) {
148 for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
148 for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
149 return output.join('');
149 return output.join('');
150 }
150 }
151
151
152 var str_format = function() {
152 var str_format = function() {
153 if (!str_format.cache.hasOwnProperty(arguments[0])) {
153 if (!str_format.cache.hasOwnProperty(arguments[0])) {
154 str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
154 str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
155 }
155 }
156 return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
156 return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
157 };
157 };
158
158
159 str_format.format = function(parse_tree, argv) {
159 str_format.format = function(parse_tree, argv) {
160 var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
160 var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
161 for (i = 0; i < tree_length; i++) {
161 for (i = 0; i < tree_length; i++) {
162 node_type = get_type(parse_tree[i]);
162 node_type = get_type(parse_tree[i]);
163 if (node_type === 'string') {
163 if (node_type === 'string') {
164 output.push(parse_tree[i]);
164 output.push(parse_tree[i]);
165 }
165 }
166 else if (node_type === 'array') {
166 else if (node_type === 'array') {
167 match = parse_tree[i]; // convenience purposes only
167 match = parse_tree[i]; // convenience purposes only
168 if (match[2]) { // keyword argument
168 if (match[2]) { // keyword argument
169 arg = argv[cursor];
169 arg = argv[cursor];
170 for (k = 0; k < match[2].length; k++) {
170 for (k = 0; k < match[2].length; k++) {
171 if (!arg.hasOwnProperty(match[2][k])) {
171 if (!arg.hasOwnProperty(match[2][k])) {
172 throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
172 throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
173 }
173 }
174 arg = arg[match[2][k]];
174 arg = arg[match[2][k]];
175 }
175 }
176 }
176 }
177 else if (match[1]) { // positional argument (explicit)
177 else if (match[1]) { // positional argument (explicit)
178 arg = argv[match[1]];
178 arg = argv[match[1]];
179 }
179 }
180 else { // positional argument (implicit)
180 else { // positional argument (implicit)
181 arg = argv[cursor++];
181 arg = argv[cursor++];
182 }
182 }
183
183
184 if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
184 if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
185 throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
185 throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
186 }
186 }
187 switch (match[8]) {
187 switch (match[8]) {
188 case 'b': arg = arg.toString(2); break;
188 case 'b': arg = arg.toString(2); break;
189 case 'c': arg = String.fromCharCode(arg); break;
189 case 'c': arg = String.fromCharCode(arg); break;
190 case 'd': arg = parseInt(arg, 10); break;
190 case 'd': arg = parseInt(arg, 10); break;
191 case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
191 case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
192 case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
192 case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
193 case 'o': arg = arg.toString(8); break;
193 case 'o': arg = arg.toString(8); break;
194 case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
194 case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
195 case 'u': arg = Math.abs(arg); break;
195 case 'u': arg = Math.abs(arg); break;
196 case 'x': arg = arg.toString(16); break;
196 case 'x': arg = arg.toString(16); break;
197 case 'X': arg = arg.toString(16).toUpperCase(); break;
197 case 'X': arg = arg.toString(16).toUpperCase(); break;
198 }
198 }
199 arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
199 arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
200 pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
200 pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
201 pad_length = match[6] - String(arg).length;
201 pad_length = match[6] - String(arg).length;
202 pad = match[6] ? str_repeat(pad_character, pad_length) : '';
202 pad = match[6] ? str_repeat(pad_character, pad_length) : '';
203 output.push(match[5] ? arg + pad : pad + arg);
203 output.push(match[5] ? arg + pad : pad + arg);
204 }
204 }
205 }
205 }
206 return output.join('');
206 return output.join('');
207 };
207 };
208
208
209 str_format.cache = {};
209 str_format.cache = {};
210
210
211 str_format.parse = function(fmt) {
211 str_format.parse = function(fmt) {
212 var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
212 var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
213 while (_fmt) {
213 while (_fmt) {
214 if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
214 if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
215 parse_tree.push(match[0]);
215 parse_tree.push(match[0]);
216 }
216 }
217 else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
217 else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
218 parse_tree.push('%');
218 parse_tree.push('%');
219 }
219 }
220 else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
220 else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
221 if (match[2]) {
221 if (match[2]) {
222 arg_names |= 1;
222 arg_names |= 1;
223 var field_list = [], replacement_field = match[2], field_match = [];
223 var field_list = [], replacement_field = match[2], field_match = [];
224 if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
224 if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
225 field_list.push(field_match[1]);
225 field_list.push(field_match[1]);
226 while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
226 while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
227 if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
227 if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
228 field_list.push(field_match[1]);
228 field_list.push(field_match[1]);
229 }
229 }
230 else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
230 else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
231 field_list.push(field_match[1]);
231 field_list.push(field_match[1]);
232 }
232 }
233 else {
233 else {
234 throw('[sprintf] huh?');
234 throw('[sprintf] huh?');
235 }
235 }
236 }
236 }
237 }
237 }
238 else {
238 else {
239 throw('[sprintf] huh?');
239 throw('[sprintf] huh?');
240 }
240 }
241 match[2] = field_list;
241 match[2] = field_list;
242 }
242 }
243 else {
243 else {
244 arg_names |= 2;
244 arg_names |= 2;
245 }
245 }
246 if (arg_names === 3) {
246 if (arg_names === 3) {
247 throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
247 throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
248 }
248 }
249 parse_tree.push(match);
249 parse_tree.push(match);
250 }
250 }
251 else {
251 else {
252 throw('[sprintf] huh?');
252 throw('[sprintf] huh?');
253 }
253 }
254 _fmt = _fmt.substring(match[0].length);
254 _fmt = _fmt.substring(match[0].length);
255 }
255 }
256 return parse_tree;
256 return parse_tree;
257 };
257 };
258
258
259 return str_format;
259 return str_format;
260 })();
260 })();
261
261
262 var vsprintf = function(fmt, argv) {
262 var vsprintf = function(fmt, argv) {
263 argv.unshift(fmt);
263 argv.unshift(fmt);
264 return sprintf.apply(null, argv);
264 return sprintf.apply(null, argv);
265 };
265 };
266 return {
266 return {
267 'url': function(route_name, params) {
267 'url': function(route_name, params) {
268 var result = route_name;
268 var result = route_name;
269 if (typeof(params) != 'object'){
269 if (typeof(params) != 'object'){
270 params = {};
270 params = {};
271 }
271 }
272 if (matchlist.hasOwnProperty(route_name)) {
272 if (matchlist.hasOwnProperty(route_name)) {
273 var route = matchlist[route_name];
273 var route = matchlist[route_name];
274 // param substitution
274 // param substitution
275 for(var i=0; i < route[1].length; i++) {
275 for(var i=0; i < route[1].length; i++) {
276 if (!params.hasOwnProperty(route[1][i]))
276 if (!params.hasOwnProperty(route[1][i]))
277 throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
277 throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
278 }
278 }
279 result = sprintf(route[0], params);
279 result = sprintf(route[0], params);
280
280
281 var ret = [];
281 var ret = [];
282 //extra params => GET
282 //extra params => GET
283 for(param in params){
283 for(param in params){
284 if (route[1].indexOf(param) == -1){
284 if (route[1].indexOf(param) == -1){
285 ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));
285 ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));
286 }
286 }
287 }
287 }
288 var _parts = ret.join("&");
288 var _parts = ret.join("&");
289 if(_parts){
289 if(_parts){
290 result = result +'?'+ _parts
290 result = result +'?'+ _parts
291 }
291 }
292 }
292 }
293
293
294 return result;
294 return result;
295 },
295 },
296 'register': function(route_name, route_tmpl, req_params) {
296 'register': function(route_name, route_tmpl, req_params) {
297 if (typeof(req_params) != 'object') {
297 if (typeof(req_params) != 'object') {
298 req_params = [];
298 req_params = [];
299 }
299 }
300 //fix escape
300 //fix escape
301 route_tmpl = unescape(route_tmpl);
301 route_tmpl = unescape(route_tmpl);
302 keys = [];
302 keys = [];
303 for (var i=0; i < req_params.length; i++) {
303 for (var i=0; i < req_params.length; i++) {
304 keys.push(req_params[i])
304 keys.push(req_params[i])
305 }
305 }
306 matchlist[route_name] = [
306 matchlist[route_name] = [
307 route_tmpl,
307 route_tmpl,
308 keys
308 keys
309 ]
309 ]
310 },
310 },
311 '_routes': function(){
311 '_routes': function(){
312 return matchlist;
312 return matchlist;
313 }
313 }
314 }
314 }
315 })();
315 })();
316
316
317
317
318 /**
318 /**
319 * GLOBAL YUI Shortcuts
319 * GLOBAL YUI Shortcuts
320 */
320 */
321 var YUC = YAHOO.util.Connect;
321 var YUC = YAHOO.util.Connect;
322 var YUD = YAHOO.util.Dom;
322 var YUD = YAHOO.util.Dom;
323 var YUE = YAHOO.util.Event;
323 var YUE = YAHOO.util.Event;
324 var YUQ = YAHOO.util.Selector.query;
324 var YUQ = YAHOO.util.Selector.query;
325
325
326 /* Invoke all functions in callbacks */
326 /* Invoke all functions in callbacks */
327 var _run_callbacks = function(callbacks){
327 var _run_callbacks = function(callbacks){
328 if (callbacks !== undefined){
328 if (callbacks !== undefined){
329 var _l = callbacks.length;
329 var _l = callbacks.length;
330 for (var i=0;i<_l;i++){
330 for (var i=0;i<_l;i++){
331 var func = callbacks[i];
331 var func = callbacks[i];
332 if(typeof(func)=='function'){
332 if(typeof(func)=='function'){
333 try{
333 try{
334 func();
334 func();
335 }catch (err){};
335 }catch (err){};
336 }
336 }
337 }
337 }
338 }
338 }
339 }
339 }
340
340
341 /**
341 /**
342 * turns objects into GET query string
342 * turns objects into GET query string
343 */
343 */
344 var _toQueryString = function(o) {
344 var _toQueryString = function(o) {
345 if(typeof o !== 'object') {
345 if(typeof o !== 'object') {
346 return false;
346 return false;
347 }
347 }
348 var _p, _qs = [];
348 var _p, _qs = [];
349 for(_p in o) {
349 for(_p in o) {
350 _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
350 _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
351 }
351 }
352 return _qs.join('&');
352 return _qs.join('&');
353 };
353 };
354
354
355 /**
355 /**
356 * Load HTML into DOM using Ajax
356 * Load HTML into DOM using Ajax
357 *
357 *
358 * @param $target: load html async and place it (or an error message) here
358 * @param $target: load html async and place it (or an error message) here
359 * @param success: success callback function
359 * @param success: success callback function
360 * @param args: query parameters to pass to url
360 * @param args: query parameters to pass to url
361 */
361 */
362 function asynchtml(url, $target, success, args){
362 function asynchtml(url, $target, success, args){
363 if(args===undefined){
363 if(args===undefined){
364 args=null;
364 args=null;
365 }
365 }
366 $target.html(_TM['Loading ...']).css('opacity','0.3');
366 $target.html(_TM['Loading ...']).css('opacity','0.3');
367
367
368 $.ajax({url: url, data: args, headers: {'X-PARTIAL-XHR': '1'}, cache: false, dataType: 'html'})
368 $.ajax({url: url, data: args, headers: {'X-PARTIAL-XHR': '1'}, cache: false, dataType: 'html'})
369 .done(function(html) {
369 .done(function(html) {
370 $target.html(html);
370 $target.html(html);
371 $target.css('opacity','1.0');
371 $target.css('opacity','1.0');
372 //execute the given original callback
372 //execute the given original callback
373 if (success !== undefined && success) {
373 if (success !== undefined && success) {
374 success();
374 success();
375 }
375 }
376 })
376 })
377 .fail(function(jqXHR, textStatus, errorThrown) {
377 .fail(function(jqXHR, textStatus, errorThrown) {
378 console.log('Ajax failure: ' + textStatus);
378 console.log('Ajax failure: ' + textStatus);
379 $target.html('<span class="error_red">ERROR: {0}</span>'.format(textStatus));
379 $target.html('<span class="error_red">ERROR: {0}</span>'.format(textStatus));
380 $target.css('opacity','1.0');
380 $target.css('opacity','1.0');
381 })
381 })
382 ;
382 ;
383 };
383 };
384
384
385 var ajaxGET = function(url,success) {
385 var ajaxGET = function(url,success) {
386 // Set special header for ajax == HTTP_X_PARTIAL_XHR
386 // Set special header for ajax == HTTP_X_PARTIAL_XHR
387 YUC.initHeader('X-PARTIAL-XHR',true);
387 YUC.initHeader('X-PARTIAL-XHR',true);
388
388
389 var sUrl = url;
389 var sUrl = url;
390 var callback = {
390 var callback = {
391 success: success,
391 success: success,
392 failure: function (o) {
392 failure: function (o) {
393 if (o.status != 0) {
393 if (o.status != 0) {
394 alert("Ajax GET error: " + o.statusText);
394 alert("Ajax GET error: " + o.statusText);
395 };
395 };
396 }
396 }
397 };
397 };
398
398
399 var request = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback);
399 var request = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback);
400 return request;
400 return request;
401 };
401 };
402
402
403 var ajaxPOST = function(url,postData,success) {
403 var ajaxPOST = function(url,postData,success) {
404 // Set special header for ajax == HTTP_X_PARTIAL_XHR
404 // Set special header for ajax == HTTP_X_PARTIAL_XHR
405 YUC.initHeader('X-PARTIAL-XHR',true);
405 YUC.initHeader('X-PARTIAL-XHR',true);
406
406
407 var sUrl = url;
407 var sUrl = url;
408 var callback = {
408 var callback = {
409 success: success,
409 success: success,
410 failure: function (o) {
410 failure: function (o) {
411 alert("Ajax POST error: " + o.statusText);
411 alert("Ajax POST error: " + o.statusText);
412 }
412 }
413 };
413 };
414 var postData = _toQueryString(postData);
414 var postData = _toQueryString(postData);
415 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
415 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
416 return request;
416 return request;
417 };
417 };
418
418
419
419
420 /**
420 /**
421 * activate .show_more links
421 * activate .show_more links
422 * the .show_more must have an id that is the the id of an element to hide prefixed with _
422 * the .show_more must have an id that is the the id of an element to hide prefixed with _
423 * the parentnode will be displayed
423 * the parentnode will be displayed
424 */
424 */
425 var show_more_event = function(){
425 var show_more_event = function(){
426 $('.show_more').click(function(e){
426 $('.show_more').click(function(e){
427 var el = e.currentTarget;
427 var el = e.currentTarget;
428 $('#' + el.id.substring(1)).hide();
428 $('#' + el.id.substring(1)).hide();
429 $(el.parentNode).show();
429 $(el.parentNode).show();
430 });
430 });
431 };
431 };
432
432
433 /**
433 /**
434 * activate .lazy-cs mouseover for showing changeset tooltip
434 * activate .lazy-cs mouseover for showing changeset tooltip
435 */
435 */
436 var show_changeset_tooltip = function(){
436 var show_changeset_tooltip = function(){
437 $('.lazy-cs').mouseover(function(e){
437 $('.lazy-cs').mouseover(function(e){
438 var $target = $(e.currentTarget);
438 var $target = $(e.currentTarget);
439 var rid = $target.attr('raw_id');
439 var rid = $target.attr('raw_id');
440 var repo_name = $target.attr('repo_name');
440 var repo_name = $target.attr('repo_name');
441 if(rid && !$target.hasClass('tooltip')){
441 if(rid && !$target.hasClass('tooltip')){
442 _show_tooltip(e, _TM['loading ...']);
442 _show_tooltip(e, _TM['loading ...']);
443 var url = pyroutes.url('changeset_info', {"repo_name": repo_name, "revision": rid});
443 var url = pyroutes.url('changeset_info', {"repo_name": repo_name, "revision": rid});
444 ajaxGET(url, function(o){
444 ajaxGET(url, function(o){
445 var json = JSON.parse(o.responseText);
445 var json = JSON.parse(o.responseText);
446 $target.addClass('tooltip')
446 $target.addClass('tooltip')
447 _show_tooltip(e, json['message']);
447 _show_tooltip(e, json['message']);
448 _activate_tooltip($target);
448 _activate_tooltip($target);
449 });
449 });
450 }
450 }
451 });
451 });
452 };
452 };
453
453
454 var _onSuccessFollow = function(target){
454 var _onSuccessFollow = function(target){
455 var $target = $(target);
455 var $target = $(target);
456 var $f_cnt = $('#current_followers_count');
456 var $f_cnt = $('#current_followers_count');
457 if($target.hasClass('follow')){
457 if($target.hasClass('follow')){
458 $target.attr('class', 'following');
458 $target.attr('class', 'following');
459 $target.attr('title', _TM['Stop following this repository']);
459 $target.attr('title', _TM['Stop following this repository']);
460 if($f_cnt.html()){
460 if($f_cnt.html()){
461 var cnt = Number($f_cnt.html())+1;
461 var cnt = Number($f_cnt.html())+1;
462 $f_cnt.html(cnt);
462 $f_cnt.html(cnt);
463 }
463 }
464 }
464 }
465 else{
465 else{
466 $target.attr('class', 'follow');
466 $target.attr('class', 'follow');
467 $target.attr('title', _TM['Start following this repository']);
467 $target.attr('title', _TM['Start following this repository']);
468 if($f_cnt.html()){
468 if($f_cnt.html()){
469 var cnt = Number($f_cnt.html())-1;
469 var cnt = Number($f_cnt.html())-1;
470 $f_cnt.html(cnt);
470 $f_cnt.html(cnt);
471 }
471 }
472 }
472 }
473 }
473 }
474
474
475 var toggleFollowingRepo = function(target, follows_repo_id, token, user_id){
475 var toggleFollowingRepo = function(target, follows_repo_id, token, user_id){
476 args = 'follows_repo_id='+follows_repo_id;
476 args = 'follows_repo_id='+follows_repo_id;
477 args+= '&amp;auth_token='+token;
477 args+= '&amp;auth_token='+token;
478 if(user_id != undefined){
478 if(user_id != undefined){
479 args+="&amp;user_id="+user_id;
479 args+="&amp;user_id="+user_id;
480 }
480 }
481 $.post(TOGGLE_FOLLOW_URL, args, function(data){
481 $.post(TOGGLE_FOLLOW_URL, args, function(data){
482 _onSuccessFollow(target);
482 _onSuccessFollow(target);
483 });
483 });
484 return false;
484 return false;
485 };
485 };
486
486
487 var showRepoSize = function(target, repo_name, token){
487 var showRepoSize = function(target, repo_name, token){
488 var args= 'auth_token='+token;
488 var args= 'auth_token='+token;
489
489
490 if(!$("#" + target).hasClass('loaded')){
490 if(!$("#" + target).hasClass('loaded')){
491 $("#" + target).html(_TM['Loading ...']);
491 $("#" + target).html(_TM['Loading ...']);
492 var url = pyroutes.url('repo_size', {"repo_name":repo_name});
492 var url = pyroutes.url('repo_size', {"repo_name":repo_name});
493 $.post(url, args, function(data) {
493 $.post(url, args, function(data) {
494 $("#" + target).html(data);
494 $("#" + target).html(data);
495 $("#" + target).addClass('loaded');
495 $("#" + target).addClass('loaded');
496 });
496 });
497 }
497 }
498 return false;
498 return false;
499 };
499 };
500
500
501 /**
501 /**
502 * tooltips
502 * tooltips
503 */
503 */
504
504
505 var tooltip_activate = function(){
505 var tooltip_activate = function(){
506 $(document).ready(_init_tooltip);
506 $(document).ready(_init_tooltip);
507 };
507 };
508
508
509 var _activate_tooltip = function($tt){
509 var _activate_tooltip = function($tt){
510 $tt.mouseover(_show_tooltip);
510 $tt.mouseover(_show_tooltip);
511 $tt.mousemove(_move_tooltip);
511 $tt.mousemove(_move_tooltip);
512 $tt.mouseout(_close_tooltip);
512 $tt.mouseout(_close_tooltip);
513 };
513 };
514
514
515 var _init_tooltip = function(){
515 var _init_tooltip = function(){
516 var $tipBox = $('#tip-box');
516 var $tipBox = $('#tip-box');
517 if(!$tipBox.length){
517 if(!$tipBox.length){
518 $tipBox = $('<div id="tip-box"></div>')
518 $tipBox = $('<div id="tip-box"></div>')
519 $(document.body).append($tipBox);
519 $(document.body).append($tipBox);
520 }
520 }
521
521
522 $tipBox.hide();
522 $tipBox.hide();
523 $tipBox.css('position', 'absolute');
523 $tipBox.css('position', 'absolute');
524 $tipBox.css('max-width', '600px');
524 $tipBox.css('max-width', '600px');
525
525
526 _activate_tooltip($('.tooltip'));
526 _activate_tooltip($('.tooltip'));
527 };
527 };
528
528
529 var _show_tooltip = function(e, tipText){
529 var _show_tooltip = function(e, tipText){
530 e.stopImmediatePropagation();
530 e.stopImmediatePropagation();
531 var el = e.currentTarget;
531 var el = e.currentTarget;
532 if(tipText){
532 if(tipText){
533 // just use it
533 // just use it
534 } else if(el.tagName.toLowerCase() === 'img'){
534 } else if(el.tagName.toLowerCase() === 'img'){
535 tipText = el.alt ? el.alt : '';
535 tipText = el.alt ? el.alt : '';
536 } else {
536 } else {
537 tipText = el.title ? el.title : '';
537 tipText = el.title ? el.title : '';
538 }
538 }
539
539
540 if(tipText !== ''){
540 if(tipText !== ''){
541 // save org title
541 // save org title
542 $(el).attr('tt_title', tipText);
542 $(el).attr('tt_title', tipText);
543 // reset title to not show org tooltips
543 // reset title to not show org tooltips
544 $(el).attr('title', '');
544 $(el).attr('title', '');
545
545
546 var $tipBox = $('#tip-box');
546 var $tipBox = $('#tip-box');
547 $tipBox.html(tipText);
547 $tipBox.html(tipText);
548 $tipBox.css('display', 'block');
548 $tipBox.css('display', 'block');
549 }
549 }
550 };
550 };
551
551
552 var _move_tooltip = function(e){
552 var _move_tooltip = function(e){
553 e.stopImmediatePropagation();
553 e.stopImmediatePropagation();
554 var $tipBox = $('#tip-box');
554 var $tipBox = $('#tip-box');
555 $tipBox.css('top', (e.pageY + 15) + 'px');
555 $tipBox.css('top', (e.pageY + 15) + 'px');
556 $tipBox.css('left', (e.pageX + 15) + 'px');
556 $tipBox.css('left', (e.pageX + 15) + 'px');
557 };
557 };
558
558
559 var _close_tooltip = function(e){
559 var _close_tooltip = function(e){
560 e.stopImmediatePropagation();
560 e.stopImmediatePropagation();
561 var $tipBox = $('#tip-box');
561 var $tipBox = $('#tip-box');
562 $tipBox.hide();
562 $tipBox.hide();
563 var el = e.currentTarget;
563 var el = e.currentTarget;
564 $(el).attr('title', $(el).attr('tt_title'));
564 $(el).attr('title', $(el).attr('tt_title'));
565 };
565 };
566
566
567 /**
567 /**
568 * Quick filter widget
568 * Quick filter widget
569 *
569 *
570 * @param target: filter input target
570 * @param target: filter input target
571 * @param nodes: list of nodes in html we want to filter.
571 * @param nodes: list of nodes in html we want to filter.
572 * @param display_element function that takes current node from nodes and
572 * @param display_element function that takes current node from nodes and
573 * does hide or show based on the node
573 * does hide or show based on the node
574 */
574 */
575 var q_filter = function(target, nodes, display_element){
575 var q_filter = function(target, nodes, display_element){
576 var nodes = nodes;
576 var nodes = nodes;
577 var $q_filter_field = $('#' + target);
577 var $q_filter_field = $('#' + target);
578 var F = YAHOO.namespace(target);
578 var F = YAHOO.namespace(target);
579
579
580 $q_filter_field.keyup(function(e){
580 $q_filter_field.keyup(function(e){
581 clearTimeout(F.filterTimeout);
581 clearTimeout(F.filterTimeout);
582 F.filterTimeout = setTimeout(F.updateFilter, 600);
582 F.filterTimeout = setTimeout(F.updateFilter, 600);
583 });
583 });
584
584
585 F.filterTimeout = null;
585 F.filterTimeout = null;
586
586
587 F.updateFilter = function() {
587 F.updateFilter = function() {
588 // Reset timeout
588 // Reset timeout
589 F.filterTimeout = null;
589 F.filterTimeout = null;
590
590
591 var obsolete = [];
591 var obsolete = [];
592
592
593 var req = $q_filter_field.val().toLowerCase();
593 var req = $q_filter_field.val().toLowerCase();
594
594
595 var l = nodes.length;
595 var l = nodes.length;
596 var i;
596 var i;
597 var showing = 0;
597 var showing = 0;
598
598
599 for (i=0; i<l; i++ ){
599 for (i=0; i<l; i++ ){
600 var n = nodes[i];
600 var n = nodes[i];
601 var target_element = display_element(n)
601 var target_element = display_element(n)
602 if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
602 if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
603 $(target_element).hide();
603 $(target_element).hide();
604 }
604 }
605 else{
605 else{
606 $(target_element).show();
606 $(target_element).show();
607 showing += 1;
607 showing += 1;
608 }
608 }
609 }
609 }
610
610
611 $('#repo_count').html(showing); /* FIXME: don't hardcode */
611 $('#repo_count').html(showing); /* FIXME: don't hardcode */
612 }
612 }
613 };
613 };
614
614
615 /* return jQuery expression with a tr with body in 3rd column and class cls and id named after the body */
615 /* return jQuery expression with a tr with body in 3rd column and class cls and id named after the body */
616 var _table_tr = function(cls, body){
616 var _table_tr = function(cls, body){
617 // like: <div class="comment" id="comment-8" line="o92"><div class="comment-wrapp">...
617 // like: <div class="comment" id="comment-8" line="o92"><div class="comment-wrapp">...
618 // except new inlines which are different ...
618 // except new inlines which are different ...
619 var comment_id = ($(body).attr('id') || 'comment-new').split('comment-')[1];
619 var comment_id = ($(body).attr('id') || 'comment-new').split('comment-')[1];
620 var tr_id = 'comment-tr-{0}'.format(comment_id);
620 var tr_id = 'comment-tr-{0}'.format(comment_id);
621 return $(('<tr id="{0}" class="{1}">'+
621 return $(('<tr id="{0}" class="{1}">'+
622 '<td class="lineno-inline new-inline"></td>'+
622 '<td class="lineno-inline new-inline"></td>'+
623 '<td class="lineno-inline old-inline"></td>'+
623 '<td class="lineno-inline old-inline"></td>'+
624 '<td>{2}</td>'+
624 '<td>{2}</td>'+
625 '</tr>').format(tr_id, cls, body));
625 '</tr>').format(tr_id, cls, body));
626 };
626 };
627
627
628 /** return jQuery expression with new inline form based on template **/
628 /** return jQuery expression with new inline form based on template **/
629 var _createInlineForm = function(parent_tr, f_path, line) {
629 var _createInlineForm = function(parent_tr, f_path, line) {
630 var $tmpl = $('#comment-inline-form-template').html().format(f_path, line);
630 var $tmpl = $('#comment-inline-form-template').html().format(f_path, line);
631 var $form = _table_tr('comment-form-inline', $tmpl)
631 var $form = _table_tr('comment-form-inline', $tmpl)
632
632
633 // create event for hide button
633 // create event for hide button
634 $form.find('.hide-inline-form').click(function(e) {
634 $form.find('.hide-inline-form').click(function(e) {
635 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
635 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
636 if($(newtr).next().hasClass('inline-comments-button')){
636 if($(newtr).next().hasClass('inline-comments-button')){
637 $(newtr).next().show();
637 $(newtr).next().show();
638 }
638 }
639 $(newtr).remove();
639 $(newtr).remove();
640 $(parent_tr).removeClass('form-open');
640 $(parent_tr).removeClass('form-open');
641 $(parent_tr).removeClass('hl-comment');
641 $(parent_tr).removeClass('hl-comment');
642 });
642 });
643
643
644 return $form
644 return $form
645 };
645 };
646
646
647 /**
647 /**
648 * Inject inline comment for an given TR. This tr should always be a .line .
648 * Inject inline comment for an given TR. This tr should always be a .line .
649 * The form will be inject after any comments.
649 * The form will be inject after any comments.
650 */
650 */
651 var injectInlineForm = function(tr){
651 var injectInlineForm = function(tr){
652 $tr = $(tr);
652 $tr = $(tr);
653 if(!$tr.hasClass('line')){
653 if(!$tr.hasClass('line')){
654 return
654 return
655 }
655 }
656 var submit_url = AJAX_COMMENT_URL;
656 var submit_url = AJAX_COMMENT_URL;
657 var $td = $tr.find('.code');
657 var $td = $tr.find('.code');
658 if($tr.hasClass('form-open') || $tr.hasClass('context') || $td.hasClass('no-comment')){
658 if($tr.hasClass('form-open') || $tr.hasClass('context') || $td.hasClass('no-comment')){
659 return
659 return
660 }
660 }
661 $tr.addClass('form-open hl-comment');
661 $tr.addClass('form-open hl-comment');
662 var $node = $tr.parent().parent().parent().find('.full_f_path');
662 var $node = $tr.parent().parent().parent().find('.full_f_path');
663 var f_path = $node.attr('path');
663 var f_path = $node.attr('path');
664 var lineno = _getLineNo(tr);
664 var lineno = _getLineNo(tr);
665 var $form = _createInlineForm(tr, f_path, lineno, submit_url);
665 var $form = _createInlineForm(tr, f_path, lineno, submit_url);
666
666
667 var $parent = $tr;
667 var $parent = $tr;
668 while ($parent.next().hasClass('inline-comments')){
668 while ($parent.next().hasClass('inline-comments')){
669 var $parent = $parent.next();
669 var $parent = $parent.next();
670 }
670 }
671 $form.insertAfter($parent);
671 $form.insertAfter($parent);
672 var $overlay = $form.find('.submitting-overlay');
672 var $overlay = $form.find('.submitting-overlay');
673 var $inlineform = $form.find('.inline-form');
673 var $inlineform = $form.find('.inline-form');
674
674
675 $form.submit(function(e){
675 $form.submit(function(e){
676 e.preventDefault();
676 e.preventDefault();
677
677
678 if(lineno === undefined){
678 if(lineno === undefined){
679 alert('Error submitting, line ' + lineno + ' not found.');
679 alert('Error submitting, line ' + lineno + ' not found.');
680 return
680 return
681 }
681 }
682 if(f_path === undefined){
682 if(f_path === undefined){
683 alert('Error submitting, file path ' + f_path + ' not found.');
683 alert('Error submitting, file path ' + f_path + ' not found.');
684 return
684 return
685 }
685 }
686
686
687 var text = $('#text_'+lineno).val();
687 var text = $('#text_'+lineno).val();
688 if(text == ""){
688 if(text == ""){
689 return
689 return
690 }
690 }
691
691
692 $overlay.show();
692 $overlay.show();
693
693
694 var success = function(o){
694 var success = function(o){
695 $tr.removeClass('form-open');
695 $tr.removeClass('form-open');
696 $form.remove();
696 $form.remove();
697 var json_data = JSON.parse(o.responseText);
697 var json_data = JSON.parse(o.responseText);
698 _renderInlineComment(json_data);
698 _renderInlineComment(json_data);
699 };
699 };
700 var postData = {
700 var postData = {
701 'text': text,
701 'text': text,
702 'f_path': f_path,
702 'f_path': f_path,
703 'line': lineno
703 'line': lineno
704 };
704 };
705 ajaxPOST(submit_url, postData, success);
705 ajaxPOST(submit_url, postData, success);
706 });
706 });
707
707
708 $('#preview-btn_'+lineno).click(function(e){
708 $('#preview-btn_'+lineno).click(function(e){
709 var text = $('#text_'+lineno).val();
709 var text = $('#text_'+lineno).val();
710 if(!text){
710 if(!text){
711 return
711 return
712 }
712 }
713 $('#preview-box_'+lineno).addClass('unloaded');
713 $('#preview-box_'+lineno).addClass('unloaded');
714 $('#preview-box_'+lineno).html(_TM['Loading ...']);
714 $('#preview-box_'+lineno).html(_TM['Loading ...']);
715 $('#edit-container_'+lineno).hide();
715 $('#edit-container_'+lineno).hide();
716 $('#edit-btn_'+lineno).show();
716 $('#edit-btn_'+lineno).show();
717 $('#preview-container_'+lineno).show();
717 $('#preview-container_'+lineno).show();
718 $('#preview-btn_'+lineno).hide();
718 $('#preview-btn_'+lineno).hide();
719
719
720 var url = pyroutes.url('changeset_comment_preview', {'repo_name': REPO_NAME});
720 var url = pyroutes.url('changeset_comment_preview', {'repo_name': REPO_NAME});
721 var post_data = {'text': text};
721 var post_data = {'text': text};
722 ajaxPOST(url, post_data, function(o){
722 ajaxPOST(url, post_data, function(o){
723 $('#preview-box_'+lineno).html(o.responseText);
723 $('#preview-box_'+lineno).html(o.responseText);
724 $('#preview-box_'+lineno).removeClass('unloaded');
724 $('#preview-box_'+lineno).removeClass('unloaded');
725 })
725 })
726 })
726 })
727 $('#edit-btn_'+lineno).click(function(e){
727 $('#edit-btn_'+lineno).click(function(e){
728 $('#edit-container_'+lineno).show();
728 $('#edit-container_'+lineno).show();
729 $('#edit-btn_'+lineno).hide();
729 $('#edit-btn_'+lineno).hide();
730 $('#preview-container_'+lineno).hide();
730 $('#preview-container_'+lineno).hide();
731 $('#preview-btn_'+lineno).show();
731 $('#preview-btn_'+lineno).show();
732 })
732 })
733
733
734 setTimeout(function(){
734 setTimeout(function(){
735 // callbacks
735 // callbacks
736 tooltip_activate();
736 tooltip_activate();
737 MentionsAutoComplete('text_'+lineno, 'mentions_container_'+lineno,
737 MentionsAutoComplete('text_'+lineno, 'mentions_container_'+lineno,
738 _USERS_AC_DATA, _GROUPS_AC_DATA);
738 _USERS_AC_DATA, _GROUPS_AC_DATA);
739 $('#text_'+lineno).focus();
739 $('#text_'+lineno).focus();
740 },10)
740 },10)
741 };
741 };
742
742
743 var deleteComment = function(comment_id){
743 var deleteComment = function(comment_id){
744 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
744 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
745 var postData = {'_method':'delete'};
745 var postData = {'_method':'delete'};
746 var success = function(o){
746 var success = function(o){
747 var $deleted = $('#comment-tr-'+comment_id);
747 var $deleted = $('#comment-tr-'+comment_id);
748 var $prev = $deleted.prev('tr');
748 var $prev = $deleted.prev('tr');
749 $deleted.remove();
749 $deleted.remove();
750 _placeAddButton($prev);
750 _placeAddButton($prev);
751 }
751 }
752 ajaxPOST(url,postData,success);
752 ajaxPOST(url,postData,success);
753 }
753 }
754
754
755 var _getLineNo = function(tr) {
755 var _getLineNo = function(tr) {
756 var line;
756 var line;
757 var o = $(tr).children()[0].id.split('_');
757 var o = $(tr).children()[0].id.split('_');
758 var n = $(tr).children()[1].id.split('_');
758 var n = $(tr).children()[1].id.split('_');
759
759
760 if (n.length >= 2) {
760 if (n.length >= 2) {
761 line = n[n.length-1];
761 line = n[n.length-1];
762 } else if (o.length >= 2) {
762 } else if (o.length >= 2) {
763 line = o[o.length-1];
763 line = o[o.length-1];
764 }
764 }
765
765
766 return line
766 return line
767 };
767 };
768
768
769 var _placeAddButton = function($line_tr){
769 var _placeAddButton = function($line_tr){
770 var $tr = $line_tr;
770 var $tr = $line_tr;
771 while ($tr.next().hasClass('inline-comments')){
771 while ($tr.next().hasClass('inline-comments')){
772 $tr.find('.add-comment').remove();
772 $tr.find('.add-comment').remove();
773 $tr = $tr.next();
773 $tr = $tr.next();
774 }
774 }
775 $tr.find('.add-comment').remove();
775 $tr.find('.add-comment').remove();
776 var label = TRANSLATION_MAP['Add another comment'];
776 var label = TRANSLATION_MAP['Add Another Comment'];
777 var $html_el = $('<div class="add-comment"><span class="btn btn-mini">{0}</span></div>'.format(label));
777 var $html_el = $('<div class="add-comment"><span class="btn btn-mini">{0}</span></div>'.format(label));
778 $html_el.click(function(e) {
778 $html_el.click(function(e) {
779 injectInlineForm($line_tr);
779 injectInlineForm($line_tr);
780 });
780 });
781 $tr.find('.comment').after($html_el);
781 $tr.find('.comment').after($html_el);
782 };
782 };
783
783
784 /**
784 /**
785 * Places the inline comment into the changeset block in proper line position
785 * Places the inline comment into the changeset block in proper line position
786 */
786 */
787 var _placeInline = function(target_id, lineno, html){
787 var _placeInline = function(target_id, lineno, html){
788 var $td = $("#{0}_{1}".format(target_id, lineno));
788 var $td = $("#{0}_{1}".format(target_id, lineno));
789 if (!$td.length){
789 if (!$td.length){
790 return false;
790 return false;
791 }
791 }
792
792
793 // check if there are comments already !
793 // check if there are comments already !
794 var $line_tr = $td.parent(); // the tr
794 var $line_tr = $td.parent(); // the tr
795 var $after_tr = $line_tr;
795 var $after_tr = $line_tr;
796 while ($after_tr.next().hasClass('inline-comments')){
796 while ($after_tr.next().hasClass('inline-comments')){
797 $after_tr = $after_tr.next();
797 $after_tr = $after_tr.next();
798 }
798 }
799 // put in the comment at the bottom
799 // put in the comment at the bottom
800 var $tr = _table_tr('inline-comments', html)
800 var $tr = _table_tr('inline-comments', html)
801 $tr.find('div.comment').addClass('inline-comment');
801 $tr.find('div.comment').addClass('inline-comment');
802 $after_tr.after($tr);
802 $after_tr.after($tr);
803
803
804 // scan nodes, and attach add button to last one
804 // scan nodes, and attach add button to last one
805 _placeAddButton($line_tr);
805 _placeAddButton($line_tr);
806 return true;
806 return true;
807 }
807 }
808
808
809 /**
809 /**
810 * make a single inline comment and place it inside
810 * make a single inline comment and place it inside
811 */
811 */
812 var _renderInlineComment = function(json_data){
812 var _renderInlineComment = function(json_data){
813 var html = json_data['rendered_text'];
813 var html = json_data['rendered_text'];
814 var lineno = json_data['line_no'];
814 var lineno = json_data['line_no'];
815 var target_id = json_data['target_id'];
815 var target_id = json_data['target_id'];
816 return _placeInline(target_id, lineno, html);
816 return _placeInline(target_id, lineno, html);
817 }
817 }
818
818
819 /**
819 /**
820 * Iterates over all the inlines, and places them inside proper blocks of data
820 * Iterates over all the inlines, and places them inside proper blocks of data
821 */
821 */
822 var renderInlineComments = function(file_comments){
822 var renderInlineComments = function(file_comments){
823 for (f in file_comments){
823 for (f in file_comments){
824 // holding all comments for a FILE
824 // holding all comments for a FILE
825 var box = file_comments[f];
825 var box = file_comments[f];
826
826
827 var target_id = $(box).attr('target_id');
827 var target_id = $(box).attr('target_id');
828 // actual comments with line numbers
828 // actual comments with line numbers
829 var comments = box.children;
829 var comments = box.children;
830 for(var i=0; i<comments.length; i++){
830 for(var i=0; i<comments.length; i++){
831 var data = {
831 var data = {
832 'rendered_text': comments[i].outerHTML,
832 'rendered_text': comments[i].outerHTML,
833 'line_no': $(comments[i]).attr('line'),
833 'line_no': $(comments[i]).attr('line'),
834 'target_id': target_id
834 'target_id': target_id
835 }
835 }
836 if (_renderInlineComment(data)) {
836 if (_renderInlineComment(data)) {
837 $(comments[i]).hide();
837 $(comments[i]).hide();
838 }else{
838 }else{
839 var txt = document.createTextNode(
839 var txt = document.createTextNode(
840 "Comment to " + YUD.getAttribute(comments[i].parentNode,'path') +
840 "Comment to " + YUD.getAttribute(comments[i].parentNode,'path') +
841 " line " + data.line_no +
841 " line " + data.line_no +
842 " which is outside the diff context:");
842 " which is outside the diff context:");
843 comments[i].insertBefore(txt, comments[i].firstChild);
843 comments[i].insertBefore(txt, comments[i].firstChild);
844 }
844 }
845 }
845 }
846 $(box).show();
846 $(box).show();
847 }
847 }
848 }
848 }
849
849
850 /**
850 /**
851 * Double link comments
851 * Double link comments
852 */
852 */
853 var linkInlineComments = function(firstlinks, comments){
853 var linkInlineComments = function(firstlinks, comments){
854 var $comments = $(comments);
854 var $comments = $(comments);
855 if ($comments.length > 0) {
855 if ($comments.length > 0) {
856 $(firstlinks).html('<a href="#{0}">First comment</a>'.format($comments.attr('id')));
856 $(firstlinks).html('<a href="#{0}">First comment</a>'.format($comments.attr('id')));
857 }
857 }
858 if ($comments.length <= 1) {
858 if ($comments.length <= 1) {
859 return;
859 return;
860 }
860 }
861
861
862 $comments.each(function(i, e){
862 $comments.each(function(i, e){
863 var prev = '';
863 var prev = '';
864 if (i > 0){
864 if (i > 0){
865 var prev_anchor = YUD.getAttribute(comments.item(i-1),'id');
865 var prev_anchor = YUD.getAttribute(comments.item(i-1),'id');
866 prev = '<a href="#{0}">Previous comment</a>'.format(prev_anchor);
866 prev = '<a href="#{0}">Previous comment</a>'.format(prev_anchor);
867 }
867 }
868 var next = '';
868 var next = '';
869 if (i+1 < comments.length){
869 if (i+1 < comments.length){
870 var next_anchor = YUD.getAttribute(comments.item(i+1),'id');
870 var next_anchor = YUD.getAttribute(comments.item(i+1),'id');
871 next = '<a href="#{0}">Next comment</a>'.format(next_anchor);
871 next = '<a href="#{0}">Next comment</a>'.format(next_anchor);
872 }
872 }
873 var $div = $(('<div class="prev-next-comment">'+
873 var $div = $(('<div class="prev-next-comment">'+
874 '<div class="prev-comment">{0}</div>'+
874 '<div class="prev-comment">{0}</div>'+
875 '<div class="next-comment">{1}</div>').format(prev, next));
875 '<div class="next-comment">{1}</div>').format(prev, next));
876 $div.prependTo(this);
876 $div.prependTo(this);
877 });
877 });
878 }
878 }
879
879
880 /* activate files.html stuff */
880 /* activate files.html stuff */
881 var fileBrowserListeners = function(current_url, node_list_url, url_base){
881 var fileBrowserListeners = function(current_url, node_list_url, url_base){
882 var current_url_branch = "?branch=__BRANCH__";
882 var current_url_branch = "?branch=__BRANCH__";
883
883
884 $('#stay_at_branch').on('click',function(e){
884 $('#stay_at_branch').on('click',function(e){
885 if(e.currentTarget.checked){
885 if(e.currentTarget.checked){
886 var uri = current_url_branch;
886 var uri = current_url_branch;
887 uri = uri.replace('__BRANCH__',e.currentTarget.value);
887 uri = uri.replace('__BRANCH__',e.currentTarget.value);
888 window.location = uri;
888 window.location = uri;
889 }
889 }
890 else{
890 else{
891 window.location = current_url;
891 window.location = current_url;
892 }
892 }
893 })
893 })
894
894
895 var $node_filter = $('#node_filter');
895 var $node_filter = $('#node_filter');
896
896
897 var filterTimeout = null;
897 var filterTimeout = null;
898 var nodes = null;
898 var nodes = null;
899
899
900 var initFilter = function(){
900 var initFilter = function(){
901 $('#node_filter_box_loading').show();
901 $('#node_filter_box_loading').show();
902 $('#search_activate_id').hide();
902 $('#search_activate_id').hide();
903 $('#add_node_id').hide();
903 $('#add_node_id').hide();
904 YUC.initHeader('X-PARTIAL-XHR',true);
904 YUC.initHeader('X-PARTIAL-XHR',true);
905 YUC.asyncRequest('GET', node_list_url, {
905 YUC.asyncRequest('GET', node_list_url, {
906 success:function(o){
906 success:function(o){
907 nodes = JSON.parse(o.responseText).nodes;
907 nodes = JSON.parse(o.responseText).nodes;
908 $('#node_filter_box_loading').hide();
908 $('#node_filter_box_loading').hide();
909 $('#node_filter_box').show();
909 $('#node_filter_box').show();
910 $node_filter.focus();
910 $node_filter.focus();
911 if($node_filter.hasClass('init')){
911 if($node_filter.hasClass('init')){
912 $node_filter.val('');
912 $node_filter.val('');
913 $node_filter.removeClass('init');
913 $node_filter.removeClass('init');
914 }
914 }
915 },
915 },
916 failure:function(o){
916 failure:function(o){
917 console.log('failed to load');
917 console.log('failed to load');
918 }
918 }
919 },null);
919 },null);
920 }
920 }
921
921
922 var updateFilter = function(e) {
922 var updateFilter = function(e) {
923 return function(){
923 return function(){
924 // Reset timeout
924 // Reset timeout
925 filterTimeout = null;
925 filterTimeout = null;
926 var query = e.currentTarget.value.toLowerCase();
926 var query = e.currentTarget.value.toLowerCase();
927 var match = [];
927 var match = [];
928 var matches = 0;
928 var matches = 0;
929 var matches_max = 20;
929 var matches_max = 20;
930 if (query != ""){
930 if (query != ""){
931 for(var i=0;i<nodes.length;i++){
931 for(var i=0;i<nodes.length;i++){
932 var pos = nodes[i].name.toLowerCase().indexOf(query)
932 var pos = nodes[i].name.toLowerCase().indexOf(query)
933 if(query && pos != -1){
933 if(query && pos != -1){
934 matches++
934 matches++
935 //show only certain amount to not kill browser
935 //show only certain amount to not kill browser
936 if (matches > matches_max){
936 if (matches > matches_max){
937 break;
937 break;
938 }
938 }
939
939
940 var n = nodes[i].name;
940 var n = nodes[i].name;
941 var t = nodes[i].type;
941 var t = nodes[i].type;
942 var n_hl = n.substring(0,pos)
942 var n_hl = n.substring(0,pos)
943 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
943 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
944 +n.substring(pos+query.length)
944 +n.substring(pos+query.length)
945 var new_url = url_base.replace('__FPATH__',n);
945 var new_url = url_base.replace('__FPATH__',n);
946 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
946 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
947 }
947 }
948 if(match.length >= matches_max){
948 if(match.length >= matches_max){
949 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
949 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
950 break;
950 break;
951 }
951 }
952 }
952 }
953 }
953 }
954 if(query != ""){
954 if(query != ""){
955 $('#tbody').hide();
955 $('#tbody').hide();
956 $('#tbody_filtered').show();
956 $('#tbody_filtered').show();
957
957
958 if (match.length==0){
958 if (match.length==0){
959 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
959 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
960 }
960 }
961
961
962 $('#tbody_filtered').html(match.join(""));
962 $('#tbody_filtered').html(match.join(""));
963 }
963 }
964 else{
964 else{
965 $('#tbody').show();
965 $('#tbody').show();
966 $('#tbody_filtered').hide();
966 $('#tbody_filtered').hide();
967 }
967 }
968 }
968 }
969 };
969 };
970
970
971 $('#filter_activate').click(function(){
971 $('#filter_activate').click(function(){
972 initFilter();
972 initFilter();
973 });
973 });
974 $node_filter.click(function(){
974 $node_filter.click(function(){
975 if($node_filter.hasClass('init')){
975 if($node_filter.hasClass('init')){
976 $node_filter.val('');
976 $node_filter.val('');
977 $node_filter.removeClass('init');
977 $node_filter.removeClass('init');
978 }
978 }
979 });
979 });
980 $node_filter.keyup(function(e){
980 $node_filter.keyup(function(e){
981 clearTimeout(filterTimeout);
981 clearTimeout(filterTimeout);
982 filterTimeout = setTimeout(updateFilter(e),600);
982 filterTimeout = setTimeout(updateFilter(e),600);
983 });
983 });
984 };
984 };
985
985
986
986
987 var initCodeMirror = function(textarea_id, resetUrl){
987 var initCodeMirror = function(textarea_id, resetUrl){
988 var myCodeMirror = CodeMirror.fromTextArea($('#' + textarea_id)[0], {
988 var myCodeMirror = CodeMirror.fromTextArea($('#' + textarea_id)[0], {
989 mode: "null",
989 mode: "null",
990 lineNumbers: true,
990 lineNumbers: true,
991 indentUnit: 4,
991 indentUnit: 4,
992 autofocus: true
992 autofocus: true
993 });
993 });
994 $('#reset').click(function(e){
994 $('#reset').click(function(e){
995 window.location=resetUrl;
995 window.location=resetUrl;
996 });
996 });
997
997
998 $('#file_enable').click(function(){
998 $('#file_enable').click(function(){
999 $('#editor_container').show();
999 $('#editor_container').show();
1000 $('#upload_file_container').hide();
1000 $('#upload_file_container').hide();
1001 $('#filename_container').show();
1001 $('#filename_container').show();
1002 $('#set_mode_header').show();
1002 $('#set_mode_header').show();
1003 });
1003 });
1004
1004
1005 $('#upload_file_enable').click(function(){
1005 $('#upload_file_enable').click(function(){
1006 $('#editor_container').hide();
1006 $('#editor_container').hide();
1007 $('#upload_file_container').show();
1007 $('#upload_file_container').show();
1008 $('#filename_container').hide();
1008 $('#filename_container').hide();
1009 $('#set_mode_header').hide();
1009 $('#set_mode_header').hide();
1010 });
1010 });
1011
1011
1012 return myCodeMirror
1012 return myCodeMirror
1013 };
1013 };
1014
1014
1015 var setCodeMirrorMode = function(codeMirrorInstance, mode) {
1015 var setCodeMirrorMode = function(codeMirrorInstance, mode) {
1016 codeMirrorInstance.setOption("mode", mode);
1016 codeMirrorInstance.setOption("mode", mode);
1017 CodeMirror.autoLoadMode(codeMirrorInstance, mode);
1017 CodeMirror.autoLoadMode(codeMirrorInstance, mode);
1018 }
1018 }
1019
1019
1020
1020
1021 var _getIdentNode = function(n){
1021 var _getIdentNode = function(n){
1022 //iterate thrugh nodes until matching interesting node
1022 //iterate thrugh nodes until matching interesting node
1023
1023
1024 if (typeof n == 'undefined'){
1024 if (typeof n == 'undefined'){
1025 return -1
1025 return -1
1026 }
1026 }
1027
1027
1028 if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
1028 if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
1029 return n
1029 return n
1030 }
1030 }
1031 else{
1031 else{
1032 return _getIdentNode(n.parentNode);
1032 return _getIdentNode(n.parentNode);
1033 }
1033 }
1034 };
1034 };
1035
1035
1036 /* generate links for multi line selects that can be shown by files.html page_highlights.
1036 /* generate links for multi line selects that can be shown by files.html page_highlights.
1037 * This is a mouseup handler for hlcode from CodeHtmlFormatter and pygmentize */
1037 * This is a mouseup handler for hlcode from CodeHtmlFormatter and pygmentize */
1038 var getSelectionLink = function(e) {
1038 var getSelectionLink = function(e) {
1039 //get selection from start/to nodes
1039 //get selection from start/to nodes
1040 if (typeof window.getSelection != "undefined") {
1040 if (typeof window.getSelection != "undefined") {
1041 s = window.getSelection();
1041 s = window.getSelection();
1042
1042
1043 from = _getIdentNode(s.anchorNode);
1043 from = _getIdentNode(s.anchorNode);
1044 till = _getIdentNode(s.focusNode);
1044 till = _getIdentNode(s.focusNode);
1045
1045
1046 f_int = parseInt(from.id.replace('L',''));
1046 f_int = parseInt(from.id.replace('L',''));
1047 t_int = parseInt(till.id.replace('L',''));
1047 t_int = parseInt(till.id.replace('L',''));
1048
1048
1049 var yoffset = 35;
1049 var yoffset = 35;
1050 var ranges = [parseInt(from.id.replace('L','')), parseInt(till.id.replace('L',''))];
1050 var ranges = [parseInt(from.id.replace('L','')), parseInt(till.id.replace('L',''))];
1051 if (ranges[0] > ranges[1]){
1051 if (ranges[0] > ranges[1]){
1052 //highlight from bottom
1052 //highlight from bottom
1053 yoffset = -yoffset;
1053 yoffset = -yoffset;
1054 ranges = [ranges[1], ranges[0]];
1054 ranges = [ranges[1], ranges[0]];
1055 }
1055 }
1056 var $hl_div = $('div#linktt');
1056 var $hl_div = $('div#linktt');
1057 // if we select more than 2 lines
1057 // if we select more than 2 lines
1058 if (ranges[0] != ranges[1]){
1058 if (ranges[0] != ranges[1]){
1059 if ($hl_div.length) {
1059 if ($hl_div.length) {
1060 $hl_div.html('');
1060 $hl_div.html('');
1061 } else {
1061 } else {
1062 $hl_div = $('<div id="linktt" class="hl-tip-box">');
1062 $hl_div = $('<div id="linktt" class="hl-tip-box">');
1063 $('body').prepend($hl_div);
1063 $('body').prepend($hl_div);
1064 }
1064 }
1065
1065
1066 $hl_div.append($('<a>').html(_TM['Selection link']).attr('href', location.href.substring(0, location.href.indexOf('#')) + '#L' + ranges[0] + '-'+ranges[1]));
1066 $hl_div.append($('<a>').html(_TM['Selection link']).attr('href', location.href.substring(0, location.href.indexOf('#')) + '#L' + ranges[0] + '-'+ranges[1]));
1067 xy = $(till).offset();
1067 xy = $(till).offset();
1068 $hl_div.css('top', (xy.top + yoffset) + 'px').css('left', xy.left + 'px');
1068 $hl_div.css('top', (xy.top + yoffset) + 'px').css('left', xy.left + 'px');
1069 $hl_div.show();
1069 $hl_div.show();
1070 }
1070 }
1071 else{
1071 else{
1072 $hl_div.hide();
1072 $hl_div.hide();
1073 }
1073 }
1074 }
1074 }
1075 };
1075 };
1076
1076
1077 var deleteNotification = function(url, notification_id, callbacks){
1077 var deleteNotification = function(url, notification_id, callbacks){
1078 var callback = {
1078 var callback = {
1079 success:function(o){
1079 success:function(o){
1080 $("#notification_"+notification_id).remove();
1080 $("#notification_"+notification_id).remove();
1081 _run_callbacks(callbacks);
1081 _run_callbacks(callbacks);
1082 },
1082 },
1083 failure:function(o){
1083 failure:function(o){
1084 alert("deleteNotification failure");
1084 alert("deleteNotification failure");
1085 }
1085 }
1086 };
1086 };
1087 var postData = '_method=delete';
1087 var postData = '_method=delete';
1088 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1088 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1089 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1089 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1090 callback, postData);
1090 callback, postData);
1091 };
1091 };
1092
1092
1093 var readNotification = function(url, notification_id, callbacks){
1093 var readNotification = function(url, notification_id, callbacks){
1094 var callback = {
1094 var callback = {
1095 success:function(o){
1095 success:function(o){
1096 var $obj = $("#notification_"+notification_id);
1096 var $obj = $("#notification_"+notification_id);
1097 $obj.removeClass('unread');
1097 $obj.removeClass('unread');
1098 $obj.find('.read-notification').remove();
1098 $obj.find('.read-notification').remove();
1099 _run_callbacks(callbacks);
1099 _run_callbacks(callbacks);
1100 },
1100 },
1101 failure:function(o){
1101 failure:function(o){
1102 alert("readNotification failure");
1102 alert("readNotification failure");
1103 }
1103 }
1104 };
1104 };
1105 var postData = '_method=put';
1105 var postData = '_method=put';
1106 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1106 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1107 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1107 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1108 callback, postData);
1108 callback, postData);
1109 };
1109 };
1110
1110
1111 /** MEMBERS AUTOCOMPLETE WIDGET **/
1111 /** MEMBERS AUTOCOMPLETE WIDGET **/
1112
1112
1113 var _MembersAutoComplete = function (divid, cont, users_list, groups_list) {
1113 var _MembersAutoComplete = function (divid, cont, users_list, groups_list) {
1114 var myUsers = users_list;
1114 var myUsers = users_list;
1115 var myGroups = groups_list;
1115 var myGroups = groups_list;
1116
1116
1117 // Define a custom search function for the DataSource of users
1117 // Define a custom search function for the DataSource of users
1118 var matchUsers = function (sQuery) {
1118 var matchUsers = function (sQuery) {
1119 // Case insensitive matching
1119 // Case insensitive matching
1120 var query = sQuery.toLowerCase();
1120 var query = sQuery.toLowerCase();
1121 var i = 0;
1121 var i = 0;
1122 var l = myUsers.length;
1122 var l = myUsers.length;
1123 var matches = [];
1123 var matches = [];
1124
1124
1125 // Match against each name of each contact
1125 // Match against each name of each contact
1126 for (; i < l; i++) {
1126 for (; i < l; i++) {
1127 contact = myUsers[i];
1127 contact = myUsers[i];
1128 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1128 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1129 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1129 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1130 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1130 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1131 matches[matches.length] = contact;
1131 matches[matches.length] = contact;
1132 }
1132 }
1133 }
1133 }
1134 return matches;
1134 return matches;
1135 };
1135 };
1136
1136
1137 // Define a custom search function for the DataSource of userGroups
1137 // Define a custom search function for the DataSource of userGroups
1138 var matchGroups = function (sQuery) {
1138 var matchGroups = function (sQuery) {
1139 // Case insensitive matching
1139 // Case insensitive matching
1140 var query = sQuery.toLowerCase();
1140 var query = sQuery.toLowerCase();
1141 var i = 0;
1141 var i = 0;
1142 var l = myGroups.length;
1142 var l = myGroups.length;
1143 var matches = [];
1143 var matches = [];
1144
1144
1145 // Match against each name of each contact
1145 // Match against each name of each contact
1146 for (; i < l; i++) {
1146 for (; i < l; i++) {
1147 matched_group = myGroups[i];
1147 matched_group = myGroups[i];
1148 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1148 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1149 matches[matches.length] = matched_group;
1149 matches[matches.length] = matched_group;
1150 }
1150 }
1151 }
1151 }
1152 return matches;
1152 return matches;
1153 };
1153 };
1154
1154
1155 //match all
1155 //match all
1156 var matchAll = function (sQuery) {
1156 var matchAll = function (sQuery) {
1157 u = matchUsers(sQuery);
1157 u = matchUsers(sQuery);
1158 g = matchGroups(sQuery);
1158 g = matchGroups(sQuery);
1159 return u.concat(g);
1159 return u.concat(g);
1160 };
1160 };
1161
1161
1162 // DataScheme for members
1162 // DataScheme for members
1163 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
1163 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
1164 memberDS.responseSchema = {
1164 memberDS.responseSchema = {
1165 fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
1165 fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
1166 };
1166 };
1167
1167
1168 // DataScheme for owner
1168 // DataScheme for owner
1169 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1169 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1170 ownerDS.responseSchema = {
1170 ownerDS.responseSchema = {
1171 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1171 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1172 };
1172 };
1173
1173
1174 // Instantiate AutoComplete for perms
1174 // Instantiate AutoComplete for perms
1175 var membersAC = new YAHOO.widget.AutoComplete(divid, cont, memberDS);
1175 var membersAC = new YAHOO.widget.AutoComplete(divid, cont, memberDS);
1176 membersAC.useShadow = false;
1176 membersAC.useShadow = false;
1177 membersAC.resultTypeList = false;
1177 membersAC.resultTypeList = false;
1178 membersAC.animVert = false;
1178 membersAC.animVert = false;
1179 membersAC.animHoriz = false;
1179 membersAC.animHoriz = false;
1180 membersAC.animSpeed = 0.1;
1180 membersAC.animSpeed = 0.1;
1181
1181
1182 // Instantiate AutoComplete for owner
1182 // Instantiate AutoComplete for owner
1183 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
1183 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
1184 ownerAC.useShadow = false;
1184 ownerAC.useShadow = false;
1185 ownerAC.resultTypeList = false;
1185 ownerAC.resultTypeList = false;
1186 ownerAC.animVert = false;
1186 ownerAC.animVert = false;
1187 ownerAC.animHoriz = false;
1187 ownerAC.animHoriz = false;
1188 ownerAC.animSpeed = 0.1;
1188 ownerAC.animSpeed = 0.1;
1189
1189
1190 // Helper highlight function for the formatter
1190 // Helper highlight function for the formatter
1191 var highlightMatch = function (full, snippet, matchindex) {
1191 var highlightMatch = function (full, snippet, matchindex) {
1192 return full.substring(0, matchindex)
1192 return full.substring(0, matchindex)
1193 + "<span class='match'>"
1193 + "<span class='match'>"
1194 + full.substr(matchindex, snippet.length)
1194 + full.substr(matchindex, snippet.length)
1195 + "</span>" + full.substring(matchindex + snippet.length);
1195 + "</span>" + full.substring(matchindex + snippet.length);
1196 };
1196 };
1197
1197
1198 // Custom formatter to highlight the matching letters
1198 // Custom formatter to highlight the matching letters
1199 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
1199 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
1200 var query = sQuery.toLowerCase();
1200 var query = sQuery.toLowerCase();
1201 var _gravatar = function(res, em, group){
1201 var _gravatar = function(res, em, group){
1202 if (group !== undefined){
1202 if (group !== undefined){
1203 em = '/images/icons/group.png'
1203 em = '/images/icons/group.png'
1204 }
1204 }
1205 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1205 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1206 return tmpl.format(em,res)
1206 return tmpl.format(em,res)
1207 }
1207 }
1208 // group
1208 // group
1209 if (oResultData.grname != undefined) {
1209 if (oResultData.grname != undefined) {
1210 var grname = oResultData.grname;
1210 var grname = oResultData.grname;
1211 var grmembers = oResultData.grmembers;
1211 var grmembers = oResultData.grmembers;
1212 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
1212 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
1213 var grprefix = "{0}: ".format(_TM['Group']);
1213 var grprefix = "{0}: ".format(_TM['Group']);
1214 var grsuffix = " (" + grmembers + " )";
1214 var grsuffix = " (" + grmembers + " )";
1215 var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
1215 var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
1216
1216
1217 if (grnameMatchIndex > -1) {
1217 if (grnameMatchIndex > -1) {
1218 return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
1218 return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
1219 }
1219 }
1220 return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
1220 return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
1221 // Users
1221 // Users
1222 } else if (oResultData.nname != undefined) {
1222 } else if (oResultData.nname != undefined) {
1223 var fname = oResultData.fname || "";
1223 var fname = oResultData.fname || "";
1224 var lname = oResultData.lname || "";
1224 var lname = oResultData.lname || "";
1225 var nname = oResultData.nname;
1225 var nname = oResultData.nname;
1226
1226
1227 // Guard against null value
1227 // Guard against null value
1228 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1228 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1229 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1229 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1230 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1230 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1231 displayfname, displaylname, displaynname;
1231 displayfname, displaylname, displaynname;
1232
1232
1233 if (fnameMatchIndex > -1) {
1233 if (fnameMatchIndex > -1) {
1234 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1234 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1235 } else {
1235 } else {
1236 displayfname = fname;
1236 displayfname = fname;
1237 }
1237 }
1238
1238
1239 if (lnameMatchIndex > -1) {
1239 if (lnameMatchIndex > -1) {
1240 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1240 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1241 } else {
1241 } else {
1242 displaylname = lname;
1242 displaylname = lname;
1243 }
1243 }
1244
1244
1245 if (nnameMatchIndex > -1) {
1245 if (nnameMatchIndex > -1) {
1246 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1246 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1247 } else {
1247 } else {
1248 displaynname = nname ? "(" + nname + ")" : "";
1248 displaynname = nname ? "(" + nname + ")" : "";
1249 }
1249 }
1250
1250
1251 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1251 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1252 } else {
1252 } else {
1253 return '';
1253 return '';
1254 }
1254 }
1255 };
1255 };
1256 membersAC.formatResult = custom_formatter;
1256 membersAC.formatResult = custom_formatter;
1257 ownerAC.formatResult = custom_formatter;
1257 ownerAC.formatResult = custom_formatter;
1258
1258
1259 var myHandler = function (sType, aArgs) {
1259 var myHandler = function (sType, aArgs) {
1260 var nextId = divid.split('perm_new_member_name_')[1];
1260 var nextId = divid.split('perm_new_member_name_')[1];
1261 var myAC = aArgs[0]; // reference back to the AC instance
1261 var myAC = aArgs[0]; // reference back to the AC instance
1262 var elLI = aArgs[1]; // reference to the selected LI element
1262 var elLI = aArgs[1]; // reference to the selected LI element
1263 var oData = aArgs[2]; // object literal of selected item's result data
1263 var oData = aArgs[2]; // object literal of selected item's result data
1264 //fill the autocomplete with value
1264 //fill the autocomplete with value
1265 if (oData.nname != undefined) {
1265 if (oData.nname != undefined) {
1266 //users
1266 //users
1267 myAC.getInputEl().value = oData.nname;
1267 myAC.getInputEl().value = oData.nname;
1268 $('#perm_new_member_type_'+nextId).val('user');
1268 $('#perm_new_member_type_'+nextId).val('user');
1269 } else {
1269 } else {
1270 //groups
1270 //groups
1271 myAC.getInputEl().value = oData.grname;
1271 myAC.getInputEl().value = oData.grname;
1272 $('#perm_new_member_type_'+nextId).val('users_group');
1272 $('#perm_new_member_type_'+nextId).val('users_group');
1273 }
1273 }
1274 };
1274 };
1275
1275
1276 membersAC.itemSelectEvent.subscribe(myHandler);
1276 membersAC.itemSelectEvent.subscribe(myHandler);
1277 if(ownerAC.itemSelectEvent){
1277 if(ownerAC.itemSelectEvent){
1278 ownerAC.itemSelectEvent.subscribe(myHandler);
1278 ownerAC.itemSelectEvent.subscribe(myHandler);
1279 }
1279 }
1280
1280
1281 return {
1281 return {
1282 memberDS: memberDS,
1282 memberDS: memberDS,
1283 ownerDS: ownerDS,
1283 ownerDS: ownerDS,
1284 membersAC: membersAC,
1284 membersAC: membersAC,
1285 ownerAC: ownerAC
1285 ownerAC: ownerAC
1286 };
1286 };
1287 }
1287 }
1288
1288
1289 var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
1289 var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
1290 var myUsers = users_list;
1290 var myUsers = users_list;
1291 var myGroups = groups_list;
1291 var myGroups = groups_list;
1292
1292
1293 // Define a custom search function for the DataSource of users
1293 // Define a custom search function for the DataSource of users
1294 var matchUsers = function (sQuery) {
1294 var matchUsers = function (sQuery) {
1295 var org_sQuery = sQuery;
1295 var org_sQuery = sQuery;
1296 if(this.mentionQuery == null){
1296 if(this.mentionQuery == null){
1297 return []
1297 return []
1298 }
1298 }
1299 sQuery = this.mentionQuery;
1299 sQuery = this.mentionQuery;
1300 // Case insensitive matching
1300 // Case insensitive matching
1301 var query = sQuery.toLowerCase();
1301 var query = sQuery.toLowerCase();
1302 var i = 0;
1302 var i = 0;
1303 var l = myUsers.length;
1303 var l = myUsers.length;
1304 var matches = [];
1304 var matches = [];
1305
1305
1306 // Match against each name of each contact
1306 // Match against each name of each contact
1307 for (; i < l; i++) {
1307 for (; i < l; i++) {
1308 contact = myUsers[i];
1308 contact = myUsers[i];
1309 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1309 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1310 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1310 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1311 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1311 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1312 matches[matches.length] = contact;
1312 matches[matches.length] = contact;
1313 }
1313 }
1314 }
1314 }
1315 return matches
1315 return matches
1316 };
1316 };
1317
1317
1318 //match all
1318 //match all
1319 var matchAll = function (sQuery) {
1319 var matchAll = function (sQuery) {
1320 u = matchUsers(sQuery);
1320 u = matchUsers(sQuery);
1321 return u
1321 return u
1322 };
1322 };
1323
1323
1324 // DataScheme for owner
1324 // DataScheme for owner
1325 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1325 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1326
1326
1327 ownerDS.responseSchema = {
1327 ownerDS.responseSchema = {
1328 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1328 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1329 };
1329 };
1330
1330
1331 // Instantiate AutoComplete for mentions
1331 // Instantiate AutoComplete for mentions
1332 var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1332 var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1333 ownerAC.useShadow = false;
1333 ownerAC.useShadow = false;
1334 ownerAC.resultTypeList = false;
1334 ownerAC.resultTypeList = false;
1335 ownerAC.suppressInputUpdate = true;
1335 ownerAC.suppressInputUpdate = true;
1336 ownerAC.animVert = false;
1336 ownerAC.animVert = false;
1337 ownerAC.animHoriz = false;
1337 ownerAC.animHoriz = false;
1338 ownerAC.animSpeed = 0.1;
1338 ownerAC.animSpeed = 0.1;
1339
1339
1340 // Helper highlight function for the formatter
1340 // Helper highlight function for the formatter
1341 var highlightMatch = function (full, snippet, matchindex) {
1341 var highlightMatch = function (full, snippet, matchindex) {
1342 return full.substring(0, matchindex)
1342 return full.substring(0, matchindex)
1343 + "<span class='match'>"
1343 + "<span class='match'>"
1344 + full.substr(matchindex, snippet.length)
1344 + full.substr(matchindex, snippet.length)
1345 + "</span>" + full.substring(matchindex + snippet.length);
1345 + "</span>" + full.substring(matchindex + snippet.length);
1346 };
1346 };
1347
1347
1348 // Custom formatter to highlight the matching letters
1348 // Custom formatter to highlight the matching letters
1349 ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1349 ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1350 var org_sQuery = sQuery;
1350 var org_sQuery = sQuery;
1351 if(this.dataSource.mentionQuery != null){
1351 if(this.dataSource.mentionQuery != null){
1352 sQuery = this.dataSource.mentionQuery;
1352 sQuery = this.dataSource.mentionQuery;
1353 }
1353 }
1354
1354
1355 var query = sQuery.toLowerCase();
1355 var query = sQuery.toLowerCase();
1356 var _gravatar = function(res, em, group){
1356 var _gravatar = function(res, em, group){
1357 if (group !== undefined){
1357 if (group !== undefined){
1358 em = '/images/icons/group.png'
1358 em = '/images/icons/group.png'
1359 }
1359 }
1360 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1360 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1361 return tmpl.format(em,res)
1361 return tmpl.format(em,res)
1362 }
1362 }
1363 if (oResultData.nname != undefined) {
1363 if (oResultData.nname != undefined) {
1364 var fname = oResultData.fname || "";
1364 var fname = oResultData.fname || "";
1365 var lname = oResultData.lname || "";
1365 var lname = oResultData.lname || "";
1366 var nname = oResultData.nname;
1366 var nname = oResultData.nname;
1367
1367
1368 // Guard against null value
1368 // Guard against null value
1369 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1369 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1370 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1370 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1371 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1371 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1372 displayfname, displaylname, displaynname;
1372 displayfname, displaylname, displaynname;
1373
1373
1374 if (fnameMatchIndex > -1) {
1374 if (fnameMatchIndex > -1) {
1375 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1375 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1376 } else {
1376 } else {
1377 displayfname = fname;
1377 displayfname = fname;
1378 }
1378 }
1379
1379
1380 if (lnameMatchIndex > -1) {
1380 if (lnameMatchIndex > -1) {
1381 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1381 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1382 } else {
1382 } else {
1383 displaylname = lname;
1383 displaylname = lname;
1384 }
1384 }
1385
1385
1386 if (nnameMatchIndex > -1) {
1386 if (nnameMatchIndex > -1) {
1387 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1387 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1388 } else {
1388 } else {
1389 displaynname = nname ? "(" + nname + ")" : "";
1389 displaynname = nname ? "(" + nname + ")" : "";
1390 }
1390 }
1391
1391
1392 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1392 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1393 } else {
1393 } else {
1394 return '';
1394 return '';
1395 }
1395 }
1396 };
1396 };
1397
1397
1398 if(ownerAC.itemSelectEvent){
1398 if(ownerAC.itemSelectEvent){
1399 ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1399 ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1400 var myAC = aArgs[0]; // reference back to the AC instance
1400 var myAC = aArgs[0]; // reference back to the AC instance
1401 var elLI = aArgs[1]; // reference to the selected LI element
1401 var elLI = aArgs[1]; // reference to the selected LI element
1402 var oData = aArgs[2]; // object literal of selected item's result data
1402 var oData = aArgs[2]; // object literal of selected item's result data
1403 //fill the autocomplete with value
1403 //fill the autocomplete with value
1404 if (oData.nname != undefined) {
1404 if (oData.nname != undefined) {
1405 //users
1405 //users
1406 //Replace the mention name with replaced
1406 //Replace the mention name with replaced
1407 var re = new RegExp();
1407 var re = new RegExp();
1408 var org = myAC.getInputEl().value;
1408 var org = myAC.getInputEl().value;
1409 var chunks = myAC.dataSource.chunks
1409 var chunks = myAC.dataSource.chunks
1410 // replace middle chunk(the search term) with actuall match
1410 // replace middle chunk(the search term) with actuall match
1411 chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
1411 chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
1412 '@'+oData.nname+' ');
1412 '@'+oData.nname+' ');
1413 myAC.getInputEl().value = chunks.join('')
1413 myAC.getInputEl().value = chunks.join('')
1414 myAC.getInputEl().focus(); // Y U NO WORK !?
1414 myAC.getInputEl().focus(); // Y U NO WORK !?
1415 } else {
1415 } else {
1416 //groups
1416 //groups
1417 myAC.getInputEl().value = oData.grname;
1417 myAC.getInputEl().value = oData.grname;
1418 $('#perm_new_member_type').val('users_group');
1418 $('#perm_new_member_type').val('users_group');
1419 }
1419 }
1420 });
1420 });
1421 }
1421 }
1422
1422
1423 // in this keybuffer we will gather current value of search !
1423 // in this keybuffer we will gather current value of search !
1424 // since we need to get this just when someone does `@` then we do the
1424 // since we need to get this just when someone does `@` then we do the
1425 // search
1425 // search
1426 ownerAC.dataSource.chunks = [];
1426 ownerAC.dataSource.chunks = [];
1427 ownerAC.dataSource.mentionQuery = null;
1427 ownerAC.dataSource.mentionQuery = null;
1428
1428
1429 ownerAC.get_mention = function(msg, max_pos) {
1429 ownerAC.get_mention = function(msg, max_pos) {
1430 var org = msg;
1430 var org = msg;
1431 // Must match utils2.py MENTIONS_REGEX.
1431 // Must match utils2.py MENTIONS_REGEX.
1432 // Only matching on string up to cursor, so it must end with $
1432 // Only matching on string up to cursor, so it must end with $
1433 var re = new RegExp('(?:^|[^a-zA-Z0-9])@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])$')
1433 var re = new RegExp('(?:^|[^a-zA-Z0-9])@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])$')
1434 var chunks = [];
1434 var chunks = [];
1435
1435
1436 // cut first chunk until current pos
1436 // cut first chunk until current pos
1437 var to_max = msg.substr(0, max_pos);
1437 var to_max = msg.substr(0, max_pos);
1438 var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
1438 var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
1439 var msg2 = to_max.substr(at_pos);
1439 var msg2 = to_max.substr(at_pos);
1440
1440
1441 chunks.push(org.substr(0,at_pos))// prefix chunk
1441 chunks.push(org.substr(0,at_pos))// prefix chunk
1442 chunks.push(msg2) // search chunk
1442 chunks.push(msg2) // search chunk
1443 chunks.push(org.substr(max_pos)) // postfix chunk
1443 chunks.push(org.substr(max_pos)) // postfix chunk
1444
1444
1445 // clean up msg2 for filtering and regex match
1445 // clean up msg2 for filtering and regex match
1446 var msg2 = msg2.lstrip(' ').lstrip('\n');
1446 var msg2 = msg2.lstrip(' ').lstrip('\n');
1447
1447
1448 if(re.test(msg2)){
1448 if(re.test(msg2)){
1449 var unam = re.exec(msg2)[1];
1449 var unam = re.exec(msg2)[1];
1450 return [unam, chunks];
1450 return [unam, chunks];
1451 }
1451 }
1452 return [null, null];
1452 return [null, null];
1453 };
1453 };
1454
1454
1455 $divid = $('#'+divid);
1455 $divid = $('#'+divid);
1456 $divid.keyup(function(e){
1456 $divid.keyup(function(e){
1457 var currentMessage = $divid.val();
1457 var currentMessage = $divid.val();
1458 var currentCaretPosition = $divid[0].selectionStart;
1458 var currentCaretPosition = $divid[0].selectionStart;
1459
1459
1460 var unam = ownerAC.get_mention(currentMessage, currentCaretPosition);
1460 var unam = ownerAC.get_mention(currentMessage, currentCaretPosition);
1461 var curr_search = null;
1461 var curr_search = null;
1462 if(unam[0]){
1462 if(unam[0]){
1463 curr_search = unam[0];
1463 curr_search = unam[0];
1464 }
1464 }
1465
1465
1466 ownerAC.dataSource.chunks = unam[1];
1466 ownerAC.dataSource.chunks = unam[1];
1467 ownerAC.dataSource.mentionQuery = curr_search;
1467 ownerAC.dataSource.mentionQuery = curr_search;
1468 });
1468 });
1469 }
1469 }
1470
1470
1471 var addReviewMember = function(id,fname,lname,nname,gravatar_link){
1471 var addReviewMember = function(id,fname,lname,nname,gravatar_link){
1472 var displayname = "{0} {1} ({2})".format(fname, lname, nname);
1472 var displayname = "{0} {1} ({2})".format(fname, lname, nname);
1473 var element = (
1473 var element = (
1474 ' <li id="reviewer_{2}">\n'+
1474 ' <li id="reviewer_{2}">\n'+
1475 ' <div class="reviewers_member">\n'+
1475 ' <div class="reviewers_member">\n'+
1476 ' <div class="reviewer_status tooltip" title="not_reviewed">\n'+
1476 ' <div class="reviewer_status tooltip" title="not_reviewed">\n'+
1477 ' <img src="/images/icons/flag_status_not_reviewed.png"/>\n'+
1477 ' <img src="/images/icons/flag_status_not_reviewed.png"/>\n'+
1478 ' </div>\n'+
1478 ' </div>\n'+
1479 ' <div class="reviewer_gravatar gravatar"><img alt="gravatar" src="{0}"/> </div>\n'+
1479 ' <div class="reviewer_gravatar gravatar"><img alt="gravatar" src="{0}"/> </div>\n'+
1480 ' <div style="float:left;">{1}</div>\n'+
1480 ' <div style="float:left;">{1}</div>\n'+
1481 ' <input type="hidden" value="{2}" name="review_members" />\n'+
1481 ' <input type="hidden" value="{2}" name="review_members" />\n'+
1482 ' <div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">\n'+
1482 ' <div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">\n'+
1483 ' <i class="icon-remove-sign" style="color: #FF4444;"></i>\n'+
1483 ' <i class="icon-remove-sign" style="color: #FF4444;"></i>\n'+
1484 ' </div> *\n'+
1484 ' </div> *\n'+
1485 ' </div>\n'+
1485 ' </div>\n'+
1486 ' </li>\n'
1486 ' </li>\n'
1487 ).format(gravatar_link, displayname, id);
1487 ).format(gravatar_link, displayname, id);
1488 // check if we don't have this ID already in
1488 // check if we don't have this ID already in
1489 var ids = [];
1489 var ids = [];
1490 $('#review_members').find('li').each(function() {
1490 $('#review_members').find('li').each(function() {
1491 ids.push(this.id);
1491 ids.push(this.id);
1492 });
1492 });
1493 if(ids.indexOf('reviewer_'+id) == -1){
1493 if(ids.indexOf('reviewer_'+id) == -1){
1494 //only add if it's not there
1494 //only add if it's not there
1495 $('#review_members').append(element);
1495 $('#review_members').append(element);
1496 }
1496 }
1497 }
1497 }
1498
1498
1499 var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){
1499 var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){
1500 var $li = $('#reviewer_{0}'.format(reviewer_id));
1500 var $li = $('#reviewer_{0}'.format(reviewer_id));
1501 $li.find('div div').css("text-decoration", "line-through");
1501 $li.find('div div').css("text-decoration", "line-through");
1502 $li.find('input').remove();
1502 $li.find('input').remove();
1503 $li.find('.reviewer_member_remove').remove();
1503 $li.find('.reviewer_member_remove').remove();
1504 }
1504 }
1505
1505
1506 /* handle "Save Changes" of addReviewMember and removeReviewMember on PR */
1506 /* handle "Save Changes" of addReviewMember and removeReviewMember on PR */
1507 var updateReviewers = function(reviewers_ids, repo_name, pull_request_id){
1507 var updateReviewers = function(reviewers_ids, repo_name, pull_request_id){
1508 if (reviewers_ids === undefined){
1508 if (reviewers_ids === undefined){
1509 var reviewers_ids = [];
1509 var reviewers_ids = [];
1510 $('#review_members').find('input').each(function(){
1510 $('#review_members').find('input').each(function(){
1511 reviewers_ids.push(this.value);
1511 reviewers_ids.push(this.value);
1512 });
1512 });
1513 }
1513 }
1514 var url = pyroutes.url('pullrequest_update', {"repo_name":repo_name,
1514 var url = pyroutes.url('pullrequest_update', {"repo_name":repo_name,
1515 "pull_request_id": pull_request_id});
1515 "pull_request_id": pull_request_id});
1516 var postData = {'_method':'put',
1516 var postData = {'_method':'put',
1517 'reviewers_ids': reviewers_ids};
1517 'reviewers_ids': reviewers_ids};
1518 var success = function(o){
1518 var success = function(o){
1519 window.location.reload();
1519 window.location.reload();
1520 }
1520 }
1521 ajaxPOST(url,postData,success);
1521 ajaxPOST(url,postData,success);
1522 }
1522 }
1523
1523
1524 /* activate auto completion of users and groups ... but only used for users as PR reviewers */
1524 /* activate auto completion of users and groups ... but only used for users as PR reviewers */
1525 var PullRequestAutoComplete = function (divid, cont, users_list, groups_list) {
1525 var PullRequestAutoComplete = function (divid, cont, users_list, groups_list) {
1526 var myUsers = users_list;
1526 var myUsers = users_list;
1527 var myGroups = groups_list;
1527 var myGroups = groups_list;
1528
1528
1529 // Define a custom search function for the DataSource of users
1529 // Define a custom search function for the DataSource of users
1530 var matchUsers = function (sQuery) {
1530 var matchUsers = function (sQuery) {
1531 // Case insensitive matching
1531 // Case insensitive matching
1532 var query = sQuery.toLowerCase();
1532 var query = sQuery.toLowerCase();
1533 var i = 0;
1533 var i = 0;
1534 var l = myUsers.length;
1534 var l = myUsers.length;
1535 var matches = [];
1535 var matches = [];
1536
1536
1537 // Match against each name of each contact
1537 // Match against each name of each contact
1538 for (; i < l; i++) {
1538 for (; i < l; i++) {
1539 contact = myUsers[i];
1539 contact = myUsers[i];
1540 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1540 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1541 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1541 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1542 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1542 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1543 matches[matches.length] = contact;
1543 matches[matches.length] = contact;
1544 }
1544 }
1545 }
1545 }
1546 return matches;
1546 return matches;
1547 };
1547 };
1548
1548
1549 // Define a custom search function for the DataSource of userGroups
1549 // Define a custom search function for the DataSource of userGroups
1550 var matchGroups = function (sQuery) {
1550 var matchGroups = function (sQuery) {
1551 // Case insensitive matching
1551 // Case insensitive matching
1552 var query = sQuery.toLowerCase();
1552 var query = sQuery.toLowerCase();
1553 var i = 0;
1553 var i = 0;
1554 var l = myGroups.length;
1554 var l = myGroups.length;
1555 var matches = [];
1555 var matches = [];
1556
1556
1557 // Match against each name of each contact
1557 // Match against each name of each contact
1558 for (; i < l; i++) {
1558 for (; i < l; i++) {
1559 matched_group = myGroups[i];
1559 matched_group = myGroups[i];
1560 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1560 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1561 matches[matches.length] = matched_group;
1561 matches[matches.length] = matched_group;
1562 }
1562 }
1563 }
1563 }
1564 return matches;
1564 return matches;
1565 };
1565 };
1566
1566
1567 //match all
1567 //match all
1568 var matchAll = function (sQuery) {
1568 var matchAll = function (sQuery) {
1569 u = matchUsers(sQuery);
1569 u = matchUsers(sQuery);
1570 return u
1570 return u
1571 };
1571 };
1572
1572
1573 // DataScheme for owner
1573 // DataScheme for owner
1574 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1574 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1575
1575
1576 ownerDS.responseSchema = {
1576 ownerDS.responseSchema = {
1577 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1577 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1578 };
1578 };
1579
1579
1580 // Instantiate AutoComplete for mentions
1580 // Instantiate AutoComplete for mentions
1581 var reviewerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1581 var reviewerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1582 reviewerAC.useShadow = false;
1582 reviewerAC.useShadow = false;
1583 reviewerAC.resultTypeList = false;
1583 reviewerAC.resultTypeList = false;
1584 reviewerAC.suppressInputUpdate = true;
1584 reviewerAC.suppressInputUpdate = true;
1585 reviewerAC.animVert = false;
1585 reviewerAC.animVert = false;
1586 reviewerAC.animHoriz = false;
1586 reviewerAC.animHoriz = false;
1587 reviewerAC.animSpeed = 0.1;
1587 reviewerAC.animSpeed = 0.1;
1588
1588
1589 // Helper highlight function for the formatter
1589 // Helper highlight function for the formatter
1590 var highlightMatch = function (full, snippet, matchindex) {
1590 var highlightMatch = function (full, snippet, matchindex) {
1591 return full.substring(0, matchindex)
1591 return full.substring(0, matchindex)
1592 + "<span class='match'>"
1592 + "<span class='match'>"
1593 + full.substr(matchindex, snippet.length)
1593 + full.substr(matchindex, snippet.length)
1594 + "</span>" + full.substring(matchindex + snippet.length);
1594 + "</span>" + full.substring(matchindex + snippet.length);
1595 };
1595 };
1596
1596
1597 // Custom formatter to highlight the matching letters
1597 // Custom formatter to highlight the matching letters
1598 reviewerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1598 reviewerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1599 var org_sQuery = sQuery;
1599 var org_sQuery = sQuery;
1600 if(this.dataSource.mentionQuery != null){
1600 if(this.dataSource.mentionQuery != null){
1601 sQuery = this.dataSource.mentionQuery;
1601 sQuery = this.dataSource.mentionQuery;
1602 }
1602 }
1603
1603
1604 var query = sQuery.toLowerCase();
1604 var query = sQuery.toLowerCase();
1605 var _gravatar = function(res, em, group){
1605 var _gravatar = function(res, em, group){
1606 if (group !== undefined){
1606 if (group !== undefined){
1607 em = '/images/icons/group.png'
1607 em = '/images/icons/group.png'
1608 }
1608 }
1609 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1609 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1610 return tmpl.format(em,res)
1610 return tmpl.format(em,res)
1611 }
1611 }
1612 if (oResultData.nname != undefined) {
1612 if (oResultData.nname != undefined) {
1613 var fname = oResultData.fname || "";
1613 var fname = oResultData.fname || "";
1614 var lname = oResultData.lname || "";
1614 var lname = oResultData.lname || "";
1615 var nname = oResultData.nname;
1615 var nname = oResultData.nname;
1616
1616
1617 // Guard against null value
1617 // Guard against null value
1618 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1618 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1619 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1619 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1620 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1620 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1621 displayfname, displaylname, displaynname;
1621 displayfname, displaylname, displaynname;
1622
1622
1623 if (fnameMatchIndex > -1) {
1623 if (fnameMatchIndex > -1) {
1624 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1624 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1625 } else {
1625 } else {
1626 displayfname = fname;
1626 displayfname = fname;
1627 }
1627 }
1628
1628
1629 if (lnameMatchIndex > -1) {
1629 if (lnameMatchIndex > -1) {
1630 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1630 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1631 } else {
1631 } else {
1632 displaylname = lname;
1632 displaylname = lname;
1633 }
1633 }
1634
1634
1635 if (nnameMatchIndex > -1) {
1635 if (nnameMatchIndex > -1) {
1636 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1636 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1637 } else {
1637 } else {
1638 displaynname = nname ? "(" + nname + ")" : "";
1638 displaynname = nname ? "(" + nname + ")" : "";
1639 }
1639 }
1640
1640
1641 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1641 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1642 } else {
1642 } else {
1643 return '';
1643 return '';
1644 }
1644 }
1645 };
1645 };
1646
1646
1647 //members cache to catch duplicates
1647 //members cache to catch duplicates
1648 reviewerAC.dataSource.cache = [];
1648 reviewerAC.dataSource.cache = [];
1649 // hack into select event
1649 // hack into select event
1650 if(reviewerAC.itemSelectEvent){
1650 if(reviewerAC.itemSelectEvent){
1651 reviewerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1651 reviewerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1652
1652
1653 var myAC = aArgs[0]; // reference back to the AC instance
1653 var myAC = aArgs[0]; // reference back to the AC instance
1654 var elLI = aArgs[1]; // reference to the selected LI element
1654 var elLI = aArgs[1]; // reference to the selected LI element
1655 var oData = aArgs[2]; // object literal of selected item's result data
1655 var oData = aArgs[2]; // object literal of selected item's result data
1656
1656
1657 //fill the autocomplete with value
1657 //fill the autocomplete with value
1658 if (oData.nname != undefined) {
1658 if (oData.nname != undefined) {
1659 addReviewMember(oData.id, oData.fname, oData.lname, oData.nname,
1659 addReviewMember(oData.id, oData.fname, oData.lname, oData.nname,
1660 oData.gravatar_lnk);
1660 oData.gravatar_lnk);
1661 myAC.dataSource.cache.push(oData.id);
1661 myAC.dataSource.cache.push(oData.id);
1662 $('#user').val('');
1662 $('#user').val('');
1663 }
1663 }
1664 });
1664 });
1665 }
1665 }
1666 }
1666 }
1667
1667
1668 /**
1668 /**
1669 * Activate .quick_repo_menu
1669 * Activate .quick_repo_menu
1670 */
1670 */
1671 var quick_repo_menu = function(){
1671 var quick_repo_menu = function(){
1672 $(".quick_repo_menu").mouseenter(function(e) {
1672 $(".quick_repo_menu").mouseenter(function(e) {
1673 var $menu = $(e.currentTarget).children().first().children().first();
1673 var $menu = $(e.currentTarget).children().first().children().first();
1674 if($menu.hasClass('hidden')){
1674 if($menu.hasClass('hidden')){
1675 $menu.removeClass('hidden').addClass('active');
1675 $menu.removeClass('hidden').addClass('active');
1676 $(e.currentTarget).removeClass('hidden').addClass('active');
1676 $(e.currentTarget).removeClass('hidden').addClass('active');
1677 }
1677 }
1678 })
1678 })
1679 $(".quick_repo_menu").mouseleave(function(e) {
1679 $(".quick_repo_menu").mouseleave(function(e) {
1680 var $menu = $(e.currentTarget).children().first().children().first();
1680 var $menu = $(e.currentTarget).children().first().children().first();
1681 if($menu.hasClass('active')){
1681 if($menu.hasClass('active')){
1682 $menu.removeClass('active').addClass('hidden');
1682 $menu.removeClass('active').addClass('hidden');
1683 $(e.currentTarget).removeClass('active').addClass('hidden');
1683 $(e.currentTarget).removeClass('active').addClass('hidden');
1684 }
1684 }
1685 })
1685 })
1686 };
1686 };
1687
1687
1688
1688
1689 /**
1689 /**
1690 * TABLE SORTING
1690 * TABLE SORTING
1691 */
1691 */
1692
1692
1693 var revisionSort = function(a, b, desc, field) {
1693 var revisionSort = function(a, b, desc, field) {
1694 var a_ = parseInt(a.getData('last_rev_raw') || 0);
1694 var a_ = parseInt(a.getData('last_rev_raw') || 0);
1695 var b_ = parseInt(b.getData('last_rev_raw') || 0);
1695 var b_ = parseInt(b.getData('last_rev_raw') || 0);
1696
1696
1697 return YAHOO.util.Sort.compare(a_, b_, desc);
1697 return YAHOO.util.Sort.compare(a_, b_, desc);
1698 };
1698 };
1699
1699
1700 var ageSort = function(a, b, desc, field) {
1700 var ageSort = function(a, b, desc, field) {
1701 // data is like: <span class="tooltip" date="2014-06-04 18:18:55.325474" title="Wed, 04 Jun 2014 18:18:55">1 day and 23 hours ago</span>
1701 // data is like: <span class="tooltip" date="2014-06-04 18:18:55.325474" title="Wed, 04 Jun 2014 18:18:55">1 day and 23 hours ago</span>
1702 var a_ = $(a.getData(field)).attr('date');
1702 var a_ = $(a.getData(field)).attr('date');
1703 var b_ = $(b.getData(field)).attr('date');
1703 var b_ = $(b.getData(field)).attr('date');
1704
1704
1705 return YAHOO.util.Sort.compare(a_, b_, desc);
1705 return YAHOO.util.Sort.compare(a_, b_, desc);
1706 };
1706 };
1707
1707
1708 var lastLoginSort = function(a, b, desc, field) {
1708 var lastLoginSort = function(a, b, desc, field) {
1709 var a_ = parseFloat(a.getData('last_login_raw') || 0);
1709 var a_ = parseFloat(a.getData('last_login_raw') || 0);
1710 var b_ = parseFloat(b.getData('last_login_raw') || 0);
1710 var b_ = parseFloat(b.getData('last_login_raw') || 0);
1711
1711
1712 return YAHOO.util.Sort.compare(a_, b_, desc);
1712 return YAHOO.util.Sort.compare(a_, b_, desc);
1713 };
1713 };
1714
1714
1715 var nameSort = function(a, b, desc, field) {
1715 var nameSort = function(a, b, desc, field) {
1716 var a_ = a.getData('raw_name') || 0;
1716 var a_ = a.getData('raw_name') || 0;
1717 var b_ = b.getData('raw_name') || 0;
1717 var b_ = b.getData('raw_name') || 0;
1718
1718
1719 return YAHOO.util.Sort.compare(a_, b_, desc);
1719 return YAHOO.util.Sort.compare(a_, b_, desc);
1720 };
1720 };
1721
1721
1722 var dateSort = function(a, b, desc, field) {
1722 var dateSort = function(a, b, desc, field) {
1723 var a_ = parseFloat(a.getData('raw_date') || 0);
1723 var a_ = parseFloat(a.getData('raw_date') || 0);
1724 var b_ = parseFloat(b.getData('raw_date') || 0);
1724 var b_ = parseFloat(b.getData('raw_date') || 0);
1725
1725
1726 return YAHOO.util.Sort.compare(a_, b_, desc);
1726 return YAHOO.util.Sort.compare(a_, b_, desc);
1727 };
1727 };
1728
1728
1729 var addPermAction = function(_html, users_list, groups_list){
1729 var addPermAction = function(_html, users_list, groups_list){
1730 var $last_node = $('.last_new_member').last(); // empty tr between last and add
1730 var $last_node = $('.last_new_member').last(); // empty tr between last and add
1731 var next_id = $('.new_members').length;
1731 var next_id = $('.new_members').length;
1732 $last_node.before($('<tr class="new_members">').append(_html.format(next_id)));
1732 $last_node.before($('<tr class="new_members">').append(_html.format(next_id)));
1733 _MembersAutoComplete("perm_new_member_name_"+next_id,
1733 _MembersAutoComplete("perm_new_member_name_"+next_id,
1734 "perm_container_"+next_id, users_list, groups_list);
1734 "perm_container_"+next_id, users_list, groups_list);
1735 }
1735 }
1736
1736
1737 function ajaxActionRevokePermission(url, obj_id, obj_type, field_id, extra_data) {
1737 function ajaxActionRevokePermission(url, obj_id, obj_type, field_id, extra_data) {
1738 var callback = {
1738 var callback = {
1739 success: function (o) {
1739 success: function (o) {
1740 $('#' + field_id).remove();
1740 $('#' + field_id).remove();
1741 },
1741 },
1742 failure: function (o) {
1742 failure: function (o) {
1743 alert(_TM['Failed to revoke permission'] + ": " + o.status);
1743 alert(_TM['Failed to revoke permission'] + ": " + o.status);
1744 }
1744 }
1745 };
1745 };
1746 query_params = {
1746 query_params = {
1747 '_method': 'delete'
1747 '_method': 'delete'
1748 }
1748 }
1749 // put extra data into POST
1749 // put extra data into POST
1750 if (extra_data !== undefined && (typeof extra_data === 'object')){
1750 if (extra_data !== undefined && (typeof extra_data === 'object')){
1751 for(k in extra_data){
1751 for(k in extra_data){
1752 query_params[k] = extra_data[k];
1752 query_params[k] = extra_data[k];
1753 }
1753 }
1754 }
1754 }
1755
1755
1756 if (obj_type=='user'){
1756 if (obj_type=='user'){
1757 query_params['user_id'] = obj_id;
1757 query_params['user_id'] = obj_id;
1758 query_params['obj_type'] = 'user';
1758 query_params['obj_type'] = 'user';
1759 }
1759 }
1760 else if (obj_type=='user_group'){
1760 else if (obj_type=='user_group'){
1761 query_params['user_group_id'] = obj_id;
1761 query_params['user_group_id'] = obj_id;
1762 query_params['obj_type'] = 'user_group';
1762 query_params['obj_type'] = 'user_group';
1763 }
1763 }
1764
1764
1765 var request = YAHOO.util.Connect.asyncRequest('POST', url, callback,
1765 var request = YAHOO.util.Connect.asyncRequest('POST', url, callback,
1766 _toQueryString(query_params));
1766 _toQueryString(query_params));
1767 };
1767 };
1768
1768
1769 /* Multi selectors */
1769 /* Multi selectors */
1770
1770
1771 var MultiSelectWidget = function(selected_id, available_id, form_id){
1771 var MultiSelectWidget = function(selected_id, available_id, form_id){
1772 var $availableselect = $('#' + available_id);
1772 var $availableselect = $('#' + available_id);
1773 var $selectedselect = $('#' + selected_id);
1773 var $selectedselect = $('#' + selected_id);
1774
1774
1775 //fill available only with those not in selected
1775 //fill available only with those not in selected
1776 var $selectedoptions = $selectedselect.children('option');
1776 var $selectedoptions = $selectedselect.children('option');
1777 $availableselect.children('option').filter(function(i, e){
1777 $availableselect.children('option').filter(function(i, e){
1778 for(var j = 0, node; node = $selectedoptions[j]; j++){
1778 for(var j = 0, node; node = $selectedoptions[j]; j++){
1779 if(node.value == e.value){
1779 if(node.value == e.value){
1780 return true;
1780 return true;
1781 }
1781 }
1782 }
1782 }
1783 return false;
1783 return false;
1784 }).remove();
1784 }).remove();
1785
1785
1786 $('#add_element').click(function(e){
1786 $('#add_element').click(function(e){
1787 $selectedselect.append($availableselect.children('option:selected'));
1787 $selectedselect.append($availableselect.children('option:selected'));
1788 });
1788 });
1789 $('#remove_element').click(function(e){
1789 $('#remove_element').click(function(e){
1790 $availableselect.append($selectedselect.children('option:selected'));
1790 $availableselect.append($selectedselect.children('option:selected'));
1791 });
1791 });
1792 $('#add_all_elements').click(function(e){
1792 $('#add_all_elements').click(function(e){
1793 $selectedselect.append($availableselect.children('option'));
1793 $selectedselect.append($availableselect.children('option'));
1794 });
1794 });
1795 $('#remove_all_elements').click(function(e){
1795 $('#remove_all_elements').click(function(e){
1796 $availableselect.append($selectedselect.children('option'));
1796 $availableselect.append($selectedselect.children('option'));
1797 });
1797 });
1798
1798
1799 $('#'+form_id).submit(function(){
1799 $('#'+form_id).submit(function(){
1800 $selectedselect.children('option').each(function(i, e){
1800 $selectedselect.children('option').each(function(i, e){
1801 e.selected = 'selected';
1801 e.selected = 'selected';
1802 });
1802 });
1803 });
1803 });
1804 }
1804 }
1805
1805
1806 // custom paginator
1806 // custom paginator
1807 var YUI_paginator = function(links_per_page, containers){
1807 var YUI_paginator = function(links_per_page, containers){
1808
1808
1809 (function () {
1809 (function () {
1810
1810
1811 var Paginator = YAHOO.widget.Paginator,
1811 var Paginator = YAHOO.widget.Paginator,
1812 l = YAHOO.lang,
1812 l = YAHOO.lang,
1813 setId = YAHOO.util.Dom.generateId;
1813 setId = YAHOO.util.Dom.generateId;
1814
1814
1815 Paginator.ui.MyFirstPageLink = function (p) {
1815 Paginator.ui.MyFirstPageLink = function (p) {
1816 this.paginator = p;
1816 this.paginator = p;
1817
1817
1818 p.subscribe('recordOffsetChange',this.update,this,true);
1818 p.subscribe('recordOffsetChange',this.update,this,true);
1819 p.subscribe('rowsPerPageChange',this.update,this,true);
1819 p.subscribe('rowsPerPageChange',this.update,this,true);
1820 p.subscribe('totalRecordsChange',this.update,this,true);
1820 p.subscribe('totalRecordsChange',this.update,this,true);
1821 p.subscribe('destroy',this.destroy,this,true);
1821 p.subscribe('destroy',this.destroy,this,true);
1822
1822
1823 // TODO: make this work
1823 // TODO: make this work
1824 p.subscribe('firstPageLinkLabelChange',this.update,this,true);
1824 p.subscribe('firstPageLinkLabelChange',this.update,this,true);
1825 p.subscribe('firstPageLinkClassChange',this.update,this,true);
1825 p.subscribe('firstPageLinkClassChange',this.update,this,true);
1826 };
1826 };
1827
1827
1828 Paginator.ui.MyFirstPageLink.init = function (p) {
1828 Paginator.ui.MyFirstPageLink.init = function (p) {
1829 p.setAttributeConfig('firstPageLinkLabel', {
1829 p.setAttributeConfig('firstPageLinkLabel', {
1830 value : 1,
1830 value : 1,
1831 validator : l.isString
1831 validator : l.isString
1832 });
1832 });
1833 p.setAttributeConfig('firstPageLinkClass', {
1833 p.setAttributeConfig('firstPageLinkClass', {
1834 value : 'yui-pg-first',
1834 value : 'yui-pg-first',
1835 validator : l.isString
1835 validator : l.isString
1836 });
1836 });
1837 p.setAttributeConfig('firstPageLinkTitle', {
1837 p.setAttributeConfig('firstPageLinkTitle', {
1838 value : 'First Page',
1838 value : 'First Page',
1839 validator : l.isString
1839 validator : l.isString
1840 });
1840 });
1841 };
1841 };
1842
1842
1843 // Instance members and methods
1843 // Instance members and methods
1844 Paginator.ui.MyFirstPageLink.prototype = {
1844 Paginator.ui.MyFirstPageLink.prototype = {
1845 current : null,
1845 current : null,
1846 leftmost_page: null,
1846 leftmost_page: null,
1847 rightmost_page: null,
1847 rightmost_page: null,
1848 link : null,
1848 link : null,
1849 span : null,
1849 span : null,
1850 dotdot : null,
1850 dotdot : null,
1851 getPos : function(cur_page, max_page, items){
1851 getPos : function(cur_page, max_page, items){
1852 var edge = parseInt(items / 2) + 1;
1852 var edge = parseInt(items / 2) + 1;
1853 if (cur_page <= edge){
1853 if (cur_page <= edge){
1854 var radius = Math.max(parseInt(items / 2), items - cur_page);
1854 var radius = Math.max(parseInt(items / 2), items - cur_page);
1855 }
1855 }
1856 else if ((max_page - cur_page) < edge) {
1856 else if ((max_page - cur_page) < edge) {
1857 var radius = (items - 1) - (max_page - cur_page);
1857 var radius = (items - 1) - (max_page - cur_page);
1858 }
1858 }
1859 else{
1859 else{
1860 var radius = parseInt(items / 2);
1860 var radius = parseInt(items / 2);
1861 }
1861 }
1862
1862
1863 var left = Math.max(1, (cur_page - (radius)))
1863 var left = Math.max(1, (cur_page - (radius)))
1864 var right = Math.min(max_page, cur_page + (radius))
1864 var right = Math.min(max_page, cur_page + (radius))
1865 return [left, cur_page, right]
1865 return [left, cur_page, right]
1866 },
1866 },
1867 render : function (id_base) {
1867 render : function (id_base) {
1868 var p = this.paginator,
1868 var p = this.paginator,
1869 c = p.get('firstPageLinkClass'),
1869 c = p.get('firstPageLinkClass'),
1870 label = p.get('firstPageLinkLabel'),
1870 label = p.get('firstPageLinkLabel'),
1871 title = p.get('firstPageLinkTitle');
1871 title = p.get('firstPageLinkTitle');
1872
1872
1873 this.link = document.createElement('a');
1873 this.link = document.createElement('a');
1874 this.span = document.createElement('span');
1874 this.span = document.createElement('span');
1875 $(this.span).hide();
1875 $(this.span).hide();
1876
1876
1877 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1877 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1878 this.leftmost_page = _pos[0];
1878 this.leftmost_page = _pos[0];
1879 this.rightmost_page = _pos[2];
1879 this.rightmost_page = _pos[2];
1880
1880
1881 setId(this.link, id_base + '-first-link');
1881 setId(this.link, id_base + '-first-link');
1882 this.link.href = '#';
1882 this.link.href = '#';
1883 this.link.className = c;
1883 this.link.className = c;
1884 this.link.innerHTML = label;
1884 this.link.innerHTML = label;
1885 this.link.title = title;
1885 this.link.title = title;
1886 YUE.on(this.link,'click',this.onClick,this,true);
1886 YUE.on(this.link,'click',this.onClick,this,true);
1887
1887
1888 setId(this.span, id_base + '-first-span');
1888 setId(this.span, id_base + '-first-span');
1889 this.span.className = c;
1889 this.span.className = c;
1890 this.span.innerHTML = label;
1890 this.span.innerHTML = label;
1891
1891
1892 this.current = p.getCurrentPage() > 1 ? this.link : this.span;
1892 this.current = p.getCurrentPage() > 1 ? this.link : this.span;
1893 return this.current;
1893 return this.current;
1894 },
1894 },
1895 update : function (e) {
1895 update : function (e) {
1896 var p = this.paginator;
1896 var p = this.paginator;
1897 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1897 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1898 this.leftmost_page = _pos[0];
1898 this.leftmost_page = _pos[0];
1899 this.rightmost_page = _pos[2];
1899 this.rightmost_page = _pos[2];
1900
1900
1901 if (e && e.prevValue === e.newValue) {
1901 if (e && e.prevValue === e.newValue) {
1902 return;
1902 return;
1903 }
1903 }
1904
1904
1905 var par = this.current ? this.current.parentNode : null;
1905 var par = this.current ? this.current.parentNode : null;
1906 if (this.leftmost_page > 1) {
1906 if (this.leftmost_page > 1) {
1907 if (par && this.current === this.span) {
1907 if (par && this.current === this.span) {
1908 par.replaceChild(this.link,this.current);
1908 par.replaceChild(this.link,this.current);
1909 this.current = this.link;
1909 this.current = this.link;
1910 }
1910 }
1911 } else {
1911 } else {
1912 if (par && this.current === this.link) {
1912 if (par && this.current === this.link) {
1913 par.replaceChild(this.span,this.current);
1913 par.replaceChild(this.span,this.current);
1914 this.current = this.span;
1914 this.current = this.span;
1915 }
1915 }
1916 }
1916 }
1917 },
1917 },
1918 destroy : function () {
1918 destroy : function () {
1919 YUE.purgeElement(this.link);
1919 YUE.purgeElement(this.link);
1920 this.current.parentNode.removeChild(this.current);
1920 this.current.parentNode.removeChild(this.current);
1921 this.link = this.span = null;
1921 this.link = this.span = null;
1922 },
1922 },
1923 onClick : function (e) {
1923 onClick : function (e) {
1924 YUE.stopEvent(e);
1924 YUE.stopEvent(e);
1925 this.paginator.setPage(1);
1925 this.paginator.setPage(1);
1926 }
1926 }
1927 };
1927 };
1928
1928
1929 })();
1929 })();
1930
1930
1931 (function () {
1931 (function () {
1932
1932
1933 var Paginator = YAHOO.widget.Paginator,
1933 var Paginator = YAHOO.widget.Paginator,
1934 l = YAHOO.lang,
1934 l = YAHOO.lang,
1935 setId = YAHOO.util.Dom.generateId;
1935 setId = YAHOO.util.Dom.generateId;
1936
1936
1937 Paginator.ui.MyLastPageLink = function (p) {
1937 Paginator.ui.MyLastPageLink = function (p) {
1938 this.paginator = p;
1938 this.paginator = p;
1939
1939
1940 p.subscribe('recordOffsetChange',this.update,this,true);
1940 p.subscribe('recordOffsetChange',this.update,this,true);
1941 p.subscribe('rowsPerPageChange',this.update,this,true);
1941 p.subscribe('rowsPerPageChange',this.update,this,true);
1942 p.subscribe('totalRecordsChange',this.update,this,true);
1942 p.subscribe('totalRecordsChange',this.update,this,true);
1943 p.subscribe('destroy',this.destroy,this,true);
1943 p.subscribe('destroy',this.destroy,this,true);
1944
1944
1945 // TODO: make this work
1945 // TODO: make this work
1946 p.subscribe('lastPageLinkLabelChange',this.update,this,true);
1946 p.subscribe('lastPageLinkLabelChange',this.update,this,true);
1947 p.subscribe('lastPageLinkClassChange', this.update,this,true);
1947 p.subscribe('lastPageLinkClassChange', this.update,this,true);
1948 };
1948 };
1949
1949
1950 Paginator.ui.MyLastPageLink.init = function (p) {
1950 Paginator.ui.MyLastPageLink.init = function (p) {
1951 p.setAttributeConfig('lastPageLinkLabel', {
1951 p.setAttributeConfig('lastPageLinkLabel', {
1952 value : -1,
1952 value : -1,
1953 validator : l.isString
1953 validator : l.isString
1954 });
1954 });
1955 p.setAttributeConfig('lastPageLinkClass', {
1955 p.setAttributeConfig('lastPageLinkClass', {
1956 value : 'yui-pg-last',
1956 value : 'yui-pg-last',
1957 validator : l.isString
1957 validator : l.isString
1958 });
1958 });
1959 p.setAttributeConfig('lastPageLinkTitle', {
1959 p.setAttributeConfig('lastPageLinkTitle', {
1960 value : 'Last Page',
1960 value : 'Last Page',
1961 validator : l.isString
1961 validator : l.isString
1962 });
1962 });
1963
1963
1964 };
1964 };
1965
1965
1966 Paginator.ui.MyLastPageLink.prototype = {
1966 Paginator.ui.MyLastPageLink.prototype = {
1967
1967
1968 current : null,
1968 current : null,
1969 leftmost_page: null,
1969 leftmost_page: null,
1970 rightmost_page: null,
1970 rightmost_page: null,
1971 link : null,
1971 link : null,
1972 span : null,
1972 span : null,
1973 dotdot : null,
1973 dotdot : null,
1974 na : null,
1974 na : null,
1975 getPos : function(cur_page, max_page, items){
1975 getPos : function(cur_page, max_page, items){
1976 var edge = parseInt(items / 2) + 1;
1976 var edge = parseInt(items / 2) + 1;
1977 if (cur_page <= edge){
1977 if (cur_page <= edge){
1978 var radius = Math.max(parseInt(items / 2), items - cur_page);
1978 var radius = Math.max(parseInt(items / 2), items - cur_page);
1979 }
1979 }
1980 else if ((max_page - cur_page) < edge) {
1980 else if ((max_page - cur_page) < edge) {
1981 var radius = (items - 1) - (max_page - cur_page);
1981 var radius = (items - 1) - (max_page - cur_page);
1982 }
1982 }
1983 else{
1983 else{
1984 var radius = parseInt(items / 2);
1984 var radius = parseInt(items / 2);
1985 }
1985 }
1986
1986
1987 var left = Math.max(1, (cur_page - (radius)))
1987 var left = Math.max(1, (cur_page - (radius)))
1988 var right = Math.min(max_page, cur_page + (radius))
1988 var right = Math.min(max_page, cur_page + (radius))
1989 return [left, cur_page, right]
1989 return [left, cur_page, right]
1990 },
1990 },
1991 render : function (id_base) {
1991 render : function (id_base) {
1992 var p = this.paginator,
1992 var p = this.paginator,
1993 c = p.get('lastPageLinkClass'),
1993 c = p.get('lastPageLinkClass'),
1994 label = p.get('lastPageLinkLabel'),
1994 label = p.get('lastPageLinkLabel'),
1995 last = p.getTotalPages(),
1995 last = p.getTotalPages(),
1996 title = p.get('lastPageLinkTitle');
1996 title = p.get('lastPageLinkTitle');
1997
1997
1998 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1998 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
1999 this.leftmost_page = _pos[0];
1999 this.leftmost_page = _pos[0];
2000 this.rightmost_page = _pos[2];
2000 this.rightmost_page = _pos[2];
2001
2001
2002 this.link = document.createElement('a');
2002 this.link = document.createElement('a');
2003 this.span = document.createElement('span');
2003 this.span = document.createElement('span');
2004 $(this.span).hide();
2004 $(this.span).hide();
2005
2005
2006 this.na = this.span.cloneNode(false);
2006 this.na = this.span.cloneNode(false);
2007
2007
2008 setId(this.link, id_base + '-last-link');
2008 setId(this.link, id_base + '-last-link');
2009 this.link.href = '#';
2009 this.link.href = '#';
2010 this.link.className = c;
2010 this.link.className = c;
2011 this.link.innerHTML = label;
2011 this.link.innerHTML = label;
2012 this.link.title = title;
2012 this.link.title = title;
2013 YUE.on(this.link,'click',this.onClick,this,true);
2013 YUE.on(this.link,'click',this.onClick,this,true);
2014
2014
2015 setId(this.span, id_base + '-last-span');
2015 setId(this.span, id_base + '-last-span');
2016 this.span.className = c;
2016 this.span.className = c;
2017 this.span.innerHTML = label;
2017 this.span.innerHTML = label;
2018
2018
2019 setId(this.na, id_base + '-last-na');
2019 setId(this.na, id_base + '-last-na');
2020
2020
2021 if (this.rightmost_page < p.getTotalPages()){
2021 if (this.rightmost_page < p.getTotalPages()){
2022 this.current = this.link;
2022 this.current = this.link;
2023 }
2023 }
2024 else{
2024 else{
2025 this.current = this.span;
2025 this.current = this.span;
2026 }
2026 }
2027
2027
2028 this.current.innerHTML = p.getTotalPages();
2028 this.current.innerHTML = p.getTotalPages();
2029 return this.current;
2029 return this.current;
2030 },
2030 },
2031
2031
2032 update : function (e) {
2032 update : function (e) {
2033 var p = this.paginator;
2033 var p = this.paginator;
2034
2034
2035 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
2035 var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
2036 this.leftmost_page = _pos[0];
2036 this.leftmost_page = _pos[0];
2037 this.rightmost_page = _pos[2];
2037 this.rightmost_page = _pos[2];
2038
2038
2039 if (e && e.prevValue === e.newValue) {
2039 if (e && e.prevValue === e.newValue) {
2040 return;
2040 return;
2041 }
2041 }
2042
2042
2043 var par = this.current ? this.current.parentNode : null,
2043 var par = this.current ? this.current.parentNode : null,
2044 after = this.link;
2044 after = this.link;
2045 if (par) {
2045 if (par) {
2046
2046
2047 // only show the last page if the rightmost one is
2047 // only show the last page if the rightmost one is
2048 // lower, so we don't have doubled entries at the end
2048 // lower, so we don't have doubled entries at the end
2049 if (!(this.rightmost_page < p.getTotalPages())){
2049 if (!(this.rightmost_page < p.getTotalPages())){
2050 after = this.span
2050 after = this.span
2051 }
2051 }
2052
2052
2053 if (this.current !== after) {
2053 if (this.current !== after) {
2054 par.replaceChild(after,this.current);
2054 par.replaceChild(after,this.current);
2055 this.current = after;
2055 this.current = after;
2056 }
2056 }
2057 }
2057 }
2058 this.current.innerHTML = this.paginator.getTotalPages();
2058 this.current.innerHTML = this.paginator.getTotalPages();
2059
2059
2060 },
2060 },
2061 destroy : function () {
2061 destroy : function () {
2062 YUE.purgeElement(this.link);
2062 YUE.purgeElement(this.link);
2063 this.current.parentNode.removeChild(this.current);
2063 this.current.parentNode.removeChild(this.current);
2064 this.link = this.span = null;
2064 this.link = this.span = null;
2065 },
2065 },
2066 onClick : function (e) {
2066 onClick : function (e) {
2067 YUE.stopEvent(e);
2067 YUE.stopEvent(e);
2068 this.paginator.setPage(this.paginator.getTotalPages());
2068 this.paginator.setPage(this.paginator.getTotalPages());
2069 }
2069 }
2070 };
2070 };
2071
2071
2072 })();
2072 })();
2073
2073
2074 var pagi = new YAHOO.widget.Paginator({
2074 var pagi = new YAHOO.widget.Paginator({
2075 rowsPerPage: links_per_page,
2075 rowsPerPage: links_per_page,
2076 alwaysVisible: false,
2076 alwaysVisible: false,
2077 template : "{PreviousPageLink} {MyFirstPageLink} {PageLinks} {MyLastPageLink} {NextPageLink}",
2077 template : "{PreviousPageLink} {MyFirstPageLink} {PageLinks} {MyLastPageLink} {NextPageLink}",
2078 pageLinks: 5,
2078 pageLinks: 5,
2079 containerClass: 'pagination-wh',
2079 containerClass: 'pagination-wh',
2080 currentPageClass: 'pager_curpage',
2080 currentPageClass: 'pager_curpage',
2081 pageLinkClass: 'pager_link',
2081 pageLinkClass: 'pager_link',
2082 nextPageLinkLabel: '&gt;',
2082 nextPageLinkLabel: '&gt;',
2083 previousPageLinkLabel: '&lt;',
2083 previousPageLinkLabel: '&lt;',
2084 containers:containers
2084 containers:containers
2085 })
2085 })
2086
2086
2087 return pagi
2087 return pagi
2088 }
2088 }
2089
2089
2090 var YUI_datatable = function(data, fields, columns, countnode, sortkey, rows){
2090 var YUI_datatable = function(data, fields, columns, countnode, sortkey, rows){
2091 var myDataSource = new YAHOO.util.DataSource(data);
2091 var myDataSource = new YAHOO.util.DataSource(data);
2092 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
2092 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
2093 myDataSource.responseSchema = {
2093 myDataSource.responseSchema = {
2094 resultsList: "records",
2094 resultsList: "records",
2095 fields: fields
2095 fields: fields
2096 };
2096 };
2097 myDataSource.doBeforeCallback = function(req, raw, res, cb) {
2097 myDataSource.doBeforeCallback = function(req, raw, res, cb) {
2098 // This is the filter function
2098 // This is the filter function
2099 var data = res.results || [],
2099 var data = res.results || [],
2100 filtered = [],
2100 filtered = [],
2101 i, l;
2101 i, l;
2102
2102
2103 if (req) {
2103 if (req) {
2104 req = req.toLowerCase();
2104 req = req.toLowerCase();
2105 for (i = 0; i<data.length; i++) {
2105 for (i = 0; i<data.length; i++) {
2106 var pos = data[i].raw_name.toLowerCase().indexOf(req)
2106 var pos = data[i].raw_name.toLowerCase().indexOf(req)
2107 if (pos != -1) {
2107 if (pos != -1) {
2108 filtered.push(data[i]);
2108 filtered.push(data[i]);
2109 }
2109 }
2110 }
2110 }
2111 res.results = filtered;
2111 res.results = filtered;
2112 }
2112 }
2113 $(countnode).html(res.results.length);
2113 $(countnode).html(res.results.length);
2114 return res;
2114 return res;
2115 }
2115 }
2116
2116
2117 var myDataTable = new YAHOO.widget.DataTable("datatable_list_wrap", columns, myDataSource, {
2117 var myDataTable = new YAHOO.widget.DataTable("datatable_list_wrap", columns, myDataSource, {
2118 sortedBy: {key:sortkey, dir:"asc"},
2118 sortedBy: {key:sortkey, dir:"asc"},
2119 paginator: YUI_paginator(rows !== undefined && rows ? rows : 25, ['user-paginator']),
2119 paginator: YUI_paginator(rows !== undefined && rows ? rows : 25, ['user-paginator']),
2120 MSG_SORTASC: _TM['MSG_SORTASC'],
2120 MSG_SORTASC: _TM['MSG_SORTASC'],
2121 MSG_SORTDESC: _TM['MSG_SORTDESC'],
2121 MSG_SORTDESC: _TM['MSG_SORTDESC'],
2122 MSG_EMPTY: _TM['MSG_EMPTY'],
2122 MSG_EMPTY: _TM['MSG_EMPTY'],
2123 MSG_ERROR: _TM['MSG_ERROR'],
2123 MSG_ERROR: _TM['MSG_ERROR'],
2124 MSG_LOADING: _TM['MSG_LOADING']
2124 MSG_LOADING: _TM['MSG_LOADING']
2125 });
2125 });
2126 myDataTable.subscribe('postRenderEvent',function(oArgs) {
2126 myDataTable.subscribe('postRenderEvent',function(oArgs) {
2127 tooltip_activate();
2127 tooltip_activate();
2128 quick_repo_menu();
2128 quick_repo_menu();
2129 });
2129 });
2130
2130
2131 var filterTimeout = null;
2131 var filterTimeout = null;
2132 var $q_filter = $('#q_filter');
2132 var $q_filter = $('#q_filter');
2133
2133
2134 updateFilter = function () {
2134 updateFilter = function () {
2135 // Reset timeout
2135 // Reset timeout
2136 filterTimeout = null;
2136 filterTimeout = null;
2137
2137
2138 // Reset sort
2138 // Reset sort
2139 var state = myDataTable.getState();
2139 var state = myDataTable.getState();
2140 state.sortedBy = {key:sortkey, dir:YAHOO.widget.DataTable.CLASS_ASC};
2140 state.sortedBy = {key:sortkey, dir:YAHOO.widget.DataTable.CLASS_ASC};
2141
2141
2142 // Get filtered data
2142 // Get filtered data
2143 myDataSource.sendRequest($q_filter.val(), {
2143 myDataSource.sendRequest($q_filter.val(), {
2144 success : myDataTable.onDataReturnInitializeTable,
2144 success : myDataTable.onDataReturnInitializeTable,
2145 failure : myDataTable.onDataReturnInitializeTable,
2145 failure : myDataTable.onDataReturnInitializeTable,
2146 scope : myDataTable,
2146 scope : myDataTable,
2147 argument: state});
2147 argument: state});
2148 };
2148 };
2149
2149
2150 $q_filter.click(function(){
2150 $q_filter.click(function(){
2151 if(!$q_filter.hasClass('loaded')){
2151 if(!$q_filter.hasClass('loaded')){
2152 //TODO: load here full list later to do search within groups
2152 //TODO: load here full list later to do search within groups
2153 $q_filter.addClass('loaded');
2153 $q_filter.addClass('loaded');
2154 }
2154 }
2155 });
2155 });
2156
2156
2157 $q_filter.keyup(function (e) {
2157 $q_filter.keyup(function (e) {
2158 clearTimeout(filterTimeout);
2158 clearTimeout(filterTimeout);
2159 filterTimeout = setTimeout(updateFilter, 600);
2159 filterTimeout = setTimeout(updateFilter, 600);
2160 });
2160 });
2161 }
2161 }
2162
2162
2163 // global hooks after DOM is loaded
2163 // global hooks after DOM is loaded
2164
2164
2165 $(document).ready(function(){
2165 $(document).ready(function(){
2166 $('.diff-collapse-button').click(function(e) {
2166 $('.diff-collapse-button').click(function(e) {
2167 var $button = $(e.currentTarget);
2167 var $button = $(e.currentTarget);
2168 var $target = $('#' + $button.attr('target'));
2168 var $target = $('#' + $button.attr('target'));
2169 if($target.hasClass('hidden')){
2169 if($target.hasClass('hidden')){
2170 $target.removeClass('hidden');
2170 $target.removeClass('hidden');
2171 $button.html("&uarr; {0} &uarr;".format(_TM['Collapse diff']));
2171 $button.html("&uarr; {0} &uarr;".format(_TM['Collapse Diff']));
2172 }
2172 }
2173 else if(!$target.hasClass('hidden')){
2173 else if(!$target.hasClass('hidden')){
2174 $target.addClass('hidden');
2174 $target.addClass('hidden');
2175 $button.html("&darr; {0} &darr;".format(_TM['Expand diff']));
2175 $button.html("&darr; {0} &darr;".format(_TM['Expand Diff']));
2176 }
2176 }
2177 });
2177 });
2178 });
2178 });
@@ -1,60 +1,60 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Admin journal')}
5 ${_('Admin Journal')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <form id="filter_form">
12 <form id="filter_form">
13 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term or _('journal filter...')}"/>
13 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term or _('journal filter...')}"/>
14 <span class="tooltip" title="${h.tooltip(h.journal_filter_help())}">?</span>
14 <span class="tooltip" title="${h.tooltip(h.journal_filter_help())}">?</span>
15 <input type='submit' value="${_('filter')}" class="btn btn-mini" style="padding:0px 2px 0px 2px;margin:0px"/>
15 <input type='submit' value="${_('Filter')}" class="btn btn-mini" style="padding:0px 2px 0px 2px;margin:0px"/>
16 ${_('Admin journal')} - ${ungettext('%s entry', '%s entries', c.users_log.item_count) % (c.users_log.item_count)}
16 ${_('Admin Journal')} - ${ungettext('%s Entry', '%s Entries', c.users_log.item_count) % (c.users_log.item_count)}
17 </form>
17 </form>
18 ${h.end_form()}
18 ${h.end_form()}
19 </%def>
19 </%def>
20
20
21 <%def name="page_nav()">
21 <%def name="page_nav()">
22 ${self.menu('admin')}
22 ${self.menu('admin')}
23 </%def>
23 </%def>
24 <%def name="main()">
24 <%def name="main()">
25 <div class="box">
25 <div class="box">
26 <!-- box / title -->
26 <!-- box / title -->
27 <div class="title">
27 <div class="title">
28 ${self.breadcrumbs()}
28 ${self.breadcrumbs()}
29 </div>
29 </div>
30 <!-- end box / title -->
30 <!-- end box / title -->
31 <div class="table">
31 <div class="table">
32 <div id="user_log">
32 <div id="user_log">
33 ${c.log_data}
33 ${c.log_data}
34 </div>
34 </div>
35 </div>
35 </div>
36 </div>
36 </div>
37
37
38 <script>
38 <script>
39 $(document).ready(function() {
39 $(document).ready(function() {
40 $('#j_filter').click(function(){
40 $('#j_filter').click(function(){
41 var $jfilter = $('#j_filter');
41 var $jfilter = $('#j_filter');
42 if($jfilter.hasClass('initial')){
42 if($jfilter.hasClass('initial')){
43 $jfilter.val('');
43 $jfilter.val('');
44 }
44 }
45 });
45 });
46 var fix_j_filter_width = function(len){
46 var fix_j_filter_width = function(len){
47 $('#j_filter').css('width', Math.max(80, len*6.50)+'px');
47 $('#j_filter').css('width', Math.max(80, len*6.50)+'px');
48 };
48 };
49 $('#j_filter').keyup(function () {
49 $('#j_filter').keyup(function () {
50 fix_j_filter_width($('#j_filter').val().length);
50 fix_j_filter_width($('#j_filter').val().length);
51 });
51 });
52 $('#filter_form').submit(function (e) {
52 $('#filter_form').submit(function (e) {
53 e.preventDefault();
53 e.preventDefault();
54 var val = $('#j_filter').val();
54 var val = $('#j_filter').val();
55 window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val);
55 window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val);
56 });
56 });
57 fix_j_filter_width($('#j_filter').val().length);
57 fix_j_filter_width($('#j_filter').val().length);
58 });
58 });
59 </script>
59 </script>
60 </%def>
60 </%def>
@@ -1,96 +1,96 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Repositories defaults')}
5 ${_('Repository Defaults')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${_('Defaults')}
14 ${_('Defaults')}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box">
22 <div class="box">
23 <!-- box / title -->
23 <!-- box / title -->
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 </div>
26 </div>
27
27
28 <h3>${_('Repositories defaults')}</h3>
28 <h3>${_('Repository Defaults')}</h3>
29
29
30 ${h.form(url('default', id='defaults'),method='put')}
30 ${h.form(url('default', id='defaults'),method='put')}
31 <div class="form">
31 <div class="form">
32 <!-- fields -->
32 <!-- fields -->
33
33
34 <div class="fields">
34 <div class="fields">
35
35
36 <div class="field">
36 <div class="field">
37 <div class="label">
37 <div class="label">
38 <label for="default_repo_type">${_('Type')}:</label>
38 <label for="default_repo_type">${_('Type')}:</label>
39 </div>
39 </div>
40 <div class="input">
40 <div class="input">
41 ${h.select('default_repo_type','hg',c.backends,class_="medium")}
41 ${h.select('default_repo_type','hg',c.backends,class_="medium")}
42 </div>
42 </div>
43 </div>
43 </div>
44
44
45 <div class="field">
45 <div class="field">
46 <div class="label label-checkbox">
46 <div class="label label-checkbox">
47 <label for="default_repo_private">${_('Private repository')}:</label>
47 <label for="default_repo_private">${_('Private repository')}:</label>
48 </div>
48 </div>
49 <div class="checkboxes">
49 <div class="checkboxes">
50 ${h.checkbox('default_repo_private',value="True")}
50 ${h.checkbox('default_repo_private',value="True")}
51 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
51 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
52 </div>
52 </div>
53 </div>
53 </div>
54
54
55
55
56 <div class="field">
56 <div class="field">
57 <div class="label label-checkbox">
57 <div class="label label-checkbox">
58 <label for="default_repo_enable_statistics">${_('Enable statistics')}:</label>
58 <label for="default_repo_enable_statistics">${_('Enable statistics')}:</label>
59 </div>
59 </div>
60 <div class="checkboxes">
60 <div class="checkboxes">
61 ${h.checkbox('default_repo_enable_statistics',value="True")}
61 ${h.checkbox('default_repo_enable_statistics',value="True")}
62 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
62 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
63 </div>
63 </div>
64 </div>
64 </div>
65
65
66 <div class="field">
66 <div class="field">
67 <div class="label label-checkbox">
67 <div class="label label-checkbox">
68 <label for="default_repo_enable_downloads">${_('Enable downloads')}:</label>
68 <label for="default_repo_enable_downloads">${_('Enable downloads')}:</label>
69 </div>
69 </div>
70 <div class="checkboxes">
70 <div class="checkboxes">
71 ${h.checkbox('default_repo_enable_downloads',value="True")}
71 ${h.checkbox('default_repo_enable_downloads',value="True")}
72 <span class="help-block">${_('Enable download menu on summary page.')}</span>
72 <span class="help-block">${_('Enable download menu on summary page.')}</span>
73 </div>
73 </div>
74 </div>
74 </div>
75
75
76 <div class="field">
76 <div class="field">
77 <div class="label label-checkbox">
77 <div class="label label-checkbox">
78 <label for="default_repo_enable_locking">${_('Enable locking')}:</label>
78 <label for="default_repo_enable_locking">${_('Enable locking')}:</label>
79 </div>
79 </div>
80 <div class="checkboxes">
80 <div class="checkboxes">
81 ${h.checkbox('default_repo_enable_locking',value="True")}
81 ${h.checkbox('default_repo_enable_locking',value="True")}
82 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
82 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
83 </div>
83 </div>
84 </div>
84 </div>
85
85
86 <div class="buttons">
86 <div class="buttons">
87 ${h.submit('save',_('Save'),class_="btn")}
87 ${h.submit('save',_('Save'),class_="btn")}
88 </div>
88 </div>
89 </div>
89 </div>
90 </div>
90 </div>
91 ${h.end_form()}
91 ${h.end_form()}
92
92
93 ##<h3>${_('Groups defaults')}</h3>
93 ##<h3>${_('Groups defaults')}</h3>
94
94
95 </div>
95 </div>
96 </%def>
96 </%def>
@@ -1,80 +1,80 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 %if c.show_private:
5 %if c.show_private:
6 ${_('Private Gists for user %s') % c.authuser.username}
6 ${_('Private Gists for User %s') % c.authuser.username}
7 %elif c.show_public:
7 %elif c.show_public:
8 ${_('Public Gists for user %s') % c.authuser.username}
8 ${_('Public Gists for User %s') % c.authuser.username}
9 %else:
9 %else:
10 ${_('Public Gists')}
10 ${_('Public Gists')}
11 %endif
11 %endif
12 %if c.site_name:
12 %if c.site_name:
13 &middot; ${c.site_name}
13 &middot; ${c.site_name}
14 %endif
14 %endif
15 </%def>
15 </%def>
16
16
17 <%def name="breadcrumbs_links()">
17 <%def name="breadcrumbs_links()">
18 %if c.show_private:
18 %if c.show_private:
19 ${_('Private Gists for user %s') % c.authuser.username}
19 ${_('Private Gists for User %s') % c.authuser.username}
20 %elif c.show_public:
20 %elif c.show_public:
21 ${_('Public Gists for user %s') % c.authuser.username}
21 ${_('Public Gists for User %s') % c.authuser.username}
22 %else:
22 %else:
23 ${_('Public Gists')}
23 ${_('Public Gists')}
24 %endif
24 %endif
25 - ${c.gists_pager.item_count}
25 - ${c.gists_pager.item_count}
26 </%def>
26 </%def>
27
27
28 <%def name="page_nav()">
28 <%def name="page_nav()">
29 ${self.menu('gists')}
29 ${self.menu('gists')}
30 </%def>
30 </%def>
31
31
32 <%def name="main()">
32 <%def name="main()">
33 <div class="box">
33 <div class="box">
34 <!-- box / title -->
34 <!-- box / title -->
35 <div class="title">
35 <div class="title">
36 ${self.breadcrumbs()}
36 ${self.breadcrumbs()}
37 %if c.authuser.username != 'default':
37 %if c.authuser.username != 'default':
38 <ul class="links">
38 <ul class="links">
39 <li>
39 <li>
40 <a href="${h.url('new_gist')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Create New Gist')}</a>
40 <a href="${h.url('new_gist')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Create New Gist')}</a>
41 </li>
41 </li>
42 </ul>
42 </ul>
43 %endif
43 %endif
44 </div>
44 </div>
45 %if c.gists_pager.item_count>0:
45 %if c.gists_pager.item_count>0:
46 % for gist in c.gists_pager:
46 % for gist in c.gists_pager:
47 <div class="gist-item" style="padding:10px 20px 10px 15px">
47 <div class="gist-item" style="padding:10px 20px 10px 15px">
48
48
49 <div class="gravatar">
49 <div class="gravatar">
50 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(gist.owner.full_contact),28)}"/>
50 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(gist.owner.full_contact),28)}"/>
51 </div>
51 </div>
52 <div title="${gist.owner.full_contact}" class="user" style="font-size: 16px">
52 <div title="${gist.owner.full_contact}" class="user" style="font-size: 16px">
53 <b>${h.person(gist.owner.full_contact)}</b> /
53 <b>${h.person(gist.owner.full_contact)}</b> /
54 <b><a href="${h.url('gist',gist_id=gist.gist_access_id)}">gist: ${gist.gist_access_id}</a></b>
54 <b><a href="${h.url('gist',gist_id=gist.gist_access_id)}">gist: ${gist.gist_access_id}</a></b>
55 </div>
55 </div>
56 <div style="padding: 4px 0px 0px 0px">
56 <div style="padding: 4px 0px 0px 0px">
57 ${_('Created')} ${h.age(gist.created_on)} /
57 ${_('Created')} ${h.age(gist.created_on)} /
58 <span style="color: #AAA">
58 <span style="color: #AAA">
59 %if gist.gist_expires == -1:
59 %if gist.gist_expires == -1:
60 ${_('Expires')}: ${_('never')}
60 ${_('Expires')}: ${_('never')}
61 %else:
61 %else:
62 ${_('Expires')}: ${h.age(h.time_to_datetime(gist.gist_expires))}
62 ${_('Expires')}: ${h.age(h.time_to_datetime(gist.gist_expires))}
63 %endif
63 %endif
64 </span>
64 </span>
65 </div>
65 </div>
66
66
67 <div style="border:0px;padding:10px 0px 0px 40px;color:#AAA">${gist.gist_description}</div>
67 <div style="border:0px;padding:10px 0px 0px 40px;color:#AAA">${gist.gist_description}</div>
68 </div>
68 </div>
69 % endfor
69 % endfor
70
70
71 <div class="notification-paginator">
71 <div class="notification-paginator">
72 <div class="pagination-wh pagination-left">
72 <div class="pagination-wh pagination-left">
73 ${c.gists_pager.pager('$link_previous ~2~ $link_next', **request.GET.mixed())}
73 ${c.gists_pager.pager('$link_previous ~2~ $link_next', **request.GET.mixed())}
74 </div>
74 </div>
75 </div>
75 </div>
76 %else:
76 %else:
77 <div class="table">${_('There are no gists yet')}</div>
77 <div class="table">${_('There are no gists yet')}</div>
78 %endif
78 %endif
79 </div>
79 </div>
80 </%def>
80 </%def>
@@ -1,53 +1,53 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('My account')} ${c.authuser.username}
5 ${_('My Account')} ${c.authuser.username}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${_('My Account')}
12 ${_('My Account')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('admin')}
16 ${self.menu('admin')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <div class="box" style="overflow:auto">
20 <div class="box" style="overflow:auto">
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 </div>
23 </div>
24
24
25 ##main
25 ##main
26 <div style="width: 150px; float:left">
26 <div style="width: 150px; float:left">
27 <ul class="nav nav-pills nav-stacked">
27 <ul class="nav nav-pills nav-stacked">
28 <li>
28 <li>
29 <div class="gravatar_box" style="height: 26px">
29 <div class="gravatar_box" style="height: 26px">
30 <div class="gravatar" style="float: left">
30 <div class="gravatar" style="float: left">
31 <img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/>
31 <img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/>
32 </div>
32 </div>
33 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
33 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
34 <strong>${c.user.username}</strong>
34 <strong>${c.user.username}</strong>
35 </div>
35 </div>
36 </div>
36 </div>
37 </li>
37 </li>
38 <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('my_account')}">${_('Profile')}</a></li>
38 <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('my_account')}">${_('Profile')}</a></li>
39 <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li>
39 <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li>
40 <li class="${'active' if c.active=='api_keys' else ''}"><a href="${h.url('my_account_api_keys')}">${_('API keys')}</a></li>
40 <li class="${'active' if c.active=='api_keys' else ''}"><a href="${h.url('my_account_api_keys')}">${_('API Keys')}</a></li>
41 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('my_account_emails')}">${_('My Emails')}</a></li>
41 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('my_account_emails')}">${_('My Emails')}</a></li>
42 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('My Repositories')}</a></li>
42 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('My Repositories')}</a></li>
43 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li>
43 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li>
44 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('My permissions')}</a></li>
44 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('My Permissions')}</a></li>
45 </ul>
45 </ul>
46 </div>
46 </div>
47
47
48 <div style="min-width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
48 <div style="min-width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
49 <%include file="/admin/my_account/my_account_${c.active}.html"/>
49 <%include file="/admin/my_account/my_account_${c.active}.html"/>
50 </div>
50 </div>
51 </div>
51 </div>
52
52
53 </%def>
53 </%def>
@@ -1,51 +1,51 b''
1 <div class="emails_wrap">
1 <div class="emails_wrap">
2 <table class="noborder">
2 <table class="noborder">
3 <tr>
3 <tr>
4 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email,16)}"/> </div></td>
4 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email,16)}"/> </div></td>
5 <td><div class="email">${c.user.email}</div></td>
5 <td><div class="email">${c.user.email}</div></td>
6 <td>
6 <td>
7 <span class="btn btn-mini btn-success disabled">${_('Primary')}</span>
7 <span class="btn btn-mini btn-success disabled">${_('Primary')}</span>
8 </td>
8 </td>
9 </tr>
9 </tr>
10 %if c.user_email_map:
10 %if c.user_email_map:
11 %for em in c.user_email_map:
11 %for em in c.user_email_map:
12 <tr>
12 <tr>
13 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.email,16)}"/> </div></td>
13 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.email,16)}"/> </div></td>
14 <td><div class="email">${em.email}</div></td>
14 <td><div class="email">${em.email}</div></td>
15 <td>
15 <td>
16 ${h.form(url('my_account_emails'),method='delete')}
16 ${h.form(url('my_account_emails'),method='delete')}
17 ${h.hidden('del_email_id',em.email_id)}
17 ${h.hidden('del_email_id',em.email_id)}
18 <i class="icon-remove-sign" style="color:#FF4444"></i>
18 <i class="icon-remove-sign" style="color:#FF4444"></i>
19 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
19 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
20 class_="action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
20 class_="action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
21 ${h.end_form()}
21 ${h.end_form()}
22 </td>
22 </td>
23 </tr>
23 </tr>
24 %endfor
24 %endfor
25 %else:
25 %else:
26 <tr><td><div class="ip">${_('No additional emails specified')}</div></td></tr>
26 <tr><td><div class="ip">${_('No additional emails specified.')}</div></td></tr>
27 %endif
27 %endif
28 </table>
28 </table>
29 </div>
29 </div>
30
30
31 <div>
31 <div>
32 ${h.form(url('my_account_emails'), method='post')}
32 ${h.form(url('my_account_emails'), method='post')}
33 <div class="form">
33 <div class="form">
34 <!-- fields -->
34 <!-- fields -->
35 <div class="fields">
35 <div class="fields">
36 <div class="field">
36 <div class="field">
37 <div class="label">
37 <div class="label">
38 <label for="new_email">${_('New email address')}:</label>
38 <label for="new_email">${_('New email address')}:</label>
39 </div>
39 </div>
40 <div class="input">
40 <div class="input">
41 ${h.text('new_email', class_='medium')}
41 ${h.text('new_email', class_='medium')}
42 </div>
42 </div>
43 </div>
43 </div>
44 <div class="buttons">
44 <div class="buttons">
45 ${h.submit('save',_('Add'),class_="btn")}
45 ${h.submit('save',_('Add'),class_="btn")}
46 ${h.reset('reset',_('Reset'),class_="btn")}
46 ${h.reset('reset',_('Reset'),class_="btn")}
47 </div>
47 </div>
48 </div>
48 </div>
49 </div>
49 </div>
50 ${h.end_form()}
50 ${h.end_form()}
51 </div>
51 </div>
@@ -1,38 +1,38 b''
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Change your account password')}</div>
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Change Your Account Password')}</div>
2 ${h.form(url('my_account_password'), method='post')}
2 ${h.form(url('my_account_password'), method='post')}
3 <div class="form">
3 <div class="form">
4 <div class="fields">
4 <div class="fields">
5 <div class="field">
5 <div class="field">
6 <div class="label">
6 <div class="label">
7 <label for="current_password">${_('Current password')}:</label>
7 <label for="current_password">${_('Current password')}:</label>
8 </div>
8 </div>
9 <div class="input">
9 <div class="input">
10 ${h.password('current_password',class_='medium',autocomplete="off")}
10 ${h.password('current_password',class_='medium',autocomplete="off")}
11 </div>
11 </div>
12 </div>
12 </div>
13
13
14 <div class="field">
14 <div class="field">
15 <div class="label">
15 <div class="label">
16 <label for="new_password">${_('New password')}:</label>
16 <label for="new_password">${_('New password')}:</label>
17 </div>
17 </div>
18 <div class="input">
18 <div class="input">
19 ${h.password('new_password',class_='medium', autocomplete="off")}
19 ${h.password('new_password',class_='medium', autocomplete="off")}
20 </div>
20 </div>
21 </div>
21 </div>
22
22
23 <div class="field">
23 <div class="field">
24 <div class="label">
24 <div class="label">
25 <label for="password_confirmation">${_('Confirm new password')}:</label>
25 <label for="password_confirmation">${_('Confirm new password')}:</label>
26 </div>
26 </div>
27 <div class="input">
27 <div class="input">
28 ${h.password('new_password_confirmation',class_='medium', autocomplete="off")}
28 ${h.password('new_password_confirmation',class_='medium', autocomplete="off")}
29 </div>
29 </div>
30 </div>
30 </div>
31
31
32 <div class="buttons">
32 <div class="buttons">
33 ${h.submit('save',_('Save'),class_="btn")}
33 ${h.submit('save',_('Save'),class_="btn")}
34 ${h.reset('reset',_('Reset'),class_="btn")}
34 ${h.reset('reset',_('Reset'),class_="btn")}
35 </div>
35 </div>
36 </div>
36 </div>
37 </div>
37 </div>
38 ${h.end_form()}
38 ${h.end_form()}
@@ -1,107 +1,107 b''
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Repositories you are owner of')}</div>
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Repositories You Own')}</div>
2 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter"
2 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter"
3 placeholder="${_('quick filter...')}" value=""/>
3 placeholder="${_('quick filter...')}" value=""/>
4
4
5 <div class="table-grid table yui-skin-sam" id="repos_list_wrap"></div>
5 <div class="table-grid table yui-skin-sam" id="repos_list_wrap"></div>
6 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
6 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
7
7
8 <script>
8 <script>
9 function table_renderer(data){
9 function table_renderer(data){
10 var myDataSource = new YAHOO.util.DataSource(data);
10 var myDataSource = new YAHOO.util.DataSource(data);
11 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
11 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
12
12
13 myDataSource.responseSchema = {
13 myDataSource.responseSchema = {
14 resultsList: "records",
14 resultsList: "records",
15 fields: [
15 fields: [
16 {key:"menu"},
16 {key:"menu"},
17 {key:"raw_name"},
17 {key:"raw_name"},
18 {key:"name"},
18 {key:"name"},
19 {key:"last_changeset"},
19 {key:"last_changeset"},
20 {key:"last_rev_raw"},
20 {key:"last_rev_raw"},
21 {key:"action"}
21 {key:"action"}
22 ]
22 ]
23 };
23 };
24 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
24 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
25 // This is the filter function
25 // This is the filter function
26 var data = res.results || [],
26 var data = res.results || [],
27 filtered = [],
27 filtered = [],
28 i,l;
28 i,l;
29
29
30 if (req) {
30 if (req) {
31 req = req.toLowerCase();
31 req = req.toLowerCase();
32 for (i = 0; i<data.length; i++) {
32 for (i = 0; i<data.length; i++) {
33 var pos = data[i].raw_name.toLowerCase().indexOf(req)
33 var pos = data[i].raw_name.toLowerCase().indexOf(req)
34 if (pos != -1) {
34 if (pos != -1) {
35 filtered.push(data[i]);
35 filtered.push(data[i]);
36 }
36 }
37 }
37 }
38 res.results = filtered;
38 res.results = filtered;
39 }
39 }
40 return res;
40 return res;
41 }
41 }
42
42
43 // main table sorting
43 // main table sorting
44 var myColumnDefs = [
44 var myColumnDefs = [
45 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
45 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
46 {key:"name",label:"${_('Name')}",sortable:true,
46 {key:"name",label:"${_('Name')}",sortable:true,
47 sortOptions: { sortFunction: nameSort }},
47 sortOptions: { sortFunction: nameSort }},
48 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
48 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
49 sortOptions: { sortFunction: revisionSort }},
49 sortOptions: { sortFunction: revisionSort }},
50 {key:"action",label:"${_('Action')}",sortable:false}
50 {key:"action",label:"${_('Action')}",sortable:false}
51 ];
51 ];
52
52
53 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
53 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
54 sortedBy:{key:"name",dir:"asc"},
54 sortedBy:{key:"name",dir:"asc"},
55 paginator: YUI_paginator(50, ['user-paginator']),
55 paginator: YUI_paginator(50, ['user-paginator']),
56
56
57 MSG_SORTASC:"${_('Click to sort ascending')}",
57 MSG_SORTASC:"${_('Click to sort ascending')}",
58 MSG_SORTDESC:"${_('Click to sort descending')}",
58 MSG_SORTDESC:"${_('Click to sort descending')}",
59 MSG_EMPTY:"${_('No records found.')}",
59 MSG_EMPTY:"${_('No records found.')}",
60 MSG_ERROR:"${_('Data error.')}",
60 MSG_ERROR:"${_('Data error.')}",
61 MSG_LOADING:"${_('Loading...')}"
61 MSG_LOADING:"${_('Loading...')}"
62 }
62 }
63 );
63 );
64 myDataTable.subscribe('postRenderEvent',function(oArgs) {
64 myDataTable.subscribe('postRenderEvent',function(oArgs) {
65 tooltip_activate();
65 tooltip_activate();
66 quick_repo_menu();
66 quick_repo_menu();
67 });
67 });
68
68
69 var filterTimeout = null;
69 var filterTimeout = null;
70
70
71 updateFilter = function() {
71 updateFilter = function() {
72 // Reset timeout
72 // Reset timeout
73 filterTimeout = null;
73 filterTimeout = null;
74
74
75 // Reset sort
75 // Reset sort
76 var state = myDataTable.getState();
76 var state = myDataTable.getState();
77 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
77 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
78
78
79 // Get filtered data
79 // Get filtered data
80 myDataSource.sendRequest(YUD.get('q_filter').value,{
80 myDataSource.sendRequest(YUD.get('q_filter').value,{
81 success : myDataTable.onDataReturnInitializeTable,
81 success : myDataTable.onDataReturnInitializeTable,
82 failure : myDataTable.onDataReturnInitializeTable,
82 failure : myDataTable.onDataReturnInitializeTable,
83 scope : myDataTable,
83 scope : myDataTable,
84 argument: state
84 argument: state
85 });
85 });
86
86
87 };
87 };
88 $('#q_filter').click(function(){
88 $('#q_filter').click(function(){
89 if(!$('#q_filter').hasClass('loaded')){
89 if(!$('#q_filter').hasClass('loaded')){
90 //TODO: load here full list later to do search within groups
90 //TODO: load here full list later to do search within groups
91 $('#q_filter').addClass('loaded');
91 $('#q_filter').addClass('loaded');
92 }
92 }
93 });
93 });
94
94
95 $('#q_filter').keyup(function(){
95 $('#q_filter').keyup(function(){
96 clearTimeout(filterTimeout);
96 clearTimeout(filterTimeout);
97 filterTimeout = setTimeout(updateFilter,600);
97 filterTimeout = setTimeout(updateFilter,600);
98 });
98 });
99
99
100 if($('#q_filter').val()) {
100 if($('#q_filter').val()) {
101 updateFilter();
101 updateFilter();
102 }
102 }
103
103
104 }
104 }
105
105
106 table_renderer(${c.data |n});
106 table_renderer(${c.data |n});
107 </script>
107 </script>
@@ -1,107 +1,107 b''
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Repositories you are watching')}</div>
1 <div style="font-size: 20px; color: #666666; padding: 0px 0px 10px 0px">${_('Repositories You are Watching')}</div>
2 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter"
2 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter"
3 placeholder="${_('quick filter...')}" value=""/>
3 placeholder="${_('quick filter...')}" value=""/>
4
4
5 <div class="table-grid table yui-skin-sam" id="repos_list_wrap"></div>
5 <div class="table-grid table yui-skin-sam" id="repos_list_wrap"></div>
6 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
6 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
7
7
8 <script>
8 <script>
9 function table_renderer(data){
9 function table_renderer(data){
10 var myDataSource = new YAHOO.util.DataSource(data);
10 var myDataSource = new YAHOO.util.DataSource(data);
11 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
11 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
12
12
13 myDataSource.responseSchema = {
13 myDataSource.responseSchema = {
14 resultsList: "records",
14 resultsList: "records",
15 fields: [
15 fields: [
16 {key:"menu"},
16 {key:"menu"},
17 {key:"raw_name"},
17 {key:"raw_name"},
18 {key:"name"},
18 {key:"name"},
19 {key:"last_changeset"},
19 {key:"last_changeset"},
20 {key:"last_rev_raw"},
20 {key:"last_rev_raw"},
21 {key:"action"}
21 {key:"action"}
22 ]
22 ]
23 };
23 };
24 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
24 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
25 // This is the filter function
25 // This is the filter function
26 var data = res.results || [],
26 var data = res.results || [],
27 filtered = [],
27 filtered = [],
28 i,l;
28 i,l;
29
29
30 if (req) {
30 if (req) {
31 req = req.toLowerCase();
31 req = req.toLowerCase();
32 for (i = 0; i<data.length; i++) {
32 for (i = 0; i<data.length; i++) {
33 var pos = data[i].raw_name.toLowerCase().indexOf(req)
33 var pos = data[i].raw_name.toLowerCase().indexOf(req)
34 if (pos != -1) {
34 if (pos != -1) {
35 filtered.push(data[i]);
35 filtered.push(data[i]);
36 }
36 }
37 }
37 }
38 res.results = filtered;
38 res.results = filtered;
39 }
39 }
40 return res;
40 return res;
41 }
41 }
42
42
43 // main table sorting
43 // main table sorting
44 var myColumnDefs = [
44 var myColumnDefs = [
45 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
45 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
46 {key:"name",label:"${_('Name')}",sortable:true,
46 {key:"name",label:"${_('Name')}",sortable:true,
47 sortOptions: { sortFunction: nameSort }},
47 sortOptions: { sortFunction: nameSort }},
48 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
48 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
49 sortOptions: { sortFunction: revisionSort }},
49 sortOptions: { sortFunction: revisionSort }},
50 {key:"action",label:"${_('Action')}",sortable:false}
50 {key:"action",label:"${_('Action')}",sortable:false}
51 ];
51 ];
52
52
53 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
53 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
54 sortedBy:{key:"name",dir:"asc"},
54 sortedBy:{key:"name",dir:"asc"},
55 paginator: YUI_paginator(50, ['user-paginator']),
55 paginator: YUI_paginator(50, ['user-paginator']),
56
56
57 MSG_SORTASC:"${_('Click to sort ascending')}",
57 MSG_SORTASC:"${_('Click to sort ascending')}",
58 MSG_SORTDESC:"${_('Click to sort descending')}",
58 MSG_SORTDESC:"${_('Click to sort descending')}",
59 MSG_EMPTY:"${_('No records found.')}",
59 MSG_EMPTY:"${_('No records found.')}",
60 MSG_ERROR:"${_('Data error.')}",
60 MSG_ERROR:"${_('Data error.')}",
61 MSG_LOADING:"${_('Loading...')}"
61 MSG_LOADING:"${_('Loading...')}"
62 }
62 }
63 );
63 );
64 myDataTable.subscribe('postRenderEvent',function(oArgs) {
64 myDataTable.subscribe('postRenderEvent',function(oArgs) {
65 tooltip_activate();
65 tooltip_activate();
66 quick_repo_menu();
66 quick_repo_menu();
67 });
67 });
68
68
69 var filterTimeout = null;
69 var filterTimeout = null;
70
70
71 updateFilter = function() {
71 updateFilter = function() {
72 // Reset timeout
72 // Reset timeout
73 filterTimeout = null;
73 filterTimeout = null;
74
74
75 // Reset sort
75 // Reset sort
76 var state = myDataTable.getState();
76 var state = myDataTable.getState();
77 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
77 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
78
78
79 // Get filtered data
79 // Get filtered data
80 myDataSource.sendRequest(YUD.get('q_filter').value,{
80 myDataSource.sendRequest(YUD.get('q_filter').value,{
81 success : myDataTable.onDataReturnInitializeTable,
81 success : myDataTable.onDataReturnInitializeTable,
82 failure : myDataTable.onDataReturnInitializeTable,
82 failure : myDataTable.onDataReturnInitializeTable,
83 scope : myDataTable,
83 scope : myDataTable,
84 argument: state
84 argument: state
85 });
85 });
86
86
87 };
87 };
88 $('#q_filter').click(function(){
88 $('#q_filter').click(function(){
89 if(!$('#q_filter').hasClass('loaded')){
89 if(!$('#q_filter').hasClass('loaded')){
90 //TODO: load here full list later to do search within groups
90 //TODO: load here full list later to do search within groups
91 $('#q_filter').addClass('loaded');
91 $('#q_filter').addClass('loaded');
92 }
92 }
93 });
93 });
94
94
95 $('#q_filter').keyup(function(){
95 $('#q_filter').keyup(function(){
96 clearTimeout(filterTimeout);
96 clearTimeout(filterTimeout);
97 filterTimeout = setTimeout(updateFilter,600);
97 filterTimeout = setTimeout(updateFilter,600);
98 });
98 });
99
99
100 if($('#q_filter').val()) {
100 if($('#q_filter').val()) {
101 updateFilter();
101 updateFilter();
102 }
102 }
103
103
104 }
104 }
105
105
106 table_renderer(${c.data |n});
106 table_renderer(${c.data |n});
107 </script>
107 </script>
@@ -1,61 +1,61 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('My Notifications')} ${c.authuser.username}
5 ${_('My Notifications')} ${c.authuser.username}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${_('My Notifications')}
12 ${_('My Notifications')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('admin')}
16 ${self.menu('admin')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <div class="box">
20 <div class="box">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
24 </div>
24 </div>
25
25
26 <div style="padding:14px 18px;text-align: right;float:left">
26 <div style="padding:14px 18px;text-align: right;float:left">
27 <span id='all' class="btn btn-mini"><a href="${h.url.current()}">${_('All')}</a></span>
27 <span id='all' class="btn btn-mini"><a href="${h.url.current()}">${_('All')}</a></span>
28 <span id='comment' class="btn btn-mini"><a href="${h.url.current(type=c.comment_type)}">${_('Comments')}</a></span>
28 <span id='comment' class="btn btn-mini"><a href="${h.url.current(type=c.comment_type)}">${_('Comments')}</a></span>
29 <span id='pull_request' class="btn btn-mini"><a href="${h.url.current(type=c.pull_request_type)}">${_('Pull Requests')}</a></span>
29 <span id='pull_request' class="btn btn-mini"><a href="${h.url.current(type=c.pull_request_type)}">${_('Pull Requests')}</a></span>
30 </div>
30 </div>
31 %if c.notifications:
31 %if c.notifications:
32 <div style="padding:14px 18px;text-align: right;float:right">
32 <div style="padding:14px 18px;text-align: right;float:right">
33 <span id='mark_all_read' class="btn btn-mini">${_('Mark all read')}</span>
33 <span id='mark_all_read' class="btn btn-mini">${_('Mark All Read')}</span>
34 </div>
34 </div>
35 %endif
35 %endif
36 <div id='notification_data'>
36 <div id='notification_data'>
37 <%include file='notifications_data.html'/>
37 <%include file='notifications_data.html'/>
38 </div>
38 </div>
39 </div>
39 </div>
40 <script type="text/javascript">
40 <script type="text/javascript">
41 var url_action = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
41 var url_action = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
42 var run = function(){
42 var run = function(){
43 $('.delete-notification').click(function(e){
43 $('.delete-notification').click(function(e){
44 var notification_id = e.currentTarget.id;
44 var notification_id = e.currentTarget.id;
45 deleteNotification(url_action,notification_id);
45 deleteNotification(url_action,notification_id);
46 });
46 });
47 $('.read-notification').click(function(e){
47 $('.read-notification').click(function(e){
48 var notification_id = e.currentTarget.id;
48 var notification_id = e.currentTarget.id;
49 readNotification(url_action,notification_id);
49 readNotification(url_action,notification_id);
50 });
50 });
51 }
51 }
52 run();
52 run();
53 $('#mark_all_read').click(function(){
53 $('#mark_all_read').click(function(){
54 var url = "${h.url('notifications_mark_all_read', **request.GET.mixed())}";
54 var url = "${h.url('notifications_mark_all_read', **request.GET.mixed())}";
55 asynchtml(url, $('#notification_data'), function(){run();});
55 asynchtml(url, $('#notification_data'), function(){run();});
56 });
56 });
57
57
58 var current_filter = "${c.current_filter}";
58 var current_filter = "${c.current_filter}";
59 $('#'+current_filter).addClass('active');
59 $('#'+current_filter).addClass('active');
60 </script>
60 </script>
61 </%def>
61 </%def>
@@ -1,57 +1,57 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Show notification')} ${c.authuser.username}
5 ${_('Show Notification')} ${c.authuser.username}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Notifications'),h.url('notifications'))}
12 ${h.link_to(_('Notifications'),h.url('notifications'))}
13 &raquo;
13 &raquo;
14 ${_('Show notification')}
14 ${_('Show Notification')}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box">
22 <div class="box">
23 <!-- box / title -->
23 <!-- box / title -->
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 </div>
26 </div>
27 <div class="table">
27 <div class="table">
28 <div id="notification_${c.notification.notification_id}">
28 <div id="notification_${c.notification.notification_id}">
29 <div class="notification-header">
29 <div class="notification-header">
30 <div class="gravatar">
30 <div class="gravatar">
31 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.notification.created_by_user.email),24)}"/>
31 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.notification.created_by_user.email),24)}"/>
32 </div>
32 </div>
33 <div class="desc">
33 <div class="desc">
34 ${c.notification.description}
34 ${c.notification.description}
35 </div>
35 </div>
36 <div class="delete-notifications">
36 <div class="delete-notifications">
37 <span id="${c.notification.notification_id}" class="delete-notification action"><i class="icon-minus-sign" id="yui-gen24"></i></span>
37 <span id="${c.notification.notification_id}" class="delete-notification action"><i class="icon-minus-sign" id="yui-gen24"></i></span>
38 </div>
38 </div>
39 </div>
39 </div>
40 <div class="notification-body">
40 <div class="notification-body">
41 <div class="notification-subject">${h.literal(c.notification.subject)}</div>
41 <div class="notification-subject">${h.literal(c.notification.subject)}</div>
42 %if c.notification.body:
42 %if c.notification.body:
43 ${h.rst_w_mentions(c.notification.body)}
43 ${h.rst_w_mentions(c.notification.body)}
44 %endif
44 %endif
45 </div>
45 </div>
46 </div>
46 </div>
47 </div>
47 </div>
48 </div>
48 </div>
49 <script type="text/javascript">
49 <script type="text/javascript">
50 var url = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
50 var url = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
51 var main = "${url('notifications')}";
51 var main = "${url('notifications')}";
52 $('.delete-notification').click(function(e){
52 $('.delete-notification').click(function(e){
53 var notification_id = e.currentTarget.id;
53 var notification_id = e.currentTarget.id;
54 deleteNotification(url,notification_id,[function(){window.location=main}])
54 deleteNotification(url,notification_id,[function(){window.location=main}])
55 });
55 });
56 </script>
56 </script>
57 </%def>
57 </%def>
@@ -1,52 +1,52 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Permissions administration')}
5 ${_('Permissions Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${_('Permissions')}
14 ${_('Permissions')}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20
20
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box" style="overflow:auto">
23 <div class="box" style="overflow:auto">
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 </div>
26 </div>
27
27
28 ##main
28 ##main
29 <div style="width: 150px; float:left">
29 <div style="width: 150px; float:left">
30 <ul class="nav nav-pills nav-stacked">
30 <ul class="nav nav-pills nav-stacked">
31 <li>
31 <li>
32 <div class="gravatar_box" style="height: 26px">
32 <div class="gravatar_box" style="height: 26px">
33 <div class="gravatar" style="float: left">
33 <div class="gravatar" style="float: left">
34 <i class="icon-ban-circle" style="font-size: 26px"></i>
34 <i class="icon-ban-circle" style="font-size: 26px"></i>
35 </div>
35 </div>
36 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
36 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
37 <strong>${_('Permissions')}</strong>
37 <strong>${_('Permissions')}</strong>
38 </div>
38 </div>
39 </div>
39 </div>
40 </li>
40 </li>
41 <li class="${'active' if c.active=='globals' else ''}"><a href="${h.url('admin_permissions')}">${_('Global')}</a></li>
41 <li class="${'active' if c.active=='globals' else ''}"><a href="${h.url('admin_permissions')}">${_('Global')}</a></li>
42 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('admin_permissions_ips')}">${_('IP whitelist')}</a></li>
42 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('admin_permissions_ips')}">${_('IP Whitelist')}</a></li>
43 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('admin_permissions_perms')}">${_('Overview')}</a></li>
43 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('admin_permissions_perms')}">${_('Overview')}</a></li>
44 </ul>
44 </ul>
45 </div>
45 </div>
46
46
47 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
47 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
48 <%include file="/admin/permissions/permissions_${c.active}.html"/>
48 <%include file="/admin/permissions/permissions_${c.active}.html"/>
49 </div>
49 </div>
50 </div>
50 </div>
51
51
52 </%def>
52 </%def>
@@ -1,113 +1,113 b''
1 ${h.form(url('admin_permissions'), method='post')}
1 ${h.form(url('admin_permissions'), method='post')}
2 <div class="form">
2 <div class="form">
3 <!-- fields -->
3 <!-- fields -->
4 <div class="fields">
4 <div class="fields">
5 <div class="field">
5 <div class="field">
6 <div class="label label-checkbox">
6 <div class="label label-checkbox">
7 <label for="anonymous">${_('Anonymous access')}:</label>
7 <label for="anonymous">${_('Anonymous access')}:</label>
8 </div>
8 </div>
9 <div class="checkboxes">
9 <div class="checkboxes">
10 <div class="checkbox">
10 <div class="checkbox">
11 ${h.checkbox('anonymous',True)}
11 ${h.checkbox('anonymous',True)}
12 </div>
12 </div>
13 <span class="help-block">${h.literal(_('Allow access to Kallithea without need to log in. Anonymous users use %s user permissions' % (h.link_to('*default*',h.url('admin_permissions_perms')))))}</span>
13 <span class="help-block">${h.literal(_('Allow access to Kallithea without needing to log in. Anonymous users use %s user permissions.' % (h.link_to('*default*',h.url('admin_permissions_perms')))))}</span>
14 </div>
14 </div>
15 </div>
15 </div>
16 <div class="field">
16 <div class="field">
17 <div class="label">
17 <div class="label">
18 <label for="default_repo_perm">${_('Repository')}:</label>
18 <label for="default_repo_perm">${_('Repository')}:</label>
19 </div>
19 </div>
20 <div class="select">
20 <div class="select">
21 ${h.select('default_repo_perm','',c.repo_perms_choices)}
21 ${h.select('default_repo_perm','',c.repo_perms_choices)}
22
22
23 ${h.checkbox('overwrite_default_repo','true')}
23 ${h.checkbox('overwrite_default_repo','true')}
24 <label for="overwrite_default_repo">
24 <label for="overwrite_default_repo">
25 <span class="tooltip"
25 <span class="tooltip"
26 title="${h.tooltip(_('All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost'))}">
26 title="${h.tooltip(_('All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost'))}">
27 ${_('Overwrite existing settings')}</span> </label>
27 ${_('Overwrite existing settings')}</span> </label>
28 </div>
28 </div>
29 </div>
29 </div>
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="default_group_perm">${_('Repository group')}:</label>
32 <label for="default_group_perm">${_('Repository group')}:</label>
33 </div>
33 </div>
34 <div class="select">
34 <div class="select">
35 ${h.select('default_group_perm','',c.group_perms_choices)}
35 ${h.select('default_group_perm','',c.group_perms_choices)}
36 ${h.checkbox('overwrite_default_group','true')}
36 ${h.checkbox('overwrite_default_group','true')}
37 <label for="overwrite_default_group">
37 <label for="overwrite_default_group">
38 <span class="tooltip"
38 <span class="tooltip"
39 title="${h.tooltip(_('All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
39 title="${h.tooltip(_('All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
40 ${_('Overwrite existing settings')}</span> </label>
40 ${_('Overwrite existing settings')}</span> </label>
41
41
42 </div>
42 </div>
43 </div>
43 </div>
44 <div class="field">
44 <div class="field">
45 <div class="label">
45 <div class="label">
46 <label for="default_group_perm">${_('User group')}:</label>
46 <label for="default_group_perm">${_('User group')}:</label>
47 </div>
47 </div>
48 <div class="select">
48 <div class="select">
49 ${h.select('default_user_group_perm','',c.user_group_perms_choices)}
49 ${h.select('default_user_group_perm','',c.user_group_perms_choices)}
50 ${h.checkbox('overwrite_default_user_group','true')}
50 ${h.checkbox('overwrite_default_user_group','true')}
51 <label for="overwrite_default_user_group">
51 <label for="overwrite_default_user_group">
52 <span class="tooltip"
52 <span class="tooltip"
53 title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
53 title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
54 ${_('Overwrite existing settings')}</span> </label>
54 ${_('Overwrite existing settings')}</span> </label>
55
55
56 </div>
56 </div>
57 </div>
57 </div>
58 <div class="field">
58 <div class="field">
59 <div class="label">
59 <div class="label">
60 <label for="default_repo_create">${_('Repository creation')}:</label>
60 <label for="default_repo_create">${_('Repository creation')}:</label>
61 </div>
61 </div>
62 <div class="select">
62 <div class="select">
63 ${h.select('default_repo_create','',c.repo_create_choices)}
63 ${h.select('default_repo_create','',c.repo_create_choices)}
64 </div>
64 </div>
65 </div>
65 </div>
66 <div class="field">
66 <div class="field">
67 <div class="label label-checkbox">
67 <div class="label label-checkbox">
68 <label for="create_on_write">${_('Repository creation with group write access')}:</label>
68 <label for="create_on_write">${_('Repository creation with group write access')}:</label>
69 </div>
69 </div>
70 <div class="select">
70 <div class="select">
71 ${h.select('create_on_write','',c.repo_create_on_write_choices)}
71 ${h.select('create_on_write','',c.repo_create_on_write_choices)}
72 <span class="help-block">${_('Write permission to repository groups allows creating repositories inside that group')}</span>
72 <span class="help-block">${_('Write permission to a repository group allows creating repositories inside that group.')}</span>
73 </div>
73 </div>
74 </div>
74 </div>
75 <div class="field">
75 <div class="field">
76 <div class="label">
76 <div class="label">
77 <label for="default_user_group_create">${_('User group creation')}:</label>
77 <label for="default_user_group_create">${_('User group creation')}:</label>
78 </div>
78 </div>
79 <div class="select">
79 <div class="select">
80 ${h.select('default_user_group_create','',c.user_group_create_choices)}
80 ${h.select('default_user_group_create','',c.user_group_create_choices)}
81 </div>
81 </div>
82 </div>
82 </div>
83 <div class="field">
83 <div class="field">
84 <div class="label">
84 <div class="label">
85 <label for="default_fork">${_('Repository forking')}:</label>
85 <label for="default_fork">${_('Repository forking')}:</label>
86 </div>
86 </div>
87 <div class="select">
87 <div class="select">
88 ${h.select('default_fork','',c.fork_choices)}
88 ${h.select('default_fork','',c.fork_choices)}
89 </div>
89 </div>
90 </div>
90 </div>
91 <div class="field">
91 <div class="field">
92 <div class="label">
92 <div class="label">
93 <label for="default_register">${_('Registration')}:</label>
93 <label for="default_register">${_('Registration')}:</label>
94 </div>
94 </div>
95 <div class="select">
95 <div class="select">
96 ${h.select('default_register','',c.register_choices)}
96 ${h.select('default_register','',c.register_choices)}
97 </div>
97 </div>
98 </div>
98 </div>
99 <div class="field">
99 <div class="field">
100 <div class="label">
100 <div class="label">
101 <label for="default_extern_activate">${_('External auth account activation')}:</label>
101 <label for="default_extern_activate">${_('External auth account activation')}:</label>
102 </div>
102 </div>
103 <div class="select">
103 <div class="select">
104 ${h.select('default_extern_activate','',c.extern_activate_choices)}
104 ${h.select('default_extern_activate','',c.extern_activate_choices)}
105 </div>
105 </div>
106 </div>
106 </div>
107 <div class="buttons">
107 <div class="buttons">
108 ${h.submit('save',_('Save'),class_="btn")}
108 ${h.submit('save',_('Save'),class_="btn")}
109 ${h.reset('reset',_('Reset'),class_="btn")}
109 ${h.reset('reset',_('Reset'),class_="btn")}
110 </div>
110 </div>
111 </div>
111 </div>
112 </div>
112 </div>
113 ${h.end_form()}
113 ${h.end_form()}
@@ -1,45 +1,45 b''
1 <h4>${_('Default ip whitelist for all users')}</h4>
1 <h4>${_('Default IP Whitelist for All Users')}</h4>
2
2
3 <div class="ips_wrap">
3 <div class="ips_wrap">
4 <table class="noborder">
4 <table class="noborder">
5 %if c.user_ip_map:
5 %if c.user_ip_map:
6 %for ip in c.user_ip_map:
6 %for ip in c.user_ip_map:
7 <tr>
7 <tr>
8 <td><div class="ip">${ip.ip_addr}</div></td>
8 <td><div class="ip">${ip.ip_addr}</div></td>
9 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
9 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
10 <td>
10 <td>
11 ${h.form(url('edit_user_ips', id=c.user.user_id),method='delete')}
11 ${h.form(url('edit_user_ips', id=c.user.user_id),method='delete')}
12 ${h.hidden('del_ip_id',ip.ip_id)}
12 ${h.hidden('del_ip_id',ip.ip_id)}
13 ${h.hidden('default_user', 'True')}
13 ${h.hidden('default_user', 'True')}
14 <i class="icon-remove-sign" style="color:#FF4444"></i> ${h.submit('remove_',_('delete'),id="remove_ip_%s" % ip.ip_id,
14 <i class="icon-remove-sign" style="color:#FF4444"></i> ${h.submit('remove_',_('delete'),id="remove_ip_%s" % ip.ip_id,
15 class_="action_button", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
15 class_="action_button", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
16 ${h.end_form()}
16 ${h.end_form()}
17 </td>
17 </td>
18 </tr>
18 </tr>
19 %endfor
19 %endfor
20 %else:
20 %else:
21 <tr><td><div class="ip">${_('All IP addresses are allowed')}</div></td></tr>
21 <tr><td><div class="ip">${_('All IP addresses are allowed.')}</div></td></tr>
22 %endif
22 %endif
23 </table>
23 </table>
24 </div>
24 </div>
25
25
26 ${h.form(url('edit_user_ips', id=c.user.user_id),method='put')}
26 ${h.form(url('edit_user_ips', id=c.user.user_id),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="new_ip">${_('New ip address')}:</label>
32 <label for="new_ip">${_('New ip address')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.hidden('default_user', 'True')}
35 ${h.hidden('default_user', 'True')}
36 ${h.text('new_ip', class_='medium')}
36 ${h.text('new_ip', class_='medium')}
37 </div>
37 </div>
38 </div>
38 </div>
39 <div class="buttons">
39 <div class="buttons">
40 ${h.submit('save',_('Add'),class_="btn")}
40 ${h.submit('save',_('Add'),class_="btn")}
41 ${h.reset('reset',_('Reset'),class_="btn")}
41 ${h.reset('reset',_('Reset'),class_="btn")}
42 </div>
42 </div>
43 </div>
43 </div>
44 </div>
44 </div>
45 ${h.end_form()}
45 ${h.end_form()}
@@ -1,5 +1,5 b''
1 <h4>${_('Default user permissions overview')}</h4>
1 <h4>${_('Default User Permissions Overview')}</h4>
2
2
3 ## permissions overview
3 ## permissions overview
4 <%namespace name="p" file="/base/perms_summary.html"/>
4 <%namespace name="p" file="/base/perms_summary.html"/>
5 ${p.perms_summary(c.perm_user.permissions, show_all=True)}
5 ${p.perms_summary(c.perm_user.permissions, show_all=True)}
@@ -1,98 +1,98 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Add repository group')}
5 ${_('Add Repository Group')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${h.link_to(_('Repository groups'),h.url('repos_groups'))}
14 ${h.link_to(_('Repository Groups'),h.url('repos_groups'))}
15 &raquo;
15 &raquo;
16 ${_('Add Repository Group')}
16 ${_('Add Repository Group')}
17 </%def>
17 </%def>
18
18
19 <%def name="page_nav()">
19 <%def name="page_nav()">
20 ${self.menu('admin')}
20 ${self.menu('admin')}
21 </%def>
21 </%def>
22
22
23 <%def name="main()">
23 <%def name="main()">
24 <div class="box">
24 <div class="box">
25 <!-- box / title -->
25 <!-- box / title -->
26 <div class="title">
26 <div class="title">
27 ${self.breadcrumbs()}
27 ${self.breadcrumbs()}
28 </div>
28 </div>
29 <!-- end box / title -->
29 <!-- end box / title -->
30 ${h.form(url('repos_groups'))}
30 ${h.form(url('repos_groups'))}
31 <div class="form">
31 <div class="form">
32 <!-- fields -->
32 <!-- fields -->
33 <div class="fields">
33 <div class="fields">
34 <div class="field">
34 <div class="field">
35 <div class="label">
35 <div class="label">
36 <label for="group_name">${_('Group name')}:</label>
36 <label for="group_name">${_('Group name')}:</label>
37 </div>
37 </div>
38 <div class="input">
38 <div class="input">
39 ${h.text('group_name',class_='small')}
39 ${h.text('group_name',class_='small')}
40 </div>
40 </div>
41 </div>
41 </div>
42
42
43 <div class="field">
43 <div class="field">
44 <div class="label label-textarea">
44 <div class="label label-textarea">
45 <label for="group_description">${_('Description')}:</label>
45 <label for="group_description">${_('Description')}:</label>
46 </div>
46 </div>
47 <div class="textarea-repo editor">
47 <div class="textarea-repo editor">
48 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
48 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
49 </div>
49 </div>
50 </div>
50 </div>
51
51
52 <div class="field">
52 <div class="field">
53 <div class="label">
53 <div class="label">
54 <label for="group_parent_id">${_('Group parent')}:</label>
54 <label for="group_parent_id">${_('Group parent')}:</label>
55 </div>
55 </div>
56 <div class="input">
56 <div class="input">
57 ${h.select('group_parent_id',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
57 ${h.select('group_parent_id',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
58 </div>
58 </div>
59 </div>
59 </div>
60
60
61 <div id="copy_perms" class="field">
61 <div id="copy_perms" class="field">
62 <div class="label label-checkbox">
62 <div class="label label-checkbox">
63 <label for="group_copy_permissions">${_('Copy parent group permissions')}:</label>
63 <label for="group_copy_permissions">${_('Copy parent group permissions')}:</label>
64 </div>
64 </div>
65 <div class="checkboxes">
65 <div class="checkboxes">
66 ${h.checkbox('group_copy_permissions',value="True")}
66 ${h.checkbox('group_copy_permissions',value="True")}
67 <span class="help-block">${_('Copy permission set from parent repository group.')}</span>
67 <span class="help-block">${_('Copy permission set from parent repository group.')}</span>
68 </div>
68 </div>
69 </div>
69 </div>
70
70
71 <div class="buttons">
71 <div class="buttons">
72 ${h.submit('save',_('Save'),class_="btn")}
72 ${h.submit('save',_('Save'),class_="btn")}
73 </div>
73 </div>
74 </div>
74 </div>
75 </div>
75 </div>
76 ${h.end_form()}
76 ${h.end_form()}
77 </div>
77 </div>
78 <script>
78 <script>
79 $(document).ready(function(){
79 $(document).ready(function(){
80 var setCopyPermsOption = function(group_val){
80 var setCopyPermsOption = function(group_val){
81 if(group_val != "-1"){
81 if(group_val != "-1"){
82 $('#copy_perms').show()
82 $('#copy_perms').show()
83 }
83 }
84 else{
84 else{
85 $('#copy_perms').hide();
85 $('#copy_perms').hide();
86 }
86 }
87 }
87 }
88 $("#group_parent_id").select2({
88 $("#group_parent_id").select2({
89 'dropdownAutoWidth': true
89 'dropdownAutoWidth': true
90 });
90 });
91 setCopyPermsOption($('#group_parent_id').val())
91 setCopyPermsOption($('#group_parent_id').val())
92 $("#group_parent_id").on("change", function(e) {
92 $("#group_parent_id").on("change", function(e) {
93 setCopyPermsOption(e.val)
93 setCopyPermsOption(e.val)
94 })
94 })
95 $('#group_name').focus();
95 $('#group_name').focus();
96 })
96 })
97 </script>
97 </script>
98 </%def>
98 </%def>
@@ -1,63 +1,63 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s Repository group settings') % c.repo_group.name}
5 ${_('%s Repository Group Settings') % c.repo_group.name}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${h.link_to(_('Repository Groups'),h.url('repos_groups'))}
14 ${h.link_to(_('Repository Groups'),h.url('repos_groups'))}
15 %if c.repo_group.parent_group:
15 %if c.repo_group.parent_group:
16 &raquo; ${h.link_to(c.repo_group.parent_group.name,h.url('repos_group_home',group_name=c.repo_group.parent_group.group_name))}
16 &raquo; ${h.link_to(c.repo_group.parent_group.name,h.url('repos_group_home',group_name=c.repo_group.parent_group.group_name))}
17 %endif
17 %endif
18 &raquo; ${c.repo_group.name}
18 &raquo; ${c.repo_group.name}
19 </%def>
19 </%def>
20
20
21 <%def name="breadcrumbs_side_links()">
21 <%def name="breadcrumbs_side_links()">
22 <ul class="links">
22 <ul class="links">
23 <li>
23 <li>
24 <a href="${h.url('new_repos_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Child Group')}</a>
24 <a href="${h.url('new_repos_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Child Group')}</a>
25 </li>
25 </li>
26 </ul>
26 </ul>
27 </%def>
27 </%def>
28
28
29 <%def name="page_nav()">
29 <%def name="page_nav()">
30 ${self.menu('admin')}
30 ${self.menu('admin')}
31 </%def>
31 </%def>
32
32
33 <%def name="main()">
33 <%def name="main()">
34 <div class="box" style="overflow:auto">
34 <div class="box" style="overflow:auto">
35 <div class="title">
35 <div class="title">
36 ${self.breadcrumbs()}
36 ${self.breadcrumbs()}
37 ${self.breadcrumbs_side_links()}
37 ${self.breadcrumbs_side_links()}
38 </div>
38 </div>
39
39
40 ##main
40 ##main
41 <div style="width: 150px; float:left">
41 <div style="width: 150px; float:left">
42 <ul class="nav nav-pills nav-stacked">
42 <ul class="nav nav-pills nav-stacked">
43 <li>
43 <li>
44 <div class="gravatar_box" style="height: 26px">
44 <div class="gravatar_box" style="height: 26px">
45 <div class="gravatar" style="float: left">
45 <div class="gravatar" style="float: left">
46 <i class="icon-folder-close" style="font-size: 26px"></i>
46 <i class="icon-folder-close" style="font-size: 26px"></i>
47 </div>
47 </div>
48 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
48 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
49 <strong>${c.repo_group.name}</strong>
49 <strong>${c.repo_group.name}</strong>
50 </div>
50 </div>
51 </div>
51 </div>
52 </li>
52 </li>
53 <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
53 <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
54 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
54 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
55 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
55 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
56 </ul>
56 </ul>
57 </div>
57 </div>
58
58
59 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
59 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
60 <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
60 <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
61 </div>
61 </div>
62 </div>
62 </div>
63 </%def>
63 </%def>
@@ -1,59 +1,59 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Repository groups administration')}
5 ${_('Repository Groups Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_group_count">0</span> ${_('repository groups')}
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_group_count">0</span> ${_('Repository Groups')}
14 </%def>
14 </%def>
15
15
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box">
22 <div class="box">
23 <!-- box / title -->
23 <!-- box / title -->
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 <ul class="links">
26 <ul class="links">
27 %if h.HasPermissionAny('hg.admin')():
27 %if h.HasPermissionAny('hg.admin')():
28 <li>
28 <li>
29 <a href="${h.url('new_repos_group')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Repository Group')}</a>
29 <a href="${h.url('new_repos_group')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Repository Group')}</a>
30 </li>
30 </li>
31 %endif
31 %endif
32 </ul>
32 </ul>
33 </div>
33 </div>
34 <!-- end box / title -->
34 <!-- end box / title -->
35 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
35 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
36 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
36 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
37 </div>
37 </div>
38 <script>
38 <script>
39 var data = ${c.data|n};
39 var data = ${c.data|n};
40 var fields = [
40 var fields = [
41 {key: "group_name"},
41 {key: "group_name"},
42 {key: "raw_name"},
42 {key: "raw_name"},
43 {key: "desc"},
43 {key: "desc"},
44 {key: "repos"},
44 {key: "repos"},
45 {key: "owner"},
45 {key: "owner"},
46 {key: "action"}
46 {key: "action"}
47 ];
47 ];
48 var column_defs = [
48 var column_defs = [
49 {key:"group_name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
49 {key:"group_name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
50 {key:"desc",label:"${_('Description')}",sortable:true},
50 {key:"desc",label:"${_('Description')}",sortable:true},
51 {key:"repos",label:"${_('Number of toplevel repositories')}",sortable:true},
51 {key:"repos",label:"${_('Number of Top-level Repositories')}",sortable:true},
52 {key:"owner",label:"${_('Owner')}",sortable:true},
52 {key:"owner",label:"${_('Owner')}",sortable:true},
53 {key:"action",label:"${_('Action')}",sortable:false}
53 {key:"action",label:"${_('Action')}",sortable:false}
54 ];
54 ];
55 var counter = YUD.get('repo_group_count');
55 var counter = YUD.get('repo_group_count');
56 var sort_key = "group_name";
56 var sort_key = "group_name";
57 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
57 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
58 </script>
58 </script>
59 </%def>
59 </%def>
@@ -1,37 +1,37 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Add repository')}
5 ${_('Add Repository')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 %if c.authuser.is_admin:
12 %if c.authuser.is_admin:
13 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 ${h.link_to(_('Admin'),h.url('admin_home'))}
14 &raquo;
14 &raquo;
15 ${h.link_to(_('Repositories'),h.url('repos'))}
15 ${h.link_to(_('Repositories'),h.url('repos'))}
16 %else:
16 %else:
17 ${_('Admin')}
17 ${_('Admin')}
18 &raquo;
18 &raquo;
19 ${_('Repositories')}
19 ${_('Repositories')}
20 %endif
20 %endif
21 &raquo;
21 &raquo;
22 ${_('Add Repository')}
22 ${_('Add Repository')}
23 </%def>
23 </%def>
24
24
25 <%def name="page_nav()">
25 <%def name="page_nav()">
26 ${self.menu('admin')}
26 ${self.menu('admin')}
27 </%def>
27 </%def>
28
28
29 <%def name="main()">
29 <%def name="main()">
30 <div class="box">
30 <div class="box">
31 <!-- box / title -->
31 <!-- box / title -->
32 <div class="title">
32 <div class="title">
33 ${self.breadcrumbs()}
33 ${self.breadcrumbs()}
34 </div>
34 </div>
35 <%include file="repo_add_base.html"/>
35 <%include file="repo_add_base.html"/>
36 </div>
36 </div>
37 </%def>
37 </%def>
@@ -1,128 +1,128 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 ${h.form(url('repos'))}
3 ${h.form(url('repos'))}
4 <div class="form">
4 <div class="form">
5 <!-- fields -->
5 <!-- fields -->
6 <div class="fields">
6 <div class="fields">
7 <div class="field">
7 <div class="field">
8 <div class="label">
8 <div class="label">
9 <label for="repo_name">${_('Name')}:</label>
9 <label for="repo_name">${_('Name')}:</label>
10 </div>
10 </div>
11 <div class="input">
11 <div class="input">
12 ${h.text('repo_name',class_="small")}
12 ${h.text('repo_name',class_="small")}
13 <div style="margin: 6px 0px 0px 0px">
13 <div style="margin: 6px 0px 0px 0px">
14 <a id="remote_clone_toggle" href="#"><i class="icon-download-alt"></i> ${_('Import existing repository ?')}</a>
14 <a id="remote_clone_toggle" href="#"><i class="icon-download-alt"></i> ${_('Import existing repository ?')}</a>
15 </div>
15 </div>
16 %if not c.authuser.is_admin:
16 %if not c.authuser.is_admin:
17 ${h.hidden('user_created',True)}
17 ${h.hidden('user_created',True)}
18 %endif
18 %endif
19 </div>
19 </div>
20 </div>
20 </div>
21 <div id="remote_clone" class="field" style="display: none">
21 <div id="remote_clone" class="field" style="display: none">
22 <div class="label">
22 <div class="label">
23 <label for="clone_uri">${_('Clone from')}:</label>
23 <label for="clone_uri">${_('Clone from')}:</label>
24 </div>
24 </div>
25 <div class="input">
25 <div class="input">
26 ${h.text('clone_uri',class_="small")}
26 ${h.text('clone_uri',class_="small")}
27 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
27 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
28 </div>
28 </div>
29 </div>
29 </div>
30 <div class="field">
30 <div class="field">
31 <div class="label label-textarea">
31 <div class="label label-textarea">
32 <label for="repo_description">${_('Description')}:</label>
32 <label for="repo_description">${_('Description')}:</label>
33 </div>
33 </div>
34 <div class="textarea-repo editor">
34 <div class="textarea-repo editor">
35 ${h.textarea('repo_description')}
35 ${h.textarea('repo_description')}
36 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
36 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
37 </div>
37 </div>
38 </div>
38 </div>
39 <div class="field">
39 <div class="field">
40 <div class="label">
40 <div class="label">
41 <label for="repo_group">${_('Repository group')}:</label>
41 <label for="repo_group">${_('Repository group')}:</label>
42 </div>
42 </div>
43 <div class="input">
43 <div class="input">
44 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
44 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
45 <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
45 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
46 </div>
46 </div>
47 </div>
47 </div>
48 <div id="copy_perms" class="field">
48 <div id="copy_perms" class="field">
49 <div class="label label-checkbox">
49 <div class="label label-checkbox">
50 <label for="repo_copy_permissions">${_('Copy parent group permissions')}:</label>
50 <label for="repo_copy_permissions">${_('Copy parent group permissions')}:</label>
51 </div>
51 </div>
52 <div class="checkboxes">
52 <div class="checkboxes">
53 ${h.checkbox('repo_copy_permissions',value="True")}
53 ${h.checkbox('repo_copy_permissions',value="True")}
54 <span class="help-block">${_('Copy permission set from parent repository group.')}</span>
54 <span class="help-block">${_('Copy permission set from parent repository group.')}</span>
55 </div>
55 </div>
56 </div>
56 </div>
57 <div class="field">
57 <div class="field">
58 <div class="label">
58 <div class="label">
59 <label for="repo_type">${_('Type')}:</label>
59 <label for="repo_type">${_('Type')}:</label>
60 </div>
60 </div>
61 <div class="input">
61 <div class="input">
62 ${h.select('repo_type','hg',c.backends,class_="small")}
62 ${h.select('repo_type','hg',c.backends,class_="small")}
63 <span class="help-block">${_('Type of repository to create.')}</span>
63 <span class="help-block">${_('Type of repository to create.')}</span>
64 </div>
64 </div>
65 </div>
65 </div>
66 <div class="field">
66 <div class="field">
67 <div class="label">
67 <div class="label">
68 <label for="repo_landing_rev">${_('Landing revision')}:</label>
68 <label for="repo_landing_rev">${_('Landing revision')}:</label>
69 </div>
69 </div>
70 <div class="input">
70 <div class="input">
71 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
71 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
72 <span class="help-block">${_('Default revision for files page, downloads, full text search index and readme generation')}</span>
72 <span class="help-block">${_('Default revision for files page, downloads, full text search index and readme generation')}</span>
73 </div>
73 </div>
74 </div>
74 </div>
75 <div class="field">
75 <div class="field">
76 <div class="label label-checkbox">
76 <div class="label label-checkbox">
77 <label for="repo_private">${_('Private repository')}:</label>
77 <label for="repo_private">${_('Private repository')}:</label>
78 </div>
78 </div>
79 <div class="checkboxes">
79 <div class="checkboxes">
80 ${h.checkbox('repo_private',value="True")}
80 ${h.checkbox('repo_private',value="True")}
81 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
81 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
82 </div>
82 </div>
83 </div>
83 </div>
84 <div class="buttons">
84 <div class="buttons">
85 ${h.submit('add',_('Add'),class_="btn")}
85 ${h.submit('add',_('Add'),class_="btn")}
86 </div>
86 </div>
87 </div>
87 </div>
88 </div>
88 </div>
89 <script>
89 <script>
90 $(document).ready(function(){
90 $(document).ready(function(){
91 var setCopyPermsOption = function(group_val){
91 var setCopyPermsOption = function(group_val){
92 if(group_val != "-1"){
92 if(group_val != "-1"){
93 $('#copy_perms').show()
93 $('#copy_perms').show()
94 }
94 }
95 else{
95 else{
96 $('#copy_perms').hide();
96 $('#copy_perms').hide();
97 }
97 }
98 }
98 }
99
99
100 $('#remote_clone_toggle').on('click', function(e){
100 $('#remote_clone_toggle').on('click', function(e){
101 $('#remote_clone').show();
101 $('#remote_clone').show();
102 e.preventDefault();
102 e.preventDefault();
103 })
103 })
104 if($('#remote_clone input').hasClass('error')){
104 if($('#remote_clone input').hasClass('error')){
105 $('#remote_clone').show();
105 $('#remote_clone').show();
106 }
106 }
107 if($('#remote_clone input').val()){
107 if($('#remote_clone input').val()){
108 $('#remote_clone').show();
108 $('#remote_clone').show();
109 }
109 }
110 $("#repo_group").select2({
110 $("#repo_group").select2({
111 'dropdownAutoWidth': true
111 'dropdownAutoWidth': true
112 });
112 });
113
113
114 setCopyPermsOption($('#repo_group').val())
114 setCopyPermsOption($('#repo_group').val())
115 $("#repo_group").on("change", function(e) {
115 $("#repo_group").on("change", function(e) {
116 setCopyPermsOption(e.val)
116 setCopyPermsOption(e.val)
117 })
117 })
118
118
119 $("#repo_type").select2({
119 $("#repo_type").select2({
120 'minimumResultsForSearch': -1
120 'minimumResultsForSearch': -1
121 });
121 });
122 $("#repo_landing_rev").select2({
122 $("#repo_landing_rev").select2({
123 'minimumResultsForSearch': -1
123 'minimumResultsForSearch': -1
124 });
124 });
125 $('#repo_name').focus();
125 $('#repo_name').focus();
126 })
126 })
127 </script>
127 </script>
128 ${h.end_form()}
128 ${h.end_form()}
@@ -1,69 +1,69 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 ## don't trigger flash messages on this page
4 ## don't trigger flash messages on this page
5 <%def name="flash_msg()">
5 <%def name="flash_msg()">
6 </%def>
6 </%def>
7
7
8 <%def name="title()">
8 <%def name="title()">
9 ${_('%s Creating repository') % c.repo_name}
9 ${_('%s Creating Repository') % c.repo_name}
10 %if c.site_name:
10 %if c.site_name:
11 &middot; ${c.site_name}
11 &middot; ${c.site_name}
12 %endif
12 %endif
13 </%def>
13 </%def>
14
14
15 <%def name="breadcrumbs_links()">
15 <%def name="breadcrumbs_links()">
16 ${_('Creating repository')} ${c.repo}
16 ${_('Creating repository')} ${c.repo}
17 </%def>
17 </%def>
18
18
19 <%def name="page_nav()">
19 <%def name="page_nav()">
20 ${self.menu('repositories')}
20 ${self.menu('repositories')}
21 </%def>
21 </%def>
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28
28
29 <div style="display:table; padding: 10px 0px; font-size: 14px;font-weight: bold;margin-right: auto;margin-left: auto">
29 <div style="display:table; padding: 10px 0px; font-size: 14px;font-weight: bold;margin-right: auto;margin-left: auto">
30 ${_('Repository "%(repo_name)s" is beeing created, you will be redirected when this process is finished.' % {'repo_name':c.repo_name})}
30 ${_('Repository "%(repo_name)s" is beeing created, you will be redirected when this process is finished.' % {'repo_name':c.repo_name})}
31 </div>
31 </div>
32
32
33 <div id="progress" style="width: 500px;margin-left: auto; margin-right: auto">
33 <div id="progress" style="width: 500px;margin-left: auto; margin-right: auto">
34 <div class="progress progress-striped active">
34 <div class="progress progress-striped active">
35 <div class="progress-bar progress-bar" role="progressbar"
35 <div class="progress-bar progress-bar" role="progressbar"
36 aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
36 aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
37 </div>
37 </div>
38 </div>
38 </div>
39 </div>
39 </div>
40 <div id="progress_error" style="display: none;">
40 <div id="progress_error" style="display: none;">
41 <div style="font-weight: bold; color:#aa1111">
41 <div style="font-weight: bold; color:#aa1111">
42 ${_("We're sorry but error occured during this operation. Please check your Kallithea server logs, or contact administrator.")}
42 ${_("We're sorry but error occured during this operation. Please check your Kallithea server logs, or contact administrator.")}
43 </div>
43 </div>
44 </div>
44 </div>
45 </div>
45 </div>
46 </%def>
46 </%def>
47
47
48 <script>
48 <script>
49 (function worker() {
49 (function worker() {
50 $.ajax({
50 $.ajax({
51 url: '${h.url('repo_check_home', repo_name=c.repo_name, repo=c.repo, task_id=c.task_id)}',
51 url: '${h.url('repo_check_home', repo_name=c.repo_name, repo=c.repo, task_id=c.task_id)}',
52 success: function(data) {
52 success: function(data) {
53 if(data.result === true){
53 if(data.result === true){
54 //redirect to created fork if our ajax loop tells us to do so.
54 //redirect to created fork if our ajax loop tells us to do so.
55 window.location = "${h.url('summary_home', repo_name = c.repo)}";
55 window.location = "${h.url('summary_home', repo_name = c.repo)}";
56 }
56 }
57 },
57 },
58 complete: function(resp, status) {
58 complete: function(resp, status) {
59 if (resp.status == 200){
59 if (resp.status == 200){
60 // Schedule the next request when the current one's complete
60 // Schedule the next request when the current one's complete
61 setTimeout(worker, 1000);
61 setTimeout(worker, 1000);
62 }
62 }
63 else{
63 else{
64 $("#progress").html($('#progress_error').html())
64 $("#progress").html($('#progress_error').html())
65 }
65 }
66 }
66 }
67 });
67 });
68 })();
68 })();
69 </script>
69 </script>
@@ -1,71 +1,71 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##
2 ##
3 ## See also repo_settings.html
3 ## See also repo_settings.html
4 ##
4 ##
5 <%inherit file="/base/base.html"/>
5 <%inherit file="/base/base.html"/>
6
6
7 <%def name="title()">
7 <%def name="title()">
8 ${_('%s repository settings') % c.repo_info.repo_name}
8 ${_('%s Repository Settings') % c.repo_info.repo_name}
9 %if c.site_name:
9 %if c.site_name:
10 &middot; ${c.site_name}
10 &middot; ${c.site_name}
11 %endif
11 %endif
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()">
14 <%def name="breadcrumbs_links()">
15 ${_('Settings')}
15 ${_('Settings')}
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('repositories')}
19 ${self.menu('repositories')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 ${self.repo_context_bar('options')}
23 ${self.repo_context_bar('options')}
24 <div class="box" style="overflow:auto">
24 <div class="box" style="overflow:auto">
25 <!--<div class="title">-->
25 <!--<div class="title">-->
26 <!--${self.breadcrumbs()}-->
26 <!--${self.breadcrumbs()}-->
27 <!--</div>-->
27 <!--</div>-->
28
28
29 ##main
29 ##main
30 <div style="width: 150px; float:left">
30 <div style="width: 150px; float:left">
31 <ul class="nav nav-pills nav-stacked">
31 <ul class="nav nav-pills nav-stacked">
32 <!--<li>-->
32 <!--<li>-->
33 <!--<div class="gravatar_box" style="height: 26px">-->
33 <!--<div class="gravatar_box" style="height: 26px">-->
34 <!--<div class="gravatar" style="float: left">-->
34 <!--<div class="gravatar" style="float: left">-->
35 <!--<i class="icon-group" style="font-size: 26px"></i>-->
35 <!--<i class="icon-group" style="font-size: 26px"></i>-->
36 <!--</div>-->
36 <!--</div>-->
37 <!--<div style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left">-->
37 <!--<div style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left">-->
38 <!--<strong>${'repo-info'}</strong>-->
38 <!--<strong>${'repo-info'}</strong>-->
39 <!--</div>-->
39 <!--</div>-->
40 <!--</div>-->
40 <!--</div>-->
41 <!--</li>-->
41 <!--</li>-->
42 <li class="${'active' if c.active=='settings' else ''}">
42 <li class="${'active' if c.active=='settings' else ''}">
43 <a href="${h.url('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a>
43 <a href="${h.url('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a>
44 </li>
44 </li>
45 <li class="${'active' if c.active=='permissions' else ''}">
45 <li class="${'active' if c.active=='permissions' else ''}">
46 <a href="${h.url('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
46 <a href="${h.url('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
47 </li>
47 </li>
48 <li class="${'active' if c.active=='advanced' else ''}">
48 <li class="${'active' if c.active=='advanced' else ''}">
49 <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
49 <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
50 </li>
50 </li>
51 <li class="${'active' if c.active=='fields' else ''}">
51 <li class="${'active' if c.active=='fields' else ''}">
52 <a href="${h.url('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra fields')}</a>
52 <a href="${h.url('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra Fields')}</a>
53 </li>
53 </li>
54 <li class="${'active' if c.active=='caches' else ''}">
54 <li class="${'active' if c.active=='caches' else ''}">
55 <a href="${h.url('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a>
55 <a href="${h.url('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a>
56 </li>
56 </li>
57 <li class="${'active' if c.active=='remote' else ''}">
57 <li class="${'active' if c.active=='remote' else ''}">
58 <a href="${h.url('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a>
58 <a href="${h.url('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a>
59 </li>
59 </li>
60 <li class="${'active' if c.active=='statistics' else ''}">
60 <li class="${'active' if c.active=='statistics' else ''}">
61 <a href="${h.url('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a>
61 <a href="${h.url('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a>
62 </li>
62 </li>
63 </ul>
63 </ul>
64 </div>
64 </div>
65
65
66 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
66 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
67 <%include file="/admin/repos/repo_edit_${c.active}.html"/>
67 <%include file="/admin/repos/repo_edit_${c.active}.html"/>
68 </div>
68 </div>
69 </div>
69 </div>
70
70
71 </%def>
71 </%def>
@@ -1,97 +1,97 b''
1 <h3>${_('Fork of')}</h3>
1 <h3>${_('Parent')}</h3>
2 ${h.form(url('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='put')}
2 ${h.form(url('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='put')}
3 <div class="form">
3 <div class="form">
4 <div class="fields">
4 <div class="fields">
5 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
5 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
6 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small")}
6 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small")}
7 </div>
7 </div>
8 <div class="field" style="border:none;color:#888">
8 <div class="field" style="border:none;color:#888">
9 <ul>
9 <ul>
10 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
10 <li>${_('''Manually set this repository as a fork of another from the list.''')}</li>
11 </ul>
11 </ul>
12 </div>
12 </div>
13 </div>
13 </div>
14 ${h.end_form()}
14 ${h.end_form()}
15
15
16 <script>
16 <script>
17 $(document).ready(function(){
17 $(document).ready(function(){
18 $("#id_fork_of").select2({
18 $("#id_fork_of").select2({
19 'dropdownAutoWidth': true
19 'dropdownAutoWidth': true
20 });
20 });
21 })
21 })
22 </script>
22 </script>
23
23
24 <h3>${_('Public journal visibility')}</h3>
24 <h3>${_('Public Journal Visibility')}</h3>
25 ${h.form(url('edit_repo_advanced_journal', repo_name=c.repo_info.repo_name), method='put')}
25 ${h.form(url('edit_repo_advanced_journal', repo_name=c.repo_info.repo_name), method='put')}
26 <div class="form">
26 <div class="form">
27 ${h.hidden('auth_token',str(h.get_token()))}
27 ${h.hidden('auth_token',str(h.get_token()))}
28 <div class="field">
28 <div class="field">
29 %if c.in_public_journal:
29 %if c.in_public_journal:
30 <button class="btn btn-small" type="submit">
30 <button class="btn btn-small" type="submit">
31 <i class="icon-minus"></i>
31 <i class="icon-minus"></i>
32 ${_('Remove from public journal')}
32 ${_('Remove from public journal')}
33 </button>
33 </button>
34 %else:
34 %else:
35 <button class="btn btn-small" type="submit">
35 <button class="btn btn-small" type="submit">
36 <i class="icon-plus"></i>
36 <i class="icon-plus"></i>
37 ${_('Add to public journal')}
37 ${_('Add to Public Journal')}
38 </button>
38 </button>
39 %endif
39 %endif
40 </div>
40 </div>
41 <div class="field" style="border:none;color:#888">
41 <div class="field" style="border:none;color:#888">
42 <ul>
42 <ul>
43 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}</li>
43 <li>${_('All actions done in this repository will be visible to everyone in the public journal.')}</li>
44 </ul>
44 </ul>
45 </div>
45 </div>
46 </div>
46 </div>
47 ${h.end_form()}
47 ${h.end_form()}
48
48
49 <h3>${_('Change locking')}</h3>
49 <h3>${_('Change Locking')}</h3>
50 ${h.form(url('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name), method='put')}
50 ${h.form(url('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name), method='put')}
51 <div class="form">
51 <div class="form">
52 <div class="fields">
52 <div class="fields">
53 %if c.repo_info.locked[0]:
53 %if c.repo_info.locked[0]:
54 ${h.hidden('set_unlock', '1')}
54 ${h.hidden('set_unlock', '1')}
55 <button class="btn btn-small" type="submit"
55 <button class="btn btn-small" type="submit"
56 onclick="return confirm('${_('Confirm to unlock repository')}');">
56 onclick="return confirm('${_('Confirm to unlock repository.')}');">
57 <i class="icon-unlock"></i>
57 <i class="icon-unlock"></i>
58 ${_('Unlock repository')}
58 ${_('Unlock Repository')}
59 </button>
59 </button>
60 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
60 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
61 %else:
61 %else:
62 ${h.hidden('set_lock', '1')}
62 ${h.hidden('set_lock', '1')}
63 <button class="btn btn-small" type="submit"
63 <button class="btn btn-small" type="submit"
64 onclick="return confirm('${_('Confirm to lock repository')}');">
64 onclick="return confirm('${_('Confirm to lock repository.')}');">
65 <i class="icon-lock"></i>
65 <i class="icon-lock"></i>
66 ${_('Lock repository')}
66 ${_('Lock Repository')}
67 </button>
67 </button>
68 ${_('Repository is not locked')}
68 ${_('Repository is not locked')}
69 %endif
69 %endif
70 </div>
70 </div>
71 <div class="field" style="border:none;color:#888">
71 <div class="field" style="border:none;color:#888">
72 <ul>
72 <ul>
73 <li>${_('Force locking on repository. Works only when anonymous access is disabled. Trigering a pull locks repository by user who pulled, only the same user can unlock by doing a push')}
73 <li>${_('Force locking on the repository. Works only when anonymous access is disabled. Triggering a pull locks the repository. The user who is pulling locks the repository; only the user who pulled and locked it can unlock it by doing a push.')}
74 </li>
74 </li>
75 </ul>
75 </ul>
76 </div>
76 </div>
77 </div>
77 </div>
78 ${h.end_form()}
78 ${h.end_form()}
79
79
80 <h3>${_('Delete')}</h3>
80 <h3>${_('Delete')}</h3>
81 ${h.form(url('repo', repo_name=c.repo_name),method='delete')}
81 ${h.form(url('repo', repo_name=c.repo_name),method='delete')}
82 <button class="btn btn-small btn-danger" type="submit"
82 <button class="btn btn-small btn-danger" type="submit"
83 onclick="return confirm('${_('Confirm to delete this repository: %s') % c.repo_name}');">
83 onclick="return confirm('${_('Confirm to delete this repository: %s') % c.repo_name}');">
84 <i class="icon-remove-sign"></i>
84 <i class="icon-remove-sign"></i>
85 ${_('Delete this repository')}
85 ${_('Delete this Repository')}
86 </button>
86 </button>
87 %if c.repo_info.forks.count():
87 %if c.repo_info.forks.count():
88 ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
88 ${ungettext('This repository has %s fork', 'This repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
89 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
89 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
90 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
90 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
91 %endif
91 %endif
92 <div class="field" style="border:none;color:#888">
92 <div class="field" style="border:none;color:#888">
93 <ul>
93 <ul>
94 <li>${_('This repository will be renamed in a special way in order to be unaccesible for Kallithea and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
94 <li>${_('The deleted repository will be moved away and hidden until the administrator expires it. The administrator can both permanently delete it or restore it.')}</li>
95 </ul>
95 </ul>
96 </div>
96 </div>
97 ${h.end_form()}
97 ${h.end_form()}
@@ -1,30 +1,30 b''
1 ${h.form(url('edit_repo_caches', repo_name=c.repo_name), method='put')}
1 ${h.form(url('edit_repo_caches', repo_name=c.repo_name), method='put')}
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
4 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate Repository Cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache.')+"');")}
5 <div class="field" style="border:none;color:#888">
5 <div class="field" style="border:none;color:#888">
6 <ul>
6 <ul>
7 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
7 <li>${_('Manually invalidate cache for this repository. On first access, the repository will be cached again.')}
8 </li>
8 </li>
9 </ul>
9 </ul>
10 </div>
10 </div>
11 <div class="field" style="border:none;">
11 <div class="field" style="border:none;">
12 ${_('List of cached values')}
12 ${_('List of Cached Values')}
13 <table>
13 <table>
14 <tr>
14 <tr>
15 <th>${_('Prefix')}</th>
15 <th>${_('Prefix')}</th>
16 <th>${_('Key')}</th>
16 <th>${_('Key')}</th>
17 <th>${_('Active')}</th>
17 <th>${_('Active')}</th>
18 </tr>
18 </tr>
19 %for cache in c.repo_info.cache_keys:
19 %for cache in c.repo_info.cache_keys:
20 <tr>
20 <tr>
21 <td>${cache.get_prefix() or '-'}</td>
21 <td>${cache.get_prefix() or '-'}</td>
22 <td>${cache.cache_key}</td>
22 <td>${cache.cache_key}</td>
23 <td>${h.boolicon(cache.cache_active)}</td>
23 <td>${h.boolicon(cache.cache_active)}</td>
24 </tr>
24 </tr>
25 %endfor
25 %endfor
26 </table>
26 </table>
27 </div>
27 </div>
28 </div>
28 </div>
29 </div>
29 </div>
30 ${h.end_form()}
30 ${h.end_form()}
@@ -1,68 +1,68 b''
1 %if c.visual.repository_fields:
1 %if c.visual.repository_fields:
2 %if c.repo_fields:
2 %if c.repo_fields:
3 <div class="emails_wrap">
3 <div class="emails_wrap">
4 <table class="noborder">
4 <table class="noborder">
5 <th>${_('Label')}</th>
5 <th>${_('Label')}</th>
6 <th>${_('Key')}</th>
6 <th>${_('Key')}</th>
7 <th>${_('Type')}</th>
7 <th>${_('Type')}</th>
8 <th>${_('Action')}</th>
8 <th>${_('Action')}</th>
9
9
10 %for field in c.repo_fields:
10 %for field in c.repo_fields:
11 <tr>
11 <tr>
12 <td>${field.field_label}</td>
12 <td>${field.field_label}</td>
13 <td>${field.field_key}</td>
13 <td>${field.field_key}</td>
14 <td>${field.field_type}</td>
14 <td>${field.field_type}</td>
15 <td>
15 <td>
16 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
16 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
17 <i class="icon-remove-sign" style="color:#FF4444"></i>
17 <i class="icon-remove-sign" style="color:#FF4444"></i>
18 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
18 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
19 class_="action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
19 class_="action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
20 ${h.end_form()}
20 ${h.end_form()}
21 </td>
21 </td>
22 </tr>
22 </tr>
23 %endfor
23 %endfor
24 </table>
24 </table>
25 </div>
25 </div>
26 %endif
26 %endif
27 ${h.form(url('create_repo_fields', repo_name=c.repo_name),method='put')}
27 ${h.form(url('create_repo_fields', repo_name=c.repo_name),method='put')}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30 <div class="fields">
30 <div class="fields">
31 <div class="field">
31 <div class="field">
32 <div class="label">
32 <div class="label">
33 <label for="new_field_key">${_('New field key')}:</label>
33 <label for="new_field_key">${_('New field key')}:</label>
34 </div>
34 </div>
35 <div class="input">
35 <div class="input">
36 ${h.text('new_field_key', class_='small')}
36 ${h.text('new_field_key', class_='small')}
37 </div>
37 </div>
38 </div>
38 </div>
39 <div class="field">
39 <div class="field">
40 <div class="label">
40 <div class="label">
41 <label for="new_field_label">${_('New field label')}:</label>
41 <label for="new_field_label">${_('New field label')}:</label>
42 </div>
42 </div>
43 <div class="input">
43 <div class="input">
44 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
44 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="new_field_desc">${_('New field description')}:</label>
50 <label for="new_field_desc">${_('New field description')}:</label>
51 </div>
51 </div>
52 <div class="input">
52 <div class="input">
53 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
53 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
54 </div>
54 </div>
55 </div>
55 </div>
56
56
57 <div class="buttons">
57 <div class="buttons">
58 ${h.submit('save',_('Add'),class_="btn")}
58 ${h.submit('save',_('Add'),class_="btn")}
59 ${h.reset('reset',_('Reset'),class_="btn")}
59 ${h.reset('reset',_('Reset'),class_="btn")}
60 </div>
60 </div>
61 </div>
61 </div>
62 </div>
62 </div>
63 ${h.end_form()}
63 ${h.end_form()}
64 %else:
64 %else:
65 <div style="font-size: 20px">
65 <div style="font-size: 20px">
66 ${_('Extra fields are disabled')}
66 ${_('Extra fields are disabled.')}
67 </div>
67 </div>
68 %endif
68 %endif
@@ -1,21 +1,21 b''
1 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
1 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
4 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
5 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small")}
5 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small")}
6 </div>
6 </div>
7 <div class="field" style="border:none;color:#888">
7 <div class="field" style="border:none;color:#888">
8 <ul>
8 <ul>
9 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
9 <li>${_('''Manually set this repository as a fork of another from the list.''')}</li>
10 </ul>
10 </ul>
11 </div>
11 </div>
12 </div>
12 </div>
13 ${h.end_form()}
13 ${h.end_form()}
14
14
15 <script>
15 <script>
16 $(document).ready(function(){
16 $(document).ready(function(){
17 $("#id_fork_of").select2({
17 $("#id_fork_of").select2({
18 'dropdownAutoWidth': true
18 'dropdownAutoWidth': true
19 });
19 });
20 })
20 })
21 </script>
21 </script>
@@ -1,16 +1,16 b''
1 %if c.repo_info.clone_uri:
1 %if c.repo_info.clone_uri:
2 <div style="font-size: 20px; padding: 0px 0px 10px 0px">
2 <div style="font-size: 20px; padding: 0px 0px 10px 0px">
3 ${_('Remote url')}: <a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri_hidden}</a></li>
3 ${_('Remote url')}: <a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri_hidden}</a></li>
4 </div>
4 </div>
5 ${h.form(url('edit_repo_remote', repo_name=c.repo_name), method='put')}
5 ${h.form(url('edit_repo_remote', repo_name=c.repo_name), method='put')}
6 <div class="form">
6 <div class="form">
7 <div class="fields">
7 <div class="fields">
8 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
8 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull Changes from Remote Location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side.')+"');")}
9 </div>
9 </div>
10 </div>
10 </div>
11 ${h.end_form()}
11 ${h.end_form()}
12 %else:
12 %else:
13 <div style="font-size: 20px">
13 <div style="font-size: 20px">
14 ${_('This repository does not have any remote url set')}
14 ${_('This repository does not have a remote url set.')}
15 </div>
15 </div>
16 %endif
16 %endif
@@ -1,164 +1,164 b''
1 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
1 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
2 <div class="form">
2 <div class="form">
3 <!-- fields -->
3 <!-- fields -->
4 <div class="fields">
4 <div class="fields">
5 <div class="field">
5 <div class="field">
6 <div class="label">
6 <div class="label">
7 <label for="repo_name">${_('Name')}:</label>
7 <label for="repo_name">${_('Name')}:</label>
8 </div>
8 </div>
9 <div class="input">
9 <div class="input">
10 ${h.text('repo_name',class_="medium")}
10 ${h.text('repo_name',class_="medium")}
11 <span class="help-block">${_('Non-changeable id')}: `_${c.repo_info.repo_id}` <span><a id="show_more_clone_id" href="#">${_('what is that ?')}</a></span></span>
11 <span class="help-block">${_('Non-changeable id')}: `_${c.repo_info.repo_id}` <span><a id="show_more_clone_id" href="#">${_('What is that?')}</a></span></span>
12 <span id="clone_id" class="help-block" style="display: none">
12 <span id="clone_id" class="help-block" style="display: none">
13 ${_('URL by id')}: `${c.repo_info.clone_url(with_id=True)}` </br>
13 ${_('URL by id')}: `${c.repo_info.clone_url(with_id=True)}` </br>
14 ${_('''In case this repository is renamed or moved into another group the repository url changes.
14 ${_('''In case this repository is renamed or moved into another group the repository url changes.
15 Using above url guarantees that this repository will allways be accessible under such url.
15 Using the above url guarantees that this repository will allways be accessible under such url.
16 Usefull for CI systems, or any other cases that you need to hardcode the url into 3rd party service.''')}</span>
16 Usefull for CI systems, or any other cases that you need to hardcode the url into 3rd party service.''')}</span>
17 </div>
17 </div>
18 </div>
18 </div>
19 <div class="field">
19 <div class="field">
20 <div class="label">
20 <div class="label">
21 <label for="clone_uri">${_('Clone uri')}:</label>
21 <label for="clone_uri">${_('Clone uri')}:</label>
22 </div>
22 </div>
23 <div class="input">
23 <div class="input">
24 %if c.repo_info.clone_uri:
24 %if c.repo_info.clone_uri:
25 <div id="clone_uri_hidden" style="font-size: 14px">
25 <div id="clone_uri_hidden" style="font-size: 14px">
26 <span id="clone_uri_hidden_value">${c.repo_info.clone_uri_hidden}</span>
26 <span id="clone_uri_hidden_value">${c.repo_info.clone_uri_hidden}</span>
27 <span style="cursor: pointer; padding: 0px 0px 5px 0px" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
27 <span style="cursor: pointer; padding: 0px 0px 5px 0px" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
28 </div>
28 </div>
29 <div id="alter_clone_uri" style="display: none">
29 <div id="alter_clone_uri" style="display: none">
30 ${h.text('clone_uri',class_="medium", placeholder=_('new value'))}
30 ${h.text('clone_uri',class_="medium", placeholder=_('new value'))}
31 </div>
31 </div>
32 %else:
32 %else:
33 ## not set yet, display form to set it
33 ## not set yet, display form to set it
34 ${h.text('clone_uri',class_="medium")}
34 ${h.text('clone_uri',class_="medium")}
35 ${h.hidden('clone_uri_change', 'NEW')}
35 ${h.hidden('clone_uri_change', 'NEW')}
36 %endif
36 %endif
37 <span id="alter_clone_uri_help_block" class="help-block">${_('http[s] url used for doing remote pulls.')}</span>
37 <span id="alter_clone_uri_help_block" class="help-block">${_('http[s] url used for doing remote pulls.')}</span>
38 </div>
38 </div>
39 </div>
39 </div>
40 <div class="field">
40 <div class="field">
41 <div class="label">
41 <div class="label">
42 <label for="repo_group">${_('Repository group')}:</label>
42 <label for="repo_group">${_('Repository group')}:</label>
43 </div>
43 </div>
44 <div class="input">
44 <div class="input">
45 ${h.select('repo_group','',c.repo_groups,class_="medium")}
45 ${h.select('repo_group','',c.repo_groups,class_="medium")}
46 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
46 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
47 </div>
47 </div>
48 </div>
48 </div>
49 <div class="field">
49 <div class="field">
50 <div class="label">
50 <div class="label">
51 <label for="repo_landing_rev">${_('Landing revision')}:</label>
51 <label for="repo_landing_rev">${_('Landing revision')}:</label>
52 </div>
52 </div>
53 <div class="input">
53 <div class="input">
54 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
54 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
55 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
55 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
56 </div>
56 </div>
57 </div>
57 </div>
58 <div class="field">
58 <div class="field">
59 <div class="label">
59 <div class="label">
60 <label for="user">${_('Owner')}:</label>
60 <label for="user">${_('Owner')}:</label>
61 </div>
61 </div>
62 <div class="input input-medium ac">
62 <div class="input input-medium ac">
63 <div class="perm_ac">
63 <div class="perm_ac">
64 ${h.text('user',class_='yui-ac-input')}
64 ${h.text('user',class_='yui-ac-input')}
65 <span class="help-block">${_('Change owner of this repository.')}</span>
65 <span class="help-block">${_('Change owner of this repository.')}</span>
66 <div id="owner_container"></div>
66 <div id="owner_container"></div>
67 </div>
67 </div>
68 </div>
68 </div>
69 </div>
69 </div>
70 <div class="field">
70 <div class="field">
71 <div class="label label-textarea">
71 <div class="label label-textarea">
72 <label for="repo_description">${_('Description')}:</label>
72 <label for="repo_description">${_('Description')}:</label>
73 </div>
73 </div>
74 <div class="textarea text-area editor">
74 <div class="textarea text-area editor">
75 ${h.textarea('repo_description', style="height:165px")}
75 ${h.textarea('repo_description', style="height:165px")}
76 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
76 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
77 </div>
77 </div>
78 </div>
78 </div>
79
79
80 <div class="field">
80 <div class="field">
81 <div class="label label-checkbox">
81 <div class="label label-checkbox">
82 <label for="repo_private">${_('Private repository')}:</label>
82 <label for="repo_private">${_('Private repository')}:</label>
83 </div>
83 </div>
84 <div class="checkboxes">
84 <div class="checkboxes">
85 ${h.checkbox('repo_private',value="True")}
85 ${h.checkbox('repo_private',value="True")}
86 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
86 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
87 </div>
87 </div>
88 </div>
88 </div>
89 <div class="field">
89 <div class="field">
90 <div class="label label-checkbox">
90 <div class="label label-checkbox">
91 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
91 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
92 </div>
92 </div>
93 <div class="checkboxes">
93 <div class="checkboxes">
94 ${h.checkbox('repo_enable_statistics',value="True")}
94 ${h.checkbox('repo_enable_statistics',value="True")}
95 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
95 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
96 </div>
96 </div>
97 </div>
97 </div>
98 <div class="field">
98 <div class="field">
99 <div class="label label-checkbox">
99 <div class="label label-checkbox">
100 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
100 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
101 </div>
101 </div>
102 <div class="checkboxes">
102 <div class="checkboxes">
103 ${h.checkbox('repo_enable_downloads',value="True")}
103 ${h.checkbox('repo_enable_downloads',value="True")}
104 <span class="help-block">${_('Enable download menu on summary page.')}</span>
104 <span class="help-block">${_('Enable download menu on summary page.')}</span>
105 </div>
105 </div>
106 </div>
106 </div>
107 <div class="field">
107 <div class="field">
108 <div class="label label-checkbox">
108 <div class="label label-checkbox">
109 <label for="repo_enable_locking">${_('Enable locking')}:</label>
109 <label for="repo_enable_locking">${_('Enable locking')}:</label>
110 </div>
110 </div>
111 <div class="checkboxes">
111 <div class="checkboxes">
112 ${h.checkbox('repo_enable_locking',value="True")}
112 ${h.checkbox('repo_enable_locking',value="True")}
113 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
113 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
114 </div>
114 </div>
115 </div>
115 </div>
116
116
117 %if c.visual.repository_fields:
117 %if c.visual.repository_fields:
118 ## EXTRA FIELDS
118 ## EXTRA FIELDS
119 %for field in c.repo_fields:
119 %for field in c.repo_fields:
120 <div class="field">
120 <div class="field">
121 <div class="label">
121 <div class="label">
122 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
122 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
123 </div>
123 </div>
124 <div class="input input-medium">
124 <div class="input input-medium">
125 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
125 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
126 %if field.field_desc:
126 %if field.field_desc:
127 <span class="help-block">${field.field_desc}</span>
127 <span class="help-block">${field.field_desc}</span>
128 %endif
128 %endif
129 </div>
129 </div>
130 </div>
130 </div>
131 %endfor
131 %endfor
132 %endif
132 %endif
133 <div class="buttons">
133 <div class="buttons">
134 ${h.submit('save',_('Save'),class_="btn")}
134 ${h.submit('save',_('Save'),class_="btn")}
135 ${h.reset('reset',_('Reset'),class_="btn")}
135 ${h.reset('reset',_('Reset'),class_="btn")}
136 </div>
136 </div>
137 </div>
137 </div>
138 </div>
138 </div>
139 ${h.end_form()}
139 ${h.end_form()}
140
140
141 <script>
141 <script>
142 $(document).ready(function(){
142 $(document).ready(function(){
143 $('#show_more_clone_id').on('click', function(e){
143 $('#show_more_clone_id').on('click', function(e){
144 $('#clone_id').show();
144 $('#clone_id').show();
145 e.preventDefault();
145 e.preventDefault();
146 })
146 })
147 $('#edit_clone_uri').on('click', function(e){
147 $('#edit_clone_uri').on('click', function(e){
148 $('#alter_clone_uri').show();
148 $('#alter_clone_uri').show();
149 $('#edit_clone_uri').hide();
149 $('#edit_clone_uri').hide();
150 $('#clone_uri_hidden').hide();
150 $('#clone_uri_hidden').hide();
151 ## store hash of old value for change detection
151 ## store hash of old value for change detection
152 var uri_change = '<input id="clone_uri_change" name="clone_uri_change" type="hidden" value="${h.md5(c.repo_info.clone_uri or "").hexdigest()}" />';
152 var uri_change = '<input id="clone_uri_change" name="clone_uri_change" type="hidden" value="${h.md5(c.repo_info.clone_uri or "").hexdigest()}" />';
153 $('#alter_clone_uri_help_block').html($('#alter_clone_uri_help_block').html()+" ("+$('#clone_uri_hidden_value').html()+")")
153 $('#alter_clone_uri_help_block').html($('#alter_clone_uri_help_block').html()+" ("+$('#clone_uri_hidden_value').html()+")")
154 })
154 })
155
155
156 $('#repo_landing_rev').select2({
156 $('#repo_landing_rev').select2({
157 'dropdownAutoWidth': true
157 'dropdownAutoWidth': true
158 });
158 });
159 $('#repo_group').select2({
159 $('#repo_group').select2({
160 'dropdownAutoWidth': true
160 'dropdownAutoWidth': true
161 });
161 });
162
162
163 })
163 })
164 </script>
164 </script>
@@ -1,13 +1,13 b''
1 ${h.form(url('edit_repo_statistics', repo_name=c.repo_info.repo_name), method='put')}
1 ${h.form(url('edit_repo_statistics', repo_name=c.repo_info.repo_name), method='put')}
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 <div class="field" style="border:none;color:#888">
4 <div class="field" style="border:none;color:#888">
5 <ul>
5 <ul>
6 <li>${_('Processed commits')}: ${c.stats_revision}/${c.repo_last_rev}</li>
6 <li>${_('Processed commits')}: ${c.stats_revision}/${c.repo_last_rev}</li>
7 <li>${_('Processed progress')}: ${c.stats_percentage}%</li>
7 <li>${_('Processed progress')}: ${c.stats_percentage}%</li>
8 </ul>
8 </ul>
9 </div>
9 </div>
10 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset statistics'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
10 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset Statistics'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to remove current statistics.')+"');")}
11 </div>
11 </div>
12 </div>
12 </div>
13 ${h.end_form()}
13 ${h.end_form()}
@@ -1,62 +1,62 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Repositories administration')}
5 ${_('Repositories Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_count">0</span> ${_('repositories')}
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_count">0</span> ${_('Repositories')}
13 </%def>
13 </%def>
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('admin')}
15 ${self.menu('admin')}
16 </%def>
16 </%def>
17 <%def name="main()">
17 <%def name="main()">
18 <div class="box">
18 <div class="box">
19
19
20 <div class="title">
20 <div class="title">
21 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
22 <ul class="links">
22 <ul class="links">
23 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
23 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
24 <li>
24 <li>
25 <a href="${h.url('new_repo')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Repository')}</a>
25 <a href="${h.url('new_repo')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add Repository')}</a>
26 </li>
26 </li>
27 %endif
27 %endif
28 </ul>
28 </ul>
29 </div>
29 </div>
30 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
30 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
31 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
31 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
32
32
33
33
34 </div>
34 </div>
35 <script>
35 <script>
36 var data = ${c.data|n};
36 var data = ${c.data|n};
37 var fields = [
37 var fields = [
38 {key:"menu"},
38 {key:"menu"},
39 {key:"raw_name"},
39 {key:"raw_name"},
40 {key:"name"},
40 {key:"name"},
41 {key:"desc"},
41 {key:"desc"},
42 {key:"last_changeset"},
42 {key:"last_changeset"},
43 {key:"last_rev_raw"},
43 {key:"last_rev_raw"},
44 {key:"owner"},
44 {key:"owner"},
45 {key:"state"},
45 {key:"state"},
46 {key:"action"}
46 {key:"action"}
47 ];
47 ];
48 var column_defs = [
48 var column_defs = [
49 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
49 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
50 {key:"name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
50 {key:"name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
51 {key:"desc",label:"${_('Description')}",sortable:true},
51 {key:"desc",label:"${_('Description')}",sortable:true},
52 {key:"last_changeset",label:"${_('Tip')}",sortable:true, sortOptions: { sortFunction: revisionSort }},
52 {key:"last_changeset",label:"${_('Tip')}",sortable:true, sortOptions: { sortFunction: revisionSort }},
53 {key:"owner",label:"${_('Owner')}",sortable:true},
53 {key:"owner",label:"${_('Owner')}",sortable:true},
54 {key:"state",label:"${_('State')}",sortable:true},
54 {key:"state",label:"${_('State')}",sortable:true},
55 {key:"action",label:"${_('Action')}",sortable:false}
55 {key:"action",label:"${_('Action')}",sortable:false}
56 ];
56 ];
57 var counter = YUD.get('repo_count');
57 var counter = YUD.get('repo_count');
58 var sort_key = "name";
58 var sort_key = "name";
59 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
59 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
60 </script>
60 </script>
61
61
62 </%def>
62 </%def>
@@ -1,56 +1,56 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Settings administration')}
5 ${_('Settings Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${_('Settings')}
14 ${_('Settings')}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box" style="overflow:auto">
22 <div class="box" style="overflow:auto">
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26
26
27 ##main
27 ##main
28 <div style="width: 150px; float:left">
28 <div style="width: 150px; float:left">
29 <ul class="nav nav-pills nav-stacked">
29 <ul class="nav nav-pills nav-stacked">
30 <li>
30 <li>
31 <div class="gravatar_box" style="height: 26px">
31 <div class="gravatar_box" style="height: 26px">
32 <div class="gravatar" style="float: left">
32 <div class="gravatar" style="float: left">
33 <i class="icon-cog" style="font-size: 26px"></i>
33 <i class="icon-cog" style="font-size: 26px"></i>
34 </div>
34 </div>
35 <div style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left">
35 <div style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left">
36 <strong>${_('Settings')}</strong>
36 <strong>${_('Settings')}</strong>
37 </div>
37 </div>
38 </div>
38 </div>
39 </li>
39 </li>
40 <li class="${'active' if c.active=='vcs' else ''}"><a href="${h.url('admin_settings')}">${_('VCS')}</a></li>
40 <li class="${'active' if c.active=='vcs' else ''}"><a href="${h.url('admin_settings')}">${_('VCS')}</a></li>
41 <li class="${'active' if c.active=='mapping' else ''}"><a href="${h.url('admin_settings_mapping')}">${_('Remap and rescan')}</a></li>
41 <li class="${'active' if c.active=='mapping' else ''}"><a href="${h.url('admin_settings_mapping')}">${_('Remap and Rescan')}</a></li>
42 <li class="${'active' if c.active=='global' else ''}"><a href="${h.url('admin_settings_global')}">${_('Global')}</a></li>
42 <li class="${'active' if c.active=='global' else ''}"><a href="${h.url('admin_settings_global')}">${_('Global')}</a></li>
43 <li class="${'active' if c.active=='visual' else ''}"><a href="${h.url('admin_settings_visual')}">${_('Visual')}</a></li>
43 <li class="${'active' if c.active=='visual' else ''}"><a href="${h.url('admin_settings_visual')}">${_('Visual')}</a></li>
44 <li class="${'active' if c.active=='email' else ''}"><a href="${h.url('admin_settings_email')}">${_('Email')}</a></li>
44 <li class="${'active' if c.active=='email' else ''}"><a href="${h.url('admin_settings_email')}">${_('Email')}</a></li>
45 <li class="${'active' if c.active=='hooks' else ''}"><a href="${h.url('admin_settings_hooks')}">${_('Hooks')}</a></li>
45 <li class="${'active' if c.active=='hooks' else ''}"><a href="${h.url('admin_settings_hooks')}">${_('Hooks')}</a></li>
46 <li class="${'active' if c.active=='search' else ''}"><a href="${h.url('admin_settings_search')}">${_('Full text search')}</a></li>
46 <li class="${'active' if c.active=='search' else ''}"><a href="${h.url('admin_settings_search')}">${_('Full Text Search')}</a></li>
47 <li class="${'active' if c.active=='system' else ''}"><a href="${h.url('admin_settings_system')}">${_('System Info')}</a></li>
47 <li class="${'active' if c.active=='system' else ''}"><a href="${h.url('admin_settings_system')}">${_('System Info')}</a></li>
48 </ul>
48 </ul>
49 </div>
49 </div>
50
50
51 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
51 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
52 <%include file="/admin/settings/settings_${c.active}.html"/>
52 <%include file="/admin/settings/settings_${c.active}.html"/>
53 </div>
53 </div>
54 </div>
54 </div>
55
55
56 </%def>
56 </%def>
@@ -1,61 +1,61 b''
1 ${h.form(url('admin_settings_global'), method='post')}
1 ${h.form(url('admin_settings_global'), method='post')}
2 <div class="form">
2 <div class="form">
3
3
4 <div class="fields">
4 <div class="fields">
5
5
6 <div class="field">
6 <div class="field">
7 <div class="label">
7 <div class="label">
8 <label for="title">${_('Site branding')}:</label>
8 <label for="title">${_('Site branding')}:</label>
9 </div>
9 </div>
10 <div class="input">
10 <div class="input">
11 ${h.text('title',size=30)}
11 ${h.text('title',size=30)}
12 <span class="help-block">${_('Set a custom title for your Kallithea Service.')}</span>
12 <span class="help-block">${_('Set a custom title for your Kallithea Service.')}</span>
13 </div>
13 </div>
14 </div>
14 </div>
15
15
16 <div class="field">
16 <div class="field">
17 <div class="label">
17 <div class="label">
18 <label for="realm">${_('HTTP authentication realm')}:</label>
18 <label for="realm">${_('HTTP authentication realm')}:</label>
19 </div>
19 </div>
20 <div class="input">
20 <div class="input">
21 ${h.text('realm',size=30)}
21 ${h.text('realm',size=30)}
22 </div>
22 </div>
23 </div>
23 </div>
24
24
25 <div class="field">
25 <div class="field">
26 <div class="label">
26 <div class="label">
27 <label for="ga_code">${_('Analytics HTML block')}:</label>
27 <label for="ga_code">${_('Analytics HTML block')}:</label>
28 </div>
28 </div>
29 <div class="input">
29 <div class="input">
30 ${h.textarea('ga_code', cols=80, rows=10)}
30 ${h.textarea('ga_code', cols=80, rows=10)}
31 <span class="help-block">${_('HTML with JavaScript for web analytics systems like Google Analytics or Piwik. This will be added at the bottom of every page.')}</span>
31 <span class="help-block">${_('HTML with JavaScript for web analytics systems like Google Analytics or Piwik. This will be added at the bottom of every page.')}</span>
32 </div>
32 </div>
33 </div>
33 </div>
34
34
35 <div class="field">
35 <div class="field">
36 <div class="label">
36 <div class="label">
37 <label for="captcha_public_key">${_('ReCaptcha public key')}:</label>
37 <label for="captcha_public_key">${_('ReCaptcha public key')}:</label>
38 </div>
38 </div>
39 <div class="input">
39 <div class="input">
40 ${h.text('captcha_public_key',size=60)}
40 ${h.text('captcha_public_key',size=60)}
41 <span class="help-block">${_('Public key for reCaptcha system.')}</span>
41 <span class="help-block">${_('Public key for reCaptcha system.')}</span>
42 </div>
42 </div>
43 </div>
43 </div>
44
44
45 <div class="field">
45 <div class="field">
46 <div class="label">
46 <div class="label">
47 <label for="captcha_private_key">${_('ReCaptcha private key')}:</label>
47 <label for="captcha_private_key">${_('ReCaptcha private key')}:</label>
48 </div>
48 </div>
49 <div class="input">
49 <div class="input">
50 ${h.text('captcha_private_key',size=60)}
50 ${h.text('captcha_private_key',size=60)}
51 <span class="help-block">${_('Private key for reCaptcha system. Setting this value will enable captcha on registration')}</span>
51 <span class="help-block">${_('Private key for reCaptcha system. Setting this value will enable captcha on registration.')}</span>
52 </div>
52 </div>
53 </div>
53 </div>
54
54
55 <div class="buttons">
55 <div class="buttons">
56 ${h.submit('save',_('Save settings'),class_="btn")}
56 ${h.submit('save',_('Save Settings'),class_="btn")}
57 ${h.reset('reset',_('Reset'),class_="btn")}
57 ${h.reset('reset',_('Reset'),class_="btn")}
58 </div>
58 </div>
59 </div>
59 </div>
60 </div>
60 </div>
61 ${h.end_form()}
61 ${h.end_form()}
@@ -1,75 +1,75 b''
1 <h4>${_('Built in Mercurial hooks - read only')}</h4>
1 <h4>${_('Built-in Mercurial Hooks (Read-Only)')}</h4>
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 % for hook in c.hooks:
4 % for hook in c.hooks:
5 <div class="field">
5 <div class="field">
6 <div class="label label">
6 <div class="label label">
7 <label for="${hook.ui_key}">${hook.ui_key}</label>
7 <label for="${hook.ui_key}">${hook.ui_key}</label>
8 </div>
8 </div>
9 <div class="input" style="margin-left:280px">
9 <div class="input" style="margin-left:280px">
10 ${h.text(hook.ui_key,hook.ui_value,size=60,readonly="readonly")}
10 ${h.text(hook.ui_key,hook.ui_value,size=60,readonly="readonly")}
11 </div>
11 </div>
12 </div>
12 </div>
13 % endfor
13 % endfor
14 </div>
14 </div>
15 <span class="help-block">${_('Hooks can be used to trigger actions on certain events such as push / pull. They can trigger Python functions or external applications.')}</span>
15 <span class="help-block">${_('Hooks can be used to trigger actions on certain events such as push / pull. They can trigger Python functions or external applications.')}</span>
16 </div>
16 </div>
17
17
18 % if c.visual.allow_custom_hooks_settings:
18 % if c.visual.allow_custom_hooks_settings:
19 <h4>${_('Custom hooks')}</h4>
19 <h4>${_('Custom Hooks')}</h4>
20 ${h.form(url('admin_settings_hooks'), method='post')}
20 ${h.form(url('admin_settings_hooks'), method='post')}
21 <div class="form">
21 <div class="form">
22 <div class="fields">
22 <div class="fields">
23
23
24 % for hook in c.custom_hooks:
24 % for hook in c.custom_hooks:
25 <div class="field" id="${'id%s' % hook.ui_id }">
25 <div class="field" id="${'id%s' % hook.ui_id }">
26 <div class="label label">
26 <div class="label label">
27 <label for="${hook.ui_key}">${hook.ui_key}</label>
27 <label for="${hook.ui_key}">${hook.ui_key}</label>
28 </div>
28 </div>
29 <div class="input" style="margin-left:280px">
29 <div class="input" style="margin-left:280px">
30 ${h.hidden('hook_ui_key',hook.ui_key)}
30 ${h.hidden('hook_ui_key',hook.ui_key)}
31 ${h.hidden('hook_ui_value',hook.ui_value)}
31 ${h.hidden('hook_ui_value',hook.ui_value)}
32 ${h.text('hook_ui_value_new',hook.ui_value,size=60)}
32 ${h.text('hook_ui_value_new',hook.ui_value,size=60)}
33 <span class="action_button"
33 <span class="action_button"
34 onclick="ajaxActionHook(${hook.ui_id},'${'id%s' % hook.ui_id }')">
34 onclick="ajaxActionHook(${hook.ui_id},'${'id%s' % hook.ui_id }')">
35 <i class="icon-remove-sign" style="color:#FF4444"></i>
35 <i class="icon-remove-sign" style="color:#FF4444"></i>
36 ${_('delete')}
36 ${_('delete')}
37 </span>
37 </span>
38 </div>
38 </div>
39 </div>
39 </div>
40 % endfor
40 % endfor
41
41
42 <div class="field">
42 <div class="field">
43 <div class="input" style="margin-left:-135px;position: absolute;">
43 <div class="input" style="margin-left:-135px;position: absolute;">
44 <div class="input">
44 <div class="input">
45 ${h.text('new_hook_ui_key',size=30)}
45 ${h.text('new_hook_ui_key',size=30)}
46 </div>
46 </div>
47 </div>
47 </div>
48 <div class="input" style="margin-left:280px">
48 <div class="input" style="margin-left:280px">
49 ${h.text('new_hook_ui_value',size=60)}
49 ${h.text('new_hook_ui_value',size=60)}
50 </div>
50 </div>
51 </div>
51 </div>
52 <div class="buttons" style="margin-left:280px">
52 <div class="buttons" style="margin-left:280px">
53 ${h.submit('save',_('Save'),class_="btn")}
53 ${h.submit('save',_('Save'),class_="btn")}
54 </div>
54 </div>
55 </div>
55 </div>
56 </div>
56 </div>
57 ${h.end_form()}
57 ${h.end_form()}
58 % endif
58 % endif
59
59
60 <script type="text/javascript">
60 <script type="text/javascript">
61 function ajaxActionHook(hook_id,field_id) {
61 function ajaxActionHook(hook_id,field_id) {
62 var sUrl = "${h.url('admin_settings_hooks')}";
62 var sUrl = "${h.url('admin_settings_hooks')}";
63 var callback = {
63 var callback = {
64 success: function (o) {
64 success: function (o) {
65 var elem = YUD.get(""+field_id);
65 var elem = YUD.get(""+field_id);
66 elem.parentNode.removeChild(elem);
66 elem.parentNode.removeChild(elem);
67 },
67 },
68 failure: function (o) {
68 failure: function (o) {
69 alert("${_('Failed to remove hook')}");
69 alert("${_('Failed to remove hook')}");
70 }
70 }
71 };
71 };
72 var postData = '_method=delete&hook_id=' + hook_id;
72 var postData = '_method=delete&hook_id=' + hook_id;
73 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
73 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
74 };
74 };
75 </script>
75 </script>
@@ -1,36 +1,36 b''
1 ${h.form(url('admin_settings_mapping'), method='post')}
1 ${h.form(url('admin_settings_mapping'), method='post')}
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 <div class="field">
4 <div class="field">
5 <div class="label label-checkbox">
5 <div class="label label-checkbox">
6 <label for="destroy">${_('Rescan option')}:</label>
6 <label for="destroy">${_('Rescan option')}:</label>
7 </div>
7 </div>
8 <div class="checkboxes">
8 <div class="checkboxes">
9 <div class="checkbox">
9 <div class="checkbox">
10 ${h.checkbox('destroy',True)}
10 ${h.checkbox('destroy',True)}
11 <label for="destroy">${_('Destroy old data')}</label>
11 <label for="destroy">${_('Destroy old data')}</label>
12 </div>
12 </div>
13 <span class="help-block">${_('In case a repository was deleted from filesystem and it still exists in the database check this option to scan obsolete data in database and remove it.')}</span>
13 <span class="help-block">${_('Check this option to remove references to repositories that no longer exist in on the filesystem.')}</span>
14
14
15 <div class="checkbox">
15 <div class="checkbox">
16 ${h.checkbox('invalidate',True)}
16 ${h.checkbox('invalidate',True)}
17 <label for="invalidate"> ${_('Invalidate cache for all repositories')}</label>
17 <label for="invalidate"> ${_('Invalidate cache for all repositories')}</label>
18 </div>
18 </div>
19 <span class="help-block">${_('Each cache data for repositories will be cleaned with this option selected. Use this to reload data and clear cache keys.')}</span>
19 <span class="help-block">${_('Check this to reload data and clear cache keys for all repositories.')}</span>
20
20
21 <div class="checkbox">
21 <div class="checkbox">
22 ${h.checkbox('hooks',True)}
22 ${h.checkbox('hooks',True)}
23 <label for="hooks"> ${_('Install GIT hooks')} </label>
23 <label for="hooks"> ${_('Install Git hooks')} </label>
24 </div>
24 </div>
25 <span class="help-block">${_('Verify if Kallitheas GIT hooks are installed for each repository. Current hooks will be updated to latest version')}</span>
25 <span class="help-block">${_("Verify if Kallithea's Git hooks are installed for each repository. Current hooks will be updated to the latest version.")}</span>
26 </div>
26 </div>
27
27
28 </div>
28 </div>
29 </div>
29 </div>
30
30
31 <div class="buttons">
31 <div class="buttons">
32 ${h.submit('rescan',_('Rescan Repositories'),class_="btn")}
32 ${h.submit('rescan',_('Rescan Repositories'),class_="btn")}
33 </div>
33 </div>
34 </div>
34 </div>
35 </div>
35 </div>
36 ${h.end_form()}
36 ${h.end_form()}
@@ -1,25 +1,25 b''
1 ${h.form(url('admin_settings_search'), method='post')}
1 ${h.form(url('admin_settings_search'), method='post')}
2 <div class="form">
2 <div class="form">
3
3
4 <div class="fields">
4 <div class="fields">
5 <div class="field">
5 <div class="field">
6 <div class="label label-checkbox">
6 <div class="label label-checkbox">
7 <label>${_('Index build option')}:</label>
7 <label>${_('Index build option')}:</label>
8 </div>
8 </div>
9 <div class="checkboxes">
9 <div class="checkboxes">
10 <div class="checkbox">
10 <div class="checkbox">
11 ${h.checkbox('full_index',True)}
11 ${h.checkbox('full_index',True)}
12 <label for="full_index">${_('Build from scratch')}</label>
12 <label for="full_index">${_('Build from scratch')}</label>
13
13
14 </div>
14 </div>
15 <span class="help-block">${_('This option completely reindex all the files within Kallithea for proper fulltext search capabilities.')}</span>
15 <span class="help-block">${_('This option completely reindexes all of the repositories for proper fulltext search capabilities.')}</span>
16
16
17 </div>
17 </div>
18 </div>
18 </div>
19
19
20 <div class="buttons">
20 <div class="buttons">
21 ${h.submit('reindex',_('Reindex'),class_="btn")}
21 ${h.submit('reindex',_('Reindex'),class_="btn")}
22 </div>
22 </div>
23 </div>
23 </div>
24 </div>
24 </div>
25 ${h.end_form()}
25 ${h.end_form()}
@@ -1,43 +1,43 b''
1 <dl class="dl-horizontal">
1 <dl class="dl-horizontal">
2 <%
2 <%
3 elems = [
3 elems = [
4 (_('Kallithea version'), h.literal('%s <b><span style="color:#036185; text-decoration: underline;cursor: pointer" id="check_for_update" >%s</span></b>' % (c.kallithea_version, _('check for updates'))), ''),
4 (_('Kallithea version'), h.literal('%s <b><span style="color:#036185; text-decoration: underline;cursor: pointer" id="check_for_update" >%s</span></b>' % (c.kallithea_version, _('check for updates'))), ''),
5 (_('Python version'), c.py_version, ''),
5 (_('Python version'), c.py_version, ''),
6 (_('Platform'), c.platform, ''),
6 (_('Platform'), c.platform, ''),
7 (_('GIT version'), c.git_version, ''),
7 (_('Git version'), c.git_version, ''),
8 (_('GIT path'), c.ini.get('git_path'), ''),
8 (_('Git path'), c.ini.get('git_path'), ''),
9 (_('Upgrade info endpoint'), h.literal('%s <br/><span style="color:#999999">%s.</span>' % (c.update_url, _('Note: please make sure this server can access this url'))), '')
9 (_('Upgrade info endpoint'), h.literal('%s <br/><span style="color:#999999">%s.</span>' % (c.update_url, _('Note: please make sure this server can access this url'))), '')
10 ]
10 ]
11 %>
11 %>
12
12
13 <div id="update_notice" style="display: none">
13 <div id="update_notice" style="display: none">
14 <div style="padding: 5px 0px 5px 0px; color: #000000; font-weight: bold">${_('Checking for updates...')}</div>
14 <div style="padding: 5px 0px 5px 0px; color: #000000; font-weight: bold">${_('Checking for updates...')}</div>
15 </div>
15 </div>
16 %for dt, dd, tt in elems:
16 %for dt, dd, tt in elems:
17 <dt style="width:150px; text-align: left">${dt}:</dt>
17 <dt style="width:150px; text-align: left">${dt}:</dt>
18 <dd style="margin-left: 160px" title="${tt}">${dd}</dd>
18 <dd style="margin-left: 160px" title="${tt}">${dd}</dd>
19 %endfor
19 %endfor
20 </dl>
20 </dl>
21
21
22 <h4>${_('Python packages')}</h4>
22 <h4>${_('Python Packages')}</h4>
23 <table class="table" style="margin:0px 0px 0px 0px">
23 <table class="table" style="margin:0px 0px 0px 0px">
24 <colgroup>
24 <colgroup>
25 <col style="width:180px">
25 <col style="width:180px">
26 </colgroup>
26 </colgroup>
27 <tbody>
27 <tbody>
28 %for key, value in c.modules:
28 %for key, value in c.modules:
29 <tr>
29 <tr>
30 <td style="padding-right:5px;">${key}</td>
30 <td style="padding-right:5px;">${key}</td>
31 <td>${value}</td>
31 <td>${value}</td>
32 </tr>
32 </tr>
33 %endfor
33 %endfor
34 </tbody>
34 </tbody>
35 </table>
35 </table>
36
36
37 <script>
37 <script>
38 $('#check_for_update').click(function(e){
38 $('#check_for_update').click(function(e){
39 var $update_notice = $('#update_notice');
39 var $update_notice = $('#update_notice');
40 $update_notice.show();
40 $update_notice.show();
41 asynchtml("${h.url('admin_settings_system_update')}", $update_notice);
41 asynchtml("${h.url('admin_settings_system_update')}", $update_notice);
42 });
42 });
43 </script>
43 </script>
@@ -1,96 +1,96 b''
1 ${h.form(url('admin_settings'), method='post')}
1 ${h.form(url('admin_settings'), method='post')}
2 <div class="form">
2 <div class="form">
3 <div class="fields">
3 <div class="fields">
4 <div class="field">
4 <div class="field">
5 <div class="label label-checkbox">
5 <div class="label label-checkbox">
6 <label>${_('Web')}:</label>
6 <label>${_('Web')}:</label>
7 </div>
7 </div>
8 <div class="checkboxes">
8 <div class="checkboxes">
9 <div class="checkbox">
9 <div class="checkbox">
10 ${h.checkbox('web_push_ssl', 'True')}
10 ${h.checkbox('web_push_ssl', 'True')}
11 <label for="web_push_ssl">${_('Require SSL for vcs operations')}</label>
11 <label for="web_push_ssl">${_('Require SSL for vcs operations')}</label>
12 </div>
12 </div>
13 <span class="help-block">${_('Activate to set Kallithea to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
13 <span class="help-block">${_('Activate to require SSL both pushing and pulling. If SSL certificate is missing, it will return a HTTP Error 406: Not Acceptable.')}</span>
14 </div>
14 </div>
15 </div>
15 </div>
16
16
17 <div class="field">
17 <div class="field">
18 <div class="label label-checkbox">
18 <div class="label label-checkbox">
19 <label>${_('Hooks')}:</label>
19 <label>${_('Hooks')}:</label>
20 </div>
20 </div>
21 <div class="checkboxes">
21 <div class="checkboxes">
22 <div class="checkbox">
22 <div class="checkbox">
23 ${h.checkbox('hooks_changegroup_repo_size','True')}
23 ${h.checkbox('hooks_changegroup_repo_size','True')}
24 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
24 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
25 </div>
25 </div>
26 <div class="checkbox">
26 <div class="checkbox">
27 ${h.checkbox('hooks_changegroup_push_logger','True')}
27 ${h.checkbox('hooks_changegroup_push_logger','True')}
28 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
28 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
29 </div>
29 </div>
30 <div class="checkbox">
30 <div class="checkbox">
31 ${h.checkbox('hooks_outgoing_pull_logger','True')}
31 ${h.checkbox('hooks_outgoing_pull_logger','True')}
32 <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
32 <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
33 </div>
33 </div>
34 <div class="checkbox">
34 <div class="checkbox">
35 ${h.checkbox('hooks_changegroup_update','True')}
35 ${h.checkbox('hooks_changegroup_update','True')}
36 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
36 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
37 </div>
37 </div>
38 </div>
38 </div>
39 </div>
39 </div>
40 <div class="field">
40 <div class="field">
41 <div class="label label-checkbox">
41 <div class="label label-checkbox">
42 <label>${_('Mercurial Extensions')}:</label>
42 <label>${_('Mercurial extensions')}:</label>
43 </div>
43 </div>
44 <div class="checkboxes">
44 <div class="checkboxes">
45 <div class="checkbox">
45 <div class="checkbox">
46 ${h.checkbox('extensions_largefiles','True')}
46 ${h.checkbox('extensions_largefiles','True')}
47 <label for="extensions_largefiles">${_('Enable largefiles extension')}</label>
47 <label for="extensions_largefiles">${_('Enable largefiles extension')}</label>
48 </div>
48 </div>
49 <div class="checkbox">
49 <div class="checkbox">
50 ${h.checkbox('extensions_hgsubversion','True')}
50 ${h.checkbox('extensions_hgsubversion','True')}
51 <label for="extensions_hgsubversion">${_('Enable hgsubversion extension')}</label>
51 <label for="extensions_hgsubversion">${_('Enable hgsubversion extension')}</label>
52 </div>
52 </div>
53 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
53 <span class="help-block">${_('Requires hgsubversion library to be installed. Enables cloning of remote Subversion repositories while converting them to Mercurial.')}</span>
54 ##<div class="checkbox">
54 ##<div class="checkbox">
55 ## ${h.checkbox('extensions_hggit','True')}
55 ## ${h.checkbox('extensions_hggit','True')}
56 ## <label for="extensions_hggit">${_('Enable hg-git extension')}</label>
56 ## <label for="extensions_hggit">${_('Enable hg-git extension')}</label>
57 ##</div>
57 ##</div>
58 ##<span class="help-block">${_('Requires hg-git library to be installed. Allows cloning remote git repositories and migrates them to Mercurial type.')}</span>
58 ##<span class="help-block">${_('Requires hg-git library to be installed. Enables cloning of remote Git repositories while converting them to Mercurial.')}</span>
59 </div>
59 </div>
60 </div>
60 </div>
61 %if c.visual.allow_repo_location_change:
61 %if c.visual.allow_repo_location_change:
62 <div class="field">
62 <div class="field">
63 <div class="label">
63 <div class="label">
64 <label for="paths_root_path">${_('Repositories location')}:</label>
64 <label for="paths_root_path">${_('Location of repositories')}:</label>
65 </div>
65 </div>
66 <div class="input">
66 <div class="input">
67 ${h.text('paths_root_path',size=60,readonly="readonly", class_="disabled")}
67 ${h.text('paths_root_path',size=60,readonly="readonly", class_="disabled")}
68 <span id="path_unlock" class="tooltip" style="cursor: pointer"
68 <span id="path_unlock" class="tooltip" style="cursor: pointer"
69 title="${h.tooltip(_('Click to unlock. You must restart Kallithea in order to make this setting take effect.'))}">
69 title="${h.tooltip(_('Click to unlock. You must restart Kallithea in order to make this setting take effect.'))}">
70 <div class="btn btn-small"><i id="path_unlock_icon" class="icon-lock"></i></div>
70 <div class="btn btn-small"><i id="path_unlock_icon" class="icon-lock"></i></div>
71 </span>
71 </span>
72 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
72 <span class="help-block">${_('Filesystem location where repositories are stored. After changing this value, a restart and rescan of the repository folder are both required.')}</span>
73 </div>
73 </div>
74 </div>
74 </div>
75 %else:
75 %else:
76 ## form still requires this but we cannot internally change it anyway
76 ## form still requires this but we cannot internally change it anyway
77 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
77 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
78 %endif
78 %endif
79 <div class="buttons">
79 <div class="buttons">
80 ${h.submit('save',_('Save settings'),class_="btn")}
80 ${h.submit('save',_('Save Settings'),class_="btn")}
81 ${h.reset('reset',_('Reset'),class_="btn")}
81 ${h.reset('reset',_('Reset'),class_="btn")}
82 </div>
82 </div>
83 </div>
83 </div>
84 </div>
84 </div>
85 ${h.end_form()}
85 ${h.end_form()}
86
86
87 <script type="text/javascript">
87 <script type="text/javascript">
88 $(document).ready(function(){
88 $(document).ready(function(){
89 $('#path_unlock').on('click', function(e){
89 $('#path_unlock').on('click', function(e){
90 $('#path_unlock_icon').removeClass('icon-lock');
90 $('#path_unlock_icon').removeClass('icon-lock');
91 $('#path_unlock_icon').addClass('icon-unlock');
91 $('#path_unlock_icon').addClass('icon-unlock');
92 $('#paths_root_path').removeAttr('readonly');
92 $('#paths_root_path').removeAttr('readonly');
93 $('#paths_root_path').removeClass('disabled');
93 $('#paths_root_path').removeClass('disabled');
94 })
94 })
95 })
95 })
96 </script>
96 </script>
@@ -1,121 +1,122 b''
1 ${h.form(url('admin_settings_visual'), method='post')}
1 ${h.form(url('admin_settings_visual'), method='post')}
2 <div class="form">
2 <div class="form">
3
3
4 <div class="fields">
4 <div class="fields">
5
5
6 <div class="field">
6 <div class="field">
7 <div class="label label-checkbox">
7 <div class="label label-checkbox">
8 <label>${_('General')}:</label>
8 <label>${_('General')}:</label>
9 </div>
9 </div>
10 <div class="checkboxes">
10 <div class="checkboxes">
11 <div class="checkbox">
11 <div class="checkbox">
12 ${h.checkbox('repository_fields','True')}
12 ${h.checkbox('repository_fields','True')}
13 <label for="repository_fields">${_('Use repository extra fields')}</label>
13 <label for="repository_fields">${_('Use repository extra fields')}</label>
14 </div>
14 </div>
15 <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span>
15 <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span>
16 <div class="checkbox">
16 <div class="checkbox">
17 ${h.checkbox('show_version','True')}
17 ${h.checkbox('show_version','True')}
18 <label for="show_version">${_('Show Kallithea version')}</label>
18 <label for="show_version">${_('Show Kallithea version')}</label>
19 </div>
19 </div>
20 <span class="help-block">${_('Shows or hides a version number of Kallithea displayed in the footer.')}</span>
20 <span class="help-block">${_('Shows or hides a version number of Kallithea displayed in the footer.')}</span>
21
21
22 <div class="checkbox">
22 <div class="checkbox">
23 ${h.checkbox('use_gravatar','True')}
23 ${h.checkbox('use_gravatar','True')}
24 <label for="use_gravatar">${_('Use Gravatars in Kallithea')}</label>
24 <label for="use_gravatar">${_('Use Gravatars in Kallithea')}</label>
25 </div>
25 </div>
26 </div>
26 </div>
27 <div class="field">
27 <div class="field">
28 <div class="input">
28 <div class="input">
29 ${h.text('gravatar_url', size=80)}
29 ${h.text('gravatar_url', size=80)}
30 <span class="help-block">${_('''Gravatar url allows you to use other avatar server application.
30 <span class="help-block">${_('''Gravatar url allows you to use another avatar server application.
31 Following variables of the URL will be replaced accordingly.
31 The following variables of the url will be replaced accordingly.
32 {scheme} 'http' or 'https' sent from running Kallithea server,
32 {scheme} 'http' or 'https' sent from running Kallithea server,
33 {email} user email,
33 {email} user email,
34 {md5email} md5 hash of the user email (like at gravatar.com),
34 {md5email} md5 hash of the user email (like at gravatar.com),
35 {size} size of the image that is expected from the server application,
35 {size} size of the image that is expected from the server application,
36 {netloc} network location/server host of running Kallithea server''')}</span>
36 {netloc} network location/server host of running Kallithea server''')}</span>
37 </div>
37 </div>
38 </div>
38 </div>
39 <div class="field">
39 <div class="field">
40 <div class="input">
40 <div class="input">
41 ${h.text('clone_uri_tmpl', size=80)}
41 ${h.text('clone_uri_tmpl', size=80)}
42 <span class="help-block">${_('''Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:
42 <span class="help-block">${_('''Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}'.
43 The following variables are available:
43 {scheme} 'http' or 'https' sent from running Kallithea server,
44 {scheme} 'http' or 'https' sent from running Kallithea server,
44 {user} current user username,
45 {user} current user username,
45 {netloc} network location/server host of running Kallithea server,
46 {netloc} network location/server host of running Kallithea server,
46 {repo} full repository name,
47 {repo} full repository name,
47 {repoid} ID of repository, can be used to contruct clone-by-id''')}</span>
48 {repoid} ID of repository, can be used to contruct clone-by-id''')}</span>
48 </div>
49 </div>
49 </div>
50 </div>
50 </div>
51 </div>
51
52
52 <div class="field">
53 <div class="field">
53 <div class="label">
54 <div class="label">
54 <label for="dashboard_items">${_('Dashboard items')}:</label>
55 <label for="dashboard_items">${_('Dashboard items')}:</label>
55 </div>
56 </div>
56 <div class="input">
57 <div class="input">
57 ${h.text('dashboard_items',size=5)}
58 ${h.text('dashboard_items',size=5)}
58 <span class="help-block">${_('Number of items displayed in the main page dashboard before pagination is shown.')}</span>
59 <span class="help-block">${_('Number of items displayed in the main page dashboard before pagination is shown.')}</span>
59 </div>
60 </div>
60 </div>
61 </div>
61
62
62 <div class="field">
63 <div class="field">
63 <div class="label">
64 <div class="label">
64 <label for="admin_grid_items">${_('Admin pages items')}:</label>
65 <label for="admin_grid_items">${_('Admin pages items')}:</label>
65 </div>
66 </div>
66 <div class="input">
67 <div class="input">
67 ${h.text('admin_grid_items',size=5)}
68 ${h.text('admin_grid_items',size=5)}
68 <span class="help-block">${_('Number of items displayed in the admin pages grids before pagination is shown.')}</span>
69 <span class="help-block">${_('Number of items displayed in the admin pages grids before pagination is shown.')}</span>
69 </div>
70 </div>
70 </div>
71 </div>
71
72
72 <div class="field">
73 <div class="field">
73 <div class="label label-checkbox">
74 <div class="label label-checkbox">
74 <label>${_('Icons')}:</label>
75 <label>${_('Icons')}:</label>
75 </div>
76 </div>
76 <div class="checkboxes">
77 <div class="checkboxes">
77 <div class="checkbox">
78 <div class="checkbox">
78 ${h.checkbox('show_public_icon','True')}
79 ${h.checkbox('show_public_icon','True')}
79 <label for="show_public_icon">${_('Show public repo icon on repositories')}</label>
80 <label for="show_public_icon">${_('Show public repo icon on repositories')}</label>
80 </div>
81 </div>
81 <div class="checkbox">
82 <div class="checkbox">
82 ${h.checkbox('show_private_icon','True')}
83 ${h.checkbox('show_private_icon','True')}
83 <label for="show_private_icon">${_('Show private repo icon on repositories')}</label>
84 <label for="show_private_icon">${_('Show private repo icon on repositories')}</label>
84 </div>
85 </div>
85 <span class="help-block">${_('Show public/private icons next to repositories names.')}</span>
86 <span class="help-block">${_('Show public/private icons next to repository names.')}</span>
86 </div>
87 </div>
87 </div>
88 </div>
88
89
89 <div class="field">
90 <div class="field">
90 <div class="label label-checkbox">
91 <div class="label label-checkbox">
91 <label>${_('Meta-Tagging')}:</label>
92 <label>${_('Meta-Tagging')}:</label>
92 </div>
93 </div>
93 <div class="checkboxes">
94 <div class="checkboxes">
94 <div class="checkbox">
95 <div class="checkbox">
95 ${h.checkbox('stylify_metatags','True')}
96 ${h.checkbox('stylify_metatags','True')}
96 <label for="stylify_metatags">${_('Stylify recognised meta tags:')}</label>
97 <label for="stylify_metatags">${_('Stylify recognised meta tags:')}</label>
97 </div>
98 </div>
98 <div style="padding-left: 20px;">
99 <div style="padding-left: 20px;">
99 <ul> <!-- Fix style here -->
100 <ul> <!-- Fix style here -->
100 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
101 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
101 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
102 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
102 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
103 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
103 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
104 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
104 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
105 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
105 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
106 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
106 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
107 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
107 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
108 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
108 </ul>
109 </ul>
109 </div>
110 </div>
110 <span class="help-block">${_('Parses meta tags from repository description field and turns them into colored tags.')}</span>
111 <span class="help-block">${_('Parses meta tags from the repository description field and turns them into colored tags.')}</span>
111 </div>
112 </div>
112 </div>
113 </div>
113
114
114 <div class="buttons">
115 <div class="buttons">
115 ${h.submit('save',_('Save settings'),class_="btn")}
116 ${h.submit('save',_('Save Settings'),class_="btn")}
116 ${h.reset('reset',_('Reset'),class_="btn")}
117 ${h.reset('reset',_('Reset'),class_="btn")}
117 </div>
118 </div>
118
119
119 </div>
120 </div>
120 </div>
121 </div>
121 ${h.end_form()}
122 ${h.end_form()}
@@ -1,72 +1,72 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Add user group')}
5 ${_('Add user group')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10 <%def name="breadcrumbs_links()">
10 <%def name="breadcrumbs_links()">
11 ${h.link_to(_('Admin'),h.url('admin_home'))}
11 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 &raquo;
12 &raquo;
13 ${h.link_to(_('User groups'),h.url('users_groups'))}
13 ${h.link_to(_('User Groups'),h.url('users_groups'))}
14 &raquo;
14 &raquo;
15 ${_('Add User Group')}
15 ${_('Add User Group')}
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('admin')}
19 ${self.menu('admin')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28 <!-- end box / title -->
28 <!-- end box / title -->
29 ${h.form(url('users_groups'))}
29 ${h.form(url('users_groups'))}
30 <div class="form">
30 <div class="form">
31 <!-- fields -->
31 <!-- fields -->
32 <div class="fields">
32 <div class="fields">
33 <div class="field">
33 <div class="field">
34 <div class="label">
34 <div class="label">
35 <label for="users_group_name">${_('Group name')}:</label>
35 <label for="users_group_name">${_('Group name')}:</label>
36 </div>
36 </div>
37 <div class="input">
37 <div class="input">
38 ${h.text('users_group_name',class_='small')}
38 ${h.text('users_group_name',class_='small')}
39 </div>
39 </div>
40 </div>
40 </div>
41 <div class="field">
41 <div class="field">
42 <div class="label label-textarea">
42 <div class="label label-textarea">
43 <label for="user_group_description">${_('Description')}:</label>
43 <label for="user_group_description">${_('Description')}:</label>
44 </div>
44 </div>
45 <div class="textarea text-area editor">
45 <div class="textarea text-area editor">
46 ${h.textarea('user_group_description')}
46 ${h.textarea('user_group_description')}
47 <span class="help-block">${_('Short, optional description for this user group.')}</span>
47 <span class="help-block">${_('Short, optional description for this user group.')}</span>
48 </div>
48 </div>
49 </div>
49 </div>
50 <div class="field">
50 <div class="field">
51 <div class="label label-checkbox">
51 <div class="label label-checkbox">
52 <label for="users_group_active">${_('Active')}:</label>
52 <label for="users_group_active">${_('Active')}:</label>
53 </div>
53 </div>
54 <div class="checkboxes">
54 <div class="checkboxes">
55 ${h.checkbox('users_group_active',value=True, checked='checked')}
55 ${h.checkbox('users_group_active',value=True, checked='checked')}
56 </div>
56 </div>
57 </div>
57 </div>
58
58
59 <div class="buttons">
59 <div class="buttons">
60 ${h.submit('save',_('Save'),class_="btn")}
60 ${h.submit('save',_('Save'),class_="btn")}
61 </div>
61 </div>
62 </div>
62 </div>
63 </div>
63 </div>
64 ${h.end_form()}
64 ${h.end_form()}
65 </div>
65 </div>
66 </%def>
66 </%def>
67
67
68 <script>
68 <script>
69 $(document).ready(function(){
69 $(document).ready(function(){
70 $('#users_group_name').focus();
70 $('#users_group_name').focus();
71 })
71 })
72 </script>
72 </script>
@@ -1,60 +1,60 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('User groups administration')}
5 ${_('User Groups Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_group_count">0</span> ${_('user groups')}
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_group_count">0</span> ${_('user groups')}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 <ul class="links">
25 <ul class="links">
26 %if h.HasPermissionAny('hg.admin', 'hg.usergroup.create.true')():
26 %if h.HasPermissionAny('hg.admin', 'hg.usergroup.create.true')():
27 <li>
27 <li>
28 <a href="${h.url('new_users_group')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add User Group')}</a>
28 <a href="${h.url('new_users_group')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add User Group')}</a>
29 </li>
29 </li>
30 %endif
30 %endif
31 </ul>
31 </ul>
32 </div>
32 </div>
33 <!-- end box / title -->
33 <!-- end box / title -->
34 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
34 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
35 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
35 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
36 </div>
36 </div>
37 <script>
37 <script>
38 var data = ${c.data|n};
38 var data = ${c.data|n};
39 var fields = [
39 var fields = [
40 {key: "group_name"},
40 {key: "group_name"},
41 {key: "raw_name"},
41 {key: "raw_name"},
42 {key: "desc"},
42 {key: "desc"},
43 {key: "members"},
43 {key: "members"},
44 {key: "active"},
44 {key: "active"},
45 {key: "owner"},
45 {key: "owner"},
46 {key: "action"}
46 {key: "action"}
47 ];
47 ];
48 var column_defs = [
48 var column_defs = [
49 {key:"group_name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
49 {key:"group_name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: nameSort }},
50 {key:"desc",label:"${_('Description')}",sortable:true},
50 {key:"desc",label:"${_('Description')}",sortable:true},
51 {key:"members",label:"${_('Members')}",sortable:false},
51 {key:"members",label:"${_('Members')}",sortable:false},
52 {key:"active",label:"${_('Active')}",sortable:true},
52 {key:"active",label:"${_('Active')}",sortable:true},
53 {key:"owner",label:"${_('Owner')}",sortable:true},
53 {key:"owner",label:"${_('Owner')}",sortable:true},
54 {key:"action",label:"${_('Action')}",sortable:false}
54 {key:"action",label:"${_('Action')}",sortable:false}
55 ];
55 ];
56 var counter = YUD.get('user_group_count');
56 var counter = YUD.get('user_group_count');
57 var sort_key = "group_name";
57 var sort_key = "group_name";
58 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
58 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
59 </script>
59 </script>
60 </%def>
60 </%def>
@@ -1,56 +1,56 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s user settings') % c.user.username}
5 ${_('%s user settings') % c.user.username}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
12 ${h.link_to(_('Admin'),h.url('admin_home'))}
13 &raquo;
13 &raquo;
14 ${h.link_to(_('Users'),h.url('users'))}
14 ${h.link_to(_('Users'),h.url('users'))}
15 &raquo;
15 &raquo;
16 ${c.user.username}
16 ${c.user.username}
17 </%def>
17 </%def>
18
18
19 <%def name="page_nav()">
19 <%def name="page_nav()">
20 ${self.menu('admin')}
20 ${self.menu('admin')}
21 </%def>
21 </%def>
22
22
23 <%def name="main()">
23 <%def name="main()">
24 <div class="box" style="overflow:auto">
24 <div class="box" style="overflow:auto">
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28
28
29 ##main
29 ##main
30 <div style="width: 150px; float:left">
30 <div style="width: 150px; float:left">
31 <ul class="nav nav-pills nav-stacked">
31 <ul class="nav nav-pills nav-stacked">
32 <li>
32 <li>
33 <div class="gravatar_box" style="height: 26px">
33 <div class="gravatar_box" style="height: 26px">
34 <div class="gravatar" style="float: left">
34 <div class="gravatar" style="float: left">
35 <img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/>
35 <img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/>
36 </div>
36 </div>
37 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
37 <div class="truncate" style="margin:10px 0px 10px 0px; color:#5f5f5f; float:left; width: 100px">
38 <strong>${c.user.username}</strong>
38 <strong>${c.user.username}</strong>
39 </div>
39 </div>
40 </div>
40 </div>
41 </li>
41 </li>
42 <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('edit_user', id=c.user.user_id)}">${_('Profile')}</a></li>
42 <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('edit_user', id=c.user.user_id)}">${_('Profile')}</a></li>
43 <li class="${'active' if c.active=='api_keys' else ''}"><a href="${h.url('edit_user_api_keys', id=c.user.user_id)}">${_('API keys')}</a></li>
43 <li class="${'active' if c.active=='api_keys' else ''}"><a href="${h.url('edit_user_api_keys', id=c.user.user_id)}">${_('API Keys')}</a></li>
44 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_advanced', id=c.user.user_id)}">${_('Advanced')}</a></li>
44 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_advanced', id=c.user.user_id)}">${_('Advanced')}</a></li>
45 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_user_perms', id=c.user.user_id)}">${_('Default permissions')}</a></li>
45 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_user_perms', id=c.user.user_id)}">${_('Default Permissions')}</a></li>
46 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('edit_user_emails', id=c.user.user_id)}">${_('Emails')}</a></li>
46 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('edit_user_emails', id=c.user.user_id)}">${_('Emails')}</a></li>
47 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('edit_user_ips', id=c.user.user_id)}">${_('Ip whitelist')}</a></li>
47 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('edit_user_ips', id=c.user.user_id)}">${_('IP Whitelist')}</a></li>
48 </ul>
48 </ul>
49 </div>
49 </div>
50
50
51 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
51 <div style="width:750px; float:left; padding: 10px 0px 0px 20px;margin: 0px 0px 0px 10px; border-left: 1px solid #DDDDDD">
52 <%include file="/admin/users/user_edit_${c.active}.html"/>
52 <%include file="/admin/users/user_edit_${c.active}.html"/>
53 </div>
53 </div>
54 </div>
54 </div>
55
55
56 </%def>
56 </%def>
@@ -1,51 +1,51 b''
1 <div class="emails_wrap">
1 <div class="emails_wrap">
2 <table class="noborder">
2 <table class="noborder">
3 <tr>
3 <tr>
4 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email,16)}"/> </div></td>
4 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email,16)}"/> </div></td>
5 <td><div class="email">${c.user.email}</div></td>
5 <td><div class="email">${c.user.email}</div></td>
6 <td>
6 <td>
7 <span class="btn btn-mini btn-success disabled">${_('Primary')}</span>
7 <span class="btn btn-mini btn-success disabled">${_('Primary')}</span>
8 </td>
8 </td>
9 </tr>
9 </tr>
10 %if c.user_email_map:
10 %if c.user_email_map:
11 %for em in c.user_email_map:
11 %for em in c.user_email_map:
12 <tr>
12 <tr>
13 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.email,16)}"/> </div></td>
13 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.email,16)}"/> </div></td>
14 <td><div class="email">${em.email}</div></td>
14 <td><div class="email">${em.email}</div></td>
15 <td>
15 <td>
16 ${h.form(url('edit_user_emails', id=c.user.user_id),method='delete')}
16 ${h.form(url('edit_user_emails', id=c.user.user_id),method='delete')}
17 ${h.hidden('del_email_id',em.email_id)}
17 ${h.hidden('del_email_id',em.email_id)}
18 <i class="icon-remove-sign" style="color:#FF4444"></i>
18 <i class="icon-remove-sign" style="color:#FF4444"></i>
19 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
19 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
20 class_="action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
20 class_="action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
21 ${h.end_form()}
21 ${h.end_form()}
22 </td>
22 </td>
23 </tr>
23 </tr>
24 %endfor
24 %endfor
25 %else:
25 %else:
26 <tr><td><div class="ip">${_('No additional emails specified')}</div></td></tr>
26 <tr><td><div class="ip">${_('No additional emails specified.')}</div></td></tr>
27 %endif
27 %endif
28 </table>
28 </table>
29 </div>
29 </div>
30
30
31 <div>
31 <div>
32 ${h.form(url('edit_user_emails', id=c.user.user_id),method='put')}
32 ${h.form(url('edit_user_emails', id=c.user.user_id),method='put')}
33 <div class="form">
33 <div class="form">
34 <!-- fields -->
34 <!-- fields -->
35 <div class="fields">
35 <div class="fields">
36 <div class="field">
36 <div class="field">
37 <div class="label">
37 <div class="label">
38 <label for="new_email">${_('New email address')}:</label>
38 <label for="new_email">${_('New email address')}:</label>
39 </div>
39 </div>
40 <div class="input">
40 <div class="input">
41 ${h.text('new_email', class_='medium')}
41 ${h.text('new_email', class_='medium')}
42 </div>
42 </div>
43 </div>
43 </div>
44 <div class="buttons">
44 <div class="buttons">
45 ${h.submit('save',_('Add'),class_="btn")}
45 ${h.submit('save',_('Add'),class_="btn")}
46 ${h.reset('reset',_('Reset'),class_="btn")}
46 ${h.reset('reset',_('Reset'),class_="btn")}
47 </div>
47 </div>
48 </div>
48 </div>
49 </div>
49 </div>
50 ${h.end_form()}
50 ${h.end_form()}
51 </div>
51 </div>
@@ -1,55 +1,55 b''
1 <div class="ips_wrap">
1 <div class="ips_wrap">
2 <table class="noborder">
2 <table class="noborder">
3 %if c.default_user_ip_map and c.inherit_default_ips:
3 %if c.default_user_ip_map and c.inherit_default_ips:
4 %for ip in c.default_user_ip_map:
4 %for ip in c.default_user_ip_map:
5 <tr>
5 <tr>
6 <td><div class="ip">${ip.ip_addr}</div></td>
6 <td><div class="ip">${ip.ip_addr}</div></td>
7 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
7 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
8 <td>${h.literal(_('Inherited from %s') % h.link_to('*default*',h.url('admin_permissions_ips')))}</td>
8 <td>${h.literal(_('Inherited from %s') % h.link_to('*default*',h.url('admin_permissions_ips')))}</td>
9 </tr>
9 </tr>
10 %endfor
10 %endfor
11 %endif
11 %endif
12
12
13 %if c.user_ip_map:
13 %if c.user_ip_map:
14 %for ip in c.user_ip_map:
14 %for ip in c.user_ip_map:
15 <tr>
15 <tr>
16 <td><div class="ip">${ip.ip_addr}</div></td>
16 <td><div class="ip">${ip.ip_addr}</div></td>
17 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
17 <td><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
18 <td>
18 <td>
19 ${h.form(url('edit_user_ips', id=c.user.user_id),method='delete')}
19 ${h.form(url('edit_user_ips', id=c.user.user_id),method='delete')}
20 ${h.hidden('del_ip_id',ip.ip_id)}
20 ${h.hidden('del_ip_id',ip.ip_id)}
21 <i class="icon-remove-sign" style="color:#FF4444"></i>
21 <i class="icon-remove-sign" style="color:#FF4444"></i>
22 ${h.submit('remove_',_('delete'),id="remove_ip_%s" % ip.ip_id,
22 ${h.submit('remove_',_('delete'),id="remove_ip_%s" % ip.ip_id,
23 class_="action_button", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
23 class_="action_button", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
24 ${h.end_form()}
24 ${h.end_form()}
25 </td>
25 </td>
26 </tr>
26 </tr>
27 %endfor
27 %endfor
28 %endif
28 %endif
29 %if not c.default_user_ip_map and not c.user_ip_map:
29 %if not c.default_user_ip_map and not c.user_ip_map:
30 <tr><td><div class="ip">${_('All IP addresses are allowed')}</div></td></tr>
30 <tr><td><div class="ip">${_('All IP addresses are allowed.')}</div></td></tr>
31 %endif
31 %endif
32 </table>
32 </table>
33 </div>
33 </div>
34
34
35 <div>
35 <div>
36 ${h.form(url('edit_user_ips', id=c.user.user_id),method='put')}
36 ${h.form(url('edit_user_ips', id=c.user.user_id),method='put')}
37 <div class="form">
37 <div class="form">
38 <!-- fields -->
38 <!-- fields -->
39 <div class="fields">
39 <div class="fields">
40 <div class="field">
40 <div class="field">
41 <div class="label">
41 <div class="label">
42 <label for="new_ip">${_('New ip address')}:</label>
42 <label for="new_ip">${_('New ip address')}:</label>
43 </div>
43 </div>
44 <div class="input">
44 <div class="input">
45 ${h.text('new_ip', class_='medium')}
45 ${h.text('new_ip', class_='medium')}
46 </div>
46 </div>
47 </div>
47 </div>
48 <div class="buttons">
48 <div class="buttons">
49 ${h.submit('save',_('Add'),class_="btn")}
49 ${h.submit('save',_('Add'),class_="btn")}
50 ${h.reset('reset',_('Reset'),class_="btn")}
50 ${h.reset('reset',_('Reset'),class_="btn")}
51 </div>
51 </div>
52 </div>
52 </div>
53 </div>
53 </div>
54 ${h.end_form()}
54 ${h.end_form()}
55 </div>
55 </div>
@@ -1,67 +1,67 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Users administration')}
5 ${_('Users Administration')}
6 %if c.site_name:
6 %if c.site_name:
7 &middot; ${c.site_name}
7 &middot; ${c.site_name}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_count">0</span> ${_('users')}
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_count">0</span> ${_('Users')}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 <ul class="links">
25 <ul class="links">
26 <li>
26 <li>
27 <a href="${h.url('new_user')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add User')}</a>
27 <a href="${h.url('new_user')}" class="btn btn-small btn-success"><i class="icon-plus"></i> ${_(u'Add User')}</a>
28 </li>
28 </li>
29 </ul>
29 </ul>
30 </div>
30 </div>
31 <!-- end box / title -->
31 <!-- end box / title -->
32 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
32 <div class="table-grid table yui-skin-sam" id="datatable_list_wrap"></div>
33 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
33 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
34 </div>
34 </div>
35
35
36 <script>
36 <script>
37 var data = ${c.data|n};
37 var data = ${c.data|n};
38 var fields = [
38 var fields = [
39 {key: "gravatar"},
39 {key: "gravatar"},
40 {key: "raw_name"},
40 {key: "raw_name"},
41 {key: "username"},
41 {key: "username"},
42 {key: "firstname"},
42 {key: "firstname"},
43 {key: "lastname"},
43 {key: "lastname"},
44 {key: "last_login"},
44 {key: "last_login"},
45 {key: "last_login_raw"},
45 {key: "last_login_raw"},
46 {key: "active"},
46 {key: "active"},
47 {key: "admin"},
47 {key: "admin"},
48 {key: "extern_type"},
48 {key: "extern_type"},
49 {key: "action"}
49 {key: "action"}
50 ];
50 ];
51 var column_defs = [
51 var column_defs = [
52 {key:"gravatar",label:"",sortable:false},
52 {key:"gravatar",label:"",sortable:false},
53 {key:"username",label:"${_('Username')}",sortable:true},
53 {key:"username",label:"${_('Username')}",sortable:true},
54 {key:"firstname",label:"${_('Firstname')}",sortable:true},
54 {key:"firstname",label:"${_('First Name')}",sortable:true},
55 {key:"lastname",label:"${_('Lastname')}",sortable:true},
55 {key:"lastname",label:"${_('Last Name')}",sortable:true},
56 {key:"last_login",label:"${_('Last login')}",sortable:true, sortOptions: { sortFunction: lastLoginSort }},
56 {key:"last_login",label:"${_('Last Login')}",sortable:true, sortOptions: { sortFunction: lastLoginSort }},
57 {key:"active",label:"${_('Active')}",sortable:true},
57 {key:"active",label:"${_('Active')}",sortable:true},
58 {key:"admin",label:"${_('Admin')}",sortable:true},
58 {key:"admin",label:"${_('Admin')}",sortable:true},
59 {key:"extern_type",label:"${_('Auth type')}",sortable:true},
59 {key:"extern_type",label:"${_('Auth Type')}",sortable:true},
60 {key:"action",label:"${_('Action')}",sortable:false}
60 {key:"action",label:"${_('Action')}",sortable:false}
61 ];
61 ];
62 var counter = YUD.get('user_count');
62 var counter = YUD.get('user_count');
63 var sort_key = "username";
63 var sort_key = "username";
64 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
64 YUI_datatable(data, fields, column_defs, counter, sort_key, ${c.visual.admin_grid_items});
65 </script>
65 </script>
66
66
67 </%def>
67 </%def>
@@ -1,605 +1,605 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header">
5 <div id="header">
6 <div id="header-inner" class="title">
6 <div id="header-inner" class="title">
7 <div id="logo">
7 <div id="logo">
8 <a href="${h.url('home')}" style="display: block;">
8 <a href="${h.url('home')}" style="display: block;">
9 <div class="header">
9 <div class="header">
10 <img src="${h.url('/images/kallithea-logo.svg')}" onerror="this.src='${h.url('/images/kallithea-logo.png')}'" alt="Kallithea"/>
10 <img src="${h.url('/images/kallithea-logo.svg')}" onerror="this.src='${h.url('/images/kallithea-logo.png')}'" alt="Kallithea"/>
11 </div>
11 </div>
12 %if c.site_name:
12 %if c.site_name:
13 <div class="branding">${c.site_name}</div>
13 <div class="branding">${c.site_name}</div>
14 %endif
14 %endif
15 </a>
15 </a>
16 </div>
16 </div>
17 <!-- MENU -->
17 <!-- MENU -->
18 ${self.page_nav()}
18 ${self.page_nav()}
19 <!-- END MENU -->
19 <!-- END MENU -->
20 ${self.body()}
20 ${self.body()}
21 </div>
21 </div>
22 </div>
22 </div>
23 <!-- END HEADER -->
23 <!-- END HEADER -->
24
24
25 <!-- CONTENT -->
25 <!-- CONTENT -->
26 <div id="content">
26 <div id="content">
27 ${self.flash_msg()}
27 ${self.flash_msg()}
28 <div id="main">
28 <div id="main">
29 ${next.main()}
29 ${next.main()}
30 </div>
30 </div>
31 </div>
31 </div>
32 <!-- END CONTENT -->
32 <!-- END CONTENT -->
33
33
34 <!-- FOOTER -->
34 <!-- FOOTER -->
35 <div id="footer">
35 <div id="footer">
36 <div id="footer-inner" class="title">
36 <div id="footer-inner" class="title">
37 <div>
37 <div>
38 <p class="footer-link">
38 <p class="footer-link">
39 ${_('Server instance: %s') % c.instance_id if c.instance_id else ''}
39 ${_('Server instance: %s') % c.instance_id if c.instance_id else ''}
40 </p>
40 </p>
41 <p class="footer-link-right">
41 <p class="footer-link-right">
42 This site is powered by
42 This site is powered by
43 %if c.visual.show_version:
43 %if c.visual.show_version:
44 <a href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a> ${c.kallithea_version},
44 <a href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a> ${c.kallithea_version},
45 %else:
45 %else:
46 <a href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a>,
46 <a href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a>,
47 %endif
47 %endif
48 which is
48 which is
49 <a href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2014 by various authors &amp; licensed under GPLv3</a>.
49 <a href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2014 by various authors &amp; licensed under GPLv3</a>.
50 %if c.issues_url:
50 %if c.issues_url:
51 &ndash; <a href="${c.issues_url}" target="_blank">${_('Support')}</a>
51 &ndash; <a href="${c.issues_url}" target="_blank">${_('Support')}</a>
52 %endif
52 %endif
53 </p>
53 </p>
54 </div>
54 </div>
55 </div>
55 </div>
56 </div>
56 </div>
57
57
58 <!-- END FOOTER -->
58 <!-- END FOOTER -->
59
59
60 ### MAKO DEFS ###
60 ### MAKO DEFS ###
61
61
62 <%def name="flash_msg()">
62 <%def name="flash_msg()">
63 <%include file="/base/flash_msg.html"/>
63 <%include file="/base/flash_msg.html"/>
64 </%def>
64 </%def>
65
65
66 <%def name="breadcrumbs()">
66 <%def name="breadcrumbs()">
67 <div class="breadcrumbs">
67 <div class="breadcrumbs">
68 ${self.breadcrumbs_links()}
68 ${self.breadcrumbs_links()}
69 </div>
69 </div>
70 </%def>
70 </%def>
71
71
72 <%def name="admin_menu()">
72 <%def name="admin_menu()">
73 <ul class="admin_menu">
73 <ul class="admin_menu">
74 <li><a href="${h.url('admin_home')}"><i class="icon-book"></i> ${_('Admin journal')}</a></li>
74 <li><a href="${h.url('admin_home')}"><i class="icon-book"></i> ${_('Admin Journal')}</a></li>
75 <li><a href="${h.url('repos')}"><i class="icon-archive"></i> ${_('Repositories')}</a></li>
75 <li><a href="${h.url('repos')}"><i class="icon-archive"></i> ${_('Repositories')}</a></li>
76 <li><a href="${h.url('repos_groups')}"><i class="icon-folder-close"></i> ${_('Repository groups')}</a></li>
76 <li><a href="${h.url('repos_groups')}"><i class="icon-folder-close"></i> ${_('Repository Groups')}</a></li>
77 <li><a href="${h.url('users')}"><i class="icon-user"></i> ${_('Users')}</a></li>
77 <li><a href="${h.url('users')}"><i class="icon-user"></i> ${_('Users')}</a></li>
78 <li><a href="${h.url('users_groups')}"><i class="icon-group"></i> ${_('User groups')}</a></li>
78 <li><a href="${h.url('users_groups')}"><i class="icon-group"></i> ${_('User Groups')}</a></li>
79 <li><a href="${h.url('admin_permissions')}"><i class="icon-ban-circle"></i> ${_('Permissions')}</a></li>
79 <li><a href="${h.url('admin_permissions')}"><i class="icon-ban-circle"></i> ${_('Permissions')}</a></li>
80 <li><a href="${h.url('auth_home')}"><i class="icon-key"></i> ${_('Authentication')}</a></li>
80 <li><a href="${h.url('auth_home')}"><i class="icon-key"></i> ${_('Authentication')}</a></li>
81 <li><a href="${h.url('defaults')}"><i class="icon-wrench"></i> ${_('Defaults')}</a></li>
81 <li><a href="${h.url('defaults')}"><i class="icon-wrench"></i> ${_('Defaults')}</a></li>
82 <li class="last"><a href="${h.url('admin_settings')}"><i class="icon-cog"></i> ${_('Settings')}</a></li>
82 <li class="last"><a href="${h.url('admin_settings')}"><i class="icon-cog"></i> ${_('Settings')}</a></li>
83 </ul>
83 </ul>
84
84
85 </%def>
85 </%def>
86
86
87
87
88 ## admin menu used for people that have some admin resources
88 ## admin menu used for people that have some admin resources
89 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
89 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
90 <ul>
90 <ul>
91 %if repositories:
91 %if repositories:
92 <li><a href="${h.url('repos')}"><i class="icon-archive"></i> ${_('Repositories')}</a></li>
92 <li><a href="${h.url('repos')}"><i class="icon-archive"></i> ${_('Repositories')}</a></li>
93 %endif
93 %endif
94 %if repository_groups:
94 %if repository_groups:
95 <li><a href="${h.url('repos_groups')}"><i class="icon-folder-close"></i> ${_('Repository groups')}</a></li>
95 <li><a href="${h.url('repos_groups')}"><i class="icon-folder-close"></i> ${_('Repository Groups')}</a></li>
96 %endif
96 %endif
97 %if user_groups:
97 %if user_groups:
98 <li><a href="${h.url('users_groups')}"><i class="icon-group"></i> ${_('User groups')}</a></li>
98 <li><a href="${h.url('users_groups')}"><i class="icon-group"></i> ${_('User Groups')}</a></li>
99 %endif
99 %endif
100 </ul>
100 </ul>
101 </%def>
101 </%def>
102
102
103 <%def name="repo_context_bar(current=None, rev=None)">
103 <%def name="repo_context_bar(current=None, rev=None)">
104 <% rev = None if rev == 'tip' else rev %>
104 <% rev = None if rev == 'tip' else rev %>
105 <%
105 <%
106 def follow_class():
106 def follow_class():
107 if c.repository_following:
107 if c.repository_following:
108 return h.literal('following')
108 return h.literal('following')
109 else:
109 else:
110 return h.literal('follow')
110 return h.literal('follow')
111 %>
111 %>
112 <%
112 <%
113 def is_current(selected):
113 def is_current(selected):
114 if selected == current:
114 if selected == current:
115 return h.literal('class="current"')
115 return h.literal('class="current"')
116 %>
116 %>
117
117
118 <!--- CONTEXT BAR -->
118 <!--- CONTEXT BAR -->
119 <div id="context-bar" class="box">
119 <div id="context-bar" class="box">
120 <h2>
120 <h2>
121 %if h.is_hg(c.db_repo):
121 %if h.is_hg(c.db_repo):
122 <i class="icon-hg" style="color: #576622; font-size: 24px"></i>
122 <i class="icon-hg" style="color: #576622; font-size: 24px"></i>
123 %endif
123 %endif
124 %if h.is_git(c.db_repo):
124 %if h.is_git(c.db_repo):
125 <i class="icon-git" style="color: #e85634; font-size: 24px"></i>
125 <i class="icon-git" style="color: #e85634; font-size: 24px"></i>
126 %endif
126 %endif
127
127
128 ## public/private
128 ## public/private
129 %if c.db_repo.private:
129 %if c.db_repo.private:
130 <i class="icon-lock"></i>
130 <i class="icon-lock"></i>
131 %else:
131 %else:
132 <i class="icon-unlock-alt"></i>
132 <i class="icon-unlock-alt"></i>
133 %endif
133 %endif
134 ${h.repo_link(c.db_repo.groups_and_repo)}
134 ${h.repo_link(c.db_repo.groups_and_repo)}
135
135
136 %if current == 'createfork':
136 %if current == 'createfork':
137 - ${_('Create fork')}
137 - ${_('Create Fork')}
138 %endif
138 %endif
139 </h2>
139 </h2>
140 <!--
140 <!--
141 <div id="breadcrumbs">
141 <div id="breadcrumbs">
142 ${h.link_to(_(u'Repositories'),h.url('home'))}
142 ${h.link_to(_(u'Repositories'),h.url('home'))}
143 &raquo;
143 &raquo;
144 ${h.repo_link(c.db_repo.groups_and_repo)}
144 ${h.repo_link(c.db_repo.groups_and_repo)}
145 </div>
145 </div>
146 -->
146 -->
147 <ul id="context-pages" class="horizontal-list">
147 <ul id="context-pages" class="horizontal-list">
148 <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-file-text"></i> ${_('Summary')}</a></li>
148 <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-file-text"></i> ${_('Summary')}</a></li>
149 %if rev:
149 %if rev:
150 <li ${is_current('changelog')}><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
150 <li ${is_current('changelog')}><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
151 %else:
151 %else:
152 <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
152 <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
153 %endif
153 %endif
154 <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-file"></i> ${_('Files')}</a></li>
154 <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-file"></i> ${_('Files')}</a></li>
155 <li ${is_current('switch-to')}>
155 <li ${is_current('switch-to')}>
156 <a href="#" id="branch_tag_switcher_2" class="dropdown"><i class="icon-random"></i> ${_('Switch To')}</a>
156 <a href="#" id="branch_tag_switcher_2" class="dropdown"><i class="icon-random"></i> ${_('Switch To')}</a>
157 <ul id="switch_to_list_2" class="switch_to submenu">
157 <ul id="switch_to_list_2" class="switch_to submenu">
158 <li><a href="#">${_('Loading...')}</a></li>
158 <li><a href="#">${_('Loading...')}</a></li>
159 </ul>
159 </ul>
160 </li>
160 </li>
161 <li ${is_current('options')}>
161 <li ${is_current('options')}>
162 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
162 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
163 <a href="${h.url('edit_repo',repo_name=c.repo_name)}" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
163 <a href="${h.url('edit_repo',repo_name=c.repo_name)}" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
164 %else:
164 %else:
165 <a href="#" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
165 <a href="#" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
166 %endif
166 %endif
167 <ul>
167 <ul>
168 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
168 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
169 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}"><i class="icon-cog"></i> ${_('Settings')}</a></li>
169 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}"><i class="icon-cog"></i> ${_('Settings')}</a></li>
170 %endif
170 %endif
171 %if c.db_repo.fork:
171 %if c.db_repo.fork:
172 <li><a href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1], other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}">
172 <li><a href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1], other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}">
173 <i class="icon-loop"></i> ${_('Compare fork')}</a></li>
173 <i class="icon-loop"></i> ${_('Compare Fork')}</a></li>
174 %endif
174 %endif
175 <li><a href="${h.url('compare_home',repo_name=c.repo_name)}"><i class="icon-loop"></i> ${_('Compare')}</a></li>
175 <li><a href="${h.url('compare_home',repo_name=c.repo_name)}"><i class="icon-loop"></i> ${_('Compare')}</a></li>
176
176
177 <li><a href="${h.url('search_repo',repo_name=c.repo_name)}"><i class="icon-search"></i> ${_('Search')}</a></li>
177 <li><a href="${h.url('search_repo',repo_name=c.repo_name)}"><i class="icon-search"></i> ${_('Search')}</a></li>
178
178
179 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.db_repo.enable_locking:
179 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.db_repo.enable_locking:
180 %if c.db_repo.locked[0]:
180 %if c.db_repo.locked[0]:
181 <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
181 <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
182 %else:
182 %else:
183 <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
183 <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
184 %endif
184 %endif
185 %endif
185 %endif
186 ## TODO: this check feels wrong, it would be better to have a check for permissions
186 ## TODO: this check feels wrong, it would be better to have a check for permissions
187 ## also it feels like a job for the controller
187 ## also it feels like a job for the controller
188 %if c.authuser.username != 'default':
188 %if c.authuser.username != 'default':
189 <li>
189 <li>
190 <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.db_repo.repo_id},'${str(h.get_token())}');">
190 <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.db_repo.repo_id},'${str(h.get_token())}');">
191 <span class="show-follow"><i class="icon-heart-empty"></i> ${_('Follow')}</span>
191 <span class="show-follow"><i class="icon-heart-empty"></i> ${_('Follow')}</span>
192 <span class="show-following"><i class="icon-heart"></i> ${_('Unfollow')}</span>
192 <span class="show-following"><i class="icon-heart"></i> ${_('Unfollow')}</span>
193 </a>
193 </a>
194 </li>
194 </li>
195 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Fork')}</a></li>
195 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Fork')}</a></li>
196 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Create Pull Request')}</a></li>
196 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Create Pull Request')}</a></li>
197 %endif
197 %endif
198 </ul>
198 </ul>
199 </li>
199 </li>
200 <li ${is_current('showpullrequest')}>
200 <li ${is_current('showpullrequest')}>
201 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> <i class="icon-code-fork"></i> ${_('Pull Requests')}
201 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> <i class="icon-code-fork"></i> ${_('Pull Requests')}
202 %if c.repository_pull_requests:
202 %if c.repository_pull_requests:
203 <span>${c.repository_pull_requests}</span>
203 <span>${c.repository_pull_requests}</span>
204 %endif
204 %endif
205 </a>
205 </a>
206 </li>
206 </li>
207 </ul>
207 </ul>
208 </div>
208 </div>
209 <script type="text/javascript">
209 <script type="text/javascript">
210 YUE.on('branch_tag_switcher_2','mouseover',function(){
210 YUE.on('branch_tag_switcher_2','mouseover',function(){
211 var $branch_tag_switcher_2 = $('#branch_tag_switcher_2');
211 var $branch_tag_switcher_2 = $('#branch_tag_switcher_2');
212 var loaded = $branch_tag_switcher_2.hasClass('loaded');
212 var loaded = $branch_tag_switcher_2.hasClass('loaded');
213 if(!loaded){
213 if(!loaded){
214 $branch_tag_switcher_2.addClass('loaded');
214 $branch_tag_switcher_2.addClass('loaded');
215 asynchtml("${h.url('branch_tag_switcher',repo_name=c.repo_name)}", $('#switch_to_list_2'));
215 asynchtml("${h.url('branch_tag_switcher',repo_name=c.repo_name)}", $('#switch_to_list_2'));
216 }
216 }
217 return false;
217 return false;
218 });
218 });
219 </script>
219 </script>
220 <!--- END CONTEXT BAR -->
220 <!--- END CONTEXT BAR -->
221 </%def>
221 </%def>
222
222
223 <%def name="menu(current=None)">
223 <%def name="menu(current=None)">
224 <%
224 <%
225 def is_current(selected):
225 def is_current(selected):
226 if selected == current:
226 if selected == current:
227 return h.literal('class="current"')
227 return h.literal('class="current"')
228 %>
228 %>
229
229
230 <ul id="quick" class="horizontal-list">
230 <ul id="quick" class="horizontal-list">
231 <!-- repo switcher -->
231 <!-- repo switcher -->
232 <li ${is_current('repositories')}>
232 <li ${is_current('repositories')}>
233 <input id="repo_switcher" name="repo_switcher" type="hidden">
233 <input id="repo_switcher" name="repo_switcher" type="hidden">
234 </li>
234 </li>
235
235
236 ##ROOT MENU
236 ##ROOT MENU
237 %if c.authuser.username != 'default':
237 %if c.authuser.username != 'default':
238 <li ${is_current('journal')}>
238 <li ${is_current('journal')}>
239 <a class="menu_link" title="${_('Show recent activity')}" href="${h.url('journal')}">
239 <a class="menu_link" title="${_('Show recent activity')}" href="${h.url('journal')}">
240 <i class="icon-book"></i> ${_('Journal')}
240 <i class="icon-book"></i> ${_('Journal')}
241 </a>
241 </a>
242 </li>
242 </li>
243 %else:
243 %else:
244 <li ${is_current('journal')}>
244 <li ${is_current('journal')}>
245 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
245 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
246 <i class="icon-book"></i> ${_('Public journal')}
246 <i class="icon-book"></i> ${_('Public journal')}
247 </a>
247 </a>
248 </li>
248 </li>
249 %endif
249 %endif
250 <li ${is_current('gists')}>
250 <li ${is_current('gists')}>
251 <a class="menu_link childs" title="${_('Show public gists')}" href="${h.url('gists')}">
251 <a class="menu_link childs" title="${_('Show public gists')}" href="${h.url('gists')}">
252 <i class="icon-file-2"></i> ${_('Gists')}
252 <i class="icon-file-2"></i> ${_('Gists')}
253 </a>
253 </a>
254 <ul class="admin_menu">
254 <ul class="admin_menu">
255 <li><a href="${h.url('new_gist', public=1)}"><i class="icon-file-alt"></i> ${_('Create new gist')}</a></li>
255 <li><a href="${h.url('new_gist', public=1)}"><i class="icon-file-alt"></i> ${_('Create New Gist')}</a></li>
256 <li><a href="${h.url('gists')}"><i class="icon-copy"></i> ${_('All public gists')}</a></li>
256 <li><a href="${h.url('gists')}"><i class="icon-copy"></i> ${_('All Public Gists')}</a></li>
257 %if c.authuser.username != 'default':
257 %if c.authuser.username != 'default':
258 <li><a href="${h.url('gists', public=1)}"><i class="icon-copy"></i> ${_('My public gists')}</a></li>
258 <li><a href="${h.url('gists', public=1)}"><i class="icon-copy"></i> ${_('My Public Gists')}</a></li>
259 <li><a href="${h.url('gists', private=1)}"><i class="icon-file-text"></i> ${_('My private gists')}</a></li>
259 <li><a href="${h.url('gists', private=1)}"><i class="icon-file-text"></i> ${_('My Private Gists')}</a></li>
260 %endif
260 %endif
261 </ul>
261 </ul>
262 </li>
262 </li>
263 <li ${is_current('search')}>
263 <li ${is_current('search')}>
264 <a class="menu_link" title="${_('Search in repositories')}" href="${h.url('search')}">
264 <a class="menu_link" title="${_('Search in repositories')}" href="${h.url('search')}">
265 <i class="icon-search"></i> ${_('Search')}
265 <i class="icon-search"></i> ${_('Search')}
266 </a>
266 </a>
267 </li>
267 </li>
268 % if h.HasPermissionAll('hg.admin')('access admin main page'):
268 % if h.HasPermissionAll('hg.admin')('access admin main page'):
269 <li ${is_current('admin')}>
269 <li ${is_current('admin')}>
270 <a class="menu_link childs" title="${_('Admin')}" href="${h.url('admin_home')}">
270 <a class="menu_link childs" title="${_('Admin')}" href="${h.url('admin_home')}">
271 <i class="icon-cog"></i> ${_('Admin')}
271 <i class="icon-cog"></i> ${_('Admin')}
272 </a>
272 </a>
273 ${admin_menu()}
273 ${admin_menu()}
274 </li>
274 </li>
275 % elif c.authuser.repositories_admin or c.authuser.repository_groups_admin or c.authuser.user_groups_admin:
275 % elif c.authuser.repositories_admin or c.authuser.repository_groups_admin or c.authuser.user_groups_admin:
276 <li ${is_current('admin')}>
276 <li ${is_current('admin')}>
277 <a class="menu_link childs" title="${_('Admin')}">
277 <a class="menu_link childs" title="${_('Admin')}">
278 <i class="icon-cog"></i> ${_('Admin')}
278 <i class="icon-cog"></i> ${_('Admin')}
279 </a>
279 </a>
280 ${admin_menu_simple(c.authuser.repositories_admin,
280 ${admin_menu_simple(c.authuser.repositories_admin,
281 c.authuser.repository_groups_admin,
281 c.authuser.repository_groups_admin,
282 c.authuser.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
282 c.authuser.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
283 </li>
283 </li>
284 % endif
284 % endif
285
285
286 <li ${is_current('my_pullrequests')}>
286 <li ${is_current('my_pullrequests')}>
287 <a class="menu_link" title="${_('My Pull Requests')}" href="${h.url('my_pullrequests')}">
287 <a class="menu_link" title="${_('My Pull Requests')}" href="${h.url('my_pullrequests')}">
288 <i class="icon-code-fork"></i> ${_('My Pull Requests')}
288 <i class="icon-code-fork"></i> ${_('My Pull Requests')}
289 %if c.my_pr_count != 0:
289 %if c.my_pr_count != 0:
290 <span class="menu_link_notifications">${c.my_pr_count}</span>
290 <span class="menu_link_notifications">${c.my_pr_count}</span>
291 %endif
291 %endif
292 </a>
292 </a>
293 </li>
293 </li>
294
294
295 ## USER MENU
295 ## USER MENU
296 <li>
296 <li>
297 <a class="menu_link childs" id="quick_login_link">
297 <a class="menu_link childs" id="quick_login_link">
298 <span class="icon">
298 <span class="icon">
299 <img src="${h.gravatar_url(c.authuser.email,20)}" alt="avatar">
299 <img src="${h.gravatar_url(c.authuser.email,20)}" alt="avatar">
300 </span>
300 </span>
301 %if c.authuser.username != 'default':
301 %if c.authuser.username != 'default':
302 <span class="menu_link_user">${c.authuser.username}</span>
302 <span class="menu_link_user">${c.authuser.username}</span>
303 %if c.unread_notifications != 0:
303 %if c.unread_notifications != 0:
304 <span class="menu_link_notifications">${c.unread_notifications}</span>
304 <span class="menu_link_notifications">${c.unread_notifications}</span>
305 %endif
305 %endif
306 %else:
306 %else:
307 <span>${_('Not logged in')}</span>
307 <span>${_('Not Logged In')}</span>
308 %endif
308 %endif
309 </a>
309 </a>
310
310
311 <div class="user-menu">
311 <div class="user-menu">
312 <div id="quick_login">
312 <div id="quick_login">
313 %if c.authuser.username == 'default' or c.authuser.user_id is None:
313 %if c.authuser.username == 'default' or c.authuser.user_id is None:
314 <h4>${_('Login to your account')}</h4>
314 <h4>${_('Login to Your Account')}</h4>
315 ${h.form(h.url('login_home',came_from=h.url.current()))}
315 ${h.form(h.url('login_home',came_from=h.url.current()))}
316 <div class="form">
316 <div class="form">
317 <div class="fields">
317 <div class="fields">
318 <div class="field">
318 <div class="field">
319 <div class="label">
319 <div class="label">
320 <label for="username">${_('Username')}:</label>
320 <label for="username">${_('Username')}:</label>
321 </div>
321 </div>
322 <div class="input">
322 <div class="input">
323 ${h.text('username',class_='focus')}
323 ${h.text('username',class_='focus')}
324 </div>
324 </div>
325
325
326 </div>
326 </div>
327 <div class="field">
327 <div class="field">
328 <div class="label">
328 <div class="label">
329 <label for="password">${_('Password')}:</label>
329 <label for="password">${_('Password')}:</label>
330 </div>
330 </div>
331 <div class="input">
331 <div class="input">
332 ${h.password('password',class_='focus')}
332 ${h.password('password',class_='focus')}
333 </div>
333 </div>
334
334
335 </div>
335 </div>
336 <div class="buttons">
336 <div class="buttons">
337 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
337 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
338 <div class="register">
338 <div class="register">
339 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
339 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
340 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
340 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
341 %endif
341 %endif
342 </div>
342 </div>
343 <div class="submit">
343 <div class="submit">
344 ${h.submit('sign_in',_('Log In'),class_="btn btn-mini")}
344 ${h.submit('sign_in',_('Log In'),class_="btn btn-mini")}
345 </div>
345 </div>
346 </div>
346 </div>
347 </div>
347 </div>
348 </div>
348 </div>
349 ${h.end_form()}
349 ${h.end_form()}
350 %else:
350 %else:
351 <div class="links_left">
351 <div class="links_left">
352 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.authuser.email,48)}" /></div>
352 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.authuser.email,48)}" /></div>
353 <div class="full_name">${c.authuser.full_name_or_username}</div>
353 <div class="full_name">${c.authuser.full_name_or_username}</div>
354 <div class="email">${c.authuser.email}</div>
354 <div class="email">${c.authuser.email}</div>
355 </div>
355 </div>
356 <div class="links_right">
356 <div class="links_right">
357 <ol class="links">
357 <ol class="links">
358 <li><a href="${h.url('notifications')}">${_('Notifications')}: ${c.unread_notifications}</a></li>
358 <li><a href="${h.url('notifications')}">${_('Notifications')}: ${c.unread_notifications}</a></li>
359 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
359 <li>${h.link_to(_(u'My Account'),h.url('my_account'))}</li>
360 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
360 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
361 </ol>
361 </ol>
362 </div>
362 </div>
363 %endif
363 %endif
364 </div>
364 </div>
365 </div>
365 </div>
366 </li>
366 </li>
367
367
368 <script type="text/javascript">
368 <script type="text/javascript">
369 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
369 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
370 var cache = {}
370 var cache = {}
371 /*format the look of items in the list*/
371 /*format the look of items in the list*/
372 var format = function(state){
372 var format = function(state){
373 if (!state.id){
373 if (!state.id){
374 return state.text; // optgroup
374 return state.text; // optgroup
375 }
375 }
376 var obj_dict = state.obj;
376 var obj_dict = state.obj;
377 var tmpl = '';
377 var tmpl = '';
378
378
379 if(obj_dict && state.type == 'repo'){
379 if(obj_dict && state.type == 'repo'){
380 tmpl += '<span class="repo-icons">';
380 tmpl += '<span class="repo-icons">';
381 if(obj_dict['repo_type'] === 'hg'){
381 if(obj_dict['repo_type'] === 'hg'){
382 tmpl += '<i class="icon-hg"></i> ';
382 tmpl += '<i class="icon-hg"></i> ';
383 }
383 }
384 else if(obj_dict['repo_type'] === 'git'){
384 else if(obj_dict['repo_type'] === 'git'){
385 tmpl += '<i class="icon-git"></i> ';
385 tmpl += '<i class="icon-git"></i> ';
386 }
386 }
387 if(obj_dict['private']){
387 if(obj_dict['private']){
388 tmpl += '<i class="icon-lock" style="color: #e85634;"></i> ';
388 tmpl += '<i class="icon-lock" style="color: #e85634;"></i> ';
389 }
389 }
390 else if(visual_show_public_icon){
390 else if(visual_show_public_icon){
391 tmpl += '<i class="icon-unlock-alt"></i> ';
391 tmpl += '<i class="icon-unlock-alt"></i> ';
392 }
392 }
393 tmpl += '</span>';
393 tmpl += '</span>';
394 }
394 }
395 if(obj_dict && state.type == 'group'){
395 if(obj_dict && state.type == 'group'){
396 tmpl += '<i class="icon-folder-close"></i> ';
396 tmpl += '<i class="icon-folder-close"></i> ';
397 }
397 }
398 tmpl += state.text;
398 tmpl += state.text;
399 return tmpl;
399 return tmpl;
400 }
400 }
401
401
402 $("#repo_switcher").select2({
402 $("#repo_switcher").select2({
403 placeholder: '<i class="icon-archive"></i> ${_('Repositories')}',
403 placeholder: '<i class="icon-archive"></i> ${_('Repositories')}',
404 dropdownAutoWidth: true,
404 dropdownAutoWidth: true,
405 formatResult: format,
405 formatResult: format,
406 formatSelection: format,
406 formatSelection: format,
407 formatNoMatches: function(term){
407 formatNoMatches: function(term){
408 return "${_('No matches found')}";
408 return "${_('No matches found')}";
409 },
409 },
410 containerCssClass: "repo-switcher",
410 containerCssClass: "repo-switcher",
411 dropdownCssClass: "repo-switcher-dropdown",
411 dropdownCssClass: "repo-switcher-dropdown",
412 escapeMarkup: function(m){
412 escapeMarkup: function(m){
413 // don't escape our custom placeholder
413 // don't escape our custom placeholder
414 if(m.substr(0,28) == '<i class="icon-archive"></i>'){
414 if(m.substr(0,28) == '<i class="icon-archive"></i>'){
415 return m;
415 return m;
416 }
416 }
417
417
418 return Select2.util.escapeMarkup(m);
418 return Select2.util.escapeMarkup(m);
419 },
419 },
420 query: function(query){
420 query: function(query){
421 var key = 'cache';
421 var key = 'cache';
422 var cached = cache[key] ;
422 var cached = cache[key] ;
423 if(cached) {
423 if(cached) {
424 var data = {results: []};
424 var data = {results: []};
425 //filter results
425 //filter results
426 $.each(cached.results, function(){
426 $.each(cached.results, function(){
427 var section = this.text;
427 var section = this.text;
428 var children = [];
428 var children = [];
429 $.each(this.children, function(){
429 $.each(this.children, function(){
430 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
430 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
431 children.push({'id': this.id, 'text': this.text, 'type': this.type, 'obj': this.obj})
431 children.push({'id': this.id, 'text': this.text, 'type': this.type, 'obj': this.obj})
432 }
432 }
433 })
433 })
434 if(children.length !== 0){
434 if(children.length !== 0){
435 data.results.push({'text': section, 'children': children})
435 data.results.push({'text': section, 'children': children})
436 }
436 }
437
437
438 });
438 });
439 query.callback(data);
439 query.callback(data);
440 }else{
440 }else{
441 $.ajax({
441 $.ajax({
442 url: "${h.url('repo_switcher_data')}",
442 url: "${h.url('repo_switcher_data')}",
443 data: {},
443 data: {},
444 dataType: 'json',
444 dataType: 'json',
445 type: 'GET',
445 type: 'GET',
446 success: function(data) {
446 success: function(data) {
447 cache[key] = data;
447 cache[key] = data;
448 query.callback({results: data.results});
448 query.callback({results: data.results});
449 }
449 }
450 })
450 })
451 }
451 }
452 }
452 }
453 });
453 });
454
454
455 $("#repo_switcher").on('select2-selecting', function(e){
455 $("#repo_switcher").on('select2-selecting', function(e){
456 e.preventDefault();
456 e.preventDefault();
457 window.location = pyroutes.url('summary_home', {'repo_name': e.val})
457 window.location = pyroutes.url('summary_home', {'repo_name': e.val})
458 })
458 })
459
459
460 ## Global mouse bindings ##
460 ## Global mouse bindings ##
461
461
462 // general help "?"
462 // general help "?"
463 Mousetrap.bind(['?'], function(e) {
463 Mousetrap.bind(['?'], function(e) {
464 $('#help_kb').modal({})
464 $('#help_kb').modal({})
465 });
465 });
466
466
467 // / open the quick filter
467 // / open the quick filter
468 Mousetrap.bind(['/'], function(e) {
468 Mousetrap.bind(['/'], function(e) {
469 $("#repo_switcher").select2("open");
469 $("#repo_switcher").select2("open");
470
470
471 // return false to prevent default browser behavior
471 // return false to prevent default browser behavior
472 // and stop event from bubbling
472 // and stop event from bubbling
473 return false;
473 return false;
474 });
474 });
475
475
476 // ctrl/command+b, show the the main bar
476 // ctrl/command+b, show the the main bar
477 Mousetrap.bind(['command+b', 'ctrl+b'], function(e) {
477 Mousetrap.bind(['command+b', 'ctrl+b'], function(e) {
478 if($('#header-inner').hasClass('hover') && $('#content').hasClass('hover')){
478 if($('#header-inner').hasClass('hover') && $('#content').hasClass('hover')){
479 $('#header-inner').removeClass('hover');
479 $('#header-inner').removeClass('hover');
480 $('#content').removeClass('hover');
480 $('#content').removeClass('hover');
481 }
481 }
482 else{
482 else{
483 $('#header-inner').addClass('hover');
483 $('#header-inner').addClass('hover');
484 $('#content').addClass('hover');
484 $('#content').addClass('hover');
485 }
485 }
486 return false;
486 return false;
487 });
487 });
488
488
489 // general nav g + action
489 // general nav g + action
490 Mousetrap.bind(['g h'], function(e) {
490 Mousetrap.bind(['g h'], function(e) {
491 window.location = pyroutes.url('home');
491 window.location = pyroutes.url('home');
492 });
492 });
493 Mousetrap.bind(['g g'], function(e) {
493 Mousetrap.bind(['g g'], function(e) {
494 window.location = pyroutes.url('gists', {'private':1});
494 window.location = pyroutes.url('gists', {'private':1});
495 });
495 });
496 Mousetrap.bind(['g G'], function(e) {
496 Mousetrap.bind(['g G'], function(e) {
497 window.location = pyroutes.url('gists', {'public':1});
497 window.location = pyroutes.url('gists', {'public':1});
498 });
498 });
499 Mousetrap.bind(['n g'], function(e) {
499 Mousetrap.bind(['n g'], function(e) {
500 window.location = pyroutes.url('new_gist');
500 window.location = pyroutes.url('new_gist');
501 });
501 });
502 Mousetrap.bind(['n r'], function(e) {
502 Mousetrap.bind(['n r'], function(e) {
503 window.location = pyroutes.url('new_repo');
503 window.location = pyroutes.url('new_repo');
504 });
504 });
505
505
506 % if hasattr(c, 'repo_name') and hasattr(c, 'db_repo'):
506 % if hasattr(c, 'repo_name') and hasattr(c, 'db_repo'):
507 // nav in repo context
507 // nav in repo context
508 Mousetrap.bind(['g s'], function(e) {
508 Mousetrap.bind(['g s'], function(e) {
509 window.location = pyroutes.url('summary_home', {'repo_name': REPO_NAME});
509 window.location = pyroutes.url('summary_home', {'repo_name': REPO_NAME});
510 });
510 });
511 Mousetrap.bind(['g c'], function(e) {
511 Mousetrap.bind(['g c'], function(e) {
512 window.location = pyroutes.url('changelog_home', {'repo_name': REPO_NAME});
512 window.location = pyroutes.url('changelog_home', {'repo_name': REPO_NAME});
513 });
513 });
514 Mousetrap.bind(['g F'], function(e) {
514 Mousetrap.bind(['g F'], function(e) {
515 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.db_repo.landing_rev[1]}', 'f_path': '', 'search': '1'});
515 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.db_repo.landing_rev[1]}', 'f_path': '', 'search': '1'});
516 });
516 });
517 Mousetrap.bind(['g f'], function(e) {
517 Mousetrap.bind(['g f'], function(e) {
518 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.db_repo.landing_rev[1]}', 'f_path': ''});
518 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.db_repo.landing_rev[1]}', 'f_path': ''});
519 });
519 });
520 Mousetrap.bind(['g o'], function(e) {
520 Mousetrap.bind(['g o'], function(e) {
521 window.location = pyroutes.url('edit_repo', {'repo_name': REPO_NAME});
521 window.location = pyroutes.url('edit_repo', {'repo_name': REPO_NAME});
522 });
522 });
523 Mousetrap.bind(['g O'], function(e) {
523 Mousetrap.bind(['g O'], function(e) {
524 window.location = pyroutes.url('edit_repo_perms', {'repo_name': REPO_NAME});
524 window.location = pyroutes.url('edit_repo_perms', {'repo_name': REPO_NAME});
525 });
525 });
526 % endif
526 % endif
527
527
528 </script>
528 </script>
529 </%def>
529 </%def>
530
530
531 %if 0:
531 %if 0:
532 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
532 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
533 <div class="modal-dialog">
533 <div class="modal-dialog">
534 <div class="modal-content">
534 <div class="modal-content">
535 <div class="modal-header">
535 <div class="modal-header">
536 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
536 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
537 <h4 class="modal-title">${_('Keyboard shortcuts')}</h4>
537 <h4 class="modal-title">${_('Keyboard shortcuts')}</h4>
538 </div>
538 </div>
539 <div class="modal-body">
539 <div class="modal-body">
540 <div class="row">
540 <div class="row">
541 <div class="col-md-5">
541 <div class="col-md-5">
542 <table class="keyboard-mappings">
542 <table class="keyboard-mappings">
543 <tbody>
543 <tbody>
544 <tr>
544 <tr>
545 <th></th>
545 <th></th>
546 <th>${_('Site-wide shortcuts')}</th>
546 <th>${_('Site-wide shortcuts')}</th>
547 </tr>
547 </tr>
548 <%
548 <%
549 elems = [
549 elems = [
550 ('/', 'Open quick search box'),
550 ('/', 'Open quick search box'),
551 ('ctrl/cmd+b', 'Show main settings bar'),
551 ('ctrl/cmd+b', 'Show main settings bar'),
552 ('g h', 'Goto home page'),
552 ('g h', 'Goto home page'),
553 ('g g', 'Goto my private gists page'),
553 ('g g', 'Goto my private gists page'),
554 ('g G', 'Goto my public gists page'),
554 ('g G', 'Goto my public gists page'),
555 ('n r', 'New repository page'),
555 ('n r', 'New repository page'),
556 ('n g', 'New gist page')
556 ('n g', 'New gist page')
557 ]
557 ]
558 %>
558 %>
559 %for key, desc in elems:
559 %for key, desc in elems:
560 <tr>
560 <tr>
561 <td class="keys">
561 <td class="keys">
562 <span class="key">${key}</span>
562 <span class="key">${key}</span>
563 </td>
563 </td>
564 <td>${desc}</td>
564 <td>${desc}</td>
565 </tr>
565 </tr>
566 %endfor
566 %endfor
567 </tbody>
567 </tbody>
568 </table>
568 </table>
569 </div>
569 </div>
570 <div class="col-md-offset-5">
570 <div class="col-md-offset-5">
571 <table class="keyboard-mappings">
571 <table class="keyboard-mappings">
572 <tbody>
572 <tbody>
573 <tr>
573 <tr>
574 <th></th>
574 <th></th>
575 <th>${_('Repositories')}</th>
575 <th>${_('Repositories')}</th>
576 </tr>
576 </tr>
577 <%
577 <%
578 elems = [
578 elems = [
579 ('g s', 'Goto summary page'),
579 ('g s', 'Goto summary page'),
580 ('g c', 'Goto changelog page'),
580 ('g c', 'Goto changelog page'),
581 ('g f', 'Goto files page'),
581 ('g f', 'Goto files page'),
582 ('g F', 'Goto files page with file search activated'),
582 ('g F', 'Goto files page with file search activated'),
583 ('g o', 'Goto repository settings'),
583 ('g o', 'Goto repository settings'),
584 ('g O', 'Goto repository permissions settings')
584 ('g O', 'Goto repository permissions settings')
585 ]
585 ]
586 %>
586 %>
587 %for key, desc in elems:
587 %for key, desc in elems:
588 <tr>
588 <tr>
589 <td class="keys">
589 <td class="keys">
590 <span class="key">${key}</span>
590 <span class="key">${key}</span>
591 </td>
591 </td>
592 <td>${desc}</td>
592 <td>${desc}</td>
593 </tr>
593 </tr>
594 %endfor
594 %endfor
595 </tbody>
595 </tbody>
596 </table>
596 </table>
597 </div>
597 </div>
598 </div>
598 </div>
599 </div>
599 </div>
600 <div class="modal-footer">
600 <div class="modal-footer">
601 </div>
601 </div>
602 </div><!-- /.modal-content -->
602 </div><!-- /.modal-content -->
603 </div><!-- /.modal-dialog -->
603 </div><!-- /.modal-dialog -->
604 </div><!-- /.modal -->
604 </div><!-- /.modal -->
605 %endif
605 %endif
@@ -1,140 +1,140 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3
3
4 <html xmlns="http://www.w3.org/1999/xhtml">
4 <html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
5 <head>
6 <title>${self.title()}</title>
6 <title>${self.title()}</title>
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <link rel="icon" href="${h.url('/images/favicon.ico')}" type="image/png" />
9 <link rel="icon" href="${h.url('/images/favicon.ico')}" type="image/png" />
10
10
11 ## CSS ###
11 ## CSS ###
12 <%def name="css()">
12 <%def name="css()">
13 <link rel="stylesheet" type="text/css" href="${h.url('/js/select2/select2.css', ver=c.kallithea_version)}"/>
13 <link rel="stylesheet" type="text/css" href="${h.url('/js/select2/select2.css', ver=c.kallithea_version)}"/>
14 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css', ver=c.kallithea_version)}"/>
14 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css', ver=c.kallithea_version)}"/>
15 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css', ver=c.kallithea_version)}" media="screen"/>
15 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css', ver=c.kallithea_version)}" media="screen"/>
16 <link rel="stylesheet" type="text/css" href="${h.url('/css/contextbar.css', ver=c.kallithea_version)}" media="screen"/>
16 <link rel="stylesheet" type="text/css" href="${h.url('/css/contextbar.css', ver=c.kallithea_version)}" media="screen"/>
17 ## EXTRA FOR CSS
17 ## EXTRA FOR CSS
18 ${self.css_extra()}
18 ${self.css_extra()}
19 </%def>
19 </%def>
20
20
21 <%def name="css_extra()"></%def>
21 <%def name="css_extra()"></%def>
22
22
23 ${self.css()}
23 ${self.css()}
24
24
25 ## JAVASCRIPT ##
25 ## JAVASCRIPT ##
26 <%def name="js()">
26 <%def name="js()">
27 <script type="text/javascript">
27 <script type="text/javascript">
28 //JS translations map
28 //JS translations map
29 var TRANSLATION_MAP = {
29 var TRANSLATION_MAP = {
30 'Add another comment':'${_("Add another comment")}',
30 'Add Another Comment':'${_("Add Another Comment")}',
31 'Stop following this repository':"${_('Stop following this repository')}",
31 'Stop following this repository':"${_('Stop following this repository')}",
32 'Start following this repository':"${_('Start following this repository')}",
32 'Start following this repository':"${_('Start following this repository')}",
33 'Group':"${_('Group')}",
33 'Group':"${_('Group')}",
34 'members':"${_('members')}",
34 'members':"${_('members')}",
35 'Loading ...':"${_('Loading ...')}",
35 'Loading ...':"${_('Loading ...')}",
36 'loading ...':"${_('loading ...')}",
36 'loading ...':"${_('loading ...')}",
37 'Search truncated': "${_('Search truncated')}",
37 'Search truncated': "${_('Search truncated')}",
38 'No matching files': "${_('No matching files')}",
38 'No matching files': "${_('No matching files')}",
39 'Open new pull request': "${_('Open new pull request')}",
39 'Open New Pull Request': "${_('Open New Pull Request')}",
40 'Open new pull request for selected changesets': "${_('Open new pull request for selected changesets')}",
40 'Open New Pull Request for Selected Changesets': "${_('Open New Pull Request for Selected Changesets')}",
41 'Show selected changesets __S &rarr; __E': "${h.literal(_('Show selected changesets __S &rarr; __E'))}",
41 'Show Selected Changesets __S &rarr; __E': "${h.literal(_('Show Selected Changesets __S &rarr; __E'))}",
42 'Show selected changeset __S': "${_('Show selected changeset __S')}",
42 'Show Selected Changeset __S': "${_('Show Selected Changeset __S')}",
43 'Selection link': "${_('Selection link')}",
43 'Selection Link': "${_('Selection Link')}",
44 'Collapse diff': "${_('Collapse diff')}",
44 'Collapse Diff': "${_('Collapse Diff')}",
45 'Expand diff': "${_('Expand diff')}",
45 'Expand Diff': "${_('Expand Diff')}",
46 'Failed to revoke permission': "${_('Failed to revoke permission')}",
46 'Failed to revoke permission': "${_('Failed to revoke permission')}",
47 'Confirm to revoke permission for {0}: {1} ?': "${_('confirm to revoke permission for {0}: {1} ?')}",
47 'Confirm to revoke permission for {0}: {1} ?': "${_('confirm to revoke permission for {0}: {1} ?')}",
48 'enabled': "${_('enabled')}",
48 'enabled': "${_('enabled')}",
49 'disabled': "${_('disabled')}",
49 'disabled': "${_('disabled')}",
50 'Select changeset': "${_('Select changeset')}",
50 'Select changeset': "${_('Select changeset')}",
51 'Specify changeset': "${_('Specify changeset')}",
51 'Specify changeset': "${_('Specify changeset')}",
52 'MSG_SORTASC': "${_('Click to sort ascending')}",
52 'MSG_SORTASC': "${_('Click to sort ascending')}",
53 'MSG_SORTDESC': "${_('Click to sort descending')}",
53 'MSG_SORTDESC': "${_('Click to sort descending')}",
54 'MSG_EMPTY': "${_('No records found.')}",
54 'MSG_EMPTY': "${_('No records found.')}",
55 'MSG_ERROR': "${_('Data error.')}",
55 'MSG_ERROR': "${_('Data error.')}",
56 'MSG_LOADING': "${_('Loading...')}"
56 'MSG_LOADING': "${_('Loading...')}"
57 };
57 };
58 var _TM = TRANSLATION_MAP;
58 var _TM = TRANSLATION_MAP;
59
59
60 var TOGGLE_FOLLOW_URL = "${h.url('toggle_following')}";
60 var TOGGLE_FOLLOW_URL = "${h.url('toggle_following')}";
61
61
62 var REPO_NAME = "";
62 var REPO_NAME = "";
63 %if hasattr(c, 'repo_name'):
63 %if hasattr(c, 'repo_name'):
64 var REPO_NAME = "${c.repo_name}";
64 var REPO_NAME = "${c.repo_name}";
65 %endif
65 %endif
66 </script>
66 </script>
67 <script type="text/javascript" src="${h.url('/js/yui.2.9.js', ver=c.kallithea_version)}"></script>
67 <script type="text/javascript" src="${h.url('/js/yui.2.9.js', ver=c.kallithea_version)}"></script>
68 <script type="text/javascript" src="${h.url('/js/jquery-1.10.2.min.js', ver=c.kallithea_version)}"></script>
68 <script type="text/javascript" src="${h.url('/js/jquery-1.10.2.min.js', ver=c.kallithea_version)}"></script>
69 <script type="text/javascript" src="${h.url('/js/bootstrap.js', ver=c.kallithea_version)}"></script>
69 <script type="text/javascript" src="${h.url('/js/bootstrap.js', ver=c.kallithea_version)}"></script>
70 <script type="text/javascript" src="${h.url('/js/select2/select2.js', ver=c.kallithea_version)}"></script>
70 <script type="text/javascript" src="${h.url('/js/select2/select2.js', ver=c.kallithea_version)}"></script>
71 <script type="text/javascript" src="${h.url('/js/mousetrap.js', ver=c.kallithea_version)}"></script>
71 <script type="text/javascript" src="${h.url('/js/mousetrap.js', ver=c.kallithea_version)}"></script>
72 <!--[if lt IE 9]>
72 <!--[if lt IE 9]>
73 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
73 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
74 <![endif]-->
74 <![endif]-->
75 <script type="text/javascript" src="${h.url('/js/yui.flot.js', ver=c.kallithea_version)}"></script>
75 <script type="text/javascript" src="${h.url('/js/yui.flot.js', ver=c.kallithea_version)}"></script>
76 <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.kallithea_version)}"></script>
76 <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.kallithea_version)}"></script>
77 <script type="text/javascript" src="${h.url('/js/pyroutes_map.js', ver=c.kallithea_version)}"></script>
77 <script type="text/javascript" src="${h.url('/js/pyroutes_map.js', ver=c.kallithea_version)}"></script>
78 <script type="text/javascript" src="${h.url('/js/base.js', ver=c.kallithea_version)}"></script>
78 <script type="text/javascript" src="${h.url('/js/base.js', ver=c.kallithea_version)}"></script>
79 ## EXTRA FOR JS
79 ## EXTRA FOR JS
80 ${self.js_extra()}
80 ${self.js_extra()}
81 <script type="text/javascript">
81 <script type="text/javascript">
82 (function(window,undefined){
82 (function(window,undefined){
83 // Prepare
83 // Prepare
84 var History = window.History; // Note: We are using a capital H instead of a lower h
84 var History = window.History; // Note: We are using a capital H instead of a lower h
85 if ( !History.enabled ) {
85 if ( !History.enabled ) {
86 // History.js is disabled for this browser.
86 // History.js is disabled for this browser.
87 // This is because we can optionally choose to support HTML4 browsers or not.
87 // This is because we can optionally choose to support HTML4 browsers or not.
88 return false;
88 return false;
89 }
89 }
90 })(window);
90 })(window);
91
91
92 $(document).ready(function(){
92 $(document).ready(function(){
93 tooltip_activate();
93 tooltip_activate();
94 show_more_event();
94 show_more_event();
95 show_changeset_tooltip();
95 show_changeset_tooltip();
96 // routes registration
96 // routes registration
97 pyroutes.register('home', "${h.url('home')}", []);
97 pyroutes.register('home', "${h.url('home')}", []);
98 pyroutes.register('new_gist', "${h.url('new_gist')}", []);
98 pyroutes.register('new_gist', "${h.url('new_gist')}", []);
99 pyroutes.register('gists', "${h.url('gists')}", []);
99 pyroutes.register('gists', "${h.url('gists')}", []);
100 pyroutes.register('new_repo', "${h.url('new_repo')}", []);
100 pyroutes.register('new_repo', "${h.url('new_repo')}", []);
101
101
102 pyroutes.register('summary_home', "${h.url('summary_home', repo_name='%(repo_name)s')}", ['repo_name']);
102 pyroutes.register('summary_home', "${h.url('summary_home', repo_name='%(repo_name)s')}", ['repo_name']);
103 pyroutes.register('changelog_home', "${h.url('changelog_home', repo_name='%(repo_name)s')}", ['repo_name']);
103 pyroutes.register('changelog_home', "${h.url('changelog_home', repo_name='%(repo_name)s')}", ['repo_name']);
104 pyroutes.register('files_home', "${h.url('files_home', repo_name='%(repo_name)s',revision='%(revision)s',f_path='%(f_path)s')}", ['repo_name', 'revision', 'f_path']);
104 pyroutes.register('files_home', "${h.url('files_home', repo_name='%(repo_name)s',revision='%(revision)s',f_path='%(f_path)s')}", ['repo_name', 'revision', 'f_path']);
105 pyroutes.register('edit_repo', "${h.url('edit_repo', repo_name='%(repo_name)s')}", ['repo_name']);
105 pyroutes.register('edit_repo', "${h.url('edit_repo', repo_name='%(repo_name)s')}", ['repo_name']);
106 pyroutes.register('edit_repo_perms', "${h.url('edit_repo_perms', repo_name='%(repo_name)s')}", ['repo_name']);
106 pyroutes.register('edit_repo_perms', "${h.url('edit_repo_perms', repo_name='%(repo_name)s')}", ['repo_name']);
107 pyroutes.register('pullrequest_home', "${h.url('pullrequest_home', repo_name='%(repo_name)s')}", ['repo_name']);
107 pyroutes.register('pullrequest_home', "${h.url('pullrequest_home', repo_name='%(repo_name)s')}", ['repo_name']);
108
108
109 pyroutes.register('toggle_following', "${h.url('toggle_following')}");
109 pyroutes.register('toggle_following', "${h.url('toggle_following')}");
110 pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
110 pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
111 pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);
111 pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);
112 pyroutes.register('changeset_comment_preview', "${h.url('changeset_comment_preview', repo_name='%(repo_name)s')}", ['repo_name']);
112 pyroutes.register('changeset_comment_preview', "${h.url('changeset_comment_preview', repo_name='%(repo_name)s')}", ['repo_name']);
113 pyroutes.register('repo_refs_data', "${h.url('repo_refs_data', repo_name='%(repo_name)s')}", ['repo_name']);
113 pyroutes.register('repo_refs_data', "${h.url('repo_refs_data', repo_name='%(repo_name)s')}", ['repo_name']);
114 });
114 });
115 </script>
115 </script>
116 </%def>
116 </%def>
117 <%def name="js_extra()"></%def>
117 <%def name="js_extra()"></%def>
118 ${self.js()}
118 ${self.js()}
119 <%def name="head_extra()"></%def>
119 <%def name="head_extra()"></%def>
120 ${self.head_extra()}
120 ${self.head_extra()}
121 </head>
121 </head>
122 <body id="body">
122 <body id="body">
123 ## IE hacks
123 ## IE hacks
124 <!--[if IE 7]>
124 <!--[if IE 7]>
125 <script>$(document.body).addClass('ie7')</script>
125 <script>$(document.body).addClass('ie7')</script>
126 <![endif]-->
126 <![endif]-->
127 <!--[if IE 8]>
127 <!--[if IE 8]>
128 <script>$(document.body).addClass('ie8')</script>
128 <script>$(document.body).addClass('ie8')</script>
129 <![endif]-->
129 <![endif]-->
130 <!--[if IE 9]>
130 <!--[if IE 9]>
131 <script>$(document.body).addClass('ie9')</script>
131 <script>$(document.body).addClass('ie9')</script>
132 <![endif]-->
132 <![endif]-->
133
133
134 ${next.body()}
134 ${next.body()}
135
135
136 %if c.ga_code:
136 %if c.ga_code:
137 ${h.literal(c.ga_code)}
137 ${h.literal(c.ga_code)}
138 %endif
138 %endif
139 </body>
139 </body>
140 </html>
140 </html>
@@ -1,298 +1,298 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${_('%s Changelog') % c.repo_name}
6 ${_('%s Changelog') % c.repo_name}
7 %if c.changelog_for_path:
7 %if c.changelog_for_path:
8 /${c.changelog_for_path}
8 /${c.changelog_for_path}
9 %endif
9 %endif
10 %if c.site_name:
10 %if c.site_name:
11 &middot; ${c.site_name}
11 &middot; ${c.site_name}
12 %endif
12 %endif
13 </%def>
13 </%def>
14
14
15 <%def name="breadcrumbs_links()">
15 <%def name="breadcrumbs_links()">
16 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
16 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
17 ${_('Changelog')}
17 ${_('Changelog')}
18 %if c.changelog_for_path:
18 %if c.changelog_for_path:
19 - /${c.changelog_for_path}
19 - /${c.changelog_for_path}
20 %endif
20 %endif
21 %if c.revision:
21 %if c.revision:
22 @ ${h.short_id(c.first_revision.raw_id)}
22 @ ${h.short_id(c.first_revision.raw_id)}
23 %endif
23 %endif
24 - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
24 - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
25 </%def>
25 </%def>
26
26
27 <%def name="page_nav()">
27 <%def name="page_nav()">
28 ${self.menu('repositories')}
28 ${self.menu('repositories')}
29 </%def>
29 </%def>
30
30
31 <%def name="main()">
31 <%def name="main()">
32 ${self.repo_context_bar('changelog', c.first_revision.raw_id if c.first_revision else None)}
32 ${self.repo_context_bar('changelog', c.first_revision.raw_id if c.first_revision else None)}
33 <div class="box">
33 <div class="box">
34 <!-- box / title -->
34 <!-- box / title -->
35 <div class="title">
35 <div class="title">
36 ${self.breadcrumbs()}
36 ${self.breadcrumbs()}
37 </div>
37 </div>
38 <div class="table">
38 <div class="table">
39 % if c.pagination:
39 % if c.pagination:
40 <div>
40 <div>
41 <div style="overflow:auto; display:${'none' if c.changelog_for_path else ''}">
41 <div style="overflow:auto; display:${'none' if c.changelog_for_path else ''}">
42 <div class="container_header">
42 <div class="container_header">
43 <div style="float:left; margin-left:20px;">
43 <div style="float:left; margin-left:20px;">
44 ${h.form(h.url.current(),method='get')}
44 ${h.form(h.url.current(),method='get')}
45 ${h.submit('set',_('Show'),class_="btn btn-small")}
45 ${h.submit('set',_('Show'),class_="btn btn-small")}
46 ${h.text('size',size=3,value=c.size)}
46 ${h.text('size',size=3,value=c.size)}
47 ${_('revisions')}
47 ${_('revisions')}
48 %if c.branch_name:
48 %if c.branch_name:
49 ${h.hidden('branch', c.branch_name)}
49 ${h.hidden('branch', c.branch_name)}
50 %endif
50 %endif
51 ${h.end_form()}
51 ${h.end_form()}
52 </div>
52 </div>
53 <div style="float: right; margin: 0px 0px 0px 4px">
53 <div style="float: right; margin: 0px 0px 0px 4px">
54 <a href="#" class="btn btn-small" id="rev_range_container" style="display:none"></a>
54 <a href="#" class="btn btn-small" id="rev_range_container" style="display:none"></a>
55 <a href="#" class="btn btn-small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
55 <a href="#" class="btn btn-small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
56 %if c.revision:
56 %if c.revision:
57 <a class="btn btn-small" href="${h.url('changelog_home', repo_name=c.repo_name)}">
57 <a class="btn btn-small" href="${h.url('changelog_home', repo_name=c.repo_name)}">
58 ${_('Go to tip of repository')}
58 ${_('Go to tip of repository')}
59 </a>
59 </a>
60 %endif
60 %endif
61 %if c.db_repo.fork:
61 %if c.db_repo.fork:
62 <a id="compare_fork"
62 <a id="compare_fork"
63 title="${_('Compare fork with %s' % c.db_repo.fork.repo_name)}"
63 title="${_('Compare fork with %s' % c.db_repo.fork.repo_name)}"
64 href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1],other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}"
64 href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1],other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}"
65 class="btn btn-small"><i class="icon-loop"></i> ${_('Compare fork with parent repo (%s)' % c.db_repo.fork.repo_name)}</a>
65 class="btn btn-small"><i class="icon-loop"></i> ${_('Compare fork with parent repo (%s)' % c.db_repo.fork.repo_name)}</a>
66 %endif
66 %endif
67 ## text and href of open_new_pr is controlled from javascript
67 ## text and href of open_new_pr is controlled from javascript
68 <a id="open_new_pr" class="btn btn-small"></a>
68 <a id="open_new_pr" class="btn btn-small"></a>
69 ${_("Branch filter:")} ${h.select('branch_filter',c.branch_name,c.branch_filters)}
69 ${_("Branch filter:")} ${h.select('branch_filter',c.branch_name,c.branch_filters)}
70 </div>
70 </div>
71 </div>
71 </div>
72 </div>
72 </div>
73
73
74 <div id="changelog" style="clear:both">
74 <div id="changelog" style="clear:both">
75
75
76 <div id="graph_nodes">
76 <div id="graph_nodes">
77 <canvas id="graph_canvas"></canvas>
77 <canvas id="graph_canvas"></canvas>
78 </div>
78 </div>
79 <div id="graph_content" style="${'margin: 0px' if c.changelog_for_path else ''}">
79 <div id="graph_content" style="${'margin: 0px' if c.changelog_for_path else ''}">
80
80
81 <table id="changesets">
81 <table id="changesets">
82 <tbody>
82 <tbody>
83 %for cnt,cs in enumerate(c.pagination):
83 %for cnt,cs in enumerate(c.pagination):
84 <tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
84 <tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
85 <td class="checkbox">
85 <td class="checkbox">
86 %if c.changelog_for_path:
86 %if c.changelog_for_path:
87 ${h.checkbox(cs.raw_id,class_="changeset_range", disabled="disabled")}
87 ${h.checkbox(cs.raw_id,class_="changeset_range", disabled="disabled")}
88 %else:
88 %else:
89 ${h.checkbox(cs.raw_id,class_="changeset_range")}
89 ${h.checkbox(cs.raw_id,class_="changeset_range")}
90 %endif
90 %endif
91 <td class="status">
91 <td class="status">
92 %if c.statuses.get(cs.raw_id):
92 %if c.statuses.get(cs.raw_id):
93 <div class="changeset-status-ico">
93 <div class="changeset-status-ico">
94 %if c.statuses.get(cs.raw_id)[2]:
94 %if c.statuses.get(cs.raw_id)[2]:
95 <a class="tooltip" title="${_('Changeset status: %s\nClick to open associated pull request #%s') % (h.changeset_status_lbl(c.statuses.get(cs.raw_id)[0]), c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
95 <a class="tooltip" title="${_('Changeset status: %s\nClick to open associated pull request #%s') % (h.changeset_status_lbl(c.statuses.get(cs.raw_id)[0]), c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
96 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
96 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
97 </a>
97 </a>
98 %else:
98 %else:
99 <a class="tooltip" title="${_('Changeset status: %s') % h.changeset_status_lbl(c.statuses.get(cs.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
99 <a class="tooltip" title="${_('Changeset status: %s') % h.changeset_status_lbl(c.statuses.get(cs.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
100 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
100 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
101 </a>
101 </a>
102 %endif
102 %endif
103 </div>
103 </div>
104 %endif
104 %endif
105 </td>
105 </td>
106 <td class="author">
106 <td class="author">
107 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
107 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
108 <span title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</span>
108 <span title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</span>
109 </td>
109 </td>
110 <td class="hash" style="width:${len(h.show_id(cs))*6.5}px">
110 <td class="hash" style="width:${len(h.show_id(cs))*6.5}px">
111 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
111 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
112 <span class="changeset_hash">${h.show_id(cs)}</span>
112 <span class="changeset_hash">${h.show_id(cs)}</span>
113 </a>
113 </a>
114 </td>
114 </td>
115 <td class="date">
115 <td class="date">
116 <div class="date">${h.age(cs.date,True)}</div>
116 <div class="date">${h.age(cs.date,True)}</div>
117 </td>
117 </td>
118 <td class="expand_commit" commit_id="${cs.raw_id}" title="${_('Expand commit message')}">
118 <td class="expand_commit" commit_id="${cs.raw_id}" title="${_('Expand commit message')}">
119 <i class="icon-resize-vertical" style="color:#DDD"></i>
119 <i class="icon-resize-vertical" style="color:#DDD"></i>
120 </td>
120 </td>
121 <td class="mid">
121 <td class="mid">
122 <div class="log-container">
122 <div class="log-container">
123 <div class="message" id="C-${cs.raw_id}">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
123 <div class="message" id="C-${cs.raw_id}">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
124 <div class="extra-container">
124 <div class="extra-container">
125 %if c.comments.get(cs.raw_id):
125 %if c.comments.get(cs.raw_id):
126 <div class="comments-container">
126 <div class="comments-container">
127 <div class="comments-cnt" title="${_('Changeset has comments')}">
127 <div class="comments-cnt" title="${_('Changeset has comments')}">
128 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
128 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
129 ${len(c.comments[cs.raw_id])}
129 ${len(c.comments[cs.raw_id])}
130 <i class="icon-comment-alt icon-comment-colored"></i>
130 <i class="icon-comment-alt icon-comment-colored"></i>
131 </a>
131 </a>
132 </div>
132 </div>
133 </div>
133 </div>
134 %endif
134 %endif
135 %if h.is_hg(c.db_repo_scm_instance):
135 %if h.is_hg(c.db_repo_scm_instance):
136 %for book in cs.bookmarks:
136 %for book in cs.bookmarks:
137 <div class="booktag" title="${_('Bookmark %s') % book}">
137 <div class="booktag" title="${_('Bookmark %s') % book}">
138 ${h.link_to(book,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
138 ${h.link_to(book,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
139 </div>
139 </div>
140 %endfor
140 %endfor
141 %endif
141 %endif
142 %for tag in cs.tags:
142 %for tag in cs.tags:
143 <div class="tagtag" title="${_('Tag %s') % tag}">
143 <div class="tagtag" title="${_('Tag %s') % tag}">
144 ${h.link_to(tag,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
144 ${h.link_to(tag,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
145 </div>
145 </div>
146 %endfor
146 %endfor
147 %if (not c.branch_name) and cs.branch:
147 %if (not c.branch_name) and cs.branch:
148 <div class="branchtag" title="${_('Branch %s' % cs.branch)}">
148 <div class="branchtag" title="${_('Branch %s' % cs.branch)}">
149 ${h.link_to(cs.branch,h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
149 ${h.link_to(cs.branch,h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
150 </div>
150 </div>
151 %endif
151 %endif
152 </div>
152 </div>
153 </div>
153 </div>
154 </td>
154 </td>
155 </tr>
155 </tr>
156 %endfor
156 %endfor
157 </tbody>
157 </tbody>
158 </table>
158 </table>
159
159
160 </div>
160 </div>
161
161
162 <div class="pagination-wh pagination-left">
162 <div class="pagination-wh pagination-left">
163 ${c.pagination.pager('$link_previous ~2~ $link_next')}
163 ${c.pagination.pager('$link_previous ~2~ $link_next')}
164 </div>
164 </div>
165 </div>
165 </div>
166 </div>
166 </div>
167
167
168 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
168 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
169 <script type="text/javascript">
169 <script type="text/javascript">
170 $(document).ready(function(){
170 $(document).ready(function(){
171 //Monitor range checkboxes and build a link to changesets ranges
171 //Monitor range checkboxes and build a link to changesets ranges
172 var checkboxes = YUD.getElementsByClassName('changeset_range');
172 var checkboxes = YUD.getElementsByClassName('changeset_range');
173 // register extra routes needed for this view
173 // register extra routes needed for this view
174 pyroutes.register('changeset_home', "${h.url('changeset_home', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
174 pyroutes.register('changeset_home', "${h.url('changeset_home', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
175
175
176 var checkbox_checker = function(e){
176 var checkbox_checker = function(e){
177 var checked_checkboxes = [];
177 var checked_checkboxes = [];
178 for (pos in checkboxes){
178 for (pos in checkboxes){
179 if(checkboxes[pos].checked){
179 if(checkboxes[pos].checked){
180 checked_checkboxes.push(checkboxes[pos]);
180 checked_checkboxes.push(checkboxes[pos]);
181 }
181 }
182 }
182 }
183 if(YUD.get('open_new_pr')){
183 if(YUD.get('open_new_pr')){
184 if(checked_checkboxes.length>1){
184 if(checked_checkboxes.length>1){
185 YUD.setStyle('open_new_pr','display','none');
185 YUD.setStyle('open_new_pr','display','none');
186 } else {
186 } else {
187 YUD.setStyle('open_new_pr','display','');
187 YUD.setStyle('open_new_pr','display','');
188 if(checked_checkboxes.length>0){
188 if(checked_checkboxes.length>0){
189 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
189 YUD.get('open_new_pr').innerHTML = _TM['Open New Pull Request for Selected Changesets'];
190 }else{
190 }else{
191 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
191 YUD.get('open_new_pr').innerHTML = _TM['Open New Pull Request'];
192 }
192 }
193 }
193 }
194 }
194 }
195
195
196 if(checked_checkboxes.length>0){
196 if(checked_checkboxes.length>0){
197 var rev_end = checked_checkboxes[0].name;
197 var rev_end = checked_checkboxes[0].name;
198 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
198 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
199 var url = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}',
199 var url = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}',
200 'revision': rev_start+'...'+rev_end});
200 'revision': rev_start+'...'+rev_end});
201
201
202 var link = (rev_start == rev_end)
202 var link = (rev_start == rev_end)
203 ? _TM['Show selected changeset __S']
203 ? _TM['Show Selected Changeset __S']
204 : _TM['Show selected changesets __S &rarr; __E'];
204 : _TM['Show Selected Changesets __S &rarr; __E'];
205
205
206 link = link.replace('__S',rev_start.substr(0,6));
206 link = link.replace('__S',rev_start.substr(0,6));
207 link = link.replace('__E',rev_end.substr(0,6));
207 link = link.replace('__E',rev_end.substr(0,6));
208 YUD.get('rev_range_container').href = url;
208 YUD.get('rev_range_container').href = url;
209 YUD.get('rev_range_container').innerHTML = link;
209 YUD.get('rev_range_container').innerHTML = link;
210 YUD.setStyle('rev_range_container','display','');
210 YUD.setStyle('rev_range_container','display','');
211 YUD.setStyle('rev_range_clear','display','');
211 YUD.setStyle('rev_range_clear','display','');
212
212
213 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
213 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
214 {'repo_name': '${c.repo_name}',
214 {'repo_name': '${c.repo_name}',
215 'rev_start': rev_start,
215 'rev_start': rev_start,
216 'rev_end': rev_end})
216 'rev_end': rev_end})
217
217
218 YUD.setStyle('compare_fork','display','none');
218 YUD.setStyle('compare_fork','display','none');
219 }else{
219 }else{
220 YUD.setStyle('rev_range_container','display','none');
220 YUD.setStyle('rev_range_container','display','none');
221 YUD.setStyle('rev_range_clear','display','none');
221 YUD.setStyle('rev_range_clear','display','none');
222 %if c.revision:
222 %if c.revision:
223 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
223 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
224 {'repo_name': '${c.repo_name}',
224 {'repo_name': '${c.repo_name}',
225 'rev_end':'${c.first_revision.raw_id}'});
225 'rev_end':'${c.first_revision.raw_id}'});
226 %else:
226 %else:
227 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
227 YUD.get('open_new_pr').href = pyroutes.url('pullrequest_home',
228 {'repo_name': '${c.repo_name}',
228 {'repo_name': '${c.repo_name}',
229 'branch':'${c.first_revision.branch}'});
229 'branch':'${c.first_revision.branch}'});
230 %endif
230 %endif
231 YUD.setStyle('compare_fork','display','');
231 YUD.setStyle('compare_fork','display','');
232 }
232 }
233 };
233 };
234 checkbox_checker();
234 checkbox_checker();
235 YUE.on(checkboxes,'click', checkbox_checker);
235 YUE.on(checkboxes,'click', checkbox_checker);
236
236
237 YUE.on('rev_range_clear','click',function(e){
237 YUE.on('rev_range_clear','click',function(e){
238 for (var i=0; i<checkboxes.length; i++){
238 for (var i=0; i<checkboxes.length; i++){
239 var cb = checkboxes[i];
239 var cb = checkboxes[i];
240 cb.checked = false;
240 cb.checked = false;
241 }
241 }
242 checkbox_checker();
242 checkbox_checker();
243 YUE.preventDefault(e);
243 YUE.preventDefault(e);
244 });
244 });
245
245
246 var msgs = YUQ('.message');
246 var msgs = YUQ('.message');
247 // get first element height
247 // get first element height
248 var el = YUQ('#graph_content .container')[0];
248 var el = YUQ('#graph_content .container')[0];
249 var row_h = el.clientHeight;
249 var row_h = el.clientHeight;
250 for(var i=0;i<msgs.length;i++){
250 for(var i=0;i<msgs.length;i++){
251 var m = msgs[i];
251 var m = msgs[i];
252
252
253 var h = m.clientHeight;
253 var h = m.clientHeight;
254 var pad = YUD.getStyle(m,'padding');
254 var pad = YUD.getStyle(m,'padding');
255 if(h > row_h){
255 if(h > row_h){
256 var offset = row_h - (h+12);
256 var offset = row_h - (h+12);
257 YUD.setStyle(m.nextElementSibling,'display','block');
257 YUD.setStyle(m.nextElementSibling,'display','block');
258 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
258 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
259 };
259 };
260 }
260 }
261
261
262 $('.expand_commit').on('click',function(e){
262 $('.expand_commit').on('click',function(e){
263 var cid = $(this).attr('commit_id');
263 var cid = $(this).attr('commit_id');
264 $('#C-'+cid).toggleClass('expanded');
264 $('#C-'+cid).toggleClass('expanded');
265
265
266 //redraw the graph, r and jsdata are bound outside function
266 //redraw the graph, r and jsdata are bound outside function
267 r.render(jsdata,100);
267 r.render(jsdata,100);
268 });
268 });
269
269
270 // change branch filter
270 // change branch filter
271 $("#branch_filter").select2({
271 $("#branch_filter").select2({
272 dropdownAutoWidth: true,
272 dropdownAutoWidth: true,
273 minimumInputLength: 1
273 minimumInputLength: 1
274 });
274 });
275
275
276 $("#branch_filter").change(function(e){
276 $("#branch_filter").change(function(e){
277 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
277 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
278 if(selected_branch != ''){
278 if(selected_branch != ''){
279 window.location = pyroutes.url('changelog_home', {'repo_name': '${c.repo_name}',
279 window.location = pyroutes.url('changelog_home', {'repo_name': '${c.repo_name}',
280 'branch': selected_branch});
280 'branch': selected_branch});
281 }else{
281 }else{
282 window.location = pyroutes.url('changelog_home', {'repo_name': '${c.repo_name}'});
282 window.location = pyroutes.url('changelog_home', {'repo_name': '${c.repo_name}'});
283 }
283 }
284 $("#changelog").hide();
284 $("#changelog").hide();
285 });
285 });
286
286
287 var jsdata = ${c.jsdata|n};
287 var jsdata = ${c.jsdata|n};
288 var r = new BranchRenderer('graph_canvas', 'graph_content');
288 var r = new BranchRenderer('graph_canvas', 'graph_content');
289 r.render(jsdata,100);
289 r.render(jsdata,100);
290 });
290 });
291
291
292 </script>
292 </script>
293 %else:
293 %else:
294 ${_('There are no changes yet')}
294 ${_('There are no changes yet')}
295 %endif
295 %endif
296 </div>
296 </div>
297 </div>
297 </div>
298 </%def>
298 </%def>
@@ -1,113 +1,113 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 %if c.repo_changesets:
2 %if c.repo_changesets:
3 <table class="table_disp">
3 <table class="table_disp">
4 <tr>
4 <tr>
5 <th class="left">${_('Revision')}</th>
5 <th class="left">${_('Revision')}</th>
6 <th class="left">${_('Commit message')}</th>
6 <th class="left">${_('Commit Message')}</th>
7 <th class="left">${_('Age')}</th>
7 <th class="left">${_('Age')}</th>
8 <th class="left">${_('Author')}</th>
8 <th class="left">${_('Author')}</th>
9 <th class="left">${_('Refs')}</th>
9 <th class="left">${_('Refs')}</th>
10 </tr>
10 </tr>
11 %for cnt,cs in enumerate(c.repo_changesets):
11 %for cnt,cs in enumerate(c.repo_changesets):
12 <tr class="parity${cnt%2}">
12 <tr class="parity${cnt%2}">
13 <td>
13 <td>
14 <div>
14 <div>
15 <div class="changeset-status-container">
15 <div class="changeset-status-container">
16 %if c.statuses.get(cs.raw_id):
16 %if c.statuses.get(cs.raw_id):
17 <div class="changeset-status-ico shortlog">
17 <div class="changeset-status-ico shortlog">
18 %if c.statuses.get(cs.raw_id)[2]:
18 %if c.statuses.get(cs.raw_id)[2]:
19 <a class="tooltip" title="${_('Changeset status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
19 <a class="tooltip" title="${_('Changeset status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
20 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
20 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
21 </a>
21 </a>
22 %else:
22 %else:
23 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
23 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
24 %endif
24 %endif
25 </div>
25 </div>
26 %endif
26 %endif
27 %if c.comments.get(cs.raw_id,[]):
27 %if c.comments.get(cs.raw_id,[]):
28 <div class="comments-container">
28 <div class="comments-container">
29 <div title="${('comments')}">
29 <div title="${('comments')}">
30 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
30 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
31 <i class="icon-comment-alt icon-comment-colored"></i> ${len(c.comments[cs.raw_id])}
31 <i class="icon-comment-alt icon-comment-colored"></i> ${len(c.comments[cs.raw_id])}
32 </a>
32 </a>
33 </div>
33 </div>
34 </div>
34 </div>
35 %endif
35 %endif
36 </div>
36 </div>
37 <pre><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${h.show_id(cs)}</a></pre>
37 <pre><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${h.show_id(cs)}</a></pre>
38 </div>
38 </div>
39 </td>
39 </td>
40 <td>
40 <td>
41 ${h.urlify_commit(h.truncate(cs.message,50),c.repo_name, h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
41 ${h.urlify_commit(h.truncate(cs.message,50),c.repo_name, h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
42 </td>
42 </td>
43 <td><span class="tooltip" title="${h.tooltip(h.fmt_date(cs.date))}">
43 <td><span class="tooltip" title="${h.tooltip(h.fmt_date(cs.date))}">
44 ${h.age(cs.date)}</span>
44 ${h.age(cs.date)}</span>
45 </td>
45 </td>
46 <td title="${cs.author}">${h.person(cs.author)}</td>
46 <td title="${cs.author}">${h.person(cs.author)}</td>
47 <td>
47 <td>
48 %if h.is_hg(c.db_repo_scm_instance):
48 %if h.is_hg(c.db_repo_scm_instance):
49 %for book in cs.bookmarks:
49 %for book in cs.bookmarks:
50 <div class="booktag" title="${_('Bookmark %s') % book}">
50 <div class="booktag" title="${_('Bookmark %s') % book}">
51 ${h.link_to(book,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
51 ${h.link_to(book,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
52 </div>
52 </div>
53 %endfor
53 %endfor
54 %endif
54 %endif
55 %for tag in cs.tags:
55 %for tag in cs.tags:
56 <div class="tagtag" title="${_('Tag %s') % tag}">
56 <div class="tagtag" title="${_('Tag %s') % tag}">
57 ${h.link_to(tag,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
57 ${h.link_to(tag,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
58 </div>
58 </div>
59 %endfor
59 %endfor
60 %if cs.branch:
60 %if cs.branch:
61 <div class="branchtag" title="${_('Branch %s' % cs.branch)}">
61 <div class="branchtag" title="${_('Branch %s' % cs.branch)}">
62 ${h.link_to(cs.branch,h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
62 ${h.link_to(cs.branch,h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
63 </div>
63 </div>
64 %endif
64 %endif
65 </td>
65 </td>
66 </tr>
66 </tr>
67 %endfor
67 %endfor
68
68
69 </table>
69 </table>
70
70
71 <script type="text/javascript">
71 <script type="text/javascript">
72 $(document).ready(function(){
72 $(document).ready(function(){
73 var $shortlog_data = $('#shortlog_data');
73 var $shortlog_data = $('#shortlog_data');
74 $shortlog_data.on('click','.pager_link',function(e){
74 $shortlog_data.on('click','.pager_link',function(e){
75 asynchtml(e.target.href, $shortlog_data, function(){tooltip_activate();});
75 asynchtml(e.target.href, $shortlog_data, function(){tooltip_activate();});
76 e.preventDefault();
76 e.preventDefault();
77 });
77 });
78 });
78 });
79 </script>
79 </script>
80
80
81 <div class="pagination-wh pagination-left">
81 <div class="pagination-wh pagination-left">
82 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
82 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
83 </div>
83 </div>
84 %else:
84 %else:
85
85
86 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
86 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
87 <h4>${_('Add or upload files directly via Kallithea')}</h4>
87 <h4>${_('Add or upload files directly via Kallithea')}</h4>
88 <div style="margin: 20px 30px;">
88 <div style="margin: 20px 30px;">
89 <div id="add_node_id" class="add_node">
89 <div id="add_node_id" class="add_node">
90 <a class="btn btn-mini" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='', anchor='edit')}">${_('Add New File')}</a>
90 <a class="btn btn-mini" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='', anchor='edit')}">${_('Add New File')}</a>
91 </div>
91 </div>
92 </div>
92 </div>
93 %endif
93 %endif
94
94
95
95
96 <h4>${_('Push new repo')}</h4>
96 <h4>${_('Push new repo')}</h4>
97 <pre>
97 <pre>
98 ${c.db_repo_scm_instance.alias} clone ${c.clone_repo_url}
98 ${c.db_repo_scm_instance.alias} clone ${c.clone_repo_url}
99 ${c.db_repo_scm_instance.alias} add README # add first file
99 ${c.db_repo_scm_instance.alias} add README # add first file
100 ${c.db_repo_scm_instance.alias} commit -m "Initial" # commit with message
100 ${c.db_repo_scm_instance.alias} commit -m "Initial" # commit with message
101 ${c.db_repo_scm_instance.alias} push ${'origin master' if h.is_git(c.db_repo_scm_instance) else ''} # push changes back
101 ${c.db_repo_scm_instance.alias} push ${'origin master' if h.is_git(c.db_repo_scm_instance) else ''} # push changes back
102 </pre>
102 </pre>
103
103
104 <h4>${_('Existing repository?')}</h4>
104 <h4>${_('Existing repository?')}</h4>
105 <pre>
105 <pre>
106 %if h.is_git(c.db_repo_scm_instance):
106 %if h.is_git(c.db_repo_scm_instance):
107 git remote add origin ${c.clone_repo_url}
107 git remote add origin ${c.clone_repo_url}
108 git push -u origin master
108 git push -u origin master
109 %else:
109 %else:
110 hg push ${c.clone_repo_url}
110 hg push ${c.clone_repo_url}
111 %endif
111 %endif
112 </pre>
112 </pre>
113 %endif
113 %endif
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now