diff --git a/css/contacts.css b/css/contacts.css index 653a33ef..c5aca42a 100644 --- a/css/contacts.css +++ b/css/contacts.css @@ -31,10 +31,10 @@ } #content textarea { font-family: inherit; } -#content input:-moz-placeholder { color: #aaa; } -#content input::-webkit-input-placeholder { color: #aaa; } -#content input:-ms-input-placeholder { color: #aaa; } -#content input:placeholder { color: #aaa; } +#content input:-moz-placeholder #content ::-moz-placeholder, #content input[placeholder], #content input:placeholder, #content input:-ms-input-placeholder, #content input::-webkit-input-placeholder, #content input:-moz-placeholder { + color: #aaa; + text-overflow: ellipsis; +} #content input:not([type="checkbox"]), #content select:not(.button), #content textarea { background-color: #fefefe; border: 1px solid #fff !important; @@ -62,7 +62,7 @@ /* Left content */ -#leftcontent { top: 3.5em !important; padding: 0; margin: 0; } +#leftcontent { position: absolute; top: 4em; padding: 0; margin: 0; } #leftcontent a { display: inline-block; padding: 0; margin: 0; } #leftcontent h3 { cursor: pointer; @@ -95,7 +95,16 @@ margin: auto 0 auto .3em; } -#groupactions { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; height: 4em; border-bottom: 1px solid #DDDDDD; } +#groupsheader { + -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; + position: fixed; + padding: 0; margin:0; + top:3.5em; left: 12.5em; + height: 4em; width: 20em; + border-bottom: 1px solid #DDDDDD; + border-right: 1px solid #DDDDDD; + background: none repeat scroll 0 0 #F8F8F8; +} /*#groupactions > button, .addcontact, .import-upload-button, .doImport { -moz-border-bottom-colors: none; -moz-border-left-colors: none; @@ -162,8 +171,9 @@ dl.form { display: block; width: auto; margin: 0; padding: 0; cursor: normal; } .no-svg .mail { background-image:url('%webroot%/core/img/actions/mail.png'); } .no-svg .import, .no-svg .upload { background-image:url('%webroot%/core/img/actions/upload.png'); } .no-svg .export, .no-svg .download { background-image:url('%webroot%/core/img/actions/download.png'); } -.no-svg .cloud:not { background-image:url('%webroot%/core/img/places/picture.png'); } -.no-svg .globe:not { background-image:url('%webroot%/core/img/actions/public.png'); } +.no-svg .cloud { background-image:url('%webroot%/core/img/places/picture.png'); } +.no-svg .globe { background-image:url('%webroot%/core/img/actions/public.png'); } +.no-svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); } .no-svg .starred { background-image:url('%appswebroot%/contacts/img/starred.png'); background-size: contain; } .no-svg .checked { background-image:url('%appswebroot%/contacts/img/checkmark-green.png'); } .no-svg .checked.disabled { background-image:url('%appswebroot%/contacts/img/checkmark-gray.png'); cursor: default; } @@ -186,6 +196,7 @@ dl.form { display: block; width: auto; margin: 0; padding: 0; cursor: normal; } .svg .export,.svg .download { background-image:url('%webroot%/core/img/actions/download.svg'); } .svg .cloud { background-image:url('%webroot%/core/img/places/picture.svg'); } .svg .globe { background-image:url('%webroot%/core/img/actions/public.svg'); } +.svg .settings { background-image:url('%webroot%/core/img/actions/settings.svg'); } .svg .starred { background-image:url('%appswebroot%/contacts/img/starred.svg'); background-size: contain; } .svg .checked { background-image:url('%appswebroot%/contacts/img/checkmark-green.svg'); } .svg .checked.disabled { background-image:url('%appswebroot%/contacts/img/checkmark-gray.svg'); cursor: default; } @@ -307,10 +318,18 @@ ul.propertylist { width: 450px; } .addressbooks-settings td.active, .addressbooks-settings td.action { width: 20px; } #contacts-settings .settings { - width: 20px; height: 20px; - float: left; + /*width: 20px; height: 20px; + float: left;*/ + color: transparent; + background-repeat: no-repeat; + background-position: left center; + background-origin: content-box; background-image:url('%webroot%/core/img/actions/settings.svg'); } +#contacts-settings .settings:hover { + font-weight: normal; + color: #666666; +} #contacts-settings.open { height: auto; } @@ -331,7 +350,7 @@ ul.propertylist { width: 450px; } z-index: 2; } #contacts-settings li,#contacts-settings li:hover { background-color: transparent; white-space: nowrap; } -#contacts-settings a.action { width: 20px; height: 20px; } +#contacts-settings a.action:not(.settings) { width: 16px; height: 16px; } #contacts-settings .actions { float: right; } .multiselectoptions label { display: block; } @@ -433,7 +452,7 @@ input[type="checkbox"].propertytype { width: 10px; } /* Right content layout */ -#rightcontent, .rightcontent { position:fixed; top: 7.5em; left: 32.5em; overflow-x:hidden; overflow-y: auto; } +#rightcontent, .rightcontent { position:absolute; top: 4em; left: 20em; overflow-x:hidden; overflow-y: auto; } /* Contact layout */ diff --git a/css/placeholder_polyfill.css b/css/placeholder_polyfill.css new file mode 100644 index 00000000..a0464add --- /dev/null +++ b/css/placeholder_polyfill.css @@ -0,0 +1,32 @@ +span.placeholder{ + position:absolute; + font-size:75%; + color:#999; + font-family:sans-serif; + padding:4px 3px; + z-index:1; + cursor:text; +} + +span.placeholder-hide-except-screenreader { + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px); + padding:0 !important; + border:0 !important; + height: 1px !important; + width: 1px !important; + overflow: hidden; +} + +span.placeholder-hide{ + display:none; +} + +/* overwrite for the HTML5 Boilerplate way to hide labels */ +label.visuallyhidden-with-placeholder{ + /*clip: auto !important;*/ + height:auto !important; + overflow: visible !important; + position:absolute !important; + left:-999em; +} \ No newline at end of file diff --git a/css/placeholder_polyfill.min.css b/css/placeholder_polyfill.min.css new file mode 100644 index 00000000..5a967b0b --- /dev/null +++ b/css/placeholder_polyfill.min.css @@ -0,0 +1,8 @@ +/** + * Html5 Placeholder Polyfill - v2.0.3 - 2012-08-21 + * web: * http://blog.ginader.de/dev/jquery/HTML5-placeholder-polyfill/ + * issues: * https://github.com/ginader/HTML5-placeholder-polyfill/issues + * Copyright (c) 2012 Dirk Ginader; Licensed MIT, GPL +*/ +label span.placeholder{position:absolute;font-size:75%;color:#999;font-family:sans-serif;padding:4px 3px;z-index:1;cursor:text}label span.placeholder-hide-except-screenreader{clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);padding:0!important;border:0!important;height:1px!important;width:1px!important;overflow:hidden} +label span.placeholder-hide{display:none}label.visuallyhidden-with-placeholder{height:auto!important;overflow:visible!important;position:absolute!important;left:-999em} \ No newline at end of file diff --git a/index.php b/index.php index aef4bacd..75bc804a 100644 --- a/index.php +++ b/index.php @@ -49,16 +49,13 @@ $maxUploadFilesize = min($maxUploadFilesize, $freeSpace); OCP\Util::addscript('contacts', 'multiselect'); OCP\Util::addscript('', 'oc-vcategories'); +OCP\Util::addscript('contacts', 'modernizr.custom'); OCP\Util::addscript('contacts', 'app'); OCP\Util::addscript('contacts', 'contacts'); -OCP\Util::addscript('contacts', 'modernizr'); -OCP\Util::addscript('contacts', 'placeholder.polyfill.jquery'); OCP\Util::addscript('contacts', 'expanding'); OCP\Util::addscript('contacts', 'jquery.combobox'); OCP\Util::addscript('files', 'jquery.fileupload'); -//OCP\Util::addscript('core', 'jquery.inview'); OCP\Util::addscript('contacts', 'jquery.Jcrop'); -OCP\Util::addscript('contacts', 'jquery.multi-autocomplete'); OCP\Util::addStyle('contacts', 'multiselect'); OCP\Util::addStyle('contacts', 'jquery.combobox'); OCP\Util::addStyle('contacts', 'jquery.Jcrop'); diff --git a/js/app.js b/js/app.js index c9f589da..b786821c 100644 --- a/js/app.js +++ b/js/app.js @@ -1,3 +1,11 @@ +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') + ] +}); + var utils = {}; /** @@ -22,11 +30,11 @@ utils.isArray = function(obj) { 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 @@ -50,7 +58,7 @@ utils.moveCursorToEnd = function(el) { range.collapse(false); range.select(); } -} +}; if (typeof Object.create !== 'function') { Object.create = function (o) { @@ -77,8 +85,9 @@ Array.prototype.clean = function(deleteValue) { // Keep it DRY ;) var wrongKey = function(event) { - return (event.type === 'keydown' && (event.keyCode !== 32 && event.keyCode !== 13)); -} + return ((event.type === 'keydown' || event.type === 'keypress') + && (event.keyCode !== 32 && event.keyCode !== 13)); +}; /** * Simply notifier @@ -140,7 +149,7 @@ OC.notify = function(params) { self.notifier.removeData(dataid); }); } -} +}; var GroupList = function(groupList, listItemTmpl) { this.$groupList = groupList; @@ -158,7 +167,7 @@ var GroupList = function(groupList, listItemTmpl) { if(response.status !== 'success') { OC.notify({message:response.data.message}); } - }) + }); } else { self.selectGroup({element:$(this)}); } @@ -166,19 +175,19 @@ var GroupList = function(groupList, listItemTmpl) { this.$groupListItemTemplate = listItemTmpl; this.categories = []; -} +}; GroupList.prototype.nameById = function(id) { - return this.findById(id).contents().filter(function(){ return(this.nodeType == 3); }).text().trim() -} + return this.findById(id).contents().filter(function(){ return(this.nodeType == 3); }).text().trim(); +}; GroupList.prototype.findById = function(id) { return this.$groupList.find('h3[data-id="' + id + '"]'); -} +}; GroupList.prototype.isFavorite = function(contactid) { return this.inGroup(contactid, 'fav'); -} +}; GroupList.prototype.selectGroup = function(params) { var id, $elem; @@ -203,15 +212,15 @@ GroupList.prototype.selectGroup = function(params) { $(document).trigger('status.group.selected', { id: this.lastgroup, type: $elem.data('type'), - contacts: $elem.data('contacts'), + contacts: $elem.data('contacts') }); -} +}; GroupList.prototype.inGroup = function(contactid, groupid) { var $groupelem = this.findById(groupid); var contacts = $groupelem.data('contacts'); return (contacts.indexOf(contactid) !== -1); -} +}; GroupList.prototype.setAsFavorite = function(contactid, state, cb) { contactid = parseInt(contactid); @@ -251,7 +260,7 @@ GroupList.prototype.setAsFavorite = function(contactid, state, cb) { } }); } -} +}; /** * Add one or more contact ids to a group @@ -315,7 +324,7 @@ GroupList.prototype.addTo = function(contactid, groupid, cb) { $(document).trigger('status.group.contactadded', { contactid: contactid, groupid: groupid, - groupname: self.nameById(groupid), + groupname: self.nameById(groupid) }); } } else { @@ -325,14 +334,14 @@ GroupList.prototype.addTo = function(contactid, groupid, cb) { } }); } -} +}; GroupList.prototype.removeFrom = function(contactid, groupid, cb) { console.log('GroupList.removeFrom', contactid, groupid); var $groupelem = this.findById(groupid); var contacts = $groupelem.data('contacts'); var ids = []; - + // If it's the 'all' group simply decrement the number if(groupid === 'all') { var $numelem = $groupelem.find('.numcontacts'); @@ -405,7 +414,7 @@ GroupList.prototype.removeFrom = function(contactid, groupid, cb) { } }); } -} +}; GroupList.prototype.removeFromAll = function(contactid, alsospecial) { var self = this; @@ -413,11 +422,11 @@ GroupList.prototype.removeFromAll = function(contactid, alsospecial) { $.each(this.$groupList.find(selector), function(i, group) { self.removeFrom(contactid, $(this).data('id')); }); -} +}; GroupList.prototype.categoriesChanged = function(newcategories) { console.log('GroupList.categoriesChanged, I should do something'); -} +}; GroupList.prototype.contactDropped = function(event, ui) { var dragitem = ui.draggable, droptarget = $(this); @@ -430,7 +439,7 @@ GroupList.prototype.contactDropped = function(event, ui) { $(this).data('obj').addTo(dragitem.data('id'), $(this).data('id')); } } -} +}; GroupList.prototype.deleteGroup = function(groupid, cb) { var $elem = this.findById(groupid); @@ -445,7 +454,7 @@ GroupList.prototype.deleteGroup = function(groupid, cb) { groupid: groupid, newgroupid: parseInt($newelem.data('id')), groupname: self.nameById(groupid), - contacts: contacts, + contacts: contacts }); $elem.remove(); self.selectGroup({element:$newelem}); @@ -456,7 +465,7 @@ GroupList.prototype.deleteGroup = function(groupid, cb) { cb(jsondata); } }); -} +}; GroupList.prototype.editGroup = function(id) { var self = this; @@ -476,16 +485,16 @@ GroupList.prototype.editGroup = function(id) { self.addGroup({name:name, element:$elem}, function(response) { if(response.status === 'success') { $elem.prepend(name).removeClass('editing').attr('data-id', response.id); - $input.next('.checked').remove() - $input.remove() + $input.next('.checked').remove(); + $input.remove(); self.$editelem = null; } else { $input.prop('disabled', false); OC.notify({message:response.message}); } }); - } - + }; + if(typeof id === 'undefined') { // Add new group var tmpl = this.$groupListItemTemplate; @@ -493,7 +502,7 @@ GroupList.prototype.editGroup = function(id) { id: 'new', type: 'category', num: 0, - name: '', + name: '' }); var $input = $(''); self.$editelem.prepend($input).addClass('editing'); @@ -533,11 +542,11 @@ GroupList.prototype.editGroup = function(id) { var $input = $('' + + 'title="' + t('contacts', 'Shared by {owner}', {owner:shared.userid}) + '" />'; var $elem = (tmpl).octemplate({ id: shared.id, type: 'shared', num: '', //jsondata.data.shared.length, - name: shared.displayname, + name: shared.displayname }); $elem.find('.numcontacts').after(sharedindicator); $elem.data('obj', self); @@ -685,27 +694,27 @@ GroupList.prototype.loadGroups = function(numcontacts, cb) { console.log('stop sorting', $(this)); var ids = []; $.each($(this).children('h3[data-type="category"]'), function(i, elem) { - ids.push($(elem).data('id')) - }) + ids.push($(elem).data('id')); + }); self.sortorder = ids; $(document).trigger('status.groups.sorted', { - sortorder: self.sortorder.join(','), + sortorder: self.sortorder.join(',') }); - }, + } }); var $elem = self.findById(self.lastgroup); $elem.addClass('active'); $(document).trigger('status.group.selected', { id: self.lastgroup, type: $elem.data('type'), - contacts: $elem.data('contacts'), + contacts: $elem.data('contacts') }); } // TODO: else if(typeof cb === 'function') { cb(); } }); -} +}; OC.Contacts = OC.Contacts || { init:function(id) { @@ -713,7 +722,7 @@ OC.Contacts = OC.Contacts || { $(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, + message: 'error in: ' + settings.url + ', '+'error: ' + xhr.responseText }); }); } @@ -777,9 +786,10 @@ OC.Contacts = OC.Contacts || { // The weird double loading is because jquery apparently doesn't // create a searchable object from a script element. $.each($($('#contactDetailsTemplate').html()), function(idx, node) { - if(node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'DIV') { + var $node = $(node); + if($node.is('div')) { var $tmpl = $(node.innerHTML); - self.detailTemplates[$tmpl.data('element')] = $(node); + self.detailTemplates[$tmpl.data('element')] = $node; } }); this.$groupListItemTemplate = $('#groupListItemTemplate'); @@ -853,7 +863,7 @@ OC.Contacts = OC.Contacts || { var id = parseInt(data.id); console.log('contact', data.id, 'deleted'); // update counts on group lists - self.groups.removeFromAll(data.id, true) + self.groups.removeFromAll(data.id, true); }); $(document).bind('status.contact.added', function(e, data) { @@ -867,7 +877,7 @@ OC.Contacts = OC.Contacts || { }); $(document).bind('status.contact.enabled', function(e, enabled) { - console.log('status.contact.enabled', enabled) + console.log('status.contact.enabled', enabled); /*if(enabled) { self.showActions(['back', 'download', 'delete', 'groups']); } else { @@ -906,7 +916,7 @@ OC.Contacts = OC.Contacts || { self.dontScroll = false; }, 100); } - self.currentlistid = result.id + self.currentlistid = result.id; }); $(document).bind('status.nomorecontacts', function(e, result) { @@ -931,7 +941,7 @@ OC.Contacts = OC.Contacts || { console.log('waiting for contacts to load'); setTimeout(function() { $(document).trigger('request.loadcontact', { - id: result.id, + id: result.id }); }, 1000); } @@ -1008,7 +1018,7 @@ OC.Contacts = OC.Contacts || { $.each(result.contacts, function(idx, contactid) { var contact = self.contacts.findById(contactid); console.log('contactid', contactid, contact); - + self.contacts.findById(contactid).removeFromGroup(result.groupname); }); }); @@ -1083,7 +1093,7 @@ OC.Contacts = OC.Contacts || { 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); @@ -1096,7 +1106,7 @@ OC.Contacts = OC.Contacts || { self.uploadPhoto(this.files); }); - $('#groupactions > .addgroup').on('click keydown',function(event) { + $('#groupsheader > .addgroup').on('click keydown',function(event) { if(wrongKey(event)) { return; } @@ -1145,8 +1155,8 @@ OC.Contacts = OC.Contacts || { // 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 + ids = [self.currentid]; + buildnow = true; } else { ids = self.contacts.getSelectedContacts(); } @@ -1156,7 +1166,7 @@ OC.Contacts = OC.Contacts || { if(!self.currentid) { self.showActions(['add']); } - + if($opt.val() === 'add') { // Add new group action = 'add'; console.log('add group...'); @@ -1179,7 +1189,7 @@ OC.Contacts = OC.Contacts || { $(document).trigger('status.contact.addedtogroup', { contactid: id, groupid: groupId, - groupname: groupName, + groupname: groupName }); }, 1000); }); @@ -1194,7 +1204,7 @@ OC.Contacts = OC.Contacts || { }); return; } - + groupName = $opt.text(), groupId = $opt.val(); console.log('trut', groupName, groupId); @@ -1215,7 +1225,7 @@ OC.Contacts = OC.Contacts || { $(document).trigger('status.contact.addedtogroup', { contactid: id, groupid: groupId, - groupname: groupName, + groupname: groupName }); }, 1000); }); @@ -1241,7 +1251,7 @@ OC.Contacts = OC.Contacts || { $(document).trigger('status.contact.removedfromgroup', { contactid: id, groupid: groupId, - groupname: groupName, + groupname: groupName }); }); } else { @@ -1281,7 +1291,7 @@ OC.Contacts = OC.Contacts || { } self.openContact($(this).data('id')); }); - + this.$settings.find('h3').on('click keydown', function(event) { if(wrongKey(event)) { return; @@ -1294,7 +1304,7 @@ OC.Contacts = OC.Contacts || { var $list = $(this).next('ul'); if($(this).data('id') === 'addressbooks') { console.log('addressbooks'); - + if(!self.$addressbookTmpl) { self.$addressbookTmpl = $('#addressbookTemplate'); } @@ -1302,9 +1312,9 @@ OC.Contacts = OC.Contacts || { $list.empty(); $.each(self.contacts.addressbooks, function(id, book) { var $li = self.$addressbookTmpl.octemplate({ - id: id, + id: id, permissions: book.permissions, - displayname: book.displayname, + displayname: book.displayname }); $list.append($li); @@ -1317,7 +1327,7 @@ OC.Contacts = OC.Contacts || { var $li = $(this).parents('li').first(); $.ajax({ type:'POST', - url:OC.filePath('contacts', 'ajax', 'addressbook/delete.php'), + url:OC.filePath('contacts', 'ajax', 'addressbook/delete.php'), data:{ id: id }, success:function(jsondata) { console.log(jsondata); @@ -1343,7 +1353,7 @@ OC.Contacts = OC.Contacts || { error:function(jqXHR, textStatus, errorThrown) { OC.notify({message:textStatus + ': ' + errorThrown}); id = false; - }, + } }); }); $list.find('a.action.globe').on('click keypress', function() { @@ -1376,13 +1386,13 @@ OC.Contacts = OC.Contacts || { $.ajax({ type:'POST', async:false, - url:OC.filePath('contacts', 'ajax', 'addressbook/add.php'), + 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 + id = jsondata.data.addressbook.id; } else { OC.notify({message:jsondata.data.message}); } @@ -1390,10 +1400,10 @@ OC.Contacts = OC.Contacts || { error:function(jqXHR, textStatus, errorThrown) { OC.notify({message:textStatus + ': ' + errorThrown}); id = false; - }, + } }); return id; - } + }; self.$importIntoSelect.empty(); $.each(self.contacts.addressbooks, function(id, book) { @@ -1403,7 +1413,7 @@ OC.Contacts = OC.Contacts || { createCallback:addAddressbookCallback, singleSelect: true, createText:String(t('contacts', 'Add address book')), - minWidth: 120, + minWidth: 120 }); } @@ -1420,11 +1430,11 @@ OC.Contacts = OC.Contacts || { $(this).hide(); self.currentid = 'new'; // Properties that the contact doesn't know - console.log('addContact, groupid', self.currentgroup) + console.log('addContact, groupid', self.currentgroup); var groupprops = { favorite: false, groups: self.groups.categories, - currentgroup: {id:self.currentgroup, name:self.groups.nameById(self.currentgroup)}, + currentgroup: {id:self.currentgroup, name:self.groups.nameById(self.currentgroup)} }; self.tmpcontact = self.contacts.addContact(groupprops); self.$rightContent.prepend(self.tmpcontact); @@ -1450,7 +1460,7 @@ OC.Contacts = OC.Contacts || { return; } console.log('download'); - document.location.href = OC.linkTo('contacts', 'export.php') + document.location.href = OC.linkTo('contacts', 'export.php') + '?selectedids=' + self.contacts.getSelectedContacts().join(','); }); @@ -1558,14 +1568,14 @@ OC.Contacts = OC.Contacts || { $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.', + $status.text(t('contacts', '{success} imported, {failed} failed.', {success:response.data.imported, failed:response.data.failed})).fadeIn(); } delete uploadingFiles[fileName]; numfiles -= 1; uploadedfiles -= 1; $progressbar.progressbar('value',50+(50/(todo-uploadedfiles))); }); - }) + }); //$status.text(t('contacts', 'Importing...')).fadeIn(); waitForImport(); }; @@ -1605,7 +1615,7 @@ OC.Contacts = OC.Contacts || { $.each(files, function(i, file) { var fileName = file.name; console.log('file.name', file.name); - var jqXHR = $('#import_fileupload').fileupload('send', + var jqXHR = $('#import_fileupload').fileupload('send', { files: file, formData: function(form) { @@ -1624,7 +1634,7 @@ OC.Contacts = OC.Contacts || { }) .error(function(jqXHR, textStatus, errorThrown) { console.log(textStatus); - OC.notify({message:errorThrown + ': ' + textStatus,}); + OC.notify({message:errorThrown + ': ' + textStatus}); }); uploadingFiles[fileName] = jqXHR; }); @@ -1673,9 +1683,9 @@ OC.Contacts = OC.Contacts || { $('#upload input.stop').hide(); } } - }) + }); }); - + $(document).on('keypress', function(event) { if(!$(event.target).is('body')) { return; @@ -1731,7 +1741,7 @@ OC.Contacts = OC.Contacts || { break; case 34: // PageDown case 78: // n - console.log('page down') + console.log('page down'); break; case 79: // o console.log('open contact?'); @@ -1757,7 +1767,7 @@ OC.Contacts = OC.Contacts || { }); - // find all with a title attribute and tipsy them + // find all with a title attribute and tipsy them $('.tooltipped.downwards:not(.onfocus)').tipsy({gravity: 'n'}); $('.tooltipped.upwards:not(.onfocus)').tipsy({gravity: 's'}); $('.tooltipped.rightwards:not(.onfocus)').tipsy({gravity: 'w'}); @@ -1792,8 +1802,8 @@ OC.Contacts = OC.Contacts || { }); $(this).dialog('close'); }, - 'Cancel':function() { - $(this).dialog('close'); + 'Cancel':function() { + $(this).dialog('close'); return false; } }, @@ -1803,12 +1813,12 @@ OC.Contacts = OC.Contacts || { }, open: function(event, ui) { $dlg.find('input').focus(); - }, + } }); }, setAllChecked: function(checked) { var selector = checked ? 'input:checkbox:visible:not(checked)' : 'input:checkbox:visible:checked'; - $.each(self.$contactList.find(selector), function() { + $.each(this.$contactList.find(selector), function() { $(this).prop('checked', checked); }); }, @@ -1847,7 +1857,7 @@ OC.Contacts = OC.Contacts || { var groupprops = { favorite: this.groups.isFavorite(this.currentid), groups: this.groups.categories, - currentgroup: {id:this.currentgroup, name:this.groups.nameById(this.currentgroup)}, + currentgroup: {id:this.currentgroup, name:this.groups.nameById(this.currentgroup)} }; var $contactelem = this.contacts.showContact(this.currentid, groupprops); var self = this; @@ -1879,7 +1889,7 @@ OC.Contacts = OC.Contacts || { OC.notify({ message:t( 'contacts', - 'The file you are trying to upload exceed the maximum size for file uploads on this server.'), + 'The file you are trying to upload exceed the maximum size for file uploads on this server.') }); return; } else { @@ -1898,12 +1908,12 @@ OC.Contacts = OC.Contacts || { }, cloudPhotoSelected:function(id, path) { var self = this; - console.log('cloudPhotoSelected, id', id) + console.log('cloudPhotoSelected, id', id); $.getJSON(OC.filePath('contacts', 'ajax', 'oc_photo.php'), {path: path, id: id},function(jsondata) { if(jsondata.status == 'success') { //alert(jsondata.data.page); - self.editPhoto(jsondata.data.id, jsondata.data.tmp) + self.editPhoto(jsondata.data.id, jsondata.data.tmp); $('#edit_photo_dialog_img').html(jsondata.data.page); } else{ @@ -1917,7 +1927,7 @@ OC.Contacts = OC.Contacts || { {id: id}, function(jsondata) { if(jsondata.status == 'success') { //alert(jsondata.data.page); - self.editPhoto(jsondata.data.id, jsondata.data.tmp) + self.editPhoto(jsondata.data.id, jsondata.data.tmp); $('#edit_photo_dialog_img').html(jsondata.data.page); } else{ @@ -1926,7 +1936,7 @@ OC.Contacts = OC.Contacts || { }); }, editPhoto:function(id, tmpkey) { - console.log('editPhoto', id, tmpkey) + console.log('editPhoto', id, tmpkey); $('.tipsy').remove(); // Simple event handler, called from onChange and onSelect // event handlers, as per the Jcrop invocation above @@ -1961,7 +1971,7 @@ OC.Contacts = OC.Contacts || { maxSize: [399, 399], bgColor: 'black', bgOpacity: .4, - boxWidth: 400, + boxWidth: 400, boxHeight: 400, setSelect: [ 100, 130, 50, 50 ]//, //aspectRatio: 0.8 @@ -2000,7 +2010,7 @@ OC.Contacts = OC.Contacts || { if(jsondata && jsondata.status === 'success') { // load cropped photo. $(document).trigger('status.contact.photoupdated', { - id: jsondata.data.id, + id: jsondata.data.id }); } else { if(!jsondata) { @@ -2016,14 +2026,14 @@ OC.Contacts = OC.Contacts || { $.ajax({ type:'POST', async:false, - url:OC.filePath('contacts', 'ajax', 'addressbook/add.php'), + url:OC.filePath('contacts', 'ajax', 'addressbook/add.php'), data:{ name: data.name, description: data.description }, success:function(jsondata) { if(jsondata.status == 'success') { if(typeof cb === 'function') { cb({ status:'success', - addressbook: jsondata.data.addressbook, + addressbook: jsondata.data.addressbook }); } } else { @@ -2040,7 +2050,7 @@ OC.Contacts = OC.Contacts || { $('body').append('
'); var $dlg = $('#addressbook_dialog').html(data).octemplate({ nameplaceholder: t('contacts', 'Enter name'), - descplaceholder: t('contacts', 'Enter description'), + descplaceholder: t('contacts', 'Enter description') }).dialog({ modal: true, height: 'auto', width: 'auto', title: t('contacts', 'Select addressbook'), @@ -2062,7 +2072,7 @@ OC.Contacts = OC.Contacts || { if(data.status === 'success') { cb({ status:'success', - addressbook:data.addressbook, + addressbook:data.addressbook }); } else { cb({status:'error'}); @@ -2075,7 +2085,7 @@ OC.Contacts = OC.Contacts || { if(typeof cb === 'function') { cb({ status:'success', - addressbook:self.contacts.addressbooks[parseInt(aid)], + addressbook:self.contacts.addressbooks[parseInt(aid)] }); } $(this).dialog('close'); @@ -2100,7 +2110,7 @@ OC.Contacts = OC.Contacts || { || book.permissions & OC.PERMISSION_DELETE)) { var row = '' + '' - + '{description}' + + '{description}'; var $row = $(row).octemplate({ id:book.id, displayname:book.displayname, @@ -2113,12 +2123,12 @@ OC.Contacts = OC.Contacts || { $lastrow.find('input.name,input.desc').on('focus', function(e) { $lastrow.find('input[type="radio"]').prop('checked', true); }); - }, + } }); }).error(function() { OC.notify({message: t('contacts', 'Network or server error. Please inform administrator.')}); }); - }, + } }; (function( $ ) { diff --git a/js/contacts.js b/js/contacts.js index 92006244..b143282c 100644 --- a/js/contacts.js +++ b/js/contacts.js @@ -23,15 +23,16 @@ OC.Contacts = OC.Contacts || {}; this.$fullTemplate = fulltemplate; this.detailTemplates = detailtemplates; + this.undoQueue = []; this.multi_properties = ['EMAIL', 'TEL', 'IMPP', 'ADR', 'URL']; - } + }; Contact.prototype.showActions = function(act) { this.$footer.children().hide(); if(act && act.length > 0) { this.$footer.children('.'+act.join(',.')).show(); } - } + }; Contact.prototype.setAsSaving = function(obj, state) { if(!obj) { @@ -44,10 +45,35 @@ OC.Contacts = OC.Contacts || {}; } else { $(obj).removeClass('loading'); }*/ - } + }; + Contact.prototype.pushToUndo = function(params) { + // Check if the same property has been changed before + // and update it's checksum if so. + if(typeof params.oldchecksum !== 'undefined') { + $.each(this.undoQueue, function(idx, item) { + if(item.checksum === params.oldchecksum) { + item.checksum = params.newchecksum; + if(params.action === 'delete') { + item.action = 'delete'; + } + return false; // Break loop + } + }); + } + this.undoQueue.push({ + action:params.action, + name: params.name, + checksum: params.newchecksum, + newvalue: params.newvalue, + oldvalue: params.oldvalue + }); + console.log('undoQueue', this.undoQueue); + } + Contact.prototype.addProperty = function($option, name) { console.log('Contact.addProperty', name) + var $elem; switch(name) { case 'NICKNAME': case 'TITLE': @@ -82,7 +108,15 @@ OC.Contacts = OC.Contacts || {}; $elem.find('input.value').addClass('new'); break; } - } + + if($elem) { + $elem.find('select.type[name="parameters[TYPE][]"]') + .combobox({ + singleclick: true, + classes: ['propertytype', 'float', 'label'], + }); + } + }; Contact.prototype.deleteProperty = function(params) { var obj = params.obj; @@ -109,7 +143,7 @@ OC.Contacts = OC.Contacts || {}; if(!jsondata) { $(document).trigger('status.contact.error', { status: 'error', - message: t('contacts', 'Network or server error. Please inform administrator.'), + message: t('contacts', 'Network or server error. Please inform administrator.') }); self.setAsSaving(obj, false); return false; @@ -119,6 +153,12 @@ OC.Contacts = OC.Contacts || {}; if(self.multi_properties.indexOf(element) !== -1) { // First find out if an existing element by looking for checksum var checksum = self.checksumFor(obj); + self.pushToUndo({ + action:'delete', + name: element, + oldchecksum: self.checksumFor(obj), + newvalue: self.valueFor(obj) + }); if(checksum) { for(var i in self.data[element]) { if(self.data[element][i].checksum === checksum) { @@ -130,22 +170,31 @@ OC.Contacts = OC.Contacts || {}; } $container.remove(); } else { + self.pushToUndo({ + action:'delete', + name: element, + newvalue: $container.find('input.value').val() + }); self.setAsSaving(obj, false); self.$fullelem.find('[data-element="' + element.toLowerCase() + '"]').hide(); $container.find('input.value').val(''); self.$addMenu.find('option[value="' + element.toUpperCase() + '"]').prop('disabled', false); } + $(document).trigger('status.contact.updated', { + property: element, + contact: self + }); return true; } else { $(document).trigger('status.contact.error', { status: 'error', - message: jsondata.data.message, + message: jsondata.data.message }); self.setAsSaving(obj, false); return false; } },'json'); - } + }; /** * @brief Act on change of a property. @@ -192,7 +241,7 @@ OC.Contacts = OC.Contacts || {}; if(!jsondata) { $(document).trigger('status.contact.error', { status: 'error', - message: t('contacts', 'Network or server error. Please inform administrator.'), + message: t('contacts', 'Network or server error. Please inform administrator.') }); $(obj).addClass('error'); self.setAsSaving(obj, false); @@ -205,24 +254,40 @@ OC.Contacts = OC.Contacts || {}; if(self.multi_properties.indexOf(element) !== -1) { // First find out if an existing element by looking for checksum var checksum = self.checksumFor(obj); - if(checksum) { - for(var i in self.data[element]) { - if(self.data[element][i].checksum === checksum) { + var value = self.valueFor(obj); + var parameters = self.parametersFor(obj); + if(checksum && checksum !== 'new') { + self.pushToUndo({ + action:'save', + name: element, + newchecksum: jsondata.data.checksum, + oldchecksum: checksum, + newvalue: value, + oldvalue: obj.defaultValue + }); + $.each(self.data[element], function(i, el) { + if(el.checksum === checksum) { self.data[element][i] = { name: element, - value: self.valueFor(obj), - parameters: self.parametersFor(obj), - checksum: jsondata.data.checksum, - } - break; + value: value, + parameters: parameters, + checksum: jsondata.data.checksum + }; + return false; } - } + }); } else { $(obj).removeClass('new'); + self.pushToUndo({ + action:'add', + name: element, + newchecksum: jsondata.data.checksum, + newvalue: value, + }); self.data[element].push({ name: element, - value: self.valueFor(obj), - parameters: self.parametersFor(obj), + value: value, + parameters: parameters, checksum: jsondata.data.checksum, }); } @@ -230,17 +295,20 @@ OC.Contacts = OC.Contacts || {}; } else { // Save value and parameters internally var value = obj ? self.valueFor(obj) : params.value; + self.pushToUndo({ + action: ((obj && obj.defaultValue) || self.data[element].length) ? 'save' : 'add', // FIXME + name: element, + newvalue: value, + }); switch(element) { case 'CATEGORIES': // We deal with this in addToGroup() break; case 'FN': if(!self.data.FN || !self.data.FN.length) { - self.data.FN = [{name:'FN', value:'', parameters:[]}] + self.data.FN = [{name:'FN', value:'', parameters:[]}]; } self.data.FN[0]['value'] = value; - // Update the list element - self.$listelem.find('.nametext').text(value); var nempty = true; if(!self.data.N) { // TODO: Maybe add a method for constructing new elements? @@ -272,10 +340,6 @@ OC.Contacts = OC.Contacts || {}; } , 500); } - $(document).trigger('status.contact.renamed', { - id: self.id, - contact: self, - }); break; case 'N': if(!utils.isArray(value)) { @@ -295,7 +359,7 @@ OC.Contacts = OC.Contacts || {}; name: element, value: value, parameters: self.parametersFor(obj), - checksum: jsondata.data.checksum, + checksum: jsondata.data.checksum }; break; default: @@ -303,25 +367,29 @@ OC.Contacts = OC.Contacts || {}; } } self.setAsSaving(obj, false); + $(document).trigger('status.contact.updated', { + property: element, + contact: self + }); return true; } else { $(document).trigger('status.contact.error', { status: 'error', - message: jsondata.data.message, + message: jsondata.data.message }); self.setAsSaving(obj, false); return false; } },'json'); - } + }; /** * Hide contact list element. */ Contact.prototype.hide = function() { this.getListItemElement().hide(); - } - + }; + /** * Remove any open contact from the DOM. */ @@ -333,7 +401,7 @@ OC.Contacts = OC.Contacts || {}; } else { return false; } - } + }; /** * Remove any open contact from the DOM and detach it's list @@ -348,7 +416,7 @@ OC.Contacts = OC.Contacts || {}; this.$listelem.detach(); return this; } - } + }; /** * Set a contacts list element as (un)checked @@ -359,7 +427,7 @@ OC.Contacts = OC.Contacts || {}; this.$listelem.find('input:checkbox').prop('checked', checked); return this; } - } + }; /** * Set a contact to en/disabled depending on its permissions. @@ -376,13 +444,13 @@ OC.Contacts = OC.Contacts || {}; $(this).prop('disabled', !enabled); }); $(document).trigger('status.contact.enabled', enabled); - } + }; /** * Add a contact from data store and remove it from the DOM * @params params. An object which can contain the optional properties: - * aid: The id of the addressbook to add the contact to. Per default it will be added to the first. - * fn: The formatted name of the contact. + * aid: The id of the addressbook to add the contact to. Per default it will be added to the first. + * fn: The formatted name of the contact. * @param cb Optional callback function which * @returns The callback gets an object as argument with a variable 'status' of either 'success' * or 'error'. On success the 'data' property of that object contains the contact id as 'id', the @@ -395,7 +463,7 @@ OC.Contacts = OC.Contacts || {}; if(!jsondata) { $(document).trigger('status.contact.error', { status: 'error', - message: t('contacts', 'Network or server error. Please inform administrator.'), + message: t('contacts', 'Network or server error. Please inform administrator.') }); return false; } @@ -404,7 +472,7 @@ OC.Contacts = OC.Contacts || {}; self.access.id = parseInt(jsondata.data.aid); self.data = jsondata.data.details; // Add contact to current group - if(self.groupprops && self.groupprops.currentgroup.name !== 'all' + if(self.groupprops && self.groupprops.currentgroup.name !== 'all' && self.groupprops.currentgroup.name !== 'fav') { if(!self.data.CATEGORIES) { self.data.CATEGORIES = [{value:[self.groupprops.currentgroup.name], parameters:[]}]; @@ -413,25 +481,25 @@ OC.Contacts = OC.Contacts || {}; // Tell OC.Contacts to save in backend $(document).trigger('request.contact.addtogroup', { id: self.id, - groupid: self.groupprops.currentgroup.id, + groupid: self.groupprops.currentgroup.id }); } } $(document).trigger('status.contact.added', { id: self.id, - contact: self, + contact: self }); } if(typeof cb == 'function') { cb(jsondata); } }); - } + }; /** * Delete contact from data store and remove it from the DOM * @param cb Optional callback function which * @returns An object with a variable 'status' of either success - * or 'error' + * or 'error' */ Contact.prototype.destroy = function(cb) { var self = this; @@ -460,7 +528,7 @@ OC.Contacts = OC.Contacts || {}; cb(retval); } }); - } + }; Contact.prototype.queryStringFor = function(obj) { var q = 'id=' + this.id; @@ -483,23 +551,23 @@ OC.Contacts = OC.Contacts || {}; } } return q; - } + }; Contact.prototype.propertyContainerFor = function(obj) { return $(obj).hasClass('propertycontainer') ? $(obj) : $(obj).parents('.propertycontainer').first(); - } + }; Contact.prototype.checksumFor = function(obj) { return this.propertyContainerFor(obj).data('checksum'); - } + }; Contact.prototype.valueFor = function(obj) { var $container = this.propertyContainerFor(obj); - console.assert($container.length > 0, 'Couldn\'t find container for ' + $(obj)) - return $container.is('input') - ? $container.val() + console.assert($container.length > 0, 'Couldn\'t find container for ' + $(obj)); + return $container.is('input') + ? $container.val() : (function() { var $elem = $container.find('textarea.value,input.value:not(:checkbox)'); console.assert($elem.length > 0, 'Couldn\'t find value for ' + $container.data('element')); @@ -513,7 +581,7 @@ OC.Contacts = OC.Contacts || {}; return retval; } })(); - } + }; Contact.prototype.parametersFor = function(obj, asText) { var parameters = []; @@ -536,12 +604,12 @@ OC.Contacts = OC.Contacts || {}; parameters[paramname].push(val); }); return parameters; - } + }; Contact.prototype.propertyTypeFor = function(obj) { var ptype = this.propertyContainerFor(obj).data('element'); return ptype ? ptype.toUpperCase() : null; - } + }; /** * Render the list item @@ -555,7 +623,7 @@ OC.Contacts = OC.Contacts || {}; tel: this.getPreferredValue('TEL', ''), adr: this.getPreferredValue('ADR', []).clean('').join(', '), categories: this.getPreferredValue('CATEGORIES', []) - .clean('').join(' / '), + .clean('').join(' / ') }); if(this.access.owner !== OC.currentUser && !(this.access.permissions & OC.PERMISSION_UPDATE @@ -563,7 +631,7 @@ OC.Contacts = OC.Contacts || {}; this.$listelem.find('input:checkbox').prop('disabled', true).css('opacity', '0'); } return this.$listelem; - } + }; /** * Render the full contact @@ -588,13 +656,13 @@ OC.Contacts = OC.Contacts || {}; $.datepicker.parseDate('yy-mm-dd', this.getPreferredValue('BDAY', '').substring(0, 10))) : '', - note: this.getPreferredValue('NOTE', ''), + note: this.getPreferredValue('NOTE', '') } : {id:'', favorite:'', name:'', nickname:'', title:'', org:'', bday:'', note:'', n0:'', n1:'', n2:'', n3:'', n4:''}; this.$fullelem = this.$fullTemplate.octemplate(values).data('contactobject', this); this.$footer = this.$fullelem.find('footer'); - + this.$fullelem.find('.tooltipped.rightwards.onfocus').tipsy({trigger: 'focus', gravity: 'w'}); this.$fullelem.on('submit', function() { return false; @@ -625,12 +693,12 @@ OC.Contacts = OC.Contacts || {}; $editor.toggle('blind'); $('body').unbind('click', bodyListener); } - } + }; $editor.toggle('blind', function() { $('body').bind('click', bodyListener); }); }); - + this.$fullelem.on('click keydown', '.delete', function(event) { $('.tipsy').remove(); if(wrongKey(event)) { @@ -646,32 +714,36 @@ OC.Contacts = OC.Contacts || {}; } if($(this).is('.close') || $(this).is('.cancel')) { $(document).trigger('request.contact.close', { - id: self.id, + id: self.id }); } else if($(this).is('.export')) { $(document).trigger('request.contact.export', { - id: self.id, + id: self.id }); } else if($(this).is('.delete')) { $(document).trigger('request.contact.delete', { - id: self.id, + id: self.id }); } return false; }); this.$fullelem.on('keypress', '.value,.parameter', function(event) { if(event.keyCode === 13 && $(this).is('input')) { - console.log('Enter'); $(this).trigger('change'); + // Prevent a second save on blur. + this.defaultValue = this.value; return false; } else if(event.keyCode === 27) { $(document).trigger('request.contact.close', { - id: self.id, + id: self.id }); } }); - + this.$fullelem.on('change', '.value,.parameter', function(event) { + if(this.value === this.defaultValue) { + return; + } self.saveProperty({obj:event.target}); }); @@ -681,7 +753,7 @@ OC.Contacts = OC.Contacts || {}; }); this.$fullelem.find('.favorite').on('click', function () { var state = $(this).hasClass('active'); - if(!this.data) { + if(!self.data) { return; } if(state) { @@ -691,7 +763,7 @@ OC.Contacts = OC.Contacts || {}; } $(document).trigger('request.contact.setasfavorite', { id: self.id, - state: !state, + state: !state }); }); this.loadPhoto(); @@ -757,7 +829,7 @@ OC.Contacts = OC.Contacts || {}; //console.log('param', param); if(param.toUpperCase() == 'PREF') { var $cb = $property.find('input[type="checkbox"]'); - $cb.attr('checked', 'checked') + $cb.attr('checked', 'checked'); meta.push($cb.attr('title')); } else if(param.toUpperCase() == 'TYPE') { @@ -798,7 +870,7 @@ OC.Contacts = OC.Contacts || {}; $property.find('select.type[name="parameters[TYPE][]"]') .combobox({ singleclick: true, - classes: ['propertytype', 'float', 'label'], + classes: ['propertytype', 'float', 'label'] }); } $list.append($property); @@ -810,19 +882,19 @@ OC.Contacts = OC.Contacts || {}; && !(this.access.permissions & OC.PERMISSION_UPDATE || this.access.permissions & OC.PERMISSION_DELETE)) { this.setEnabled(false); - this.showActions(['close']); + this.showActions(['close', 'export']); } else { this.setEnabled(true); this.showActions(['close', 'add', 'export', 'delete']); } return this.$fullelem; - } + }; Contact.prototype.isEditable = function() { return ((this.access.owner === OC.currentUser) || (this.access.permissions & OC.PERMISSION_UPDATE || this.access.permissions & OC.PERMISSION_DELETE)); - } + }; /** * Render a simple property. Used for EMAIL and TEL. @@ -837,7 +909,7 @@ OC.Contacts = OC.Contacts || {}; ? { value: property.value, checksum: property.checksum } : { value: '', checksum: 'new' }; return this.detailTemplates[name].octemplate(values); - } + }; /** * Render an ADR (address) property. @@ -865,7 +937,7 @@ OC.Contacts = OC.Contacts || {}; adr4: property.value[4] || '', adr5: property.value[5] || '', adr6: property.value[6] || '', - idx: idx, + idx: idx } : {value:'', checksum:'new', adr0:'', adr1:'', adr2:'', adr3:'', adr4:'', adr5:'', adr6:'', idx: idx}; var $elem = this.detailTemplates['adr'].octemplate(values); @@ -889,7 +961,7 @@ OC.Contacts = OC.Contacts || {}; $('body').unbind('click', bodyListener); }); } - } + }; $viewer.slideUp(); $editor.toggle('blind', function() { $('body').bind('click', bodyListener); @@ -914,7 +986,7 @@ OC.Contacts = OC.Contacts || {}; label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName, value: item.name, country: item.countryName - } + }; })); } }); @@ -924,7 +996,7 @@ OC.Contacts = OC.Contacts || {}; if(ui.item && $elem.find('.value.country').val().trim().length == 0) { $elem.find('.value.country').val(ui.item.country); } - }, + } }); $elem.find('.value.country') .autocomplete({ @@ -946,15 +1018,15 @@ OC.Contacts = OC.Contacts || {}; return { label: item.name, value: item.name - } + }; })); } }); }, - minLength: 2, + minLength: 2 }); return $elem; - } + }; /** * Render an IMPP (Instant Messaging) property. @@ -967,10 +1039,10 @@ OC.Contacts = OC.Contacts || {}; } var values = property ? { value: property.value, - checksum: property.checksum, + checksum: property.checksum } : {value: '', checksum: 'new'}; return this.detailTemplates['impp'].octemplate(values); - } + }; /** * Render the PHOTO property. @@ -983,7 +1055,7 @@ OC.Contacts = OC.Contacts || {}; this.$photowrapper.addClass('loading').addClass('wait'); var $phototools = this.$fullelem.find('#phototools'); delete this.photo; - $('img.contactphoto').remove() + $('img.contactphoto').remove(); this.photo = new Image(); $(this.photo).load(function () { $(this).addClass('contactphoto'); @@ -1012,17 +1084,17 @@ OC.Contacts = OC.Contacts || {}; $phototools.find('.edit').on('click', function() { $(document).trigger('request.edit.contactphoto', { - id: self.id, + id: self.id }); }); $phototools.find('.cloud').on('click', function() { $(document).trigger('request.select.contactphoto.fromcloud', { - id: self.id, + id: self.id }); }); $phototools.find('.upload').on('click', function() { $(document).trigger('request.select.contactphoto.fromlocal', { - id: self.id, + id: self.id }); }); if(this.data && this.data.PHOTO) { @@ -1039,7 +1111,7 @@ OC.Contacts = OC.Contacts || {}; .css('background', 'url(' + OC.filePath('', '', 'remote.php')+'/contactthumbnail?id='+self.id+refreshstr + ')'); }); } - } + }; /** * Get the jquery element associated with this object @@ -1049,7 +1121,7 @@ OC.Contacts = OC.Contacts || {}; this.renderListItem(); } return this.$listelem; - } + }; /** * Get the preferred value for a property. @@ -1079,7 +1151,7 @@ OC.Contacts = OC.Contacts || {}; }); } return pref; - } + }; /** * Returns true/false depending on the contact being in the @@ -1097,9 +1169,9 @@ OC.Contacts = OC.Contacts || {}; if(typeof categories[i] === 'string' && (name.toLowerCase() === categories[i].toLowerCase())) { return true; } - }; + } return false; - } + }; /** * Add this contact to a group @@ -1108,7 +1180,7 @@ OC.Contacts = OC.Contacts || {}; Contact.prototype.addToGroup = function(name) { console.log('addToGroup', name); if(!this.data.CATEGORIES) { - this.data.CATEGORIES = [{value:[name]},]; + this.data.CATEGORIES = [{value:[name]}]; } else { if(this.inGroup(name)) { return; @@ -1120,7 +1192,7 @@ OC.Contacts = OC.Contacts || {}; } } this.saveProperty({name:'CATEGORIES', value:this.data.CATEGORIES[0].value.join(',') }); - } + }; /** * Remove this contact to a group @@ -1151,7 +1223,7 @@ OC.Contacts = OC.Contacts || {}; } } this.saveProperty({name:'CATEGORIES', value:this.data.CATEGORIES[0].value.join(',') }); - } + }; Contact.prototype.setCurrent = function(on) { if(on) { @@ -1162,9 +1234,9 @@ OC.Contacts = OC.Contacts || {}; $(document).trigger('status.contact.currentlistitem', { id: this.id, pos: Math.round(this.$listelem.position().top), - height: Math.round(this.$listelem.height()), + height: Math.round(this.$listelem.height()) }); - } + }; Contact.prototype.next = function() { var $next = this.$listelem.next('tr'); @@ -1174,10 +1246,10 @@ OC.Contacts = OC.Contacts || {}; $(document).trigger('status.contact.currentlistitem', { id: parseInt($next.data('id')), pos: Math.round($next.position().top), - height: Math.round($next.height()), + height: Math.round($next.height()) }); } - } + }; Contact.prototype.prev = function() { var $prev = this.$listelem.prev('tr'); @@ -1187,10 +1259,10 @@ OC.Contacts = OC.Contacts || {}; $(document).trigger('status.contact.currentlistitem', { id: parseInt($prev.data('id')), pos: Math.round($prev.position().top), - height: Math.round($prev.height()), + height: Math.round($prev.height()) }); } - } + }; var ContactList = function(contactlist, contactlistitemtemplate, contactfulltemplate, contactdetailtemplates) { //console.log('ContactList', contactlist, contactlistitemtemplate, contactfulltemplate, contactdetailtemplates); @@ -1209,10 +1281,13 @@ OC.Contacts = OC.Contacts || {}; self.insertContact(data.contact.renderListItem()); }); - $(document).bind('status.contact.renamed', function(e, data) { - self.insertContact(data.contact.getListItemElement().detach()); + $(document).bind('status.contact.updated', function(e, data) { + if(['FN', 'EMAIL', 'TEL', 'ADR', 'CATEGORIES'].indexOf(data.property) !== -1) { + data.contact.getListItemElement().remove(); + self.insertContact(self.contacts[parseInt(data.contact.id)].renderListItem()); + } }); - } + }; /** * Show/hide contacts belonging to an addressbook. @@ -1230,7 +1305,7 @@ OC.Contacts = OC.Contacts || {}; this.contacts[contact].getListItemElement().hide(); } } - } + }; /** * Show/hide contacts belonging to shared addressbooks. @@ -1247,7 +1322,7 @@ OC.Contacts = OC.Contacts || {}; } } } - } + }; /** * Show contacts in list @@ -1272,7 +1347,7 @@ OC.Contacts = OC.Contacts || {}; this.contacts[contact].getListItemElement().show(); } } - } + }; ContactList.prototype.contactPos = function(id) { if(!id) { @@ -1282,15 +1357,15 @@ OC.Contacts = OC.Contacts || {}; var $elem = this.contacts[parseInt(id)].getListItemElement(); var pos = $elem.offset().top - this.$contactList.offset().top + this.$contactList.scrollTop(); return pos; - } + }; ContactList.prototype.hideContact = function(id) { this.contacts[parseInt(id)].hide(); - } + }; ContactList.prototype.closeContact = function(id) { this.contacts[parseInt(id)].close(); - } + }; /** * Returns a Contact object by searching for its id @@ -1312,7 +1387,7 @@ OC.Contacts = OC.Contacts || {}; } else if(utils.isArray(id)) { $.extend(this.deletionQueue, id); } else { - throw { name: 'WrongParameterType', message: 'ContactList.delayedDelete only accept integers or arrays.'} + throw { name: 'WrongParameterType', message: 'ContactList.delayedDelete only accept integers or arrays.'}; } $.each(this.deletionQueue, function(idx, id) { self.contacts[id].detach().setChecked(false); @@ -1326,7 +1401,7 @@ OC.Contacts = OC.Contacts || {}; e.returnValue = String(warn); } return warn; - } + }; } if(this.$contactList.find('tr:visible').length === 0) { $(document).trigger('status.visiblecontacts'); @@ -1350,7 +1425,7 @@ OC.Contacts = OC.Contacts || {}; window.onbeforeunload = null; } }); - } + }; /** * Delete a contact with this id @@ -1379,7 +1454,7 @@ OC.Contacts = OC.Contacts || {}; if(response.status === 'success') { delete self.contacts[id]; $(document).trigger('status.contact.deleted', { - id: id, + id: id }); self.length -= 1; if(self.length === 0) { @@ -1389,7 +1464,7 @@ OC.Contacts = OC.Contacts || {}; OC.notify({message:response.message}); } }); - } + }; /** * Opens the contact with this id in edit mode @@ -1399,7 +1474,7 @@ OC.Contacts = OC.Contacts || {}; ContactList.prototype.showContact = function(id, props) { console.assert(typeof id === 'number', 'ContactList.showContact called with a non-number'); this.currentContact = id; - console.log('Contacts.showContact', id, this.contacts[this.currentContact], this.contacts) + console.log('Contacts.showContact', id, this.contacts[this.currentContact], this.contacts); return this.contacts[this.currentContact].renderContact(props); }; @@ -1413,10 +1488,10 @@ OC.Contacts = OC.Contacts || {}; revert: 'invalid', //containment: '#content', opacity: 0.8, helper: 'clone', - zIndex: 1000, + zIndex: 1000 }); var name = $contact.find('.nametext').text().toLowerCase(); - var added = false + var added = false; this.$contactList.find('tr').each(function() { if ($(this).find('.nametext').text().toLowerCase().localeCompare(name) > 0) { $(this).before($contact); @@ -1429,7 +1504,7 @@ OC.Contacts = OC.Contacts || {}; } $contact.show(); return $contact; - } + }; /** * Add contact @@ -1450,7 +1525,7 @@ OC.Contacts = OC.Contacts || {}; this.contacts[this.currentContact].close(); } return contact.renderContact(props); - } + }; /** * Get contacts selected in list @@ -1464,17 +1539,17 @@ OC.Contacts = OC.Contacts || {}; contacts.push(parseInt($(b).parents('tr').first().data('id'))); }); return contacts; - } + }; ContactList.prototype.setCurrent = function(id, deselect_other) { - self = this; + var self = this; if(deselect_other === true) { $.each(this.contacts, function(contact) { self.contacts[contact].setCurrent(false); }); } this.contacts[parseInt(id)].setCurrent(true); - } + }; // Should only be neccesary with progressive loading, but it's damn fast, so... ;) ContactList.prototype.doSort = function() { @@ -1485,10 +1560,18 @@ OC.Contacts = OC.Contacts || {}; return $(a).find('td.name').text().toUpperCase().localeCompare($(b).find('td.name').text().toUpperCase()); }); + var items = []; $.each(rows, function(index, row) { - self.$contactList.append(row); + items.push(row); + if(items.length === 100) { + self.$contactList.append(items); + items = []; + } }); - } + if(items.length > 0) { + self.$contactList.append(items); + } + }; /** * Save addressbook data @@ -1496,8 +1579,8 @@ OC.Contacts = OC.Contacts || {}; */ ContactList.prototype.unsetAddressbook = function(id) { delete this.addressbooks[id]; - } - + }; + /** * Save addressbook data * @param object book @@ -1510,9 +1593,9 @@ OC.Contacts = OC.Contacts || {}; id: parseInt(book.id), displayname: book.displayname, description: book.description, - active: Boolean(parseInt(book.active)), + active: Boolean(parseInt(book.active)) }; - } + }; /** * Load contacts * @param int offset @@ -1527,6 +1610,7 @@ OC.Contacts = OC.Contacts || {}; $.each(jsondata.data.addressbooks, function(i, book) { self.setAddressbook(book); }); + var items = []; $.each(jsondata.data.contacts, function(c, contact) { self.contacts[parseInt(contact.id)] = new Contact( @@ -1540,6 +1624,7 @@ OC.Contacts = OC.Contacts || {}; ); self.length +=1; var $item = self.contacts[parseInt(contact.id)].renderListItem(); + items.push($item.get(0)); $item.draggable({ distance: 10, revert: 'invalid', @@ -1547,10 +1632,18 @@ OC.Contacts = OC.Contacts || {}; opacity: 0.8, helper: 'clone', zIndex: 1000, }); - self.$contactList.append($item); - //self.insertContact(item); + if(items.length === 100) { + self.$contactList.append(items); + items = []; + } }); - self.doSort(); + if(items.length > 0) { + self.$contactList.append(items); + } + setTimeout(function() { + self.doSort(); + } + , 2000); $(document).trigger('status.contacts.loaded', { status: true, numcontacts: jsondata.data.contacts.length diff --git a/js/loader.js b/js/loader.js index ce869a70..f3c12caa 100644 --- a/js/loader.js +++ b/js/loader.js @@ -75,7 +75,7 @@ Contacts_Import={ } }); } -} +}; var openContact = function(id) { if(typeof OC.Contacts !== 'undefined') { @@ -83,7 +83,7 @@ var openContact = function(id) { } else { window.location.href = OC.linkTo('contacts', 'index.php') + '?id=' + id; } -} +}; $(document).ready(function(){ if(typeof FileActions !== 'undefined'){ @@ -91,5 +91,5 @@ $(document).ready(function(){ FileActions.setDefault('text/vcard','importaddressbook'); FileActions.register('text/x-vcard','importaddressbook', OC.PERMISSION_READ, '', Contacts_Import.importdialog); FileActions.setDefault('text/x-vcard','importaddressbook'); - }; + } }); \ No newline at end of file diff --git a/js/modernizr.custom.js b/js/modernizr.custom.js new file mode 100644 index 00000000..523a0833 --- /dev/null +++ b/js/modernizr.custom.js @@ -0,0 +1,814 @@ +/* Modernizr 2.6.2 (Custom Build) | MIT & BSD + * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-flexboxlegacy-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-canvas-draganddrop-audio-video-input-inputtypes-localstorage-sessionstorage-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-elem_track-load + */ +; + + + +window.Modernizr = (function( window, document, undefined ) { + + var version = '2.6.2', + + Modernizr = {}, + + enableClasses = true, + + docElement = document.documentElement, + + mod = 'modernizr', + modElem = document.createElement(mod), + mStyle = modElem.style, + + inputElem = document.createElement('input') , + + smile = ':)', + + toString = {}.toString, + + prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), + + + + omPrefixes = 'Webkit Moz O ms', + + cssomPrefixes = omPrefixes.split(' '), + + domPrefixes = omPrefixes.toLowerCase().split(' '), + + ns = {'svg': 'http://www.w3.org/2000/svg'}, + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + slice = classes.slice, + + featureName, + + + injectElementWithStyles = function( rule, callback, nodes, testnames ) { + + var style, ret, node, docOverflow, + div = document.createElement('div'), + body = document.body, + fakeBody = body || document.createElement('body'); + + if ( parseInt(nodes, 10) ) { + while ( nodes-- ) { + node = document.createElement('div'); + node.id = testnames ? testnames[nodes] : mod + (nodes + 1); + div.appendChild(node); + } + } + + style = ['­',''].join(''); + div.id = mod; + (body ? div : fakeBody).innerHTML += style; + fakeBody.appendChild(div); + if ( !body ) { + fakeBody.style.background = ''; + fakeBody.style.overflow = 'hidden'; + docOverflow = docElement.style.overflow; + docElement.style.overflow = 'hidden'; + docElement.appendChild(fakeBody); + } + + ret = callback(div, rule); + if ( !body ) { + fakeBody.parentNode.removeChild(fakeBody); + docElement.style.overflow = docOverflow; + } else { + div.parentNode.removeChild(div); + } + + return !!ret; + + }, + + testMediaQuery = function( mq ) { + + var matchMedia = window.matchMedia || window.msMatchMedia; + if ( matchMedia ) { + return matchMedia(mq).matches; + } + + var bool; + + injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) { + bool = (window.getComputedStyle ? + getComputedStyle(node, null) : + node.currentStyle)['position'] == 'absolute'; + }); + + return bool; + + }, + + + isEventSupported = (function() { + + var TAGNAMES = { + 'select': 'input', 'change': 'input', + 'submit': 'form', 'reset': 'form', + 'error': 'img', 'load': 'img', 'abort': 'img' + }; + + function isEventSupported( eventName, element ) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + var isSupported = eventName in element; + + if ( !isSupported ) { + if ( !element.setAttribute ) { + element = document.createElement('div'); + } + if ( element.setAttribute && element.removeAttribute ) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + if ( !is(element[eventName], 'undefined') ) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(), + + + _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp; + + if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { + hasOwnProp = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProp = function (object, property) { + return ((property in object) && is(object.constructor.prototype[property], 'undefined')); + }; + } + + + if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { + + var target = this; + + if (typeof target != "function") { + throw new TypeError(); + } + + var args = slice.call(arguments, 1), + bound = function () { + + if (this instanceof bound) { + + var F = function(){}; + F.prototype = target.prototype; + var self = new F(); + + var result = target.apply( + self, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return self; + + } else { + + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + + return bound; + }; + } + + function setCss( str ) { + mStyle.cssText = str; + } + + function setCssAll( str1, str2 ) { + return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + function is( obj, type ) { + return typeof obj === type; + } + + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + function testProps( props, prefixed ) { + for ( var i in props ) { + var prop = props[i]; + if ( !contains(prop, "-") && mStyle[prop] !== undefined ) { + return prefixed == 'pfx' ? prop : true; + } + } + return false; + } + + function testDOMProps( props, obj, elem ) { + for ( var i in props ) { + var item = obj[props[i]]; + if ( item !== undefined) { + + if (elem === false) return props[i]; + + if (is(item, 'function')){ + return item.bind(elem || obj); + } + + return item; + } + } + return false; + } + + function testPropsAll( prop, prefixed, elem ) { + + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), + props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); + + if(is(prefixed, "string") || is(prefixed, "undefined")) { + return testProps(props, prefixed); + + } else { + props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); + return testDOMProps(props, prefixed, elem); + } + } tests['flexbox'] = function() { + return testPropsAll('flexWrap'); + }; + + + tests['flexboxlegacy'] = function() { + return testPropsAll('boxDirection'); + }; + + + tests['canvas'] = function() { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }; tests['webgl'] = function() { + return !!window.WebGLRenderingContext; + }; + + + tests['touch'] = function() { + var bool; + + if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { + bool = true; + } else { + injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) { + bool = node.offsetTop === 9; + }); + } + + return bool; + }; + + + + tests['geolocation'] = function() { + return 'geolocation' in navigator; + }; + + + + tests['draganddrop'] = function() { + var div = document.createElement('div'); + return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div); + }; + + + + tests['rgba'] = function() { + setCss('background-color:rgba(150,255,150,.5)'); + + return contains(mStyle.backgroundColor, 'rgba'); + }; + + tests['hsla'] = function() { + setCss('background-color:hsla(120,40%,100%,.5)'); + + return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla'); + }; + + tests['multiplebgs'] = function() { + setCss('background:url(https://),url(https://),red url(https://)'); + + return (/(url\s*\(.*?){3}/).test(mStyle.background); + }; tests['backgroundsize'] = function() { + return testPropsAll('backgroundSize'); + }; + + tests['borderimage'] = function() { + return testPropsAll('borderImage'); + }; + + + + tests['borderradius'] = function() { + return testPropsAll('borderRadius'); + }; + + tests['boxshadow'] = function() { + return testPropsAll('boxShadow'); + }; + + tests['textshadow'] = function() { + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + setCssAll('opacity:.55'); + + return (/^0.55$/).test(mStyle.opacity); + }; + + + tests['cssanimations'] = function() { + return testPropsAll('animationName'); + }; + + + tests['csscolumns'] = function() { + return testPropsAll('columnCount'); + }; + + + tests['cssgradients'] = function() { + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + setCss( + (str1 + '-webkit- '.split(' ').join(str2 + str1) + + prefixes.join(str3 + str1)).slice(0, -str1.length) + ); + + return contains(mStyle.backgroundImage, 'gradient'); + }; + + + tests['cssreflections'] = function() { + return testPropsAll('boxReflect'); + }; + + + tests['csstransforms'] = function() { + return !!testPropsAll('transform'); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!testPropsAll('perspective'); + + if ( ret && 'webkitPerspective' in docElement.style ) { + + injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) { + ret = node.offsetLeft === 9 && node.offsetHeight === 3; + }); + } + return ret; + }; + + + tests['csstransitions'] = function() { + return testPropsAll('transition'); + }; + + + + tests['fontface'] = function() { + var bool; + + injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) { + var style = document.getElementById('smodernizr'), + sheet = style.sheet || style.styleSheet, + cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : ''; + + bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0; + }); + + return bool; + }; + + tests['generatedcontent'] = function() { + var bool; + + injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) { + bool = node.offsetHeight >= 3; + }); + + return bool; + }; + tests['video'] = function() { + var elem = document.createElement('video'), + bool = false; + + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,''); + + bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,''); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,''); + } + + } catch(e) { } + + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = false; + + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''); + bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,''); + + bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,''); + bool.m4a = ( elem.canPlayType('audio/x-m4a;') || + elem.canPlayType('audio/aac;')) .replace(/^no$/,''); + } + } catch(e) { } + + return bool; + }; + + + tests['localstorage'] = function() { + try { + localStorage.setItem(mod, mod); + localStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + sessionStorage.setItem(mod, mod); + sessionStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + tests['svg'] = function() { + return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; + }; + + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + tests['smil'] = function() { + return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); + }; + + + tests['svgclippaths'] = function() { + return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); + }; + + function webforms() { + Modernizr['input'] = (function( props ) { + for ( var i = 0, len = props.length; i < len; i++ ) { + attrs[ props[i] ] = !!(props[i] in inputElem); + } + if (attrs.list){ + attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement); + } + return attrs; + })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); + Modernizr['inputtypes'] = (function(props) { + + for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { + + inputElem.setAttribute('type', inputElemType = props[i]); + bool = inputElem.type !== 'text'; + + if ( bool ) { + + inputElem.value = smile; + inputElem.style.cssText = 'position:absolute;visibility:hidden;'; + + if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { + + docElement.appendChild(inputElem); + defaultView = document.defaultView; + + bool = defaultView.getComputedStyle && + defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && + (inputElem.offsetHeight !== 0); + + docElement.removeChild(inputElem); + + } else if ( /^(search|tel)$/.test(inputElemType) ){ + } else if ( /^(url|email)$/.test(inputElemType) ) { + bool = inputElem.checkValidity && inputElem.checkValidity() === false; + + } else { + bool = inputElem.value != smile; + } + } + + inputs[ props[i] ] = !!bool; + } + return inputs; + })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); + } + for ( var feature in tests ) { + if ( hasOwnProp(tests, feature) ) { + featureName = feature.toLowerCase(); + Modernizr[featureName] = tests[feature](); + + classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); + } + } + + Modernizr.input || webforms(); + + + Modernizr.addTest = function ( feature, test ) { + if ( typeof feature == 'object' ) { + for ( var key in feature ) { + if ( hasOwnProp( feature, key ) ) { + Modernizr.addTest( key, feature[ key ] ); + } + } + } else { + + feature = feature.toLowerCase(); + + if ( Modernizr[feature] !== undefined ) { + return Modernizr; + } + + test = typeof test == 'function' ? test() : test; + + if (typeof enableClasses !== "undefined" && enableClasses) { + docElement.className += ' ' + (test ? '' : 'no-') + feature; + } + Modernizr[feature] = test; + + } + + return Modernizr; + }; + + + setCss(''); + modElem = inputElem = null; + + ;(function(window, document) { + var options = window.html5 || {}; + + var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; + + var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; + + var supportsHtml5Styles; + + var expando = '_html5shiv'; + + var expanID = 0; + + var expandoData = {}; + + var supportsUnknownElements; + + (function() { + try { + var a = document.createElement('a'); + a.innerHTML = ''; + supportsHtml5Styles = ('hidden' in a); + + supportsUnknownElements = a.childNodes.length == 1 || (function() { + (document.createElement)('a'); + var frag = document.createDocumentFragment(); + return ( + typeof frag.cloneNode == 'undefined' || + typeof frag.createDocumentFragment == 'undefined' || + typeof frag.createElement == 'undefined' + ); + }()); + } catch(e) { + supportsHtml5Styles = true; + supportsUnknownElements = true; + } + + }()); function addStyleSheet(ownerDocument, cssText) { + var p = ownerDocument.createElement('p'), + parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; + + p.innerHTML = 'x'; + return parent.insertBefore(p.lastChild, parent.firstChild); + } + + function getElements() { + var elements = html5.elements; + return typeof elements == 'string' ? elements.split(' ') : elements; + } + + function getExpandoData(ownerDocument) { + var data = expandoData[ownerDocument[expando]]; + if (!data) { + data = {}; + expanID++; + ownerDocument[expando] = expanID; + expandoData[expanID] = data; + } + return data; + } + + function createElement(nodeName, ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createElement(nodeName); + } + if (!data) { + data = getExpandoData(ownerDocument); + } + var node; + + if (data.cache[nodeName]) { + node = data.cache[nodeName].cloneNode(); + } else if (saveClones.test(nodeName)) { + node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); + } else { + node = data.createElem(nodeName); + } + + return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node; + } + + function createDocumentFragment(ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createDocumentFragment(); + } + data = data || getExpandoData(ownerDocument); + var clone = data.frag.cloneNode(), + i = 0, + elems = getElements(), + l = elems.length; + for(;i0) { if(self.menuDirection === 'down') { @@ -146,7 +146,7 @@ settings.labels.splice(index,1); } var oldWidth=button.width(); - button.children('span').first().text(settings.labels.length > 0 + button.children('span').first().text(settings.labels.length > 0 ? settings.labels.join(', ') : settings.title); var newOuterWidth=Math.max((button.outerWidth()-2),settings.minOuterWidth)+'px'; @@ -193,7 +193,7 @@ return false; } var li=$(this).parent(); - var val = $(this).val() + var val = $(this).val(); var select=button.parent().next(); if(typeof settings.createCallback === 'function') { var response = settings.createCallback(select, val); @@ -217,7 +217,7 @@ select.append(option); li.prev().children('input').prop('checked', true).trigger('change'); button.parent().data('preventHide',false); - button.children('span').first().text(settings.labels.length > 0 + button.children('span').first().text(settings.labels.length > 0 ? settings.labels.join(', ') : settings.title); if(self.menuDirection === 'up') { @@ -276,7 +276,7 @@ } } }); - + return span; }; })( jQuery ); \ No newline at end of file diff --git a/js/placeholder.polyfill.jquery.js b/js/placeholder.polyfill.jquery.js deleted file mode 100644 index 16969eb8..00000000 --- a/js/placeholder.polyfill.jquery.js +++ /dev/null @@ -1,212 +0,0 @@ -/** -* HTML5 placeholder polyfill -* @requires jQuery - tested with 1.6.2 but might as well work with older versions -* -* code: https://github.com/ginader/HTML5-placeholder-polyfill -* please report issues at: https://github.com/ginader/HTML5-placeholder-polyfill/issues -* -* Copyright (c) 2012 Dirk Ginader (ginader.de) -* Dual licensed under the MIT and GPL licenses: -* http://www.opensource.org/licenses/mit-license.php -* http://www.gnu.org/licenses/gpl.html -* -* Version: 2.0.3 -* -* History: -* * 1.0 initial release -* * 1.1 added support for multiline placeholders in textareas -* * 1.2 Allow label to wrap the input element by noah https://github.com/ginader/HTML5-placeholder-polyfill/pull/1 -* * 1.3 New option to read placeholder to Screenreaders. Turned on by default -* * 1.4 made placeholder more rubust to allow labels being offscreen + added minified version of the 3rd party libs -* * 1.5 emptying the native placeholder to prevent double rendering in Browsers with partial support -* * 1.6 optional reformat when a textarea is being resized - requires http://benalman.com/projects/jquery-resize-plugin/ -* * 1.7 feature detection is now included in the polyfill so you can simply include it without the need for Modernizr -* * 1.8 replacing the HTML5 Boilerplate .visuallyhidden technique with one that still allows the placeholder to be rendered -* * 1.8.1 bugfix for implicit labels -* * 1.9 New option "hideOnFocus" which, if set to false will mimic the behavior of mobile safari and chrome (remove label when typed instead of onfocus) -* * 1.9.1 added reformat event on window resize -* * 1.9.2 more flexible way to "fix" labels that are hidden using clip() thanks to grahambates: https://github.com/ginader/HTML5-placeholder-polyfill/issues/12 -* * 2.0 new easier configuration technique and new options forceApply and AutoInit and support for setters and getters -* * 2.0.1 changed check for empty field so a space character is no longer ignored -* * 2.0.2 allow rerun of the placeholder() to cover generated elements - existing polyfilled placeholder will be repositioned. Fixing: https://github.com/ginader/HTML5-placeholder-polyfill/issues/15 -* * 2.0.3 turn debugging of for production. fix https://github.com/ginader/HTML5-placeholder-polyfill/issues/18 -*/ - -(function($) { - var debug = false, - animId; - function showPlaceholderIfEmpty(input,options) { - if( input.val() === '' ){ - input.data('placeholder').removeClass(options.hideClass); - }else{ - input.data('placeholder').addClass(options.hideClass); - } - } - function hidePlaceholder(input,options){ - input.data('placeholder').addClass(options.hideClass); - } - function positionPlaceholder(placeholder,input){ - var ta = input.is('textarea'); - placeholder.css({ - width : input.innerWidth()-(ta ? 20 : 4), - height : input.innerHeight()-6, - lineHeight : input.css('line-height'), - whiteSpace : ta ? 'normal' : 'nowrap', - overflow : 'hidden' - }).offset(input.offset()); - } - function startFilledCheckChange(input,options){ - var input = input, - val = input.val(); - (function checkloop(){ - animId = requestAnimationFrame(checkloop); - if(input.val() != val){ - hidePlaceholder(input,options); - stopCheckChange(); - startEmptiedCheckChange(input,options); - } - })(); - } - function startEmptiedCheckChange(input,options){ - var input = input, - val = input.val(); - (function checkloop(){ - animId = requestAnimationFrame(checkloop); - showPlaceholderIfEmpty(input,options); - })(); - } - function stopCheckChange(){ - cancelAnimationFrame(animId); - } - function log(msg){ - if(debug && window.console && window.console.log){ - window.console.log(msg); - } - } - - $.fn.placeHolder = function(config) { - log('init placeHolder'); - var o = this; - var l = $(this).length; - this.options = $.extend({ - className: 'placeholder', // css class that is used to style the placeholder - visibleToScreenreaders : true, // expose the placeholder text to screenreaders or not - visibleToScreenreadersHideClass : 'placeholder-hide-except-screenreader', // css class is used to visually hide the placeholder - visibleToNoneHideClass : 'placeholder-hide', // css class used to hide the placeholder for all - hideOnFocus : false, // either hide the placeholder on focus or on type - removeLabelClass : 'visuallyhidden', // remove this class from a label (to fix hidden labels) - hiddenOverrideClass : 'visuallyhidden-with-placeholder', // replace the label above with this class - forceHiddenOverride : true, // allow the replace of the removeLabelClass with hiddenOverrideClass or not - forceApply : false, // apply the polyfill even for browser with native support - autoInit : true // init automatically or not - }, config); - this.options.hideClass = this.options.visibleToScreenreaders ? this.options.visibleToScreenreadersHideClass : this.options.visibleToNoneHideClass; - return $(this).each(function(index) { - var input = $(this), - text = input.attr('placeholder'), - id = input.attr('id'), - label,placeholder,titleNeeded,polyfilled; - label = input.closest('label'); - input.removeAttr('placeholder'); - if(!label.length && !id){ - log('the input element with the placeholder needs an id!'); - return; - } - label = label.length ? label : $('label[for="'+id+'"]').first(); - if(!label.length){ - log('the input element with the placeholder needs a label!'); - return; - } - polyfilled = $(label).find('.placeholder'); - if(polyfilled.length) { - //log('the input element already has a polyfilled placeholder!'); - positionPlaceholder(polyfilled,input); - return input; - } - - if(label.hasClass(o.options.removeLabelClass)){ - label.removeClass(o.options.removeLabelClass) - .addClass(o.options.hiddenOverrideClass); - } - - placeholder = $(''+text+'').appendTo(label); - - titleNeeded = (placeholder.width() > input.width()); - if(titleNeeded){ - placeholder.attr('title',text); - } - positionPlaceholder(placeholder,input); - input.data('placeholder',placeholder); - placeholder.data('input',placeholder); - placeholder.click(function(){ - $(this).data('input').focus(); - }); - input.focusin(function() { - if(!o.options.hideOnFocus && window.requestAnimationFrame){ - startFilledCheckChange(input,o.options); - }else{ - hidePlaceholder(input,o.options); - } - }); - input.focusout(function(){ - showPlaceholderIfEmpty($(this),o.options); - if(!o.options.hideOnFocus && window.cancelAnimationFrame){ - stopCheckChange(); - } - }); - showPlaceholderIfEmpty(input,o.options); - - // reformat on window resize and optional reformat on font resize - requires: http://www.tomdeater.com/jquery/onfontresize/ - $(document).bind("fontresize resize", function(){ - positionPlaceholder(placeholder,input); - }); - - // optional reformat when a textarea is being resized - requires http://benalman.com/projects/jquery-resize-plugin/ - if($.event.special.resize){ - $("textarea").bind("resize", function(e){ - positionPlaceholder(placeholder,input); - }); - }else{ - // we simply disable the resizeablilty of textareas when we can't react on them resizing - $("textarea").css('resize','none'); - } - - if(index >= l-1){ - $.attrHooks.placeholder = { - get: function(elem) { - if (elem.nodeName.toLowerCase() == 'input' || elem.nodeName.toLowerCase() == 'textarea') { - if( $(elem).data('placeholder') ){ - // has been polyfilled - return $( $(elem).data('placeholder') ).text(); - }else{ - // native / not yet polyfilled - return $(elem)[0].placeholder; - } - - }else{ - return undefined; - } - }, - set: function(elem, value){ - return $( $(elem).data('placeholder') ).text(value); - } - }; - } - }); - - - - }; - $(function(){ - var config = window.placeHolderConfig || {}; - if(config.autoInit === false){ - log('placeholder:abort because autoInit is off'); - return - } - if('placeholder' in $('')[0] && !config.forceApply){ // don't run the polyfill when the browser has native support - log('placeholder:abort because browser has native support'); - return; - } - $('input[placeholder], textarea[placeholder]').placeHolder(config); - }); -})(jQuery); \ No newline at end of file diff --git a/js/placeholder_polyfill.jquery.js b/js/placeholder_polyfill.jquery.js new file mode 100644 index 00000000..9f42284f --- /dev/null +++ b/js/placeholder_polyfill.jquery.js @@ -0,0 +1,1005 @@ + + + + + + + + + HTML5-placeholder-polyfill/src/placeholder_polyfill.jquery.js at master · ginader/HTML5-placeholder-polyfill · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ +
+ + + + + + + +
+
+ +
+
+
+ + + + + +

