Browse Source

Move jQuery plugins into modules and add them to the bundle

Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
tags/v16.0.0alpha1
Christoph Wurst 5 years ago
parent
commit
3ced9cd83d
No account linked to committer's email address

+ 0
- 6
core/js/core.json View File

@@ -1,12 +1,7 @@
{
"libraries": [
"jquery-showpassword.js",
"jquery.avatar.js",
"jquery.contactsmenu.js",
"placeholder.js"
],
"modules": [
"jquery.ocdialog.js",
"oc-dialogs.js",
"js.js",
"share.js",
@@ -18,7 +13,6 @@
"sharedialoglinkshareview.js",
"sharedialogresharerinfoview.js",
"sharedialogshareelistview.js",
"octemplate.js",
"contactsmenu_templates.js",
"public/appconfig.js",
"public/comments.js",

+ 202
- 15
core/js/dist/main.js
File diff suppressed because it is too large
View File


+ 1
- 1
core/js/dist/main.js.map
File diff suppressed because it is too large
View File


+ 0
- 127
core/js/jquery-showpassword.js View File

@@ -1,127 +0,0 @@
/*
* @name Show Password
* @description
* @version 1.3
* @requires Jquery 1.5
*
* @author Jan Jarfalk
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @special-thanks Michel Gratton
*
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
*/
(function($){
$.fn.extend({
showPassword: function(c) {
// Setup callback object
var callback = {'fn':null,'args':{}};
callback.fn = c;
// Clones passwords and turn the clones into text inputs
var cloneElement = function( element ) {
var $element = $(element);
var $clone = $("<input />");
// Name added for JQuery Validation compatibility
// Element name is required to avoid script warning.
$clone.attr({
'type' : 'text',
'class' : $element.attr('class'),
'style' : $element.attr('style'),
'size' : $element.attr('size'),
'name' : $element.attr('name')+'-clone',
'tabindex' : $element.attr('tabindex'),
'autocomplete' : 'off'
});

if($element.attr('placeholder') !== undefined) {
$clone.attr('placeholder', $element.attr('placeholder'));
}

return $clone;
};
// Transfers values between two elements
var update = function(a,b){
b.val(a.val());
};
// Shows a or b depending on checkbox
var setState = function( checkbox, a, b ){
if(checkbox.is(':checked')){
update(a,b);
b.show();
a.hide();
} else {
update(b,a);
b.hide();
a.show();
}
};
return this.each(function() {
var $input = $(this),
$checkbox = $($input.data('typetoggle'));
// Create clone
var $clone = cloneElement($input);
$clone.insertAfter($input);
// Set callback arguments
if(callback.fn){
callback.args.input = $input;
callback.args.checkbox = $checkbox;
callback.args.clone = $clone;
}

$checkbox.bind('click', function() {
setState( $checkbox, $input, $clone );
});
$input.bind('keyup', function() {
update( $input, $clone );
});
$clone.bind('keyup', function(){
update( $clone, $input );
// Added for JQuery Validation compatibility
// This will trigger validation if it's ON for keyup event
$input.trigger('keyup');
});
// Added for JQuery Validation compatibility
// This will trigger validation if it's ON for blur event
$clone.bind('blur', function() { $input.trigger('focusout'); });
setState( $checkbox, $input, $clone );

// set type of password field clone (type=text) to password right on submit
// to prevent browser save the value of this field
$clone.closest('form').submit(function(e) {
// .prop has to be used, because .attr throws
// an error while changing a type of an input
// element
$clone.prop('type', 'password');
});

if( callback.fn ){
callback.fn( callback.args );
}

});
}
});
})(jQuery);

+ 0
- 146
core/js/jquery.avatar.js View File

@@ -1,146 +0,0 @@
/**
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/

/**
* This plugin inserts the right avatar for the user, depending on, whether a
* custom avatar is uploaded - which it uses then - or not, and display a
* placeholder with the first letter of the users name instead.
* For this it queries the core_avatar_get route, thus this plugin is fit very
* tightly for owncloud, and it may not work anywhere else.
*
* You may use this on any <div></div>
* Here I'm using <div class="avatardiv"></div> as an example.
*
* There are 5 ways to call this:
*
* 1. $('.avatardiv').avatar('jdoe', 128);
* This will make the div to jdoe's fitting avatar, with a size of 128px.
*
* 2. $('.avatardiv').avatar('jdoe');
* This will make the div to jdoe's fitting avatar. If the div already has a
* height, it will be used for the avatars size. Otherwise this plugin will
* search for 'size' DOM data, to use for avatar size. If neither are available
* it will default to 64px.
*
* 3. $('.avatardiv').avatar();
* This will search the DOM for 'user' data, to use as the username. If there
* is no username available it will default to a placeholder with the value of
* "?". The size will be determined the same way, as the second example.
*
* 4. $('.avatardiv').avatar('jdoe', 128, true);
* This will behave like the first example, except it will also append random
* hashes to the custom avatar images, to force image reloading in IE8.
*
* 5. $('.avatardiv').avatar('jdoe', 128, undefined, true);
* This will behave like the first example, but it will hide the avatardiv, if
* it will display the default placeholder. undefined is the ie8fix from
* example 4 and can be either true, or false/undefined, to be ignored.
*
* 6. $('.avatardiv').avatar('jdoe', 128, undefined, true, callback);
* This will behave like the above example, but it will call the function
* defined in callback after the avatar is placed into the DOM.
*
*/

(function ($) {
$.fn.avatar = function(user, size, ie8fix, hidedefault, callback, displayname) {
var setAvatarForUnknownUser = function(target) {
target.imageplaceholder('?');
target.css('background-color', '#b9b9b9');
};

if (typeof(user) !== 'undefined') {
user = String(user);
}
if (typeof(displayname) !== 'undefined') {
displayname = String(displayname);
}

if (typeof(size) === 'undefined') {
if (this.height() > 0) {
size = this.height();
} else if (this.data('size') > 0) {
size = this.data('size');
} else {
size = 64;
}
}

this.height(size);
this.width(size);

if (typeof(user) === 'undefined') {
if (typeof(this.data('user')) !== 'undefined') {
user = this.data('user');
} else {
setAvatarForUnknownUser(this);
return;
}
}

// sanitize
user = String(user).replace(/\//g,'');

var $div = this;
var url;

// If this is our own avatar we have to use the version attribute
if (user === OC.getCurrentUser().uid) {
url = OC.generateUrl(
'/avatar/{user}/{size}?v={version}',
{
user: user,
size: Math.ceil(size * window.devicePixelRatio),
version: oc_userconfig.avatar.version
});
} else {
url = OC.generateUrl(
'/avatar/{user}/{size}',
{
user: user,
size: Math.ceil(size * window.devicePixelRatio)
});
}

var img = new Image();

// If the new image loads successfully set it.
img.onload = function() {
$div.clearimageplaceholder();
$div.append(img);

if(typeof callback === 'function') {
callback();
}
};
// Fallback when avatar loading fails:
// Use old placeholder when a displayname attribute is defined,
// otherwise show the unknown user placeholder.
img.onerror = function () {
$div.clearimageplaceholder();
if (typeof(displayname) !== 'undefined') {
$div.imageplaceholder(user, displayname);
} else {
setAvatarForUnknownUser($div);
}

if(typeof callback === 'function') {
callback();
}
};

if (size < 32) {
$div.addClass('icon-loading-small');
} else {
$div.addClass('icon-loading');
}
img.width = size;
img.height = size;
img.src = url;
img.alt = '';
};
}(jQuery));

+ 0
- 110
core/js/jquery.contactsmenu.js View File

@@ -1,110 +0,0 @@
/**
* Copyright (c) 2017 Georg Ehrke <oc.list@georgehrke.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/

(function ($) {

var LIST = ''
+ '<div class="menu popovermenu menu-left hidden contactsmenu-popover">'
+ ' <ul>'
+ ' <li>'
+ ' <a>'
+ ' <span class="icon-loading-small"></span>'
+ ' </a>'
+ ' </li>'
+ ' </ul>'
+ '</div>';

$.fn.contactsMenu = function(shareWith, shareType, appendTo) {
// 0 - user, 4 - email, 6 - remote
var allowedTypes = [0, 4, 6];
if (allowedTypes.indexOf(shareType) === -1) {
return;
}

var $div = this;
appendTo.append(LIST);
var $list = appendTo.find('div.contactsmenu-popover');

$div.click(function() {
if (!$list.hasClass('hidden')) {
$list.addClass('hidden');
$list.hide();
return;
}

$list.removeClass('hidden');
$list.show();

if ($list.hasClass('loaded')) {
return;
}

$list.addClass('loaded');
$.ajax(OC.generateUrl('/contactsmenu/findOne'), {
method: 'POST',
data: {
shareType: shareType,
shareWith: shareWith
}
}).then(function(data) {
$list.find('ul').find('li').addClass('hidden');

var actions;
if (!data.topAction) {
actions = [{
hyperlink: '#',
title: t('core', 'No action available')
}];
} else {
actions = [data.topAction].concat(data.actions);
}

actions.forEach(function(action) {
var template = OC.ContactsMenu.Templates['jquery_entry'];
$list.find('ul').append(template(action));
});

if (actions.length === 0) {

}
}, function(jqXHR) {
$list.find('ul').find('li').addClass('hidden');

var title;
if (jqXHR.status === 404) {
title = t('core', 'No action available');
} else {
title = t('core', 'Error fetching contact actions');
}

var template = OC.ContactsMenu.Templates['jquery_entry'];
$list.find('ul').append(template({
hyperlink: '#',
title: title
}));
});
});

$(document).click(function(event) {
var clickedList = ($list.has(event.target).length > 0);
var clickedTarget = ($div.has(event.target).length > 0);

$div.each(function() {
if ($(this).is(event.target)) {
clickedTarget = true;
}
});

if (clickedList || clickedTarget) {
return;
}

$list.addClass('hidden');
$list.hide();
});
};
}(jQuery));

+ 0
- 249
core/js/jquery.ocdialog.js View File

@@ -1,249 +0,0 @@
(function($) {
$.widget('oc.ocdialog', {
options: {
width: 'auto',
height: 'auto',
closeButton: true,
closeOnEscape: true,
modal: false
},
_create: function() {
var self = this;

this.originalCss = {
display: this.element[0].style.display,
width: this.element[0].style.width,
height: this.element[0].style.height
};

this.originalTitle = this.element.attr('title');
this.options.title = this.options.title || this.originalTitle;

this.$dialog = $('<div class="oc-dialog" />')
.attr({
// Setting tabIndex makes the div focusable
tabIndex: -1,
role: 'dialog'
})
.insertBefore(this.element);
this.$dialog.append(this.element.detach());
this.element.removeAttr('title').addClass('oc-dialog-content').appendTo(this.$dialog);

this.$dialog.css({
display: 'inline-block',
position: 'fixed'
});

this.enterCallback = null;

$(document).on('keydown keyup', function(event) {
if (
event.target !== self.$dialog.get(0) &&
self.$dialog.find($(event.target)).length === 0
) {
return;
}
// Escape
if (
event.keyCode === 27 &&
event.type === 'keydown' &&
self.options.closeOnEscape
) {
event.stopImmediatePropagation();
self.close();
return false;
}
// Enter
if(event.keyCode === 13) {
event.stopImmediatePropagation();
if (self.enterCallback !== null) {
self.enterCallback();
event.preventDefault();
return false;
}
if(event.type === 'keyup') {
event.preventDefault();
return false;
}
// If no button is selected we trigger the primary
if (
self.$buttonrow &&
self.$buttonrow.find($(event.target)).length === 0
) {
var $button = self.$buttonrow.find('button.primary');
if($button && !$button.prop('disabled')) {
$button.trigger('click');
}
} else if(self.$buttonrow) {
$(event.target).trigger('click');
}
return false;
}
});

this._setOptions(this.options);
this._createOverlay();
},
_init: function() {
this.$dialog.focus();
this._trigger('open');
},
_setOption: function(key, value) {
var self = this;
switch(key) {
case 'title':
if(this.$title) {
this.$title.text(value);
} else {
var $title = $('<h2 class="oc-dialog-title">'
+ value
+ '</h2>');
this.$title = $title.prependTo(this.$dialog);
}
this._setSizes();
break;
case 'buttons':
if(this.$buttonrow) {
this.$buttonrow.empty();
} else {
var $buttonrow = $('<div class="oc-dialog-buttonrow" />');
this.$buttonrow = $buttonrow.appendTo(this.$dialog);
}
if (value.length === 1) {
this.$buttonrow.addClass('onebutton');
} else if (value.length === 2) {
this.$buttonrow.addClass('twobuttons');
} else if (value.length === 3) {
this.$buttonrow.addClass('threebuttons');
}
$.each(value, function(idx, val) {
var $button = $('<button>').text(val.text);
if (val.classes) {
$button.addClass(val.classes);
}
if(val.defaultButton) {
$button.addClass('primary');
self.$defaultButton = $button;
}
self.$buttonrow.append($button);
$button.click(function() {
val.click.apply(self.element[0], arguments);
});
});
this.$buttonrow.find('button')
.on('focus', function(event) {
self.$buttonrow.find('button').removeClass('primary');
$(this).addClass('primary');
});
this._setSizes();
break;
case 'style':
if (value.buttons !== undefined) {
this.$buttonrow.addClass(value.buttons);
}
break;
case 'closeButton':
if(value) {
var $closeButton = $('<a class="oc-dialog-close"></a>');
this.$dialog.prepend($closeButton);
$closeButton.on('click', function() {
self.close();
});
} else {
this.$dialog.find('.oc-dialog-close').remove();
}
break;
case 'width':
this.$dialog.css('width', value);
break;
case 'height':
this.$dialog.css('height', value);
break;
case 'close':
this.closeCB = value;
break;
}
//this._super(key, value);
$.Widget.prototype._setOption.apply(this, arguments );
},
_setOptions: function(options) {
//this._super(options);
$.Widget.prototype._setOptions.apply(this, arguments);
},
_setSizes: function() {
var lessHeight = 0;
if(this.$title) {
lessHeight += this.$title.outerHeight(true);
}
if(this.$buttonrow) {
lessHeight += this.$buttonrow.outerHeight(true);
}
this.element.css({
'height': 'calc(100% - ' + lessHeight + 'px)'
});
},
_createOverlay: function() {
if(!this.options.modal) {
return;
}

var self = this;
this.overlay = $('<div>')
.addClass('oc-dialog-dim')
.appendTo($('#content'));
this.overlay.on('click keydown keyup', function(event) {
if(event.target !== self.$dialog.get(0) && self.$dialog.find($(event.target)).length === 0) {
event.preventDefault();
event.stopPropagation();
return;
}
});
},
_destroyOverlay: function() {
if (!this.options.modal) {
return;
}

if (this.overlay) {
this.overlay.off('click keydown keyup');
this.overlay.remove();
this.overlay = null;
}
},
widget: function() {
return this.$dialog;
},
setEnterCallback: function(callback) {
this.enterCallback = callback;
},
unsetEnterCallback: function() {
this.enterCallback = null;
},
close: function() {
this._destroyOverlay();
var self = this;
// Ugly hack to catch remaining keyup events.
setTimeout(function() {
self._trigger('close', self);
}, 200);

self.$dialog.remove();
this.destroy();
},
destroy: function() {
if(this.$title) {
this.$title.remove();
}
if(this.$buttonrow) {
this.$buttonrow.remove();
}

if(this.originalTitle) {
this.element.attr('title', this.originalTitle);
}
this.element.removeClass('oc-dialog-content')
.css(this.originalCss).detach().insertBefore(this.$dialog);
this.$dialog.remove();
}
});
}(jQuery));

+ 0
- 106
core/js/js.js View File

@@ -29,15 +29,6 @@ if (typeof console === "undefined" || typeof console.log === "undefined") {
}
}

/**
* Sanitizes a HTML string by replacing all potential dangerous characters with HTML entities
* @param {string} s String to sanitize
* @return {string} Sanitized string
*/
function escapeHTML(s) {
return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('"').join('&quot;').split('\'').join('&#039;');
}

/** @namespace OCP */
var OCP = Object.assign({}, window.OCP);

@@ -1832,13 +1823,6 @@ OC.PasswordConfirmation = {

$(document).ready(initCore);

/**
* Filter Jquery selector by attribute value
*/
$.fn.filterAttr = function(attr_name, attr_value) {
return this.filter(function() { return $(this).attr(attr_name) === attr_value; });
};

/**
* Returns a human readable file size
* @param {number} size Size in bytes
@@ -2338,93 +2322,3 @@ OC.set=function(name, value) {
document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
}
})();

/**
* select a range in an input field
* @link http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
* @param {type} start
* @param {type} end
*/
jQuery.fn.selectRange = function(start, end) {
return this.each(function() {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};

/**
* check if an element exists.
* allows you to write if ($('#myid').exists()) to increase readability
* @link http://stackoverflow.com/questions/31044/is-there-an-exists-function-for-jquery
*/
jQuery.fn.exists = function(){
return this.length > 0;
};

/**
* jQuery tipsy shim for the bootstrap tooltip
*/
jQuery.fn.tipsy = function(argument) {
console.warn('Deprecation warning: tipsy is deprecated. Use tooltip instead.');
if(typeof argument === 'object' && argument !== null) {

// tipsy defaults
var options = {
placement: 'bottom',
delay: { 'show': 0, 'hide': 0},
trigger: 'hover',
html: false,
container: 'body'
};
if(argument.gravity) {
switch(argument.gravity) {
case 'n':
case 'nw':
case 'ne':
options.placement='bottom';
break;
case 's':
case 'sw':
case 'se':
options.placement='top';
break;
case 'w':
options.placement='right';
break;
case 'e':
options.placement='left';
break;
}
}
if(argument.trigger) {
options.trigger = argument.trigger;
}
if(argument.delayIn) {
options.delay.show = argument.delayIn;
}
if(argument.delayOut) {
options.delay.hide = argument.delayOut;
}
if(argument.html) {
options.html = true;
}
if(argument.fallback) {
options.title = argument.fallback;
}
// destroy old tooltip in case the title has changed
jQuery.fn.tooltip.call(this, 'destroy');
jQuery.fn.tooltip.call(this, options);
} else {
this.tooltip(argument);
jQuery.fn.tooltip.call(this, argument);
}
return this;
};

+ 1
- 6
core/js/merged-template-prepend.json View File

@@ -1,16 +1,11 @@
[
"jquery.ocdialog.js",
"oc-dialogs.js",
"js.js",
"octemplate.js",
"public/appconfig.js",
"public/comments.js",
"public/whatsnew.js",
"oc-requesttoken.js",
"mimetype.js",
"mimetypelist.js",
"select2-toggleselect.js",
"placeholder.js",
"jquery.avatar.js",
"jquery.contactsmenu.js"
"select2-toggleselect.js"
]

+ 0
- 105
core/js/octemplate.js View File

@@ -1,105 +0,0 @@
/**
* jQuery plugin for micro templates
*
* Strings are automatically escaped, but that can be disabled by setting
* escapeFunction to null.
*
* Usage examples:
*
* var htmlStr = '<p>Bake, uncovered, until the {greasystuff} is melted and the {pasta} is heated through, about {min} minutes.</p>'
* $(htmlStr).octemplate({greasystuff: 'cheese', pasta: 'macaroni', min: 10});
*
* var htmlStr = '<p>Welcome back {user}</p>';
* $(htmlStr).octemplate({user: 'John Q. Public'}, {escapeFunction: null});
*
* Be aware that the target string must be wrapped in an HTML element for the
* plugin to work. The following won't work:
*
* var textStr = 'Welcome back {user}';
* $(textStr).octemplate({user: 'John Q. Public'});
*
* For anything larger than one-liners, you can use a simple $.get() ajax
* request to get the template, or you can embed them it the page using the
* text/template type:
*
* <script id="contactListItemTemplate" type="text/template">
* <tr class="contact" data-id="{id}">
* <td class="name">
* <input type="checkbox" name="id" value="{id}" /><span class="nametext">{name}</span>
* </td>
* <td class="email">
* <a href="mailto:{email}">{email}</a>
* </td>
* <td class="phone">{phone}</td>
* </tr>
* </script>
*
* var $tmpl = $('#contactListItemTemplate');
* var contacts = // fetched in some ajax call
*
* $.each(contacts, function(idx, contact) {
* $contactList.append(
* $tmpl.octemplate({
* id: contact.getId(),
* name: contact.getDisplayName(),
* email: contact.getPreferredEmail(),
* phone: contact.getPreferredPhone(),
* });
* );
* });
*/
(function( $ ) {
/**
* Object Template
* Inspired by micro templating done by e.g. underscore.js
*/
var Template = {
init: function(vars, options, elem) {
// Mix in the passed in options with the default options
this.vars = vars;
this.options = $.extend({},this.options,options);

this.elem = elem;
var self = this;

if(typeof this.options.escapeFunction === 'function') {
var keys = Object.keys(this.vars);
for (var key = 0; key < keys.length; key++) {
if(typeof this.vars[keys[key]] === 'string') {
this.vars[keys[key]] = self.options.escapeFunction(this.vars[keys[key]]);
}
}
}

var _html = this._build(this.vars);
return $(_html);
},
// From stackoverflow.com/questions/1408289/best-way-to-do-variable-interpolation-in-javascript
_build: function(o){
var data = this.elem.attr('type') === 'text/template' ? this.elem.html() : this.elem.get(0).outerHTML;
try {
return data.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
} catch(e) {
console.error(e, 'data:', data);
}
},
options: {
escapeFunction: escapeHTML
}
};

$.fn.octemplate = function(vars, options) {
vars = vars || {};
if(this.length) {
var _template = Object.create(Template);
return _template.init(vars, options, this);
}
};

})( jQuery );


+ 0
- 174
core/js/placeholder.js View File

@@ -1,174 +0,0 @@
/**
* ownCloud
*
* @author John Molakvoæ
* @copyright 2016-2018 John Molakvoæ <skjnldsv@protonmail.com>
* @author Morris Jobke
* @copyright 2013 Morris Jobke <morris.jobke@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/

/*
* Adds a background color to the element called on and adds the first character
* of the passed in string. This string is also the seed for the generation of
* the background color.
*
* You have following HTML:
*
* <div id="albumart"></div>
*
* And call this from Javascript:
*
* $('#albumart').imageplaceholder('The Album Title');
*
* Which will result in:
*
* <div id="albumart" style="background-color: rgb(121, 90, 171); ... ">T</div>
*
* You may also call it like this, to have a different background, than the seed:
*
* $('#albumart').imageplaceholder('The Album Title', 'Album Title');
*
* Resulting in:
*
* <div id="albumart" style="background-color: rgb(121, 90, 171); ... ">A</div>
*
*/

/*
* Alternatively, you can use the prototype function to convert your string to rgb colors:
*
* "a6741a86aded5611a8e46ce16f2ad646".toRgb()
*
* Will return the rgb parameters within the following object:
*
* Color {r: 208, g: 158, b: 109}
*
*/

(function ($) {

String.prototype.toRgb = function() {
// Normalize hash
var hash = this.toLowerCase();

// Already a md5 hash?
if( hash.match(/^([0-9a-f]{4}-?){8}$/) === null ) {
hash = md5(hash);
}

hash = hash.replace(/[^0-9a-f]/g, '');

function Color(r,g,b) {
this.r = r;
this.g = g;
this.b = b;
}

function stepCalc(steps, ends) {
var step = new Array(3);
step[0] = (ends[1].r - ends[0].r) / steps;
step[1] = (ends[1].g - ends[0].g) / steps;
step[2] = (ends[1].b - ends[0].b) / steps;
return step;
}

function mixPalette(steps, color1, color2) {
var count = steps + 1;
var palette = new Array();
palette.push(color1);
var step = stepCalc(steps, [color1, color2])
for (var i = 1; i < steps; i++) {
var r = parseInt(color1.r + (step[0] * i));
var g = parseInt(color1.g + (step[1] * i));
var b = parseInt(color1.b + (step[2] * i));
palette.push(new Color(r,g,b));
}
return palette;
}

var red = new Color(182, 70, 157);
var yellow = new Color(221, 203, 85);
var blue = new Color(0, 130, 201); // Nextcloud blue
// Number of steps to go from a color to another
// 3 colors * 6 will result in 18 generated colors
var steps = 6;

var palette1 = mixPalette(steps, red, yellow);
var palette2 = mixPalette(steps, yellow, blue);
var palette3 = mixPalette(steps, blue, red);

var finalPalette = palette1.concat(palette2).concat(palette3);

// Convert a string to an integer evenly
function hashToInt(hash, maximum) {
var finalInt = 0;
var result = Array();

// Splitting evenly the string
for (var i=0; i<hash.length; i++) {
// chars in md5 goes up to f, hex:16
result.push(parseInt(hash.charAt(i), 16) % 16);
}
// Adds up all results
for (var j in result) {
finalInt += result[j];
}
// chars in md5 goes up to f, hex:16
// make sure we're always using int in our operation
return parseInt(parseInt(finalInt) % maximum);
}
return finalPalette[hashToInt(hash, steps * 3 )];
};

$.fn.imageplaceholder = function(seed, text, size) {
text = text || seed;

// Compute the hash
var rgb = seed.toRgb();
this.css('background-color', 'rgb('+rgb.r+', '+rgb.g+', '+rgb.b+')');

// Placeholders are square
var height = this.height() || size || 32;
this.height(height);
this.width(height);

// CSS rules
this.css('color', '#fff');
this.css('font-weight', 'normal');
this.css('text-align', 'center');

// calculate the height
this.css('line-height', height + 'px');
this.css('font-size', (height * 0.55) + 'px');

if(seed !== null && seed.length) {
this.html(text[0].toUpperCase());
}
};

$.fn.clearimageplaceholder = function() {
this.css('background-color', '');
this.css('color', '');
this.css('font-weight', '');
this.css('text-align', '');
this.css('line-height', '');
this.css('font-size', '');
this.html('');
this.removeClass('icon-loading');
this.removeClass('icon-loading-small');
};
}(jQuery));

+ 36
- 0
core/src/Util/escapeHTML.js View File

@@ -0,0 +1,36 @@
/*
* @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/>.
*/

/**
* Sanitizes a HTML string by replacing all potential dangerous characters with HTML entities
* @param {string} s String to sanitize
* @return {string} Sanitized string
*/
export default function escapeHTML (s) {
return s.toString()
.split('&')
.join('&amp;')
.split('<')
.join('&lt;').split('>')
.join('&gt;').split('"')
.join('&quot;').split('\'')
.join('&#039;');
}

+ 2
- 0
core/src/globals.js View File

@@ -51,6 +51,7 @@ import 'strengthify/strengthify.css'
import OC from './OC/index'
import OCP from './OCP/index'
import OCA from './OCA/index'
import escapeHTML from './Util/escapeHTML'

window['_'] = _
window['$'] = $
@@ -72,6 +73,7 @@ window['moment'] = moment
window['OC'] = OC
window['OCP'] = OCP
window['OCA'] = OCA
window['escapeHTML'] = escapeHTML

/**
* translate a string

+ 162
- 0
core/src/jquery/avatar.js View File

@@ -0,0 +1,162 @@
/*
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 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 OC from '../OC'

/**
* This plugin inserts the right avatar for the user, depending on, whether a
* custom avatar is uploaded - which it uses then - or not, and display a
* placeholder with the first letter of the users name instead.
* For this it queries the core_avatar_get route, thus this plugin is fit very
* tightly for owncloud, and it may not work anywhere else.
*
* You may use this on any <div></div>
* Here I'm using <div class="avatardiv"></div> as an example.
*
* There are 5 ways to call this:
*
* 1. $('.avatardiv').avatar('jdoe', 128);
* This will make the div to jdoe's fitting avatar, with a size of 128px.
*
* 2. $('.avatardiv').avatar('jdoe');
* This will make the div to jdoe's fitting avatar. If the div already has a
* height, it will be used for the avatars size. Otherwise this plugin will
* search for 'size' DOM data, to use for avatar size. If neither are available
* it will default to 64px.
*
* 3. $('.avatardiv').avatar();
* This will search the DOM for 'user' data, to use as the username. If there
* is no username available it will default to a placeholder with the value of
* "?". The size will be determined the same way, as the second example.
*
* 4. $('.avatardiv').avatar('jdoe', 128, true);
* This will behave like the first example, except it will also append random
* hashes to the custom avatar images, to force image reloading in IE8.
*
* 5. $('.avatardiv').avatar('jdoe', 128, undefined, true);
* This will behave like the first example, but it will hide the avatardiv, if
* it will display the default placeholder. undefined is the ie8fix from
* example 4 and can be either true, or false/undefined, to be ignored.
*
* 6. $('.avatardiv').avatar('jdoe', 128, undefined, true, callback);
* This will behave like the above example, but it will call the function
* defined in callback after the avatar is placed into the DOM.
*
*/

$.fn.avatar = function (user, size, ie8fix, hidedefault, callback, displayname) {
var setAvatarForUnknownUser = function (target) {
target.imageplaceholder('?');
target.css('background-color', '#b9b9b9');
};

if (typeof (user) !== 'undefined') {
user = String(user);
}
if (typeof (displayname) !== 'undefined') {
displayname = String(displayname);
}

if (typeof (size) === 'undefined') {
if (this.height() > 0) {
size = this.height();
} else if (this.data('size') > 0) {
size = this.data('size');
} else {
size = 64;
}
}

this.height(size);
this.width(size);

if (typeof (user) === 'undefined') {
if (typeof (this.data('user')) !== 'undefined') {
user = this.data('user');
} else {
setAvatarForUnknownUser(this);
return;
}
}

// sanitize
user = String(user).replace(/\//g, '');

var $div = this;
var url;

// If this is our own avatar we have to use the version attribute
if (user === OC.getCurrentUser().uid) {
url = OC.generateUrl(
'/avatar/{user}/{size}?v={version}',
{
user: user,
size: Math.ceil(size * window.devicePixelRatio),
version: oc_userconfig.avatar.version
});
} else {
url = OC.generateUrl(
'/avatar/{user}/{size}',
{
user: user,
size: Math.ceil(size * window.devicePixelRatio)
});
}

var img = new Image();

// If the new image loads successfully set it.
img.onload = function () {
$div.clearimageplaceholder();
$div.append(img);

if (typeof callback === 'function') {
callback();
}
};
// Fallback when avatar loading fails:
// Use old placeholder when a displayname attribute is defined,
// otherwise show the unknown user placeholder.
img.onerror = function () {
$div.clearimageplaceholder();
if (typeof (displayname) !== 'undefined') {
$div.imageplaceholder(user, displayname);
} else {
setAvatarForUnknownUser($div);
}

if (typeof callback === 'function') {
callback();
}
};

if (size < 32) {
$div.addClass('icon-loading-small');
} else {
$div.addClass('icon-loading');
}
img.width = size;
img.height = size;
img.src = url;
img.alt = '';
};

+ 125
- 0
core/src/jquery/contactsmenu.js View File

@@ -0,0 +1,125 @@
/*
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 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 OC from '../OC'

const LIST = ''
+ '<div class="menu popovermenu menu-left hidden contactsmenu-popover">'
+ ' <ul>'
+ ' <li>'
+ ' <a>'
+ ' <span class="icon-loading-small"></span>'
+ ' </a>'
+ ' </li>'
+ ' </ul>'
+ '</div>';

$.fn.contactsMenu = function (shareWith, shareType, appendTo) {
// 0 - user, 4 - email, 6 - remote
var allowedTypes = [0, 4, 6];
if (allowedTypes.indexOf(shareType) === -1) {
return;
}

var $div = this;
appendTo.append(LIST);
var $list = appendTo.find('div.contactsmenu-popover');

$div.click(function () {
if (!$list.hasClass('hidden')) {
$list.addClass('hidden');
$list.hide();
return;
}

$list.removeClass('hidden');
$list.show();

if ($list.hasClass('loaded')) {
return;
}

$list.addClass('loaded');
$.ajax(OC.generateUrl('/contactsmenu/findOne'), {
method: 'POST',
data: {
shareType: shareType,
shareWith: shareWith
}
}).then(function (data) {
$list.find('ul').find('li').addClass('hidden');

var actions;
if (!data.topAction) {
actions = [{
hyperlink: '#',
title: t('core', 'No action available')
}];
} else {
actions = [data.topAction].concat(data.actions);
}

actions.forEach(function (action) {
var template = OC.ContactsMenu.Templates['jquery_entry'];
$list.find('ul').append(template(action));
});

if (actions.length === 0) {

}
}, function (jqXHR) {
$list.find('ul').find('li').addClass('hidden');

var title;
if (jqXHR.status === 404) {
title = t('core', 'No action available');
} else {
title = t('core', 'Error fetching contact actions');
}

var template = OC.ContactsMenu.Templates['jquery_entry'];
$list.find('ul').append(template({
hyperlink: '#',
title: title
}));
});
});

$(document).click(function (event) {
var clickedList = ($list.has(event.target).length > 0);
var clickedTarget = ($div.has(event.target).length > 0);

$div.each(function () {
if ($(this).is(event.target)) {
clickedTarget = true;
}
});

if (clickedList || clickedTarget) {
return;
}

$list.addClass('hidden');
$list.hide();
});
};

+ 31
- 0
core/src/jquery/exists.js View File

@@ -0,0 +1,31 @@
/*
* @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'

/**
* check if an element exists.
* allows you to write if ($('#myid').exists()) to increase readability
* @link http://stackoverflow.com/questions/31044/is-there-an-exists-function-for-jquery
*/
$.fn.exists = function () {
return this.length > 0;
};

+ 31
- 0
core/src/jquery/filterattr.js View File

@@ -0,0 +1,31 @@
/*
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 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'

/**
* Filter jQuery selector by attribute value
*/
$.fn.filterAttr = function (attrName, attrValue) {
return this.filter(function () {
return $(this).attr(attrName) === attrValue;
});
};

+ 32
- 0
core/src/jquery/index.js View File

@@ -0,0 +1,32 @@
/*
* @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 './avatar'
import './contactsmenu'
import './exists'
import './filterattr'
import './ocdialog'
import './octemplate'
import './placeholder'
import './selectrange'
import './showpassword'
import './tipsy'
import './ui-fixes'

+ 270
- 0
core/src/jquery/ocdialog.js View File

@@ -0,0 +1,270 @@
/*
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 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'

$.widget('oc.ocdialog', {
options: {
width: 'auto',
height: 'auto',
closeButton: true,
closeOnEscape: true,
modal: false
},
_create: function () {
var self = this;

this.originalCss = {
display: this.element[0].style.display,
width: this.element[0].style.width,
height: this.element[0].style.height
};

this.originalTitle = this.element.attr('title');
this.options.title = this.options.title || this.originalTitle;

this.$dialog = $('<div class="oc-dialog" />')
.attr({
// Setting tabIndex makes the div focusable
tabIndex: -1,
role: 'dialog'
})
.insertBefore(this.element);
this.$dialog.append(this.element.detach());
this.element.removeAttr('title').addClass('oc-dialog-content').appendTo(this.$dialog);

this.$dialog.css({
display: 'inline-block',
position: 'fixed'
});

this.enterCallback = null;

$(document).on('keydown keyup', function (event) {
if (
event.target !== self.$dialog.get(0) &&
self.$dialog.find($(event.target)).length === 0
) {
return;
}
// Escape
if (
event.keyCode === 27 &&
event.type === 'keydown' &&
self.options.closeOnEscape
) {
event.stopImmediatePropagation();
self.close();
return false;
}
// Enter
if (event.keyCode === 13) {
event.stopImmediatePropagation();
if (self.enterCallback !== null) {
self.enterCallback();
event.preventDefault();
return false;
}
if (event.type === 'keyup') {
event.preventDefault();
return false;
}
// If no button is selected we trigger the primary
if (
self.$buttonrow &&
self.$buttonrow.find($(event.target)).length === 0
) {
var $button = self.$buttonrow.find('button.primary');
if ($button && !$button.prop('disabled')) {
$button.trigger('click');
}
} else if (self.$buttonrow) {
$(event.target).trigger('click');
}
return false;
}
});

this._setOptions(this.options);
this._createOverlay();
},
_init: function () {
this.$dialog.focus();
this._trigger('open');
},
_setOption: function (key, value) {
var self = this;
switch (key) {
case 'title':
if (this.$title) {
this.$title.text(value);
} else {
var $title = $('<h2 class="oc-dialog-title">'
+ value
+ '</h2>');
this.$title = $title.prependTo(this.$dialog);
}
this._setSizes();
break;
case 'buttons':
if (this.$buttonrow) {
this.$buttonrow.empty();
} else {
var $buttonrow = $('<div class="oc-dialog-buttonrow" />');
this.$buttonrow = $buttonrow.appendTo(this.$dialog);
}
if (value.length === 1) {
this.$buttonrow.addClass('onebutton');
} else if (value.length === 2) {
this.$buttonrow.addClass('twobuttons');
} else if (value.length === 3) {
this.$buttonrow.addClass('threebuttons');
}
$.each(value, function (idx, val) {
var $button = $('<button>').text(val.text);
if (val.classes) {
$button.addClass(val.classes);
}
if (val.defaultButton) {
$button.addClass('primary');
self.$defaultButton = $button;
}
self.$buttonrow.append($button);
$button.click(function () {
val.click.apply(self.element[0], arguments);
});
});
this.$buttonrow.find('button')
.on('focus', function (event) {
self.$buttonrow.find('button').removeClass('primary');
$(this).addClass('primary');
});
this._setSizes();
break;
case 'style':
if (value.buttons !== undefined) {
this.$buttonrow.addClass(value.buttons);
}
break;
case 'closeButton':
if (value) {
var $closeButton = $('<a class="oc-dialog-close"></a>');
this.$dialog.prepend($closeButton);
$closeButton.on('click', function () {
self.close();
});
} else {
this.$dialog.find('.oc-dialog-close').remove();
}
break;
case 'width':
this.$dialog.css('width', value);
break;
case 'height':
this.$dialog.css('height', value);
break;
case 'close':
this.closeCB = value;
break;
}
//this._super(key, value);
$.Widget.prototype._setOption.apply(this, arguments);
},
_setOptions: function (options) {
//this._super(options);
$.Widget.prototype._setOptions.apply(this, arguments);
},
_setSizes: function () {
var lessHeight = 0;
if (this.$title) {
lessHeight += this.$title.outerHeight(true);
}
if (this.$buttonrow) {
lessHeight += this.$buttonrow.outerHeight(true);
}
this.element.css({
'height': 'calc(100% - ' + lessHeight + 'px)'
});
},
_createOverlay: function () {
if (!this.options.modal) {
return;
}

var self = this;
this.overlay = $('<div>')
.addClass('oc-dialog-dim')
.appendTo($('#content'));
this.overlay.on('click keydown keyup', function (event) {
if (event.target !== self.$dialog.get(0) && self.$dialog.find($(event.target)).length === 0) {
event.preventDefault();
event.stopPropagation();
return;
}
});
},
_destroyOverlay: function () {
if (!this.options.modal) {
return;
}

if (this.overlay) {
this.overlay.off('click keydown keyup');
this.overlay.remove();
this.overlay = null;
}
},
widget: function () {
return this.$dialog;
},
setEnterCallback: function (callback) {
this.enterCallback = callback;
},
unsetEnterCallback: function () {
this.enterCallback = null;
},
close: function () {
this._destroyOverlay();
var self = this;
// Ugly hack to catch remaining keyup events.
setTimeout(function () {
self._trigger('close', self);
}, 200);

self.$dialog.remove();
this.destroy();
},
destroy: function () {
if (this.$title) {
this.$title.remove();
}
if (this.$buttonrow) {
this.$buttonrow.remove();
}

if (this.originalTitle) {
this.element.attr('title', this.originalTitle);
}
this.element.removeClass('oc-dialog-content')
.css(this.originalCss).detach().insertBefore(this.$dialog);
this.$dialog.remove();
}
});

+ 104
- 0
core/src/jquery/octemplate.js View File

@@ -0,0 +1,104 @@
import $ from 'jquery'
import escapeHTML from '../Util/escapeHTML'

/**
* jQuery plugin for micro templates
*
* Strings are automatically escaped, but that can be disabled by setting
* escapeFunction to null.
*
* Usage examples:
*
* var htmlStr = '<p>Bake, uncovered, until the {greasystuff} is melted and the {pasta} is heated through, about {min} minutes.</p>'
* $(htmlStr).octemplate({greasystuff: 'cheese', pasta: 'macaroni', min: 10});
*
* var htmlStr = '<p>Welcome back {user}</p>';
* $(htmlStr).octemplate({user: 'John Q. Public'}, {escapeFunction: null});
*
* Be aware that the target string must be wrapped in an HTML element for the
* plugin to work. The following won't work:
*
* var textStr = 'Welcome back {user}';
* $(textStr).octemplate({user: 'John Q. Public'});
*
* For anything larger than one-liners, you can use a simple $.get() ajax
* request to get the template, or you can embed them it the page using the
* text/template type:
*
* <script id="contactListItemTemplate" type="text/template">
* <tr class="contact" data-id="{id}">
* <td class="name">
* <input type="checkbox" name="id" value="{id}" /><span class="nametext">{name}</span>
* </td>
* <td class="email">
* <a href="mailto:{email}">{email}</a>
* </td>
* <td class="phone">{phone}</td>
* </tr>
* </script>
*
* var $tmpl = $('#contactListItemTemplate');
* var contacts = // fetched in some ajax call
*
* $.each(contacts, function(idx, contact) {
* $contactList.append(
* $tmpl.octemplate({
* id: contact.getId(),
* name: contact.getDisplayName(),
* email: contact.getPreferredEmail(),
* phone: contact.getPreferredPhone(),
* });
* );
* });
*/
/**
* Object Template
* Inspired by micro templating done by e.g. underscore.js
*/
const Template = {
init: function (vars, options, elem) {
// Mix in the passed in options with the default options
this.vars = vars;
this.options = $.extend({}, this.options, options);

this.elem = elem;
var self = this;

if (typeof this.options.escapeFunction === 'function') {
var keys = Object.keys(this.vars);
for (var key = 0; key < keys.length; key++) {
if (typeof this.vars[keys[key]] === 'string') {
this.vars[keys[key]] = self.options.escapeFunction(this.vars[keys[key]]);
}
}
}

var _html = this._build(this.vars);
return $(_html);
},
// From stackoverflow.com/questions/1408289/best-way-to-do-variable-interpolation-in-javascript
_build: function (o) {
var data = this.elem.attr('type') === 'text/template' ? this.elem.html() : this.elem.get(0).outerHTML;
try {
return data.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
} catch (e) {
console.error(e, 'data:', data);
}
},
options: {
escapeFunction: escapeHTML
}
};

$.fn.octemplate = function (vars, options) {
vars = vars || {};
if (this.length) {
var _template = Object.create(Template);
return _template.init(vars, options, this);
}
};

+ 174
- 0
core/src/jquery/placeholder.js View File

@@ -0,0 +1,174 @@
/**
* ownCloud
*
* @author John Molakvoæ
* @copyright 2016-2018 John Molakvoæ <skjnldsv@protonmail.com>
* @author Morris Jobke
* @copyright 2013 Morris Jobke <morris.jobke@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/

import $ from 'jquery'

/*
* Adds a background color to the element called on and adds the first character
* of the passed in string. This string is also the seed for the generation of
* the background color.
*
* You have following HTML:
*
* <div id="albumart"></div>
*
* And call this from Javascript:
*
* $('#albumart').imageplaceholder('The Album Title');
*
* Which will result in:
*
* <div id="albumart" style="background-color: rgb(121, 90, 171); ... ">T</div>
*
* You may also call it like this, to have a different background, than the seed:
*
* $('#albumart').imageplaceholder('The Album Title', 'Album Title');
*
* Resulting in:
*
* <div id="albumart" style="background-color: rgb(121, 90, 171); ... ">A</div>
*
*/

/*
* Alternatively, you can use the prototype function to convert your string to rgb colors:
*
* "a6741a86aded5611a8e46ce16f2ad646".toRgb()
*
* Will return the rgb parameters within the following object:
*
* Color {r: 208, g: 158, b: 109}
*
*/

String.prototype.toRgb = function () {
// Normalize hash
var hash = this.toLowerCase();

// Already a md5 hash?
if (hash.match(/^([0-9a-f]{4}-?){8}$/) === null) {
hash = md5(hash);
}

hash = hash.replace(/[^0-9a-f]/g, '');

function Color (r, g, b) {
this.r = r;
this.g = g;
this.b = b;
}

function stepCalc (steps, ends) {
var step = new Array(3);
step[0] = (ends[1].r - ends[0].r) / steps;
step[1] = (ends[1].g - ends[0].g) / steps;
step[2] = (ends[1].b - ends[0].b) / steps;
return step;
}

function mixPalette (steps, color1, color2) {
var count = steps + 1;
var palette = new Array();
palette.push(color1);
var step = stepCalc(steps, [color1, color2])
for (var i = 1; i < steps; i++) {
var r = parseInt(color1.r + (step[0] * i));
var g = parseInt(color1.g + (step[1] * i));
var b = parseInt(color1.b + (step[2] * i));
palette.push(new Color(r, g, b));
}
return palette;
}

var red = new Color(182, 70, 157);
var yellow = new Color(221, 203, 85);
var blue = new Color(0, 130, 201); // Nextcloud blue
// Number of steps to go from a color to another
// 3 colors * 6 will result in 18 generated colors
var steps = 6;

var palette1 = mixPalette(steps, red, yellow);
var palette2 = mixPalette(steps, yellow, blue);
var palette3 = mixPalette(steps, blue, red);

var finalPalette = palette1.concat(palette2).concat(palette3);

// Convert a string to an integer evenly
function hashToInt (hash, maximum) {
var finalInt = 0;
var result = Array();

// Splitting evenly the string
for (var i = 0; i < hash.length; i++) {
// chars in md5 goes up to f, hex:16
result.push(parseInt(hash.charAt(i), 16) % 16);
}
// Adds up all results
for (var j in result) {
finalInt += result[j];
}
// chars in md5 goes up to f, hex:16
// make sure we're always using int in our operation
return parseInt(parseInt(finalInt) % maximum);
}

return finalPalette[hashToInt(hash, steps * 3)];
};

$.fn.imageplaceholder = function (seed, text, size) {
text = text || seed;

// Compute the hash
var rgb = seed.toRgb();
this.css('background-color', 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')');

// Placeholders are square
var height = this.height() || size || 32;
this.height(height);
this.width(height);

// CSS rules
this.css('color', '#fff');
this.css('font-weight', 'normal');
this.css('text-align', 'center');

// calculate the height
this.css('line-height', height + 'px');
this.css('font-size', (height * 0.55) + 'px');

if (seed !== null && seed.length) {
this.html(text[0].toUpperCase());
}
};

$.fn.clearimageplaceholder = function () {
this.css('background-color', '');
this.css('color', '');
this.css('font-weight', '');
this.css('text-align', '');
this.css('line-height', '');
this.css('font-size', '');
this.html('');
this.removeClass('icon-loading');
this.removeClass('icon-loading-small');
};

+ 43
- 0
core/src/jquery/selectrange.js View File

@@ -0,0 +1,43 @@
/*
* @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'

/**
* select a range in an input field
* @link http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
* @param {type} start
* @param {type} end
*/
$.fn.selectRange = function (start, end) {
return this.each(function () {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};

+ 149
- 0
core/src/jquery/showpassword.js View File

@@ -0,0 +1,149 @@
/*
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 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'

/*
* @name Show Password
* @description
* @version 1.3
* @requires Jquery 1.5
*
* @author Jan Jarfalk
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @special-thanks Michel Gratton
*
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
*/
$.fn.extend({
showPassword: function (c) {

// Setup callback object
var callback = {'fn': null, 'args': {}};
callback.fn = c;

// Clones passwords and turn the clones into text inputs
var cloneElement = function (element) {

var $element = $(element);

var $clone = $("<input />");

// Name added for JQuery Validation compatibility
// Element name is required to avoid script warning.
$clone.attr({
'type': 'text',
'class': $element.attr('class'),
'style': $element.attr('style'),
'size': $element.attr('size'),
'name': $element.attr('name') + '-clone',
'tabindex': $element.attr('tabindex'),
'autocomplete': 'off'
});

if ($element.attr('placeholder') !== undefined) {
$clone.attr('placeholder', $element.attr('placeholder'));
}

return $clone;

};

// Transfers values between two elements
var update = function (a, b) {
b.val(a.val());
};

// Shows a or b depending on checkbox
var setState = function (checkbox, a, b) {

if (checkbox.is(':checked')) {
update(a, b);
b.show();
a.hide();
} else {
update(b, a);
b.hide();
a.show();
}

};

return this.each(function () {

var $input = $(this),
$checkbox = $($input.data('typetoggle'));

// Create clone
var $clone = cloneElement($input);
$clone.insertAfter($input);

// Set callback arguments
if (callback.fn) {
callback.args.input = $input;
callback.args.checkbox = $checkbox;
callback.args.clone = $clone;
}


$checkbox.bind('click', function () {
setState($checkbox, $input, $clone);
});

$input.bind('keyup', function () {
update($input, $clone);
});

$clone.bind('keyup', function () {
update($clone, $input);

// Added for JQuery Validation compatibility
// This will trigger validation if it's ON for keyup event
$input.trigger('keyup');

});

// Added for JQuery Validation compatibility
// This will trigger validation if it's ON for blur event
$clone.bind('blur', function () {
$input.trigger('focusout');
});

setState($checkbox, $input, $clone);

// set type of password field clone (type=text) to password right on submit
// to prevent browser save the value of this field
$clone.closest('form').submit(function (e) {
// .prop has to be used, because .attr throws
// an error while changing a type of an input
// element
$clone.prop('type', 'password');
});

if (callback.fn) {
callback.fn(callback.args);
}

});
}
});

+ 83
- 0
core/src/jquery/tipsy.js View File

@@ -0,0 +1,83 @@
/*
* @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'

/**
* $ tipsy shim for the bootstrap tooltip
* @deprecated
*/
$.fn.tipsy = function (argument) {
console.warn('Deprecation warning: tipsy is deprecated. Use tooltip instead.');
if (typeof argument === 'object' && argument !== null) {

// tipsy defaults
var options = {
placement: 'bottom',
delay: {'show': 0, 'hide': 0},
trigger: 'hover',
html: false,
container: 'body'
};
if (argument.gravity) {
switch (argument.gravity) {
case 'n':
case 'nw':
case 'ne':
options.placement = 'bottom';
break;
case 's':
case 'sw':
case 'se':
options.placement = 'top';
break;
case 'w':
options.placement = 'right';
break;
case 'e':
options.placement = 'left';
break;
}
}
if (argument.trigger) {
options.trigger = argument.trigger;
}
if (argument.delayIn) {
options.delay.show = argument.delayIn;
}
if (argument.delayOut) {
options.delay.hide = argument.delayOut;
}
if (argument.html) {
options.html = true;
}
if (argument.fallback) {
options.title = argument.fallback;
}
// destroy old tooltip in case the title has changed
$.fn.tooltip.call(this, 'destroy');
$.fn.tooltip.call(this, options);
} else {
this.tooltip(argument);
$.fn.tooltip.call(this, argument);
}
return this;
};

core/js/jquery-ui-fixes.js → core/src/jquery/ui-fixes.js View File

@@ -1,8 +1,8 @@
// Various jquery fixes
import $ from 'jquery'

// Set autocomplete width the same as the related input
// See http://stackoverflow.com/a/11845718
jQuery.ui.autocomplete.prototype._resizeMenu = function () {
$.ui.autocomplete.prototype._resizeMenu = function () {
var ul = this.menu.element;
ul.outerWidth(this.element.outerWidth());
};

+ 1
- 0
core/src/main.js View File

@@ -23,6 +23,7 @@ import '@babel/polyfill'

import './globals'
import $ from 'jquery'
import './jquery/index'
import {registerAppsSlideToggle} from './OC/apps'

$(document).ready(function () {

Loading…
Cancel
Save