.project
# Ignore raintpl generated pages
-*.rtpl.php
\ No newline at end of file
+*.rtpl.php
+
+# Ignore test dependencies
+composer.lock
+/vendor/
+
+# Ignore test output
+phpmd.html
License: MIT License (http://opensource.org/licenses/MIT)
Copyright: (C) jQuery Foundation and other contributors,https://jquery.com/download/
-Files: inc/jquery-lazyload*.js
+Files: inc/blazy*.js
License: MIT License (http://opensource.org/licenses/MIT)
-Copyright: (C) Mika Tuupola, https://github.com/tuupola
+Copyright: (C) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
Files: inc/qr.js
License: GPLv3 License (http://opensource.org/licenses/gpl-3.0)
--- /dev/null
+# Shaarli, the personal, minimalist, super-fast, no-database delicious clone.
+#
+# Makefile for PHP code analysis & testing
+#
+# Prerequisites:
+# - install Composer, either:
+# - from your distro's package manager;
+# - from the official website (https://getcomposer.org/download/);
+# - install/update test dependencies:
+# $ composer install # 1st setup
+# $ composer update
+BIN = vendor/bin
+PHP_SOURCE = index.php
+MESS_DETECTOR_RULES = cleancode,codesize,controversial,design,naming,unusedcode
+
+all: static_analysis_summary
+
+##
+# Concise status of the project
+#
+# These targets are non-blocking: || exit 0
+##
+static_analysis_summary: code_sniffer_source copy_paste mess_detector_summary
+
+##
+# PHP_CodeSniffer
+#
+# Detects PHP syntax errors
+#
+# Documentation (usage, output formatting):
+# - http://pear.php.net/manual/en/package.php.php-codesniffer.usage.php
+# - http://pear.php.net/manual/en/package.php.php-codesniffer.reporting.php
+##
+code_sniffer: code_sniffer_full
+
+# - errors by Git author
+code_sniffer_blame:
+ @$(BIN)/phpcs $(PHP_SOURCE) --report-gitblame
+
+# - all errors/warnings
+code_sniffer_full:
+ @$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200
+
+# - errors grouped by kind
+code_sniffer_source:
+ @$(BIN)/phpcs $(PHP_SOURCE) --report-source || exit 0
+
+##
+# PHP Copy/Paste Detector
+#
+# Detects code redundancy
+#
+# Documentation: https://github.com/sebastianbergmann/phpcpd
+##
+copy_paste:
+ @echo "-----------------------"
+ @echo "PHP COPY/PASTE DETECTOR"
+ @echo "-----------------------"
+ @$(BIN)/phpcpd $(PHP_SOURCE) || exit 0
+ @echo
+
+##
+# PHP Mess Detector
+#
+# Detects PHP syntax errors, sorted by category
+#
+# Rules documentation: http://phpmd.org/rules/index.html
+#
+mess_title:
+ @echo "-----------------"
+ @echo "PHP MESS DETECTOR"
+ @echo "-----------------"
+
+# - all warnings
+mess_detector: mess_title
+ @$(BIN)/phpmd $(PHP_SOURCE) text $(MESS_DETECTOR_RULES) | sed 's_.*\/__'
+
+# - all warnings
+# the generated HTML contains links to PHPMD's documentation
+mess_detector_html:
+ @$(BIN)/phpmd $(PHP_SOURCE) html $(MESS_DETECTOR_RULES) \
+ --reportfile phpmd.html || exit 0
+
+# - warnings grouped by message, sorted by descending frequency order
+mess_detector_grouped: mess_title
+ @$(BIN)/phpmd $(PHP_SOURCE) text $(MESS_DETECTOR_RULES) \
+ | cut -f 2 | sort | uniq -c | sort -nr
+
+# - summary: number of warnings by rule set
+mess_detector_summary: mess_title
+ @for rule in $$(echo $(MESS_DETECTOR_RULES) | tr ',' ' '); do \
+ warnings=$$($(BIN)/phpmd $(PHP_SOURCE) text $$rule | wc -l); \
+ printf "$$warnings\t$$rule\n"; \
+ done;
You want to share the links you discover ? Shaarli is a minimalist delicious clone you can install on your own website.
It is designed to be personal (single-user), fast and handy.
-[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli) [![Bountysource](https://www.bountysource.com/badge/team?team_id=19583&style=bounties_received)](https://www.bountysource.com/teams/shaarli/issues)
## Features:
## Installing
-Shaarli requires php 5.1
+Shaarli requires php 5.1. `php-gd` is optional and provides thumbnail resizing.
* Download the latest stable release from https://github.com/shaarli/Shaarli/releases
* Unpack the archive in a directory on your web server
## Upgrading
-Delete all files and directories except the `data` directory, then unzip the new version of Shaarli.
-You will not lose your links and you will not have to reconfigure it.
-
+ * **If you installed from the zip:** Delete all files and directories except the `data` directory, then unzip the new version of Shaarli. You will not lose your links and you will not have to reconfigure it.
+ * **If you installed using `git clone`**: run `git pull` in your Shaarli directory.
## About
--- /dev/null
+{
+ "name": "shaarli/shaarli",
+ "description": "The personal, minimalist, super-fast, no-database delicious clone",
+ "license": "MIT",
+ "support": {
+ "issues": "https://github.com/shaarli/Shaarli/issues"
+ },
+ "require": {},
+ "require-dev": {
+ "phpmd/phpmd" : "@stable",
+ "sebastian/phpcpd": "*",
+ "squizlabs/php_codesniffer": "2.*"
+ }
+}
+++ /dev/null
-JQuery 1.11.2
-===============================================================================
-Copyright jQuery Foundation and other contributors, https://jquery.org/
-
-This software consists of voluntary contributions made by many
-individuals. For exact contribution history, see the revision history
-available at https://github.com/jquery/jquery
-
-The following license applies to all parts of this software except as
-documented below:
-
-====
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-====
-
-All files located in the node_modules and external directories are
-externally maintained libraries used by this software which have their
-own licenses; we recommend you read them, as their terms may differ from
-the terms above.
-
-
-
-JQuery UI 1.11.2
-===============================================================================
-Copyright jQuery Foundation and other contributors, https://jquery.org/
-
-This software consists of voluntary contributions made by many
-individuals. For exact contribution history, see the revision history
-available at https://github.com/jquery/jquery-ui
-
-The following license applies to all parts of this software except as
-documented below:
-
-====
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-====
-
-Copyright and related rights for sample code are waived via CC0. Sample
-code is defined as all source code contained within the demos directory.
-
-CC0: http://creativecommons.org/publicdomain/zero/1.0/
-
-====
-
-All files located in the node_modules and external directories are
-externally maintained libraries used by this software which have their
-own licenses; we recommend you read them, as their terms may differ from
-the terms above.
-
-
-
-QR.js 1.1.3
-===============================================================================
-Copyright (C) 2014 Alasdair Mercer, http://neocotic.com
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-
-
-JQuery Lazyload 1.9.3
-===============================================================================
-By Mika Tuupola (https://github.com/tuupola)
-
-All code licensed under the MIT License[1]. All images licensed under
-Creative Commons Attribution 3.0 Unported License[2]. In other words you are
-basically free to do whatever you want. Just don’t remove my name from the
-source.
-
-[1]: http://opensource.org/licenses/mit-license.php
-[2]: http://creativecommons.org/licenses/by/3.0/deed.en_US
\ No newline at end of file
--- /dev/null
+/*!
+ hey, [be]Lazy.js - v1.3.1 - 2015.02.01
+ A lazy loading and multi-serving image script
+ (c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
+*/
+;(function(root, blazy) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register bLazy as an anonymous module
+ define(blazy);
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = blazy();
+ } else {
+ // Browser globals. Register bLazy on window
+ root.Blazy = blazy();
+ }
+})(this, function () {
+ 'use strict';
+
+ //vars
+ var source, options, viewport, images, count, isRetina, destroyed;
+ //throttle vars
+ var validateT, saveViewportOffsetT;
+
+ // constructor
+ function Blazy(settings) {
+ //IE7- fallback for missing querySelectorAll support
+ if (!document.querySelectorAll) {
+ var s=document.createStyleSheet();
+ document.querySelectorAll = function(r, c, i, j, a) {
+ a=document.all, c=[], r = r.replace(/\[for\b/gi, '[htmlFor').split(',');
+ for (i=r.length; i--;) {
+ s.addRule(r[i], 'k:v');
+ for (j=a.length; j--;) a[j].currentStyle.k && c.push(a[j]);
+ s.removeRule(0);
+ }
+ return c;
+ };
+ }
+ //init vars
+ destroyed = true;
+ images = [];
+ viewport = {};
+ //options
+ options = settings || {};
+ options.error = options.error || false;
+ options.offset = options.offset || 100;
+ options.success = options.success || false;
+ options.selector = options.selector || '.b-lazy';
+ options.separator = options.separator || '|';
+ options.container = options.container ? document.querySelectorAll(options.container) : false;
+ options.errorClass = options.errorClass || 'b-error';
+ options.breakpoints = options.breakpoints || false;
+ options.successClass = options.successClass || 'b-loaded';
+ options.src = source = options.src || 'data-src';
+ isRetina = window.devicePixelRatio > 1;
+ viewport.top = 0 - options.offset;
+ viewport.left = 0 - options.offset;
+ //throttle, ensures that we don't call the functions too often
+ validateT = throttle(validate, 25);
+ saveViewportOffsetT = throttle(saveViewportOffset, 50);
+
+ saveViewportOffset();
+
+ //handle multi-served image src
+ each(options.breakpoints, function(object){
+ if(object.width >= window.screen.width) {
+ source = object.src;
+ return false;
+ }
+ });
+
+ // start lazy load
+ initialize();
+ }
+
+ /* public functions
+ ************************************/
+ Blazy.prototype.revalidate = function() {
+ initialize();
+ };
+ Blazy.prototype.load = function(element, force){
+ if(!isElementLoaded(element)) loadImage(element, force);
+ };
+ Blazy.prototype.destroy = function(){
+ if(options.container){
+ each(options.container, function(object){
+ unbindEvent(object, 'scroll', validateT);
+ });
+ }
+ unbindEvent(window, 'scroll', validateT);
+ unbindEvent(window, 'resize', validateT);
+ unbindEvent(window, 'resize', saveViewportOffsetT);
+ count = 0;
+ images.length = 0;
+ destroyed = true;
+ };
+
+ /* private helper functions
+ ************************************/
+ function initialize(){
+ // First we create an array of images to lazy load
+ createImageArray(options.selector);
+ // Then we bind resize and scroll events if not already binded
+ if(destroyed) {
+ destroyed = false;
+ if(options.container) {
+ each(options.container, function(object){
+ bindEvent(object, 'scroll', validateT);
+ });
+ }
+ bindEvent(window, 'resize', saveViewportOffsetT);
+ bindEvent(window, 'resize', validateT);
+ bindEvent(window, 'scroll', validateT);
+ }
+ // And finally, we start to lazy load. Should bLazy ensure domready?
+ validate();
+ }
+
+ function validate() {
+ for(var i = 0; i<count; i++){
+ var image = images[i];
+ if(elementInView(image) || isElementLoaded(image)) {
+ Blazy.prototype.load(image);
+ images.splice(i, 1);
+ count--;
+ i--;
+ }
+ }
+ if(count === 0) {
+ Blazy.prototype.destroy();
+ }
+ }
+
+ function loadImage(ele, force){
+ // if element is visible
+ if(force || (ele.offsetWidth > 0 && ele.offsetHeight > 0)) {
+ var dataSrc = ele.getAttribute(source) || ele.getAttribute(options.src); // fallback to default data-src
+ if(dataSrc) {
+ var dataSrcSplitted = dataSrc.split(options.separator);
+ var src = dataSrcSplitted[isRetina && dataSrcSplitted.length > 1 ? 1 : 0];
+ var img = new Image();
+ // cleanup markup, remove data source attributes
+ each(options.breakpoints, function(object){
+ ele.removeAttribute(object.src);
+ });
+ ele.removeAttribute(options.src);
+ img.onerror = function() {
+ if(options.error) options.error(ele, "invalid");
+ ele.className = ele.className + ' ' + options.errorClass;
+ };
+ img.onload = function() {
+ // Is element an image or should we add the src as a background image?
+ ele.nodeName.toLowerCase() === 'img' ? ele.src = src : ele.style.backgroundImage = 'url("' + src + '")';
+ ele.className = ele.className + ' ' + options.successClass;
+ if(options.success) options.success(ele);
+ };
+ img.src = src; //preload image
+ } else {
+ if(options.error) options.error(ele, "missing");
+ ele.className = ele.className + ' ' + options.errorClass;
+ }
+ }
+ }
+
+ function elementInView(ele) {
+ var rect = ele.getBoundingClientRect();
+
+ return (
+ // Intersection
+ rect.right >= viewport.left
+ && rect.bottom >= viewport.top
+ && rect.left <= viewport.right
+ && rect.top <= viewport.bottom
+ );
+ }
+
+ function isElementLoaded(ele) {
+ return (' ' + ele.className + ' ').indexOf(' ' + options.successClass + ' ') !== -1;
+ }
+
+ function createImageArray(selector) {
+ var nodelist = document.querySelectorAll(selector);
+ count = nodelist.length;
+ //converting nodelist to array
+ for(var i = count; i--; images.unshift(nodelist[i])){}
+ }
+
+ function saveViewportOffset(){
+ viewport.bottom = (window.innerHeight || document.documentElement.clientHeight) + options.offset;
+ viewport.right = (window.innerWidth || document.documentElement.clientWidth) + options.offset;
+ }
+
+ function bindEvent(ele, type, fn) {
+ if (ele.attachEvent) {
+ ele.attachEvent && ele.attachEvent('on' + type, fn);
+ } else {
+ ele.addEventListener(type, fn, false);
+ }
+ }
+
+ function unbindEvent(ele, type, fn) {
+ if (ele.detachEvent) {
+ ele.detachEvent && ele.detachEvent('on' + type, fn);
+ } else {
+ ele.removeEventListener(type, fn, false);
+ }
+ }
+
+ function each(object, fn){
+ if(object && fn) {
+ var l = object.length;
+ for(var i = 0; i<l && fn(object[i], i) !== false; i++){}
+ }
+ }
+
+ function throttle(fn, minDelay) {
+ var lastCall = 0;
+ return function() {
+ var now = +new Date();
+ if (now - lastCall < minDelay) {
+ return;
+ }
+ lastCall = now;
+ fn.apply(images, arguments);
+ };
+ }
+
+ return Blazy;
+});
--- /dev/null
+/*!
+ hey, [be]Lazy.js - v1.3.1 - 2015.02.01
+ A lazy loading and multi-serving image script
+ (c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
+*/
+ (function(d,h){"function"===typeof define&&define.amd?define(h):"object"===typeof exports?module.exports=h():d.Blazy=h()})(this,function(){function d(b){if(!document.querySelectorAll){var g=document.createStyleSheet();document.querySelectorAll=function(b,a,e,d,f){f=document.all;a=[];b=b.replace(/\[for\b/gi,"[htmlFor").split(",");for(e=b.length;e--;){g.addRule(b[e],"k:v");for(d=f.length;d--;)f[d].currentStyle.k&&a.push(f[d]);g.removeRule(0)}return a}}m=!0;k=[];e={};a=b||{};a.error=a.error||!1;a.offset=a.offset||100;a.success=a.success||!1;a.selector=a.selector||".b-lazy";a.separator=a.separator||"|";a.container=a.container?document.querySelectorAll(a.container):!1;a.errorClass=a.errorClass||"b-error";a.breakpoints=a.breakpoints||!1;a.successClass=a.successClass||"b-loaded";a.src=r=a.src||"data-src";u=1<window.devicePixelRatio;e.top=0-a.offset;e.left=0-a.offset;f=v(w,25);t=v(x,50);x();n(a.breakpoints,function(b){if(b.width>=window.screen.width)return r=b.src,!1});h()}function h(){y(a.selector);m&&(m=!1,a.container&&n(a.container,function(b){p(b,"scroll",f)}),p(window,"resize",t),p(window,"resize",f),p(window,"scroll",f));w()}function w(){for(var b=0;b<l;b++){var g=k[b],c=g.getBoundingClientRect();if(c.right>=e.left&&c.bottom>=e.top&&c.left<=e.right&&c.top<=e.bottom||-1!==(" "+g.className+" ").indexOf(" "+a.successClass+" "))d.prototype.load(g),k.splice(b,1),l--,b--}0===l&&d.prototype.destroy()}function z(b,g){if(g||0<b.offsetWidth&&0<b.offsetHeight){var c=b.getAttribute(r)||b.getAttribute(a.src);if(c){var c=c.split(a.separator),d=c[u&&1<c.length?1:0],c=new Image;n(a.breakpoints,function(a){b.removeAttribute(a.src)});b.removeAttribute(a.src);c.onerror=function(){a.error&&a.error(b,"invalid");b.className=b.className+" "+a.errorClass};c.onload=function(){"img"===b.nodeName.toLowerCase()?b.src=d:b.style.backgroundImage='url("'+d+'")';b.className=b.className+" "+a.successClass;a.success&&a.success(b)};c.src=d}else a.error&&a.error(b,"missing"),b.className=b.className+" "+a.errorClass}}function y(b){b=document.querySelectorAll(b);for(var a=l=b.length;a--;k.unshift(b[a]));}function x(){e.bottom=(window.innerHeight||document.documentElement.clientHeight)+a.offset;e.right=(window.innerWidth||document.documentElement.clientWidth)+a.offset}function p(b,a,c){b.attachEvent?b.attachEvent&&b.attachEvent("on"+a,c):b.addEventListener(a,c,!1)}function q(b,a,c){b.detachEvent?b.detachEvent&&b.detachEvent("on"+a,c):b.removeEventListener(a,c,!1)}function n(a,d){if(a&&d)for(var c=a.length,e=0;e<c&&!1!==d(a[e],e);e++);}function v(a,d){var c=0;return function(){var e=+new Date;e-c<d||(c=e,a.apply(k,arguments))}}var r,a,e,k,l,u,m,f,t;d.prototype.revalidate=function(){h()};d.prototype.load=function(b,d){-1===(" "+b.className+" ").indexOf(" "+a.successClass+" ")&&z(b,d)};d.prototype.destroy=function(){a.container&&n(a.container,function(a){q(a,"scroll",f)});q(window,"scroll",f);q(window,"resize",f);q(window,"resize",t);l=0;k.length=0;m=!0};return d});
\ No newline at end of file
+++ /dev/null
-/*
- * Lazy Load - jQuery plugin for lazy loading images
- *
- * Copyright (c) 2007-2013 Mika Tuupola
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/mit-license.php
- *
- * Project home:
- * http://www.appelsiini.net/projects/lazyload
- *
- * Version: 1.9.3
- *
- */
-
-(function($, window, document, undefined) {
- var $window = $(window);
-
- $.fn.lazyload = function(options) {
- var elements = this;
- var $container;
- var settings = {
- threshold : 0,
- failure_limit : 0,
- event : "scroll",
- effect : "show",
- container : window,
- data_attribute : "original",
- skip_invisible : true,
- appear : null,
- load : null,
- placeholder : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"
- };
-
- function update() {
- var counter = 0;
-
- elements.each(function() {
- var $this = $(this);
- if (settings.skip_invisible && !$this.is(":visible")) {
- return;
- }
- if ($.abovethetop(this, settings) ||
- $.leftofbegin(this, settings)) {
- /* Nothing. */
- } else if (!$.belowthefold(this, settings) &&
- !$.rightoffold(this, settings)) {
- $this.trigger("appear");
- /* if we found an image we'll load, reset the counter */
- counter = 0;
- } else {
- if (++counter > settings.failure_limit) {
- return false;
- }
- }
- });
-
- }
-
- if(options) {
- /* Maintain BC for a couple of versions. */
- if (undefined !== options.failurelimit) {
- options.failure_limit = options.failurelimit;
- delete options.failurelimit;
- }
- if (undefined !== options.effectspeed) {
- options.effect_speed = options.effectspeed;
- delete options.effectspeed;
- }
-
- $.extend(settings, options);
- }
-
- /* Cache container as jQuery as object. */
- $container = (settings.container === undefined ||
- settings.container === window) ? $window : $(settings.container);
-
- /* Fire one scroll event per scroll. Not one scroll event per image. */
- if (0 === settings.event.indexOf("scroll")) {
- $container.bind(settings.event, function() {
- return update();
- });
- }
-
- this.each(function() {
- var self = this;
- var $self = $(self);
-
- self.loaded = false;
-
- /* If no src attribute given use data:uri. */
- if ($self.attr("src") === undefined || $self.attr("src") === false) {
- if ($self.is("img")) {
- $self.attr("src", settings.placeholder);
- }
- }
-
- /* When appear is triggered load original image. */
- $self.one("appear", function() {
- if (!this.loaded) {
- if (settings.appear) {
- var elements_left = elements.length;
- settings.appear.call(self, elements_left, settings);
- }
- $("<img />")
- .bind("load", function() {
-
- var original = $self.attr("data-" + settings.data_attribute);
- $self.hide();
- if ($self.is("img")) {
- $self.attr("src", original);
- } else {
- $self.css("background-image", "url('" + original + "')");
- }
- $self[settings.effect](settings.effect_speed);
-
- self.loaded = true;
-
- /* Remove image from array so it is not looped next time. */
- var temp = $.grep(elements, function(element) {
- return !element.loaded;
- });
- elements = $(temp);
-
- if (settings.load) {
- var elements_left = elements.length;
- settings.load.call(self, elements_left, settings);
- }
- })
- .attr("src", $self.attr("data-" + settings.data_attribute));
- }
- });
-
- /* When wanted event is triggered load original image */
- /* by triggering appear. */
- if (0 !== settings.event.indexOf("scroll")) {
- $self.bind(settings.event, function() {
- if (!self.loaded) {
- $self.trigger("appear");
- }
- });
- }
- });
-
- /* Check if something appears when window is resized. */
- $window.bind("resize", function() {
- update();
- });
-
- /* With IOS5 force loading images when navigating with back button. */
- /* Non optimal workaround. */
- if ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) {
- $window.bind("pageshow", function(event) {
- if (event.originalEvent && event.originalEvent.persisted) {
- elements.each(function() {
- $(this).trigger("appear");
- });
- }
- });
- }
-
- /* Force initial check if images should appear. */
- $(document).ready(function() {
- update();
- });
-
- return this;
- };
-
- /* Convenience methods in jQuery namespace. */
- /* Use as $.belowthefold(element, {threshold : 100, container : window}) */
-
- $.belowthefold = function(element, settings) {
- var fold;
-
- if (settings.container === undefined || settings.container === window) {
- fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop();
- } else {
- fold = $(settings.container).offset().top + $(settings.container).height();
- }
-
- return fold <= $(element).offset().top - settings.threshold;
- };
-
- $.rightoffold = function(element, settings) {
- var fold;
-
- if (settings.container === undefined || settings.container === window) {
- fold = $window.width() + $window.scrollLeft();
- } else {
- fold = $(settings.container).offset().left + $(settings.container).width();
- }
-
- return fold <= $(element).offset().left - settings.threshold;
- };
-
- $.abovethetop = function(element, settings) {
- var fold;
-
- if (settings.container === undefined || settings.container === window) {
- fold = $window.scrollTop();
- } else {
- fold = $(settings.container).offset().top;
- }
-
- return fold >= $(element).offset().top + settings.threshold + $(element).height();
- };
-
- $.leftofbegin = function(element, settings) {
- var fold;
-
- if (settings.container === undefined || settings.container === window) {
- fold = $window.scrollLeft();
- } else {
- fold = $(settings.container).offset().left;
- }
-
- return fold >= $(element).offset().left + settings.threshold + $(element).width();
- };
-
- $.inviewport = function(element, settings) {
- return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) &&
- !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
- };
-
- /* Custom selectors for your convenience. */
- /* Use as $("img:below-the-fold").something() or */
- /* $("img").filter(":below-the-fold").something() which is faster */
-
- $.extend($.expr[":"], {
- "below-the-fold" : function(a) { return $.belowthefold(a, {threshold : 0}); },
- "above-the-top" : function(a) { return !$.belowthefold(a, {threshold : 0}); },
- "right-of-screen": function(a) { return $.rightoffold(a, {threshold : 0}); },
- "left-of-screen" : function(a) { return !$.rightoffold(a, {threshold : 0}); },
- "in-viewport" : function(a) { return $.inviewport(a, {threshold : 0}); },
- /* Maintain BC for couple of versions. */
- "above-the-fold" : function(a) { return !$.belowthefold(a, {threshold : 0}); },
- "right-of-fold" : function(a) { return $.rightoffold(a, {threshold : 0}); },
- "left-of-fold" : function(a) { return !$.rightoffold(a, {threshold : 0}); }
- });
-
-})(jQuery, window, document);
+++ /dev/null
-/*! Lazy Load 1.9.3 - MIT license - Copyright 2010-2013 Mika Tuupola */
-!function(a,b,c,d){var e=a(b);a.fn.lazyload=function(f){function g(){var b=0;i.each(function(){var c=a(this);if(!j.skip_invisible||c.is(":visible"))if(a.abovethetop(this,j)||a.leftofbegin(this,j));else if(a.belowthefold(this,j)||a.rightoffold(this,j)){if(++b>j.failure_limit)return!1}else c.trigger("appear"),b=0})}var h,i=this,j={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null,placeholder:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"};return f&&(d!==f.failurelimit&&(f.failure_limit=f.failurelimit,delete f.failurelimit),d!==f.effectspeed&&(f.effect_speed=f.effectspeed,delete f.effectspeed),a.extend(j,f)),h=j.container===d||j.container===b?e:a(j.container),0===j.event.indexOf("scroll")&&h.bind(j.event,function(){return g()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,(c.attr("src")===d||c.attr("src")===!1)&&c.is("img")&&c.attr("src",j.placeholder),c.one("appear",function(){if(!this.loaded){if(j.appear){var d=i.length;j.appear.call(b,d,j)}a("<img />").bind("load",function(){var d=c.attr("data-"+j.data_attribute);c.hide(),c.is("img")?c.attr("src",d):c.css("background-image","url('"+d+"')"),c[j.effect](j.effect_speed),b.loaded=!0;var e=a.grep(i,function(a){return!a.loaded});if(i=a(e),j.load){var f=i.length;j.load.call(b,f,j)}}).attr("src",c.attr("data-"+j.data_attribute))}}),0!==j.event.indexOf("scroll")&&c.bind(j.event,function(){b.loaded||c.trigger("appear")})}),e.bind("resize",function(){g()}),/(?:iphone|ipod|ipad).*os 5/gi.test(navigator.appVersion)&&e.bind("pageshow",function(b){b.originalEvent&&b.originalEvent.persisted&&i.each(function(){a(this).trigger("appear")})}),a(c).ready(function(){g()}),this},a.belowthefold=function(c,f){var g;return g=f.container===d||f.container===b?(b.innerHeight?b.innerHeight:e.height())+e.scrollTop():a(f.container).offset().top+a(f.container).height(),g<=a(c).offset().top-f.threshold},a.rightoffold=function(c,f){var g;return g=f.container===d||f.container===b?e.width()+e.scrollLeft():a(f.container).offset().left+a(f.container).width(),g<=a(c).offset().left-f.threshold},a.abovethetop=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollTop():a(f.container).offset().top,g>=a(c).offset().top+f.threshold+a(c).height()},a.leftofbegin=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollLeft():a(f.container).offset().left,g>=a(c).offset().left+f.threshold+a(c).width()},a.inviewport=function(b,c){return!(a.rightoffold(b,c)||a.leftofbegin(b,c)||a.belowthefold(b,c)||a.abovethetop(b,c))},a.extend(a.expr[":"],{"below-the-fold":function(b){return a.belowthefold(b,{threshold:0})},"above-the-top":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-screen":function(b){return a.rightoffold(b,{threshold:0})},"left-of-screen":function(b){return!a.rightoffold(b,{threshold:0})},"in-viewport":function(b){return a.inviewport(b,{threshold:0})},"above-the-fold":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-fold":function(b){return a.rightoffold(b,{threshold:0})},"left-of-fold":function(b){return!a.rightoffold(b,{threshold:0})}})}(jQuery,window,document);
\ No newline at end of file
float: left;
}
+.b-lazy {
+ -webkit-transition: opacity 500ms ease-in-out;
+ -moz-transition: opacity 500ms ease-in-out;
+ -o-transition: opacity 500ms ease-in-out;
+ transition: opacity 500ms ease-in-out;
+ opacity: 0;
+}
+.b-lazy.b-loaded {
+ opacity: 1;
+}
+
.picwall_pictureframe img {
max-width: 100%;
height: auto;
+ color: transparent;
} /* Adapt the width of the image */
.picwall_pictureframe a {
function checkUpdate()
{
if (!isLoggedIn()) return ''; // Do not check versions for visitors.
+ if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) return ''; // Do not check if the user doesn't want to.
// Get latest version number at most once a day.
if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])<time()-($GLOBALS['config']['UPDATECHECK_INTERVAL'])))
{
$version=shaarli_version;
- list($httpstatus,$headers,$data) = getHTTP('https://raw.githubusercontent.com/shaarli/Shaarli/master/shaarli_version.txt',2);
- if (strpos($httpstatus,'200 OK')!==false) $version=$data;
+ list($httpstatus,$headers,$data) = getHTTP('https://raw.githubusercontent.com/shaarli/Shaarli/master/shaarli_version.php',2);
+ if (strpos($httpstatus,'200 OK')!==false) $version=str_replace(' */ ?>','',str_replace('<?php /* ','',$data));
// If failed, never mind. We don't want to bother the user with that.
file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date
}
$GLOBALS['disablejquery']=!empty($_POST['disablejquery']);
$GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']);
$GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']);
+ $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
writeConfig();
echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>';
exit;
if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo '<script>self.close();</script>'; exit; }
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
$returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited.
+ if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead
header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on.
exit;
}
{
$url=$_GET['post'];
- // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...)
- $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i);
- $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i);
- $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i);
+
+ // We remove the annoying parameters added by FeedBurner, GoogleFeedProxy, Facebook...
+ $annoyingpatterns = array('/[\?&]utm_source=[^&]*/', '/[\?&]utm_campaign=[^&]*/', '/[\?&]utm_medium=[^&]*/', '/#xtor=RSS-[^&]*/', '/[\?&]fb_[^&]*/', '/[\?&]__scoop[^&]*/', '/#tk\.rss_all\?/', '/[\?&]action_ref_map=[^&]*/', '/[\?&]action_type_map=[^&]*/', '/[\?&]action_object_map=[^&]*/');
+ foreach($annoyingpatterns as $pattern)
+ {
+ $url = preg_replace($pattern, "", $url);
+ }
$link_is_new = false;
$link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link)
$html='<a href="'.htmlspecialchars($t['href']).'">';
- // Lazy image (only loaded by JavaScript when in the viewport).
- if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled)
- $html.='<img class="lazyimage" src="'.htmlspecialchars($t['src']).'"';
- else
- $html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
+ // Lazy image
+ $html.='<img class="b-lazy" src="#" data-src="'.htmlspecialchars($t['src']).'"';
if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
$GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] );
+ $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
writeConfig();
echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>';
exit;
$config .= '$GLOBALS[\'disablejquery\']='.var_export($GLOBALS['disablejquery'],true).'; ';
$config .= '$GLOBALS[\'privateLinkByDefault\']='.var_export($GLOBALS['privateLinkByDefault'],true).'; ';
$config .= '$GLOBALS[\'config\'][\'ENABLE_RSS_PERMALINKS\']='.var_export($GLOBALS['config']['ENABLE_RSS_PERMALINKS'], true).'; ';
+ $config .= '$GLOBALS[\'config\'][\'ENABLE_UPDATECHECK\']='.var_export($GLOBALS['config']['ENABLE_UPDATECHECK'], true).'; ';
$config .= ' ?>';
if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0)
{
--- /dev/null
+<?php /* 0.0.43beta */ ?>
+++ /dev/null
-0.0.43beta
<td>
<input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks" {if="!empty($GLOBALS['config']['ENABLE_RSS_PERMALINKS'])"}checked{/if}/><label for="enableRssPermalinks"> Switches the RSS feed URLs between full URLs and shortlinks. Enabling it will show a permalink in the description, and the feed item will be linked to the absolute URL. Disabling it swaps this behaviour around (permalink in title and link in description). RSS Permalinks are currently <b>{if="$GLOBALS['config']['ENABLE_RSS_PERMALINKS']"}enabled{else}disabled{/if}</b></label>
</td>
+ </tr>
+ <tr><td valign="top"><b>Update:</b></td><td>
+ <input type="checkbox" name="updateCheck" id="updateCheck" {if="!empty($GLOBALS['config']['ENABLE_UPDATECHECK'])"}checked{/if}/>
+ <label for="updateCheck"> Notify me when a new release is ready</label></td>
</tr>
<tr><td></td><td class="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr>
</table>
<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
<link href="images/favicon.ico#" rel="shortcut icon" type="image/x-icon" />
<link type="text/css" rel="stylesheet" href="../inc/reset.css" />
-<link type="text/css" rel="stylesheet" href="inc/shaarli.css?version={$version|urlencode}#" />
-{if="is_file('inc/user.css')"}<link type="text/css" rel="stylesheet" href="inc/user.css?version={$version|urlencode}#" />{/if}
+<link type="text/css" rel="stylesheet" href="../inc/shaarli.css" />
+{if="is_file('inc/user.css')"}<link type="text/css" rel="stylesheet" href="../inc/user.css" />{/if}
<head>{include="includes"}{$timezone_js}</head>
<body onload="document.installform.setlogin.focus();">
<div id="install">
-<h1>Shaarli</h1>
-It looks like it's the first time you run Shaarli. Please configure it:<br>
-<form method="POST" action="#" name="installform" id="installform">
-<table>
-<tr><td><b>Login:</b></td><td><input type="text" name="setlogin" size="30"></td></tr>
-<tr><td><b>Password:</b></td><td><input type="password" name="setpassword" size="30"></td></tr>
-{$timezone_html}
-<tr><td><b>Page title:</b></td><td><input type="text" name="title" size="30"></td></tr>
-<tr><td colspan="2"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr>
-</table>
-</form>
+ <h1>Shaarli</h1>
+ It looks like it's the first time you run Shaarli. Please configure it:<br>
+ <form method="POST" action="#" name="installform" id="installform">
+ <table>
+ <tr><td><b>Login:</b></td><td><input type="text" name="setlogin" size="30"></td></tr>
+ <tr><td><b>Password:</b></td><td><input type="password" name="setpassword" size="30"></td></tr>
+ {$timezone_html}
+ <tr><td><b>Page title:</b></td><td><input type="text" name="title" size="30"></td></tr>
+ <tr><td valign="top"><b>Update:</b></td><td>
+ <input type="checkbox" name="updateCheck" id="updateCheck" checked="checked"><label for="updateCheck"> Notify me when a new release is ready</label></td>
+ </tr>
+ <tr><td colspan="2"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr>
+ </table>
+ </form>
</div>
{include="page.footer"}
</body>
<!DOCTYPE html>
<html>
<head>{include="includes"}
-{if="empty($GLOBALS['disablejquery'])"}
-<script src="inc/jquery-1.11.2.min.js#"></script>
-<script src="inc/jquery-ui-1.11.2.min.js#"></script>
-<script src="inc/jquery.lazyload-1.9.3.min.js#"></script>
-{/if}
+<script src="inc/blazy-1.3.1.min.js#"></script>
</head>
<body>
<div id="pageheader">{include="page.header"}</div>
</div>
{include="page.footer"}
-{if="empty($GLOBALS['disablejquery'])"}
<script>
-$(document).ready(function() {
- $("img.lazyimage").show().lazyload();
-});
+ var bLazy = new Blazy();
</script>
-{/if}
</body>
</html>
\ No newline at end of file
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>{include="includes"}</head>
-<body>
-<div id="pageheader">{include="page.header"}</div>
-<div style="background-color:#003;">
- {loop="linksToDisplay"}
- <div style="float:left;width:48%;border-right:2px solid white;height:120px;overflow:hide;">
- <div style="float:left;width:120px;text-align:center">{$value.thumbnail}</div>
- <a href="{$value.permalink}" style="color:yellow;font-weight:bold;text-decoration:none;">{$value.title|htmlspecialchars}</a><br>
- <span style="font-size:8pt;color:#eee;">{$value.description|htmlspecialchars}</span>
- <div style="clear:both;"></div>
- </div><br>
- {/loop}
-</div>
-
-{include="page.footer"}
-</body>
-</html>
\ No newline at end of file
<a href="?do=import"><b>Import</b> <span>: Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)</span></a> <br><br>
<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>
<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)+'&description='%20+%20encodeURIComponent(document.getSelection())+'&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>
+ <a class="smallbutton" onclick="alert('Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link...');return false;" href="?private=1&post="><b>✚Add Note</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 "✚Add Note" button anytime to start composing a (default private) Note (text post) to your Shaarli.</span></a><br><br>
<div class="clear"></div>
</div>
</div>