##// END OF EJS Templates
file: new file editors...
dan -
r3754:5cee44bd new-ui
parent child Browse files
Show More
@@ -68,6 +68,10 b' def includeme(config):'
68 68 pattern='/_markup_preview')
69 69
70 70 config.add_route(
71 name='file_preview',
72 pattern='/_file_preview')
73
74 config.add_route(
71 75 name='store_user_session_value',
72 76 pattern='/_store_session_attr')
73 77
@@ -27,11 +27,12 b' from pyramid.view import view_config'
27 27 from rhodecode.apps._base import BaseAppView
28 28 from rhodecode.lib import helpers as h
29 29 from rhodecode.lib.auth import (
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator,
31 CSRFRequired)
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.lib.codeblocks import filenode_as_lines_tokens
32 32 from rhodecode.lib.index import searcher_from_config
33 33 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
34 34 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.vcs.nodes import FileNode
35 36 from rhodecode.model.db import (
36 37 func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
37 38 from rhodecode.model.repo import RepoModel
@@ -743,6 +744,34 b' class HomeView(BaseAppView):'
743 744 @LoginRequired()
744 745 @CSRFRequired()
745 746 @view_config(
747 route_name='file_preview', request_method='POST',
748 renderer='string', xhr=True)
749 def file_preview(self):
750 # Technically a CSRF token is not needed as no state changes with this
751 # call. However, as this is a POST is better to have it, so automated
752 # tools don't flag it as potential CSRF.
753 # Post is required because the payload could be bigger than the maximum
754 # allowed by GET.
755
756 text = self.request.POST.get('text')
757 file_path = self.request.POST.get('file_path')
758
759 renderer = h.renderer_from_filename(file_path)
760
761 if renderer:
762 return h.render(text, renderer=renderer, mentions=True)
763 else:
764 self.load_default_context()
765 _render = self.request.get_partial_renderer(
766 'rhodecode:templates/files/file_content.mako')
767
768 lines = filenode_as_lines_tokens(FileNode(file_path, text))
769
770 return _render('render_lines', lines)
771
772 @LoginRequired()
773 @CSRFRequired()
774 @view_config(
746 775 route_name='store_user_session_value', request_method='POST',
747 776 renderer='string', xhr=True)
748 777 def store_user_session_attr(self):
@@ -25,6 +25,7 b' import shutil'
25 25 import tempfile
26 26 import collections
27 27 import urllib
28 import pathlib2
28 29
29 30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
30 31 from pyramid.view import view_config
@@ -42,7 +43,7 b' from rhodecode.lib.exceptions import Non'
42 43 from rhodecode.lib.codeblocks import (
43 44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
44 45 from rhodecode.lib.utils2 import (
45 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1)
46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
46 47 from rhodecode.lib.auth import (
47 48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
48 49 from rhodecode.lib.vcs import path as vcspath
@@ -87,7 +88,7 b' class RepoFilesView(RepoAppView):'
87 88 c.enable_downloads = self.db_repo.enable_downloads
88 89 return c
89 90
90 def _ensure_not_locked(self):
91 def _ensure_not_locked(self, commit_id='tip'):
91 92 _ = self.request.translate
92 93
93 94 repo = self.db_repo
@@ -98,21 +99,40 b' class RepoFilesView(RepoAppView):'
98 99 'warning')
99 100 files_url = h.route_path(
100 101 'repo_files:default_path',
101 repo_name=self.db_repo_name, commit_id='tip')
102 repo_name=self.db_repo_name, commit_id=commit_id)
102 103 raise HTTPFound(files_url)
103 104
104 def check_branch_permission(self, branch_name):
105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
106 _ = self.request.translate
107
108 if not is_head:
109 message = _('You can only modify files with commit being a valid branch head.')
110 h.flash(message, category='warning')
111
112 if json_mode:
113 return message
114
115 files_url = h.route_path(
116 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
117 f_path=f_path)
118 raise HTTPFound(files_url)
119
120 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
105 121 _ = self.request.translate
106 122
107 123 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
108 124 self.db_repo_name, branch_name)
109 125 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
110 h.flash(
111 _('Branch `{}` changes forbidden by rule {}.').format(branch_name, rule),
112 'warning')
126 message = _('Branch `{}` changes forbidden by rule {}.').format(
127 branch_name, rule)
128 h.flash(message, 'warning')
129
130 if json_mode:
131 return message
132
113 133 files_url = h.route_path(
114 'repo_files:default_path',
115 repo_name=self.db_repo_name, commit_id='tip')
134 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
135
116 136 raise HTTPFound(files_url)
117 137
118 138 def _get_commit_and_path(self):
@@ -146,8 +166,7 b' class RepoFilesView(RepoAppView):'
146 166
147 167 _url = h.route_path(
148 168 'repo_files_add_file',
149 repo_name=self.db_repo_name, commit_id=0, f_path='',
150 _anchor='edit')
169 repo_name=self.db_repo_name, commit_id=0, f_path='')
151 170
152 171 if h.HasRepoPermissionAny(
153 172 'repository.write', 'repository.admin')(self.db_repo_name):
@@ -217,7 +236,7 b' class RepoFilesView(RepoAppView):'
217 236 break
218 237
219 238 # checked branches, means we only need to try to get the branch/commit_sha
220 if not repo.is_empty:
239 if not repo.is_empty():
221 240 commit = repo.get_commit(commit_id=commit_id)
222 241 if commit:
223 242 branch_name = commit.branch
@@ -276,6 +295,15 b' class RepoFilesView(RepoAppView):'
276 295
277 296 return commit_id, ext, fileformat, content_type
278 297
298 def create_pure_path(self, *parts):
299 # Split paths and sanitize them, removing any ../ etc
300 sanitized_path = [
301 x for x in pathlib2.PurePath(*parts).parts
302 if x not in ['.', '..']]
303
304 pure_path = pathlib2.PurePath(*sanitized_path)
305 return pure_path
306
279 307 @LoginRequired()
280 308 @HasRepoPermissionAnyDecorator(
281 309 'repository.read', 'repository.write', 'repository.admin')
@@ -1054,15 +1082,9 b' class RepoFilesView(RepoAppView):'
1054 1082 _branch_name, _sha_commit_id, is_head = \
1055 1083 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1056 1084
1057 if not is_head:
1058 h.flash(_('You can only delete files with commit '
1059 'being a valid branch head.'), category='warning')
1060 raise HTTPFound(
1061 h.route_path('repo_files',
1062 repo_name=self.db_repo_name, commit_id='tip',
1063 f_path=f_path))
1085 self.forbid_non_head(is_head, f_path)
1086 self.check_branch_permission(_branch_name)
1064 1087
1065 self.check_branch_permission(_branch_name)
1066 1088 c.commit = self._get_commit_or_redirect(commit_id)
1067 1089 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1068 1090
@@ -1088,13 +1110,7 b' class RepoFilesView(RepoAppView):'
1088 1110 _branch_name, _sha_commit_id, is_head = \
1089 1111 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1090 1112
1091 if not is_head:
1092 h.flash(_('You can only delete files with commit '
1093 'being a valid branch head.'), category='warning')
1094 raise HTTPFound(
1095 h.route_path('repo_files',
1096 repo_name=self.db_repo_name, commit_id='tip',
1097 f_path=f_path))
1113 self.forbid_non_head(is_head, f_path)
1098 1114 self.check_branch_permission(_branch_name)
1099 1115
1100 1116 c.commit = self._get_commit_or_redirect(commit_id)
@@ -1144,14 +1160,8 b' class RepoFilesView(RepoAppView):'
1144 1160 _branch_name, _sha_commit_id, is_head = \
1145 1161 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1146 1162
1147 if not is_head:
1148 h.flash(_('You can only edit files with commit '
1149 'being a valid branch head.'), category='warning')
1150 raise HTTPFound(
1151 h.route_path('repo_files',
1152 repo_name=self.db_repo_name, commit_id='tip',
1153 f_path=f_path))
1154 self.check_branch_permission(_branch_name)
1163 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1164 self.check_branch_permission(_branch_name, commit_id=commit_id)
1155 1165
1156 1166 c.commit = self._get_commit_or_redirect(commit_id)
1157 1167 c.file = self._get_filenode_or_redirect(c.commit, f_path)
@@ -1163,8 +1173,7 b' class RepoFilesView(RepoAppView):'
1163 1173 commit_id=c.commit.raw_id, f_path=f_path)
1164 1174 raise HTTPFound(files_url)
1165 1175
1166 c.default_message = _(
1167 'Edited file {} via RhodeCode Enterprise').format(f_path)
1176 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1168 1177 c.f_path = f_path
1169 1178
1170 1179 return self._get_template_context(c)
@@ -1181,32 +1190,23 b' class RepoFilesView(RepoAppView):'
1181 1190 commit_id, f_path = self._get_commit_and_path()
1182 1191
1183 1192 self._ensure_not_locked()
1184 _branch_name, _sha_commit_id, is_head = \
1185 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1186
1187 if not is_head:
1188 h.flash(_('You can only edit files with commit '
1189 'being a valid branch head.'), category='warning')
1190 raise HTTPFound(
1191 h.route_path('repo_files',
1192 repo_name=self.db_repo_name, commit_id='tip',
1193 f_path=f_path))
1194
1195 self.check_branch_permission(_branch_name)
1196 1193
1197 1194 c.commit = self._get_commit_or_redirect(commit_id)
1198 1195 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1199 1196
1200 1197 if c.file.is_binary:
1201 raise HTTPFound(
1202 h.route_path('repo_files',
1203 repo_name=self.db_repo_name,
1204 commit_id=c.commit.raw_id,
1205 f_path=f_path))
1198 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1199 commit_id=c.commit.raw_id, f_path=f_path))
1200
1201 _branch_name, _sha_commit_id, is_head = \
1202 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1206 1203
1207 c.default_message = _(
1208 'Edited file {} via RhodeCode Enterprise').format(f_path)
1204 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1205 self.check_branch_permission(_branch_name, commit_id=commit_id)
1206
1207 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1209 1208 c.f_path = f_path
1209
1210 1210 old_content = c.file.content
1211 1211 sl = old_content.splitlines(1)
1212 1212 first_line = sl[0] if sl else ''
@@ -1217,20 +1217,25 b' class RepoFilesView(RepoAppView):'
1217 1217 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1218 1218
1219 1219 message = r_post.get('message') or c.default_message
1220 org_f_path = c.file.unicode_path
1220 org_node_path = c.file.unicode_path
1221 1221 filename = r_post['filename']
1222 org_filename = c.file.name
1222
1223 root_path = c.file.dir_path
1224 pure_path = self.create_pure_path(root_path, filename)
1225 node_path = safe_unicode(bytes(pure_path))
1223 1226
1224 if content == old_content and filename == org_filename:
1225 h.flash(_('No changes'), category='warning')
1226 raise HTTPFound(
1227 h.route_path('repo_commit', repo_name=self.db_repo_name,
1228 commit_id='tip'))
1227 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1228 commit_id=commit_id)
1229 if content == old_content and node_path == org_node_path:
1230 h.flash(_('No changes detected on {}').format(org_node_path),
1231 category='warning')
1232 raise HTTPFound(default_redirect_url)
1233
1229 1234 try:
1230 1235 mapping = {
1231 org_f_path: {
1232 'org_filename': org_f_path,
1233 'filename': os.path.join(c.file.dir_path, filename),
1236 org_node_path: {
1237 'org_filename': org_node_path,
1238 'filename': node_path,
1234 1239 'content': content,
1235 1240 'lexer': '',
1236 1241 'op': 'mod',
@@ -1238,7 +1243,7 b' class RepoFilesView(RepoAppView):'
1238 1243 }
1239 1244 }
1240 1245
1241 ScmModel().update_nodes(
1246 commit = ScmModel().update_nodes(
1242 1247 user=self._rhodecode_db_user.user_id,
1243 1248 repo=self.db_repo,
1244 1249 message=message,
@@ -1246,15 +1251,16 b' class RepoFilesView(RepoAppView):'
1246 1251 parent_commit=c.commit,
1247 1252 )
1248 1253
1249 h.flash(
1250 _('Successfully committed changes to file `{}`').format(
1254 h.flash(_('Successfully committed changes to file `{}`').format(
1251 1255 h.escape(f_path)), category='success')
1256 default_redirect_url = h.route_path(
1257 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1258
1252 1259 except Exception:
1253 1260 log.exception('Error occurred during commit')
1254 1261 h.flash(_('Error occurred during commit'), category='error')
1255 raise HTTPFound(
1256 h.route_path('repo_commit', repo_name=self.db_repo_name,
1257 commit_id='tip'))
1262
1263 raise HTTPFound(default_redirect_url)
1258 1264
1259 1265 @LoginRequired()
1260 1266 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
@@ -1274,10 +1280,8 b' class RepoFilesView(RepoAppView):'
1274 1280 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1275 1281 if c.commit is None:
1276 1282 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1277 c.default_message = (_('Added file via RhodeCode Enterprise'))
1278 c.f_path = f_path.lstrip('/') # ensure not relative path
1279 1283
1280 if self.rhodecode_vcs_repo.is_empty:
1284 if self.rhodecode_vcs_repo.is_empty():
1281 1285 # for empty repository we cannot check for current branch, we rely on
1282 1286 # c.commit.branch instead
1283 1287 _branch_name = c.commit.branch
@@ -1286,15 +1290,11 b' class RepoFilesView(RepoAppView):'
1286 1290 _branch_name, _sha_commit_id, is_head = \
1287 1291 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1288 1292
1289 if not is_head:
1290 h.flash(_('You can only add files with commit '
1291 'being a valid branch head.'), category='warning')
1292 raise HTTPFound(
1293 h.route_path('repo_files',
1294 repo_name=self.db_repo_name, commit_id='tip',
1295 f_path=f_path))
1293 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1294 self.check_branch_permission(_branch_name, commit_id=commit_id)
1296 1295
1297 self.check_branch_permission(_branch_name)
1296 c.default_message = (_('Added file via RhodeCode Enterprise'))
1297 c.f_path = f_path.lstrip('/') # ensure not relative path
1298 1298
1299 1299 return self._get_template_context(c)
1300 1300
@@ -1311,14 +1311,19 b' class RepoFilesView(RepoAppView):'
1311 1311
1312 1312 self._ensure_not_locked()
1313 1313
1314 r_post = self.request.POST
1315
1316 c.commit = self._get_commit_or_redirect(
1317 commit_id, redirect_after=False)
1314 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1318 1315 if c.commit is None:
1319 1316 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1320 1317
1321 if self.rhodecode_vcs_repo.is_empty:
1318 # calculate redirect URL
1319 if self.rhodecode_vcs_repo.is_empty():
1320 default_redirect_url = h.route_path(
1321 'repo_summary', repo_name=self.db_repo_name)
1322 else:
1323 default_redirect_url = h.route_path(
1324 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1325
1326 if self.rhodecode_vcs_repo.is_empty():
1322 1327 # for empty repository we cannot check for current branch, we rely on
1323 1328 # c.commit.branch instead
1324 1329 _branch_name = c.commit.branch
@@ -1327,70 +1332,42 b' class RepoFilesView(RepoAppView):'
1327 1332 _branch_name, _sha_commit_id, is_head = \
1328 1333 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1329 1334
1330 if not is_head:
1331 h.flash(_('You can only add files with commit '
1332 'being a valid branch head.'), category='warning')
1333 raise HTTPFound(
1334 h.route_path('repo_files',
1335 repo_name=self.db_repo_name, commit_id='tip',
1336 f_path=f_path))
1337
1338 self.check_branch_permission(_branch_name)
1335 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1336 self.check_branch_permission(_branch_name, commit_id=commit_id)
1339 1337
1340 1338 c.default_message = (_('Added file via RhodeCode Enterprise'))
1341 1339 c.f_path = f_path
1340
1341 r_post = self.request.POST
1342 message = r_post.get('message') or c.default_message
1343 filename = r_post.get('filename')
1342 1344 unix_mode = 0
1343 1345 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1344 1346
1345 message = r_post.get('message') or c.default_message
1346 filename = r_post.get('filename')
1347 location = r_post.get('location', '') # dir location
1348 file_obj = r_post.get('upload_file', None)
1349
1350 if file_obj is not None and hasattr(file_obj, 'filename'):
1351 filename = r_post.get('filename_upload')
1352 content = file_obj.file
1353
1354 if hasattr(content, 'file'):
1355 # non posix systems store real file under file attr
1356 content = content.file
1357
1358 if self.rhodecode_vcs_repo.is_empty:
1359 default_redirect_url = h.route_path(
1360 'repo_summary', repo_name=self.db_repo_name)
1361 else:
1362 default_redirect_url = h.route_path(
1363 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1364
1347 if not filename:
1365 1348 # If there's no commit, redirect to repo summary
1366 1349 if type(c.commit) is EmptyCommit:
1367 1350 redirect_url = h.route_path(
1368 1351 'repo_summary', repo_name=self.db_repo_name)
1369 1352 else:
1370 1353 redirect_url = default_redirect_url
1371
1372 if not filename:
1373 h.flash(_('No filename'), category='warning')
1354 h.flash(_('No filename specified'), category='warning')
1374 1355 raise HTTPFound(redirect_url)
1375 1356
1376 # extract the location from filename,
1377 # allows using foo/bar.txt syntax to create subdirectories
1378 subdir_loc = filename.rsplit('/', 1)
1379 if len(subdir_loc) == 2:
1380 location = os.path.join(location, subdir_loc[0])
1357 root_path = f_path
1358 pure_path = self.create_pure_path(root_path, filename)
1359 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1381 1360
1382 # strip all crap out of file, just leave the basename
1383 filename = os.path.basename(filename)
1384 node_path = os.path.join(location, filename)
1385 1361 author = self._rhodecode_db_user.full_contact
1386
1387 try:
1388 1362 nodes = {
1389 1363 node_path: {
1390 1364 'content': content
1391 1365 }
1392 1366 }
1393 ScmModel().create_nodes(
1367
1368 try:
1369
1370 commit = ScmModel().create_nodes(
1394 1371 user=self._rhodecode_db_user.user_id,
1395 1372 repo=self.db_repo,
1396 1373 message=message,
@@ -1399,13 +1376,15 b' class RepoFilesView(RepoAppView):'
1399 1376 author=author,
1400 1377 )
1401 1378
1402 h.flash(
1403 _('Successfully committed new file `{}`').format(
1379 h.flash(_('Successfully committed new file `{}`').format(
1404 1380 h.escape(node_path)), category='success')
1381
1382 default_redirect_url = h.route_path(
1383 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1384
1405 1385 except NonRelativePathError:
1406 1386 log.exception('Non Relative path found')
1407 h.flash(_(
1408 'The location specified must be a relative path and must not '
1387 h.flash(_('The location specified must be a relative path and must not '
1409 1388 'contain .. in the path'), category='warning')
1410 1389 raise HTTPFound(default_redirect_url)
1411 1390 except (NodeError, NodeAlreadyExistsError) as e:
@@ -1415,3 +1394,135 b' class RepoFilesView(RepoAppView):'
1415 1394 h.flash(_('Error occurred during commit'), category='error')
1416 1395
1417 1396 raise HTTPFound(default_redirect_url)
1397
1398 @LoginRequired()
1399 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1400 @CSRFRequired()
1401 @view_config(
1402 route_name='repo_files_upload_file', request_method='POST',
1403 renderer='json_ext')
1404 def repo_files_upload_file(self):
1405 _ = self.request.translate
1406 c = self.load_default_context()
1407 commit_id, f_path = self._get_commit_and_path()
1408
1409 self._ensure_not_locked()
1410
1411 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1412 if c.commit is None:
1413 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1414
1415 # calculate redirect URL
1416 if self.rhodecode_vcs_repo.is_empty():
1417 default_redirect_url = h.route_path(
1418 'repo_summary', repo_name=self.db_repo_name)
1419 else:
1420 default_redirect_url = h.route_path(
1421 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1422
1423 if self.rhodecode_vcs_repo.is_empty():
1424 # for empty repository we cannot check for current branch, we rely on
1425 # c.commit.branch instead
1426 _branch_name = c.commit.branch
1427 is_head = True
1428 else:
1429 _branch_name, _sha_commit_id, is_head = \
1430 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1431
1432 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1433 if error:
1434 return {
1435 'error': error,
1436 'redirect_url': default_redirect_url
1437 }
1438 error = self.check_branch_permission(_branch_name, json_mode=True)
1439 if error:
1440 return {
1441 'error': error,
1442 'redirect_url': default_redirect_url
1443 }
1444
1445 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1446 c.f_path = f_path
1447
1448 r_post = self.request.POST
1449
1450 message = c.default_message
1451 user_message = r_post.getall('message')
1452 if isinstance(user_message, list) and user_message:
1453 # we take the first from duplicated results if it's not empty
1454 message = user_message[0] if user_message[0] else message
1455
1456 nodes = {}
1457
1458 for file_obj in r_post.getall('files_upload') or []:
1459 content = file_obj.file
1460 filename = file_obj.filename
1461
1462 root_path = f_path
1463 pure_path = self.create_pure_path(root_path, filename)
1464 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1465
1466 nodes[node_path] = {
1467 'content': content
1468 }
1469
1470 if not nodes:
1471 error = 'missing files'
1472 return {
1473 'error': error,
1474 'redirect_url': default_redirect_url
1475 }
1476
1477 author = self._rhodecode_db_user.full_contact
1478
1479 try:
1480 commit = ScmModel().create_nodes(
1481 user=self._rhodecode_db_user.user_id,
1482 repo=self.db_repo,
1483 message=message,
1484 nodes=nodes,
1485 parent_commit=c.commit,
1486 author=author,
1487 )
1488 if len(nodes) == 1:
1489 flash_message = _('Successfully committed {} new files').format(len(nodes))
1490 else:
1491 flash_message = _('Successfully committed 1 new file')
1492
1493 h.flash(flash_message, category='success')
1494
1495 default_redirect_url = h.route_path(
1496 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1497
1498 except NonRelativePathError:
1499 log.exception('Non Relative path found')
1500 error = _('The location specified must be a relative path and must not '
1501 'contain .. in the path')
1502 h.flash(error, category='warning')
1503
1504 return {
1505 'error': error,
1506 'redirect_url': default_redirect_url
1507 }
1508 except (NodeError, NodeAlreadyExistsError) as e:
1509 error = h.escape(e)
1510 h.flash(error, category='error')
1511
1512 return {
1513 'error': error,
1514 'redirect_url': default_redirect_url
1515 }
1516 except Exception:
1517 log.exception('Error occurred during commit')
1518 error = _('Error occurred during commit')
1519 h.flash(error, category='error')
1520 return {
1521 'error': error,
1522 'redirect_url': default_redirect_url
1523 }
1524
1525 return {
1526 'error': None,
1527 'redirect_url': default_redirect_url
1528 }
@@ -1939,23 +1939,26 b' def secure_form(form_url, method="POST",'
1939 1939
1940 1940 def dropdownmenu(name, selected, options, enable_filter=False, **attrs):
1941 1941 select_html = select(name, selected, options, **attrs)
1942
1942 1943 select2 = """
1943 1944 <script>
1944 1945 $(document).ready(function() {
1945 1946 $('#%s').select2({
1946 containerCssClass: 'drop-menu',
1947 containerCssClass: 'drop-menu %s',
1947 1948 dropdownCssClass: 'drop-menu-dropdown',
1948 1949 dropdownAutoWidth: true%s
1949 1950 });
1950 1951 });
1951 1952 </script>
1952 1953 """
1954
1953 1955 filter_option = """,
1954 1956 minimumResultsForSearch: -1
1955 1957 """
1956 1958 input_id = attrs.get('id') or name
1959 extra_classes = ' '.join(attrs.pop('extra_classes', []))
1957 1960 filter_enabled = "" if enable_filter else filter_option
1958 select_script = literal(select2 % (input_id, filter_enabled))
1961 select_script = literal(select2 % (input_id, extra_classes, filter_enabled))
1959 1962
1960 1963 return literal(select_html+select_script)
1961 1964
@@ -818,6 +818,8 b' class ScmModel(BaseModel):'
818 818 repo_name=repo.repo_name, repo_alias=scm_instance.alias,
819 819 commit_ids=[tip.raw_id])
820 820
821 return tip
822
821 823 def delete_nodes(self, user, repo, message, nodes, parent_commit=None,
822 824 author=None, trigger_push_hook=True):
823 825 """
@@ -27,7 +27,7 b''
27 27
28 28 .CodeMirror-gutters {
29 29 border-right: 1px solid #ddd;
30 background-color: @grey6;
30 background-color: white;
31 31 white-space: nowrap;
32 32 }
33 33 .CodeMirror-linenumbers {}
@@ -231,6 +231,11 b' form.rcform {'
231 231
232 232 .drop-menu {
233 233 float: left;
234
235 & + .last-item {
236 margin: 0;
237 }
238
234 239 margin: 0 @input-padding 0 0;
235 240 }
236 241
@@ -277,7 +277,9 b' input.inline[type="file"] {'
277 277 // Gists
278 278 #files_data {
279 279 clear: both; //for firefox
280 }
280 padding-top: 10px;
281 }
282
281 283 #gistid {
282 284 margin-right: @padding;
283 285 }
@@ -1329,7 +1331,7 b' table.integrations {'
1329 1331
1330 1332 #editor_container{
1331 1333 position: relative;
1332 margin: @padding;
1334 margin: @padding 10px;
1333 1335 }
1334 1336 }
1335 1337
@@ -2063,15 +2065,15 b' BIN_FILENODE = 7'
2063 2065
2064 2066 // Files
2065 2067 .edit-file-title {
2066 border-bottom: @border-thickness solid @border-default-color;
2067
2068 .breadcrumbs {
2069 margin-bottom: 0;
2068 font-size: 16px;
2069
2070 .title-heading {
2071 padding: 2px;
2070 2072 }
2071 2073 }
2072 2074
2073 2075 .edit-file-fieldset {
2074 margin-top: @sidebarpadding;
2076 margin: @sidebarpadding 0;
2075 2077
2076 2078 .fieldset {
2077 2079 .left-label {
@@ -2120,6 +2122,27 b' BIN_FILENODE = 7'
2120 2122 margin: 0 0 0 10px;
2121 2123 }
2122 2124
2125 .file-upload-transaction-wrapper {
2126 margin-top: 57px;
2127 clear: both;
2128 }
2129
2130 .file-upload-transaction-wrapper .error {
2131 color: @color5;
2132 }
2133
2134 .file-upload-transaction {
2135 min-height: 200px;
2136 padding: 54px;
2137 border: 1px solid @grey5;
2138 text-align: center;
2139 clear: both;
2140 }
2141
2142 .file-upload-transaction i {
2143 font-size: 48px
2144 }
2145
2123 2146 h3.files_location{
2124 2147 line-height: 2.4em;
2125 2148 }
@@ -2308,6 +2331,101 b' h3.files_location{'
2308 2331 }
2309 2332
2310 2333
2334 .edit-file-fieldset #location,
2335 .edit-file-fieldset #filename {
2336 display: flex;
2337 width: -moz-available; /* WebKit-based browsers will ignore this. */
2338 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2339 width: fill-available;
2340 border: 0;
2341 }
2342
2343 .path-items {
2344 display: flex;
2345 padding: 0;
2346 border: 1px solid #eeeeee;
2347 width: 100%;
2348 float: left;
2349
2350 .breadcrumb-path {
2351 line-height: 30px;
2352 padding: 0 4px;
2353 white-space: nowrap;
2354 }
2355
2356 .location-path {
2357 width: -moz-available; /* WebKit-based browsers will ignore this. */
2358 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2359 width: fill-available;
2360
2361 .file-name-input {
2362 padding: 0.5em 0;
2363 }
2364
2365 }
2366
2367 ul {
2368 display: flex;
2369 margin: 0;
2370 padding: 0;
2371 }
2372 li {
2373 list-style-type: none;
2374 }
2375 }
2376
2377 .editor-items {
2378 height: 40px;
2379 margin: 10px 0 -17px 10px;
2380
2381 .editor-action {
2382 cursor: pointer;
2383 }
2384
2385 .editor-action.active {
2386 border-bottom: 2px solid #5C5C5C;
2387 }
2388
2389 li {
2390 list-style-type: none;
2391 }
2392 }
2393
2394 .edit-file-fieldset .message textarea {
2395 border: 1px solid #eeeeee;
2396 }
2397
2398 #files_data .codeblock {
2399 background-color: #F5F5F5;
2400 }
2401
2402 #editor_preview {
2403 background: white;
2404 }
2405
2406 .show-editor {
2407 padding: 10px;
2408 background-color: white;
2409
2410 }
2411
2412 .show-preview {
2413 padding: 10px;
2414 background-color: white;
2415 border-left: 1px solid #eeeeee;
2416 }
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2311 2429 // Search
2312 2430
2313 2431 .search-form{
@@ -2577,27 +2695,28 b' form.markup-form {'
2577 2695 padding: 20px;
2578 2696 }
2579 2697
2580 .dropzone {
2698 .dropzone,
2699 .dropzone-pure {
2581 2700 border: 2px dashed @grey5;
2582 2701 border-radius: 5px;
2583 2702 background: white;
2584 2703 min-height: 200px;
2585 2704 padding: 54px;
2586 }
2587 .dropzone .dz-message {
2705
2706 .dz-message {
2588 2707 font-weight: 700;
2589 }
2590
2591 .dropzone .dz-message {
2592 2708 text-align: center;
2593 2709 margin: 2em 0;
2594 2710 }
2595 2711
2712 }
2713
2596 2714 .dz-preview {
2597 margin: 10px 0px !important;
2715 margin: 10px 0 !important;
2598 2716 position: relative;
2599 2717 vertical-align: top;
2600 2718 padding: 10px;
2719 border-bottom: 1px solid @grey5;
2601 2720 }
2602 2721
2603 2722 .dz-filename {
@@ -2605,6 +2724,10 b' form.markup-form {'
2605 2724 float:left;
2606 2725 }
2607 2726
2727 .dz-sending {
2728 float: right;
2729 }
2730
2608 2731 .dz-response {
2609 2732 clear:both
2610 2733 }
@@ -2615,4 +2738,6 b' form.markup-form {'
2615 2738
2616 2739 .dz-error-message {
2617 2740 color: @alert2;
2618 } No newline at end of file
2741 padding-top: 10px;
2742 clear: both;
2743 }
@@ -149,6 +149,7 b' function registerRCRoutes() {'
149 149 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
150 150 pyroutes.register('goto_switcher_data', '/_goto_data', []);
151 151 pyroutes.register('markup_preview', '/_markup_preview', []);
152 pyroutes.register('file_preview', '/_file_preview', []);
152 153 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
153 154 pyroutes.register('journal', '/_admin/journal', []);
154 155 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
@@ -204,7 +204,12 b' var CodeMirrorCompleteAfter = function(c'
204 204 };
205 205
206 206 var initCodeMirror = function(textAreadId, resetUrl, focus, options) {
207 if (textAreadId.substr(0,1) === "#"){
208 var ta = $(textAreadId).get(0);
209 }else {
207 210 var ta = $('#' + textAreadId).get(0);
211 }
212
208 213 if (focus === undefined) {
209 214 focus = true;
210 215 }
@@ -644,18 +649,6 b' var fillCodeMirrorOptions = function(tar'
644 649 }
645 650 };
646 651
647 var CodeMirrorPreviewEnable = function(edit_mode) {
648 // in case it a preview enabled mode enable the button
649 if (['markdown', 'rst', 'gfm'].indexOf(edit_mode) !== -1) {
650 $('#render_preview').removeClass('hidden');
651 }
652 else {
653 if (!$('#render_preview').hasClass('hidden')) {
654 $('#render_preview').addClass('hidden');
655 }
656 }
657 };
658
659 652
660 653 /* markup form */
661 654 (function(mod) {
@@ -409,3 +409,109 b' var showAuthors = function(elem, annotat'
409 409 $('#file_authors_title').html(_gettext('All Authors'))
410 410 })
411 411 };
412
413
414 (function (mod) {
415
416 if (typeof exports == "object" && typeof module == "object") {
417 // CommonJS
418 module.exports = mod();
419 } else {
420 // Plain browser env
421 (this || window).FileEditor = mod();
422 }
423
424 })(function () {
425 "use strict";
426
427 function FileEditor(textAreaElement, options) {
428 if (!(this instanceof FileEditor)) {
429 return new FileEditor(textAreaElement, options);
430 }
431 // bind the element instance to our Form
432 var te = $(textAreaElement).get(0);
433 if (te !== undefined) {
434 te.FileEditor = this;
435 }
436
437 this.modes_select = '#set_mode';
438 this.filename_selector = '#filename';
439 this.commit_btn_selector = '#commit_btn';
440 this.line_wrap_selector = '#line_wrap';
441 this.editor_preview_selector = '#editor_preview';
442
443 if (te !== undefined) {
444 this.cm = initCodeMirror(textAreaElement, null, false);
445 }
446
447 // FUNCTIONS and helpers
448 var self = this;
449
450 this.submitHandler = function() {
451 $(self.commit_btn_selector).on('click', function(e) {
452
453 var filename = $(self.filename_selector).val();
454 if (filename === "") {
455 alert("Missing filename");
456 e.preventDefault();
457 }
458
459 var button = $(this);
460 if (button.hasClass('clicked')) {
461 button.attr('disabled', true);
462 } else {
463 button.addClass('clicked');
464 }
465 });
466 };
467 this.submitHandler();
468
469 // on select line wraps change the editor
470 this.lineWrapHandler = function () {
471 $(self.line_wrap_selector).on('change', function (e) {
472 var selected = e.currentTarget;
473 var line_wraps = {'on': true, 'off': false}[selected.value];
474 setCodeMirrorLineWrap(self.cm, line_wraps)
475 });
476 };
477 this.lineWrapHandler();
478
479
480 this.showPreview = function () {
481
482 var _text = self.cm.getValue();
483 var _file_path = $(self.filename_selector).val();
484 if (_text && _file_path) {
485 $('.show-preview').addClass('active');
486 $('.show-editor').removeClass('active');
487
488 $(self.editor_preview_selector).show();
489 $(self.cm.getWrapperElement()).hide();
490
491
492 var post_data = {'text': _text, 'file_path': _file_path, 'csrf_token': CSRF_TOKEN};
493 $(self.editor_preview_selector).html(_gettext('Loading ...'));
494
495 var url = pyroutes.url('file_preview');
496
497 ajaxPOST(url, post_data, function (o) {
498 $(self.editor_preview_selector).html(o);
499 })
500 }
501
502 };
503
504 this.showEditor = function () {
505 $(self.editor_preview_selector).hide();
506 $('.show-editor').addClass('active');
507 $('.show-preview').removeClass('active');
508
509 $(self.cm.getWrapperElement()).show();
510 };
511
512
513 }
514
515 return FileEditor;
516 });
517
@@ -1,7 +1,7 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 ${_('%s Files Add') % c.repo_name}
4 ${_('{} Files Add').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
@@ -11,58 +11,60 b''
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 <%def name="breadcrumbs_links()">
15 ${_('Add new file')} @ ${h.show_id(c.commit)} ${_('Branch')}: ${c.commit.branch}
16 </%def>
14 <%def name="breadcrumbs_links()"></%def>
17 15
18 16 <%def name="menu_bar_subnav()">
19 17 ${self.repo_menu(active='files')}
20 18 </%def>
21 19
22 20 <%def name="main()">
21
23 22 <div class="box">
24 23
25 24 <div class="edit-file-title">
26 ${self.breadcrumbs()}
25 <span class="title-heading">${_('Add new file')} @ <code>${h.show_id(c.commit)}</code></span>
26 <span class="tag branchtag"><i class="icon-branch"></i> ${c.commit.branch}</span>
27 27 </div>
28 28
29 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', enctype="multipart/form-data", class_="form-horizontal", request=request)}
29 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
30 30 <div class="edit-file-fieldset">
31 <div class="fieldset">
32 <div id="destination-label" class="left-label">
33 ${_('Path')}:
34 </div>
35 <div class="right-content">
31 <div class="path-items">
32 <ul>
33 <li class="breadcrumb-path">
36 34 <div>
37 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path, request.GET.get('at'))} /
38 <input type="input-small" value="${c.f_path}" size="46" name="location" id="location">
35 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
36 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
39 37 </div>
40 </div>
41 </div>
42 <div id="filename_container" class="fieldset">
43 <div class="filename-label left-label">
44 ${_('Filename')}:
45 </div>
46 <div class="right-content">
47 <input class="input-small" type="text" value="" size="46" name="filename" id="filename">
48
49 </div>
38 </li>
39 <li class="location-path">
40 <input class="file-name-input input-small" type="text" value="" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
41 </li>
42 </ul>
50 43 </div>
51 44
52 45 </div>
53 46
54 47 <div class="table">
55 48 <div id="files_data">
49
56 50 <div id="codeblock" class="codeblock">
57 <div class="code-header form" id="set_mode_header">
58 <div class="fields">
51 <div class="editor-items">
52 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
53 ${_('Edit')}
54 </div>
55
56 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
57 ${_('Preview')}
58 </div>
59
60 <div class="pull-right">
61 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off'))], extra_classes=['last-item'])}
62 </div>
63 <div class="pull-right">
59 64 ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)}
60 <label for="line_wrap">${_('line wraps')}</label>
61 ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])}
62
63 <div id="render_preview" class="btn btn-small preview hidden" >${_('Preview')}</div>
64 65 </div>
65 66 </div>
67
66 68 <div id="editor_container">
67 69 <pre id="editor_pre"></pre>
68 70 <textarea id="editor" name="content" ></textarea>
@@ -74,109 +76,35 b''
74 76
75 77 <div class="edit-file-fieldset">
76 78 <div class="fieldset">
77 <div id="commit-message-label" class="commit-message-label left-label">
78 ${_('Commit Message')}:
79 </div>
80 <div class="right-content">
81 79 <div class="message">
82 80 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
83 81 </div>
84 82 </div>
85 </div>
86 <div class="pull-right">
87 ${h.reset('reset',_('Cancel'),class_="btn btn-small")}
83 <div class="pull-left">
88 84 ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-success")}
89 85 </div>
90 86 </div>
91 87 ${h.end_form()}
92 88 </div>
89
93 90 <script type="text/javascript">
94 91
95 $('#commit_btn').on('click', function() {
96 var button = $(this);
97 if (button.hasClass('clicked')) {
98 button.attr('disabled', true);
99 } else {
100 button.addClass('clicked');
101 }
102 });
103
104 var hide_upload = function(){
105 $('#files_data').show();
106 $('#upload_file_container').hide();
107 $('#filename_container').show();
108 };
109
110 $('#file_enable').on('click', function(e){
111 e.preventDefault();
112 hide_upload();
113 });
114
115 var renderer = "";
116 var reset_url = "${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}";
117 var myCodeMirror = initCodeMirror('editor', reset_url, false);
118
92 $(document).ready(function () {
119 93 var modes_select = $('#set_mode');
94 var filename_selector = '#filename';
120 95 fillCodeMirrorOptions(modes_select);
121 96
122 var filename_selector = '#filename';
123 var callback = function(filename, mimetype, mode){
124 CodeMirrorPreviewEnable(mode);
125 };
97 fileEditor = new FileEditor('#editor');
98
126 99 // on change of select field set mode
127 setCodeMirrorModeFromSelect(
128 modes_select, filename_selector, myCodeMirror, callback);
100 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
129 101
130 102 // on entering the new filename set mode, from given extension
131 setCodeMirrorModeFromInput(
132 modes_select, filename_selector, myCodeMirror, callback);
133
134 // if the file is renderable set line wraps automatically
135 if (renderer !== ""){
136 var line_wrap = 'on';
137 $($('#line_wrap option[value="'+line_wrap+'"]')[0]).attr("selected", "selected");
138 setCodeMirrorLineWrap(myCodeMirror, true);
139 }
140
141 // on select line wraps change the editor
142 $('#line_wrap').on('change', function(e){
143 var selected = e.currentTarget;
144 var line_wraps = {'on': true, 'off': false}[selected.value];
145 setCodeMirrorLineWrap(myCodeMirror, line_wraps)
146 });
147
148 // render preview/edit button
149 $('#render_preview').on('click', function(e){
150 if($(this).hasClass('preview')){
151 $(this).removeClass('preview');
152 $(this).html("${_('Edit')}");
153 $('#editor_preview').show();
154 $(myCodeMirror.getWrapperElement()).hide();
103 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
155 104
156 var possible_renderer = {
157 'rst':'rst',
158 'markdown':'markdown',
159 'gfm': 'markdown'}[myCodeMirror.getMode().name];
160 var _text = myCodeMirror.getValue();
161 var _renderer = possible_renderer || DEFAULT_RENDERER;
162 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
163 $('#editor_preview').html(_gettext('Loading ...'));
164 var url = pyroutes.url('repo_commit_comment_preview',
165 {'repo_name': '${c.repo_name}',
166 'commit_id': '${c.commit.raw_id}'});
105 $('#filename').focus();
167 106
168 ajaxPOST(url, post_data, function(o){
169 $('#editor_preview').html(o);
170 })
171 }
172 else{
173 $(this).addClass('preview');
174 $(this).html("${_('Preview')}");
175 $('#editor_preview').hide();
176 $(myCodeMirror.getWrapperElement()).show();
177 }
178 107 });
179 $('#filename').focus();
180 108
181 109 </script>
182 110 </%def>
@@ -1,7 +1,7 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 ${_('%s Files Delete') % c.repo_name}
4 ${_('{} Files Delete').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
@@ -11,29 +11,36 b''
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 <%def name="breadcrumbs_links()">
15 ${_('Delete file')} @ ${h.show_id(c.commit)}
16 </%def>
14 <%def name="breadcrumbs_links()"></%def>
17 15
18 16 <%def name="menu_bar_subnav()">
19 17 ${self.repo_menu(active='files')}
20 18 </%def>
21 19
22 20 <%def name="main()">
21
23 22 <div class="box">
23
24 24 <div class="edit-file-title">
25 ${self.breadcrumbs()}
25 <span class="title-heading">${_('Delete file')} @ <code>${h.show_id(c.commit)}</code></span>
26 <span class="tag branchtag"><i class="icon-branch"></i> ${c.commit.branch}</span>
26 27 </div>
27 ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', class_="form-horizontal", request=request)}
28
29 ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
28 30 <div class="edit-file-fieldset">
29 <div class="fieldset">
30 <div id="destination-label" class="left-label">
31 ${_('Path')}:
31 <div class="path-items">
32 <li class="breadcrumb-path">
33 <div>
34 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
35 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
32 36 </div>
33 <div class="right-content">
34 <span id="path-breadcrumbs">${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path, request.GET.get('at'))}</span>
37 </li>
38 <li class="location-path">
39 <input type="hidden" value="${c.f_path}" name="root_path">
40 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" disabled="disabled">
41 </li>
35 42 </div>
36 </div>
43
37 44 </div>
38 45
39 46 <div id="codeblock" class="codeblock delete-file-preview">
@@ -53,20 +60,26 b''
53 60
54 61 <div class="edit-file-fieldset">
55 62 <div class="fieldset">
56 <div id="commit-message-label" class="commit-message-label left-label">
57 ${_('Commit Message')}:
58 </div>
59 <div class="right-content">
60 63 <div class="message">
61 64 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
62 65 </div>
63 66 </div>
64 </div>
65 <div class="pull-right">
66 ${h.reset('reset',_('Cancel'),class_="btn btn-small btn-danger")}
67 ${h.submit('commit',_('Delete File'),class_="btn btn-small btn-danger-action")}
67 <div class="pull-left">
68 ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-danger-action")}
68 69 </div>
69 70 </div>
70 71 ${h.end_form()}
71 72 </div>
73
74
75 <script type="text/javascript">
76
77 $(document).ready(function () {
78
79 fileEditor = new FileEditor('#editor');
80
81 });
82
83 </script>
84
72 85 </%def>
@@ -1,7 +1,7 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 ${_('%s File Edit') % c.repo_name}
4 ${_('{} Files Edit').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
@@ -11,77 +11,61 b''
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 <%def name="breadcrumbs_links()">
15 ${_('Edit file')} @ ${h.show_id(c.commit)}
16 </%def>
14 <%def name="breadcrumbs_links()"></%def>
17 15
18 16 <%def name="menu_bar_subnav()">
19 17 ${self.repo_menu(active='files')}
20 18 </%def>
21 19
22 20 <%def name="main()">
23 <% renderer = h.renderer_from_filename(c.f_path)%>
21
24 22 <div class="box">
23
25 24 <div class="edit-file-title">
26 ${self.breadcrumbs()}
25 <span class="title-heading">${_('Edit file')} @ <code>${h.show_id(c.commit)}</code></span>
26 <span class="tag branchtag"><i class="icon-branch"></i> ${c.commit.branch}</span>
27 27 </div>
28
29 ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
28 30 <div class="edit-file-fieldset">
29 <div class="fieldset">
30 <div id="destination-label" class="left-label">
31 ${_('Path')}:
31 <div class="path-items">
32 <ul>
33 <li class="breadcrumb-path">
34 <div>
35 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
36 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
32 37 </div>
33 <div class="right-content">
34 <div id="specify-custom-path-container">
35 <span id="path-breadcrumbs">${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path, request.GET.get('at'))}</span>
38 </li>
39 <li class="location-path">
40 <input type="hidden" value="${c.f_path}" name="root_path">
41 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
42 </li>
43 </ul>
36 44 </div>
37 </div>
38 </div>
45
39 46 </div>
40 47
41 48 <div class="table">
42 ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
49 <div id="files_data">
50
43 51 <div id="codeblock" class="codeblock" >
44 <div class="code-header">
45 <div class="stats">
46 <i class="icon-file"></i>
47 <span class="item">${h.link_to("r%s:%s" % (c.file.commit.idx,h.short_id(c.file.commit.raw_id)),h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.file.commit.raw_id))}</span>
48 <span class="item">${h.format_byte_size_binary(c.file.size)}</span>
49 <span class="item last">${c.file.mimetype}</span>
50 <div class="buttons">
51 <a class="btn btn-mini" href="${h.route_path('repo_commits_file',repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">
52 <i class="icon-time"></i> ${_('history')}
53 </a>
52 <div class="editor-items">
53 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
54 ${_('Edit')}
55 </div>
54 56
55 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
56 % if not c.file.is_binary:
57 %if True:
58 ${h.link_to(_('source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")}
59 %else:
60 ${h.link_to(_('annotation'),h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")}
61 %endif
57 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
58 ${_('Preview')}
59 </div>
62 60
63 <a class="btn btn-mini" href="${h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
64 ${_('raw')}
65 </a>
66 <a class="btn btn-mini" href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
67 <i class="icon-archive"></i> ${_('download')}
68 </a>
69 % endif
70 % endif
61 <div class="pull-right">
62 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off')),])}
63 </div>
64 <div class="pull-right">
65 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))],enable_filter=True)}
71 66 </div>
72 67 </div>
73 <div class="form">
74 <label for="set_mode">${_('Editing file')}:</label>
75 ${'%s /' % c.file.dir_path if c.file.dir_path else c.file.dir_path}
76 <input id="filename" type="text" name="filename" value="${c.file.name}">
77 68
78 ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)}
79 <label for="line_wrap">${_('line wraps')}</label>
80 ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])}
81
82 <div id="render_preview" class="btn btn-small preview hidden">${_('Preview')}</div>
83 </div>
84 </div>
85 69 <div id="editor_container">
86 70 <pre id="editor_pre"></pre>
87 71 <textarea id="editor" name="content" >${h.escape(c.file.content)|n}</textarea>
@@ -89,106 +73,48 b''
89 73 </div>
90 74 </div>
91 75 </div>
76 </div>
92 77
93 78 <div class="edit-file-fieldset">
94 79 <div class="fieldset">
95 <div id="commit-message-label" class="commit-message-label left-label">
96 ${_('Commit Message')}:
97 </div>
98 <div class="right-content">
99 80 <div class="message">
100 81 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
101 82 </div>
102 83 </div>
103 </div>
104 <div class="pull-right">
105 ${h.reset('reset',_('Cancel'),class_="btn btn-small")}
106 ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-success")}
84 <div class="pull-left">
85 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
107 86 </div>
108 87 </div>
109 88 ${h.end_form()}
110 89 </div>
111 90
112 91 <script type="text/javascript">
92
113 93 $(document).ready(function(){
114 var renderer = "${renderer}";
115 var reset_url = "${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.file.path)}";
116 var myCodeMirror = initCodeMirror('editor', reset_url);
117
118 94 var modes_select = $('#set_mode');
95 var filename_selector = '#filename';
119 96 fillCodeMirrorOptions(modes_select);
120 97
98 fileEditor = new FileEditor('#editor');
99
121 100 // try to detect the mode based on the file we edit
122 var mimetype = "${c.file.mimetype}";
123 var detected_mode = detectCodeMirrorMode(
124 "${c.file.name}", mimetype);
101 var detected_mode = detectCodeMirrorMode("${c.file.name}", "${c.file.mimetype}");
125 102
126 103 if(detected_mode){
127 setCodeMirrorMode(myCodeMirror, detected_mode);
128 $(modes_select).select2("val", mimetype);
129 $(modes_select).change();
130 setCodeMirrorMode(myCodeMirror, detected_mode);
104 setCodeMirrorMode(fileEditor.cm, detected_mode);
105
106 var mimetype = $(modes_select).find("option[mode={0}]".format(detected_mode)).val();
107 $(modes_select).select2("val", mimetype).trigger('change');
131 108 }
132 109
133 var filename_selector = '#filename';
134 var callback = function(filename, mimetype, mode){
135 CodeMirrorPreviewEnable(mode);
136 };
137 110 // on change of select field set mode
138 setCodeMirrorModeFromSelect(
139 modes_select, filename_selector, myCodeMirror, callback);
111 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
140 112
141 113 // on entering the new filename set mode, from given extension
142 setCodeMirrorModeFromInput(
143 modes_select, filename_selector, myCodeMirror, callback);
114 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
144 115
145 // if the file is renderable set line wraps automatically
146 if (renderer !== ""){
147 var line_wrap = 'on';
148 $($('#line_wrap option[value="'+line_wrap+'"]')[0]).attr("selected", "selected");
149 setCodeMirrorLineWrap(myCodeMirror, true);
150 }
151 // on select line wraps change the editor
152 $('#line_wrap').on('change', function(e){
153 var selected = e.currentTarget;
154 var line_wraps = {'on': true, 'off': false}[selected.value];
155 setCodeMirrorLineWrap(myCodeMirror, line_wraps)
156 116 });
157 117
158 // render preview/edit button
159 if (mimetype === 'text/x-rst' || mimetype === 'text/plain') {
160 $('#render_preview').removeClass('hidden');
161 }
162 $('#render_preview').on('click', function(e){
163 if($(this).hasClass('preview')){
164 $(this).removeClass('preview');
165 $(this).html("${_('Edit')}");
166 $('#editor_preview').show();
167 $(myCodeMirror.getWrapperElement()).hide();
168 118
169 var possible_renderer = {
170 'rst':'rst',
171 'markdown':'markdown',
172 'gfm': 'markdown'}[myCodeMirror.getMode().name];
173 var _text = myCodeMirror.getValue();
174 var _renderer = possible_renderer || DEFAULT_RENDERER;
175 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
176 $('#editor_preview').html(_gettext('Loading ...'));
177 var url = pyroutes.url('repo_commit_comment_preview',
178 {'repo_name': '${c.repo_name}',
179 'commit_id': '${c.commit.raw_id}'});
180 ajaxPOST(url, post_data, function(o){
181 $('#editor_preview').html(o);
182 })
183 }
184 else{
185 $(this).addClass('preview');
186 $(this).html("${_('Preview')}");
187 $('#editor_preview').hide();
188 $(myCodeMirror.getWrapperElement()).show();
189 }
190 });
191
192 })
193 119 </script>
194 120 </%def>
@@ -23,17 +23,17 b''
23 23
24 24 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
25 25 ## on branch head, can edit files
26 %if c.on_branch_head and c.branch_or_raw_id and not c.file.is_binary:
26 %if c.on_branch_head and c.branch_or_raw_id:
27 27 ## binary files are delete only
28 28 % if c.file.is_binary:
29 29 ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing binary files not allowed'))}
30 ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit'),class_="btn btn-danger")}
30 ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path),class_="btn btn-danger")}
31 31 % else:
32 <a class="btn btn-default" href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">
32 <a class="btn btn-default" href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path)}">
33 33 ${_('Edit on branch: ')}<code>${c.branch_name}</code>
34 34 </a>
35 35
36 <a class="btn btn-danger" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">
36 <a class="btn btn-danger" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path)}">
37 37 ${_('Delete')}
38 38 </a>
39 39 % endif
@@ -1,7 +1,7 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 ${_('%s Files Add') % c.repo_name}
4 ${_('{} Files Upload').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
@@ -11,180 +11,197 b''
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 <%def name="breadcrumbs_links()">
15 ${_('Add new file')} @ ${h.show_id(c.commit)} ${_('Branch')}: ${c.commit.branch}
16 </%def>
14 <%def name="breadcrumbs_links()"></%def>
17 15
18 16 <%def name="menu_bar_subnav()">
19 17 ${self.repo_menu(active='files')}
20 18 </%def>
21 19
22 20 <%def name="main()">
21
23 22 <div class="box">
23 ## Template for uploads
24 <div style="display: none" id="tpl-dropzone">
25 <div class="dz-preview dz-file-preview">
26 <div class="dz-details">
24 27
25 <div class="edit-file-title">
26 ${self.breadcrumbs()}
28 <div class="dz-filename">
29 <span data-dz-name></span>
30 </div>
31 <div class="dz-filename-size">
32 <span class="dz-size" data-dz-size></span>
33
27 34 </div>
28 35
29 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', enctype="multipart/form-data", class_="form-horizontal", request=request)}
30 <div class="edit-file-fieldset">
31 <div class="fieldset">
32 <div id="destination-label" class="left-label">
33 ${_('Path')}:
36 <div class="dz-sending" style="display: none">${_('Uploading...')}</div>
37 <div class="dz-response" style="display: none">
38 ${_('Uploaded')} 100%
39 </div>
40
34 41 </div>
35 <div class="right-content">
36 <div>
37 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path, request.GET.get('at'))} /
38 <input type="input-small" value="${c.f_path}" size="46" name="location" id="location">
42 <div class="dz-progress">
43 <span class="dz-upload" data-dz-uploadprogress></span>
44 </div>
45
46 <div class="dz-error-message">
39 47 </div>
40 48 </div>
41 49 </div>
42 50
43 <div id="upload_file_container" class="fieldset">
44 <div class="filename-label left-label">
45 ${_('Filename')}:
51 <div class="edit-file-title">
52 <span class="title-heading">${_('Upload new file')} @ <code>${h.show_id(c.commit)}</code></span>
53 <span class="tag branchtag"><i class="icon-branch"></i> ${c.commit.branch}</span>
46 54 </div>
47 <div class="right-content">
48 <input class="input-small" type="text" value="" size="46" name="filename_upload" id="filename_upload" placeholder="${_('No file selected')}">
55
56 <% form_url = h.route_path('repo_files_upload_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path) %>
57 ##${h.secure_form(form_url, id='eform', enctype="multipart/form-data", request=request)}
58 <div class="edit-file-fieldset">
59 <div class="path-items">
60 <ul>
61 <li class="breadcrumb-path">
62 <div>
63 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
64 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
49 65 </div>
50 <div class="filename-label left-label file-upload-label">
51 ${_('Upload file')}:
66 </li>
67 <li class="location-path">
68
69 </li>
70 </ul>
71 </div>
72
52 73 </div>
53 <div class="right-content file-upload-input">
54 <label for="upload_file" class="btn btn-default">Browse</label>
74
75 <div class="upload-form table">
76 <div id="files_data">
55 77
56 <input type="file" name="upload_file" id="upload_file">
78 <div class="dropzone-wrapper" id="file-uploader">
79 <div class="dropzone-pure">
80 <div class="dz-message">
81 <i class="icon-upload" style="font-size:36px"></i></br>
82 ${_("Drag'n Drop files here or")} <span class="link">${_('Choose your files')}</span>.<br>
83 </div>
84 </div>
85
57 86 </div>
58 87 </div>
59 88
60 89 </div>
61 90
62 <div class="table">
63 <div id="files_data">
64 <div id="codeblock" class="codeblock">
65 <div class="code-header form" id="set_mode_header">
66 <div class="fields">
67 ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)}
68 <label for="line_wrap">${_('line wraps')}</label>
69 ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])}
70
71 <div id="render_preview" class="btn btn-small preview hidden" >${_('Preview')}</div>
72 </div>
73 </div>
74 <div id="editor_container">
75 <pre id="editor_pre"></pre>
76 <textarea id="editor" name="content" ></textarea>
77 <div id="editor_preview"></div>
78 </div>
79 </div>
80 </div>
81 </div>
82
83 <div class="edit-file-fieldset">
91 <div class="upload-form edit-file-fieldset">
84 92 <div class="fieldset">
85 <div id="commit-message-label" class="commit-message-label left-label">
86 ${_('Commit Message')}:
87 </div>
88 <div class="right-content">
89 93 <div class="message">
90 94 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
91 95 </div>
92 96 </div>
93 </div>
94 <div class="pull-right">
95 ${h.reset('reset',_('Cancel'),class_="btn btn-small")}
97 <div class="pull-left">
96 98 ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-success")}
97 99 </div>
98 100 </div>
99 ${h.end_form()}
101 ##${h.end_form()}
102
103 <div class="file-upload-transaction-wrapper" style="display: none">
104 <div class="file-upload-transaction">
105 <h3>${_('Commiting...')}</h3>
106 <p>${_('Please wait while the files are being uploaded')}</p>
107 <p class="error" style="display: none">
108
109 </p>
110 <i class="icon-spin animate-spin"></i>
111 <p></p>
100 112 </div>
113 </div>
114
115 </div>
116
101 117 <script type="text/javascript">
102 118
103 $('#commit_btn').on('click', function() {
119 $(document).ready(function () {
120
121 //see: https://www.dropzonejs.com/#configuration
122 myDropzone = new Dropzone("div#file-uploader", {
123 url: "${form_url}",
124 headers: {"X-CSRF-Token": CSRF_TOKEN},
125 paramName: function () {
126 return "files_upload"
127 }, // The name that will be used to transfer the file
128 parallelUploads: 20,
129 maxFiles: 20,
130 uploadMultiple: true,
131 //chunking: true, // use chunking transfer, not supported at the moment
132 //maxFilesize: 2, // in MBs
133 autoProcessQueue: false, // if false queue will not be processed automatically.
134 createImageThumbnails: false,
135 previewTemplate: document.querySelector('#tpl-dropzone').innerHTML,
136 accept: function (file, done) {
137 done();
138 },
139 init: function () {
140 this.on("addedfile", function (file) {
141
142 });
143
144 this.on("sending", function (file, xhr, formData) {
145 formData.append("message", $('#commit').val());
146 $(file.previewElement).find('.dz-sending').show();
147 });
148
149 this.on("success", function (file, response) {
150 $(file.previewElement).find('.dz-sending').hide();
151 $(file.previewElement).find('.dz-response').show();
152
153 if (response.error !== null) {
154 $('.file-upload-transaction-wrapper .error').html('ERROR: {0}'.format(response.error));
155 $('.file-upload-transaction-wrapper .error').show();
156 $('.file-upload-transaction-wrapper i').hide()
157 }
158
159 var redirect_url = response.redirect_url || '/';
160 window.location = redirect_url
161
162 });
163
164 this.on("error", function (file, errorMessage, xhr) {
165 var error = null;
166
167 if (xhr !== undefined){
168 var httpStatus = xhr.status + " " + xhr.statusText;
169 if (xhr.status >= 500) {
170 error = httpStatus;
171 }
172 }
173
174 if (error === null) {
175 error = errorMessage.error || errorMessage || httpStatus;
176 }
177
178 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
179 });
180 }
181 });
182
183 $('#commit_btn').on('click', function(e) {
184 e.preventDefault();
104 185 var button = $(this);
105 186 if (button.hasClass('clicked')) {
106 187 button.attr('disabled', true);
107 188 } else {
108 189 button.addClass('clicked');
109 190 }
110 });
111 191
112 var hide_upload = function(){
113 $('#files_data').show();
114 $('#upload_file_container').hide();
115 $('#filename_container').show();
116 };
117
118 $('#file_enable').on('click', function(e){
192 var files = myDropzone.getQueuedFiles();
193 if (files.length === 0) {
194 alert("Missing files");
119 195 e.preventDefault();
120 hide_upload();
121 });
122
123 var renderer = "";
124 var reset_url = "${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}";
125 var myCodeMirror = initCodeMirror('editor', reset_url, false);
126
127 var modes_select = $('#set_mode');
128 fillCodeMirrorOptions(modes_select);
129
130 var filename_selector = '#filename';
131 var callback = function(filename, mimetype, mode){
132 CodeMirrorPreviewEnable(mode);
133 };
134 // on change of select field set mode
135 setCodeMirrorModeFromSelect(
136 modes_select, filename_selector, myCodeMirror, callback);
137
138 // on entering the new filename set mode, from given extension
139 setCodeMirrorModeFromInput(
140 modes_select, filename_selector, myCodeMirror, callback);
141
142 // if the file is renderable set line wraps automatically
143 if (renderer !== ""){
144 var line_wrap = 'on';
145 $($('#line_wrap option[value="'+line_wrap+'"]')[0]).attr("selected", "selected");
146 setCodeMirrorLineWrap(myCodeMirror, true);
147 196 }
148 197
149 // on select line wraps change the editor
150 $('#line_wrap').on('change', function(e){
151 var selected = e.currentTarget;
152 var line_wraps = {'on': true, 'off': false}[selected.value];
153 setCodeMirrorLineWrap(myCodeMirror, line_wraps)
198 $('.upload-form').hide();
199 $('.file-upload-transaction-wrapper').show();
200 myDropzone.processQueue();
201
154 202 });
155 203
156 // render preview/edit button
157 $('#render_preview').on('click', function(e){
158 if($(this).hasClass('preview')){
159 $(this).removeClass('preview');
160 $(this).html("${_('Edit')}");
161 $('#editor_preview').show();
162 $(myCodeMirror.getWrapperElement()).hide();
163
164 var possible_renderer = {
165 'rst':'rst',
166 'markdown':'markdown',
167 'gfm': 'markdown'}[myCodeMirror.getMode().name];
168 var _text = myCodeMirror.getValue();
169 var _renderer = possible_renderer || DEFAULT_RENDERER;
170 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
171 $('#editor_preview').html(_gettext('Loading ...'));
172 var url = pyroutes.url('repo_commit_comment_preview',
173 {'repo_name': '${c.repo_name}',
174 'commit_id': '${c.commit.raw_id}'});
175
176 ajaxPOST(url, post_data, function(o){
177 $('#editor_preview').html(o);
178 })
179 }
180 else{
181 $(this).addClass('preview');
182 $(this).html("${_('Preview')}");
183 $('#editor_preview').hide();
184 $(myCodeMirror.getWrapperElement()).show();
185 }
186 204 });
187 $('#filename').focus();
188 205
189 206 </script>
190 207 </%def>
General Comments 0
You need to be logged in to leave comments. Login now