##// END OF EJS Templates
fixed small issues with adding new filenodes
marcink -
r1484:1db451a4 beta
parent child Browse files
Show More
@@ -1,496 +1,500 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.files
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Files controller for RhodeCode
7 7
8 8 :created_on: Apr 21, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import traceback
29 29
30 30 from os.path import join as jn
31 31
32 32 from pylons import request, response, session, tmpl_context as c, url
33 33 from pylons.i18n.translation import _
34 34 from pylons.controllers.util import redirect
35 35 from pylons.decorators import jsonify
36 36
37 37 from vcs.conf import settings
38 38 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
39 39 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
40 40 from vcs.nodes import FileNode, NodeKind
41 41 from vcs.utils import diffs as differ
42 42
43 43 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
44 44 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
45 45 from rhodecode.lib.base import BaseRepoController, render
46 46 from rhodecode.lib.utils import EmptyChangeset
47 47 import rhodecode.lib.helpers as h
48 48 from rhodecode.model.repo import RepoModel
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52
53 53 class FilesController(BaseRepoController):
54 54
55 55 @LoginRequired()
56 56 def __before__(self):
57 57 super(FilesController, self).__before__()
58 58 c.cut_off_limit = self.cut_off_limit
59 59
60 60 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
61 61 """
62 62 Safe way to get changeset if error occur it redirects to tip with
63 63 proper message
64 64
65 65 :param rev: revision to fetch
66 66 :param repo_name: repo name to redirect after
67 67 """
68 68
69 69 try:
70 70 return c.rhodecode_repo.get_changeset(rev)
71 71 except EmptyRepositoryError, e:
72 72 if not redirect_after:
73 73 return None
74 74 url_ = url('files_add_home',
75 75 repo_name=c.repo_name,
76 76 revision=0,f_path='')
77 77 add_new = '<a href="%s">[%s]</a>' % (url_,_('add new'))
78 78 h.flash(h.literal(_('There are no files yet %s' % add_new)),
79 79 category='warning')
80 80 redirect(h.url('summary_home', repo_name=repo_name))
81 81
82 82 except RepositoryError, e:
83 83 h.flash(str(e), category='warning')
84 84 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
85 85
86 86 def __get_filenode_or_redirect(self, repo_name, cs, path):
87 87 """
88 88 Returns file_node, if error occurs or given path is directory,
89 89 it'll redirect to top level path
90 90
91 91 :param repo_name: repo_name
92 92 :param cs: given changeset
93 93 :param path: path to lookup
94 94 """
95 95
96 96 try:
97 97 file_node = cs.get_node(path)
98 98 if file_node.is_dir():
99 99 raise RepositoryError('given path is a directory')
100 100 except RepositoryError, e:
101 101 h.flash(str(e), category='warning')
102 102 redirect(h.url('files_home', repo_name=repo_name,
103 103 revision=cs.raw_id))
104 104
105 105 return file_node
106 106
107 107
108 108 def __get_paths(self, changeset, starting_path):
109 109 """recursive walk in root dir and return a set of all path in that dir
110 110 based on repository walk function
111 111 """
112 112 _files = list()
113 113 _dirs = list()
114 114
115 115 try:
116 116 tip = changeset
117 117 for topnode, dirs, files in tip.walk(starting_path):
118 118 for f in files:
119 119 _files.append(f.path)
120 120 for d in dirs:
121 121 _dirs.append(d.path)
122 122 except RepositoryError, e:
123 123 log.debug(traceback.format_exc())
124 124 pass
125 125 return _dirs, _files
126 126
127 127 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
128 128 'repository.admin')
129 129 def index(self, repo_name, revision, f_path):
130 130 #reditect to given revision from form if given
131 131 post_revision = request.POST.get('at_rev', None)
132 132 if post_revision:
133 133 cs = self.__get_cs_or_redirect(post_revision, repo_name)
134 134 redirect(url('files_home', repo_name=c.repo_name,
135 135 revision=cs.raw_id, f_path=f_path))
136 136
137 137 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
138 138 c.branch = request.GET.get('branch', None)
139 139 c.f_path = f_path
140 140
141 141 cur_rev = c.changeset.revision
142 142
143 143 #prev link
144 144 try:
145 145 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
146 146 c.url_prev = url('files_home', repo_name=c.repo_name,
147 147 revision=prev_rev.raw_id, f_path=f_path)
148 148 if c.branch:
149 149 c.url_prev += '?branch=%s' % c.branch
150 150 except (ChangesetDoesNotExistError, VCSError):
151 151 c.url_prev = '#'
152 152
153 153 #next link
154 154 try:
155 155 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
156 156 c.url_next = url('files_home', repo_name=c.repo_name,
157 157 revision=next_rev.raw_id, f_path=f_path)
158 158 if c.branch:
159 159 c.url_next += '?branch=%s' % c.branch
160 160 except (ChangesetDoesNotExistError, VCSError):
161 161 c.url_next = '#'
162 162
163 163 #files or dirs
164 164 try:
165 165 c.files_list = c.changeset.get_node(f_path)
166 166
167 167 if c.files_list.is_file():
168 168 c.file_history = self._get_node_history(c.changeset, f_path)
169 169 else:
170 170 c.file_history = []
171 171 except RepositoryError, e:
172 172 h.flash(str(e), category='warning')
173 173 redirect(h.url('files_home', repo_name=repo_name,
174 174 revision=revision))
175 175
176 176 return render('files/files.html')
177 177
178 178 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 179 'repository.admin')
180 180 def rawfile(self, repo_name, revision, f_path):
181 181 cs = self.__get_cs_or_redirect(revision, repo_name)
182 182 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
183 183
184 184 response.content_disposition = 'attachment; filename=%s' % \
185 185 safe_str(f_path.split(os.sep)[-1])
186 186
187 187 response.content_type = file_node.mimetype
188 188 return file_node.content
189 189
190 190 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
191 191 'repository.admin')
192 192 def raw(self, repo_name, revision, f_path):
193 193 cs = self.__get_cs_or_redirect(revision, repo_name)
194 194 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
195 195
196 196 raw_mimetype_mapping = {
197 197 # map original mimetype to a mimetype used for "show as raw"
198 198 # you can also provide a content-disposition to override the
199 199 # default "attachment" disposition.
200 200 # orig_type: (new_type, new_dispo)
201 201
202 202 # show images inline:
203 203 'image/x-icon': ('image/x-icon', 'inline'),
204 204 'image/png': ('image/png', 'inline'),
205 205 'image/gif': ('image/gif', 'inline'),
206 206 'image/jpeg': ('image/jpeg', 'inline'),
207 207 'image/svg+xml': ('image/svg+xml', 'inline'),
208 208 }
209 209
210 210 mimetype = file_node.mimetype
211 211 try:
212 212 mimetype, dispo = raw_mimetype_mapping[mimetype]
213 213 except KeyError:
214 214 # we don't know anything special about this, handle it safely
215 215 if file_node.is_binary:
216 216 # do same as download raw for binary files
217 217 mimetype, dispo = 'application/octet-stream', 'attachment'
218 218 else:
219 219 # do not just use the original mimetype, but force text/plain,
220 220 # otherwise it would serve text/html and that might be unsafe.
221 221 # Note: underlying vcs library fakes text/plain mimetype if the
222 222 # mimetype can not be determined and it thinks it is not
223 223 # binary.This might lead to erroneous text display in some
224 224 # cases, but helps in other cases, like with text files
225 225 # without extension.
226 226 mimetype, dispo = 'text/plain', 'inline'
227 227
228 228 if dispo == 'attachment':
229 229 dispo = 'attachment; filename=%s' % \
230 230 safe_str(f_path.split(os.sep)[-1])
231 231
232 232 response.content_disposition = dispo
233 233 response.content_type = mimetype
234 234 return file_node.content
235 235
236 236 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
237 237 'repository.admin')
238 238 def annotate(self, repo_name, revision, f_path):
239 239 c.cs = self.__get_cs_or_redirect(revision, repo_name)
240 240 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
241 241
242 242 c.file_history = self._get_node_history(c.cs, f_path)
243 243 c.f_path = f_path
244 244 return render('files/files_annotate.html')
245 245
246 246 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
247 247 def edit(self, repo_name, revision, f_path):
248 248 r_post = request.POST
249 249
250 250 c.cs = self.__get_cs_or_redirect(revision, repo_name)
251 251 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
252 252
253 253 if c.file.is_binary:
254 254 return redirect(url('files_home', repo_name=c.repo_name,
255 255 revision=c.cs.raw_id, f_path=f_path))
256 256
257 257 c.f_path = f_path
258 258
259 259 if r_post:
260 260
261 261 old_content = c.file.content
262 262 sl = old_content.splitlines(1)
263 263 first_line = sl[0] if sl else ''
264 264 # modes: 0 - Unix, 1 - Mac, 2 - DOS
265 265 mode = detect_mode(first_line, 0)
266 266 content = convert_line_endings(r_post.get('content'), mode)
267 267
268 268 message = r_post.get('message') or (_('Edited %s via RhodeCode')
269 269 % (f_path))
270 270 author = self.rhodecode_user.full_contact
271 271
272 272 if content == old_content:
273 273 h.flash(_('No changes'),
274 274 category='warning')
275 275 return redirect(url('changeset_home', repo_name=c.repo_name,
276 276 revision='tip'))
277 277
278 278 try:
279 279 self.scm_model.commit_change(repo=c.rhodecode_repo,
280 280 repo_name=repo_name, cs=c.cs,
281 281 user=self.rhodecode_user,
282 282 author=author, message=message,
283 283 content=content, f_path=f_path)
284 284 h.flash(_('Successfully committed to %s' % f_path),
285 285 category='success')
286 286
287 287 except Exception:
288 288 log.error(traceback.format_exc())
289 289 h.flash(_('Error occurred during commit'), category='error')
290 290 return redirect(url('changeset_home',
291 291 repo_name=c.repo_name, revision='tip'))
292 292
293 293 return render('files/files_edit.html')
294 294
295 295 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
296 296 def add(self, repo_name, revision, f_path):
297 297 r_post = request.POST
298 298 c.cs = self.__get_cs_or_redirect(revision, repo_name,
299 299 redirect_after=False)
300 300 if c.cs is None:
301 301 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
302 302
303 303 c.f_path = f_path
304 304
305 305 if r_post:
306 306 unix_mode = 0
307 307 content = convert_line_endings(r_post.get('content'), unix_mode)
308 308
309 309 message = r_post.get('message') or (_('Added %s via RhodeCode')
310 310 % (f_path))
311 311 location = r_post.get('location')
312 312 filename = r_post.get('filename')
313 313 node_path = os.path.join(location, filename)
314 314 author = self.rhodecode_user.full_contact
315 315
316 316 if not content:
317 317 h.flash(_('No content'), category='warning')
318 318 return redirect(url('changeset_home', repo_name=c.repo_name,
319 319 revision='tip'))
320 if not filename:
321 h.flash(_('No filename'), category='warning')
322 return redirect(url('changeset_home', repo_name=c.repo_name,
323 revision='tip'))
320 324
321 325 try:
322 326 self.scm_model.create_node(repo=c.rhodecode_repo,
323 327 repo_name=repo_name, cs=c.cs,
324 328 user=self.rhodecode_user,
325 329 author=author, message=message,
326 330 content=content, f_path=node_path)
327 331 h.flash(_('Successfully committed to %s' % node_path),
328 332 category='success')
329 333
330 334 except Exception:
331 335 log.error(traceback.format_exc())
332 336 h.flash(_('Error occurred during commit'), category='error')
333 337 return redirect(url('changeset_home',
334 338 repo_name=c.repo_name, revision='tip'))
335 339
336 340 return render('files/files_add.html')
337 341
338 342 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
339 343 'repository.admin')
340 344 def archivefile(self, repo_name, fname):
341 345
342 346 fileformat = None
343 347 revision = None
344 348 ext = None
345 349 subrepos = request.GET.get('subrepos') == 'true'
346 350
347 351 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
348 352 archive_spec = fname.split(ext_data[1])
349 353 if len(archive_spec) == 2 and archive_spec[1] == '':
350 354 fileformat = a_type or ext_data[1]
351 355 revision = archive_spec[0]
352 356 ext = ext_data[1]
353 357
354 358 try:
355 359 dbrepo = RepoModel().get_by_repo_name(repo_name)
356 360 if dbrepo.enable_downloads is False:
357 361 return _('downloads disabled')
358 362
359 363 cs = c.rhodecode_repo.get_changeset(revision)
360 364 content_type = settings.ARCHIVE_SPECS[fileformat][0]
361 365 except ChangesetDoesNotExistError:
362 366 return _('Unknown revision %s') % revision
363 367 except EmptyRepositoryError:
364 368 return _('Empty repository')
365 369 except (ImproperArchiveTypeError, KeyError):
366 370 return _('Unknown archive type')
367 371
368 372 response.content_type = content_type
369 373 response.content_disposition = 'attachment; filename=%s-%s%s' \
370 374 % (repo_name, revision, ext)
371 375
372 376 import tempfile
373 377 archive = tempfile.mkstemp()[1]
374 378 t = open(archive, 'wb')
375 379 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
376 380
377 381 def get_chunked_archive(archive):
378 382 stream = open(archive, 'rb')
379 383 while True:
380 384 data = stream.read(4096)
381 385 if not data:
382 386 os.remove(archive)
383 387 break
384 388 yield data
385 389
386 390 return get_chunked_archive(archive)
387 391
388 392 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
389 393 'repository.admin')
390 394 def diff(self, repo_name, f_path):
391 395 diff1 = request.GET.get('diff1')
392 396 diff2 = request.GET.get('diff2')
393 397 c.action = request.GET.get('diff')
394 398 c.no_changes = diff1 == diff2
395 399 c.f_path = f_path
396 400 c.big_diff = False
397 401
398 402 try:
399 403 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
400 404 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
401 405 node1 = c.changeset_1.get_node(f_path)
402 406 else:
403 407 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
404 408 node1 = FileNode('.', '', changeset=c.changeset_1)
405 409
406 410 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
407 411 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
408 412 node2 = c.changeset_2.get_node(f_path)
409 413 else:
410 414 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
411 415 node2 = FileNode('.', '', changeset=c.changeset_2)
412 416 except RepositoryError:
413 417 return redirect(url('files_home',
414 418 repo_name=c.repo_name, f_path=f_path))
415 419
416 420 if c.action == 'download':
417 421 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
418 422 format='gitdiff')
419 423
420 424 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
421 425 response.content_type = 'text/plain'
422 426 response.content_disposition = 'attachment; filename=%s' \
423 427 % diff_name
424 428 return diff.raw_diff()
425 429
426 430 elif c.action == 'raw':
427 431 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
428 432 format='gitdiff')
429 433 response.content_type = 'text/plain'
430 434 return diff.raw_diff()
431 435
432 436 elif c.action == 'diff':
433 437 if node1.is_binary or node2.is_binary:
434 438 c.cur_diff = _('Binary file')
435 439 elif node1.size > self.cut_off_limit or \
436 440 node2.size > self.cut_off_limit:
437 441 c.cur_diff = ''
438 442 c.big_diff = True
439 443 else:
440 444 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
441 445 format='gitdiff')
442 446 c.cur_diff = diff.as_html()
443 447 else:
444 448
445 449 #default option
446 450 if node1.is_binary or node2.is_binary:
447 451 c.cur_diff = _('Binary file')
448 452 elif node1.size > self.cut_off_limit or \
449 453 node2.size > self.cut_off_limit:
450 454 c.cur_diff = ''
451 455 c.big_diff = True
452 456
453 457 else:
454 458 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
455 459 format='gitdiff')
456 460 c.cur_diff = diff.as_html()
457 461
458 462 if not c.cur_diff and not c.big_diff:
459 463 c.no_changes = True
460 464 return render('files/file_diff.html')
461 465
462 466 def _get_node_history(self, cs, f_path):
463 467 changesets = cs.get_file_history(f_path)
464 468 hist_l = []
465 469
466 470 changesets_group = ([], _("Changesets"))
467 471 branches_group = ([], _("Branches"))
468 472 tags_group = ([], _("Tags"))
469 473
470 474 for chs in changesets:
471 475 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
472 476 changesets_group[0].append((chs.raw_id, n_desc,))
473 477
474 478 hist_l.append(changesets_group)
475 479
476 480 for name, chs in c.rhodecode_repo.branches.items():
477 481 #chs = chs.split(':')[-1]
478 482 branches_group[0].append((chs, name),)
479 483 hist_l.append(branches_group)
480 484
481 485 for name, chs in c.rhodecode_repo.tags.items():
482 486 #chs = chs.split(':')[-1]
483 487 tags_group[0].append((chs, name),)
484 488 hist_l.append(tags_group)
485 489
486 490 return hist_l
487 491
488 492 @jsonify
489 493 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
490 494 'repository.admin')
491 495 def nodelist(self, repo_name, revision, f_path):
492 496 if request.environ.get('HTTP_X_PARTIAL_XHR'):
493 497 cs = self.__get_cs_or_redirect(revision, repo_name)
494 498 _d, _f = self.__get_paths(cs, f_path)
495 499 return _d + _f
496 500
@@ -1,85 +1,86 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Edit file')} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="js_extra()">
8 8 <script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
9 9 </%def>
10 10 <%def name="css_extra()">
11 11 <link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()">
15 15 ${h.link_to(u'Home',h.url('/'))}
16 16 &raquo;
17 17 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
18 18 &raquo;
19 19 ${_('add file')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
20 20 </%def>
21 21
22 22 <%def name="page_nav()">
23 23 ${self.menu('files')}
24 24 </%def>
25 25 <%def name="main()">
26 26 <div class="box">
27 27 <!-- box / title -->
28 28 <div class="title">
29 29 ${self.breadcrumbs()}
30 30 <ul class="links">
31 31 <li>
32 32 <span style="text-transform: uppercase;">
33 33 <a href="#">${_('branch')}: ${c.cs.branch}</a></span>
34 34 </li>
35 35 </ul>
36 36 </div>
37 37 <div class="table">
38 38 <div id="files_data">
39 39 ${h.form(h.url.current(),method='post',id='eform')}
40 40 <h3>${_('Add new file')}</h3>
41 41 <div class="form">
42 42 <div class="fields">
43 43 <div class="field">
44 44 <div class="label">
45 45 <label for="location">${_('Location')}</label>
46 46 </div>
47 47 <div class="input">
48 48 <input type="text" value="${c.f_path}" size="30" name="location" id="location">
49 ${_('use / to separate directories')}
49 50 </div>
50 51 </div>
51 52
52 53 <div class="field">
53 54 <div class="label">
54 55 <label for="filename">${_('File Name')}:</label>
55 56 </div>
56 57 <div class="input">
57 58 <input type="text" value="" size="30" name="filename" id="filename">
58 59 </div>
59 60 </div>
60 61 </div>
61 62 </div>
62 63 <div id="body" class="codeblock">
63 64 <pre id="editor_pre"></pre>
64 65 <textarea id="editor" name="content" style="display:none"></textarea>
65 <div style="padding-top: 10px;">${_('commit message')}</div>
66 <div style="padding: 10px;color:#666666">${_('commit message')}</div>
66 67 <textarea id="commit" name="message" style="height: 100px;width: 99%"></textarea>
67 68 </div>
68 69 <div style="text-align: right;padding-top: 5px">
69 70 <input id="reset" type="button" value="${_('Reset')}" class="ui-button-small" />
70 71 ${h.submit('commit',_('Commit changes'),class_="ui-button-small-blue")}
71 72 </div>
72 73 ${h.end_form()}
73 74 <script type="text/javascript">
74 75 var myCodeMirror = CodeMirror.fromTextArea(YUD.get('editor'),{
75 76 mode: "null",
76 77 lineNumbers:true
77 78 });
78 79 YUE.on('reset','click',function(){
79 80 window.location="${h.url('files_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.f_path)}";
80 81 })
81 82 </script>
82 83 </div>
83 84 </div>
84 85 </div>
85 86 </%def> No newline at end of file
@@ -1,66 +1,64 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Edit file')} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="js_extra()">
8 8 <script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
9 9 </%def>
10 10 <%def name="css_extra()">
11 11 <link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()">
15 15 ${h.link_to(u'Home',h.url('/'))}
16 16 &raquo;
17 17 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
18 18 &raquo;
19 19 ${_('edit file')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
20 20 </%def>
21 21
22 22 <%def name="page_nav()">
23 23 ${self.menu('files')}
24 24 </%def>
25 25 <%def name="main()">
26 26 <div class="box">
27 27 <!-- box / title -->
28 28 <div class="title">
29 29 ${self.breadcrumbs()}
30 30 <ul class="links">
31 31 <li>
32 32 <span style="text-transform: uppercase;">
33 33 <a href="#">${_('branch')}: ${c.cs.branch}</a></span>
34 34 </li>
35 35 </ul>
36 36 </div>
37 37 <div class="table">
38 38 <div id="files_data">
39 39 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cs.revision,c.file.path)}</h3>
40 40 ${h.form(h.url.current(),method='post',id='eform')}
41 41 <div id="body" class="codeblock">
42 42 <pre id="editor_pre"></pre>
43 43 <textarea id="editor" name="content" style="display:none">${c.file.content|n}</textarea>
44
45 <div style="padding-top: 10px;">${_('commit message')}</div>
44 <div style="padding: 10px;color:#666666">${_('commit message')}</div>
46 45 <textarea id="commit" name="message" style="height: 100px;width: 99%"></textarea>
47
48 46 </div>
49 47 <div style="text-align: right;padding-top: 5px">
50 48 <input id="reset" type="button" value="${_('Reset')}" class="ui-button-small" />
51 49 ${h.submit('commit',_('Commit changes'),class_="ui-button-small-blue")}
52 50 </div>
53 51 ${h.end_form()}
54 52 <script type="text/javascript">
55 53 var myCodeMirror = CodeMirror.fromTextArea(YUD.get('editor'),{
56 54 mode: "null",
57 55 lineNumbers:true
58 56 });
59 57 YUE.on('reset','click',function(){
60 58 window.location="${h.url('files_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.file.path)}";
61 59 })
62 60 </script>
63 61 </div>
64 62 </div>
65 63 </div>
66 64 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now