diff options
Diffstat (limited to 'core/js')
-rw-r--r-- | core/js/avatar.js | 11 | ||||
-rw-r--r-- | core/js/jquery.avatar.js | 87 | ||||
-rw-r--r-- | core/js/jquery.ocdialog.js | 3 | ||||
-rw-r--r-- | core/js/js.js | 56 | ||||
-rw-r--r-- | core/js/oc-dialogs.js | 287 | ||||
-rw-r--r-- | core/js/placeholder.js | 15 | ||||
-rw-r--r-- | core/js/share.js | 25 |
7 files changed, 462 insertions, 22 deletions
diff --git a/core/js/avatar.js b/core/js/avatar.js new file mode 100644 index 00000000000..57e6daa0930 --- /dev/null +++ b/core/js/avatar.js @@ -0,0 +1,11 @@ +$(document).ready(function(){ + if (OC.currentUser) { + $('#header .avatardiv').avatar(OC.currentUser, 32); + // Personal settings + $('#avatar .avatardiv').avatar(OC.currentUser, 128); + } + // User settings + $.each($('td.avatar .avatardiv'), function(i, element) { + $(element).avatar($(element).parent().parent().data('uid'), 32); + }); +}); diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js new file mode 100644 index 00000000000..88a4c25d1ee --- /dev/null +++ b/core/js/jquery.avatar.js @@ -0,0 +1,87 @@ +/** + * 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 4 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 aready 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 + * "x". 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. + */ + +(function ($) { + $.fn.avatar = function(user, size, ie8fix) { + 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 { + this.placeholder('x'); + return; + } + } + + // sanitize + user = user.replace(/\//g,''); + + var $div = this; + + OC.Router.registerLoadedCallback(function() { + var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken; + $.get(url, function(result) { + if (typeof(result) === 'object') { + if (result.data && result.data.displayname) { + $div.placeholder(user, result.data.displayname); + } else { + $div.placeholder(user); + } + } else { + if (ie8fix === true) { + $div.html('<img src="'+url+'#'+Math.floor(Math.random()*1000)+'">'); + } else { + $div.html('<img src="'+url+'">'); + } + } + }); + }); + }; +}(jQuery)); diff --git a/core/js/jquery.ocdialog.js b/core/js/jquery.ocdialog.js index f1836fd4727..02cd6ac1466 100644 --- a/core/js/jquery.ocdialog.js +++ b/core/js/jquery.ocdialog.js @@ -103,6 +103,9 @@ } $.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; diff --git a/core/js/js.js b/core/js/js.js index 1999ff73d23..b7f7ff1ac15 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -322,6 +322,38 @@ var OC={ return date.getDate()+'.'+(date.getMonth()+1)+'.'+date.getFullYear()+', '+date.getHours()+':'+date.getMinutes(); }, /** + * Parses a URL query string into a JS map + * @param queryString query string in the format param1=1234¶m2=abcde¶m3=xyz + * @return map containing key/values matching the URL parameters + */ + parseQueryString:function(queryString){ + var parts, + components, + result = {}, + key, + value; + if (!queryString){ + return null; + } + if (queryString[0] === '?'){ + queryString = queryString.substr(1); + } + parts = queryString.split('&'); + for (var i = 0; i < parts.length; i++){ + components = parts[i].split('='); + if (!components.length){ + continue; + } + key = decodeURIComponent(components[0]); + if (!key){ + continue; + } + value = components[1]; + result[key] = value && decodeURIComponent(value); + } + return result; + }, + /** * Opens a popup with the setting for an app. * @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'. * @param loadJS boolean or String. If true 'js/settings.js' is loaded. If it's a string @@ -691,11 +723,17 @@ $(document).ready(function(){ } }else if(event.keyCode===27){//esc OC.search.hide(); + if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system + FileList.unfilter(); + } }else{ var query=$('#searchbox').val(); if(OC.search.lastQuery!==query){ OC.search.lastQuery=query; OC.search.currentResult=-1; + if (FileList && typeof FileList.filter === 'function') { //TODO add hook system + FileList.filter(query); + } if(query.length>2){ OC.search(query); }else{ @@ -808,6 +846,13 @@ function formatDate(date){ return $.datepicker.formatDate(datepickerFormatDate, date)+' '+date.getHours()+':'+((date.getMinutes()<10)?'0':'')+date.getMinutes(); } +// taken from http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery +function getURLParameter(name) { + return decodeURI( + (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search) || [, null])[1] + ); +} + /** * takes an absolute timestamp and return a string with a human-friendly relative date * @param int a Unix timestamp @@ -874,7 +919,7 @@ OC.set=function(name, value) { * @param {type} start * @param {type} end */ -$.fn.selectRange = function(start, end) { +jQuery.fn.selectRange = function(start, end) { return this.each(function() { if (this.setSelectionRange) { this.focus(); @@ -890,6 +935,15 @@ $.fn.selectRange = function(start, end) { }; /** + * 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; +} + +/** * Calls the server periodically every 15 mins to ensure that session doesnt * time out */ diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index 61b58d00fa6..ac37b109e76 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -139,8 +139,12 @@ var OCdialogs = { } }); }) - .fail(function() { - alert(t('core', 'Error loading file picker template')); + .fail(function(status, error) { + // If the method is called while navigating away + // from the page, it is probably not needed ;) + if(status !== 0) { + alert(t('core', 'Error loading file picker template: {error}', {error: error})); + } }); }, /** @@ -206,10 +210,255 @@ var OCdialogs = { }); OCdialogs.dialogs_counter++; }) - .fail(function() { - alert(t('core', 'Error loading file picker template')); + .fail(function(status, error) { + // If the method is called while navigating away from + // the page, we still want to deliver the message. + if(status === 0) { + alert(title + ': ' + content); + } else { + alert(t('core', 'Error loading message template: {error}', {error: error})); + } }); }, + _fileexistsshown: false, + /** + * Displays file exists dialog + * @param {object} data upload object + * @param {object} original file with name, size and mtime + * @param {object} replacement file with name, size and mtime + * @param {object} controller with onCancel, onSkip, onReplace and onRename methods + */ + fileexists:function(data, original, replacement, controller) { + var self = this; + + var getCroppedPreview = function(file) { + var deferred = new $.Deferred(); + // Only process image files. + var type = file.type.split('/').shift(); + if (window.FileReader && type === 'image') { + var reader = new FileReader(); + reader.onload = function (e) { + var blob = new Blob([e.target.result]); + window.URL = window.URL || window.webkitURL; + var originalUrl = window.URL.createObjectURL(blob); + var image = new Image(); + image.src = originalUrl; + image.onload = function () { + var url = crop(image); + deferred.resolve(url); + } + }; + reader.readAsArrayBuffer(file); + } else { + deferred.reject(); + } + return deferred; + }; + + var crop = function(img) { + var canvas = document.createElement('canvas'), + width = img.width, + height = img.height, + x, y, size; + + // calculate the width and height, constraining the proportions + if (width > height) { + y = 0; + x = (width - height) / 2; + } else { + y = (height - width) / 2; + x = 0; + } + size = Math.min(width, height); + + // resize the canvas and draw the image data into it + canvas.width = 64; + canvas.height = 64; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, x, y, size, size, 0, 0, 64, 64); + return canvas.toDataURL("image/png", 0.7); + }; + + var addConflict = function(conflicts, original, replacement) { + + var conflict = conflicts.find('.template').clone().removeClass('template').addClass('conflict'); + + conflict.data('data',data); + + conflict.find('.filename').text(original.name); + conflict.find('.original .size').text(humanFileSize(original.size)); + conflict.find('.original .mtime').text(formatDate(original.mtime*1000)); + // ie sucks + if (replacement.size && replacement.lastModifiedDate) { + conflict.find('.replacement .size').text(humanFileSize(replacement.size)); + conflict.find('.replacement .mtime').text(formatDate(replacement.lastModifiedDate)); + } + var path = getPathForPreview(original.name); + lazyLoadPreview(path, original.type, function(previewpath){ + conflict.find('.original .icon').css('background-image','url('+previewpath+')'); + }, 96, 96); + getCroppedPreview(replacement).then( + function(path){ + conflict.find('.replacement .icon').css('background-image','url(' + path + ')'); + }, function(){ + getMimeIcon(replacement.type,function(path){ + conflict.find('.replacement .icon').css('background-image','url(' + path + ')'); + }); + } + ); + conflicts.append(conflict); + + //set more recent mtime bold + // ie sucks + if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() > original.mtime*1000) { + conflict.find('.replacement .mtime').css('font-weight', 'bold'); + } else if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() < original.mtime*1000) { + conflict.find('.original .mtime').css('font-weight', 'bold'); + } else { + //TODO add to same mtime collection? + } + + // set bigger size bold + if (replacement.size && replacement.size > original.size) { + conflict.find('.replacement .size').css('font-weight', 'bold'); + } else if (replacement.size && replacement.size < original.size) { + conflict.find('.original .size').css('font-weight', 'bold'); + } else { + //TODO add to same size collection? + } + + //TODO show skip action for files with same size and mtime in bottom row + + }; + //var selection = controller.getSelection(data.originalFiles); + //if (selection.defaultAction) { + // controller[selection.defaultAction](data); + //} else { + var dialog_name = 'oc-dialog-fileexists-content'; + var dialog_id = '#' + dialog_name; + if (this._fileexistsshown) { + // add conflict + + var conflicts = $(dialog_id+ ' .conflicts'); + addConflict(conflicts, original, replacement); + + var count = $(dialog_id+ ' .conflict').length; + var title = n('files', + '{count} file conflict', + '{count} file conflicts', + count, + {count:count} + ); + $(dialog_id).parent().children('.oc-dialog-title').text(title); + + //recalculate dimensions + $(window).trigger('resize'); + + } else { + //create dialog + this._fileexistsshown = true; + $.when(this._getFileExistsTemplate()).then(function($tmpl) { + var title = t('files','One file conflict'); + var $dlg = $tmpl.octemplate({ + dialog_name: dialog_name, + title: title, + type: 'fileexists', + + why: t('files','Which files do you want to keep?'), + what: t('files','If you select both versions, the copied file will have a number added to its name.') + }); + $('body').append($dlg); + + var conflicts = $($dlg).find('.conflicts'); + addConflict(conflicts, original, replacement); + + buttonlist = [{ + text: t('core', 'Cancel'), + classes: 'cancel', + click: function(){ + if ( typeof controller.onCancel !== 'undefined') { + controller.onCancel(data); + } + $(dialog_id).ocdialog('close'); + } + }, + { + text: t('core', 'Continue'), + classes: 'continue', + click: function(){ + if ( typeof controller.onContinue !== 'undefined') { + controller.onContinue($(dialog_id + ' .conflict')); + } + $(dialog_id).ocdialog('close'); + } + }]; + + $(dialog_id).ocdialog({ + width: 500, + closeOnEscape: true, + modal: true, + buttons: buttonlist, + closeButton: null, + close: function(event, ui) { + self._fileexistsshown = false; + $(this).ocdialog('destroy').remove(); + } + }); + + $(dialog_id).css('height','auto'); + + //add checkbox toggling actions + $(dialog_id).find('.allnewfiles').on('click', function() { + var checkboxes = $(dialog_id).find('.conflict .replacement input[type="checkbox"]'); + checkboxes.prop('checked', $(this).prop('checked')); + }); + $(dialog_id).find('.allexistingfiles').on('click', function() { + var checkboxes = $(dialog_id).find('.conflict .original input[type="checkbox"]'); + checkboxes.prop('checked', $(this).prop('checked')); + }); + $(dialog_id).find('.conflicts').on('click', '.replacement,.original', function() { + var checkbox = $(this).find('input[type="checkbox"]'); + checkbox.prop('checked', !checkbox.prop('checked')); + }); + $(dialog_id).find('.conflicts').on('click', 'input[type="checkbox"]', function() { + var checkbox = $(this); + checkbox.prop('checked', !checkbox.prop('checked')); + }); + + //update counters + $(dialog_id).on('click', '.replacement,.allnewfiles', function() { + var count = $(dialog_id).find('.conflict .replacement input[type="checkbox"]:checked').length; + if (count === $(dialog_id+ ' .conflict').length) { + $(dialog_id).find('.allnewfiles').prop('checked', true); + $(dialog_id).find('.allnewfiles + .count').text(t('files','(all selected)')); + } else if (count > 0) { + $(dialog_id).find('.allnewfiles').prop('checked', false); + $(dialog_id).find('.allnewfiles + .count').text(t('files','({count} selected)',{count:count})); + } else { + $(dialog_id).find('.allnewfiles').prop('checked', false); + $(dialog_id).find('.allnewfiles + .count').text(''); + } + }); + $(dialog_id).on('click', '.original,.allexistingfiles', function(){ + var count = $(dialog_id).find('.conflict .original input[type="checkbox"]:checked').length; + if (count === $(dialog_id+ ' .conflict').length) { + $(dialog_id).find('.allexistingfiles').prop('checked', true); + $(dialog_id).find('.allexistingfiles + .count').text(t('files','(all selected)')); + } else if (count > 0) { + $(dialog_id).find('.allexistingfiles').prop('checked', false); + $(dialog_id).find('.allexistingfiles + .count').text(t('files','({count} selected)',{count:count})); + } else { + $(dialog_id).find('.allexistingfiles').prop('checked', false); + $(dialog_id).find('.allexistingfiles + .count').text(''); + } + }); + }) + .fail(function() { + alert(t('core', 'Error loading file exists template')); + }); + } + //} + }, _getFilePickerTemplate: function() { var defer = $.Deferred(); if(!this.$filePickerTemplate) { @@ -219,8 +468,8 @@ var OCdialogs = { self.$listTmpl = self.$filePickerTemplate.find('.filelist li:first-child').detach(); defer.resolve(self.$filePickerTemplate); }) - .fail(function() { - defer.reject(); + .fail(function(jqXHR, textStatus, errorThrown) { + defer.reject(jqXHR.status, errorThrown); }); } else { defer.resolve(this.$filePickerTemplate); @@ -235,14 +484,30 @@ var OCdialogs = { self.$messageTemplate = $(tmpl); defer.resolve(self.$messageTemplate); }) - .fail(function() { - defer.reject(); + .fail(function(jqXHR, textStatus, errorThrown) { + defer.reject(jqXHR.status, errorThrown); }); } else { defer.resolve(this.$messageTemplate); } return defer.promise(); }, + _getFileExistsTemplate: function () { + var defer = $.Deferred(); + if (!this.$fileexistsTemplate) { + var self = this; + $.get(OC.filePath('files', 'templates', 'fileexists.html'), function (tmpl) { + self.$fileexistsTemplate = $(tmpl); + defer.resolve(self.$fileexistsTemplate); + }) + .fail(function () { + defer.reject(); + }); + } else { + defer.resolve(this.$fileexistsTemplate); + } + return defer.promise(); + }, _getFileList: function(dir, mimeType) { if (typeof(mimeType) === "string") { mimeType = [mimeType]; @@ -292,11 +557,7 @@ var OCdialogs = { filename: entry.name, date: OC.mtime2date(entry.mtime) }); - if (entry.mimetype === "httpd/unix-directory") { - $li.find('img').attr('src', OC.imagePath('core', 'filetypes/folder.png')); - } else { - $li.find('img').attr('src', OC.Router.generate('core_ajax_preview', {x:32, y:32, file:escapeHTML(dir+'/'+entry.name)}) ); - } + $li.find('img').attr('src', entry.mimetype_icon); self.$filelist.append($li); }); diff --git a/core/js/placeholder.js b/core/js/placeholder.js index d63730547d7..ee2a8ce84c4 100644 --- a/core/js/placeholder.js +++ b/core/js/placeholder.js @@ -36,10 +36,21 @@ * * <div id="albumart" style="background-color: hsl(123, 90%, 65%); ... ">T</div> * + * You may also call it like this, to have a different background, than the seed: + * + * $('#albumart').placeholder('The Album Title', 'Album Title'); + * + * Resulting in: + * + * <div id="albumart" style="background-color: hsl(123, 90%, 65%); ... ">A</div> + * */ (function ($) { - $.fn.placeholder = function(seed) { + $.fn.placeholder = function(seed, text) { + // set optional argument "text" to value of "seed" if undefined + text = text || seed; + var hash = md5(seed), maxRange = parseInt('ffffffffffffffffffffffffffffffff', 16), hue = parseInt(hash, 16) / maxRange * 256, @@ -56,7 +67,7 @@ this.css('font-size', (height * 0.55) + 'px'); if(seed !== null && seed.length) { - this.html(seed[0].toUpperCase()); + this.html(text[0].toUpperCase()); } }; }(jQuery)); diff --git a/core/js/share.js b/core/js/share.js index 27c16f38b92..82f5da0baea 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -174,10 +174,10 @@ OC.Share={ var allowPublicUploadStatus = false; $.each(data.shares, function(key, value) { - if (allowPublicUploadStatus) { + if (value.share_type === OC.Share.SHARE_TYPE_LINK) { + allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false; return true; } - allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false; }); html += '<input id="shareWith" type="text" placeholder="'+t('core', 'Share with')+'" />'; @@ -233,6 +233,7 @@ OC.Share={ // } else { $.get(OC.filePath('core', 'ajax', 'share.php'), { fetch: 'getShareWith', search: search.term, itemShares: OC.Share.itemShares }, function(result) { if (result.status == 'success' && result.data.length > 0) { + $( "#shareWith" ).autocomplete( "option", "autoFocus", true ); response(result.data); } else { // Suggest sharing via email if valid email address @@ -240,6 +241,7 @@ OC.Share={ // if (pattern.test(search.term)) { // response([{label: t('core', 'Share via email:')+' '+search.term, value: {shareType: OC.Share.SHARE_TYPE_EMAIL, shareWith: search.term}}]); // } else { + $( "#shareWith" ).autocomplete( "option", "autoFocus", false ); response([t('core', 'No people found')]); // } } @@ -423,7 +425,7 @@ OC.Share={ dateFormat : 'dd-mm-yy' }); } -} +}; $(document).ready(function() { @@ -481,7 +483,7 @@ $(document).ready(function() { if (!$('.cruds', this).is(':visible')) { $('a', this).hide(); if (!$('input[name="edit"]', this).is(':checked')) { - $('input:[type=checkbox]', this).hide(); + $('input[type="checkbox"]', this).hide(); $('label', this).hide(); } } else { @@ -512,7 +514,7 @@ $(document).ready(function() { $(document).on('change', '#dropdown .permissions', function() { if ($(this).attr('name') == 'edit') { - var li = $(this).parent().parent() + var li = $(this).parent().parent(); var checkboxes = $('.permissions', li); var checked = $(this).is(':checked'); // Check/uncheck Create, Update, and Delete checkboxes if Edit is checked/unck @@ -601,7 +603,18 @@ $(document).ready(function() { if (!$('#showPassword').is(':checked') ) { var itemType = $('#dropdown').data('item-type'); var itemSource = $('#dropdown').data('item-source'); - OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', OC.PERMISSION_READ); + var allowPublicUpload = $('#sharingDialogAllowPublicUpload').is(':checked'); + var permissions = 0; + + // Calculate permissions + if (allowPublicUpload) { + permissions = OC.PERMISSION_UPDATE + OC.PERMISSION_CREATE + OC.PERMISSION_READ; + } else { + permissions = OC.PERMISSION_READ; + } + + + OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', permissions); } else { $('#linkPassText').focus(); } |