/* * Editdialog app code */ EDIT_STATE = null; EDIT_BACKUP = null; $(document).ready(function() { var dirSep = '/'; EDIT_BACKUP = { validate_tab: function(tab) { var tabs = $('#edit-dialog').parent().find('[role=tablist] > li'); tab += ''; if (tab.length > 0 && tab[0] == '#') tab = tab.substr(1); if (parseInt(tab) + '' == tab) { tab = tabs[parseInt(tab)] } else { var tt = tab; tab = null; for(var n in tabs) { var href = $(n).find('a').attr('href'); if (href && href[0] == '#') { href = href.substr(1); } if (tabs[n] == tt || href == tab) { tab = tabs[n]; break; } } } if (tab) { var href = $(tab).find('a').attr('href'); if (href && href[0] == '#') href = href.substr(1); var index; for(index in tabs) if (tab == tabs[index]) break; if (EDIT_BACKUP.validate_form_map[href]) { if (!EDIT_BACKUP.validate_form_map[href](index)) { return false; } } return true; } else { return false; } }, validate_form_map: { 'edit-tab-general': function(tabindex) { if ($('#backup-name').val().trim() == '') { $('#edit-dialog').tabs( "option", "active", tabindex); $('#backup-name').focus(); alert('You must enter a name for the backup'); return false; } if ($('#encryption-method').val() != '') { if ($('#encryption-password').val().trim() == '') { $('#edit-dialog').tabs( "option", "active", tabindex); $('#encryption-password').focus(); alert('You must enter a passphrase'); return false; } if (!EDIT_STATE.passwordShown && $('#repeat-password').hasClass('password-mismatch')) { $('#edit-dialog').tabs( "option", "active", tabindex); $('#repeat-password').focus(); alert('The passwords do not match'); return false; } } return true; }, 'edit-tab-sourcedata': function(tabindex) { if ($('#source-folder-paths').find('.source-folder').length == 0) { $('#edit-dialog').tabs( "option", "active", tabindex); $('#source-folder-paths').focus(); alert('You must select at least one source folder to back up'); return false; } return true; }, 'edit-tab-target': function(tabindex) { if ($('#backup-uri').val().trim() == '') { $('#edit-dialog').tabs( "option", "active", tabindex); $('#backup-uri').focus(); alert('You must enter a connection url for the backup'); return false; } return true; }, 'edit-tab-schedule': function(tabindex) { if ($('#use-scheduled-run').is(':checked')) { var t = Date.parse($('#next-run-date').val() + 'T' + $('#next-run-time').val()); if (isNaN(t)) { $('#edit-dialog').tabs( "option", "active", tabindex); $('#next-run-time').focus(); alert('You must enter a valid time'); return false; } } return true; } }, fill_form_map: { 'encryption-module': 'encryption-method', 'Name': 'backup-name', 'TargetURL': 'backup-uri', 'passphrase': function(dict, key, val, cfgel) { $('#encryption-password').val(val); $('#repeat-password').val(val); }, 'Sources': function(dict, key, val, cfgel) { var sources = val || []; var lookup = {}; if (EDIT_STATE.orig_config && EDIT_STATE.orig_config.DisplayNames) lookup = EDIT_STATE.orig_config.DisplayNames; $('#source-folder-paths').find('.source-folder').remove(); for(var n in sources) { var p = sources[n]; var rp = p; addSourceFolder(rp, lookup[p] || p); } }, 'Tags': function(dict, key, val, cfgel) { var tags = val || []; //$('#backup-labels').val(tags.join(', ')); }, 'Schedule': function(dict, key, val, cfgel) { $('#use-scheduled-run').attr('checked', val != null) $('#use-scheduled-run').trigger('change'); }, 'Repeat': function(dict, key, val, cfgel) { $('#use-scheduled-run').attr('checked', val != ''); $('#use-scheduled-run').change(); if (!$('#use-scheduled-run').is(':checked')) return; var m = (/(\d*)(\w)/mg).exec(val); var mul = null; if (m) { switch(m[2]) { case 'D': mul = 'days'; break; case 'h': mul = 'hours'; break; case 'M': mul = 'months'; break; case 'Y': mul = 'years'; break; case 'W': mul = 'weeks'; break; } } if (!mul) { // Strange stuff, just use it as-is $('#repeat-run-number').val(val + ''); $('#repeat-run-multiplier').val('custom'); } else { $('#repeat-run-number').val(m[1]); $('#repeat-run-multiplier').val(m[2]); } }, 'Time': function(dict, key, val, cfgel) { var parts = val.split(':'); var now = new Date(); var msec = Date.parse(val); if (isNaN(msec)) msec = Date.parse("1970-01-01T" + val); var d = null; if (isNaN(msec)) { d = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 13, 0, 0); $('#next-run-time').val('13:00'); $('#next-run-date').val(now); } else { d = new Date(msec); if (d.getFullYear() <= 1970) { msec += new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0).getTime(); d = new Date(msec); } } var y = d.getFullYear() + ''; var m = (d.getMonth() + 1) + ''; var n = d.getDate() + ''; var h = d.getHours() + ''; var l = d.getMinutes() + ''; var s = d.getSeconds() + ''; if (m.length == 1) m = '0' + m; if (n.length == 1) n = '0' + n; if (h.length == 1) h = '0' + h; if (l.length == 1) l = '0' + l; if (s.length == 1) s = '0' + s; $('#next-run-date').val(y + '-' + m + '-' + n); $('#next-run-time').val(h + ':' + l + ':' + s); }, 'AllowedDays': function(dict, key, val, cfgel) { var d = false; if (val == null || val.length == 0) d = true; var n = { 'mon': d, 'tue': d, 'wed': d, 'thu': d, 'fri': d, 'sat': d, 'sun': d }; for(var i in val) if (n[val[i]] !== undefined) n[val[i]] = true; for(var k in n) { $('#allow-day-' + k).attr('checked', n[k]); } }, 'dblock-size': function(dict, key, val, cfgel) { var m = (/(\d*)(\w*)/mg).exec(val); var mul = null; if (m) { $('#dblock-size-number').val(m[1]); $('#dblock-size-multiplier').val(m[2]); } } }, fill_dict_map: { 'source-folder-path-text': false, 'repeat-password': false, 'dblock-size-multiplier': false, 'repeat-run-multiplier': false, 'next-run-date': false, 'allow-day-mon': false, 'allow-day-tue': false, 'allow-day-wed': false, 'allow-day-thu': false, 'allow-day-fri': false, 'allow-day-sat': false, 'allow-day-sun': function(dict, key, el, cfgel) { if (!$('#use-scheduled-run').is(':checked')) return; if (!dict['Schedule']) dict['Schedule'] = {}; // Collect all days var days = []; var r = ['mon', 'tue', 'wed', 'thu','fri', 'sat', 'sun']; for(var k in r) if ($('#allow-day-' + r[k]).is(':checked')) days.push(r[k]); dict['Schedule']['AllowedDays']= days; }, 'encryption-password': function(dict, key, el, cfgel) { dict['Backup']['Settings']['passphrase'] = $(el).val(); }, 'source-folder-list': function(dict, key, el, cfgel) { var sources = []; $('#source-folder-paths').find('.source-folder').each(function(i,el) { var p = $(el).data('id'); sources.push(p); }); dict['Backup']['Sources'] = sources; }, 'use-scheduled-run': function(dict, key, el, cfgel) { if (!$(el).is(':checked')) { dict['Schedule'] = null; } else if(!dict['Schedule']) { dict['Schedule'] = {}; } }, 'backup-uri': function(dict, key, el, cfgel) { dict['Backup']['TargetURL'] = $(el).val(); }, 'backup-name': function(dict, key, el, cfgel) { dict['Backup']['Name'] = $(el).val(); }, 'backup-labels': function(dict, key, el, cfgel) { // dict['Backup']['Tags'] = $(el).val().split(','); }, 'encryption-method': function(dict, key, el, cfgel) { dict['Backup']['Settings']['encryption-module'] = $(el).val(); if ($(el).val().trim() == '') dict['Backup']['Settings']['--no-encryption'] = true; else delete dict['Backup']['Settings']['--no-encryption']; }, 'next-run-time': function(dict, key, el, cfgel) { if (!$('#use-scheduled-run').is(':checked')) return; if (!dict['Schedule']) dict['Schedule'] = {}; var t = Date.parse($('#next-run-date').val()); if (t != NaN) { var tp = $('#next-run-time').val().split(':'); while(tp.length < 3) tp.push('00'); var d = new Date(t); d = new Date(d.getFullYear(), d.getMonth(), d.getDate(), parseInt(tp[0]), parseInt(tp[1]), parseInt(tp[2])) dict['Schedule']['Time'] = d.toISOString(); } }, 'dblock-size-number': function(dict, key, el, cfgel) { dict['Backup']['Settings']['dblock-size'] = $(el).val() + $('#dblock-size-multiplier').val(); }, 'repeat-run-number': function(dict, key, el, cfgel) { if (!$('#use-scheduled-run').is(':checked')) return; if (!dict['Schedule']) dict['Schedule'] = {}; var m = $('#repeat-run-multiplier').val(); if (m == 'custom') dict['Schedule']['Repeat'] = $(el).val(); else dict['Schedule']['Repeat'] = $(el).val() + m; } } }; $('#backup-name').watermark('Photos 2014'); // $('#backup-labels').watermark('work, docs, s3, movies, other'); $('#backup-uri').watermark('webdavs://user:pass@example.com:995/backup?option=true'); $('#encryption-password').watermark('Long and secret passphrase'); $('#repeat-password').watermark('Long and secret passphrase'); $('#backup-options').watermark('Enter one option pr. line in commandline format, eg. --dblock-size=100MB'); $('#source-folder-path-text').watermark('Enter a path to back up'); $('#source-filters').watermark('One filter per line, e.g. "+*.txt" or "-[.*\\.txt]"'); var updateState = function() { if (EDIT_STATE != null) EDIT_STATE.dataModified = true; }; $('#backup-name').change(updateState); // $('#backup-labels').change(updateState); $('#backup-uri').change(updateState); $('#encryption-password').change(updateState); $('#repeat-password').change(updateState); $('#backup-options').change(updateState); $('#source-filters').change(updateState); function split(val) { return val.split(/,\s*/); } function extractLast(val) { return split(val).pop(); } // $('#backup-labels').autocomplete({ // minLength: 0, // source: function(request, response) { // if (EDIT_STATE != null && EDIT_STATE.tags != null) // response( $.ui.autocomplete.filter(EDIT_STATE.tags, extractLast(request.term))); // }, // focus: function() { // return false; // }, // select: function( event, ui ) { // var terms = split( this.value ); // terms.pop(); //remove current // terms.push(ui.item.value); // terms.push(''); //prepare for new // this.value = terms.join(', '); // return false; // } // }); var updatePasswordIndicator = function() { var strengthMap = { 0: "Useless", 1: "Very weak", 2: "Weak", 3: "Strong", 4: "Very strong" }; $.passwordStrength($('#encryption-password')[0].value, function(r) { var f = $('#backup-password-strength'); if (r == null) { f.text('Strength: Unknown'); r = {score: -1} } else { console.log(r) f.text('Strength: ' + strengthMap[r.score]); } f.removeClass('password-strength-0'); f.removeClass('password-strength-1'); f.removeClass('password-strength-2'); f.removeClass('password-strength-3'); f.removeClass('password-strength-4'); f.removeClass('password-strength-unknown'); if (r.score == 0) f.addClass('password-strength-0'); else if (r.score == 1) f.addClass('password-strength-1'); else if (r.score == 2) f.addClass('password-strength-2'); else if (r.score == 3) f.addClass('password-strength-3'); else if (r.score == 4) f.addClass('password-strength-4'); else f.addClass('password-strength-unknown'); }); if ($('#encryption-password').val() != $('#repeat-password').val()) { $('#repeat-password').addClass('password-mismatch'); //$('#encryption-password').addClass('password-mismatch'); } else { $('#repeat-password').removeClass('password-mismatch'); //$('#encryption-password').removeClass('password-mismatch'); } } $('#encryption-password').change(updatePasswordIndicator); $('#repeat-password').change(updatePasswordIndicator); $('#encryption-password').keyup(updatePasswordIndicator); $('#repeat-password').keyup(updatePasswordIndicator); $('#toggle-show-password').click(function() { $('#encryption-password').togglePassword(); }); $('#encryption-password').on('passwordShown', function () { $('#toggle-show-password').text('Hide') $('#repeat-password').showPassword(); EDIT_STATE.passwordShown = true; //$('#repeat-password').hide(); //$('#repeat-password-label').hide(); }).on('passwordHidden', function () { $('#toggle-show-password').text('Show') $('#repeat-password').hidePassword(); EDIT_STATE.passwordShown = false; //$('#repeat-password').show(); //$('#repeat-password-label').show(); }); $('#generate-password').click(function() { var specials = '!@#$%^&*()_+{}:"<>?[];\',./'; var lowercase = 'abcdefghijklmnopqrstuvwxyz'; var uppercase = lowercase.toUpperCase(); var numbers = '0123456789'; var all = specials + lowercase + uppercase + numbers; function choose(str, n) { var res = ''; for (var i = 0; i < n; i++) { res += str.charAt(Math.floor(Math.random() * str.length)); } return res; }; var pwd = ( choose(specials, 2) + choose(lowercase, 2) + choose(uppercase, 2) + choose(numbers, 2) + choose(all, (Math.random()*5) + 5) ).split(''); for(var i = 0; i < pwd.length; i++) { var pos = parseInt(Math.random() * pwd.length); var t = pwd[i] pwd[i] = pwd[pos]; pwd[pos] = t; } pwd = pwd.join(''); $('#encryption-password')[0].value = pwd; $('#repeat-password')[0].value = pwd; $('#encryption-password').showPassword(); updatePasswordIndicator(); }); $('#backup-uri-label').click(function() { $('#connection-uri-dialog').dialog('open'); }); var dlg_buttons = $('#edit-dialog').parent().find('.ui-dialog-buttonpane').find('.ui-button'); $('#edit-dialog').on( "tabsactivate", function( event, ui ) { var tabs = $('#edit-dialog').parent().find('[role=tablist] > li'); if (ui.newPanel.attr('id') == tabs.first().attr('aria-controls')) dlg_buttons.first().button('option', 'disabled', true); else if (ui.oldPanel.attr('id') == tabs.first().attr('aria-controls')) dlg_buttons.first().button('option', 'disabled', false); if (ui.newPanel.attr('id') == tabs.last().attr('aria-controls')) dlg_buttons.last().button('option', 'label', 'Save'); else if (ui.oldPanel.attr('id') == tabs.last().attr('aria-controls')) dlg_buttons.last().button('option', 'label', 'Next >'); }); $('#edit-dialog').on( "dialogopen", function( event, ui ) { $('#edit-dialog-form').each(function(i, e) { e.reset(); }); $('#source-folder-paths').find('.source-folder').remove(); removeSourceFolder(); EDIT_STATE = { passwordShown: false, dataModified: false, passwordModified: false, newBackup: true }; APP_DATA.getServerConfig(function(serverdata) { dirSep = serverdata.DirectorySeparator; if (serverdata['EncryptionModules'] == null || serverdata['EncryptionModules'].length == 0) { $('#encryption-area').hide(); } else { $('#encryption-area').show(); var drop = $('#encryption-method'); drop.empty(); drop.append($("").attr("value", '').text('No encryption')); var encmodules = serverdata['EncryptionModules']; for (var i = 0; i < encmodules.length; i++) drop.append($("").attr("value", encmodules[i].Key).text(encmodules[i].DisplayName)); } $('#encryption-method').change(); }); APP_DATA.getLabels(function(labels) { EDIT_STATE.tags = labels; }); $('#edit-dialog').tabs('option', 'active', 0); }); $('#encryption-method').change(function() { if ($('#encryption-method').val() == '') $('#encryption-password-area').hide(); else $('#encryption-password-area').show(); }); $('#edit-dialog').on( "dialogbeforeclose", function( event, ui ) { //TODO: Actually set this flag if (EDIT_STATE.dataModified) { if (!confirm('Close without saving?')) return false; } }); var readFormData = function(validateOptions) { var obj = { 'Schedule': {}, 'Backup': { 'Settings': {}, 'Filters': [], 'Sources': [], 'Tags': [] } }; // To protect against data loss, we use the orig config and update it if (EDIT_STATE.orig_config != null) $.extend(true, obj, EDIT_STATE.orig_config); for(var k in obj.Backup.Settings) if (k.substr(0, 2) == '--') delete obj.Backup.Settings[k]; APP_UTIL.read_form($('#edit-dialog-form'), EDIT_BACKUP.fill_dict_map, obj); if (!APP_UTIL.parseOptionStrings($('#backup-options').val(), obj.Backup.Settings, function() { //TODO: Add validation return true; })) { return null; } var filters = $('#source-filters').val(); var filterlist = []; if (filters != '') { var lines = filters.split('\n'); for(var i in lines) { var ld = lines[i].trim(); if (ld == '') continue; if (ld[0] != '-' && ld[0] != '+') { EDIT_URI.validation_error($('#source-filters'), 'Each filter line must start with either a "+" or a "-" character'); return null; } filterlist.push({'Expression': ld.substr(1), 'Include': ld[0] == '+', 'Order': i}); } } obj.Backup.Filters = filterlist; return obj }; dlg_buttons.last().click(function(event, ui) { var tabs = $('#edit-dialog').parent().find('[role=tablist] > li'); if (event.curPage == tabs.size() - 1) { // Saving, validate first for(var n in tabs) { if (!EDIT_BACKUP.validate_tab(n)) { return; } } var obj = readFormData(true); if (obj == null) return; //Fixup, change settings dict into array var set = obj.Backup.Settings; obj.Backup.Settings = []; for(var k in set) obj.Backup.Settings.push({Name: k, Value: set[k]}); if (EDIT_STATE.newBackup) { APP_DATA.locateUriDb(obj.Backup.TargetURL, function(res) { var existing_db = (res.Exists && confirm("An existing local database for the storage has been found.\nRe-using the database will allow the commandline and server instances to work on the same remote storage.\n\n Do you wish to use the existing database?")) ? true : false; APP_DATA.addBackup(obj, function() { EDIT_STATE.dataModified = false; $('#edit-dialog').dialog('close'); }, function(data, succes, status) { alert('Could not save: ' + status); }, { existing_db: existing_db }); }, function(data, succes, status) { alert('Could not save: ' + status); }); } else { APP_DATA.updateBackup(obj, function() { EDIT_STATE.dataModified = false; $('#edit-dialog').dialog('close'); }, function(data, succes, status) { alert('Could not save: ' + status); }); } } }); var removeSourceFolder = function(el) { var container = $('#source-folder-paths'); if (el) container.each(function(i, e) { e.removeChild(el) }); if (container.find('.source-folder').length == 0) { container.addClass('empty'); $('#source-folder-paths-hint').show(); } }; var addSourceFolder = function(path, display) { var container = $('#source-folder-paths'); container.removeClass('empty'); $('#source-folder-paths-hint').hide(); if (path == null || path.trim() == '') return false; var exists = false; container.find('.source-folder').each(function(i,el) { exists |= $(el).data('id') == path; }); if (exists) return false; var div = $('