diff --git a/apps/contacts/css/styles.css b/apps/contacts/css/styles.css
index f961767a0d6..b6709c5a791 100644
--- a/apps/contacts/css/styles.css
+++ b/apps/contacts/css/styles.css
@@ -1,3 +1,4 @@
+#contacts li { padding-left:25px;background:url('../img/person.svg') no-repeat; }
#chooseaddressbook {margin-right: 170px; float: right;}
#contacts_details_name { font-weight:bold;font-size:1.1em;margin-left:25%;}
#contacts_details_photo { margin:.5em 0em .5em 25%; }
diff --git a/apps/contacts/img/person.png b/apps/contacts/img/person.png
new file mode 100644
index 00000000000..17e79196540
Binary files /dev/null and b/apps/contacts/img/person.png differ
diff --git a/apps/contacts/img/person.svg b/apps/contacts/img/person.svg
new file mode 100644
index 00000000000..c4842c5916b
--- /dev/null
+++ b/apps/contacts/img/person.svg
@@ -0,0 +1,175 @@
+
+
+
+
diff --git a/apps/contacts/js/interface.js b/apps/contacts/js/interface.js
index 02470d5a767..3190efae3cc 100644
--- a/apps/contacts/js/interface.js
+++ b/apps/contacts/js/interface.js
@@ -108,6 +108,18 @@ Contacts={
})
$.each(contacts, function(idx, itm) { contactlist.append(itm); });
*/
+ setTimeout(Contacts.UI.Contacts.lazyupdate(), 500);
+ },
+ lazyupdate:function(){
+ //alert('lazyupdate');
+ $('#contacts li').live('inview', function(){
+ if (!$(this).attr('style')) {
+ //alert($(this).data('id') + ' has background: ' + $(this).attr('style'));
+ $(this).css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat');
+ }/* else {
+ alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url'));
+ }*/
+ });
}
}
}
@@ -279,4 +291,25 @@ $(document).ready(function(){
});
$('#contacts_addcardform select').chosen();
+
+ $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
+ if (isInView) { //NOTE: I've kept all conditions for future reference ;-)
+ // element is now visible in the viewport
+ if (visiblePartY == 'top') {
+ // top part of element is visible
+ } else if (visiblePartY == 'bottom') {
+ // bottom part of element is visible
+ } else {
+ // whole part of element is visible
+ if (!$(this).attr('style')) {
+ //alert($(this).data('id') + ' has background: ' + $(this).attr('style'));
+ $(this).css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat');
+ }/* else {
+ alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url'));
+ }*/
+ }
+ } else {
+ // element has gone out of viewport
+ }
+ });
});
diff --git a/apps/contacts/js/jquery.inview.js b/apps/contacts/js/jquery.inview.js
new file mode 100644
index 00000000000..a38ab164977
--- /dev/null
+++ b/apps/contacts/js/jquery.inview.js
@@ -0,0 +1,118 @@
+/**
+ * author Christopher Blum
+ * - based on the idea of Remy Sharp, http://remysharp.com/2009/01/26/element-in-view-event-plugin/
+ * - forked from http://github.com/zuk/jquery.inview/
+ */
+(function ($) {
+ var inviewObjects = {}, viewportSize, viewportOffset,
+ d = document, w = window, documentElement = d.documentElement, expando = $.expando;
+
+ $.event.special.inview = {
+ add: function(data) {
+ inviewObjects[data.guid + "-" + this[expando]] = { data: data, $element: $(this) };
+ },
+
+ remove: function(data) {
+ try { delete inviewObjects[data.guid + "-" + this[expando]]; } catch(e) {}
+ }
+ };
+
+ function getViewportSize() {
+ var mode, domObject, size = { height: w.innerHeight, width: w.innerWidth };
+
+ // if this is correct then return it. iPad has compat Mode, so will
+ // go into check clientHeight/clientWidth (which has the wrong value).
+ if (!size.height) {
+ mode = d.compatMode;
+ if (mode || !$.support.boxModel) { // IE, Gecko
+ domObject = mode === 'CSS1Compat' ?
+ documentElement : // Standards
+ d.body; // Quirks
+ size = {
+ height: domObject.clientHeight,
+ width: domObject.clientWidth
+ };
+ }
+ }
+
+ return size;
+ }
+
+ function getViewportOffset() {
+ return {
+ top: w.pageYOffset || documentElement.scrollTop || d.body.scrollTop,
+ left: w.pageXOffset || documentElement.scrollLeft || d.body.scrollLeft
+ };
+ }
+
+ function checkInView() {
+ var $elements = $(), elementsLength, i = 0;
+
+ $.each(inviewObjects, function(i, inviewObject) {
+ var selector = inviewObject.data.selector,
+ $element = inviewObject.$element;
+ $elements = $elements.add(selector ? $element.find(selector) : $element);
+ });
+
+ elementsLength = $elements.length;
+ if (elementsLength) {
+ viewportSize = viewportSize || getViewportSize();
+ viewportOffset = viewportOffset || getViewportOffset();
+
+ for (; i viewportOffset.top &&
+ elementOffset.top < viewportOffset.top + viewportSize.height &&
+ elementOffset.left + elementSize.width > viewportOffset.left &&
+ elementOffset.left < viewportOffset.left + viewportSize.width) {
+ visiblePartX = (viewportOffset.left > elementOffset.left ?
+ 'right' : (viewportOffset.left + viewportSize.width) < (elementOffset.left + elementSize.width) ?
+ 'left' : 'both');
+ visiblePartY = (viewportOffset.top > elementOffset.top ?
+ 'bottom' : (viewportOffset.top + viewportSize.height) < (elementOffset.top + elementSize.height) ?
+ 'top' : 'both');
+ visiblePartsMerged = visiblePartX + "-" + visiblePartY;
+ if (!inView || inView !== visiblePartsMerged) {
+ $element.data('inview', visiblePartsMerged).trigger('inview', [true, visiblePartX, visiblePartY]);
+ }
+ } else if (inView) {
+ $element.data('inview', false).trigger('inview', [false]);
+ }
+ }
+ }
+ }
+
+ $(w).bind("scroll resize", function() {
+ viewportSize = viewportOffset = null;
+ });
+
+ // Use setInterval in order to also make sure this captures elements within
+ // "overflow:scroll" elements or elements that appeared in the dom tree due to
+ // dom manipulation and reflow
+ // old: $(window).scroll(checkInView);
+ //
+ // By the way, iOS (iPad, iPhone, ...) seems to not execute, or at least delays
+ // intervals while the user scrolls. Therefore the inview event might fire a bit late there
+ setInterval(checkInView, 250);
+})(jQuery);
\ No newline at end of file
diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php
index 8592ffe1c4c..9e63b201987 100644
--- a/apps/contacts/templates/index.php
+++ b/apps/contacts/templates/index.php
@@ -1,3 +1,10 @@
+
+
diff --git a/apps/contacts/thumbnail.php b/apps/contacts/thumbnail.php
new file mode 100644
index 00000000000..bf0a6e96a5d
--- /dev/null
+++ b/apps/contacts/thumbnail.php
@@ -0,0 +1,150 @@
+.
+ *
+ */
+
+// Init owncloud
+require_once('../../lib/base.php');
+OC_Util::checkLoggedIn();
+OC_Util::checkAppEnabled('contacts');
+
+if(!function_exists('imagecreatefromjpeg')) {
+ OC_Log::write('contacts','GD module not installed',OC_Log::ERROR);
+ header('Content-Type: image/png');
+ // TODO: Check if it works to read the file and echo the content.
+ return 'img/person.png';
+}
+
+function getStandardImage(){
+ $src_img = imagecreatefrompng('img/person.png');
+ header('Content-Type: image/png');
+ imagepng($src_img);
+ imagedestroy($src_img);
+}
+
+
+$id = $_GET['id'];
+
+$l10n = new OC_L10N('contacts');
+
+$card = OC_Contacts_VCard::find( $id );
+if( $card === false ){
+ echo $l10n->t('Contact could not be found.');
+ exit();
+}
+
+$addressbook = OC_Contacts_Addressbook::find( $card['addressbookid'] );
+if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
+ echo $l10n->t('This is not your contact.'); // This is a weird error, why would it come up? (Better feedback for users?)
+ exit();
+}
+
+$content = OC_VObject::parse($card['carddata']);
+
+// invalid vcard
+if( is_null($content)){
+ echo $l10n->t('This card is not RFC compatible.');
+ exit();
+}
+
+// define the width and height for the thumbnail
+// note that theese dimmensions are considered the maximum dimmension and are not fixed,
+// because we have to keep the image ratio intact or it will be deformed
+$thumbnail_width = 23;
+$thumbnail_height = 23;
+
+// Photo :-)
+foreach($content->children as $child){
+ if($child->name == 'PHOTO'){
+ foreach($child->parameters as $parameter){
+ if( $parameter->name == 'TYPE' ){
+ $mime = $parameter->value;
+ }
+ }
+ $data = base64_decode($child->value);
+ $src_img = imagecreatefromstring($data);
+ if ($src_img !== false) {
+ //gets the dimmensions of the image
+ $width_orig=imageSX($src_img);
+ $height_orig=imageSY($src_img);
+ $ratio_orig = $width_orig/$height_orig;
+
+ if ($thumbnail_width/$thumbnail_height > $ratio_orig) {
+ $new_height = $thumbnail_width/$ratio_orig;
+ $new_width = $thumbnail_width;
+ } else {
+ $new_width = $thumbnail_height*$ratio_orig;
+ $new_height = $thumbnail_height;
+ }
+
+ $x_mid = $new_width/2; //horizontal middle
+ $y_mid = $new_height/2; //vertical middle
+
+ $process = imagecreatetruecolor(round($new_width), round($new_height));
+ if ($process == false) {
+ getStandardImage();
+ //echo 'Error creating process image: '.$new_width.'x'.$new_height;
+ OC_Log::write('contacts','Error creating process image for '.$id.' '.$new_width.'x'.$new_height,OC_Log::ERROR);
+ imagedestroy($process);
+ imagedestroy($src_img);
+ exit();
+ }
+
+ imagecopyresampled($process, $src_img, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig);
+ if ($process == false) {
+ getStandardImage();
+ //echo 'Error resampling process image: '.$new_width.'x'.$new_height;
+ OC_Log::write('contacts','Error resampling process image for '.$id.' '.$new_width.'x'.$new_height,OC_Log::ERROR);
+ imagedestroy($process);
+ imagedestroy($src_img);
+ exit();
+ }
+ $thumb = imagecreatetruecolor($thumbnail_width, $thumbnail_height);
+ if ($process == false) {
+ getStandardImage();
+ //echo 'Error creating thumb image: '.$thumbnail_width.'x'.$thumbnail_height;
+ OC_Log::write('contacts','Error creating thumb image for '.$id.' '.$thumbnail_width.'x'.$thumbnail_height,OC_Log::ERROR);
+ imagedestroy($process);
+ imagedestroy($src_img);
+ exit();
+ }
+ imagecopyresampled($thumb, $process, 0, 0, ($x_mid-($thumbnail_width/2)), ($y_mid-($thumbnail_height/2)), $thumbnail_width, $thumbnail_height, $thumbnail_width, $thumbnail_height);
+ if ($thumb !== false) {
+ header('Content-Type: image/png');
+ imagepng($thumb);
+ } else {
+ getStandardImage();
+ OC_Log::write('contacts','Error resampling thumb image for '.$id.' '.$thumbnail_width.'x'.$thumbnail_height,OC_Log::ERROR);
+ //echo 'An error occurred resampling thumb.';
+ }
+ imagedestroy($thumb);
+ imagedestroy($process);
+ imagedestroy($src_img);
+ }
+ else {
+ getStandardImage();
+ }
+ exit();
+ }
+}
+getStandardImage();
+
+// Not found :-(
+//echo $l10n->t('This card does not contain a photo.');