Fix #48 No more scroll to top on click + add notifications to actions

This commit is contained in:
Luc Didry
2018-05-07 23:06:03 +02:00
parent dd9dc7bd7d
commit 3eb8db123e
14 changed files with 484 additions and 21 deletions
+13
View File
@@ -160,3 +160,16 @@ cover:
script:
- make cover
coverage: '/Total .*\d+\.\d+$/'
### Push new translations strings to https://trad.framasoft.org
##
#
trads:
stage: cover
image: framasoft/push-trad:latest
script:
- sed -e 's#<project-version>.*</project-version>#<project-version>development</project-version>#' -i zanata.xml
- if [ ! -z ${ZANATA_CONFIG+x} ]; then mkdir -p ${HOME}/.config; echo -e "${ZANATA_CONFIG}" > ${HOME}/.config/zanata.ini; fi
- if [ ! -z ${ZANATA_CONFIG+x} ]; then make push-locales; fi
only:
- development
+7 -1
View File
@@ -5,6 +5,12 @@ CARTON=carton exec
LUTIM=script/lutim
REAL_LUTIM=script/application
minify:
@echo "CSS concatenation"
@cd ./themes/default/public/css/ && cat bootstrap.min.css fontello.css hennypenny.css lutim.css toastify.css | csso > common.min.css
@cd ./themes/default/public/css/ && cat animation.css uploader.css markdown.css | csso > not_stats.min.css
@cd ./themes/default/public/css/ && cat photoswipe.css default-skin/default-skin.css | csso > gallery.min.css
locales:
$(XGETTEXT) $(EXTRACTDIR) -o $(POT) 2>/dev/null
@@ -34,7 +40,7 @@ test: podcheck test-sqlite test-pg
clean:
rm -rf lutim.db files/
dev:
dev: minify
$(CARTON) morbo $(LUTIM) --listen http://0.0.0.0:3000 --watch lib/ --watch script/ --watch themes/ --watch lutim.conf
devlog:
+1 -1
View File
@@ -106,7 +106,7 @@ sub startup {
$self->plugin('GzipStatic');
# Cache static files
$self->plugin('StaticCache');
$self->plugin('StaticCache' => { even_in_dev => 1 });
# Helpers
$self->plugin('Lutim::Plugin::Helpers');
+1 -1
View File
@@ -70,7 +70,7 @@ sub startup {
$self->plugin('GzipStatic');
# Cache static files
$self->plugin('StaticCache');
$self->plugin('StaticCache' => { even_in_dev => 1 });
# Helpers
$self->plugin('Lutim::Plugin::Helpers');
+18 -6
View File
@@ -76,11 +76,15 @@ msgstr ""
msgid "Contributors"
msgstr ""
#: themes/default/templates/partial/lutim.js.ep:218 themes/default/templates/partial/lutim.js.ep:272 themes/default/templates/partial/lutim.js.ep:350
#: themes/default/templates/partial/common.js.ep:96
msgid "Copied to clipboard"
msgstr ""
#: themes/default/templates/partial/lutim.js.ep:218 themes/default/templates/partial/lutim.js.ep:273 themes/default/templates/partial/lutim.js.ep:351
msgid "Copy all view links to clipboard"
msgstr ""
#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:108 themes/default/templates/partial/lutim.js.ep:123 themes/default/templates/partial/lutim.js.ep:82 themes/default/templates/partial/lutim.js.ep:94
#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:177 themes/default/templates/partial/lutim.js.ep:108 themes/default/templates/partial/lutim.js.ep:123 themes/default/templates/partial/lutim.js.ep:82 themes/default/templates/partial/lutim.js.ep:94
msgid "Copy to clipboard"
msgstr ""
@@ -108,7 +112,7 @@ msgstr ""
msgid "Deleted images in 30 days"
msgstr ""
#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145
#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:169 themes/default/templates/partial/common.js.ep:172
msgid "Deletion link"
msgstr ""
@@ -164,11 +168,11 @@ msgstr ""
msgid "Gallery link"
msgstr ""
#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87
#: themes/default/templates/partial/common.js.ep:105 themes/default/templates/partial/common.js.ep:122
msgid "Hit Ctrl+C, then Enter to copy the short link"
msgstr ""
#: themes/default/templates/layouts/default.html.ep:54
#: themes/default/templates/layouts/default.html.ep:48
msgid "Homepage"
msgstr ""
@@ -196,6 +200,10 @@ msgstr ""
msgid "Image delay"
msgstr ""
#: themes/default/templates/partial/common.js.ep:142
msgid "Image deleted"
msgstr ""
#: lib/Lutim/Controller.pm:752
msgid "Image not found."
msgstr ""
@@ -362,7 +370,7 @@ msgstr ""
#. ($tx->res->max_message_size)
#. ($c->req->max_message_size)
#. (config('max_file_size')
#: lib/Lutim/Controller.pm:309 lib/Lutim/Controller.pm:378 themes/default/templates/partial/lutim.js.ep:244
#: lib/Lutim/Controller.pm:309 lib/Lutim/Controller.pm:378 themes/default/templates/partial/lutim.js.ep:245
msgid "The file exceed the size limit (%1)"
msgstr ""
@@ -413,6 +421,10 @@ msgstr ""
msgid "Tweet it!"
msgstr ""
#: themes/default/templates/partial/common.js.ep:85
msgid "Unable to copy to clipboard"
msgstr ""
#. ($short)
#: lib/Lutim/Controller.pm:106 lib/Lutim/Controller.pm:200 lib/Lutim/Controller.pm:271
msgid "Unable to find the image %1."
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
@-moz-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.animate-spin{-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;display:inline-block}.uploader{border:2px dotted #a5a5c7;width:100%;color:#92aab0;text-align:center;vertical-align:middle;padding:30px 0;margin-bottom:10px;font-size:200%;cursor:default;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.uploader div.or{font-size:50%;font-weight:700;color:silver;padding:10px}@media (max-width:768px){.uploader div.browser label{max-width:95%}}@media (min-width:768px){.uploader div.browser label{width:300px}}.uploader div.browser label{background-color:#5a7bc2;color:#fff;padding:6px 0;font-size:40%;font-weight:700;cursor:pointer;border-radius:2px;position:relative;overflow:hidden;display:block;margin:20px auto 0;box-shadow:2px 2px 2px #888}.uploader div.browser span{cursor:pointer}.uploader div.browser input{position:absolute;top:0;right:0;margin:0;border:solid transparent;border-width:0 0 100px 200px;opacity:0;filter:alpha(opacity= 0);-o-transform:translate(250px,-50px) scale(1);-moz-transform:translate(-300px,0) scale(4);direction:ltr;cursor:pointer}.uploader div.browser label:hover{background-color:#427fed}@font-face{font-family:'markdown';src:url(../../font/markdown.eot?-6fnbp5);src:url(../../font/markdown.eot?#iefix-6fnbp5) format('embedded-opentype'),url(../../font/markdown.woff?-6fnbp5) format('woff'),url(../../font/markdown.ttf?-6fnbp5) format('truetype'),url(../../font/markdown.svg?-6fnbp5#markdown) format('svg');font-weight:400;font-style:normal}[class*=" markdown-"],[class^=markdown-]{font-family:'markdown';speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.markdown-mark:before{content:"\e600"}.markdown-mark-solid:before{content:"\e601"}
+60
View File
@@ -0,0 +1,60 @@
/*!
* Toastify js 1.2.0
* https://github.com/apvarun/toastify-js
* @license MIT licensed
*
* Copyright (C) 2018 Varun A P
*/
.toastify {
padding: 12px 20px;
color: #ffffff;
display: inline-block;
box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3);
background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);
background: linear-gradient(135deg, #73a5ff, #5477f5);
position: fixed;
opacity: 0;
transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
border-radius: 2px;
cursor: pointer;
text-decoration: none;
max-width: calc(50% - 20px);
}
.toastify.on {
opacity: 1;
}
.toast-close {
opacity: 0.4;
padding: 0 5px;
}
.right {
right: 15px;
}
.left {
left: 15px;
}
.top {
top: -150px;
}
.bottom {
bottom: -150px;
}
.rounded {
border-radius: 25px;
}
.avatar{
width: 1.5em;
height: 1.5em;
margin: 0 5px;
border-radius: 2px;
}
@media only screen and (max-width: 360px){
.right, .left{
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
max-width: fit-content;
}
}
+4 -1
View File
@@ -50,7 +50,10 @@ function share(url) {
}
});
}
function evaluateCopyAll() {
function evaluateCopyAll(e) {
if (e) {
e.preventDefault();
}
setTimeout(function() {
if ($('.view-link-input').length === 0) {
$('#copy-all').parent().remove();
+315
View File
@@ -0,0 +1,315 @@
/*!
* Toastify js 1.2.0
* https://github.com/apvarun/toastify-js
* @license MIT licensed
*
* Copyright (C) 2018 Varun A P
*/
;
(function (root, factory) {
if(typeof module === "object" && module.exports) {
require('./toastify.css');
module.exports = factory();
} else {
root.Toastify = factory();
}
}(this, function (global) {
// Object initialization
var Toastify = function (options) {
// Returning a new init object
return new Toastify.lib.init(options);
},
// Library version
version = "1.2.0";
// Defining the prototype of the object
Toastify.lib = Toastify.prototype = {
toastify: version,
constructor: Toastify,
// Initializing the object with required parameters
init: function (options) {
// Verifying and validating the input object
if (!options) {
options = {};
}
// Creating the options object
this.options = {};
// Validating the options
this.options.text = options.text || 'Hi there!'; // Display message
this.options.duration = options.duration || 3000; // Display duration
this.options.selector = options.selector; // Parent selector
this.options.callback = options.callback || function () { }; // Callback after display
this.options.destination = options.destination; // On-click destination
this.options.newWindow = options.newWindow || false; // Open destination in new window
this.options.close = options.close || false; // Show toast close icon
this.options.gravity = (options.gravity == "bottom") ? "bottom" : "top"; // toast position - top or bottom
this.options.positionLeft = options.positionLeft || false; // toast position - left or right
this.options.backgroundColor = options.backgroundColor || "linear-gradient(135deg, #73a5ff, #5477f5)"; // toast position - left or right
this.options.avatar = options.avatar || ""; // toast position - left or right
// Returning the current object for chaining functions
return this;
},
// Building the DOM element
buildToast: function () {
// Validating if the options are defined
if (!this.options) {
throw "Toastify is not initialized";
}
// Creating the DOM object
var divElement = document.createElement("div");
divElement.className = 'toastify on';
// Positioning toast to left or right
if (this.options.positionLeft === true) {
divElement.className += " left";
} else {
divElement.className += " right";
}
// Assigning gravity of element
divElement.className += " " + this.options.gravity;
divElement.style.background = this.options.backgroundColor;
// Adding the toast message
divElement.innerHTML = this.options.text;
if (this.options.avatar !== "") {
var avatarElement = document.createElement("img");
avatarElement.src = this.options.avatar;
avatarElement.className = "avatar";
if (this.options.positionLeft === true) {
// Adding close icon on the left of content
divElement.appendChild(avatarElement);
} else {
// Adding close icon on the right of content
divElement.insertAdjacentElement('beforeend', avatarElement);
}
}
// Adding a close icon to the toast
if (this.options.close === true) {
// Create a span for close element
var closeElement = document.createElement("span");
closeElement.innerHTML = "&#10006;";
closeElement.className = 'toast-close';
// Triggering the removal of toast from DOM on close click
closeElement.addEventListener('click', function (event) {
event.stopPropagation();
this.removeElement(event.target.parentElement);
window.clearTimeout(event.target.parentElement.timeOutValue);
}.bind(this));
//Calculating screen width
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
// Adding the close icon to the toast element
// Display on the right if screen width is less than or equal to 360px
if (this.options.positionLeft === true && width > 360) {
// Adding close icon on the left of content
divElement.insertAdjacentElement('afterbegin', closeElement);
} else {
// Adding close icon on the right of content
divElement.appendChild(closeElement);
}
}
// Adding an on-click destination path
if (typeof this.options.destination !== 'undefined') {
divElement.addEventListener('click', function (event) {
event.stopPropagation();
if(this.options.newWindow === true){
window.open(this.options.destination, '_blank')
} else {
window.location = this.options.destination;
}
}.bind(this));
}
// Returning the generated element
return divElement;
},
// Displaying the toast
showToast: function () {
// Creating the DOM object for the toast
var toastElement = this.buildToast();
// Getting the root element to with the toast needs to be added
var rootElement;
if (typeof this.options.selector === "undefined") {
rootElement = document.body;
} else {
rootElement = document.getElementById(this.options.selector);
}
// Validating if root element is present in DOM
if (!rootElement) {
throw "Root element is not defined";
}
// Adding the DOM element
rootElement.insertBefore(toastElement, rootElement.firstChild);
// Repositioning the toasts in case multiple toasts are present
Toastify.reposition();
toastElement.timeOutValue = window.setTimeout(function () {
// Remove the toast from DOM
this.removeElement(toastElement);
}.bind(this), this.options.duration); // Binding `this` for function invocation
// Supporting function chaining
return this;
},
// Removing the element from the DOM
removeElement: function (toastElement) {
// Hiding the element
// toastElement.classList.remove("on");
toastElement.className = toastElement.className.replace(" on","");
// Removing the element from DOM after transition end
window.setTimeout(function () {
// Remove the elemenf from the DOM
toastElement.parentNode.removeChild(toastElement);
// Calling the callback function
this.options.callback.call(toastElement);
// Repositioning the toasts again
Toastify.reposition();
}.bind(this), 400); // Binding `this` for function invocation
}
}
// Positioning the toasts on the DOM
Toastify.reposition = function () {
// Top margins with gravity
var topLeftOffsetSize = {
top: 15,
bottom: 15
};
var topRightOffsetSize = {
top: 15,
bottom: 15
};
var offsetSize = {
top: 15,
bottom: 15
};
// Get all toast messages on the DOM
var allToasts = document.getElementsByClassName('toastify');
var classUsed;
// Modifying the position of each toast element
for (var i = 0; i < allToasts.length; i++) {
// Getting the applied gravity
if (containsClass(allToasts[i], 'top') === true) {
classUsed = "top";
} else {
classUsed = "bottom";
}
var height = allToasts[i].offsetHeight;
// Spacing between toasts
var offset = 15;
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
// Show toast in center if screen with less than or qual to 360px
if (width <= 360) {
// Setting the position
allToasts[i].style[classUsed] = offsetSize[classUsed] + 'px';
offsetSize[classUsed] += height + offset;
} else {
if (containsClass(allToasts[i], 'left') === true) {
// Setting the position
allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + 'px';
topLeftOffsetSize[classUsed] += height + offset;
} else {
// Setting the position
allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + 'px';
topRightOffsetSize[classUsed] += height + offset;
}
}
}
// Supporting function chaining
return this;
}
function containsClass(elem, yourClass) {
if(!elem || typeof yourClass !== 'string') {
return false;
} else if(elem.className && elem.className.trim().split(/\s+/gi).indexOf(yourClass) > -1) {
return true;
} else {
return false;
}
}
// Setting up the prototype for the init object
Toastify.lib.init.prototype = Toastify.lib;
// Returning the Toastify function to be assigned to the window object/module
return Toastify;
}));
@@ -21,20 +21,14 @@
<link rel="apple-touch-icon" sizes="120x120" href="<%= url_for('/img/lutim120.png') %>">
<link rel="apple-touch-icon" sizes="152x152" href="<%= url_for('/img/lutim152.png') %>">
<link rel="apple-touch-icon-precomposed" sizes="128x128" href="<%= url_for('/img/lutim128.png') %>">
%= stylesheet '/css/bootstrap.min.css'
%= stylesheet '/css/fontello-embedded.css'
%= stylesheet '/css/hennypenny.css'
%= stylesheet '/css/lutim.css'
%= stylesheet '/css/common.min.css'
% if (current_route 'stats') {
%= stylesheet '/css/morris-0.4.3.min.css'
% } else {
%= stylesheet '/css/animation.css'
%= stylesheet '/css/uploader.css'
%= stylesheet '/css/markdown.css'
%= stylesheet '/css/not_stats.min.css'
% }
% if (current_route 'gallery') {
%= stylesheet '/css/photoswipe.css'
%= stylesheet '/css/default-skin/default-skin.css'
%= stylesheet '/css/gallery.min.css'
% }
%= javascript '/js/jquery-3.2.1.min.js'
</head>
@@ -72,6 +66,7 @@
% if (defined(config('piwik_img'))) {
<img src="<%== config('piwik_img') %>" style="border:0" alt="">
% }
%= javascript '/js/toastify.js'
%= javascript '/js/bootstrap.min.js'
% if (current_route 'stats') {
%= javascript '/js/lutim.js'
+28 -1
View File
@@ -81,7 +81,25 @@ function copyToClipboard(el) {
var msg = successful ? 'successful' : 'unsuccessful';
console.debug('Copying text command was ' + msg);
if (!successful) {
Toastify({
text: '<%= l('Unable to copy to clipboard') %>',
duration: 3000,
newWindow: true,
close: true,
gravity: 'bottom',
positionLeft: false,
backgroundColor: '#f2dede'
}).showToast();
throw new Error('Copying text command was ' + msg);
} else {
Toastify({
text: '<%= l('Copied to clipboard') %>',
duration: 3000,
newWindow: true,
close: true,
gravity: 'bottom',
positionLeft: false
}).showToast();
}
} catch (err) {
prompt('<%= l('Hit Ctrl+C, then Enter to copy the short link') %>', el.val());
@@ -105,7 +123,8 @@ function copyAllToClipboard() {
}
}
function delImage() {
function delImage(e) {
e.preventDefault();
var short = $(this).attr('data-short');
var token = $(this).attr('data-token');
$.ajax({
@@ -119,6 +138,14 @@ function delImage() {
$('#alert-'+short).remove();
evaluateCopyAll();
delItem(short);
Toastify({
text: '<%= l('Image deleted') %>',
duration: 3000,
newWindow: true,
close: true,
gravity: 'bottom',
positionLeft: false
}).showToast();
} else {
alert(data.msg);
}
+2 -1
View File
@@ -222,7 +222,8 @@ function bindddz(firstview, deleteday) {
);
}
$('.messages').append(buildMessage(data.success, data.msg));
$('#del-'+data.msg.real_short).on('click', function() {
$('#del-'+data.msg.real_short).on('click', function(e) {
e.preventDefault();
rmFromShortHash(data.msg.short+'.'+data.msg.ext)
rmFromZipHash(data.msg.short);
});