+ public + + + / + HTML5-placeholder-polyfill +

+
+ + + + + +
+ + + + + + +
+ + +
+ + branch: master + + +
+ +
Switch branches/tags
+
+
+ + +
+ +
+
+
+ +

+ master +

+
+
+
Nothing to show
+
+ + +
+
+
+
+ + + +
+ + + + + + + +
+
+ +
+ + + + + + +
+ + +
+ + + + + + + +
+ + Dirk Ginader + + + +
+

5 contributors

+ + + + + + + +
+ +
+ + +
+ +
+
+ +
+
+
+
+ + file + 213 lines (198 sloc) + 8.945 kb +
+ +
+
+ + + + + +
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+
+
+
/**
* HTML5 placeholder polyfill
* @requires jQuery - tested with 1.6.2 but might as well work with older versions
*
* code: https://github.com/ginader/HTML5-placeholder-polyfill
* please report issues at: https://github.com/ginader/HTML5-placeholder-polyfill/issues
*
* Copyright (c) 2012 Dirk Ginader (ginader.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Version: 2.0.6
*
*/

(function($) {
    var debug = false,
        animId;
    function showPlaceholderIfEmpty(input,options) {
        if( input.val() === '' ){
            input.data('placeholder').removeClass(options.hideClass);
        }else{
            input.data('placeholder').addClass(options.hideClass);
        }
    }
    function hidePlaceholder(input,options){
        input.data('placeholder').addClass(options.hideClass);
    }
    function positionPlaceholder(placeholder,input){
        var ta = input.is('textarea');

        // Determine if we need to shift the header down more.
        var offset = input.offset();
        if (input.css('padding') && input.css('padding') !== '0px') {
          var padding = input.css('padding').split(' ');
          offset.top += Number(padding[0].replace('px', ''));
          offset.left += Number(padding[padding.length - 1].replace('px', ''));
        }
        else {
          if (input.css('padding-top') && input.css('padding-top') !== '0px') {
            offset.top += Number(input.css('padding-top').replace('px', ''));
          }
          if (input.css('padding-left') && input.css('padding-left') !== '0px') {
            offset.left += Number(input.css('padding-left').replace('px', ''));
          }
        }

        placeholder.css({
            width : input.innerWidth()-(ta ? 20 : 4),
            height : input.innerHeight()-6,
            lineHeight : input.css('line-height'),
            whiteSpace : ta ? 'normal' : 'nowrap',
            overflow : 'hidden'
        }).offset(offset);
    }
    function startFilledCheckChange(input,options){
        var val = input.val();
        (function checkloop(){
            animId = requestAnimationFrame(checkloop);
            if(input.val() !== val){
                hidePlaceholder(input,options);
                stopCheckChange();
                startEmptiedCheckChange(input,options);
            }
        }());
    }
    function startEmptiedCheckChange(input,options){
        (function checkloop(){
            animId = requestAnimationFrame(checkloop);
            showPlaceholderIfEmpty(input,options);
        }());
    }
    function stopCheckChange(){
        cancelAnimationFrame(animId);
    }
    function log(msg){
        if(debug && window.console && window.console.log){
            window.console.log(msg);
        }
    }

    $.fn.placeHolder = function(config) {
        log('init placeHolder');
        var o = this;
        var l = $(this).length;
        this.options = $.extend({
            className: 'placeholder', // css class that is used to style the placeholder
            visibleToScreenreaders : true, // expose the placeholder text to screenreaders or not
            visibleToScreenreadersHideClass : 'placeholder-hide-except-screenreader', // css class is used to visually hide the placeholder
            visibleToNoneHideClass : 'placeholder-hide', // css class used to hide the placeholder for all
            hideOnFocus : false, // either hide the placeholder on focus or on type
            removeLabelClass : 'visuallyhidden', // remove this class from a label (to fix hidden labels)
            hiddenOverrideClass : 'visuallyhidden-with-placeholder', // replace the label above with this class
            forceHiddenOverride : true, // allow the replace of the removeLabelClass with hiddenOverrideClass or not
            forceApply : false, // apply the polyfill even for browser with native support
            autoInit : true // init automatically or not
        }, config);
        this.options.hideClass = this.options.visibleToScreenreaders ? this.options.visibleToScreenreadersHideClass : this.options.visibleToNoneHideClass;
        return $(this).each(function(index) {
            var input = $(this),
                text = input.attr('placeholder'),
                id = input.attr('id'),
                label,placeholder,titleNeeded,polyfilled;
            if(text === "" || text === undefined) {
              text = input[0].attributes["placeholder"].value;
            }
            label = input.closest('label');
            input.removeAttr('placeholder');
            if(!label.length && !id){
                log('the input element with the placeholder needs an id!');
                return;
            }
            label = label.length ? label : $('label[for="'+id+'"]').first();
            if(!label.length){
                log('the input element with the placeholder needs a label!');
                return;
            }
            polyfilled = $(label).find('.placeholder');
            if(polyfilled.length) {
                //log('the input element already has a polyfilled placeholder!');
                positionPlaceholder(polyfilled,input);
                polyfilled.text(text);
                return input;
            }
            
            if(label.hasClass(o.options.removeLabelClass)){
                label.removeClass(o.options.removeLabelClass)
                     .addClass(o.options.hiddenOverrideClass);
            }

            placeholder = $('<span>').addClass(o.options.className).text(text).appendTo(label);

            titleNeeded = (placeholder.width() > input.width());
            if(titleNeeded){
                placeholder.attr('title',text);
            }
            positionPlaceholder(placeholder,input);
            input.data('placeholder',placeholder);
            placeholder.data('input',placeholder);
            placeholder.click(function(){
                $(this).data('input').focus();
            });
            input.focusin(function() {
                if(!o.options.hideOnFocus && window.requestAnimationFrame){
                    startFilledCheckChange(input,o.options);
                }else{
                    hidePlaceholder(input,o.options);
                }
            });
            input.focusout(function(){
                showPlaceholderIfEmpty($(this),o.options);
                if(!o.options.hideOnFocus && window.cancelAnimationFrame){
                    stopCheckChange();
                }
            });
            showPlaceholderIfEmpty(input,o.options);

            // reformat on window resize and optional reformat on font resize - requires: http://www.tomdeater.com/jquery/onfontresize/
            $(document).bind("fontresize resize", function(){
                positionPlaceholder(placeholder,input);
            });

            // optional reformat when a textarea is being resized - requires http://benalman.com/projects/jquery-resize-plugin/
            if($.event.special.resize){
                $("textarea").bind("resize", function(e){
                    positionPlaceholder(placeholder,input);
                });
            }else{
                // we simply disable the resizeablilty of textareas when we can't react on them resizing
                $("textarea").css('resize','none');
            }

            if(index >= l-1){
                $.attrHooks.placeholder = {
                    get: function(elem) {
                        if (elem.nodeName.toLowerCase() === 'input' || elem.nodeName.toLowerCase() === 'textarea') {
                            if( $(elem).data('placeholder') ){
                                // has been polyfilled
                                return $( $(elem).data('placeholder') ).text();
                            }else{
                                // native / not yet polyfilled
                                return $(elem)[0].placeholder;
                            }
                            
                        }else{
                            return undefined;
                        }
                    },
                    set: function(elem, value){
                        return $( $(elem).data('placeholder') ).text(value);
                    }
                };
            }
        });

    

    };
    $(function(){
        var config = window.placeHolderConfig || {};
        if(config.autoInit === false){
            log('placeholder:abort because autoInit is off');
            return;
        }
        if(('placeholder' in $('<input>')[0] || 'placeHolder' in $('<input>')[0]) && !config.forceApply){ // don't run the polyfill when the browser has native support
            log('placeholder:abort because browser has native support');
            return;
        }
        $('input[placeholder], textarea[placeholder]').placeHolder(config);
    });
}(jQuery));
+
+
+ +
+
+
+ + + + +
+
+ + + + +
+
+
+
+ + +
+ + + + + + + + + +
+

