Modernizr.load({ test: Modernizr.input.placeholder, nope: [ OC.filePath('contacts', 'css', 'placeholder_polyfill.min.css'), OC.filePath('contacts', 'js', 'placeholder_polyfill.jquery.min.combo.js') ] }); (function($) { $.QueryString = (function(a) { if (a == "") return {}; var b = {}; for (var i = 0; i < a.length; ++i) { var p=a[i].split('='); if (p.length != 2) continue; b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); } return b; })(window.location.search.substr(1).split('&')) })(jQuery); var utils = {}; /** * utils.isArray * * Best guess if object is an array. */ utils.isArray = function(obj) { // do an instanceof check first if (obj instanceof Array) { return true; } // then check for obvious falses if (typeof obj !== 'object') { return false; } if (utils.type(obj) === 'array') { return true; } return false; }; utils.isInt = function(s) { return typeof s === 'number' && (s.toString().search(/^-?[0-9]+$/) === 0); }; utils.isUInt = function(s) { return typeof s === 'number' && (s.toString().search(/^[0-9]+$/) === 0); }; /** * utils.type * * Attempt to ascertain actual object type. */ utils.type = function(obj) { if (obj === null || typeof obj === 'undefined') { return String (obj); } return Object.prototype.toString.call(obj) .replace(/\[object ([a-zA-Z]+)\]/, '$1').toLowerCase(); }; utils.moveCursorToEnd = function(el) { if (typeof el.selectionStart === 'number') { el.selectionStart = el.selectionEnd = el.value.length; } else if (typeof el.createTextRange !== 'undefined') { el.focus(); var range = el.createTextRange(); range.collapse(false); range.select(); } }; if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } Array.prototype.clone = function() { return this.slice(0); }; Array.prototype.clean = function(deleteValue) { var arr = this.clone(); for (var i = 0; i < arr.length; i++) { if (arr[i] == deleteValue) { arr.splice(i, 1); i--; } } return arr; }; // Keep it DRY ;) var wrongKey = function(event) { return ((event.type === 'keydown' || event.type === 'keypress') && (event.keyCode !== 32 && event.keyCode !== 13)); }; /** * Simply notifier * Arguments: * @param message The text message to show. * @param timeout The timeout in seconds before the notification disappears. Default 10. * @param timeouthandler A function to run on timeout. * @param clickhandler A function to run on click. If a timeouthandler is given it will be cancelled on click. * @param data An object that will be passed as argument to the timeouthandler and clickhandler functions. * @param cancel If set cancel all ongoing timer events and hide the notification. */ OC.notify = function(params) { var self = this; if(!self.notifier) { self.notifier = $('#notification'); } if(params.cancel) { self.notifier.off('click'); for(var id in self.notifier.data()) { if($.isNumeric(id)) { clearTimeout(parseInt(id)); } } self.notifier.text('').fadeOut().removeData(); return; } self.notifier.text(params.message); self.notifier.fadeIn().css('display', 'inline'); self.notifier.on('click', function() { $(this).fadeOut();}); var timer = setTimeout(function() { self.notifier.fadeOut(); if(params.timeouthandler && $.isFunction(params.timeouthandler)) { params.timeouthandler(self.notifier.data(dataid)); self.notifier.off('click'); self.notifier.removeData(dataid); } }, params.timeout && $.isNumeric(params.timeout) ? parseInt(params.timeout)*1000 : 10000); var dataid = timer.toString(); if(params.data) { self.notifier.data(dataid, params.data); } if(params.clickhandler && $.isFunction(params.clickhandler)) { self.notifier.on('click', function() { clearTimeout(timer); self.notifier.off('click'); params.clickhandler(self.notifier.data(dataid)); self.notifier.removeData(dataid); }); } }; OC.Contacts = OC.Contacts || { init:function() { if(oc_debug === true) { $(document).ajaxError(function(e, xhr, settings, exception) { // Don't try to get translation because it's likely a network error. OC.notify({ message: 'error in: ' + settings.url + ', '+'error: ' + xhr.responseText }); }); } this.scrollTimeoutMiliSecs = 100; this.isScrolling = false; this.cacheElements(); this.contacts = new OC.Contacts.ContactList( this.$contactList, this.$contactListItemTemplate, this.$contactDragItemTemplate, this.$contactFullTemplate, this.detailTemplates ); this.groups = new OC.Contacts.GroupList(this.$groupList, this.$groupListItemTemplate); OCCategories.changed = this.groups.categoriesChanged; OCCategories.app = 'contacts'; OCCategories.type = 'contact'; this.bindEvents(); this.$toggleAll.show(); this.showActions(['add']); }, loading:function(obj, state) { $(obj).toggleClass('loading', state); }, /** * Show/hide elements in the header * @param act An array of actions to show based on class name e.g ['add', 'delete'] */ hideActions:function() { this.showActions(false); }, showActions:function(act) { console.log('showActions', act); //console.trace(); this.$headeractions.children().hide(); if(act && act.length > 0) { this.$headeractions.children('.'+act.join(',.')).show(); } }, showAction:function(act, show) { this.$headeractions.find('.' + act).toggle(show); }, cacheElements: function() { var self = this; this.detailTemplates = {}; // Load templates for contact details. // The weird double loading is because jquery apparently doesn't // create a searchable object from a script element. $.each($($('#contactDetailsTemplate').html()), function(idx, node) { var $node = $(node); if($node.is('div')) { var $tmpl = $(node.innerHTML); self.detailTemplates[$tmpl.data('element')] = $node; } }); this.$groupListItemTemplate = $('#groupListItemTemplate'); this.$contactListItemTemplate = $('#contactListItemTemplate'); this.$contactDragItemTemplate = $('#contactDragItemTemplate'); this.$contactFullTemplate = $('#contactFullTemplate'); this.$contactDetailsTemplate = $('#contactDetailsTemplate'); this.$rightContent = $('#rightcontent'); this.$header = $('#contactsheader'); this.$headeractions = this.$header.find('div.actions'); this.$groupList = $('#grouplist'); this.$contactList = $('#contactlist'); this.$contactListHeader = $('#contactlistheader'); this.$toggleAll = $('#toggle_all'); this.$groups = this.$headeractions.find('.groups'); this.$ninjahelp = $('#ninjahelp'); this.$firstRun = $('#firstrun'); this.$settings = $('#contacts-settings'); this.$importFileInput = $('#import_fileupload'); this.$importIntoSelect = $('#import_into'); }, // Build the select to add/remove from groups. buildGroupSelect: function() { // If a contact is open we know which categories it's in if(this.currentid) { var contact = this.contacts.findById(this.currentid); if(contact === null) { return false; } this.$groups.find('optgroup,option:not([value="-1"])').remove(); var addopts = '', rmopts = ''; $.each(this.groups.categories, function(i, category) { if(contact.inGroup(category.name)) { rmopts += ''; } else { addopts += ''; } }); if(addopts.length) { $(addopts).appendTo(this.$groups) .wrapAll(''); } if(rmopts.length) { $(rmopts).appendTo(this.$groups) .wrapAll(''); } } else if(this.contacts.getSelectedContacts().length > 0) { // Otherwise add all categories to both add and remove this.$groups.find('optgroup,option:not([value="-1"])').remove(); var addopts = '', rmopts = ''; $.each(this.groups.categories, function(i, category) { rmopts += ''; addopts += ''; }); $(addopts).appendTo(this.$groups) .wrapAll(''); $(rmopts).appendTo(this.$groups) .wrapAll(''); } else { // 3rd option: No contact open, none checked, just show "Add group..." this.$groups.find('optgroup,option:not([value="-1"])').remove(); } $('').appendTo(this.$groups); this.$groups.val(-1); }, bindEvents: function() { var self = this; // Should fix Opera check for delayed delete. $(window).unload(function (){ $(window).trigger('beforeunload'); }); this.hashChange = function() { console.log('hashchange', window.location.hash) var id = parseInt(window.location.hash.substr(1)); if(id && id !== self.currentid) { self.openContact(id); } else if(!id && self.currentid) { self.closeContact(self.currentid); } } $(window).bind('popstate', this.hashChange); $(window).bind('hashchange', this.hashChange); // App specific events $(document).bind('status.contact.deleted', function(e, data) { var id = parseInt(data.id); if(id === self.currentid) { delete self.currentid; } console.log('contact', data.id, 'deleted'); // update counts on group lists self.groups.removeFromAll(data.id, true); }); $(document).bind('status.contact.added', function(e, data) { self.currentid = parseInt(data.id); self.buildGroupSelect(); self.hideActions(); }); $(document).bind('status.contact.error', function(e, data) { OC.notify({message:data.message}); }); $(document).bind('status.contact.enabled', function(e, enabled) { console.log('status.contact.enabled', enabled); /*if(enabled) { self.showActions(['back', 'download', 'delete', 'groups']); } else { self.showActions(['back']); }*/ }); $(document).bind('status.contacts.loaded', function(e, result) { console.log('status.contacts.loaded', result); if(result.status !== true) { alert('Error loading contacts!'); } else { self.numcontacts = result.numcontacts; self.loading(self.$rightContent, false); self.groups.loadGroups(self.numcontacts, function() { self.loading($('#leftcontent'), false); var id = $.QueryString['id']; // Keep for backwards compatible links. self.currentid = parseInt(id); if(!self.currentid) { self.currentid = parseInt(window.location.hash.substr(1)); } console.log('Groups loaded, currentid', self.currentid); if(self.currentid) { self.openContact(self.currentid); } }); if(!result.is_indexed) { // Wait a couple of mins then check if contacts are indexed. setTimeout(function() { OC.notify({message:t('contacts', 'Indexing contacts'), timeout:20}); $.post(OC.filePath('contacts', 'ajax', 'indexproperties.php')); }, 10000); } else { console.log('contacts are indexed.'); } } }); $(document).bind('status.contact.currentlistitem', function(e, result) { //console.log('status.contact.currentlistitem', result, self.$rightContent.height()); if(self.dontScroll !== true) { if(result.pos > self.$rightContent.height()) { self.$rightContent.scrollTop(result.pos - self.$rightContent.height() + result.height); } else if(result.pos < self.$rightContent.offset().top) { self.$rightContent.scrollTop(result.pos); } } else { setTimeout(function() { self.dontScroll = false; }, 100); } self.currentlistid = result.id; }); $(document).bind('status.nomorecontacts', function(e, result) { console.log('status.nomorecontacts', result); self.$contactList.hide(); self.$firstRun.show(); // TODO: Show a first-run page. }); $(document).bind('status.visiblecontacts', function(e, result) { console.log('status.visiblecontacts', result); // TODO: To be decided. }); // A contact id was in the request $(document).bind('request.loadcontact', function(e, result) { console.log('request.loadcontact', result); if(self.numcontacts) { self.openContact(result.id); } else { // Contacts are not loaded yet, try again. console.log('waiting for contacts to load'); setTimeout(function() { $(document).trigger('request.loadcontact', { id: result.id }); }, 1000); } }); $(document).bind('request.contact.setasfavorite', function(e, data) { console.log('contact', data.id, 'request.contact.setasfavorite'); self.groups.setAsFavorite(data.id, data.state); }); $(document).bind('request.contact.addtogroup', function(e, data) { self.groups.addTo(data.id, data.groupid, function(response) { console.log('contact', data.id, 'request.contact.addtogroup', response); }); }); $(document).bind('request.contact.removefromgroup', function(e, data) { console.log('contact', data.id, 'request.contact.removefromgroup'); self.groups.removeFrom(data.id, data.groupid); }); $(document).bind('request.contact.export', function(e, data) { var id = parseInt(data.id); console.log('contact', data.id, 'request.contact.export'); document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + self.currentid; }); $(document).bind('request.contact.close', function(e, data) { var id = parseInt(data.id); console.log('contact', data.id, 'request.contact.close'); self.closeContact(id); }); $(document).bind('request.contact.delete', function(e, data) { var id = parseInt(data.id); console.log('contact', data.id, 'request.contact.delete'); self.closeContact(id); self.contacts.delayedDelete(id); self.$contactList.removeClass('dim'); self.showActions(['add']); }); $(document).bind('request.select.contactphoto.fromlocal', function(e, result) { console.log('request.select.contactphoto.fromlocal', result); $('#contactphoto_fileupload').trigger('click'); }); $(document).bind('request.select.contactphoto.fromcloud', function(e, result) { console.log('request.select.contactphoto.fromcloud', result); OC.dialogs.filepicker(t('contacts', 'Select photo'), function(path) { self.cloudPhotoSelected(self.currentid, path); }, false, 'image', true); }); $(document).bind('request.edit.contactphoto', function(e, result) { console.log('request.edit.contactphoto', result); self.editCurrentPhoto(result.id); }); $(document).bind('request.addressbook.activate', function(e, result) { console.log('request.addressbook.activate', result); self.contacts.showFromAddressbook(result.id, result.activate); }); $(document).bind('status.contact.removedfromgroup', function(e, result) { console.log('status.contact.removedfromgroup', result); if(self.currentgroup == result.groupid) { self.contacts.hideContact(result.contactid); self.closeContact(result.contactid); } }); $(document).bind('status.group.groupremoved', function(e, result) { console.log('status.group.groupremoved', result); if(parseInt(result.groupid) === parseInt(self.currentgroup)) { self.contacts.showContacts([]); self.currentgroup = 'all'; } $.each(result.contacts, function(idx, contactid) { var contact = self.contacts.findById(contactid); console.log('contactid', contactid, contact); self.contacts.findById(contactid).removeFromGroup(result.groupname); }); }); $(document).bind('status.group.contactadded', function(e, result) { console.log('status.group.contactadded', result); var contact = self.contacts.findById(result.contactid); if(!contact) { return false; } contact.addToGroup(result.groupname); }); // Group sorted, save the sort order $(document).bind('status.groups.sorted', function(e, result) { console.log('status.groups.sorted', result); $.post(OC.filePath('contacts', 'ajax', 'setpreference.php'), {'key':'groupsort', 'value':result.sortorder}, function(jsondata) { if(jsondata.status !== 'success') { OC.notify({message: jsondata ? jsondata.data.message : t('contacts', 'Network or server error. Please inform administrator.')}); } }); }); // Group selected, only show contacts from that group $(document).bind('status.group.selected', function(e, result) { console.log('status.group.selected', result); self.currentgroup = result.id; // Close any open contact. if(self.currentid) { var id = self.currentid; self.closeContact(id); self.jumpToContact(id); } self.$contactList.show(); self.$toggleAll.show(); self.showActions(['add']); if(result.type === 'category' || result.type === 'fav') { self.contacts.showContacts(result.contacts); } else if(result.type === 'shared') { self.contacts.showFromAddressbook(self.currentgroup, true, true); } else { self.contacts.showContacts(self.currentgroup); } $.post(OC.filePath('contacts', 'ajax', 'setpreference.php'), {'key':'lastgroup', 'value':self.currentgroup}, function(jsondata) { if(!jsondata || jsondata.status !== 'success') { OC.notify({message: (jsondata && jsondata.data) ? jsondata.data.message : t('contacts', 'Network or server error. Please inform administrator.')}); } }); self.$rightContent.scrollTop(0); }); // mark items whose title was hid under the top edge as read /*this.$rightContent.scroll(function() { // prevent too many scroll requests; if(!self.isScrolling) { self.isScrolling = true; var num = self.$contactList.find('tr').length; //console.log('num', num); var offset = self.$contactList.find('tr:eq(' + (num-20) + ')').offset().top; if(offset < self.$rightContent.height()) { console.log('load more'); self.contacts.loadContacts(num, function() { self.isScrolling = false; }); } else { setTimeout(function() { self.isScrolling = false; }, self.scrollTimeoutMiliSecs); } //console.log('scroll, unseen:', offset, self.$rightContent.height()); } });*/ this.$settings.find('.settings').on('click keydown',function(event) { if(wrongKey(event)) { return; } var bodyListener = function(e) { if(self.$settings.find($(e.target)).length == 0) { self.$settings.switchClass('open', ''); } }; if(self.$settings.hasClass('open')) { self.$settings.switchClass('open', ''); $('body').unbind('click', bodyListener); } else { // FIXME: Settings needs to be refactored self.$settings.find('h2').trigger('click'); self.$settings.switchClass('', 'open'); $('body').bind('click', bodyListener); } }); $('#contactphoto_fileupload').on('change', function() { self.uploadPhoto(this.files); }); $('#groupsheader > .addgroup').on('click keydown',function(event) { if(wrongKey(event)) { return; } self.groups.editGroup(); //self.addGroup(); }); this.$ninjahelp.find('.close').on('click keydown',function(event) { if(wrongKey(event)) { return; } self.$ninjahelp.hide(); }); this.$toggleAll.on('change', function() { var isChecked = $(this).is(':checked'); self.setAllChecked(isChecked); if(self.$groups.find('option').length === 1) { self.buildGroupSelect(); } if(isChecked) { self.showActions(['add', 'download', 'groups', 'delete', 'favorite']); } else { self.showActions(['add']); } }); this.$contactList.on('change', 'input:checkbox', function(event) { if($(this).is(':checked')) { if(self.$groups.find('option').length === 1) { self.buildGroupSelect(); } self.showActions(['add', 'download', 'groups', 'delete', 'favorite']); } else if(self.contacts.getSelectedContacts().length === 0) { self.showActions(['add']); } }); // Add to/remove from group multiple contacts. // FIXME: Refactor this to be usable for favoriting also. this.$groups.on('change', function() { var $opt = $(this).find('option:selected'); var action = $opt.parent().data('action'); var ids, groupName, groupId, buildnow = false; // If a contact is open the action is only applied to that, // otherwise on all selected items. if(self.currentid) { ids = [self.currentid]; buildnow = true; } else { ids = self.contacts.getSelectedContacts(); } self.setAllChecked(false); self.$toggleAll.prop('checked', false); if(!self.currentid) { self.showActions(['add']); } if($opt.val() === 'add') { // Add new group action = 'add'; console.log('add group...'); self.$groups.val(-1); self.addGroup(function(response) { if(response.status === 'success') { groupId = response.id; groupName = response.name; self.groups.addTo(ids, groupId, function(result) { if(result.status === 'success') { $.each(ids, function(idx, id) { // Delay each contact to not trigger too many ajax calls // at a time. setTimeout(function() { var contact = self.contacts.findById(id); if(contact === null) { return true; } contact.addToGroup(groupName); // I don't think this is used... if(buildnow) { self.buildGroupSelect(); } $(document).trigger('status.contact.addedtogroup', { contactid: id, groupid: groupId, groupname: groupName }); }, 1000); }); } else { // TODO: Use message returned from groups object. OC.notify({message:t('contacts', t('contacts', 'Error adding to group.'))}); } }); } else { OC.notify({message: response.message}); } }); return; } groupName = $opt.text(), groupId = $opt.val(); console.log('trut', groupName, groupId); if(action === 'add') { self.groups.addTo(ids, $opt.val(), function(result) { console.log('after add', result); if(result.status === 'success') { $.each(result.ids, function(idx, id) { // Delay each contact to not trigger too many ajax calls // at a time. setTimeout(function() { console.log('adding', id, 'to', groupName); var contact = self.contacts.findById(id); if(contact === null) { return true; } contact.addToGroup(groupName); // I don't think this is used... if(buildnow) { self.buildGroupSelect(); } $(document).trigger('status.contact.addedtogroup', { contactid: id, groupid: groupId, groupname: groupName }); }, 1000); }); } else { var msg = result.message ? result.message : t('contacts', 'Error adding to group.'); OC.notify({message:msg}); } }); if(!buildnow) { self.$groups.val(-1).hide().find('optgroup,option:not([value="-1"])').remove(); } } else if(action === 'remove') { self.groups.removeFrom(ids, $opt.val(), function(result) { console.log('after remove', result); if(result.status === 'success') { var groupname = $opt.text(), groupid = $opt.val(); $.each(result.ids, function(idx, id) { var contact = self.contacts.findById(id); if(contact === null) { return true; } contact.removeFromGroup(groupname); if(buildnow) { self.buildGroupSelect(); } // If a group is selected the contact has to be removed from the list $(document).trigger('status.contact.removedfromgroup', { contactid: id, groupid: groupId, groupname: groupName }); }); } else { var msg = result.message ? result.message : t('contacts', 'Error removing from group.'); OC.notify({message:msg}); } }); if(!buildnow) { self.$groups.val(-1).hide().find('optgroup,option:not([value="-1"])').remove(); } } // else something's wrong ;) self.setAllChecked(false); }); // Contact list. Either open a contact or perform an action (mailto etc.) this.$contactList.on('click', 'tr', function(event) { if($(event.target).is('input')) { return; } if(event.ctrlKey || event.metaKey) { event.stopPropagation(); event.preventDefault(); console.log('select', event); self.dontScroll = true; self.contacts.select($(this).data('id'), true); return; } if($(event.target).is('a.mailto')) { var mailto = 'mailto:' + $.trim($(this).find('.email').text()); console.log('mailto', mailto); try { window.location.href=mailto; } catch(e) { alert(t('contacts', 'There was an error opening a mail composer.')); } return; } self.openContact($(this).data('id')); }); this.$settings.find('h2').on('click keydown', function(event) { if(wrongKey(event)) { return; } if($(this).next('ul').is(':visible')) { //$(this).next('ul').slideUp(); return; } console.log('settings'); var $list = $(this).next('ul'); if($(this).data('id') === 'addressbooks') { console.log('addressbooks'); if(!self.$addressbookTmpl) { self.$addressbookTmpl = $('#addressbookTemplate'); } $list.empty(); $.each(self.contacts.addressbooks, function(id, book) { var $li = self.$addressbookTmpl.octemplate({ id: id, permissions: book.permissions, displayname: book.displayname }); $list.append($li); }); $list.find('a.action').tipsy({gravity: 'w'}); $list.find('a.action.delete').on('click keypress', function() { $('.tipsy').remove(); var id = parseInt($(this).parents('li').first().data('id')); console.log('delete', id); var $li = $(this).parents('li').first(); $.ajax({ type:'POST', url:OC.filePath('contacts', 'ajax', 'addressbook/delete.php'), data:{ id: id }, success:function(jsondata) { console.log(jsondata); if(jsondata.status == 'success') { self.contacts.unsetAddressbook(id); $li.remove(); OC.notify({ message:t('contacts','Deleting done. Click here to cancel reloading.'), timeout:5, timeouthandler:function() { console.log('reloading'); window.location.href = OC.linkTo('contacts', 'index.php'); }, clickhandler:function() { console.log('reloading cancelled'); OC.notify({cancel:true}); } }); } else { OC.notify({message:jsondata.data.message}); } }, error:function(jqXHR, textStatus, errorThrown) { OC.notify({message:textStatus + ': ' + errorThrown}); id = false; } }); }); $list.find('a.action.globe').on('click keypress', function() { var id = parseInt($(this).parents('li').first().data('id')); var book = self.contacts.addressbooks[id]; var uri = (book.owner === oc_current_user ) ? book.uri : book.uri + '_shared_by_' + book.owner; var link = OC.linkToRemote('carddav')+'/addressbooks/'+encodeURIComponent(oc_current_user)+'/'+encodeURIComponent(uri); var $dropdown = $('
'); $dropdown.appendTo($(this).parents('li').first()); var $input = $dropdown.find('input'); $input.focus().get(0).select(); $input.on('blur', function() { $dropdown.hide('blind', function() { $dropdown.remove(); }); }); }); if(typeof OC.Share !== 'undefined') { OC.Share.loadIcons('addressbook'); } else { $list.find('a.action.share').css('display', 'none'); } } else if($(this).data('id') === 'import') { console.log('import'); $('.import-upload').show(); $('.import-select').hide(); var addAddressbookCallback = function(select, name) { var id; $.ajax({ type:'POST', async:false, url:OC.filePath('contacts', 'ajax', 'addressbook/add.php'), data:{ name: name }, success:function(jsondata) { console.log(jsondata); if(jsondata.status == 'success') { self.contacts.setAddressbook(jsondata.data.addressbook); id = jsondata.data.addressbook.id; } else { OC.notify({message:jsondata.data.message}); } }, error:function(jqXHR, textStatus, errorThrown) { OC.notify({message:textStatus + ': ' + errorThrown}); id = false; } }); return id; }; self.$importIntoSelect.empty(); $.each(self.contacts.addressbooks, function(id, book) { self.$importIntoSelect.append(''); }); self.$importIntoSelect.multiSelect({ createCallback:addAddressbookCallback, singleSelect: true, createText:String(t('contacts', 'Add address book')), minWidth: 120 }); } $(this).parents('ul').first().find('ul:visible').slideUp(); $list.toggle('slow'); }); var addContact = function() { console.log('add'); self.$toggleAll.hide(); $(this).hide(); self.currentid = 'new'; // Properties that the contact doesn't know console.log('addContact, groupid', self.currentgroup); var groupprops = { favorite: false, groups: self.groups.categories, currentgroup: {id:self.currentgroup, name:self.groups.nameById(self.currentgroup)} }; self.$firstRun.hide(); self.$contactList.show(); self.tmpcontact = self.contacts.addContact(groupprops); self.$rightContent.prepend(self.tmpcontact); self.hideActions(); }; this.$firstRun.on('click keydown', '.import', function(event) { event.preventDefault(); event.stopPropagation(); self.$settings.find('.settings').click(); }); this.$firstRun.on('click keydown', '.addcontact', function(event) { if(wrongKey(event)) { return; } addContact(); }); this.$header.on('click keydown', '.add', function(event) { if(wrongKey(event)) { return; } addContact(); }); this.$header.on('click keydown', '.delete', function(event) { if(wrongKey(event)) { return; } console.log('delete'); if(self.currentid) { console.assert(utils.isUInt(self.currentid), 'self.currentid is not an integer'); self.contacts.delayedDelete(self.currentid); } else { self.contacts.delayedDelete(self.contacts.getSelectedContacts()); } self.showActions(['add']); }); this.$header.on('click keydown', '.download', function(event) { if(wrongKey(event)) { return; } console.log('download'); document.location.href = OC.linkTo('contacts', 'export.php') + '?selectedids=' + self.contacts.getSelectedContacts().join(','); }); this.$header.on('click keydown', '.favorite', function(event) { if(wrongKey(event)) { return; } if(!utils.isUInt(self.currentid)) { return; } // FIXME: This should only apply for contacts list. var state = self.groups.isFavorite(self.currentid); console.log('Favorite?', this, state); self.groups.setAsFavorite(self.currentid, !state, function(jsondata) { if(jsondata.status === 'success') { if(state) { self.$header.find('.favorite').switchClass('active', ''); } else { self.$header.find('.favorite').switchClass('', 'active'); } } else { OC.notify({message:t('contacts', jsondata.data.message)}); } }); }); this.$contactList.on('mouseenter', 'td.email', function(event) { if($.trim($(this).text()).length > 3) { $(this).find('.mailto').css('display', 'inline-block'); //.fadeIn(100); } }); this.$contactList.on('mouseleave', 'td.email', function(event) { $(this).find('.mailto').fadeOut(100); }); // Import using jquery.fileupload $(function() { var uploadingFiles = {}, numfiles = 0, uploadedfiles = 0, retries = 0; var aid, importError = false; var $progressbar = $('#import-progress'); var $status = $('#import-status-text'); var waitForImport = function() { if(numfiles == 0 && uploadedfiles == 0) { $progressbar.progressbar('value',100); if(!importError) { OC.notify({ message:t('contacts','Import done. Click here to cancel reloading.'), timeout:5, timeouthandler:function() { console.log('reloading'); window.location.href = OC.linkTo('contacts', 'index.php'); }, clickhandler:function() { console.log('reloading cancelled'); OC.notify({cancel:true}); } }); } retries = aid = 0; $progressbar.fadeOut(); setTimeout(function() { $status.fadeOut('slow'); $('.import-upload').show(); }, 3000); } else { setTimeout(function() { waitForImport(); }, 1000); } }; var doImport = function(file, aid, cb) { $.post(OC.filePath('contacts', '', 'import.php'), { id: aid, file: file, fstype: 'OC_FilesystemView' }, function(jsondata) { if(jsondata.status != 'success') { importError = true; OC.notify({message:jsondata.data.message}); } if(typeof cb == 'function') { cb(jsondata); } }); return false; }; var importFiles = function(aid, uploadingFiles) { console.log('importFiles', aid, uploadingFiles); if(numfiles != uploadedfiles) { OC.notify({message:t('contacts', 'Not all files uploaded. Retrying...')}); retries += 1; if(retries > 3) { numfiles = uploadedfiles = retries = aid = 0; uploadingFiles = {}; $progressbar.fadeOut(); OC.dialogs.alert(t('contacts', 'Something went wrong with the upload, please retry.'), t('contacts', 'Error')); return; } setTimeout(function() { // Just to let any uploads finish importFiles(aid, uploadingFiles); }, 1000); } $progressbar.progressbar('value', 50); var todo = uploadedfiles; $.each(uploadingFiles, function(fileName, data) { $status.text(t('contacts', 'Importing from {filename}...', {filename:fileName})).fadeIn(); doImport(fileName, aid, function(response) { if(response.status === 'success') { $status.text(t('contacts', '{success} imported, {failed} failed.', {success:response.data.imported, failed:response.data.failed})).fadeIn(); } else { $('.import-upload').show(); $('.import-select').hide(); } delete uploadingFiles[fileName]; numfiles -= 1; uploadedfiles -= 1; $progressbar.progressbar('value',50+(50/(todo-uploadedfiles))); }); }); //$status.text(t('contacts', 'Importing...')).fadeIn(); waitForImport(); }; // Start the actual import. $('.doImport').on('click keypress', function(event) { if(wrongKey(event)) { return; } aid = $(this).prev('select').val(); $('.import-select').hide(); importFiles(aid, uploadingFiles); }); $('#import_fileupload').fileupload({ acceptFileTypes: /^text\/(directory|vcard|x-vcard)$/i, add: function(e, data) { var files = data.files; var totalSize=0; if(files) { numfiles += files.length; uploadedfiles = 0; for(var i=0;i').append(this.eq(0).clone()).html(); }; /** * Object Template * Inspired by micro templating done by e.g. underscore.js */ var Template = { init: function(options, elem) { // Mix in the passed in options with the default options this.options = $.extend({},this.options,options); // Save the element reference, both as a jQuery // reference and a normal reference this.elem = elem; this.$elem = $(elem); var _html = this._build(this.options); //console.log('html', this.$elem.html()); return $(_html); }, // From stackoverflow.com/questions/1408289/best-way-to-do-variable-interpolation-in-javascript _build: function(o){ var data = this.$elem.html(); //this.$elem.attr('type') === 'text/template' //? this.$elem.html() : this.$elem.outerHTML(); return data.replace(/{([^{}]*)}/g, function (a, b) { var r = o[b]; return typeof r === 'string' || typeof r === 'number' ? r : a; } ); }, options: { } }; $.fn.octemplate = function(options) { if ( this.length ) { var _template = Object.create(Template); return _template.init(options, this); } }; })( jQuery ); $(document).ready(function() { OC.Contacts.init(); });