Merge pull request #134 from niphlod/issue/admin_refactor

first step to a nicer code style of admin
This commit is contained in:
mdipierro
2013-07-14 12:37:02 -07:00
11 changed files with 816 additions and 1344 deletions
+6 -7
View File
@@ -561,11 +561,11 @@ def edit():
# Load json only if it is ajax edited... # Load json only if it is ajax edited...
app = get_app(request.vars.app) app = get_app(request.vars.app)
if not(request.ajax): if not(request.ajax):
# return the scaffolding, the rest will be through ajax requests # return the scaffolding, the rest will be through ajax requests
response.title = T('Editing %s' % app) response.title = T('Editing %s' % app)
editarea_preferences = {} editarea_preferences = {}
editarea_preferences['FONT_SIZE'] = '10' editarea_preferences['FONT_SIZE'] = '10'
editarea_preferences['FULL_SCREEN'] = 'false' editarea_preferences['FULL_SCREEN'] = 'false'
editarea_preferences['ALLOW_TOGGLE'] = 'true' editarea_preferences['ALLOW_TOGGLE'] = 'true'
editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4' editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4'
@@ -574,7 +574,7 @@ def edit():
if key in globals(): if key in globals():
editarea_preferences[key] = globals()[key] editarea_preferences[key] = globals()[key]
return response.render ('default/edit.html', dict(app=request.args[0], editarea_preferences=editarea_preferences)) return response.render ('default/edit.html', dict(app=request.args[0], editarea_preferences=editarea_preferences))
""" File edit handler """ """ File edit handler """
# Load json only if it is ajax edited... # Load json only if it is ajax edited...
app = get_app(request.vars.app) app = get_app(request.vars.app)
@@ -722,7 +722,7 @@ def edit():
vf = os.path.split(v)[-1] vf = os.path.split(v)[-1]
vargs = "/".join([viewpath.replace(os.sep, "/"), vf]) vargs = "/".join([viewpath.replace(os.sep, "/"), vf])
editviewlinks.append(A(vf.split(".")[0], editviewlinks.append(A(vf.split(".")[0],
_class="editor_filelink", _class="editor_filelink",
_href=URL('edit', args=[vargs]))) _href=URL('edit', args=[vargs])))
if len(request.args) > 2 and request.args[1] == 'controllers': if len(request.args) > 2 and request.args[1] == 'controllers':
@@ -746,11 +746,11 @@ def edit():
view_link=view_link, view_link=view_link,
editviewlinks=editviewlinks, editviewlinks=editviewlinks,
id=IS_SLUG()(filename)[0], id=IS_SLUG()(filename)[0],
force= True if (request.vars.restore or request.vars.revert) else False) force= True if (request.vars.restore or request.vars.revert) else False)
plain_html = response.render('default/edit_js.html', file_details) plain_html = response.render('default/edit_js.html', file_details)
file_details['plain_html'] = plain_html file_details['plain_html'] = plain_html
return response.json(file_details) return response.json(file_details)
def resolve(): def resolve():
""" """
@@ -1770,4 +1770,3 @@ def git_push():
session.flash = T("Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.") session.flash = T("Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.")
redirect(URL('site')) redirect(URL('site'))
return dict(app=app, form=form) return dict(app=app, form=form)
+24 -8
View File
@@ -8,6 +8,7 @@
'%Y-%m-%d': '%d/%m/%Y', '%Y-%m-%d': '%d/%m/%Y',
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', '%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
'(requires internet access)': '(requires internet access)', '(requires internet access)': '(requires internet access)',
'(requires internet access, experimental)': '(requires internet access, experimental)',
'(something like "it-it")': '(qualcosa simile a "it-it")', '(something like "it-it")': '(qualcosa simile a "it-it")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', '@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
@@ -43,6 +44,7 @@
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': "ATTENZIONE: L'accesso richiede una connessione sicura (HTTPS) o l'esecuzione di web2py in locale (connessione su localhost)", 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': "ATTENZIONE: L'accesso richiede una connessione sicura (HTTPS) o l'esecuzione di web2py in locale (connessione su localhost)",
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTZIONE: NON ESEGUIRE PIÙ TEST IN PARALLELO (I TEST NON SONO "THREAD SAFE")', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTZIONE: NON ESEGUIRE PIÙ TEST IN PARALLELO (I TEST NON SONO "THREAD SAFE")',
'ATTENTION: you cannot edit the running application!': "ATTENZIONE: non puoi modificare l'applicazione correntemente in uso ", 'ATTENTION: you cannot edit the running application!': "ATTENZIONE: non puoi modificare l'applicazione correntemente in uso ",
'Autocomplete Python Code': 'Autocomplete Python Code',
'Available databases and tables': 'Database e tabelle disponibili', 'Available databases and tables': 'Database e tabelle disponibili',
'back': 'indietro', 'back': 'indietro',
'cache': 'cache', 'cache': 'cache',
@@ -113,10 +115,12 @@
'Edit': 'modifica', 'Edit': 'modifica',
'Edit application': 'Modifica applicazione', 'Edit application': 'Modifica applicazione',
'edit controller': 'modifica controller', 'edit controller': 'modifica controller',
'edit controller:': 'edit controller:',
'Edit current record': 'Modifica record corrente', 'Edit current record': 'Modifica record corrente',
'edit profile': 'modifica profilo', 'edit profile': 'modifica profilo',
'Edit This App': 'Modifica questa applicazione', 'Edit This App': 'Modifica questa applicazione',
'edit views:': 'modifica viste (view):', 'edit views:': 'modifica viste (view):',
'Editing bigul': 'Editing bigul',
'Editing file "%s"': 'Modifica del file "%s"', 'Editing file "%s"': 'Modifica del file "%s"',
'Editing Language file': 'Modifica file linguaggio', 'Editing Language file': 'Modifica file linguaggio',
'Enterprise Web Framework': 'Enterprise Web Framework', 'Enterprise Web Framework': 'Enterprise Web Framework',
@@ -140,6 +144,8 @@
'file saved on %(time)s': "file salvato nell'istante %(time)s", 'file saved on %(time)s': "file salvato nell'istante %(time)s",
'file saved on %s': 'file salvato: %s', 'file saved on %s': 'file salvato: %s',
'filter': 'filter', 'filter': 'filter',
'Find Next': 'Find Next',
'Find Previous': 'Find Previous',
'Frames': 'Frames', 'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'I test delle funzioni senza "doctests" risulteranno sempre [passed].', 'Functions with no doctests will result in [passed] tests.': 'I test delle funzioni senza "doctests" risulteranno sempre [passed].',
'Get from URL:': 'Get from URL:', 'Get from URL:': 'Get from URL:',
@@ -177,15 +183,16 @@
'License for': 'Licenza relativa a', 'License for': 'Licenza relativa a',
'loading...': 'caricamento...', 'loading...': 'caricamento...',
'locals': 'locals', 'locals': 'locals',
'login': 'accesso',
'Login': 'Accesso', 'Login': 'Accesso',
'login': 'accesso',
'Login to the Administrative Interface': "Accesso all'interfaccia amministrativa", 'Login to the Administrative Interface': "Accesso all'interfaccia amministrativa",
'Logout': 'uscita', 'Logout': 'uscita',
'Main Menu': 'Menu principale', 'Main Menu': 'Menu principale',
'Manage': 'Manage',
'Menu Model': 'Menu Modelli', 'Menu Model': 'Menu Modelli',
'merge': 'unisci', 'merge': 'unisci',
'models': 'modelli',
'Models': 'Modelli', 'Models': 'Modelli',
'models': 'modelli',
'Modules': 'Moduli', 'Modules': 'Moduli',
'modules': 'moduli', 'modules': 'moduli',
'new application "%s" created': 'creata la nuova applicazione "%s"', 'new application "%s" created': 'creata la nuova applicazione "%s"',
@@ -198,6 +205,7 @@
'NO': 'NO', 'NO': 'NO',
'No databases in this application': 'Nessun database presente in questa applicazione', 'No databases in this application': 'Nessun database presente in questa applicazione',
'no match': 'nessuna corrispondenza', 'no match': 'nessuna corrispondenza',
'online designer': 'online designer',
'or alternatively': 'or alternatively', 'or alternatively': 'or alternatively',
'Or Get from URL:': 'Or Get from URL:', 'Or Get from URL:': 'Or Get from URL:',
'or import from csv file': 'oppure importa da file CSV', 'or import from csv file': 'oppure importa da file CSV',
@@ -206,6 +214,7 @@
'Overwrite installed app': 'sovrascrivi applicazione installata', 'Overwrite installed app': 'sovrascrivi applicazione installata',
'Pack all': 'crea pacchetto', 'Pack all': 'crea pacchetto',
'Pack compiled': 'crea pacchetto del codice compilato', 'Pack compiled': 'crea pacchetto del codice compilato',
'Pack custom': 'Pack custom',
'pack plugin': 'crea pacchetto del plugin', 'pack plugin': 'crea pacchetto del plugin',
'PAM authenticated user, cannot change password here': 'utente autenticato tramite PAM, impossibile modificare password qui', 'PAM authenticated user, cannot change password here': 'utente autenticato tramite PAM, impossibile modificare password qui',
'password changed': 'password modificata', 'password changed': 'password modificata',
@@ -217,15 +226,19 @@
'Plural-Forms:': 'Plural-Forms:', 'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Powered by', 'Powered by': 'Powered by',
'previous 100 rows': '100 righe precedenti', 'previous 100 rows': '100 righe precedenti',
'private files': 'private files',
'Private files': 'Private files', 'Private files': 'Private files',
'private files': 'private files',
'Query:': 'Richiesta (query):', 'Query:': 'Richiesta (query):',
'Rapid Search': 'Rapid Search',
'record': 'record', 'record': 'record',
'record does not exist': 'il record non esiste', 'record does not exist': 'il record non esiste',
'record id': 'ID del record', 'record id': 'ID del record',
'register': 'registrazione', 'register': 'registrazione',
'reload': 'reload', 'reload': 'reload',
'Reload routes': 'Reload routes',
'Remove compiled': 'rimozione codice compilato', 'Remove compiled': 'rimozione codice compilato',
'Replace': 'Replace',
'Replace All': 'Replace All',
'request': 'request', 'request': 'request',
'Resolve Conflict file': 'File di risoluzione conflitto', 'Resolve Conflict file': 'File di risoluzione conflitto',
'response': 'response', 'response': 'response',
@@ -237,6 +250,8 @@
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
'Running on %s': 'Running on %s', 'Running on %s': 'Running on %s',
'Save': 'Save', 'Save': 'Save',
'Save file:': 'Save file:',
'Save file: %s': 'Save file: %s',
'Save via Ajax': 'Save via Ajax', 'Save via Ajax': 'Save via Ajax',
'Saved file hash:': 'Hash del file salvato:', 'Saved file hash:': 'Hash del file salvato:',
'selected': 'selezionato', 'selected': 'selezionato',
@@ -245,23 +260,24 @@
'shell': 'shell', 'shell': 'shell',
'Site': 'sito', 'Site': 'sito',
'some files could not be removed': 'non è stato possibile rimuovere alcuni files', 'some files could not be removed': 'non è stato possibile rimuovere alcuni files',
'Start searching': 'Start searching',
'Start wizard': 'start wizard', 'Start wizard': 'start wizard',
'state': 'stato', 'state': 'stato',
'static': 'statico', 'static': 'statico',
'Static': 'Static', 'Static': 'Static',
'Static files': 'Files statici', 'Static files': 'Files statici',
'Stylesheet': 'Foglio di stile (stylesheet)', 'Stylesheet': 'Foglio di stile (stylesheet)',
'submit': 'invia',
'Submit': 'Submit', 'Submit': 'Submit',
'submit': 'invia',
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?', 'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
'table': 'tabella', 'table': 'tabella',
'test': 'test', 'test': 'test',
'Testing application': 'Test applicazione in corsg', 'Testing application': 'Test applicazione in corsg',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La richiesta (query) è una condizione come ad esempio "db.tabella1.campo1==\'valore\'". Una condizione come "db.tabella1.campo1==db.tabella2.campo2" produce un "JOIN" SQL.', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La richiesta (query) è una condizione come ad esempio "db.tabella1.campo1==\'valore\'". Una condizione come "db.tabella1.campo1==db.tabella2.campo2" produce un "JOIN" SQL.',
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
'the application logic, each URL path is mapped in one exposed function in the controller': 'logica dell\'applicazione, ogni percorso "URL" corrisponde ad una funzione esposta da un controller', 'the application logic, each URL path is mapped in one exposed function in the controller': 'logica dell\'applicazione, ogni percorso "URL" corrisponde ad una funzione esposta da un controller',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
'the data representation, define database tables and sets': 'rappresentazione dei dati, definizione di tabelle di database e di "set" ', 'the data representation, define database tables and sets': 'rappresentazione dei dati, definizione di tabelle di database e di "set" ',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
'the presentations layer, views are also known as templates': 'Presentazione dell\'applicazione, viste (views, chiamate anche "templates")', 'the presentations layer, views are also known as templates': 'Presentazione dell\'applicazione, viste (views, chiamate anche "templates")',
'There are no controllers': 'Non ci sono controller', 'There are no controllers': 'Non ci sono controller',
@@ -273,8 +289,8 @@
'There are no translators, only default language is supported': 'Non ci sono traduzioni, viene solo supportato il linguaggio di base', 'There are no translators, only default language is supported': 'Non ci sono traduzioni, viene solo supportato il linguaggio di base',
'There are no views': 'Non ci sono viste ("view")', 'There are no views': 'Non ci sono viste ("view")',
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
'these files are served without processing, your images go here': 'questi files vengono serviti così come sono, le immagini vanno qui',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here', 'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
'these files are served without processing, your images go here': 'questi files vengono serviti così come sono, le immagini vanno qui',
'This is the %(filename)s template': 'Questo è il template %(filename)s', 'This is the %(filename)s template': 'Questo è il template %(filename)s',
'Ticket': 'Ticket', 'Ticket': 'Ticket',
'Ticket ID': 'Ticket ID', 'Ticket ID': 'Ticket ID',
@@ -322,8 +338,8 @@
'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s', 'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s',
'versioning': 'sistema di versioni', 'versioning': 'sistema di versioni',
'Versioning': 'Versioning', 'Versioning': 'Versioning',
'view': 'vista',
'View': 'Vista', 'View': 'Vista',
'view': 'vista',
'Views': 'viste', 'Views': 'viste',
'views': 'viste', 'views': 'viste',
'Web Framework': 'Web Framework', 'Web Framework': 'Web Framework',
+242 -223
View File
@@ -1,262 +1,281 @@
function prepareDataForSave(name,data) { function prepareDataForSave(name, data) {
var obj = new Object(); var obj = new Object();
obj.Name = name; obj.Name = name;
obj.Data = data; obj.Data = data;
return obj; return obj;
} }
function prepareMultiPartPOST(data) { function prepareMultiPartPOST(data) {
// var boundary = 'sPlItME' + Math.floor(Math.random()*10000); // var boundary = 'sPlItME' + Math.floor(Math.random()*10000);
var boundary = '' + Math.floor(Math.random()*10000); var boundary = '' + Math.floor(Math.random() * 10000);
var reqdata = '--' + boundary + '\r\n'; var reqdata = '--' + boundary + '\r\n';
//console.log(data.length); //console.log(data.length);
for (var i=0;i < data.length;i++) { for(var i = 0; i < data.length; i++) {
reqdata += 'content-disposition: form-data; name="'; reqdata += 'content-disposition: form-data; name="';
reqdata += data[i].Name + '"'; reqdata += data[i].Name + '"';
reqdata += "\r\n\r\n" ; reqdata += "\r\n\r\n";
reqdata += data[i].Data; reqdata += data[i].Data;
reqdata += "\r\n" ; reqdata += "\r\n";
reqdata += '--' + boundary + '\r\n'; reqdata += '--' + boundary + '\r\n';
} }
return new Array(reqdata,boundary); return new Array(reqdata, boundary);
} }
function on_error() { function on_error() {
jQuery("input[name='saved_on']").attr('style','background-color:red'); jQuery("input[name='saved_on']").attr('style', 'background-color:red');
jQuery("input[name='saved_on']").val('communication error'); jQuery("input[name='saved_on']").val('communication error');
} }
function doHighlight(highlight) { function doHighlight(highlight) {
// Put the cursor at the offending line: // Put the cursor at the offending line:
editor.setCursor({line:highlight.lineno-1, editor.setCursor({
ch:highlight.offset+1}); line: highlight.lineno - 1,
} ch: highlight.offset + 1
});
}
function doClickSave() { function doClickSave() {
var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id'); var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id');
var editor = jQuery (currentTabID + ' textarea').data('editor'); var editor = jQuery(currentTabID + ' textarea').data('editor');
var data = editor.getValue(); var data = editor.getValue();
var dataForPost = prepareMultiPartPOST(new Array( var dataForPost = prepareMultiPartPOST(new Array(
prepareDataForSave('data', data), prepareDataForSave('data', data),
prepareDataForSave('file_hash', prepareDataForSave('file_hash',
jQuery(currentTabID + " input[name='file_hash']").val()), jQuery(currentTabID + " input[name='file_hash']").val()),
prepareDataForSave('saved_on', prepareDataForSave('saved_on',
jQuery(currentTabID + " input[name='saved_on']").val()), jQuery(currentTabID + " input[name='saved_on']").val()),
prepareDataForSave('saved_on', prepareDataForSave('saved_on',
jQuery(currentTabID + " input[name='saved_on']").val()), jQuery(currentTabID + " input[name='saved_on']").val()),
prepareDataForSave('from_ajax','true'))); prepareDataForSave('from_ajax', 'true')));
// console.info(area.textarea.value); // console.info(area.textarea.value);
jQuery(currentTabID + " input[name='saved_on']").attr('style', jQuery(currentTabID + " input[name='saved_on']").attr('style',
'background-color:yellow'); 'background-color:yellow');
jQuery(currentTabID + " input[name='saved_on']").val('saving now...') jQuery(currentTabID + " input[name='saved_on']").val('saving now...')
currentUrl = jQuery(currentTabID + ' form').attr('action'); currentUrl = jQuery(currentTabID + ' form').attr('action');
jQuery.ajax({ jQuery.ajax({
type: "POST", type: "POST",
contentType: 'multipart/form-data;boundary="' contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
+ dataForPost[1] + '"', url: currentUrl,
url: currentUrl, dataType: "json",
dataType: "json", data: dataForPost[0],
data: dataForPost[0], timeout: 5000,
timeout: 5000, beforeSend: function (xhr) {
beforeSend: function(xhr) { xhr.setRequestHeader('web2py-component-location',
xhr.setRequestHeader('web2py-component-location', document.location);
document.location); xhr.setRequestHeader('web2py-component-element',
xhr.setRequestHeader('web2py-component-element', 'doClickSave');
'doClickSave'); },
}, success: function (json, text, xhr) {
success: function(json,text,xhr){ jQuery(editor).data('saved', true); // Set as saved
jQuery(editor).data('saved', true); // Set as saved editor.on("change", store_changes_function); // Re-enable change watcher
editor.on("change", store_changes_function); // Re-enable change watcher // reenable disabled submit button
// reenable disabled submit button var t = jQuery("input[name='save']");
var t=jQuery("input[name='save']"); t.attr('class', '');
t.attr('class',''); t.attr('disabled', '');
t.attr('disabled',''); try {
try { if(json.error) {
if (json.error) { window.location.href = json.redirect;
window.location.href=json.redirect; } else {
} else { // console.info( json.file_hash );
// console.info( json.file_hash ); jQuery(currentTabID + " input[name='file_hash']").val(json.file_hash);
jQuery(currentTabID + " input[name='file_hash']").val(json.file_hash); jQuery(currentTabID + " input[name='saved_on']").val(json.saved_on);
jQuery(currentTabID + " input[name='saved_on']").val(json.saved_on); if(json.highlight) {
if (json.highlight) { doHighlight(json.highlight);
doHighlight(json.highlight); } else {
} else { jQuery(currentTabID + " input[name='saved_on']").attr('style', 'background-color:#99FF99');
jQuery(currentTabID + " input[name='saved_on']").attr('style','background-color:#99FF99'); //jQuery(".flash").delay(1000).fadeOut('slow');
//jQuery(".flash").delay(1000).fadeOut('slow'); }
} // console.info(jQuery("input[name='file_hash']").val());
// console.info(jQuery("input[name='file_hash']").val()); var output = '<b>exposes:</b> ';
var output = '<b>exposes:</b> '; for(var i in json.functions) {
for ( var i in json.functions) { output += ' <a target="_blank" href="/' + json.application + '/' + json.controller + '/' + json.functions[i] + '">' + json.functions[i] + '</a>,';
output += ' <a target="_blank" href="/' + json.application + '/' + json.controller + '/' + json.functions[i] + '">' + json.functions[i] + '</a>,'; }
} if(output != '<b>exposes:</b> ') {
if(output!='<b>exposes:</b> ') { jQuery(currentTabID + " .exposed").html(output.substring(0, output.length - 1));
jQuery(currentTabID + " .exposed").html( output.substring(0, output.length-1)); }
} }
} } catch(e) {
} catch(e) { on_error();} on_error();
}, }
error: function(json) { on_error(); } },
}); error: function (json) {
return false; on_error();
}
});
return false;
} }
function getActiveEditor() { function getActiveEditor() {
var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id'); var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id');
var editor = jQuery (currentTabID + ' textarea').data('editor'); var editor = jQuery(currentTabID + ' textarea').data('editor');
return editor; return editor;
} }
function getSelectionRange() { function getSelectionRange() {
var editor = getActiveEditor(); var editor = getActiveEditor();
var sel = {}; var sel = {};
sel['start'] = editor.getCursor(true).line; sel['start'] = editor.getCursor(true).line;
sel['end'] = editor.getCursor(false).line; sel['end'] = editor.getCursor(false).line;
sel['data'] = ''; sel['data'] = '';
return sel; return sel;
} }
function doToggleBreakpoint(filename, url, sel) { function doToggleBreakpoint(filename, url, sel) {
var editor = getActiveEditor(); var editor = getActiveEditor();
if (sel==null) { if(sel == null) {
// use cursor position to determine the breakpoint line // use cursor position to determine the breakpoint line
// (gutter already tell us the selected line) // (gutter already tell us the selected line)
sel = getSelectionRange(); sel = getSelectionRange();
}
var dataForPost = prepareMultiPartPOST(new Array(
prepareDataForSave('filename', filename),
prepareDataForSave('sel_start', sel["start"]),
prepareDataForSave('sel_end', sel["end"]),
prepareDataForSave('data', sel['data'])));
jQuery.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
url: url,
dataType: "json",
data: dataForPost[0],
timeout: 5000,
beforeSend: function (xhr) {
xhr.setRequestHeader('web2py-component-location',
document.location);
xhr.setRequestHeader('web2py-component-element',
'doSetBreakpoint');
},
success: function (json, text, xhr) {
// show flash message (if any)
var flash = xhr.getResponseHeader('web2py-component-flash');
if(flash) {
jQuery('.flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
} else jQuery('.flash').hide();
try {
if(json.error) {
window.location.href = json.redirect;
} else {
if(json.ok == true) {
// mark the breakpoint if ok=True
editor.setGutterMarker(json.lineno - 1, "breakpoints", makeMarker());
} else if(json.ok == false) {
// remove mark if ok=False
editor.setGutterMarker(json.lineno - 1, "breakpoints", null);
}
}
} catch(e) {
on_error();
}
},
error: function (json) {
on_error();
} }
var dataForPost = prepareMultiPartPOST(new Array( });
prepareDataForSave('filename', filename), return false;
prepareDataForSave('sel_start', sel["start"]),
prepareDataForSave('sel_end', sel["end"]),
prepareDataForSave('data', sel['data'])));
jQuery.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="'+dataForPost[1]+'"',
url: url,
dataType: "json",
data: dataForPost[0],
timeout: 5000,
beforeSend: function(xhr) {
xhr.setRequestHeader('web2py-component-location',
document.location);
xhr.setRequestHeader('web2py-component-element',
'doSetBreakpoint');},
success: function(json,text,xhr){
// show flash message (if any)
var flash=xhr.getResponseHeader('web2py-component-flash');
if (flash) {
jQuery('.flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
}
else jQuery('.flash').hide();
try {
if (json.error) {
window.location.href=json.redirect;
} else {
if (json.ok==true) {
// mark the breakpoint if ok=True
editor.setGutterMarker(json.lineno-1, "breakpoints", makeMarker());
} else if (json.ok==false) {
// remove mark if ok=False
editor.setGutterMarker(json.lineno-1, "breakpoints", null);
}
}
} catch(e) { on_error(); }
},
error: function(json) { on_error(); }
});
return false;
} }
// on load, update all breakpoints markers: // on load, update all breakpoints markers:
function doListBreakpoints(filename, url, editor) { function doListBreakpoints(filename, url, editor) {
var dataForPost = prepareMultiPartPOST(new Array( var dataForPost = prepareMultiPartPOST(new Array(
prepareDataForSave('filename', filename) prepareDataForSave('filename', filename)
)); ));
jQuery.ajax({ jQuery.ajax({
type: "POST", type: "POST",
contentType: 'multipart/form-data;boundary="'+dataForPost[1]+'"', contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
url: url, url: url,
dataType: "json", dataType: "json",
data: dataForPost[0], data: dataForPost[0],
timeout: 5000, timeout: 5000,
beforeSend: function(xhr) { beforeSend: function (xhr) {
xhr.setRequestHeader('web2py-component-location', xhr.setRequestHeader('web2py-component-location',
document.location); document.location);
xhr.setRequestHeader('web2py-component-element', xhr.setRequestHeader('web2py-component-element',
'doListBreakpoints');}, 'doListBreakpoints');
success: function(json,text,xhr){ },
try { success: function (json, text, xhr) {
if (json.error) { try {
window.location.href=json.redirect; if(json.error) {
} else { window.location.href = json.redirect;
var editor = getActiveEditor(); } else {
for (i in json.breakpoints) { var editor = getActiveEditor();
lineno = json.breakpoints[i]; for(i in json.breakpoints) {
// mark the breakpoint if ok=True lineno = json.breakpoints[i];
editor.setGutterMarker(lineno-1, "breakpoints",makeMarker()); // mark the breakpoint if ok=True
} editor.setGutterMarker(lineno - 1, "breakpoints", makeMarker());
} }
} catch(e) { on_error(); } }
}, } catch(e) {
error: function(json) { on_error(); } on_error();
}); }
return false; },
error: function (json) {
on_error();
}
});
return false;
} }
function makeMarker() { function makeMarker() {
var marker = document.createElement("div"); var marker = document.createElement("div");
marker.style.color = "#822"; marker.style.color = "#822";
marker.innerHTML = "●"; marker.innerHTML = "●";
marker.className = "breakpoint"; marker.className = "breakpoint";
return marker; return marker;
} }
function keepalive(url) { function keepalive(url) {
jQuery.ajax({ jQuery.ajax({
type: "GET", type: "GET",
url: url, url: url,
timeout: 1000, timeout: 1000,
success: function(){}, success: function () {},
error: function(x) { on_error(); } }); error: function (x) {
on_error();
}
});
} }
function load_file (url) { function load_file(url) {
jQuery.ajax({ jQuery.ajax({
type: "GET", type: "GET",
dataType: 'json', dataType: 'json',
url: url, url: url,
timeout: 1000, timeout: 1000,
success: function(json){ success: function (json) {
if (typeof(json['plain_html']) !== undefined) { if(typeof (json['plain_html']) !== undefined) {
if (jQuery('#' + json['id']).length === 0 || json['force'] === true) { if(jQuery('#' + json['id']).length === 0 || json['force'] === true) {
// Create a tab and put the code in it // Create a tab and put the code in it
var tab_header = '<li><a href="#'+json['id']+'" data-toggle="tab">'+json['filename']+'<button type="button" class="close">&times;</button></a></li>'; var tab_header = '<li><a href="#' + json['id'] + '" data-toggle="tab">' + json['filename'] + '<button type="button" class="close">&times;</button></a></li>';
var tab_body = '<div id="' + json['id'] + '" class="tab-pane fade in " >' + json['plain_html'] + '</div>'; var tab_body = '<div id="' + json['id'] + '" class="tab-pane fade in " >' + json['plain_html'] + '</div>';
if (json['force'] === false) { if(json['force'] === false) {
jQuery('#filesTab').append(jQuery(tab_header)); jQuery('#filesTab').append(jQuery(tab_header));
jQuery('#myTabContent').append(jQuery(tab_body)); jQuery('#myTabContent').append(jQuery(tab_body));
} else { } else {
jQuery('#' + json['id']).html(jQuery(tab_body)); jQuery('#' + json['id']).html(jQuery(tab_body));
} }
} }
jQuery("a[href='#" + json['id'] + "']" ).click(); jQuery("a[href='#" + json['id'] + "']").click();
} }
}, },
error: function(x) { on_error(); } error: function (x) {
}); on_error();
}
});
} }
function set_font(editor, incr) { function set_font(editor, incr) {
var fontSize = ''; var fontSize = '';
if (incr !== 0) { if(incr !== 0) {
fontSize = parseInt(jQuery(editor.getWrapperElement()).css('font-size')); fontSize = parseInt(jQuery(editor.getWrapperElement()).css('font-size'));
fontSize = fontSize + incr + "px"; fontSize = fontSize + incr + "px";
} }
jQuery(editor.getWrapperElement()).css('font-size', fontSize); jQuery(editor.getWrapperElement()).css('font-size', fontSize);
editor.refresh(); editor.refresh();
} }
var template_js = '<p class="repo-name">{{{a_tag}}}</p><small>{{address}}</small>'; var template_js = '<p class="repo-name">{{{a_tag}}}</p><small>{{address}}</small>';
File diff suppressed because one or more lines are too long
+141 -141
View File
@@ -10,9 +10,9 @@
return files return files
def editfile(path,file,vars={}): def editfile(path,file,vars={}):
args=(path,file) if 'app' in vars else (app,path,file) args=(path,file) if 'app' in vars else (app,path,file)
url = URL('edit', args=args, vars=vars) url = URL('edit', args=args, vars=vars)
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;') return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
}} }}
{{cm=URL('static','codemirror')}} {{cm=URL('static','codemirror')}}
<link rel="stylesheet" href="{{=cm}}/lib/codemirror.css"> <link rel="stylesheet" href="{{=cm}}/lib/codemirror.css">
@@ -38,123 +38,123 @@
<link rel="stylesheet" href="{{=cm}}/addon/dialog/dialog.css"> <link rel="stylesheet" href="{{=cm}}/addon/dialog/dialog.css">
<script src="{{=cm}}/addon/selection/active-line.js"></script> <script src="{{=cm}}/addon/selection/active-line.js"></script>
<script src="{{=cm}}/emmet.min.js"></script> <script src="{{=cm}}/emmet.min.js"></script>
<script language="Javascript" type="text/javascript" src="{{=URL('static','js/ajax_editor.js')}}"></script> <script src="{{=URL('static','js/ajax_editor.js')}}"></script>
<link rel="stylesheet" href="{{=URL('static/css','typeahead.js-bootstrap.css')}}"> <link rel="stylesheet" href="{{=URL('static/css','typeahead.js-bootstrap.css')}}">
<link rel="stylesheet" href="{{=URL('static/css','web2py-codemirror.css')}}"> <link rel="stylesheet" href="{{=URL('static/css','web2py-codemirror.css')}}">
<script language="Javascript" type="text/javascript"> <script type="text/javascript">
var current_theme = "web2py"; //Default theme var current_theme = "web2py"; //Default theme
var current_font_incr = 0; // Default font-size, 0 means don't set var current_font_incr = 0; // Default font-size, 0 means don't set
jQuery(document).on('shown click', 'a[data-toggle="tab"]', function (e) { jQuery(document).on('shown click', 'a[data-toggle="tab"]', function (e) {
var tab_id = jQuery(this).attr('href'); var tab_id = jQuery(this).attr('href');
var editor = jQuery(tab_id + " textarea").data('editor'); var editor = jQuery(tab_id + " textarea").data('editor');
if (editor) { if (editor) {
editor.setSize(jQuery(tab_id).width(), jQuery(tab_id).height()); editor.setSize(jQuery(tab_id).width(), jQuery(tab_id).height());
editor.refresh(); editor.refresh();
} }
//jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");}); //jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");});
}); });
// Close the selected tab // Close the selected tab
jQuery(document).on('click', '#filesTab button[class="close"]', function (e) { jQuery(document).on('click', '#filesTab button[class="close"]', function (e) {
var tab_body = jQuery(jQuery(this).parent().attr("href")); // it should be a div var tab_body = jQuery(jQuery(this).parent().attr("href")); // it should be a div
var tab_header = jQuery(this).parent().parent(); // it should be a li var tab_header = jQuery(this).parent().parent(); // it should be a li
var saved = jQuery(tab_body.find('textarea').data('editor')).data('saved'); var saved = jQuery(tab_body.find('textarea').data('editor')).data('saved');
var close = true; var close = true;
if (saved === false) { if (saved === false) {
close = confirm("You are closing an unsaved file") close = confirm("You are closing an unsaved file")
} }
if (close) { if (close) {
if (tab_header.hasClass('active') === true) { //Set active an other tab if (tab_header.hasClass('active') === true) { //Set active an other tab
jQuery(tab_header).prev().children('a[data-toggle="tab"]').tab('show'); // Select first tab jQuery(tab_header).prev().children('a[data-toggle="tab"]').tab('show'); // Select first tab
} }
tab_header.remove(); //remove li of tab tab_header.remove(); //remove li of tab
tab_body.remove(); //remove li of tab tab_body.remove(); //remove li of tab
} }
}); });
// Revert current file // Revert current file
jQuery(document).on('click', '#revert', function (e) { jQuery(document).on('click', '#revert', function (e) {
e.preventDefault(); e.preventDefault();
load_file(jQuery(this).attr("href")); load_file(jQuery(this).attr("href"));
}); });
// Restore current file // Restore current file
jQuery(document).on('click', '#restore', function (e) { jQuery(document).on('click', '#restore', function (e) {
e.preventDefault(); e.preventDefault();
load_file(jQuery(this).attr("href")); load_file(jQuery(this).attr("href"));
}); });
// open the selected file // open the selected file
jQuery(document).on('click', 'a.editor_filelink', function (e) { jQuery(document).on('click', 'a.editor_filelink', function (e) {
e.preventDefault(); e.preventDefault();
var url = jQuery(this).attr("href"); var url = jQuery(this).attr("href");
load_file(url); load_file(url);
}); });
// change the codemirror theme // change the codemirror theme
jQuery(document).on('click', '#themes a', function (e) { jQuery(document).on('click', '#themes a', function (e) {
e.preventDefault(); e.preventDefault();
var href = jQuery(this).attr('href'); var href = jQuery(this).attr('href');
var name = jQuery(this).text().replace('.css', ''); var name = jQuery(this).text().replace('.css', '');
var link = jQuery("<link>"); var link = jQuery("<link>");
link.attr({ link.attr({
type: 'text/css', type: 'text/css',
rel: 'stylesheet', rel: 'stylesheet',
href: href href: href
}); });
jQuery("head").append( link ); jQuery("head").append( link );
jQuery('textarea[name="data"]') .each(function(id, ta) { jQuery('textarea[name="data"]') .each(function(id, ta) {
editor = jQuery(ta).data('editor'); editor = jQuery(ta).data('editor');
editor.setOption("theme", name); editor.setOption("theme", name);
}); });
jQuery('#themeName').html(name); jQuery('#themeName').html(name);
current_theme = name; current_theme = name;
//#TODO save on session //#TODO save on session
}); });
// incr/decr editor font-size // incr/decr editor font-size
jQuery(document).on('click', 'a.font_button', function (e) { jQuery(document).on('click', 'a.font_button', function (e) {
e.preventDefault(); e.preventDefault();
var id = jQuery(this).attr('id'); var id = jQuery(this).attr('id');
var new_font_incr; var new_font_incr;
switch (id) { switch (id) {
case 'incr': new_incr = 2; break; case 'incr': new_incr = 2; break;
case 'decr': new_incr = -2; break; case 'decr': new_incr = -2; break;
case 'default': new_incr = 0; break; case 'default': new_incr = 0; break;
} }
jQuery('textarea[name="data"]') .each(function(id, ta) { jQuery('textarea[name="data"]') .each(function(id, ta) {
editor = jQuery(ta).data('editor'); editor = jQuery(ta).data('editor');
set_font(editor, new_incr); set_font(editor, new_incr);
}); });
current_font_incr = (new_incr !== 0) ? current_font_incr + new_incr : 0; current_font_incr = (new_incr !== 0) ? current_font_incr + new_incr : 0;
}); });
function isFullScreen(instance) { function isFullScreen(instance) {
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className); return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
} }
function winHeight() { function winHeight() {
return window.innerHeight || (document.documentElement || document.body).clientHeight; return window.innerHeight || (document.documentElement || document.body).clientHeight;
} }
function setFullScreen(instance, full) { function setFullScreen(instance, full) {
var wrap = instance.getWrapperElement() var wrap = instance.getWrapperElement()
if (full) { if (full) {
wrap.className += " CodeMirror-fullscreen"; wrap.className += " CodeMirror-fullscreen";
wrap.style.height = winHeight() + "px"; wrap.style.height = winHeight() + "px";
document.documentElement.style.overflow = "hidden"; document.documentElement.style.overflow = "hidden";
} else { } else {
wrap.className = wrap.className.replace(" CodeMirror-fullscreen", ""); wrap.className = wrap.className.replace(" CodeMirror-fullscreen", "");
wrap.style.height = ""; wrap.style.height = "";
document.documentElement.style.overflow = ""; document.documentElement.style.overflow = "";
} }
instance.refresh(); instance.refresh();
} }
CodeMirror.on(window, "resize", function() { CodeMirror.on(window, "resize", function() {
var showing = document.body.getElementsByClassName("CodeMirror-fullscreen")[0]; var showing = document.body.getElementsByClassName("CodeMirror-fullscreen")[0];
if (!showing) return; if (!showing) return;
showing.CodeMirror.getWrappererElement().style.height = winHeight() + "px"; showing.CodeMirror.getWrappererElement().style.height = winHeight() + "px";
}); });
{{if len(request.args) > 1:}} {{if len(request.args) > 1:}}
load_file('{{=URL(f='edit', args=request.args, vars=request.get_vars)}}'); load_file('{{=URL(f='edit', args=request.args, vars=request.get_vars)}}');
{{pass}} {{pass}}
</script> </script>
@@ -167,17 +167,17 @@ jQuery(document).on('click', 'a.font_button', function (e) {
<a class="button btn" onclick="jQuery('#files').toggle(); return false" href="#">Files toggle</a> <a class="button btn" onclick="jQuery('#files').toggle(); return false" href="#">Files toggle</a>
</div> </div>
<div class="dropdown btn-group pull-left"> <div class="dropdown btn-group pull-left">
<a class="dropdown-toggle button btn" data-target="themes" data-toggle="dropdown" href="#" >Theme: <span id="themeName" style="color: #E8953C">Web2py</span> <span class="caret"></span></a> <a class="dropdown-toggle button btn" data-target="themes" data-toggle="dropdown" href="#" >Theme: <span id="themeName" style="color: #E8953C">Web2py</span> <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" id="themes"> <ul class="dropdown-menu" role="menu" id="themes">
{{for f in listfiles('admin', "static/codemirror/theme", regexp='.*\.css$' ):}} {{for f in listfiles('admin', "static/codemirror/theme", regexp='.*\.css$' ):}}
<li class=""><a href="{{=URL('static/codemirror/theme', f, host=True)}}">{{=f[:-4]}}</a></li> <li class=""><a href="{{=URL('static/codemirror/theme', f, host=True)}}">{{=f[:-4]}}</a></li>
{{pass}} {{pass}}
</ul> </ul>
</div> </div>
<div class="btn-group"> <div class="btn-group">
<a id="decr" class="button btn font_button">-</a> <a id="decr" class="button btn font_button">-</a>
<a id="default" class="button btn font_button" >A</a> <a id="default" class="button btn font_button" >A</a>
<a id="incr" class="button btn font_button">+</a> <a id="incr" class="button btn font_button">+</a>
</div> </div>
<div class="btn-group"> <div class="btn-group">
{{=button(URL('design',args=request.vars.app if request.vars.app else request.args[0], anchor=request.vars.id), T('back'))}} {{=button(URL('design',args=request.vars.app if request.vars.app else request.args[0], anchor=request.vars.id), T('back'))}}
@@ -190,52 +190,52 @@ jQuery(document).on('click', 'a.font_button', function (e) {
</div> </div>
<div id="editor_area" class="row-fluid"> <div id="editor_area" class="row-fluid">
<div id="files"> <div id="files">
<ul class="nav nav-list span2 well" rel="pagebookmark" id="filelist"> <ul class="nav nav-list span2 well" rel="pagebookmark" id="filelist">
<li><input type="text" placeholder="{{=T('Rapid Search')}}" class="input-block-level typeahead-tw search-query"></li> <li><input type="text" placeholder="{{=T('Rapid Search')}}" class="input-block-level typeahead-tw search-query"></li>
{{dirs=[{'name':'models', 'reg':'.*\.py$'}, {{dirs=[{'name':'models', 'reg':'.*\.py$'},
{'name':'controllers', 'reg':'.*\.py$'}, {'name':'controllers', 'reg':'.*\.py$'},
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'}, {'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
{'name':'modules', 'reg':'.*\.py$'}, {'name':'modules', 'reg':'.*\.py$'},
{'name':'private', 'reg': '[^\.#].*'}]}} {'name':'private', 'reg': '[^\.#].*'}]}}
{{auto_complete_list=[]}} {{auto_complete_list=[]}}
{{for dir in dirs:}} {{for dir in dirs:}}
<li class="nav-header component" onclick="collapse('{{="%s_files" % dir['name']}}');">{{=dir['name']}}</li> <li class="nav-header component" onclick="collapse('{{="%s_files" % dir['name']}}');">{{=dir['name']}}</li>
<li id="{{="%s_files" % dir['name']}}"> <li id="{{="%s_files" % dir['name']}}">
<ul class="nav nav-list small-font"> <ul class="nav nav-list small-font">
{{for f in listfiles(app, dir['name'], regexp=dir['reg'] ):}} {{for f in listfiles(app, dir['name'], regexp=dir['reg'] ):}}
{{id="%s__" % dir['name'] + f.replace('.','__')}} {{id="%s__" % dir['name'] + f.replace('.','__')}}
{{current_file = request.args(len(request.args) - 1)}} {{current_file = request.args(len(request.args) - 1)}}
<li class="{{#='active' if current_file==f else ''}}" style="overflow:hidden"> <li class="{{#='active' if current_file==f else ''}}" style="overflow:hidden">
{{a_tag=editfile(dir['name'], f, dict(id=id))}} {{a_tag=editfile(dir['name'], f, dict(id=id))}}
{{=a_tag}} {{=a_tag}}
{{auto_complete_list.append({'value':f, 'tokens':f.split('/'), 'a_tag':a_tag})}} {{auto_complete_list.append({'value':f, 'tokens':f.split('/'), 'a_tag':a_tag})}}
</li> </li>
{{pass}} {{pass}}
</ul> </ul>
</li> </li>
{{pass}} {{pass}}
</ul> </ul>
</div> </div>
<div class="span10" id="edit_placeholder"> <div class="span10" id="edit_placeholder">
<ul class="nav nav-tabs " id="filesTab"> <ul class="nav nav-tabs " id="filesTab">
</ul> </ul>
<div id="myTabContent" class="tab-content"> <div id="myTabContent" class="tab-content">
</div> </div>
</div> </div>
</div> </div>
<!-- Typeahead scripts here so the page load faster --> <!-- Typeahead scripts here so the page load faster -->
<script src="{{=URL('static/js', 'typeahead.min.js')}}"></script> <script src="{{=URL('static/js', 'typeahead.min.js')}}"></script>
<script src="{{=URL('static/js', 'hogan-2.0.0.js')}}"></script> <script src="{{=URL('static/js', 'hogan-2.0.0.js')}}"></script>
<script> <script>
jQuery('.typeahead-tw').typeahead({ jQuery('.typeahead-tw').typeahead({
name: 'files', name: 'files',
local:{{from gluon.serializers import json}}{{=XML(json(auto_complete_list))}}, local:{{from gluon.serializers import json}}{{=XML(json(auto_complete_list))}},
template: template_js, template: template_js,
engine: Hogan, engine: Hogan,
}); });
jQuery(document).on("typeahead:selected", '.typeahead', function(e, datum) { jQuery(document).on("typeahead:selected", '.typeahead', function(e, datum) {
load_file(datum.link); load_file(datum.link);
jQuery(this).val(''); jQuery(this).val('');
}); });
</script> </script>
<!-- end "edit" block --> <!-- end "edit" block -->
+137 -137
View File
@@ -4,168 +4,168 @@
<form action="{{=URL('edit', args=filename)}}" method="post" name="editform" id="editform" class="form-inline row-fluid"> <form action="{{=URL('edit', args=filename)}}" method="post" name="editform" id="editform" class="form-inline row-fluid">
<div class="span12 well well-small"> <div class="span12 well well-small">
<label class="">{{=T('Save file:')}}</label> <label class="">{{=T('Save file:')}}</label>
<a value="save" title="{{=T('Save file: %s', filename)}}" href="#" name="save" onclick="return doClickSave();" class="icon saveicon" style="background-image: -webkit-linear-gradient(top,white,#E6E6E6);">{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}</a> <a value="save" title="{{=T('Save file: %s', filename)}}" href="#" name="save" onclick="return doClickSave();" class="icon saveicon" style="background-image: -webkit-linear-gradient(top,white,#E6E6E6);">{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}</a>
<label class="">{{=T('Saved file hash:')}}</label> <label class="">{{=T('Saved file hash:')}}</label>
<input type="input" name="file_hash" value="{{=file_hash}}" class="input-long uneditable-input" readonly="readonly"/> <input type="input" name="file_hash" value="{{=file_hash}}" class="input-long uneditable-input" readonly="readonly"/>
<label>{{=T('Last saved on:')}}</label> <label>{{=T('Last saved on:')}}</label>
<input type="input" name="saved_on" value="{{=saved_on}}" class="input-normal uneditable-input" readonly="readonly"/> <input type="input" name="saved_on" value="{{=saved_on}}" class="input-normal uneditable-input" readonly="readonly"/>
{{if filetype=='python':}} {{if filetype=='python':}}
{{=A(SPAN(T('toggle breakpoint')), {{=A(SPAN(T('toggle breakpoint')),
_value="breakpoint", _name="breakpoint", _value="breakpoint", _name="breakpoint",
_onclick="return doToggleBreakpoint('%s','%s://%s%s',null);" % (filename, _onclick="return doToggleBreakpoint('%s','%s://%s%s',null);" % (filename,
request.env['wsgi_url_scheme'], request.env['http_host'], request.env['wsgi_url_scheme'], request.env['http_host'],
URL(c='debug', f='toggle_breakpoint')), URL(c='debug', f='toggle_breakpoint')),
_class="button special btn btn-inverse")}} _class="button special btn btn-inverse")}}
{{pass}} {{pass}}
{{if view_link:}} {{if view_link:}}
{{=button(view_link, T('try view'))}} {{=button(view_link, T('try view'))}}
{{pass}} {{pass}}
<p class="formfield"> <p class="formfield">
{{if functions:}} {{if functions:}}
<span style="text-align:left;" class="exposed"> <span style="text-align:left;" class="exposed">
{{=B(T('exposes:'))}} {{=XML(', '.join([A(f,_target="_blank", _href=URL(a=app,c=controller,f=f)).xml() for f in functions]))}} {{=B(T('exposes:'))}} {{=XML(', '.join([A(f,_target="_blank", _href=URL(a=app,c=controller,f=f)).xml() for f in functions]))}}
</span> </span>
{{if editviewlinks:}}<br/> {{if editviewlinks:}}<br/>
{{=B(T('edit views:'))}} {{=B(T('edit views:'))}}
{{=XML(', '.join([v.xml() for v in editviewlinks]))}} {{=XML(', '.join([v.xml() for v in editviewlinks]))}}
{{pass}} {{pass}}
{{pass}} {{pass}}
{{if edit_controller:}} {{if edit_controller:}}
{{=B(T('edit controller:'))}} {{=B(T('edit controller:'))}}
{{=A(request.args[2]+'.py', _class="editor_filelink", _target="_blank", _href=edit_controller)}} {{=A(request.args[2]+'.py', _class="editor_filelink", _target="_blank", _href=edit_controller)}}
{{pass}} {{pass}}
</p> </p>
</div> </div>
<textarea style=" height:100%; direction:ltr;" id="textarea_{{=id}}" class="input-block-level" name="data" >{{=data}}</textarea> <textarea style=" height:100%; direction:ltr;" id="textarea_{{=id}}" class="input-block-level" name="data" >{{=data}}</textarea>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("textarea_{{=id}}"),{ var editor = CodeMirror.fromTextArea(document.getElementById("textarea_{{=id}}"),{
{{if filetype=='html':}} {{if filetype=='html':}}
mode : "text/html", mode : "text/html",
profile: 'xhtml', profile: 'xhtml',
{{else:}} {{else:}}
mode: { name: '{{=filetype}}'{{if filetype=='python':}},version: 2,singleLineStringErrors: false, {{pass}} }, mode: { name: '{{=filetype}}'{{if filetype=='python':}},version: 2,singleLineStringErrors: false, {{pass}} },
{{pass}} {{pass}}
lineNumbers: true, lineNumbers: true,
indentUnit: 4, indentUnit: 4,
styleActiveLine: true, styleActiveLine: true,
autoCloseTags: true, autoCloseTags: true,
theme: current_theme, theme: current_theme,
tabMode: "shift", tabMode: "shift",
lineWrapping: true, lineWrapping: true,
gutters: ["CodeMirror-linenumbers", "breakpoints"], gutters: ["CodeMirror-linenumbers", "breakpoints"],
{{if TEXT_EDITOR_KEYBINDING == 'emacs':}}keyMap: "emacs",{{pass}} {{if TEXT_EDITOR_KEYBINDING == 'emacs':}}keyMap: "emacs",{{pass}}
{{if TEXT_EDITOR_KEYBINDING == 'vi':}}keyMap: "vim",{{pass}} {{if TEXT_EDITOR_KEYBINDING == 'vi':}}keyMap: "vim",{{pass}}
matchBrackets: true, matchBrackets: true,
autofocus: false, autofocus: false,
height: "350px", height: "350px",
showTrailingSpace: true showTrailingSpace: true
}); });
editor.on("gutterClick", function(cm, n) {
var info = cm.lineInfo(n);
cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker());
sel = {start: n, end: n, data: ''};
doToggleBreakpoint({{=XML("'%s','%s://%s%s'" % (filename,
request.env['wsgi_url_scheme'], request.env['http_host'],
URL(c='debug', f='toggle_breakpoint')))}}, sel);
});
function makeMarker() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
marker.className = "breakpoint";
return marker;
}
{{if filetype=='html':}} editor.on("gutterClick", function(cm, n) {
// must be here or break emmet/zencoding for html var info = cm.lineInfo(n);
CodeMirror.defaults.extraKeys["Ctrl-S"] = cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker());
function(instance) { sel = {start: n, end: n, data: ''};
doClickSave();}; doToggleBreakpoint({{=XML("'%s','%s://%s%s'" % (filename,
CodeMirror.defaults.extraKeys["Ctrl-F11"]= request.env['wsgi_url_scheme'], request.env['http_host'],
function(instance) { URL(c='debug', f='toggle_breakpoint')))}}, sel);
setFullScreen(instance, !isFullScreen(instance));}; });
CodeMirror.defaults.extraKeys["Tab"] = "indentMore"; function makeMarker() {
CodeMirror.defaults.extraKeys["Esc"]= var marker = document.createElement("div");
function(instance) { marker.style.color = "#822";
if (isFullScreen(instance)) { marker.innerHTML = "●";
setFullScreen(instance, false);};} marker.className = "breakpoint";
{{pass}} return marker;
{{if filetype=='python':}} }
// must be here or break emmet/zencoding for python
CodeMirror.defaults.extraKeys["Ctrl-S"] = {{if filetype=='html':}}
function(instance) { // must be here or break emmet/zencoding for html
doClickSave();}; CodeMirror.defaults.extraKeys["Ctrl-S"] =
CodeMirror.defaults.extraKeys["Ctrl-Space"] = function(instance) {
"autocomplete"; doClickSave();};
CodeMirror.defaults.extraKeys["Ctrl-F11"]= CodeMirror.defaults.extraKeys["Ctrl-F11"]=
function(instance) { function(instance) {
setFullScreen(instance, !isFullScreen(instance));}; setFullScreen(instance, !isFullScreen(instance));};
CodeMirror.defaults.extraKeys["Tab"] = "indentMore"; CodeMirror.defaults.extraKeys["Tab"] = "indentMore";
CodeMirror.defaults.extraKeys["Esc"]= CodeMirror.defaults.extraKeys["Esc"]=
function(instance) { function(instance) {
if (isFullScreen(instance)) { if (isFullScreen(instance)) {
setFullScreen(instance, false);};} setFullScreen(instance, false);};}
//for autocomplete {{pass}}
CodeMirror.commands.autocomplete = function(cm) { {{if filetype=='python':}}
// must be here or break emmet/zencoding for python
CodeMirror.defaults.extraKeys["Ctrl-S"] =
function(instance) {
doClickSave();};
CodeMirror.defaults.extraKeys["Ctrl-Space"] =
"autocomplete";
CodeMirror.defaults.extraKeys["Ctrl-F11"]=
function(instance) {
setFullScreen(instance, !isFullScreen(instance));};
CodeMirror.defaults.extraKeys["Tab"] = "indentMore";
CodeMirror.defaults.extraKeys["Esc"]=
function(instance) {
if (isFullScreen(instance)) {
setFullScreen(instance, false);};}
//for autocomplete
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.pythonHint); CodeMirror.showHint(cm, CodeMirror.pythonHint);
} }
{{pass}} {{pass}}
store_changes_function = function(instance, changeObj) { store_changes_function = function(instance, changeObj) {
jQuery(instance).data('saved', false); jQuery(instance).data('saved', false);
instance.off("change", store_changes_function); instance.off("change", store_changes_function);
} }
editor.on("change", store_changes_function); editor.on("change", store_changes_function);
// save the editor as textarea data attribute // save the editor as textarea data attribute
jQuery("#{{=id}} textarea").data('editor', editor); jQuery("#{{=id}} textarea").data('editor', editor);
var hlLine = editor.addLineClass(0, "background", "activeline"); var hlLine = editor.addLineClass(0, "background", "activeline");
window.mirror = editor; //backward compatibility window.mirror = editor; //backward compatibility
set_font(editor, current_font_incr); set_font(editor, current_font_incr);
doListBreakpoints({{=XML("'%s','%s://%s%s'" % (filename, doListBreakpoints({{=XML("'%s','%s://%s%s'" % (filename,
request.env['wsgi_url_scheme'], request.env['http_host'], request.env['wsgi_url_scheme'], request.env['http_host'],
URL(c='debug', f='list_breakpoints')))}}, editor); URL(c='debug', f='list_breakpoints')))}}, editor);
</script> </script>
<div class="editor-bar-bottom" style="margin-top:9px;"> <div class="editor-bar-bottom" style="margin-top:9px;">
<a class="editbutton btn" href="{{=URL('edit', args=request.args, vars={'restore':True})}}" id="restore">{{=T('restore')}}</a> <a class="editbutton btn" href="{{=URL('edit', args=request.args, vars={'restore':True})}}" id="restore">{{=T('restore')}}</a>
{{=T('currently saved or')}} {{=T('currently saved or')}}
<a class="editbutton btn" href="{{=URL('edit', args=request.args, vars={'revert':True})}}" id="revert">{{=T('revert')}}</a> <a class="editbutton btn" href="{{=URL('edit', args=request.args, vars={'revert':True})}}" id="revert">{{=T('revert')}}</a>
{{=T('to previous version.')}} {{=T('to previous version.')}}
</div> </div>
<br/> <br/>
</form> </form>
<div class="row-fluid"> <div class="row-fluid">
<div class="help alert alert-block alert-info"> <div class="help alert alert-block alert-info">
{{if TEXT_EDITOR == 'codemirror' and filetype=='html':}} {{if TEXT_EDITOR == 'codemirror' and filetype=='html':}}
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3> <h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
<ul class="keybindings unstyled"> <ul class="keybindings unstyled">
{{=shortcut('Ctrl+S', T('Save via Ajax'))}} {{=shortcut('Ctrl+S', T('Save via Ajax'))}}
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}} {{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}} {{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}} {{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}} {{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}} {{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}} {{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
{{=shortcut('Tab', T('Expand Abbreviation'))}} {{=shortcut('Tab', T('Expand Abbreviation'))}}
</ul> </ul>
{{elif TEXT_EDITOR == 'codemirror':}} {{elif TEXT_EDITOR == 'codemirror':}}
<h3>{{=T("Key bindings")}}</h3> <h3>{{=T("Key bindings")}}</h3>
<ul class="keybindings unstyled"> <ul class="keybindings unstyled">
{{=shortcut('Ctrl+S', T('Save via Ajax'))}} {{=shortcut('Ctrl+S', T('Save via Ajax'))}}
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}} {{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
{{if filetype=='python':}} {{if filetype=='python':}}
{{=shortcut('Ctrl-Space', T('Autocomplete Python Code'))}} {{=shortcut('Ctrl-Space', T('Autocomplete Python Code'))}}
{{pass}} {{pass}}
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}} {{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}} {{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}} {{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}} {{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}} {{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
</ul> </ul>
{{pass}} {{pass}}
</div> </div>
</div> </div>
@@ -7,7 +7,7 @@ function delkey(id) {
return false; return false;
} }
function hideShowTranslated(){ function hideShowTranslated(){
jQuery(".translated").closest("div.row-fluid").toggle(); jQuery(".translated").closest("div.row-fluid").toggle();
} }
</script> </script>
+112 -112
View File
@@ -3,122 +3,122 @@
{{block sectionclass}}errors{{end}} {{block sectionclass}}errors{{end}}
<!-- begin "errors" block --> <!-- begin "errors" block -->
{{if db_ready['status'] == False: {{if db_ready['status'] == False:
switchbutton = A(SPAN("switch to : db"), _href=db_ready['errlink'], _class="button unavailable btn btn-danger", _title="%s" % (db_ready['errmessage'])) switchbutton = A(SPAN("switch to : db"), _href=db_ready['errlink'], _class="button unavailable btn btn-danger", _title="%s" % (db_ready['errmessage']))
else: else:
switchbutton = A(SPAN("switch to : db"), _href=URL(args=[app, 'dbnew']), _class="button btn") switchbutton = A(SPAN("switch to : db"), _href=URL(args=[app, 'dbnew']), _class="button btn")
pass}} pass}}
<h2>{{=T('Error logs for "%(app)s"',dict(app=app))}}</h2> <h2>{{=T('Error logs for "%(app)s"',dict(app=app))}}</h2>
<div class="errorform"> <div class="errorform">
<form name="myform" method="post"> <form name="myform" method="post">
{{ if 'new' in method: }} {{ if 'new' in method: }}
{{base_url = 'db' in method and 'ticketdb' or 'ticket' }} {{base_url = 'db' in method and 'ticketdb' or 'ticket' }}
<p class="controls row-fluid"> <p class="controls row-fluid">
<div class="controls controls-row"> <div class="controls controls-row">
{{if 'db' in method:}} {{if 'db' in method:}}
<span class="uneditable-input">source : db</span> <span class="uneditable-input">source : db</span>
<a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>switch to : filesystem</span></a> <a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>switch to : filesystem</span></a>
<a class="button btn" href="{{=URL(args=[app, 'dbold'])}}"><span>lists by ticket</span></a> <a class="button btn" href="{{=URL(args=[app, 'dbold'])}}"><span>lists by ticket</span></a>
{{else:}} {{else:}}
<span class="uneditable-input">source : filesystem</span> <span class="uneditable-input">source : filesystem</span>
{{=switchbutton}} {{=switchbutton}}
<a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>lists by ticket</span></a> <a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>lists by ticket</span></a>
{{pass}} {{pass}}
</div> </div>
</p> </p>
<div class="tablebar"> <div class="tablebar">
<input value="{{=T('delete all checked')}}" type="submit" class="btn"/> <input value="{{=T('delete all checked')}}" type="submit" class="btn"/>
<span class="help label label-info">{{=T('Click row to expand traceback')}}</span> <span class="help label label-info">{{=T('Click row to expand traceback')}}</span>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span6"> <div class="span6">
<table id="trck_errors" class="sortable table table-hover table-condensed"> <table id="trck_errors" class="sortable table table-hover table-condensed">
<thead> <thead>
<tr> <tr>
<th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th> <th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th>
<th class="column2">{{=T("Count")}}</th> <th class="column2">{{=T("Count")}}</th>
<th class="column3">{{=T("File")}}</th> <th class="column3">{{=T("File")}}</th>
<th>{{=T("Error")}}</th> <th>{{=T("Error")}}</th>
<th class="columnN"></th> <th class="columnN"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{for e in errors:}} {{for e in errors:}}
<tr class="error_ticket"> <tr class="error_ticket">
<td class="cbcentered"><input type="checkbox" name="delete_{{=e['hash']}}" /></td> <td class="cbcentered"><input type="checkbox" name="delete_{{=e['hash']}}" /></td>
<td>{{=e['count']}}</td> <td>{{=e['count']}}</td>
<td>{{=e['causer']}}</td> <td>{{=e['causer']}}</td>
<td>{{=A(e['last_line'],_href="#",_onclick="collapse('%s');return false;"%e['hash'])}}</td> <td>{{=A(e['last_line'],_href="#",_onclick="collapse('%s');return false;"%e['hash'])}}</td>
<td>+&nbsp;{{=A(T('details'),_href=URL(base_url,args=[app,e['ticket']]))}}</td> <td>+&nbsp;{{=A(T('details'),_href=URL(base_url,args=[app,e['ticket']]))}}</td>
</tr> </tr>
<tr id="{{=e['hash']}}" class="traceback"> <tr id="{{=e['hash']}}" class="traceback">
<td colspan="5"> <td colspan="5">
<div class="ticket_code"> <div class="ticket_code">
{{=CODE(e['pickel']['traceback'])}} {{=CODE(e['pickel']['traceback'])}}
</div> </div>
</td> </td>
</tr> </tr>
{{pass}} {{pass}}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
{{ else: }} {{ else: }}
<p class="controls row-fluid"> <p class="controls row-fluid">
<div class="controls controls-row"> <div class="controls controls-row">
{{if 'db' in method:}} {{if 'db' in method:}}
<span class="uneditable-input">source : db</span> <span class="uneditable-input">source : db</span>
<a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>switch to : filesystem</span></a> <a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>switch to : filesystem</span></a>
<a class="button btn" href="{{=URL(args=[app, 'dbnew'])}}"><span>lists by exception</span></a> <a class="button btn" href="{{=URL(args=[app, 'dbnew'])}}"><span>lists by exception</span></a>
{{else:}} {{else:}}
<span class="uneditable-input">source : filesystem</span> <span class="uneditable-input">source : filesystem</span>
{{=switchbutton}} {{=switchbutton}}
<a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>lists by exception</span></a> <a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>lists by exception</span></a>
{{pass}} {{pass}}
</div> </div>
</p> </p>
<div class="tablebar"> <div class="tablebar">
<input value="{{=T('delete all checked')}}" type="submit" class="btn"/> <input value="{{=T('delete all checked')}}" type="submit" class="btn"/>
<span class="help label label-info">{{=T('Click row to expand traceback')}}</span> <span class="help label label-info">{{=T('Click row to expand traceback')}}</span>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span6"> <div class="span6">
<table id="trck_errors" class="sortable table table-hover table-condensed"> <table id="trck_errors" class="sortable table table-hover table-condensed">
<thead> <thead>
<tr> <tr>
<th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th> <th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th>
<th>{{=T("Ticket")}}</th> <th>{{=T("Ticket")}}</th>
<th class="columnN1">{{=T("Date and Time")}}</th> <th class="columnN1">{{=T("Date and Time")}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{for ticket in tickets:}} {{for ticket in tickets:}}
<tr> <tr>
<td class="cbcentered"><input type="checkbox" name="delete_{{=ticket}}"/></td> <td class="cbcentered"><input type="checkbox" name="delete_{{=ticket}}"/></td>
{{if 'db' in method:}} {{if 'db' in method:}}
<td><a href="{{=URL('ticketdb',args=[app,ticket])}}">{{=ticket}}</a></td> <td><a href="{{=URL('ticketdb',args=[app,ticket])}}">{{=ticket}}</a></td>
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',times[ticket].timetuple())}}</td> <td>{{=time.strftime('%Y-%m-%d %H:%M:%S',times[ticket].timetuple())}}</td>
{{else:}} {{else:}}
<td><a href="{{=URL('ticket',args=[app,ticket])}}">{{=ticket}}</a></td> <td><a href="{{=URL('ticket',args=[app,ticket])}}">{{=ticket}}</a></td>
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.stat(os.path.join(request.folder,'../%s/errors/%s' % (app,ticket)))[stat.ST_CTIME]))}}</td> <td>{{=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.stat(os.path.join(request.folder,'../%s/errors/%s' % (app,ticket)))[stat.ST_CTIME]))}}</td>
{{pass}} {{pass}}
</tr> </tr>
{{pass}} {{pass}}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
{{ pass }} {{ pass }}
</form><!-- /errorform --> </form><!-- /errorform -->
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
jQuery(document).ready(function() { jQuery(document).ready(function() {
jQuery('.traceback').hide(); jQuery('.traceback').hide();
jQuery("#trck_errors thead tr th:first input[type=checkbox]").click(function() { jQuery("#trck_errors thead tr th:first input[type=checkbox]").click(function() {
var checkedStatus = this.checked; var checkedStatus = this.checked;
jQuery("#trck_errors tbody tr td:first-child input[type=checkbox]").each(function() { jQuery("#trck_errors tbody tr td:first-child input[type=checkbox]").each(function() {
this.checked = checkedStatus; this.checked = checkedStatus;
}); });
}); });
}); });
</script> </script>
<!-- end "errors" block --> <!-- end "errors" block -->
@@ -9,18 +9,18 @@
<ul class="collapsible"> <ul class="collapsible">
{{for file in files[path]['files']:}} {{for file in files[path]['files']:}}
<li style="list-style-type: none;"> <li style="list-style-type: none;">
{{p = os.path.relpath(os.path.join(path,file),base)}} {{p = os.path.relpath(os.path.join(path,file),base)}}
<input type="checkbox" value="{{=p}}" name="file" checked="checked"/> <input type="checkbox" value="{{=p}}" name="file" checked="checked"/>
{{=file}} {{=file}}
</li> </li>
{{pass}} {{pass}}
{{for dir in files[path]['folders']:}} {{for dir in files[path]['folders']:}}
<li style="list-style-type: none;"> <li style="list-style-type: none;">
{{tree(os.path.join(path,dir))}} {{tree(os.path.join(path,dir))}}
</li> </li>
{{pass}} {{pass}}
</ul> </ul>
{{return}} {{return}}
<form action="{{=URL(args=request.args)}}" method="POST"> <form action="{{=URL(args=request.args)}}" method="POST">
<h2>{{=T('Select Files to Package')}}</h2> <h2>{{=T('Select Files to Package')}}</h2>
+107 -108
View File
@@ -7,57 +7,57 @@
<div class="applist_inner"> <div class="applist_inner">
<h2>{{=T("Installed applications")}}</h2> <h2>{{=T("Installed applications")}}</h2>
<table width="100%" class="table"> <table width="100%" class="table">
{{for a in apps:}} {{for a in apps:}}
<tr>{{buttons = []}} <tr>{{buttons = []}}
<td> <td>
{{if a==request.application:}} {{if a==request.application:}}
<h4 class="currentapp">{{=a}} ({{=T('currently running')}})</h4> <h4 class="currentapp">{{=a}} ({{=T('currently running')}})</h4>
{{else:}} {{else:}}
<h4 class="editableapp">{{=A(a,_href=URL(a,'default','index'))}}</h4> <h4 class="editableapp">{{=A(a,_href=URL(a,'default','index'))}}</h4>
{{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}} {{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}}
{{if not os.path.exists('applications/%s/compiled' % a):}} {{if not os.path.exists('applications/%s/compiled' % a):}}
{{buttons.append((URL('design',args=a), T("Edit")))}} {{buttons.append((URL('design',args=a), T("Edit")))}}
{{else:}} {{else:}}
{{buttons.append((URL(a,'appadmin','index'), T("appadmin")))}} {{buttons.append((URL(a,'appadmin','index'), T("appadmin")))}}
{{pass}} {{pass}}
{{buttons.append((URL('about',args=a), T("About")))}} {{buttons.append((URL('about',args=a), T("About")))}}
{{pass}} {{pass}}
{{buttons.append((URL('errors',args=a), T("Errors")))}} {{buttons.append((URL('errors',args=a), T("Errors")))}}
{{buttons.append((URL('cleanup',args=a), T("Clean")))}} {{buttons.append((URL('cleanup',args=a), T("Clean")))}}
{{buttons.append((URL('pack',args=a), T("Pack all")))}} {{buttons.append((URL('pack',args=a), T("Pack all")))}}
{{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}} {{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}}
{{if not os.path.exists('applications/%s/compiled' % a):}} {{if not os.path.exists('applications/%s/compiled' % a):}}
{{buttons.append((URL('compile_app',args=a), T("Compile")))}} {{buttons.append((URL('compile_app',args=a), T("Compile")))}}
{{else:}} {{else:}}
{{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}} {{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}}
{{if glob.glob('applications/%s/controllers/*.py' % a):}} {{if glob.glob('applications/%s/controllers/*.py' % a):}}
{{buttons.append((URL('remove_compiled_app',args=a), T("Remove compiled")))}} {{buttons.append((URL('remove_compiled_app',args=a), T("Remove compiled")))}}
{{pass}} {{pass}}
{{pass}} {{pass}}
{{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }} {{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }}
{{buttons.append((URL('git_pull',args=a), T("Git Pull")))}} {{buttons.append((URL('git_pull',args=a), T("Git Pull")))}}
{{buttons.append((URL('git_push',args=a), T("Git Push")))}} {{buttons.append((URL('git_push',args=a), T("Git Push")))}}
{{pass}} {{pass}}
{{if a!=request.application:}} {{if a!=request.application:}}
{{buttons.append((URL('uninstall',args=a), T("Uninstall")))}} {{buttons.append((URL('uninstall',args=a), T("Uninstall")))}}
{{pass}} {{pass}}
</td> </td>
<td> <td>
<div class="btn-group"> <div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
{{=T('Manage')}} {{=T('Manage')}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{{for link,name in buttons:}} {{for link,name in buttons:}}
{{=LI(A(name,_href=link))}} {{=LI(A(name,_href=link))}}
{{pass}} {{pass}}
</ul> </ul>
</div> </div>
{{=button_enable(URL('enable',args=a), a)}} {{=button_enable(URL('enable',args=a), a)}}
</td> </td>
</tr> </tr>
{{pass}} {{pass}}
</table> </table>
</div> </div>
</div> <!-- /applist --> </div> <!-- /applist -->
@@ -65,85 +65,85 @@
<div class="sidebar_inner controls well well-small"> <div class="sidebar_inner controls well well-small">
<!-- CHANGE ADMIN PWD --> <!-- CHANGE ADMIN PWD -->
<div class="pwdchange pull-right"> <div class="pwdchange pull-right">
{{if MULTI_USER_MODE:}} {{if MULTI_USER_MODE:}}
{{=auth.navbar()}} {{=auth.navbar()}}
{{else:}} {{else:}}
{{=sp_button(URL('change_password'), T('Change admin password'))}} {{=sp_button(URL('change_password'), T('Change admin password'))}}
{{=button(URL('default','reload_routes'), T('Reload routes'))}} {{=button(URL('default','reload_routes'), T('Reload routes'))}}
{{pass}} {{pass}}
</div> <!-- /CHANGE ADMIN PWD --> </div> <!-- /CHANGE ADMIN PWD -->
{{if is_manager():}} {{if is_manager():}}
<!-- VERSION --> <!-- VERSION -->
<div class="box"> <div class="box">
<h4>{{=T("Version")}}</h4> <h4>{{=T("Version")}}</h4>
<p> <p>
<tt>{{=myversion}}</tt><br/> <tt>{{=myversion}}</tt><br/>
({{=T("Running on %s", request.env.server_software)}}) ({{=T("Running on %s", request.env.server_software)}})
</p> </p>
<p id="check_version" class="row-buttons"> <p id="check_version" class="row-buttons">
{{if session.check_version:}} {{if session.check_version:}}
{{=T('Checking for upgrades...')}} {{=T('Checking for upgrades...')}}
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script> <script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
{{session.check_version=False}} {{session.check_version=False}}
{{else:}} {{else:}}
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}} {{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
{{pass}} {{pass}}
</p> </p>
{{if session.is_mobile=='auto':}} {{if session.is_mobile=='auto':}}
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p> <p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
{{pass}} {{pass}}
</div> <!-- /VERSION --> </div> <!-- /VERSION -->
{{pass}} {{pass}}
{{if MULTI_USER_MODE and is_manager():}} {{if MULTI_USER_MODE and is_manager():}}
<!-- MULTI_USER_INTERFACE --> <!-- MULTI_USER_INTERFACE -->
<div class="box"> <div class="box">
<h4>{{=T("Multi User Mode")}}</h4> <h4>{{=T("Multi User Mode")}}</h4>
<p class="row-buttons"> <p class="row-buttons">
{{=button(URL('bulk_register'),T('Bulk Register'))}} {{=button(URL('bulk_register'),T('Bulk Register'))}}
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}} {{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
</p> </p>
</div> <!-- /MULTI_USER_INTERFACE --> </div> <!-- /MULTI_USER_INTERFACE -->
{{pass}} {{pass}}
<!-- SCAFFOLD APP --> <!-- SCAFFOLD APP -->
<div class="box"> <div class="box">
<h4>{{=T("New simple application")}}</h4> <h4>{{=T("New simple application")}}</h4>
{{=form_create.custom.begin}} {{=form_create.custom.begin}}
{{=LABEL(T("Application name:"))}} {{=LABEL(T("Application name:"))}}
{{=form_create.custom.widget.name}} {{=form_create.custom.widget.name}}
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div> <div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
{{=form_create.custom.end}} {{=form_create.custom.end}}
</div> <!-- /SCAFFOLD APP --> </div> <!-- /SCAFFOLD APP -->
<!-- UPLOAD PACKAGE --> <!-- UPLOAD PACKAGE -->
<div class="box"> <div class="box">
<h4>{{=T("Upload and install packed application")}}</h4> <h4>{{=T("Upload and install packed application")}}</h4>
{{=form_update.custom.begin}} {{=form_update.custom.begin}}
<label for="appupdate_name">{{=T("Application name:")}}</label> <label for="appupdate_name">{{=T("Application name:")}}</label>
{{=form_update.custom.widget.name}} {{=form_update.custom.widget.name}}
<label for="appupdate_file">{{=T("Upload a package:")}}</label> <label for="appupdate_file">{{=T("Upload a package:")}}</label>
{{=form_update.custom.widget.file}} {{=form_update.custom.widget.file}}
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label> <label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small> {{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
<div class="controls"> <div class="controls">
<label class="checkbox"> <label class="checkbox">
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}} {{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
</label> </label>
<button type="submit" class='btn'>{{=T('Install')}}</button> <button type="submit" class='btn'>{{=T('Install')}}</button>
</div> </div>
{{=form_update.custom.end}} {{=form_update.custom.end}}
</div> <!-- /UPLOAD PACKAGE --> </div> <!-- /UPLOAD PACKAGE -->
<!-- DEPLOY ON GAE --> <!-- DEPLOY ON GAE -->
<div class="box"> <div class="box">
<h4>{{=T("Deploy")}}</h4> <h4>{{=T("Deploy")}}</h4>
<p class="row-buttons"> <p class="row-buttons">
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}} {{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}} {{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
</p> </p>
</div> <!-- /DEPLOY ON GAE --> </div> <!-- /DEPLOY ON GAE -->
<!-- APP WIZARD --> <!-- APP WIZARD -->
<div class="box"> <div class="box">
<h4>{{=T("New application wizard")}}</h4> <h4>{{=T("New application wizard")}}</h4>
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}<br/> <p>{{=button(URL('wizard','index'), T('Start wizard'))}}<br/>
{{=T("(requires internet access, experimental)")}}</p> {{=T("(requires internet access, experimental)")}}</p>
</div> <!-- /APP WIZARD --> </div> <!-- /APP WIZARD -->
<a class="twitter-timeline" href="https://twitter.com/web2py" data-widget-id="340456915207327745">Tweets by @web2py</a> <a class="twitter-timeline" href="https://twitter.com/web2py" data-widget-id="340456915207327745">Tweets by @web2py</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
@@ -151,4 +151,3 @@
</div> <!-- /sidebar --> </div> <!-- /sidebar -->
</div> <!-- /row-fluid </div> <!-- /row-fluid
<!-- end "site" block --> <!-- end "site" block -->
+39 -39
View File
@@ -16,7 +16,7 @@
<tr> <tr>
<th>Python</th> <th>Python</th>
<td>{{=snapshot.get('pyver','')}}</td> <td>{{=snapshot.get('pyver','')}}</td>
</tr> </tr>
{{pass}} {{pass}}
</tbody> </tbody>
</table> </table>
@@ -45,14 +45,14 @@
<div class="inspect"> <div class="inspect">
<h4>{{=T("Exception instance attributes")}}</h4> <h4>{{=T("Exception instance attributes")}}</h4>
<table> <table>
<tbody> <tbody>
{{for k,v in snapshot['exception'].items():}} {{for k,v in snapshot['exception'].items():}}
<tr> <tr>
<th>{{=k}}</th> <th>{{=k}}</th>
<td>{{=v}}</td> <td>{{=v}}</td>
</tr> </tr>
{{pass}} {{pass}}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
@@ -65,36 +65,36 @@
<li> <li>
{{is_hidden = (i != len(snapshot['frames'])-1 and 'hide' or 'inspect')}} {{is_hidden = (i != len(snapshot['frames'])-1 and 'hide' or 'inspect')}}
<div class="framefile inspect controls"> <div class="framefile inspect controls">
<p> <p>
<strong>File {{="%s in %s at line %s" % (frame['file'], frame['func'], frame['lnum'])}}</strong> <strong>File {{="%s in %s at line %s" % (frame['file'], frame['func'], frame['lnum'])}}</strong>
<a class="button tbbutton btn" onclick="collapse('{{='%s_code_inner' % i}}');"><span>{{=T("code")}}</span></a> <a class="button tbbutton btn" onclick="collapse('{{='%s_code_inner' % i}}');"><span>{{=T("code")}}</span></a>
<a class="button tbbutton btn" onclick="collapse('{{='%s_args_inner' % i}}');"><span>{{=T("arguments")}}</span></a> <a class="button tbbutton btn" onclick="collapse('{{='%s_args_inner' % i}}');"><span>{{=T("arguments")}}</span></a>
<a class="button tbbutton btn" onclick="collapse('{{='%s_vars_inner' % i}}');"><span>{{=T("variables")}}</span></a> <a class="button tbbutton btn" onclick="collapse('{{='%s_vars_inner' % i}}');"><span>{{=T("variables")}}</span></a>
</p> </p>
<div id="{{='%s_args_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto"> <div id="{{='%s_args_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
<h5>Function argument list</h5> <h5>Function argument list</h5>
<p>{{=frame['call']}}</p> <p>{{=frame['call']}}</p>
</div> </div>
<div id="{{='%s_code_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto"> <div id="{{='%s_code_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
<h5>Code listing</h5> <h5>Code listing</h5>
{{if frame['lines']:}} {{if frame['lines']:}}
<pre>{{=CODE('\n'.join([x[1] for x in sorted(frame['lines'].items(),key=lambda x: x[0])]), <pre>{{=CODE('\n'.join([x[1] for x in sorted(frame['lines'].items(),key=lambda x: x[0])]),
language='python', link=None, counter=min(frame['lines'].keys()), highlight_line=frame['lnum'])}}</pre> language='python', link=None, counter=min(frame['lines'].keys()), highlight_line=frame['lnum'])}}</pre>
{{pass}} {{pass}}
</div> </div>
<div id="{{='%s_vars_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto"> <div id="{{='%s_vars_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
<h5>Variables</h5> <h5>Variables</h5>
<table> <table>
<tbody> <tbody>
{{for k,v in frame['dump'].items():}} {{for k,v in frame['dump'].items():}}
<tr> <tr>
<th>{{=k}}</th> <th>{{=k}}</th>
<td>{{=v}}</td> <td>{{=v}}</td>
</tr> </tr>
{{pass}} {{pass}}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</li> </li>
{{pass}} {{pass}}