mirror of
https://github.com/YunoHost-Apps/shaarli_ynh.git
synced 2024-09-03 20:26:10 +02:00
apply modification for multiuser from https://github.com/Roultabie/Shaarli
This commit is contained in:
parent
edadc45397
commit
1890330cc0
11 changed files with 462 additions and 69 deletions
BIN
sources/images/contributor.png
Normal file
BIN
sources/images/contributor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 541 B |
108
sources/inc/jquery.highlight.js
Normal file
108
sources/inc/jquery.highlight.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* jQuery Highlight plugin
|
||||||
|
*
|
||||||
|
* Based on highlight v3 by Johann Burkard
|
||||||
|
* http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
|
||||||
|
*
|
||||||
|
* Code a little bit refactored and cleaned (in my humble opinion).
|
||||||
|
* Most important changes:
|
||||||
|
* - has an option to highlight only entire words (wordsOnly - false by default),
|
||||||
|
* - has an option to be case sensitive (caseSensitive - false by default)
|
||||||
|
* - highlight element tag and class names can be specified in options
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* // wrap every occurrance of text 'lorem' in content
|
||||||
|
* // with <span class='highlight'> (default options)
|
||||||
|
* $('#content').highlight('lorem');
|
||||||
|
*
|
||||||
|
* // search for and highlight more terms at once
|
||||||
|
* // so you can save some time on traversing DOM
|
||||||
|
* $('#content').highlight(['lorem', 'ipsum']);
|
||||||
|
* $('#content').highlight('lorem ipsum');
|
||||||
|
*
|
||||||
|
* // search only for entire word 'lorem'
|
||||||
|
* $('#content').highlight('lorem', { wordsOnly: true });
|
||||||
|
*
|
||||||
|
* // don't ignore case during search of term 'lorem'
|
||||||
|
* $('#content').highlight('lorem', { caseSensitive: true });
|
||||||
|
*
|
||||||
|
* // wrap every occurrance of term 'ipsum' in content
|
||||||
|
* // with <em class='important'>
|
||||||
|
* $('#content').highlight('ipsum', { element: 'em', className: 'important' });
|
||||||
|
*
|
||||||
|
* // remove default highlight
|
||||||
|
* $('#content').unhighlight();
|
||||||
|
*
|
||||||
|
* // remove custom highlight
|
||||||
|
* $('#content').unhighlight({ element: 'em', className: 'important' });
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Bartek Szopka
|
||||||
|
*
|
||||||
|
* Licensed under MIT license.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
jQuery.extend({
|
||||||
|
highlight: function (node, re, nodeName, className) {
|
||||||
|
if (node.nodeType === 3) {
|
||||||
|
var match = node.data.match(re);
|
||||||
|
if (match) {
|
||||||
|
var highlight = document.createElement(nodeName || 'span');
|
||||||
|
highlight.className = className || 'highlight';
|
||||||
|
var wordNode = node.splitText(match.index);
|
||||||
|
wordNode.splitText(match[0].length);
|
||||||
|
var wordClone = wordNode.cloneNode(true);
|
||||||
|
highlight.appendChild(wordClone);
|
||||||
|
wordNode.parentNode.replaceChild(highlight, wordNode);
|
||||||
|
return 1; //skip added node in parent
|
||||||
|
}
|
||||||
|
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
|
||||||
|
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
|
||||||
|
!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
|
||||||
|
for (var i = 0; i < node.childNodes.length; i++) {
|
||||||
|
i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.fn.unhighlight = function (options) {
|
||||||
|
var settings = { className: 'highlight', element: 'span' };
|
||||||
|
jQuery.extend(settings, options);
|
||||||
|
|
||||||
|
return this.find(settings.element + "." + settings.className).each(function () {
|
||||||
|
var parent = this.parentNode;
|
||||||
|
parent.replaceChild(this.firstChild, this);
|
||||||
|
parent.normalize();
|
||||||
|
}).end();
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery.fn.highlight = function (words, options) {
|
||||||
|
var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
|
||||||
|
jQuery.extend(settings, options);
|
||||||
|
|
||||||
|
if (words.constructor === String) {
|
||||||
|
words = [words];
|
||||||
|
}
|
||||||
|
words = jQuery.grep(words, function(word, i){
|
||||||
|
return word != '';
|
||||||
|
});
|
||||||
|
words = jQuery.map(words, function(word, i) {
|
||||||
|
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||||
|
});
|
||||||
|
if (words.length == 0) { return this; };
|
||||||
|
|
||||||
|
var flag = settings.caseSensitive ? "" : "i";
|
||||||
|
var pattern = "(" + words.join("|") + ")";
|
||||||
|
if (settings.wordsOnly) {
|
||||||
|
pattern = "\\b" + pattern + "\\b";
|
||||||
|
}
|
||||||
|
var re = new RegExp(pattern, flag);
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
jQuery.highlight(this, re, settings.element, settings.className);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ version: 2.8.2r1
|
||||||
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}
|
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}
|
||||||
|
|
||||||
body { font-family: "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; font-size:10pt; background-color: #ffffff; }
|
body { font-family: "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; font-size:10pt; background-color: #ffffff; }
|
||||||
input, textarea {
|
input, textarea, select {
|
||||||
background-color: #dedede;
|
background-color: #dedede;
|
||||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dedede), to(#ffffff));
|
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dedede), to(#ffffff));
|
||||||
background: -webkit-linear-gradient(#dedede, #ffffff);
|
background: -webkit-linear-gradient(#dedede, #ffffff);
|
||||||
|
@ -227,6 +227,7 @@ cursor:pointer;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
#linklist li.private { background: url('../images/private.png') no-repeat 10px center; padding-left:60px; }
|
#linklist li.private { background: url('../images/private.png') no-repeat 10px center; padding-left:60px; }
|
||||||
|
#linklist li.contributor { background: url('../images/contributor.png') no-repeat 10px center; padding-left:60px; }
|
||||||
#linklist li { padding-left:26px; }
|
#linklist li { padding-left:26px; }
|
||||||
.private .linktitle a {color:#969696;}
|
.private .linktitle a {color:#969696;}
|
||||||
.linktitle { font-size:14pt; font-weight:bold; }
|
.linktitle { font-size:14pt; font-weight:bold; }
|
||||||
|
@ -236,6 +237,7 @@ cursor:pointer;
|
||||||
.linkdate a { background-image:url('../images/calendar.png');padding:2px 0 3px 20px;background-repeat:no-repeat;text-decoration: none; color:#E28E3F; }
|
.linkdate a { background-image:url('../images/calendar.png');padding:2px 0 3px 20px;background-repeat:no-repeat;text-decoration: none; color:#E28E3F; }
|
||||||
.linkdate a:hover { color: #F57900 }
|
.linkdate a:hover { color: #F57900 }
|
||||||
.linkurl { font-size:8pt; color:#4BAA74; }
|
.linkurl { font-size:8pt; color:#4BAA74; }
|
||||||
|
.linkauthor { font-size:8pt; color:#4BAA74; font-style: italic;}
|
||||||
.linkdescription { color:#000; margin-top:0; margin-bottom:12px; font-weight:normal; max-height:400px; overflow:auto; }
|
.linkdescription { color:#000; margin-top:0; margin-bottom:12px; font-weight:normal; max-height:400px; overflow:auto; }
|
||||||
.linkdescription a { text-decoration: none; color:#3465A4; }
|
.linkdescription a { text-decoration: none; color:#3465A4; }
|
||||||
.linkdescription a:hover { color:#F57900; }
|
.linkdescription a:hover { color:#F57900; }
|
||||||
|
@ -464,3 +466,76 @@ div.dailyEntryDescription { font-size:10pt; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Highlight search results */
|
||||||
|
.highlight { background-color: #FFFF33; }
|
||||||
|
|
||||||
|
/* Manage users */
|
||||||
|
#manageusers {
|
||||||
|
margin: 10px 10px 10px 0px;
|
||||||
|
}
|
||||||
|
#manageusers form {
|
||||||
|
width: 170px;
|
||||||
|
float: left;
|
||||||
|
margin-left: 15px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: linear-gradient(#555555, #222222);
|
||||||
|
border-radius: 5px 5px 5px 5px;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: -1px 2px 5px 1px rgba(0, 0, 0, 0.7),
|
||||||
|
-1px 2px 15px rgba(255, 255, 255, 0.4) inset;
|
||||||
|
}
|
||||||
|
#manageusers .sysadmin {
|
||||||
|
background-color: #555555;
|
||||||
|
background-image: repeating-linear-gradient(135deg, transparent, transparent 20px, rgba(255,255,255,.5) 20px, rgba(255,255,255,.5) 40px);
|
||||||
|
}
|
||||||
|
#manageusers #createuserbadge {
|
||||||
|
padding-bottom: 11px;
|
||||||
|
background: linear-gradient(#777777, #444444);
|
||||||
|
}
|
||||||
|
#manageusers h4 {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
#manageusers select, #manageusers input {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
#manageusers select {
|
||||||
|
width: 170px;
|
||||||
|
height: 25px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#manageusers input[type=text] {
|
||||||
|
width: 160px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#manageusers input[type=submit] {
|
||||||
|
font-style: italic;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#manageusers input[type=submit]:disabled {
|
||||||
|
font-style: italic;
|
||||||
|
color: grey;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
#manageusers input[type=submit]:hover {
|
||||||
|
box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.3) inset;
|
||||||
|
}
|
||||||
|
#manageusers input[type=submit]:disabled {
|
||||||
|
box-shadow: 0px 0px 0px rgba(255, 255, 255, 0) inset;
|
||||||
|
}
|
||||||
|
#manageusers .updateuser {
|
||||||
|
width: 170px;
|
||||||
|
background: linear-gradient(#2b552e, #112212);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
#manageusers .smallsubmit {
|
||||||
|
width: 83px;
|
||||||
|
}
|
||||||
|
#manageusers .resetpassword {
|
||||||
|
background: linear-gradient(#555555, #222222);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
#manageusers .deleteuser {
|
||||||
|
background: linear-gradient(#552b2b, #221111);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
|
@ -5,6 +5,11 @@
|
||||||
// Licence: http://www.opensource.org/licenses/zlib-license.php
|
// Licence: http://www.opensource.org/licenses/zlib-license.php
|
||||||
// Requires: php 5.1.x (but autocomplete fields will only work if you have php 5.2.x)
|
// Requires: php 5.1.x (but autocomplete fields will only work if you have php 5.2.x)
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
|
// NEVER TRUST IN PHP.INI
|
||||||
|
// Some hosts do not define a default timezone in php.ini,
|
||||||
|
// so we have to do this for avoid the strict standard error.
|
||||||
|
date_default_timezone_set('UTC');
|
||||||
|
// -----------------------------------------------------------------------------------------------
|
||||||
// Hardcoded parameter (These parameters can be overwritten by creating the file /config/options.php)
|
// Hardcoded parameter (These parameters can be overwritten by creating the file /config/options.php)
|
||||||
$GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory
|
$GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory
|
||||||
$GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password)
|
$GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password)
|
||||||
|
@ -15,6 +20,7 @@ $GLOBALS['config']['BAN_AFTER'] = 4; // Ban IP after this many failures.
|
||||||
$GLOBALS['config']['BAN_DURATION'] = 1800; // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes)
|
$GLOBALS['config']['BAN_DURATION'] = 1800; // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes)
|
||||||
$GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login
|
$GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login
|
||||||
$GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in.
|
$GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in.
|
||||||
|
$GLOBALS['config']['HIDE_QRCODE'] = false; // If true, qrcodes are not shown.
|
||||||
$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links.
|
$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links.
|
||||||
$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr)
|
$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr)
|
||||||
$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory.
|
$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory.
|
||||||
|
@ -23,6 +29,13 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty
|
||||||
$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli.
|
$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli.
|
||||||
$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours
|
$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours
|
||||||
// Note: You must have publisher.php in the same directory as Shaarli index.php
|
// Note: You must have publisher.php in the same directory as Shaarli index.php
|
||||||
|
// // -----------------------------------------------------------------------------------------------
|
||||||
|
// Levels for multi users
|
||||||
|
$GLOBALS['level']['administrator'] = 4;
|
||||||
|
$GLOBALS['level']['moderator'] = 3;
|
||||||
|
$GLOBALS['level']['contributor'] = 2;
|
||||||
|
$GLOBALS['level']['reader'] = 1;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
// You should not touch below (or at your own risks !)
|
// You should not touch below (or at your own risks !)
|
||||||
// Optionnal config file.
|
// Optionnal config file.
|
||||||
|
@ -103,7 +116,7 @@ if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=fa
|
||||||
if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install();
|
if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install();
|
||||||
|
|
||||||
require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS.
|
require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS.
|
||||||
|
define('SHAARLI_OWNER', $GLOBALS['login'][0]);
|
||||||
|
|
||||||
autoLocale(); // Sniff browser language and set date format accordingly.
|
autoLocale(); // Sniff browser language and set date format accordingly.
|
||||||
header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling.
|
header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling.
|
||||||
|
@ -292,19 +305,26 @@ function allIPs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that user/password is correct.
|
// Check that user/password is correct.
|
||||||
function check_auth($login,$password)
|
function check_auth($username,$password)
|
||||||
{
|
{
|
||||||
$hash = sha1($password.$login.$GLOBALS['salt']);
|
//$currentHash = sha1($password.$username.$GLOBALS['salt']);
|
||||||
if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash'])
|
if (is_array($GLOBALS['login']))
|
||||||
{ // Login/password is correct.
|
{
|
||||||
$_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
|
if (in_array($username, $GLOBALS['login'])) {
|
||||||
$_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked.
|
if ($GLOBALS['password'][$username] === sha1($password . $username . $GLOBALS['salt'])) {
|
||||||
$_SESSION['username']=$login;
|
// Login/password is correct.
|
||||||
$_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration.
|
$_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
|
||||||
logm('Login successful');
|
$_SESSION['ip'] = allIPs(); // We store IP address(es) of the client to make sure session is not hijacked.
|
||||||
return True;
|
$_SESSION['username'] = $username;
|
||||||
|
$_SESSION['level'] = $GLOBALS['level'][$username];
|
||||||
|
$_SESSION['email'] = $GLOBALS['email'][$username];
|
||||||
|
$_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration.
|
||||||
|
logm('Login successful');
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logm('Login failed for user '.$login);
|
logm('Login failed for user '.$username);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +348,7 @@ function isLoggedIn()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force logout.
|
// Force logout.
|
||||||
function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['privateonly']); } }
|
function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['level']); unset($_SESSION['privateonly']); } }
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
|
@ -636,6 +656,7 @@ class pageBuilder
|
||||||
$this->tpl->assign('version',shaarli_version);
|
$this->tpl->assign('version',shaarli_version);
|
||||||
$this->tpl->assign('scripturl',indexUrl());
|
$this->tpl->assign('scripturl',indexUrl());
|
||||||
$this->tpl->assign('pagetitle','Shaarli');
|
$this->tpl->assign('pagetitle','Shaarli');
|
||||||
|
$this->tpl->assign('shaarliOwner', SHAARLI_OWNER);
|
||||||
$this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
|
$this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
|
||||||
if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
|
if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
|
||||||
if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
|
if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
|
||||||
|
@ -647,6 +668,7 @@ class pageBuilder
|
||||||
public function assign($what,$where)
|
public function assign($what,$where)
|
||||||
{
|
{
|
||||||
if ($this->tpl===false) $this->initialize(); // Lazy initialization
|
if ($this->tpl===false) $this->initialize(); // Lazy initialization
|
||||||
|
$this->initializeUser();
|
||||||
$this->tpl->assign($what,$where);
|
$this->tpl->assign($what,$where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,6 +679,28 @@ class pageBuilder
|
||||||
if ($this->tpl===false) $this->initialize(); // Lazy initialization
|
if ($this->tpl===false) $this->initialize(); // Lazy initialization
|
||||||
$this->tpl->draw($page);
|
$this->tpl->draw($page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function initializeUser()
|
||||||
|
{
|
||||||
|
if (!empty($_SESSION['username'])) {
|
||||||
|
$this->tpl->assign('currentUser',$_SESSION['username']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->tpl->assign('currentUser','');
|
||||||
|
}
|
||||||
|
if (!empty($_SESSION['level'])) {
|
||||||
|
$this->tpl->assign('currentUserLevel',$_SESSION['level']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->tpl->assign('currentUserLevel','');
|
||||||
|
}
|
||||||
|
if (!empty($_SESSION['email'])) {
|
||||||
|
$this->tpl->assign('currentUserEmail',$_SESSION['email']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->tpl->assign('currentUserEmail','');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
|
@ -688,6 +732,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
|
||||||
private $keys; // List of linkdate keys (for the Iterator interface implementation)
|
private $keys; // List of linkdate keys (for the Iterator interface implementation)
|
||||||
private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
|
private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
|
||||||
private $loggedin; // Is the used logged in ? (used to filter private links)
|
private $loggedin; // Is the used logged in ? (used to filter private links)
|
||||||
|
public static $editLink; // If user edit link (preserve private links)
|
||||||
|
|
||||||
// Constructor:
|
// Constructor:
|
||||||
function __construct($isLoggedIn)
|
function __construct($isLoggedIn)
|
||||||
|
@ -732,9 +777,11 @@ class linkdb implements Iterator, Countable, ArrayAccess
|
||||||
if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
|
if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
|
||||||
{
|
{
|
||||||
$this->links = array();
|
$this->links = array();
|
||||||
$link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software');
|
$link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','author'=>SHAARLI_OWNER, 'private'=>'0','linkdate'=>'20110914_190000','tags'=>'opensource software');
|
||||||
$this->links[$link['linkdate']] = $link;
|
$this->links[$link['linkdate']] = $link;
|
||||||
$link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://pastebin.com/smCEEeSn','description'=>'SShhhh!! I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff');
|
$link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://pastebin.com/smCEEeSn','description'=>'SShhhh!! I\'m a private link only YOU can see. You can delete me too.','author'=>SHAARLI_OWNER, 'private'=>'2','linkdate'=>'20110914_074522','tags'=>'secretstuff');
|
||||||
|
$this->links[$link['linkdate']] = $link;
|
||||||
|
$link = array('title'=>'Contributor link','url'=>'http://sebsauvage.net','description'=>'Here is a link viewed only by contributors and logged user.','author'=>SHAARLI_OWNER, 'private'=>'1','linkdate'=>'20111007_233200','tags'=>'contributor link');
|
||||||
$this->links[$link['linkdate']] = $link;
|
$this->links[$link['linkdate']] = $link;
|
||||||
file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
|
file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
|
||||||
}
|
}
|
||||||
|
@ -744,17 +791,29 @@ class linkdb implements Iterator, Countable, ArrayAccess
|
||||||
private function readdb()
|
private function readdb()
|
||||||
{
|
{
|
||||||
// Read data
|
// Read data
|
||||||
$this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
|
$links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
|
||||||
// Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439
|
// Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439
|
||||||
|
|
||||||
// If user is not logged in, filter private links.
|
// If user is not logged in, filter private links.
|
||||||
if (!$this->loggedin)
|
if (!$this->loggedin)
|
||||||
{
|
{
|
||||||
$toremove=array();
|
$toremove=array();
|
||||||
foreach($this->links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
|
foreach($links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
|
||||||
foreach($toremove as $linkdate) { unset($this->links[$linkdate]); }
|
foreach($toremove as $linkdate) { unset($links[$linkdate]); }
|
||||||
|
$this->links = $links;
|
||||||
|
}
|
||||||
|
// If user edit a link, preserve private links of others.
|
||||||
|
elseif (self::$editLink)
|
||||||
|
{
|
||||||
|
$this->links = $links;
|
||||||
|
}
|
||||||
|
// If user is logged in, filter private links.
|
||||||
|
else {
|
||||||
|
$toremove=array();
|
||||||
|
foreach($links as $link) { if ($link['private']!=0 && ($link['private']==2 && $link['author'] != $_SESSION['username'])) $toremove[]=$link['linkdate']; }
|
||||||
|
foreach($toremove as $linkdate) { unset($links[$linkdate]); }
|
||||||
|
$this->links = $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the list of the mapping URLs-->linkdate up-to-date.
|
// Keep the list of the mapping URLs-->linkdate up-to-date.
|
||||||
$this->urls=array();
|
$this->urls=array();
|
||||||
foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
|
foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
|
||||||
|
@ -764,7 +823,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
|
||||||
public function savedb()
|
public function savedb()
|
||||||
{
|
{
|
||||||
if (!$this->loggedin) die('You are not authorized to change the database.');
|
if (!$this->loggedin) die('You are not authorized to change the database.');
|
||||||
file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX);
|
file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX, LOCK_EX);
|
||||||
invalidateCaches();
|
invalidateCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,8 +1225,8 @@ function showDaily()
|
||||||
// Render HTML page (according to URL parameters and user rights)
|
// Render HTML page (according to URL parameters and user rights)
|
||||||
function renderPage()
|
function renderPage()
|
||||||
{
|
{
|
||||||
|
if (isset($_POST['save_edit'])) linkdb::$editLink = TRUE;
|
||||||
$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
|
$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
|
||||||
|
|
||||||
// -------- Display login form.
|
// -------- Display login form.
|
||||||
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login'))
|
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login'))
|
||||||
{
|
{
|
||||||
|
@ -1335,11 +1394,11 @@ function renderPage()
|
||||||
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
|
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
|
||||||
|
|
||||||
// Make sure old password is correct.
|
// Make sure old password is correct.
|
||||||
$oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']);
|
$oldhash = sha1($_POST['oldpassword'].$_SESSION['username'].$GLOBALS['salt']);
|
||||||
if ($oldhash!=$GLOBALS['hash']) { echo '<script language="JavaScript">alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; }
|
if ($oldhash != $GLOBALS['password'][$_SESSION['username']]) { echo '<script language="JavaScript">alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; }
|
||||||
// Save new password
|
// Save new password
|
||||||
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
|
//$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
|
||||||
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
|
$GLOBALS['password'][$_SESSION['username']] = sha1($_POST['setpassword'].$_SESSION['username'].$GLOBALS['salt']);
|
||||||
writeConfig();
|
writeConfig();
|
||||||
echo '<script language="JavaScript">alert("Your password has been changed.");document.location=\'?do=tools\';</script>';
|
echo '<script language="JavaScript">alert("Your password has been changed.");document.location=\'?do=tools\';</script>';
|
||||||
exit;
|
exit;
|
||||||
|
@ -1354,6 +1413,59 @@ function renderPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------- User wants to manage users.
|
||||||
|
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=users')) {
|
||||||
|
$PAGE = new pageBuilder;
|
||||||
|
foreach ($GLOBALS['login'] as $key => $username) {
|
||||||
|
if ($key === 0) $users[$key]['sysAdmin'] = TRUE;
|
||||||
|
else $users[$key]['sysAdmin'] = FALSE;
|
||||||
|
$users[$key]['username'] = $username;
|
||||||
|
$users[$key]['level'] = $GLOBALS['level'][$username];
|
||||||
|
$users[$key]['email'] = $GLOBALS['email'][$username];
|
||||||
|
}
|
||||||
|
$PAGE->assign('users', $users);
|
||||||
|
$PAGE->renderPage('manageusers');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Create / Editing user.
|
||||||
|
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=saveUser')) {
|
||||||
|
$saveUserMessage = 'user successfully updated !';
|
||||||
|
if (isset($_GET['deleteUser'])) {
|
||||||
|
if (is_array($GLOBALS['login'])) {
|
||||||
|
if (in_array($_GET['username'], $GLOBALS['login'])) {
|
||||||
|
$sUkey = array_search($_GET['username'], $GLOBALS['login']);
|
||||||
|
if ($sUkey !== 0) {
|
||||||
|
unset($GLOBALS['login'][$sUkey], $GLOBALS['password'][$_GET['username']],
|
||||||
|
$GLOBALS['level'][$_GET['username']], $GLOBALS['email'][$_GET['username']]);
|
||||||
|
$GLOBALS['login'] = array_values($GLOBALS['login']);
|
||||||
|
writeConfig();
|
||||||
|
echo '<script language="JavaScript">alert("' . $_GET['username'] . ' was deleted.");document.location=\'?do=users\';</script>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (is_array($GLOBALS['login'])) {
|
||||||
|
if (!in_array($_GET['username'], $GLOBALS['login'])) {
|
||||||
|
$newUserKey = count($GLOBALS['login']);
|
||||||
|
$newUser = array($newUserKey => $_GET['username']);
|
||||||
|
$GLOBALS['login'] = $GLOBALS['login'] + $newUser;
|
||||||
|
$saveUserMessage = 'user successfully created !';
|
||||||
|
}
|
||||||
|
if (is_array($newUser) || isset($_GET['resetPassword'])) {
|
||||||
|
$newPassword = smallHash(sha1(uniqid('',true).'_'.mt_rand()));
|
||||||
|
$GLOBALS['password'][$_GET['username']] = sha1($newPassword . $_GET['username'] . $GLOBALS['salt']);
|
||||||
|
$saveUserMessage .= ' His new password is ' . $newPassword;
|
||||||
|
}
|
||||||
|
$GLOBALS['level'][$_GET['username']] = (int) $_GET['userlevel'];
|
||||||
|
$GLOBALS['email'][$_GET['username']] = $_GET['email'];
|
||||||
|
}
|
||||||
|
writeConfig();
|
||||||
|
echo '<script language="JavaScript">alert("' . $saveUserMessage . '");document.location=\'?do=users\';</script>';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// -------- User wants to change configuration
|
// -------- User wants to change configuration
|
||||||
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=configure'))
|
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=configure'))
|
||||||
{
|
{
|
||||||
|
@ -1452,11 +1564,19 @@ function renderPage()
|
||||||
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
|
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
|
||||||
$tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
|
$tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
|
||||||
$linkdate=$_POST['lf_linkdate'];
|
$linkdate=$_POST['lf_linkdate'];
|
||||||
|
// If user is not an admin and try to edit other link of him and keep author when updating link
|
||||||
|
if (isset($LINKSDB[$linkdate])) {
|
||||||
|
if ($_SESSION['level'] < 3 && $LINKSDB[$linkdate]['author'] !== $_SESSION['username']) die('You cannot edit link of other !');
|
||||||
|
$author = $LINKSDB[$linkdate]['author'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$author = $_SESSION['username'];
|
||||||
|
}
|
||||||
$url = trim($_POST['lf_url']);
|
$url = trim($_POST['lf_url']);
|
||||||
if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?'))
|
if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?'))
|
||||||
$url = 'http://'.$url;
|
$url = 'http://'.$url;
|
||||||
$link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),
|
$link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>$_POST['lf_private'],
|
||||||
'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
|
'author' => $author,'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
|
||||||
if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
|
if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
|
||||||
$LINKSDB[$linkdate] = $link;
|
$LINKSDB[$linkdate] = $link;
|
||||||
$LINKSDB->savedb(); // save to disk
|
$LINKSDB->savedb(); // save to disk
|
||||||
|
@ -1489,6 +1609,7 @@ function renderPage()
|
||||||
// - confirmation is handled by javascript
|
// - confirmation is handled by javascript
|
||||||
// - we are protected from XSRF by the token.
|
// - we are protected from XSRF by the token.
|
||||||
$linkdate=$_POST['lf_linkdate'];
|
$linkdate=$_POST['lf_linkdate'];
|
||||||
|
if ($_SESSION['level'] < 3 && $LINKSDB[$linkdate]['author'] !== $_SESSION['username']) die('You cannot delete link of other !');
|
||||||
unset($LINKSDB[$linkdate]);
|
unset($LINKSDB[$linkdate]);
|
||||||
$LINKSDB->savedb(); // save to disk
|
$LINKSDB->savedb(); // save to disk
|
||||||
|
|
||||||
|
@ -1505,6 +1626,7 @@ function renderPage()
|
||||||
{
|
{
|
||||||
$link = $LINKSDB[$_GET['edit_link']]; // Read database
|
$link = $LINKSDB[$_GET['edit_link']]; // Read database
|
||||||
if (!$link) { header('Location: ?'); exit; } // Link not found in database.
|
if (!$link) { header('Location: ?'); exit; } // Link not found in database.
|
||||||
|
if ($_SESSION['level'] < 3 && $LINKSDB[$_GET['edit_link']]['author'] !== $_SESSION['username']) exit; // If user is not an admin and try to edit other link of him
|
||||||
$PAGE = new pageBuilder;
|
$PAGE = new pageBuilder;
|
||||||
$PAGE->assign('linkcount',count($LINKSDB));
|
$PAGE->assign('linkcount',count($LINKSDB));
|
||||||
$PAGE->assign('link',$link);
|
$PAGE->assign('link',$link);
|
||||||
|
@ -1532,7 +1654,7 @@ function renderPage()
|
||||||
$link_is_new = true; // This is a new link
|
$link_is_new = true; // This is a new link
|
||||||
$linkdate = strval(date('Ymd_His'));
|
$linkdate = strval(date('Ymd_His'));
|
||||||
$title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).
|
$title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).
|
||||||
$description=''; $tags=''; $private=0;
|
$description=''; $tags=''; $private=2; $author = $_SESSION['username'];
|
||||||
if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
|
if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
|
||||||
// If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.)
|
// If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.)
|
||||||
if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
|
if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
|
||||||
|
@ -1543,7 +1665,7 @@ function renderPage()
|
||||||
|
|
||||||
}
|
}
|
||||||
if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself)
|
if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself)
|
||||||
$link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0);
|
$link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>2, 'author' => $author);
|
||||||
}
|
}
|
||||||
|
|
||||||
$PAGE = new pageBuilder;
|
$PAGE = new pageBuilder;
|
||||||
|
@ -1784,7 +1906,9 @@ function buildLinkList($PAGE,$LINKSDB)
|
||||||
$link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
|
$link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
|
||||||
$title=$link['title'];
|
$title=$link['title'];
|
||||||
$classLi = $i%2!=0 ? '' : 'publicLinkHightLight';
|
$classLi = $i%2!=0 ? '' : 'publicLinkHightLight';
|
||||||
$link['class'] = ($link['private']==0 ? $classLi : 'private');
|
if ($link['private']==="2") $classLi = 'private';
|
||||||
|
elseif ($link['private']==="1") $classLi = 'contributor';
|
||||||
|
$link['class'] = $classLi;
|
||||||
$link['localdate']=linkdate2locale($link['linkdate']);
|
$link['localdate']=linkdate2locale($link['linkdate']);
|
||||||
$taglist = explode(' ',$link['tags']);
|
$taglist = explode(' ',$link['tags']);
|
||||||
uasort($taglist, 'strcasecmp');
|
uasort($taglist, 'strcasecmp');
|
||||||
|
@ -1979,7 +2103,6 @@ function lazyThumbnail($url,$href=false)
|
||||||
else
|
else
|
||||||
$html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
|
$html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
|
||||||
|
|
||||||
$html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
|
|
||||||
if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
|
if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
|
||||||
if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
|
if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
|
||||||
if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
|
if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
|
||||||
|
@ -1997,6 +2120,27 @@ function lazyThumbnail($url,$href=false)
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------
|
||||||
|
// Create user
|
||||||
|
function createUser($username, $password, $level = '', $email = '')
|
||||||
|
{
|
||||||
|
$currentLogin = array($username);
|
||||||
|
$currentPassword = array($username => sha1($password . $username . $GLOBALS['salt']));
|
||||||
|
$currentLevel = array($username => $level);
|
||||||
|
$currentEmail = array($username => $email);
|
||||||
|
if (is_array($GLOBALS['login'])) {
|
||||||
|
$GLOBALS['login'] = array_merge($GLOBALS['login'], $currentLogin);
|
||||||
|
$GLOBALS['password'] = array_merge($GLOBALS['password'], $currentPassword);
|
||||||
|
$GLOBALS['level'] = array_merge($GLOBALS['level'], $currentLevel);
|
||||||
|
$GLOBALS['email'] = array_merge($GLOBALS['email'] , $currentEmail);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$GLOBALS['login'] = $currentLogin;
|
||||||
|
$GLOBALS['password'] = $currentPassword;
|
||||||
|
$GLOBALS['level'] = $currentLevel;
|
||||||
|
$GLOBALS['email'] = $currentEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
// Installation
|
// Installation
|
||||||
|
@ -2031,18 +2175,19 @@ function install()
|
||||||
if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
|
if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
|
||||||
{
|
{
|
||||||
$tz = 'UTC';
|
$tz = 'UTC';
|
||||||
if (!empty($_POST['continent']) && !empty($_POST['city']))
|
if (!empty($_POST['continent']) && !empty($_POST['city'])) {
|
||||||
if (isTZvalid($_POST['continent'],$_POST['city']))
|
if (isTZvalid($_POST['continent'],$_POST['city'])) {
|
||||||
$tz = $_POST['continent'].'/'.$_POST['city'];
|
$tz = $_POST['continent'].'/'.$_POST['city'];
|
||||||
$GLOBALS['timezone'] = $tz;
|
$GLOBALS['timezone'] = $tz;
|
||||||
// Everything is ok, let's create config file.
|
// Everything is ok, let's create config file.
|
||||||
$GLOBALS['login'] = $_POST['setlogin'];
|
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
|
||||||
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
|
$GLOBALS['title'] = $_POST['settitle'];
|
||||||
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
|
createUser($_POST['setlogin'], $_POST['setpassword'], $GLOBALS['level']['administrator'], $_POST['setemail']);
|
||||||
$GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] );
|
writeConfig();
|
||||||
writeConfig();
|
echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links !");document.location=\'?do=login\';</script>';
|
||||||
echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links !");document.location=\'?do=login\';</script>';
|
exit;
|
||||||
exit;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display config form:
|
// Display config form:
|
||||||
|
@ -2165,13 +2310,20 @@ function processWS()
|
||||||
function writeConfig()
|
function writeConfig()
|
||||||
{
|
{
|
||||||
if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config.
|
if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config.
|
||||||
$config='<?php $GLOBALS[\'login\']='.var_export($GLOBALS['login'],true).'; $GLOBALS[\'hash\']='.var_export($GLOBALS['hash'],true).'; $GLOBALS[\'salt\']='.var_export($GLOBALS['salt'],true).'; ';
|
$config ='<?php' .PHP_EOL;
|
||||||
$config .='$GLOBALS[\'timezone\']='.var_export($GLOBALS['timezone'],true).'; date_default_timezone_set('.var_export($GLOBALS['timezone'],true).'); $GLOBALS[\'title\']='.var_export($GLOBALS['title'],true).';';
|
$config .= '$GLOBALS[\'login\'] = ' . var_export($GLOBALS['login'],true) . ';' . PHP_EOL;
|
||||||
$config .= '$GLOBALS[\'redirector\']='.var_export($GLOBALS['redirector'],true).'; ';
|
$config .= '$GLOBALS[\'password\'] = ' . var_export($GLOBALS['password'],true) . ';' . PHP_EOL;
|
||||||
$config .= '$GLOBALS[\'disablesessionprotection\']='.var_export($GLOBALS['disablesessionprotection'],true).'; ';
|
$config .= '$GLOBALS[\'level\'] = ' . var_export($GLOBALS['level'],true) . ';' . PHP_EOL;
|
||||||
$config .= '$GLOBALS[\'disablejquery\']='.var_export($GLOBALS['disablejquery'],true).'; ';
|
$config .= '$GLOBALS[\'email\'] = ' . var_export($GLOBALS['email'],true) . ';' . PHP_EOL;
|
||||||
$config .= '$GLOBALS[\'privateLinkByDefault\']='.var_export($GLOBALS['privateLinkByDefault'],true).'; ';
|
$config .= '$GLOBALS[\'salt\'] = ' . var_export($GLOBALS['salt'],true) . ';' . PHP_EOL;
|
||||||
$config .= ' ?>';
|
$config .= '$GLOBALS[\'timezone\'] = ' . var_export($GLOBALS['timezone'],true) . ';' . PHP_EOL;
|
||||||
|
$config .= 'date_default_timezone_set(' . var_export($GLOBALS['timezone'],true) . ');' . PHP_EOL;
|
||||||
|
$config .= '$GLOBALS[\'title\'] = '.var_export($GLOBALS['title'],true).';' . PHP_EOL;
|
||||||
|
$config .= '$GLOBALS[\'redirector\'] = '.var_export($GLOBALS['redirector'],true).';' . PHP_EOL;
|
||||||
|
$config .= '$GLOBALS[\'disablesessionprotection\'] = ' . var_export($GLOBALS['disablesessionprotection'],true) . ';' . PHP_EOL;
|
||||||
|
$config .= '$GLOBALS[\'disablejquery\'] = ' . var_export($GLOBALS['disablejquery'],true) . ';' . PHP_EOL;
|
||||||
|
$config .= '$GLOBALS[\'privateLinkByDefault\'] = ' . var_export($GLOBALS['privateLinkByDefault'],true) . ';' . PHP_EOL;
|
||||||
|
$config .= '?>';
|
||||||
if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0)
|
if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0)
|
||||||
{
|
{
|
||||||
echo '<script language="JavaScript">alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>';
|
echo '<script language="JavaScript">alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>';
|
||||||
|
|
|
@ -14,13 +14,12 @@
|
||||||
<i>Title</i><br><input type="text" name="lf_title" value="{$link.title|htmlspecialchars}" style="width:100%"><br>
|
<i>Title</i><br><input type="text" name="lf_title" value="{$link.title|htmlspecialchars}" style="width:100%"><br>
|
||||||
<i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$link.description|htmlspecialchars}</textarea><br>
|
<i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$link.description|htmlspecialchars}</textarea><br>
|
||||||
<i>Tags</i><br><input type="text" id="lf_tags" name="lf_tags" value="{$link.tags|htmlspecialchars}" style="width:100%"><br>
|
<i>Tags</i><br><input type="text" id="lf_tags" name="lf_tags" value="{$link.tags|htmlspecialchars}" style="width:100%"><br>
|
||||||
{if condition="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"}
|
<label for="lf_private"><i>State of your link</i></label><br>
|
||||||
<input type="checkbox" checked="checked" name="lf_private" id="lf_private">
|
<select name="lf_private" id="lf_private">
|
||||||
<label for="lf_private"><i>Private</i></label><br>
|
<option value="2"{if condition="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == 2"} selected{/if}>Private</option>
|
||||||
{else}
|
<option value="1"{if condition="$link.private == 1"} selected{/if}>Collaborators</option>
|
||||||
<input type="checkbox" name="lf_private" id="lf_private">
|
<option value="0">Public</option>
|
||||||
<label for="lf_private"><i>Private</i></label><br>
|
</select>
|
||||||
{/if}
|
|
||||||
<input type="submit" value="Save" name="save_edit" class="bigbutton" style="margin-left:40px;">
|
<input type="submit" value="Save" name="save_edit" class="bigbutton" style="margin-left:40px;">
|
||||||
<input type="submit" value="Cancel" name="cancel_edit" class="bigbutton" style="margin-left:40px;">
|
<input type="submit" value="Cancel" name="cancel_edit" class="bigbutton" style="margin-left:40px;">
|
||||||
{if condition="!$link_is_new"}<input type="submit" value="Delete" name="delete_link" class="bigbutton" style="margin-left:180px;" onClick="return confirmDeleteLink();">{/if}
|
{if condition="!$link_is_new"}<input type="submit" value="Delete" name="delete_link" class="bigbutton" style="margin-left:180px;" onClick="return confirmDeleteLink();">{/if}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<a name="{$value.linkdate|smallHash}" id="{$value.linkdate|smallHash}"></a>
|
<a name="{$value.linkdate|smallHash}" id="{$value.linkdate|smallHash}"></a>
|
||||||
<div class="thumbnail">{$value.url|thumbnail}</div>
|
<div class="thumbnail">{$value.url|thumbnail}</div>
|
||||||
<div class="linkcontainer">
|
<div class="linkcontainer">
|
||||||
{if="isLoggedIn()"}
|
{if="$currentUserLevel > 3 || $currentUser === $value.author"}
|
||||||
<div class="linkeditbuttons">
|
<div class="linkeditbuttons">
|
||||||
<form method="GET" class="buttoneditform"><input type="hidden" name="edit_link" value="{$value.linkdate}"><input type="image" alt="Edit" src="images/edit_icon.png#" title="Edit" class="button_edit"></form><br>
|
<form method="GET" class="buttoneditform"><input type="hidden" name="edit_link" value="{$value.linkdate}"><input type="image" alt="Edit" src="images/edit_icon.png#" title="Edit" class="button_edit"></form><br>
|
||||||
<form method="POST" class="buttoneditform"><input type="hidden" name="lf_linkdate" value="{$value.linkdate}">
|
<form method="POST" class="buttoneditform"><input type="hidden" name="lf_linkdate" value="{$value.linkdate}">
|
||||||
|
@ -43,14 +43,18 @@
|
||||||
<span class="linktitle"><a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
|
<span class="linktitle"><a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
|
||||||
<br>
|
<br>
|
||||||
{if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
|
{if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
|
||||||
|
|
||||||
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
||||||
<span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{$value.localdate|htmlspecialchars} - permalink</a> - </span>
|
<span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{$value.localdate|htmlspecialchars} - permalink</a> - </span>
|
||||||
{else}
|
{else}
|
||||||
<span class="linkdate" title="Short link here"><a href="?{$value.linkdate|smallHash}">permalink</a> - </span>
|
<span class="linkdate" title="Short link here"><a href="?{$value.linkdate|smallHash}">permalink</a> - </span>
|
||||||
{/if}
|
{/if}
|
||||||
|
{if="!$GLOBALS['config']['HIDE_QRCODE']"}
|
||||||
<div style="position:relative;display:inline;"><a href="http://invx.com/code/qrcode/?code={$scripturl|urlencode}%3F{$value.linkdate|smallHash}&width=200&height=200"
|
<div style="position:relative;display:inline;"><a href="http://invx.com/code/qrcode/?code={$scripturl|urlencode}%3F{$value.linkdate|smallHash}&width=200&height=200"
|
||||||
{if="empty($GLOBALS['disablejquery'])"}onclick="return false;"{/if} class="qrcode"><img src="images/qrcode.png#" width="13" height="13" title="QR-Code"></a></div> -
|
{if="empty($GLOBALS['disablejquery'])"}onclick="return false;"{/if} class="qrcode"><img src="images/qrcode.png#" width="13" height="13" title="QR-Code"></a></div> -
|
||||||
<span class="linkurl" title="Short link">{$value.url|htmlspecialchars}</span><br>
|
{/if}
|
||||||
|
<span class="linkurl" title="Short link">{$value.url|htmlspecialchars} - </span>
|
||||||
|
<span class="linkauthor" title="Author">Added by {$value.author}</span><br>
|
||||||
{if="$value.tags"}
|
{if="$value.tags"}
|
||||||
<div class="linktaglist">
|
<div class="linktaglist">
|
||||||
{loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value|htmlspecialchars}</a></span> {/loop}
|
{loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value|htmlspecialchars}</a></span> {/loop}
|
||||||
|
|
43
sources/tpl/manageusers.html
Normal file
43
sources/tpl/manageusers.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>{include="includes"}</head>
|
||||||
|
<body>
|
||||||
|
<div id="pageheader">
|
||||||
|
{include="page.header"}
|
||||||
|
</div>
|
||||||
|
<div id="manageusers">
|
||||||
|
<form method="GET" name="edituser" id="createuserbadge">
|
||||||
|
<h4>New user</h4>
|
||||||
|
<input type="hidden" name="do" value="saveUser">
|
||||||
|
<input type="text" name="username" value="" placeholder="username">
|
||||||
|
<select name="userlevel" id="eu_level">
|
||||||
|
<option value="4">Administrator</option>
|
||||||
|
<option value="3">Moderator</option>
|
||||||
|
<option value="2">Contributor</option>
|
||||||
|
<option value="1" selected>Reader</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" name="email" value="" placeholder="email">
|
||||||
|
<input type="submit" name="createUser" value="create user" class="updateuser">
|
||||||
|
</form>
|
||||||
|
{loop="users"}
|
||||||
|
<form method="GET" name="edituser" class="userBadge {if="$value.username === $shaarliOwner"}sysadmin{/if}">
|
||||||
|
<h4>{$value.username}</h4>
|
||||||
|
<input type="hidden" name="do" value="saveUser">
|
||||||
|
<input type="hidden" name="username" value="{$value.username}">
|
||||||
|
<select name="userlevel" id="userlevel">
|
||||||
|
<option value="4"{if="$value.level == 4"} selected{/if}>Administrator</option>
|
||||||
|
<option value="3"{if="$value.level == 3"} selected{/if}>Moderator</option>
|
||||||
|
<option value="2"{if="$value.level == 2"} selected{/if}>Contributor</option>
|
||||||
|
<option value="1"{if="$value.level == 1"} selected{/if}>Reader</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" name="email" value="{$value.email}">
|
||||||
|
<input type="submit" name="updateUser" value="update card" class="updateuser">
|
||||||
|
<input type="submit" name="resetPassword" value="reset pass" class="smallsubmit resetpassword">
|
||||||
|
<input type="submit" name="deleteUser" value="delete user" class="smallsubmit deleteuser" {if="$value.username === $shaarliOwner"}disabled{/if} onClick="return confirm('Do you really want to delete {$value.username} ?')">
|
||||||
|
</form>
|
||||||
|
{/loop}
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
{include="page.footer"}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -18,3 +18,13 @@ $(document).ready(function()
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{if="empty($GLOBALS['disablejquery']) && isset($_GET['searchterm'])"}
|
||||||
|
<script src="inc/jquery.highlight.js#"></script>
|
||||||
|
<script language="JavaScript">
|
||||||
|
$(document).ready(function()
|
||||||
|
{
|
||||||
|
$('#linklist li').highlight("{$search_crits}");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{/if}
|
|
@ -9,7 +9,7 @@
|
||||||
{else}
|
{else}
|
||||||
<a href="?" class="nomobile">Home</a>
|
<a href="?" class="nomobile">Home</a>
|
||||||
{if="isLoggedIn()"}
|
{if="isLoggedIn()"}
|
||||||
<a href="?do=logout">Logout</a><a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a>
|
<a href="?do=logout">Logout <i>({$currentUser})</i></a><a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a>
|
||||||
{elseif="$GLOBALS['config']['OPEN_SHAARLI']"}
|
{elseif="$GLOBALS['config']['OPEN_SHAARLI']"}
|
||||||
<a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a>
|
<a href="?do=tools">Tools</a><a href="?do=addlink"><b>Add link</b></a>
|
||||||
{else}
|
{else}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</center>
|
</center>
|
||||||
{include="page.footer"}
|
{include="page.footer"}
|
||||||
</body>
|
|
||||||
{if="empty($GLOBALS['disablejquery'])"}
|
{if="empty($GLOBALS['disablejquery'])"}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
@ -25,4 +25,5 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{/if}
|
{/if}
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -5,12 +5,13 @@
|
||||||
<div id="pageheader">
|
<div id="pageheader">
|
||||||
{include="page.header"}
|
{include="page.header"}
|
||||||
<div id="toolsdiv">
|
<div id="toolsdiv">
|
||||||
{if="!$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b> <span>: Change your password.</span></a><br><br>{/if}
|
{if="count($GLOBALS['login'])>=1 || !$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b> <span>: Change your password.</span></a><br><br>{/if}
|
||||||
<a href="?do=configure"><b>Configure your Shaarli</b> <span>: Change Title, timezone...</span></a><br><br>
|
{if="$currentUserLevel >= 3"}<a href="?do=users"><b>Manage users</b> <span>: Reset password / create or delete user.</span></a><br><br>{/if}
|
||||||
<a href="?do=changetag"><b>Rename/delete tags</b> <span>: Rename or delete a tag in all links</span></a><br><br>
|
{if="$currentUserLevel == 4"}<a href="?do=configure"><b>Configure your Shaarli</b> <span>: Change Title, timezone...</span></a><br><br>{/if}
|
||||||
<a href="?do=import"><b>Import</b> <span>: Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)</span></a> <br><br>
|
{if="$currentUserLevel >= 3"}<a href="?do=changetag"><b>Rename/delete tags</b> <span>: Rename or delete a tag in all links</span></a><br><br>{/if}
|
||||||
<a href="?do=export"><b>Export</b> <span>: Export Netscape html bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)</span></a><br><br>
|
{if="$currentUserLevel == 4"}<a href="?do=import"><b>Import</b> <span>: Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)</span></a> <br><br>{/if}
|
||||||
<a class="smallbutton" onclick="alert('Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link...');return false;" href="javascript:javascript:(function(){var%20url%20=%20location.href;var%20title%20=%20document.title%20||%20url;window.open('{$pageabsaddr}?post='%20+%20encodeURIComponent(url)+'&title='%20+%20encodeURIComponent(title)+'&source=bookmarklet','_blank','menubar=no,height=390,width=600,toolbar=no,scrollbars=no,status=no,dialog=1');})();"><b>Shaare link</b></a> <a href="#" style="clear:none;"><span>⇐ Drag this link to your bookmarks toolbar (or right-click it and choose Bookmark This Link....).<br> Then click "Shaare link" button in any page you want to share.</span></a><br><br>
|
{if="$currentUserLevel == 4"}<a href="?do=export"><b>Export</b> <span>: Export Netscape html bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)</span></a><br><br>{/if}
|
||||||
|
<a class="smallbutton" onclick="alert('Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link...');return false;" href="javascript:javascript:(function(){var%20url%20=%20location.href;var%20title%20=%20document.title%20||%20url;window.open('{$pageabsaddr}?post='%20+%20encodeURIComponent(url)+'&title='%20+%20encodeURIComponent(title)+'&source=bookmarklet','_blank','menubar=no,height=390,width=600,toolbar=no,scrollbars=no,status=no,dialog=1');})();"><b>Shaare link</b></a> <a href="#" style="clear:none;"><span>⇐ Drag this link to your bookmarks toolbar (or right-click it and choose Bookmark This Link....).<br> Then click "Shaare link" button in any page you want to share.</span></a><br><br>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue