aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--images/feed-icon-14x14.pngbin0 -> 689 bytes
-rw-r--r--images/private_16x16.pngbin0 -> 439 bytes
-rw-r--r--inc/jquery.lazyload.min.js15
-rw-r--r--inc/shaarli.css49
-rw-r--r--index.php322
-rw-r--r--tpl/daily.html13
-rw-r--r--tpl/dailyrss.html8
-rw-r--r--tpl/includes.html2
-rw-r--r--tpl/linklist.html20
-rw-r--r--tpl/linklist.paging.html23
-rw-r--r--tpl/page.header.html8
-rw-r--r--tpl/picwall.html9
12 files changed, 359 insertions, 110 deletions
diff --git a/images/feed-icon-14x14.png b/images/feed-icon-14x14.png
new file mode 100644
index 00000000..b3c949d2
--- /dev/null
+++ b/images/feed-icon-14x14.png
Binary files differ
diff --git a/images/private_16x16.png b/images/private_16x16.png
new file mode 100644
index 00000000..d58c4823
--- /dev/null
+++ b/images/private_16x16.png
Binary files differ
diff --git a/inc/jquery.lazyload.min.js b/inc/jquery.lazyload.min.js
new file mode 100644
index 00000000..2364d8d9
--- /dev/null
+++ b/inc/jquery.lazyload.min.js
@@ -0,0 +1,15 @@
1/*
2 * Lazy Load - jQuery plugin for lazy loading images
3 *
4 * Copyright (c) 2007-2012 Mika Tuupola
5 *
6 * Licensed under the MIT license:
7 * http://www.opensource.org/licenses/mit-license.php
8 *
9 * Project home:
10 * http://www.appelsiini.net/projects/lazyload
11 *
12 * Version: 1.7.0
13 *
14 */
15(function(a,b){$window=a(b),a.fn.lazyload=function(c){var d={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null};c&&(undefined!==c.failurelimit&&(c.failure_limit=c.failurelimit,delete c.failurelimit),undefined!==c.effectspeed&&(c.effect_speed=c.effectspeed,delete c.effectspeed),a.extend(d,c));var e=this;return 0==d.event.indexOf("scroll")&&a(d.container).bind(d.event,function(b){var c=0;e.each(function(){$this=a(this);if(d.skip_invisible&&!$this.is(":visible"))return;if(!a.abovethetop(this,d)&&!a.leftofbegin(this,d))if(!a.belowthefold(this,d)&&!a.rightoffold(this,d))$this.trigger("appear");else if(++c>d.failure_limit)return!1})}),this.each(function(){var b=this,c=a(b);b.loaded=!1,c.one("appear",function(){if(!this.loaded){if(d.appear){var f=e.length;d.appear.call(b,f,d)}a("<img />").bind("load",function(){c.hide().attr("src",c.data(d.data_attribute))[d.effect](d.effect_speed),b.loaded=!0;var f=a.grep(e,function(a){return!a.loaded});e=a(f);if(d.load){var g=e.length;d.load.call(b,g,d)}}).attr("src",c.data(d.data_attribute))}}),0!=d.event.indexOf("scroll")&&c.bind(d.event,function(a){b.loaded||c.trigger("appear")})}),$window.bind("resize",function(b){a(d.container).trigger(d.event)}),a(d.container).trigger(d.event),this},a.belowthefold=function(c,d){if(d.container===undefined||d.container===b)var e=$window.height()+$window.scrollTop();else var e=a(d.container).offset().top+a(d.container).height();return e<=a(c).offset().top-d.threshold},a.rightoffold=function(c,d){if(d.container===undefined||d.container===b)var e=$window.width()+$window.scrollLeft();else var e=a(d.container).offset().left+a(d.container).width();return e<=a(c).offset().left-d.threshold},a.abovethetop=function(c,d){if(d.container===undefined||d.container===b)var e=$window.scrollTop();else var e=a(d.container).offset().top;return e>=a(c).offset().top+d.threshold+a(c).height()},a.leftofbegin=function(c,d){if(d.container===undefined||d.container===b)var e=$window.scrollLeft();else var e=a(d.container).offset().left;return e>=a(c).offset().left+d.threshold+a(c).width()},a.inviewport=function(b,c){return!a.rightofscreen(b,c)&&!a.leftofscreen(b,c)&&!a.belowthefold(b,c)&&!a.abovethetop(b,c)},a.extend(a.expr[":"],{"below-the-fold":function(c){return a.belowthefold(c,{threshold:0,container:b})},"above-the-top":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-screen":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-screen":function(c){return!a.rightoffold(c,{threshold:0,container:b})},"in-viewport":function(c){return!a.inviewport(c,{threshold:0,container:b})},"above-the-fold":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-fold":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-fold":function(c){return!a.rightoffold(c,{threshold:0,container:b})}})})(jQuery,window)
diff --git a/inc/shaarli.css b/inc/shaarli.css
index a949666e..5b4b88b6 100644
--- a/inc/shaarli.css
+++ b/inc/shaarli.css
@@ -184,6 +184,12 @@ cursor:pointer;
184.paging a:visited { color:#ccc; } 184.paging a:visited { color:#ccc; }
185.paging a:hover { color:#FFFFC9; } 185.paging a:hover { color:#FFFFC9; }
186.paging a:active { color:#fff; } 186.paging a:active { color:#fff; }
187#paging_privatelinks { float:left; }
188#paging_linksperpage { float:right; padding-right:5px; }
189#paging_current { display:inline; color:#fff; padding:0 20 0 20; }
190#paging_older { margin-right:15px; }
191#paging_newer { margin-left:15px; }
192
187#headerform { color:#ffffff; padding:5px 5px 5px 5px; clear: both;} 193#headerform { color:#ffffff; padding:5px 5px 5px 5px; clear: both;}
188#toolsdiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; } 194#toolsdiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; }
189#uploaddiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; } 195#uploaddiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; }
@@ -325,6 +331,11 @@ div.daily
325 position:relative; 331 position:relative;
326 border-bottom: 2px solid black; 332 border-bottom: 2px solid black;
327} 333}
334
335#daily_col1 { float:left;position:relative; width:33%; padding-left:1%; }
336#daily_col2 { float:left;position:relative; width:33%; }
337#daily_col3 { float:left;position:relative; width:33%;}
338
328div.dailyAbout 339div.dailyAbout
329{ 340{
330 float:left; 341 float:left;
@@ -383,6 +394,11 @@ div.dailyEntryDescription
383 clear:both; 394 clear:both;
384} 395}
385 396
397/* For lazy images loading in picture wall.
398 using http://www.appelsiini.net/projects/lazyload
399 */
400.lazyimage { display:none; }
401
386@media print { 402@media print {
387html {border:none;background:#fff!important;color:#000!important;} 403html {border:none;background:#fff!important;color:#000!important;}
388body {font-size:12pt;width:auto!important;margin:auto!important;} 404body {font-size:12pt;width:auto!important;margin:auto!important;}
@@ -397,3 +413,36 @@ a {color:#000!important;text-decoration:none!important;}
397.linktag { border: 1px solid black; font-style:italic; font-size:8pt;} 413.linktag { border: 1px solid black; font-style:italic; font-size:8pt;}
398 414
399} 415}
416
417
418@media handheld, only screen and (max-width: 480px), only screen and (max-device-width: 854px)
419{
420/* A few fixes for mobile devices (far from perfect). */
421.nomobile { display:none; }
422#logo { display:none; }
423#pageheader a
424{
425 padding:5px;
426 border-radius: 5px 5px 5px 5px;
427 margin:3px;
428}
429.searchform,.tagfilter { display:block !important; margin:0px !important; padding:0px !important; width:100% !important; }
430.searchform input,.tagfilter input { margin:0px !important; padding:0px !important; display:inline !important; }
431.tagfilter input.bigbutton,.searchform input.bigbutton,.addform input.bigbutton{ width:30%; font-size:smaller;}
432#searchform_value { width:70% !important; }
433#tagfilter_value { width:70% !important; }
434div.qrcode { position:relative; float:left; top:-10px; left:0px; }
435#paging_privatelinks { float;none; }
436#paging_linksperpage { float:none; margin-bottom:10px; font-size:smaller;}
437#paging_older,#paging_newer,#paging_linksperpage a { border: 1px solid black; padding:3px 5px 3px 5px; background-color:#666; color:#fff; border-radius: 5px 5px 5px 5px;}
438.thumbnail { float:none; height:auto; margin: 0px; text-align:center;}
439#cloudtag { padding:0px; }
440div.dailyAbout { float:none; position:relative; width:100%; clear:both; padding:0px; top:0px; left:0px; }
441#daily_col1,#daily_col2,#daily_col3 { float:none; width:100%; padding:0px;}
442div.dailyTitle { font-size: 18pt; margin-top:5px; padding:0px;}
443div.dailyDate { font-size: 11pt;padding:0px; display:block; }
444div.dailyEntryTitle { font-size:16pt; font-weight:bold;}
445div.dailyEntryDescription { font-size:10pt; }
446
447}
448
diff --git a/index.php b/index.php
index 9dd6483e..936d6129 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,5 @@
1<?php 1<?php
2// Shaarli 0.0.36 beta - Shaare your links... 2// Shaarli 0.0.37 beta - Shaare your links...
3// The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net 3// The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net
4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli 4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli
5// Licence: http://www.opensource.org/licenses/zlib-license.php 5// Licence: http://www.opensource.org/licenses/zlib-license.php
@@ -58,7 +58,7 @@ header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
58header("Cache-Control: no-store, no-cache, must-revalidate"); 58header("Cache-Control: no-store, no-cache, must-revalidate");
59header("Cache-Control: post-check=0, pre-check=0", false); 59header("Cache-Control: post-check=0, pre-check=0", false);
60header("Pragma: no-cache"); 60header("Pragma: no-cache");
61define('shaarli_version','0.0.36 beta'); 61define('shaarli_version','0.0.37 beta');
62if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } 62if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); }
63if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. 63if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files.
64if ($GLOBALS['config']['ENABLE_LOCALCACHE']) 64if ($GLOBALS['config']['ENABLE_LOCALCACHE'])
@@ -153,8 +153,8 @@ function text2clickable($url)
153// even in the absence of <pre> (This is used in description to keep text formatting) 153// even in the absence of <pre> (This is used in description to keep text formatting)
154function keepMultipleSpaces($text) 154function keepMultipleSpaces($text)
155{ 155{
156 return str_replace(' ',' &nbsp;',$text); 156 return str_replace(' ',' &nbsp;',$text);
157 157
158} 158}
159// ------------------------------------------------------------------------------------------ 159// ------------------------------------------------------------------------------------------
160// Sniff browser language to display dates in the right format automatically. 160// Sniff browser language to display dates in the right format automatically.
@@ -850,6 +850,75 @@ function showATOM()
850} 850}
851 851
852// ------------------------------------------------------------------------------------------ 852// ------------------------------------------------------------------------------------------
853// Daily RSS feed: 1 RSS entry per day giving all the links on that day.
854// Gives the last 7 days (which have links).
855// This RSS feed cannot be filtered.
856function showDailyRSS()
857{
858 global $LINKSDB;
859
860 /* Some Shaarlies may have very few links, so we need to look
861 back in time (rsort()) until we have enough days ($nb_of_days).
862 */
863 $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; }
864 rsort($linkdates);
865 $nb_of_days=7; // We take 7 days.
866 $today=Date('Ymd');
867 $days=array();
868 foreach($linkdates as $linkdate)
869 {
870 $day=substr($linkdate,0,8); // Extract day (without time)
871 if (strcmp($day,$today)<0)
872 {
873 if (empty($days[$day])) $days[$day]=array();
874 $days[$day][]=$linkdate;
875 }
876 if (count($days)>$nb_of_days) break; // Have we collected enough days ?
877 }
878
879 // Build the RSS feed.
880 header('Content-Type: application/rss+xml; charset=utf-8');
881 $pageaddr=htmlspecialchars(indexUrl());
882 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
883 echo '<channel><title>Daily - '.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>';
884 echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n";
885
886 foreach($days as $day=>$linkdates) // For each day.
887 {
888 $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
889 $rfc822date = linkdate2rfc822($day.'_000000');
890 $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
891 echo '<item><title>'.htmlspecialchars($GLOBALS['title'].' - '.$daydate).'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
892 echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>";
893
894 // Build the HTML body of this RSS entry.
895 $html='';
896 $href='';
897 $links=array();
898 // We pre-format some fields for proper output.
899 foreach($linkdates as $linkdate)
900 {
901 $l = $LINKSDB[$linkdate];
902 $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description']))));
903 $l['thumbnail'] = thumbnail($l['url']);
904 $l['localdate']=linkdate2locale($l['linkdate']);
905 if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute
906 $links[$linkdate]=$l;
907 }
908 // Then build the HTML for this day:
909 $tpl = new RainTPL;
910 $tpl->assign('links',$links);
911 $html = $tpl->draw('dailyrss',$return_string=true);
912 echo "\n";
913 echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n";
914
915 }
916 echo '</channel></rss>';
917 exit;
918}
919
920
921// ------------------------------------------------------------------------------------------
853// Render HTML page (according to URL parameters and user rights) 922// Render HTML page (according to URL parameters and user rights)
854function renderPage() 923function renderPage()
855{ 924{
@@ -861,7 +930,7 @@ function renderPage()
861 if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli 930 if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli
862 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. 931 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
863 $PAGE = new pageBuilder; 932 $PAGE = new pageBuilder;
864 $PAGE->assign('token',$token); 933 $PAGE->assign('token',$token);
865 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); 934 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:''));
866 $PAGE->renderPage('loginform'); 935 $PAGE->renderPage('loginform');
867 exit; 936 exit;
@@ -890,17 +959,17 @@ function renderPage()
890 foreach($links as $link) 959 foreach($links as $link)
891 { 960 {
892 $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); 961 $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES);
893 $thumb=thumbnail($link['url'],$permalink); 962 $thumb=lazyThumbnail($link['url'],$permalink);
894 if ($thumb!='') // Only output links which have a thumbnail. 963 if ($thumb!='') // Only output links which have a thumbnail.
895 { 964 {
896 $link['thumbnail']=$thumb; // Thumbnail HTML code. 965 $link['thumbnail']=$thumb; // Thumbnail HTML code.
897 $link['permalink']=$permalink; 966 $link['permalink']=$permalink;
898 $linksToDisplay[]=$link; // Add to array. 967 $linksToDisplay[]=$link; // Add to array.
899 } 968 }
900 } 969 }
901 $PAGE = new pageBuilder; 970 $PAGE = new pageBuilder;
902 $PAGE->assign('linksToDisplay',$linksToDisplay); 971 $PAGE->assign('linksToDisplay',$linksToDisplay);
903 $PAGE->renderPage('picwall'); 972 $PAGE->renderPage('picwall');
904 exit; 973 exit;
905 } 974 }
906 975
@@ -915,12 +984,12 @@ function renderPage()
915 $tagList=array(); 984 $tagList=array();
916 foreach($tags as $key=>$value) 985 foreach($tags as $key=>$value)
917 { 986 {
918 $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8)); 987 $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8));
919 } 988 }
920 $PAGE = new pageBuilder; 989 $PAGE = new pageBuilder;
921 $PAGE->assign('tags',$tagList); 990 $PAGE->assign('tags',$tagList);
922 $PAGE->renderPage('tagcloud'); 991 $PAGE->renderPage('tagcloud');
923 exit; 992 exit;
924 } 993 }
925 994
926 // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) 995 // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...)
@@ -960,6 +1029,21 @@ function renderPage()
960 exit; 1029 exit;
961 } 1030 }
962 1031
1032 // -------- User wants to see only private links (toggle)
1033 if (isset($_GET['privateonly']))
1034 {
1035 if (empty($_SESSION['privateonly']))
1036 {
1037 $_SESSION['privateonly']=1; // See only private links
1038 }
1039 else
1040 {
1041 unset($_SESSION['privateonly']); // See all links
1042 }
1043 header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
1044 exit;
1045 }
1046
963 // --------- Daily (all links form a specific day) ---------------------- 1047 // --------- Daily (all links form a specific day) ----------------------
964 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily')) 1048 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily'))
965 { 1049 {
@@ -1000,7 +1084,7 @@ function renderPage()
1000 $fill[$index]+=$length; 1084 $fill[$index]+=$length;
1001 } 1085 }
1002 $PAGE = new pageBuilder; 1086 $PAGE = new pageBuilder;
1003 $PAGE->assign('linksToDisplay',$linksToDisplay); 1087 $PAGE->assign('linksToDisplay',$linksToDisplay);
1004 $PAGE->assign('col1',$columns[0]); 1088 $PAGE->assign('col1',$columns[0]);
1005 $PAGE->assign('col2',$columns[1]); 1089 $PAGE->assign('col2',$columns[1]);
1006 $PAGE->assign('col3',$columns[2]); 1090 $PAGE->assign('col3',$columns[2]);
@@ -1021,10 +1105,10 @@ function renderPage()
1021 header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. 1105 header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link.
1022 exit; 1106 exit;
1023 } 1107 }
1024 $PAGE = new pageBuilder; 1108 $PAGE = new pageBuilder;
1025 buildLinkList($PAGE); // Compute list of links to display 1109 buildLinkList($PAGE); // Compute list of links to display
1026 $PAGE->renderPage('linklist'); 1110 $PAGE->renderPage('linklist');
1027 exit; // Never remove this one ! All operations below are reserved for logged in user. 1111 exit; // Never remove this one ! All operations below are reserved for logged in user.
1028 } 1112 }
1029 1113
1030 // -------- All other functions are reserved for the registered user: 1114 // -------- All other functions are reserved for the registered user:
@@ -1032,9 +1116,9 @@ function renderPage()
1032 // -------- Display the Tools menu if requested (import/export/bookmarklet...) 1116 // -------- Display the Tools menu if requested (import/export/bookmarklet...)
1033 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools')) 1117 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools'))
1034 { 1118 {
1035 $PAGE = new pageBuilder; 1119 $PAGE = new pageBuilder;
1036 $PAGE->assign('pageabsaddr',indexUrl()); 1120 $PAGE->assign('pageabsaddr',indexUrl());
1037 $PAGE->renderPage('tools'); 1121 $PAGE->renderPage('tools');
1038 exit; 1122 exit;
1039 } 1123 }
1040 1124
@@ -1058,10 +1142,10 @@ function renderPage()
1058 } 1142 }
1059 else // show the change password form. 1143 else // show the change password form.
1060 { 1144 {
1061 $PAGE = new pageBuilder; 1145 $PAGE = new pageBuilder;
1062 $PAGE->assign('token',getToken()); 1146 $PAGE->assign('token',getToken());
1063 $PAGE->renderPage('changepassword'); 1147 $PAGE->renderPage('changepassword');
1064 exit; 1148 exit;
1065 } 1149 }
1066 } 1150 }
1067 1151
@@ -1084,15 +1168,15 @@ function renderPage()
1084 } 1168 }
1085 else // Show the configuration form. 1169 else // Show the configuration form.
1086 { 1170 {
1087 $PAGE = new pageBuilder; 1171 $PAGE = new pageBuilder;
1088 $PAGE->assign('token',getToken()); 1172 $PAGE->assign('token',getToken());
1089 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); 1173 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
1090 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); 1174 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
1091 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); 1175 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
1092 $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? 1176 $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ?
1093 $PAGE->assign('timezone_js',$timezone_js); 1177 $PAGE->assign('timezone_js',$timezone_js);
1094 $PAGE->renderPage('configure'); 1178 $PAGE->renderPage('configure');
1095 exit; 1179 exit;
1096 } 1180 }
1097 } 1181 }
1098 1182
@@ -1101,10 +1185,10 @@ function renderPage()
1101 { 1185 {
1102 if (empty($_POST['fromtag'])) 1186 if (empty($_POST['fromtag']))
1103 { 1187 {
1104 $PAGE = new pageBuilder; 1188 $PAGE = new pageBuilder;
1105 $PAGE->assign('token',getToken()); 1189 $PAGE->assign('token',getToken());
1106 $PAGE->renderPage('changetag'); 1190 $PAGE->renderPage('changetag');
1107 exit; 1191 exit;
1108 } 1192 }
1109 if (!tokenOk($_POST['token'])) die('Wrong token.'); 1193 if (!tokenOk($_POST['token'])) die('Wrong token.');
1110 1194
@@ -1148,8 +1232,8 @@ function renderPage()
1148 // -------- User wants to add a link without using the bookmarklet: show form. 1232 // -------- User wants to add a link without using the bookmarklet: show form.
1149 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) 1233 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink'))
1150 { 1234 {
1151 $PAGE = new pageBuilder; 1235 $PAGE = new pageBuilder;
1152 $PAGE->renderPage('addlink'); 1236 $PAGE->renderPage('addlink');
1153 exit; 1237 exit;
1154 } 1238 }
1155 1239
@@ -1207,12 +1291,12 @@ function renderPage()
1207 { 1291 {
1208 $link = $LINKSDB[$_GET['edit_link']]; // Read database 1292 $link = $LINKSDB[$_GET['edit_link']]; // Read database
1209 if (!$link) { header('Location: ?'); exit; } // Link not found in database. 1293 if (!$link) { header('Location: ?'); exit; } // Link not found in database.
1210 $PAGE = new pageBuilder; 1294 $PAGE = new pageBuilder;
1211 $PAGE->assign('link',$link); 1295 $PAGE->assign('link',$link);
1212 $PAGE->assign('link_is_new',false); 1296 $PAGE->assign('link_is_new',false);
1213 $PAGE->assign('token',getToken()); // XSRF protection. 1297 $PAGE->assign('token',getToken()); // XSRF protection.
1214 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); 1298 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
1215 $PAGE->renderPage('editlink'); 1299 $PAGE->renderPage('editlink');
1216 exit; 1300 exit;
1217 } 1301 }
1218 1302
@@ -1246,12 +1330,12 @@ function renderPage()
1246 $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0); 1330 $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0);
1247 } 1331 }
1248 1332
1249 $PAGE = new pageBuilder; 1333 $PAGE = new pageBuilder;
1250 $PAGE->assign('link',$link); 1334 $PAGE->assign('link',$link);
1251 $PAGE->assign('link_is_new',$link_is_new); 1335 $PAGE->assign('link_is_new',$link_is_new);
1252 $PAGE->assign('token',getToken()); // XSRF protection. 1336 $PAGE->assign('token',getToken()); // XSRF protection.
1253 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); 1337 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
1254 $PAGE->renderPage('editlink'); 1338 $PAGE->renderPage('editlink');
1255 exit; 1339 exit;
1256 } 1340 }
1257 1341
@@ -1260,9 +1344,9 @@ function renderPage()
1260 { 1344 {
1261 if (empty($_GET['what'])) 1345 if (empty($_GET['what']))
1262 { 1346 {
1263 $PAGE = new pageBuilder; 1347 $PAGE = new pageBuilder;
1264 $PAGE->renderPage('export'); 1348 $PAGE->renderPage('export');
1265 exit; 1349 exit;
1266 } 1350 }
1267 $exportWhat=$_GET['what']; 1351 $exportWhat=$_GET['what'];
1268 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); 1352 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???');
@@ -1313,10 +1397,10 @@ HTML;
1313 // -------- Show upload/import dialog: 1397 // -------- Show upload/import dialog:
1314 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import')) 1398 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import'))
1315 { 1399 {
1316 $PAGE = new pageBuilder; 1400 $PAGE = new pageBuilder;
1317 $PAGE->assign('token',getToken()); 1401 $PAGE->assign('token',getToken());
1318 $PAGE->assign('maxfilesize',getMaxFileSize()); 1402 $PAGE->assign('maxfilesize',getMaxFileSize());
1319 $PAGE->renderPage('import'); 1403 $PAGE->renderPage('import');
1320 exit; 1404 exit;
1321 } 1405 }
1322 1406
@@ -1430,14 +1514,24 @@ function buildLinkList($PAGE)
1430 $search_crits=explode(' ',trim($_GET['searchtags'])); 1514 $search_crits=explode(' ',trim($_GET['searchtags']));
1431 $search_type='tags'; 1515 $search_type='tags';
1432 } 1516 }
1433 elseif (isset($_SERVER["QUERY_STRING"]) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER["QUERY_STRING"])) // Detect smallHashes in URL 1517 elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL
1434 { 1518 {
1435 $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6)); 1519 $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6));
1436 $search_type='permalink'; 1520 $search_type='permalink';
1437 } 1521 }
1438 else 1522 else
1439 $linksToDisplay = $LINKSDB; // otherwise, display without filtering. 1523 $linksToDisplay = $LINKSDB; // otherwise, display without filtering.
1440 1524
1525 // Option: Show only private links
1526 if (!empty($_SESSION['privateonly']))
1527 {
1528 $tmp = array();
1529 foreach($linksToDisplay as $linkdate=>$link)
1530 {
1531 if ($link['private']!=0) $tmp[$linkdate]=$link;
1532 }
1533 $linksToDisplay=$tmp;
1534 }
1441 1535
1442 // ---- Handle paging. 1536 // ---- Handle paging.
1443 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess ??? 1537 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess ???
@@ -1494,16 +1588,18 @@ function buildLinkList($PAGE)
1494 return; 1588 return;
1495} 1589}
1496 1590
1497// Returns the HTML code to display a thumbnail for a link 1591// Compute the thumbnail for a link.
1592//
1498// with a link to the original URL. 1593// with a link to the original URL.
1499// Understands various services (youtube.com...) 1594// Understands various services (youtube.com...)
1500// Input: $url = url for which the thumbnail must be found. 1595// Input: $url = url for which the thumbnail must be found.
1501// $href = if provided, this URL will be followed instead of $url 1596// $href = if provided, this URL will be followed instead of $url
1502// Returns '' if no thumbnail available. 1597// Returns an associative array with thumbnail attributes (src,href,width,height,style,alt)
1503function thumbnail($url,$href=false) 1598// Some of them may be missing.
1599// Return an empty array if no thumbnail available.
1600function computeThumbnail($url,$href=false)
1504{ 1601{
1505 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return ''; 1602 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return array();
1506
1507 if ($href==false) $href=$url; 1603 if ($href==false) $href=$url;
1508 1604
1509 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. 1605 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link.
@@ -1513,38 +1609,47 @@ function thumbnail($url,$href=false)
1513 if ($domain=='youtube.com' || $domain=='www.youtube.com') 1609 if ($domain=='youtube.com' || $domain=='www.youtube.com')
1514 { 1610 {
1515 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail 1611 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail
1516 if (!empty($params['v'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi/'.htmlspecialchars($params['v']).'/default.jpg" width="120" height="90" alt="YouTube thumbnail"></a>'; 1612 if (!empty($params['v'])) return array('src'=>'http://img.youtube.com/vi/'.$params['v'].'/default.jpg',
1613 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
1517 } 1614 }
1518 if ($domain=='youtu.be') // Youtube short links 1615 if ($domain=='youtu.be') // Youtube short links
1519 { 1616 {
1520 $path = parse_url($url,PHP_URL_PATH); 1617 $path = parse_url($url,PHP_URL_PATH);
1521 return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi'.htmlspecialchars($path).'/default.jpg" width="120" height="90" alt="YouTube thumbnail"></a>'; 1618 return array('src'=>'http://img.youtube.com/vi'.$path.'/default.jpg',
1619 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
1522 } 1620 }
1523 if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting 1621 if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting
1524 { 1622 {
1525 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename. 1623 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename.
1526 if (!empty($params) && !empty($params['img'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']).'" style:"max-width:120px; max-height:150px" alt="pix.toile-libre.org thumbnail"></a>'; 1624 if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']),
1625 'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail');
1527 } 1626 }
1528 1627
1529 if ($domain=='imgur.com') 1628 if ($domain=='imgur.com')
1530 { 1629 {
1531 $path = parse_url($url,PHP_URL_PATH); 1630 $path = parse_url($url,PHP_URL_PATH);
1532 if (startsWith($path,'/a/')) return ''; // Thumbnails for albums are not available. 1631 if (startsWith($path,'/a/')) return array(); // Thumbnails for albums are not available.
1533 if (startsWith($path,'/r/')) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars(basename($path)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1632 if (startsWith($path,'/r/')) return array('src'=>'http://i.imgur.com/'.basename($path).'s.jpg',
1534 if (startsWith($path,'/gallery/')) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com'.htmlspecialchars(substr($path,8)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1633 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1535 if (substr_count($path,'/')==1) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars(substr($path,1)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1634 if (startsWith($path,'/gallery/')) return array('src'=>'http://i.imgur.com'.substr($path,8).'s.jpg',
1635 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1636
1637 if (substr_count($path,'/')==1) return array('src'=>'http://i.imgur.com/'.substr($path,1).'s.jpg',
1638 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1536 } 1639 }
1537 if ($domain=='i.imgur.com') 1640 if ($domain=='i.imgur.com')
1538 { 1641 {
1539 $pi = pathinfo(parse_url($url,PHP_URL_PATH)); 1642 $pi = pathinfo(parse_url($url,PHP_URL_PATH));
1540 if (!empty($pi['filename'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars($pi['filename']).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1643 if (!empty($pi['filename'])) return array('src'=>'http://i.imgur.com/'.$pi['filename'].'s.jpg',
1644 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1541 } 1645 }
1542 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') 1646 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com')
1543 { 1647 {
1544 if (strpos($url,'dailymotion.com/video/')!==false) 1648 if (strpos($url,'dailymotion.com/video/')!==false)
1545 { 1649 {
1546 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); 1650 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url);
1547 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="DailyMotion thumbnail"></a>'; 1651 return array('src'=>$thumburl,
1652 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail');
1548 } 1653 }
1549 } 1654 }
1550 if (endsWith($domain,'.imageshack.us')) 1655 if (endsWith($domain,'.imageshack.us'))
@@ -1553,7 +1658,8 @@ function thumbnail($url,$href=false)
1553 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1658 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1554 { 1659 {
1555 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; 1660 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext;
1556 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="imageshack.us thumbnail"></a>'; 1661 return array('src'=>$thumburl,
1662 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail');
1557 } 1663 }
1558 } 1664 }
1559 1665
@@ -1561,7 +1667,7 @@ function thumbnail($url,$href=false)
1561 // So we deport the thumbnail generation in order not to slow down page generation 1667 // So we deport the thumbnail generation in order not to slow down page generation
1562 // (and we also cache the thumbnail) 1668 // (and we also cache the thumbnail)
1563 1669
1564 if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return ''; // If local cache is disabled, no thumbnails for services which require the use a local cache. 1670 if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache.
1565 1671
1566 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') 1672 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')
1567 || $domain=='vimeo.com' 1673 || $domain=='vimeo.com'
@@ -1572,20 +1678,21 @@ function thumbnail($url,$href=false)
1572 if ($domain=='vimeo.com') 1678 if ($domain=='vimeo.com')
1573 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) 1679 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric)
1574 $path = parse_url($url,PHP_URL_PATH); 1680 $path = parse_url($url,PHP_URL_PATH);
1575 if (!preg_match('!/\d+.+?!',$path)) return ''; // This is not a single video URL. 1681 if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL.
1576 } 1682 }
1577 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) 1683 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
1578 { // Make sure this url points to a single comic (/xxx... where xxx is numeric) 1684 { // Make sure this url points to a single comic (/xxx... where xxx is numeric)
1579 $path = parse_url($url,PHP_URL_PATH); 1685 $path = parse_url($url,PHP_URL_PATH);
1580 if (!preg_match('!/\d+.+?!',$path)) return ''; 1686 if (!preg_match('!/\d+.+?!',$path)) return array();
1581 } 1687 }
1582 if ($domain=='ted.com' || endsWith($domain,'.ted.com')) 1688 if ($domain=='ted.com' || endsWith($domain,'.ted.com'))
1583 { // Make sure this TED url points to a video (/talks/...) 1689 { // Make sure this TED url points to a video (/talks/...)
1584 $path = parse_url($url,PHP_URL_PATH); 1690 $path = parse_url($url,PHP_URL_PATH);
1585 if ("/talks/" !== substr($path,0,7)) return ''; // This is not a single video URL. 1691 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
1586 } 1692 }
1587 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1693 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1588 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;" alt="thumbnail"></a>'; 1694 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
1695 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1589 } 1696 }
1590 1697
1591 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif 1698 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif
@@ -1595,12 +1702,68 @@ function thumbnail($url,$href=false)
1595 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1702 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1596 { 1703 {
1597 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1704 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1598 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;"></a>'; 1705 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
1706 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1599 } 1707 }
1600 return ''; // No thumbnail. 1708 return array(); // No thumbnail.
1709
1710}
1711
1712
1713// Returns the HTML code to display a thumbnail for a link
1714// with a link to the original URL.
1715// Understands various services (youtube.com...)
1716// Input: $url = url for which the thumbnail must be found.
1717// $href = if provided, this URL will be followed instead of $url
1718// Returns '' if no thumbnail available.
1719function thumbnail($url,$href=false)
1720{
1721 $t = computeThumbnail($url,$href);
1722 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1723
1724 $html='<a href="'.htmlspecialchars($t['href']).'"><img src="'.htmlspecialchars($t['src']).'"';
1725 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1726 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1727 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1728 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1729 $html.='></a>';
1730 return $html;
1731}
1732
1601 1733
1734// Returns the HTML code to display a thumbnail for a link
1735// for the picture wall (using lazy image loading)
1736// Understands various services (youtube.com...)
1737// Input: $url = url for which the thumbnail must be found.
1738// $href = if provided, this URL will be followed instead of $url
1739// Returns '' if no thumbnail available.
1740function lazyThumbnail($url,$href=false)
1741{
1742 $t = computeThumbnail($url,$href);
1743 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1744
1745 $html='<a href="'.htmlspecialchars($t['href']).'">';
1746
1747 // Lazy image (only loaded by javascript when in the viewport).
1748 $html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
1749 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1750 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1751 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1752 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1753 $html.='>';
1754
1755 // No-javascript fallback:
1756 $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"';
1757 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1758 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1759 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1760 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1761 $html.='></noscript></a>';
1762
1763 return $html;
1602} 1764}
1603 1765
1766
1604// ----------------------------------------------------------------------------------------------- 1767// -----------------------------------------------------------------------------------------------
1605// Installation 1768// Installation
1606// This function should NEVER be called if the file data/config.php exists. 1769// This function should NEVER be called if the file data/config.php exists.
@@ -1861,11 +2024,11 @@ function genThumbnail()
1861 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page 2024 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page
1862 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html 2025 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html
1863 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" /> 2026 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" />
1864 list($httpstatus,$headers,$data) = getHTTP($url,5); 2027 list($httpstatus,$headers,$data) = getHTTP($url,5);
1865 if (strpos($httpstatus,'200 OK')!==false) 2028 if (strpos($httpstatus,'200 OK')!==false)
1866 { 2029 {
1867 // Extract the link to the thumbnail 2030 // Extract the link to the thumbnail
1868 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)[^s]!',$data,$matches); 2031 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!',$data,$matches);
1869 if (!empty($matches[1])) 2032 if (!empty($matches[1]))
1870 { // Let's download the image. 2033 { // Let's download the image.
1871 $imageurl=$matches[1]; 2034 $imageurl=$matches[1];
@@ -1982,6 +2145,7 @@ if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=g
1982$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). 2145$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
1983if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI) 2146if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI)
1984if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; 2147if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE'];
2148if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=dailyrss')) { showDailyRSS(); exit; }
1985if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } 2149if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; }
1986if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } 2150if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }
1987renderPage(); 2151renderPage();
diff --git a/tpl/daily.html b/tpl/daily.html
index 9ee74739..bdaf2032 100644
--- a/tpl/daily.html
+++ b/tpl/daily.html
@@ -7,14 +7,15 @@
7 <div class="dailyAbout"> 7 <div class="dailyAbout">
8 All links of one day<br>in a single page.<br> 8 All links of one day<br>in a single page.<br>
9 <a href="?do=daily&day={$previousday}"><b>&lt;</b>Previous day</a> - 9 <a href="?do=daily&day={$previousday}"><b>&lt;</b>Previous day</a> -
10 <a href="?do=daily&day={$nextday}">Next day<b>&gt;</b></a> 10 <a href="?do=daily&day={$nextday}">Next day<b>&gt;</b></a><br><br>
11 <a href="?do=dailyrss" title="1 RSS entry per day"><img src="images/feed-icon-14x14.png#" width="14" height="14" style="position:relative;top:3px; margin-right:4px;">Daily RSS Feed</a>
11 </div> 12 </div>
12 <div class="dailyTitle"><img src="../images/floral_left.png" width="51" height="50"> The Shaarli Daily <img src="../images/floral_right.png" width="51" height="50"></div> 13 <div class="dailyTitle"><img src="../images/floral_left.png" width="51" height="50" class="nomobile"> The Shaarli Daily <img src="../images/floral_right.png" width="51" height="50" class="nomobile"></div>
13 <div class="dailyDate">&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097; {$day} &#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;</div> 14 <div class="dailyDate"><span class="nomobile">&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;</span> {$day} <span class="nomobile">&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;&#x0097;</span></div>
14 <div style="clear:both;"></div> 15 <div style="clear:both;"></div>
15 16
16 {if="$linksToDisplay"} 17 {if="$linksToDisplay"}
17 <div style="float:left;position:relative; width:33%; padding-left:1%;"> 18 <div id="daily_col1">
18 {loop="col1"} 19 {loop="col1"}
19 <div class="dailyEntry"> 20 <div class="dailyEntry">
20 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div> 21 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div>
@@ -26,7 +27,7 @@
26 {/loop} 27 {/loop}
27 </div> 28 </div>
28 29
29 <div style="float:left;position:relative; width:33%;"> 30 <div id="daily_col2">
30 {loop="col2"} 31 {loop="col2"}
31 <div class="dailyEntry"> 32 <div class="dailyEntry">
32 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div> 33 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div>
@@ -38,7 +39,7 @@
38 {/loop} 39 {/loop}
39 </div> 40 </div>
40 41
41 <div style="float:left;position:relative; width:33%;"> 42 <div id="daily_col3">
42 {loop="col3"} 43 {loop="col3"}
43 <div class="dailyEntry"> 44 <div class="dailyEntry">
44 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div> 45 <div style="float:right;position:relative;top:-1px;"><a href="?{$value.linkdate|smallHash}"><img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"></a></div>
diff --git a/tpl/dailyrss.html b/tpl/dailyrss.html
new file mode 100644
index 00000000..436e1cd2
--- /dev/null
+++ b/tpl/dailyrss.html
@@ -0,0 +1,8 @@
1{loop="links"}
2 <h3><a href="{$value.url}">{$value.title|htmlspecialchars}</a></h3>
3 <small>{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{$value.localdate|htmlspecialchars} - {/if}{if="$value.tags"}{$value.tags|htmlspecialchars}{/if}<br>
4 {$value.url|htmlspecialchars}</small><br>
5 {if="$value.thumbnail"}{$value.thumbnail}{/if}<br>
6 {if="$value.description"}{$value.formatedDescription}{/if}
7 <br><br><hr>
8{/loop} \ No newline at end of file
diff --git a/tpl/includes.html b/tpl/includes.html
index 7cfb07f2..5319f452 100644
--- a/tpl/includes.html
+++ b/tpl/includes.html
@@ -1,5 +1,7 @@
1<title>{$pagetitle}</title> 1<title>{$pagetitle}</title>
2<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 2<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3<meta name="format-detection" content="telephone=no" />
4<meta name="viewport" content="width=device-width,initial-scale=1.0" />
3<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" /> 5<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" />
4<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" /> 6<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
5<link href="images/favicon.ico#" rel="shortcut icon" type="image/x-icon" /> 7<link href="images/favicon.ico#" rel="shortcut icon" type="image/x-icon" />
diff --git a/tpl/linklist.html b/tpl/linklist.html
index dc5b5398..1067d6fc 100644
--- a/tpl/linklist.html
+++ b/tpl/linklist.html
@@ -5,8 +5,8 @@
5<div id="pageheader"> 5<div id="pageheader">
6 {include="page.header"} 6 {include="page.header"}
7 <div id="headerform" style="width:100%; white-space:nowrap;"> 7 <div id="headerform" style="width:100%; white-space:nowrap;">
8 <form method="GET" class="searchform" name="searchform" style="display:inline;"><input type="text" name="searchterm" style="width:30%" value=""> <input type="submit" value="Search" class="bigbutton"></form> 8 <form method="GET" class="searchform" name="searchform" style="display:inline;"><input type="text" id="searchform_value" name="searchterm" style="width:30%" value=""> <input type="submit" value="Search" class="bigbutton"></form>
9 <form method="GET" class="tagfilter" name="tagfilter" style="display:inline;margin-left:24px;"><input type="text" name="searchtags" id="searchtags" style="width:10%" value=""> <input type="submit" value="Filter by tag" class="bigbutton"></form> 9 <form method="GET" class="tagfilter" name="tagfilter" style="display:inline;margin-left:24px;"><input type="text" name="searchtags" id="tagfilter_value" style="width:10%" value=""> <input type="submit" value="Filter by tag" class="bigbutton"></form>
10 </div> 10 </div>
11</div> 11</div>
12 12
@@ -60,16 +60,14 @@
60 60
61 {include="page.footer"} 61 {include="page.footer"}
62<script> 62<script>
63$('a.qrcode').click(function(){ 63$(document).ready(function() {
64 hide_qrcode(); 64 $('a.qrcode').click(function(){
65 var link = $(this).attr('href'); 65 hide_qrcode();
66 $(this).after('<div class="qrcode" onclick="hide_qrcode();return false;"><img src="'+link+'#" width="200" height="200"><br>click to close</div>'); 66 var link = $(this).attr('href');
67 $(this).after('<div class="qrcode" onclick="hide_qrcode();return false;"><img src="'+link+'#" width="200" height="200"><br>click to close</div>');
68 });
67}); 69});
68 70function hide_qrcode() { $('div.qrcode').remove(); }
69function hide_qrcode()
70{
71 $('div.qrcode').remove();
72}
73</script> 71</script>
74</body> 72</body>
75</html> \ No newline at end of file 73</html> \ No newline at end of file
diff --git a/tpl/linklist.paging.html b/tpl/linklist.paging.html
index 27e7440d..b1f9871f 100644
--- a/tpl/linklist.paging.html
+++ b/tpl/linklist.paging.html
@@ -1,9 +1,14 @@
1 <div class="paging"> 1<div class="paging">
2 <div style="float:right; padding-right:5px;"> 2{if="isLoggedIn()"}
3 Links per page: <a href="?linksperpage=20">20</a> <a href="?linksperpage=50">50</a> <a href="?linksperpage=100">100</a> 3 <div id="paging_privatelinks">
4 <form method="GET" style="display:inline;" class="linksperpage"><input type="text" name="linksperpage" size="2" style="height:15px;"></form> 4 <a href="?privateonly"><img src="images/private_16x16.png#" width="16" height="16" title="See private links only (toggle)" alt="See private links only (toggle)"></a>
5 </div> 5 </div>
6 {if="$previous_page_url"} <a href="{$previous_page_url}">&#x25C4;Older</a> {/if} 6{/if}
7 <span style="color:#fff; padding:0 20 0 20;">page {$page_current} / {$page_max} </span> 7 <div id="paging_linksperpage">
8 {if="$next_page_url"} <a href="{$next_page_url}">Newer&#x25BA;</a> {/if} 8 Links per page: <a href="?linksperpage=20">20</a> <a href="?linksperpage=50">50</a> <a href="?linksperpage=100">100</a>
9 </div> \ No newline at end of file 9 <form method="GET" style="display:inline;" class="linksperpage"><input type="text" name="linksperpage" size="2" style="height:15px;"></form>
10 </div>
11 {if="$previous_page_url"} <a href="{$previous_page_url}" id="paging_older">&#x25C4;Older</a> {/if}
12 <div id="paging_current">page {$page_current} / {$page_max} </div>
13 {if="$next_page_url"} <a href="{$next_page_url}" id="paging_newer">Newer&#x25BA;</a> {/if}
14</div> \ No newline at end of file
diff --git a/tpl/page.header.html b/tpl/page.header.html
index 0c304367..3ad2f205 100644
--- a/tpl/page.header.html
+++ b/tpl/page.header.html
@@ -1,12 +1,12 @@
1 1
2 <div id="logo" title="Share your links !" onclick="document.location='?';"></div> 2 <div id="logo" title="Share your links !" onclick="document.location='?';"></div>
3 <div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;">Shaare your links...<br>{$linkcount} links</div> 3 <div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;" class="nomobile">Shaare your links...<br>{$linkcount} links</div>
4 <span id="shaarli_title"><a href="?">{$shaarlititle}</a></span> 4 <span id="shaarli_title"><a href="?">{$shaarlititle}</a></span>
5 5
6{if="!empty($_GET['source']) && $_GET['source']=='bookmarklet'"} 6{if="!empty($_GET['source']) && $_GET['source']=='bookmarklet'"}
7 {ignore} When called as a popup from bookmarklet, do not display menu. {/ignore} 7 {ignore} When called as a popup from bookmarklet, do not display menu. {/ignore}
8{else} 8{else}
9 <a href="?">Home</a> 9 <a href="?" class="nomobile">Home</a>
10 {if="isLoggedIn()"} 10 {if="isLoggedIn()"}
11 <a href="?do=logout">Logout</a><a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a> 11 <a href="?do=logout">Logout</a><a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a>
12 {elseif="$GLOBALS['config']['OPEN_SHAARLI']"} 12 {elseif="$GLOBALS['config']['OPEN_SHAARLI']"}
@@ -14,8 +14,8 @@
14 {else} 14 {else}
15 <a href="?do=login">Login</a> 15 <a href="?do=login">Login</a>
16 {/if} 16 {/if}
17 <a href="{$feedurl}?do=rss{$searchcrits}">RSS Feed</a> 17 <a href="{$feedurl}?do=rss{$searchcrits}" class="nomobile">RSS Feed</a>
18 <a href="{$feedurl}?do=atom{$searchcrits}" style="padding-left:10px;">ATOM Feed</a> 18 <a href="{$feedurl}?do=atom{$searchcrits}" style="padding-left:10px;" class="nomobile">ATOM Feed</a>
19 <a href="?do=tagcloud">Tag cloud</a> 19 <a href="?do=tagcloud">Tag cloud</a>
20 <a href="?do=picwall{$searchcrits}">Picture wall</a> 20 <a href="?do=picwall{$searchcrits}">Picture wall</a>
21 <a href="?do=daily">Daily</a> 21 <a href="?do=daily">Daily</a>
diff --git a/tpl/picwall.html b/tpl/picwall.html
index da6df762..2083a629 100644
--- a/tpl/picwall.html
+++ b/tpl/picwall.html
@@ -1,6 +1,8 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head>{include="includes"}</head> 3<head>{include="includes"}
4<script src="inc/jquery.lazyload.min.js#"></script>
5</head>
4<body> 6<body>
5<div id="pageheader">{include="page.header"}</div> 7<div id="pageheader">{include="page.header"}</div>
6<center> 8<center>
@@ -14,4 +16,9 @@
14</center> 16</center>
15{include="page.footer"} 17{include="page.footer"}
16</body> 18</body>
19<script>
20$(document).ready(function() {
21 $("img.lazyimage").show().lazyload();
22});
23</script>
17</html> \ No newline at end of file 24</html> \ No newline at end of file