Markdown Cheat Sheet

+ +
+ +
+
+

Format Text

+

Headers

+
+# This is an <h1> tag
+## This is an <h2> tag
+###### This is an <h6> tag
+

Text styles

+
+*This text will be italic*
+_This will also be italic_
+**This text will be bold**
+__This will also be bold__
+
+*You **can** combine them*
+
+
+
+

Lists

+

Unordered

+
+* Item 1
+* Item 2
+  * Item 2a
+  * Item 2b
+

Ordered

+
+1. Item 1
+2. Item 2
+3. Item 3
+   * Item 3a
+   * Item 3b
+
+
+

Miscellaneous

+

Images

+
+![GitHub Logo](/images/logo.png)
+Format: ![Alt Text](url)
+
+

Links

+
+http://github.com - automatic!
+[GitHub](http://github.com)
+

Blockquotes

+
+As Kanye West said:
+
+> We're living the future so
+> the present is our past.
+
+
+
+
+ +

Code Examples in Markdown

+
+

Syntax highlighting with GFM

+
+```javascript
+function fancyAlert(arg) {
+  if(arg) {
+    $.facebox({div:'#foo'})
+  }
+}
+```
+
+
+

Or, indent your code 4 spaces

+
+Here is a Python code example
+without syntax highlighting:
+
+    def foo:
+      if not bar:
+        return true
+
+
+

Inline code for comments

+
+I think you should use an
+`<addr>` element here instead.
+
+
+ +
+ + + +
+ + Something went wrong with that request. Please try again. + +
+ + + + + + + + diff --git a/js/placeholder_polyfill.jquery.min.combo.js b/js/placeholder_polyfill.jquery.min.combo.js new file mode 100644 index 00000000..3e3a3dfd --- /dev/null +++ b/js/placeholder_polyfill.jquery.min.combo.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2008 Tom Deater (http://www.tomdeater.com) + * Licensed under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ +jQuery.onFontResize=(function(a){a(document).ready(function(){var c=a(" +
+ +
- -
- -
-