Merge pull request #13957 from nextcloud/refactor/oc-search-passwordconfirm-util
Move OC.Search, OC.PasswordConfirmation and OC.Util to the server bundle
This commit is contained in:
commit
8709f6b218
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
515
core/js/js.js
515
core/js/js.js
|
@ -492,13 +492,6 @@ Object.assign(window.OC, {
|
|||
return path;
|
||||
},
|
||||
|
||||
/**
|
||||
* Do a search query and display the results
|
||||
* @param {string} query the search query
|
||||
*/
|
||||
search: function (query) {
|
||||
OC.Search.search(query, null, 0, 30);
|
||||
},
|
||||
/**
|
||||
* Dialog helper for jquery dialogs.
|
||||
*
|
||||
|
@ -871,13 +864,6 @@ Object.assign(window.OC, {
|
|||
});
|
||||
|
||||
/**
|
||||
* @namespace OC.search
|
||||
*/
|
||||
OC.search.customResults = {};
|
||||
/**
|
||||
* @deprecated use get/setFormatter() instead
|
||||
*/
|
||||
OC.search.resultTypes = {};
|
||||
|
||||
OC.addStyle.loaded=[];
|
||||
OC.addScript.loaded=[];
|
||||
|
@ -1323,134 +1309,8 @@ function initCore() {
|
|||
OC.PasswordConfirmation.init();
|
||||
}
|
||||
|
||||
OC.PasswordConfirmation = {
|
||||
callback: null,
|
||||
pageLoadTime: null,
|
||||
init: function() {
|
||||
$('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));
|
||||
this.pageLoadTime = moment.now();
|
||||
},
|
||||
|
||||
requiresPasswordConfirmation: function() {
|
||||
var serverTimeDiff = this.pageLoadTime - (nc_pageLoad * 1000);
|
||||
var timeSinceLogin = moment.now() - (serverTimeDiff + (nc_lastLogin * 1000));
|
||||
|
||||
// if timeSinceLogin > 30 minutes and user backend allows password confirmation
|
||||
return (backendAllowsPasswordConfirmation && timeSinceLogin > 30 * 60 * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} callback
|
||||
*/
|
||||
requirePasswordConfirmation: function(callback, options, rejectCallback) {
|
||||
options = typeof options !== 'undefined' ? options : {};
|
||||
var defaults = {
|
||||
title: t('core','Authentication required'),
|
||||
text: t(
|
||||
'core',
|
||||
'This action requires you to confirm your password'
|
||||
),
|
||||
confirm: t('core', 'Confirm'),
|
||||
label: t('core','Password'),
|
||||
error: '',
|
||||
};
|
||||
|
||||
var config = _.extend(defaults, options);
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this.requiresPasswordConfirmation()) {
|
||||
OC.dialogs.prompt(
|
||||
config.text,
|
||||
config.title,
|
||||
function (result, password) {
|
||||
if (result && password !== '') {
|
||||
self._confirmPassword(password, config);
|
||||
} else if (_.isFunction(rejectCallback)) {
|
||||
rejectCallback()
|
||||
}
|
||||
},
|
||||
true,
|
||||
config.label,
|
||||
true
|
||||
).then(function() {
|
||||
var $dialog = $('.oc-dialog:visible');
|
||||
$dialog.find('.ui-icon').remove();
|
||||
$dialog.addClass('password-confirmation');
|
||||
if (config.error !== '') {
|
||||
var $error = $('<p></p>').addClass('msg warning').text(config.error);
|
||||
}
|
||||
$dialog.find('.oc-dialog-content').append($error);
|
||||
$dialog.find('.oc-dialog-buttonrow').addClass('aside');
|
||||
|
||||
var $buttons = $dialog.find('button');
|
||||
$buttons.eq(0).hide();
|
||||
$buttons.eq(1).text(config.confirm);
|
||||
});
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
},
|
||||
|
||||
_confirmPassword: function(password, config) {
|
||||
var self = this;
|
||||
|
||||
$.ajax({
|
||||
url: OC.generateUrl('/login/confirm'),
|
||||
data: {
|
||||
password: password
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(response) {
|
||||
nc_lastLogin = response.lastLogin;
|
||||
|
||||
if (_.isFunction(self.callback)) {
|
||||
self.callback();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
config.error = t('core', 'Failed to authenticate, try again');
|
||||
OC.PasswordConfirmation.requirePasswordConfirmation(self.callback, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(initCore);
|
||||
|
||||
/**
|
||||
* Returns a human readable file size
|
||||
* @param {number} size Size in bytes
|
||||
* @param {boolean} skipSmallSizes return '< 1 kB' for small files
|
||||
* @return {string}
|
||||
*/
|
||||
function humanFileSize(size, skipSmallSizes) {
|
||||
var humanList = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
// Calculate Log with base 1024: size = 1024 ** order
|
||||
var order = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
|
||||
// Stay in range of the byte sizes that are defined
|
||||
order = Math.min(humanList.length - 1, order);
|
||||
var readableFormat = humanList[order];
|
||||
var relativeSize = (size / Math.pow(1024, order)).toFixed(1);
|
||||
if(skipSmallSizes === true && order === 0) {
|
||||
if(relativeSize !== "0.0"){
|
||||
return '< 1 KB';
|
||||
} else {
|
||||
return '0 KB';
|
||||
}
|
||||
}
|
||||
if(order < 2){
|
||||
relativeSize = parseFloat(relativeSize).toFixed(0);
|
||||
}
|
||||
else if(relativeSize.substr(relativeSize.length-2,2)==='.0'){
|
||||
relativeSize=relativeSize.substr(0,relativeSize.length-2);
|
||||
}
|
||||
else{
|
||||
relativeSize = parseFloat(relativeSize).toLocaleString(OC.getCanonicalLocale());
|
||||
}
|
||||
return relativeSize + ' ' + readableFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an UNIX timestamp to a human understandable format
|
||||
* @param {number} timestamp UNIX timestamp
|
||||
|
@ -1486,381 +1346,6 @@ function relative_modified_date(timestamp) {
|
|||
return OC.Util.relativeModifiedDate(timestamp * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
* @namespace
|
||||
*/
|
||||
OC.Util = {
|
||||
// TODO: remove original functions from global namespace
|
||||
humanFileSize: humanFileSize,
|
||||
|
||||
/**
|
||||
* Returns a file size in bytes from a humanly readable string
|
||||
* Makes 2kB to 2048.
|
||||
* Inspired by computerFileSize in helper.php
|
||||
* @param {string} string file size in human readable format
|
||||
* @return {number} or null if string could not be parsed
|
||||
*
|
||||
*
|
||||
*/
|
||||
computerFileSize: function (string) {
|
||||
if (typeof string !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
var s = string.toLowerCase().trim();
|
||||
var bytes = null;
|
||||
|
||||
var bytesArray = {
|
||||
'b' : 1,
|
||||
'k' : 1024,
|
||||
'kb': 1024,
|
||||
'mb': 1024 * 1024,
|
||||
'm' : 1024 * 1024,
|
||||
'gb': 1024 * 1024 * 1024,
|
||||
'g' : 1024 * 1024 * 1024,
|
||||
'tb': 1024 * 1024 * 1024 * 1024,
|
||||
't' : 1024 * 1024 * 1024 * 1024,
|
||||
'pb': 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
'p' : 1024 * 1024 * 1024 * 1024 * 1024
|
||||
};
|
||||
|
||||
var matches = s.match(/^[\s+]?([0-9]*)(\.([0-9]+))?( +)?([kmgtp]?b?)$/i);
|
||||
if (matches !== null) {
|
||||
bytes = parseFloat(s);
|
||||
if (!isFinite(bytes)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (matches[5]) {
|
||||
bytes = bytes * bytesArray[matches[5]];
|
||||
}
|
||||
|
||||
bytes = Math.round(bytes);
|
||||
return bytes;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param timestamp
|
||||
* @param format
|
||||
* @returns {string} timestamp formatted as requested
|
||||
*/
|
||||
formatDate: function (timestamp, format) {
|
||||
format = format || "LLL";
|
||||
return moment(timestamp).format(format);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param timestamp
|
||||
* @returns {string} human readable difference from now
|
||||
*/
|
||||
relativeModifiedDate: function (timestamp) {
|
||||
var diff = moment().diff(moment(timestamp));
|
||||
if (diff >= 0 && diff < 45000 ) {
|
||||
return t('core', 'seconds ago');
|
||||
}
|
||||
return moment(timestamp).fromNow();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether this is IE
|
||||
*
|
||||
* @return {bool} true if this is IE, false otherwise
|
||||
*/
|
||||
isIE: function() {
|
||||
return $('html').hasClass('ie');
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the width of a generic browser scrollbar
|
||||
*
|
||||
* @return {int} width of scrollbar
|
||||
*/
|
||||
getScrollBarWidth: function() {
|
||||
if (this._scrollBarWidth) {
|
||||
return this._scrollBarWidth;
|
||||
}
|
||||
|
||||
var inner = document.createElement('p');
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = document.createElement('div');
|
||||
outer.style.position = "absolute";
|
||||
outer.style.top = "0px";
|
||||
outer.style.left = "0px";
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "200px";
|
||||
outer.style.height = "150px";
|
||||
outer.style.overflow = "hidden";
|
||||
outer.appendChild (inner);
|
||||
|
||||
document.body.appendChild (outer);
|
||||
var w1 = inner.offsetWidth;
|
||||
outer.style.overflow = 'scroll';
|
||||
var w2 = inner.offsetWidth;
|
||||
if(w1 === w2) {
|
||||
w2 = outer.clientWidth;
|
||||
}
|
||||
|
||||
document.body.removeChild (outer);
|
||||
|
||||
this._scrollBarWidth = (w1 - w2);
|
||||
|
||||
return this._scrollBarWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the time component from a given date
|
||||
*
|
||||
* @param {Date} date date
|
||||
* @return {Date} date with stripped time
|
||||
*/
|
||||
stripTime: function(date) {
|
||||
// FIXME: likely to break when crossing DST
|
||||
// would be better to use a library like momentJS
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
},
|
||||
|
||||
_chunkify: function(t) {
|
||||
// Adapted from http://my.opera.com/GreyWyvern/blog/show.dml/1671288
|
||||
var tz = [], x = 0, y = -1, n = 0, code, c;
|
||||
|
||||
while (x < t.length) {
|
||||
c = t.charAt(x);
|
||||
// only include the dot in strings
|
||||
var m = ((!n && c === '.') || (c >= '0' && c <= '9'));
|
||||
if (m !== n) {
|
||||
// next chunk
|
||||
y++;
|
||||
tz[y] = '';
|
||||
n = m;
|
||||
}
|
||||
tz[y] += c;
|
||||
x++;
|
||||
}
|
||||
return tz;
|
||||
},
|
||||
/**
|
||||
* Compare two strings to provide a natural sort
|
||||
* @param a first string to compare
|
||||
* @param b second string to compare
|
||||
* @return -1 if b comes before a, 1 if a comes before b
|
||||
* or 0 if the strings are identical
|
||||
*/
|
||||
naturalSortCompare: function(a, b) {
|
||||
var x;
|
||||
var aa = OC.Util._chunkify(a);
|
||||
var bb = OC.Util._chunkify(b);
|
||||
|
||||
for (x = 0; aa[x] && bb[x]; x++) {
|
||||
if (aa[x] !== bb[x]) {
|
||||
var aNum = Number(aa[x]), bNum = Number(bb[x]);
|
||||
// note: == is correct here
|
||||
if (aNum == aa[x] && bNum == bb[x]) {
|
||||
return aNum - bNum;
|
||||
} else {
|
||||
// Note: This locale setting isn't supported by all browsers but for the ones
|
||||
// that do there will be more consistency between client-server sorting
|
||||
return aa[x].localeCompare(bb[x], OC.getLanguage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return aa.length - bb.length;
|
||||
},
|
||||
/**
|
||||
* Calls the callback in a given interval until it returns true
|
||||
* @param {function} callback
|
||||
* @param {integer} interval in milliseconds
|
||||
*/
|
||||
waitFor: function(callback, interval) {
|
||||
var internalCallback = function() {
|
||||
if(callback() !== true) {
|
||||
setTimeout(internalCallback, interval);
|
||||
}
|
||||
};
|
||||
|
||||
internalCallback();
|
||||
},
|
||||
/**
|
||||
* Checks if a cookie with the given name is present and is set to the provided value.
|
||||
* @param {string} name name of the cookie
|
||||
* @param {string} value value of the cookie
|
||||
* @return {boolean} true if the cookie with the given name has the given value
|
||||
*/
|
||||
isCookieSetToValue: function(name, value) {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i=0; i < cookies.length; i++) {
|
||||
var cookie = cookies[i].split('=');
|
||||
if (cookie[0].trim() === name && cookie[1].trim() === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class for the history API,
|
||||
* includes fallback to using the URL hash when
|
||||
* the browser doesn't support the history API.
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
OC.Util.History = {
|
||||
_handlers: [],
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
* @param {boolean} [replace=false] whether to replace instead of pushing
|
||||
*/
|
||||
_pushState: function(params, url, replace) {
|
||||
var strParams;
|
||||
if (typeof(params) === 'string') {
|
||||
strParams = params;
|
||||
}
|
||||
else {
|
||||
strParams = OC.buildQueryString(params);
|
||||
}
|
||||
if (window.history.pushState) {
|
||||
url = url || location.pathname + '?' + strParams;
|
||||
// Workaround for bug with SVG and window.history.pushState on Firefox < 51
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=652991
|
||||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
if (isFirefox && parseInt(navigator.userAgent.split('/').pop()) < 51) {
|
||||
var patterns = document.querySelectorAll('[fill^="url(#"], [stroke^="url(#"], [filter^="url(#invert"]');
|
||||
for (var i = 0, ii = patterns.length, pattern; i < ii; i++) {
|
||||
pattern = patterns[i];
|
||||
pattern.style.fill = pattern.style.fill;
|
||||
pattern.style.stroke = pattern.style.stroke;
|
||||
pattern.removeAttribute("filter");
|
||||
pattern.setAttribute("filter", "url(#invert)");
|
||||
}
|
||||
}
|
||||
if (replace) {
|
||||
window.history.replaceState(params, '', url);
|
||||
} else {
|
||||
window.history.pushState(params, '', url);
|
||||
}
|
||||
}
|
||||
// use URL hash for IE8
|
||||
else {
|
||||
window.location.hash = '?' + strParams;
|
||||
// inhibit next onhashchange that just added itself
|
||||
// to the event queue
|
||||
this._cancelPop = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
*/
|
||||
pushState: function(params, url) {
|
||||
return this._pushState(params, url, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
*/
|
||||
replaceState: function(params, url) {
|
||||
return this._pushState(params, url, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a popstate handler
|
||||
*
|
||||
* @param handler function
|
||||
*/
|
||||
addOnPopStateHandler: function(handler) {
|
||||
this._handlers.push(handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a query string from the hash part of the URL.
|
||||
* (workaround for IE8 / IE9)
|
||||
*/
|
||||
_parseHashQuery: function() {
|
||||
var hash = window.location.hash,
|
||||
pos = hash.indexOf('?');
|
||||
if (pos >= 0) {
|
||||
return hash.substr(pos + 1);
|
||||
}
|
||||
if (hash.length) {
|
||||
// remove hash sign
|
||||
return hash.substr(1);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_decodeQuery: function(query) {
|
||||
return query.replace(/\+/g, ' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse the query/search part of the URL.
|
||||
* Also try and parse it from the URL hash (for IE8)
|
||||
*
|
||||
* @return map of parameters
|
||||
*/
|
||||
parseUrlQuery: function() {
|
||||
var query = this._parseHashQuery(),
|
||||
params;
|
||||
// try and parse from URL hash first
|
||||
if (query) {
|
||||
params = OC.parseQueryString(this._decodeQuery(query));
|
||||
}
|
||||
// else read from query attributes
|
||||
params = _.extend(params || {}, OC.parseQueryString(this._decodeQuery(location.search)));
|
||||
return params || {};
|
||||
},
|
||||
|
||||
_onPopState: function(e) {
|
||||
if (this._cancelPop) {
|
||||
this._cancelPop = false;
|
||||
return;
|
||||
}
|
||||
var params;
|
||||
if (!this._handlers.length) {
|
||||
return;
|
||||
}
|
||||
params = (e && e.state);
|
||||
if (_.isString(params)) {
|
||||
params = OC.parseQueryString(params);
|
||||
} else if (!params) {
|
||||
params = this.parseUrlQuery() || {};
|
||||
}
|
||||
for (var i = 0; i < this._handlers.length; i++) {
|
||||
this._handlers[i](params);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// fallback to hashchange when no history support
|
||||
if (window.history.pushState) {
|
||||
window.onpopstate = _.bind(OC.Util.History._onPopState, OC.Util.History);
|
||||
|
|
|
@ -27,7 +27,10 @@ import EventSource from './eventsource'
|
|||
import L10N from './l10n'
|
||||
import msg from './msg'
|
||||
import Notification from './notification'
|
||||
import PasswordConfirmation from './password-confirmation'
|
||||
import Plugins from './plugins'
|
||||
import search from './search'
|
||||
import Util from './util'
|
||||
|
||||
/** @namespace OC */
|
||||
export default {
|
||||
|
@ -39,5 +42,8 @@ export default {
|
|||
L10N,
|
||||
msg,
|
||||
Notification,
|
||||
PasswordConfirmation,
|
||||
Plugins,
|
||||
search,
|
||||
Util,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/* global nc_pageLoad */
|
||||
|
||||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import _ from 'underscore'
|
||||
import $ from 'jquery'
|
||||
import moment from 'moment'
|
||||
|
||||
import OC from './index'
|
||||
|
||||
/**
|
||||
* @namespace OC.PasswordConfirmation
|
||||
*/
|
||||
export default {
|
||||
callback: null,
|
||||
|
||||
pageLoadTime: null,
|
||||
|
||||
init: function () {
|
||||
$('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));
|
||||
this.pageLoadTime = moment.now();
|
||||
},
|
||||
|
||||
requiresPasswordConfirmation: function () {
|
||||
var serverTimeDiff = this.pageLoadTime - (nc_pageLoad * 1000);
|
||||
var timeSinceLogin = moment.now() - (serverTimeDiff + (nc_lastLogin * 1000));
|
||||
|
||||
// if timeSinceLogin > 30 minutes and user backend allows password confirmation
|
||||
return (backendAllowsPasswordConfirmation && timeSinceLogin > 30 * 60 * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} callback
|
||||
*/
|
||||
requirePasswordConfirmation: function (callback, options, rejectCallback) {
|
||||
options = typeof options !== 'undefined' ? options : {};
|
||||
var defaults = {
|
||||
title: t('core', 'Authentication required'),
|
||||
text: t(
|
||||
'core',
|
||||
'This action requires you to confirm your password'
|
||||
),
|
||||
confirm: t('core', 'Confirm'),
|
||||
label: t('core', 'Password'),
|
||||
error: '',
|
||||
};
|
||||
|
||||
var config = _.extend(defaults, options);
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this.requiresPasswordConfirmation()) {
|
||||
OC.dialogs.prompt(
|
||||
config.text,
|
||||
config.title,
|
||||
function (result, password) {
|
||||
if (result && password !== '') {
|
||||
self._confirmPassword(password, config);
|
||||
} else if (_.isFunction(rejectCallback)) {
|
||||
rejectCallback()
|
||||
}
|
||||
},
|
||||
true,
|
||||
config.label,
|
||||
true
|
||||
).then(function () {
|
||||
var $dialog = $('.oc-dialog:visible');
|
||||
$dialog.find('.ui-icon').remove();
|
||||
$dialog.addClass('password-confirmation');
|
||||
if (config.error !== '') {
|
||||
var $error = $('<p></p>').addClass('msg warning').text(config.error);
|
||||
}
|
||||
$dialog.find('.oc-dialog-content').append($error);
|
||||
$dialog.find('.oc-dialog-buttonrow').addClass('aside');
|
||||
|
||||
var $buttons = $dialog.find('button');
|
||||
$buttons.eq(0).hide();
|
||||
$buttons.eq(1).text(config.confirm);
|
||||
});
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
},
|
||||
|
||||
_confirmPassword: function (password, config) {
|
||||
var self = this;
|
||||
|
||||
$.ajax({
|
||||
url: OC.generateUrl('/login/confirm'),
|
||||
data: {
|
||||
password: password
|
||||
},
|
||||
type: 'POST',
|
||||
success: function (response) {
|
||||
nc_lastLogin = response.lastLogin;
|
||||
|
||||
if (_.isFunction(self.callback)) {
|
||||
self.callback();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
config.error = t('core', 'Failed to authenticate, try again');
|
||||
OC.PasswordConfirmation.requirePasswordConfirmation(self.callback, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import OC from './index'
|
||||
|
||||
/**
|
||||
* Do a search query and display the results
|
||||
* @param {string} query the search query
|
||||
*/
|
||||
const search = function (query) {
|
||||
OC.Search.search(query, null, 0, 30);
|
||||
};
|
||||
|
||||
/**
|
||||
* @namespace OC.search
|
||||
*/
|
||||
search.customResults = {};
|
||||
/**
|
||||
* @deprecated use get/setFormatter() instead
|
||||
*/
|
||||
search.resultTypes = {};
|
||||
|
||||
export default search;
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import _ from 'underscore'
|
||||
|
||||
import OC from './index'
|
||||
|
||||
/**
|
||||
* Utility class for the history API,
|
||||
* includes fallback to using the URL hash when
|
||||
* the browser doesn't support the history API.
|
||||
*
|
||||
* @namespace OC.Util.History
|
||||
*/
|
||||
export default {
|
||||
|
||||
_handlers: [],
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
* @param {boolean} [replace=false] whether to replace instead of pushing
|
||||
*/
|
||||
_pushState: function (params, url, replace) {
|
||||
var strParams;
|
||||
if (typeof (params) === 'string') {
|
||||
strParams = params;
|
||||
} else {
|
||||
strParams = OC.buildQueryString(params);
|
||||
}
|
||||
if (window.history.pushState) {
|
||||
url = url || location.pathname + '?' + strParams;
|
||||
// Workaround for bug with SVG and window.history.pushState on Firefox < 51
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=652991
|
||||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
if (isFirefox && parseInt(navigator.userAgent.split('/').pop()) < 51) {
|
||||
var patterns = document.querySelectorAll('[fill^="url(#"], [stroke^="url(#"], [filter^="url(#invert"]');
|
||||
for (var i = 0, ii = patterns.length, pattern; i < ii; i++) {
|
||||
pattern = patterns[i];
|
||||
pattern.style.fill = pattern.style.fill;
|
||||
pattern.style.stroke = pattern.style.stroke;
|
||||
pattern.removeAttribute("filter");
|
||||
pattern.setAttribute("filter", "url(#invert)");
|
||||
}
|
||||
}
|
||||
if (replace) {
|
||||
window.history.replaceState(params, '', url);
|
||||
} else {
|
||||
window.history.pushState(params, '', url);
|
||||
}
|
||||
}
|
||||
// use URL hash for IE8
|
||||
else {
|
||||
window.location.hash = '?' + strParams;
|
||||
// inhibit next onhashchange that just added itself
|
||||
// to the event queue
|
||||
this._cancelPop = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
*/
|
||||
pushState: function (params, url) {
|
||||
return this._pushState(params, url, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param {Object|string} params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {string} [url] URL to be used, otherwise the current URL will be used,
|
||||
* using the params as query string
|
||||
*/
|
||||
replaceState: function (params, url) {
|
||||
return this._pushState(params, url, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a popstate handler
|
||||
*
|
||||
* @param handler function
|
||||
*/
|
||||
addOnPopStateHandler: function (handler) {
|
||||
this._handlers.push(handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a query string from the hash part of the URL.
|
||||
* (workaround for IE8 / IE9)
|
||||
*/
|
||||
_parseHashQuery: function () {
|
||||
var hash = window.location.hash,
|
||||
pos = hash.indexOf('?');
|
||||
if (pos >= 0) {
|
||||
return hash.substr(pos + 1);
|
||||
}
|
||||
if (hash.length) {
|
||||
// remove hash sign
|
||||
return hash.substr(1);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_decodeQuery: function (query) {
|
||||
return query.replace(/\+/g, ' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse the query/search part of the URL.
|
||||
* Also try and parse it from the URL hash (for IE8)
|
||||
*
|
||||
* @return map of parameters
|
||||
*/
|
||||
parseUrlQuery: function () {
|
||||
var query = this._parseHashQuery(),
|
||||
params;
|
||||
// try and parse from URL hash first
|
||||
if (query) {
|
||||
params = OC.parseQueryString(this._decodeQuery(query));
|
||||
}
|
||||
// else read from query attributes
|
||||
params = _.extend(params || {}, OC.parseQueryString(this._decodeQuery(location.search)));
|
||||
return params || {};
|
||||
},
|
||||
|
||||
_onPopState: function (e) {
|
||||
if (this._cancelPop) {
|
||||
this._cancelPop = false;
|
||||
return;
|
||||
}
|
||||
var params;
|
||||
if (!this._handlers.length) {
|
||||
return;
|
||||
}
|
||||
params = (e && e.state);
|
||||
if (_.isString(params)) {
|
||||
params = OC.parseQueryString(params);
|
||||
} else if (!params) {
|
||||
params = this.parseUrlQuery() || {};
|
||||
}
|
||||
for (var i = 0; i < this._handlers.length; i++) {
|
||||
this._handlers[i](params);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/* global t */
|
||||
|
||||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import moment from 'moment'
|
||||
|
||||
import History from './util-history'
|
||||
import OC from './index'
|
||||
import humanFileSize from '../Util/human-file-size'
|
||||
|
||||
function chunkify(t) {
|
||||
// Adapted from http://my.opera.com/GreyWyvern/blog/show.dml/1671288
|
||||
let tz = [], x = 0, y = -1, n = 0, code, c;
|
||||
|
||||
while (x < t.length) {
|
||||
c = t.charAt(x);
|
||||
// only include the dot in strings
|
||||
var m = ((!n && c === '.') || (c >= '0' && c <= '9'));
|
||||
if (m !== n) {
|
||||
// next chunk
|
||||
y++;
|
||||
tz[y] = '';
|
||||
n = m;
|
||||
}
|
||||
tz[y] += c;
|
||||
x++;
|
||||
}
|
||||
return tz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
* @namespace OC.Util
|
||||
*/
|
||||
export default {
|
||||
|
||||
History,
|
||||
|
||||
// TODO: remove original functions from global namespace
|
||||
humanFileSize,
|
||||
|
||||
/**
|
||||
* Returns a file size in bytes from a humanly readable string
|
||||
* Makes 2kB to 2048.
|
||||
* Inspired by computerFileSize in helper.php
|
||||
* @param {string} string file size in human readable format
|
||||
* @return {number} or null if string could not be parsed
|
||||
*
|
||||
*
|
||||
*/
|
||||
computerFileSize: function (string) {
|
||||
if (typeof string !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
var s = string.toLowerCase().trim();
|
||||
var bytes = null;
|
||||
|
||||
var bytesArray = {
|
||||
'b': 1,
|
||||
'k': 1024,
|
||||
'kb': 1024,
|
||||
'mb': 1024 * 1024,
|
||||
'm': 1024 * 1024,
|
||||
'gb': 1024 * 1024 * 1024,
|
||||
'g': 1024 * 1024 * 1024,
|
||||
'tb': 1024 * 1024 * 1024 * 1024,
|
||||
't': 1024 * 1024 * 1024 * 1024,
|
||||
'pb': 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
'p': 1024 * 1024 * 1024 * 1024 * 1024
|
||||
};
|
||||
|
||||
var matches = s.match(/^[\s+]?([0-9]*)(\.([0-9]+))?( +)?([kmgtp]?b?)$/i);
|
||||
if (matches !== null) {
|
||||
bytes = parseFloat(s);
|
||||
if (!isFinite(bytes)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (matches[5]) {
|
||||
bytes = bytes * bytesArray[matches[5]];
|
||||
}
|
||||
|
||||
bytes = Math.round(bytes);
|
||||
return bytes;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param timestamp
|
||||
* @param format
|
||||
* @returns {string} timestamp formatted as requested
|
||||
*/
|
||||
formatDate: function (timestamp, format) {
|
||||
format = format || "LLL";
|
||||
return moment(timestamp).format(format);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param timestamp
|
||||
* @returns {string} human readable difference from now
|
||||
*/
|
||||
relativeModifiedDate: function (timestamp) {
|
||||
var diff = moment().diff(moment(timestamp));
|
||||
if (diff >= 0 && diff < 45000) {
|
||||
return t('core', 'seconds ago');
|
||||
}
|
||||
return moment(timestamp).fromNow();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether this is IE
|
||||
*
|
||||
* @return {bool} true if this is IE, false otherwise
|
||||
*/
|
||||
isIE: function () {
|
||||
return $('html').hasClass('ie');
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the width of a generic browser scrollbar
|
||||
*
|
||||
* @return {int} width of scrollbar
|
||||
*/
|
||||
getScrollBarWidth: function () {
|
||||
if (this._scrollBarWidth) {
|
||||
return this._scrollBarWidth;
|
||||
}
|
||||
|
||||
var inner = document.createElement('p');
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = document.createElement('div');
|
||||
outer.style.position = "absolute";
|
||||
outer.style.top = "0px";
|
||||
outer.style.left = "0px";
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "200px";
|
||||
outer.style.height = "150px";
|
||||
outer.style.overflow = "hidden";
|
||||
outer.appendChild(inner);
|
||||
|
||||
document.body.appendChild(outer);
|
||||
var w1 = inner.offsetWidth;
|
||||
outer.style.overflow = 'scroll';
|
||||
var w2 = inner.offsetWidth;
|
||||
if (w1 === w2) {
|
||||
w2 = outer.clientWidth;
|
||||
}
|
||||
|
||||
document.body.removeChild(outer);
|
||||
|
||||
this._scrollBarWidth = (w1 - w2);
|
||||
|
||||
return this._scrollBarWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the time component from a given date
|
||||
*
|
||||
* @param {Date} date date
|
||||
* @return {Date} date with stripped time
|
||||
*/
|
||||
stripTime: function (date) {
|
||||
// FIXME: likely to break when crossing DST
|
||||
// would be better to use a library like momentJS
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
},
|
||||
|
||||
/**
|
||||
* Compare two strings to provide a natural sort
|
||||
* @param a first string to compare
|
||||
* @param b second string to compare
|
||||
* @return -1 if b comes before a, 1 if a comes before b
|
||||
* or 0 if the strings are identical
|
||||
*/
|
||||
naturalSortCompare: function (a, b) {
|
||||
var x;
|
||||
var aa = chunkify(a);
|
||||
var bb = chunkify(b);
|
||||
|
||||
for (x = 0; aa[x] && bb[x]; x++) {
|
||||
if (aa[x] !== bb[x]) {
|
||||
var aNum = Number(aa[x]), bNum = Number(bb[x]);
|
||||
// note: == is correct here
|
||||
if (aNum == aa[x] && bNum == bb[x]) {
|
||||
return aNum - bNum;
|
||||
} else {
|
||||
// Note: This locale setting isn't supported by all browsers but for the ones
|
||||
// that do there will be more consistency between client-server sorting
|
||||
return aa[x].localeCompare(bb[x], OC.getLanguage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return aa.length - bb.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the callback in a given interval until it returns true
|
||||
* @param {function} callback
|
||||
* @param {integer} interval in milliseconds
|
||||
*/
|
||||
waitFor: function (callback, interval) {
|
||||
var internalCallback = function () {
|
||||
if (callback() !== true) {
|
||||
setTimeout(internalCallback, interval);
|
||||
}
|
||||
};
|
||||
|
||||
internalCallback();
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if a cookie with the given name is present and is set to the provided value.
|
||||
* @param {string} name name of the cookie
|
||||
* @param {string} value value of the cookie
|
||||
* @return {boolean} true if the cookie with the given name has the given value
|
||||
*/
|
||||
isCookieSetToValue: function (name, value) {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = cookies[i].split('=');
|
||||
if (cookie[0].trim() === name && cookie[1].trim() === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a human readable file size
|
||||
* @param {number} size Size in bytes
|
||||
* @param {boolean} skipSmallSizes return '< 1 kB' for small files
|
||||
* @return {string}
|
||||
*/
|
||||
export default function humanFileSize (size, skipSmallSizes) {
|
||||
var humanList = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
// Calculate Log with base 1024: size = 1024 ** order
|
||||
var order = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
|
||||
// Stay in range of the byte sizes that are defined
|
||||
order = Math.min(humanList.length - 1, order);
|
||||
var readableFormat = humanList[order];
|
||||
var relativeSize = (size / Math.pow(1024, order)).toFixed(1);
|
||||
if (skipSmallSizes === true && order === 0) {
|
||||
if (relativeSize !== "0.0") {
|
||||
return '< 1 KB';
|
||||
} else {
|
||||
return '0 KB';
|
||||
}
|
||||
}
|
||||
if (order < 2) {
|
||||
relativeSize = parseFloat(relativeSize).toFixed(0);
|
||||
} else if (relativeSize.substr(relativeSize.length - 2, 2) === '.0') {
|
||||
relativeSize = relativeSize.substr(0, relativeSize.length - 2);
|
||||
} else {
|
||||
relativeSize = parseFloat(relativeSize).toLocaleString(OC.getCanonicalLocale());
|
||||
}
|
||||
return relativeSize + ' ' + readableFormat;
|
||||
}
|
|
@ -52,6 +52,7 @@ import OC from './OC/index'
|
|||
import OCP from './OCP/index'
|
||||
import OCA from './OCA/index'
|
||||
import escapeHTML from './Util/escapeHTML'
|
||||
import humanFileSize from './Util/human-file-size'
|
||||
|
||||
window['_'] = _
|
||||
window['$'] = $
|
||||
|
@ -74,6 +75,7 @@ window['OC'] = OC
|
|||
window['OCP'] = OCP
|
||||
window['OCA'] = OCA
|
||||
window['escapeHTML'] = escapeHTML
|
||||
window['humanFileSize'] = humanFileSize
|
||||
|
||||
/**
|
||||
* translate a string
|
||||
|
|
Loading…
Reference in New Issue