personal.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /* global OC */
  2. /**
  3. * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
  4. * 2013, Morris Jobke <morris.jobke@gmail.com>
  5. * 2016, Christoph Wurst <christoph@owncloud.com>
  6. * This file is licensed under the Affero General Public License version 3 or later.
  7. * See the COPYING-README file.
  8. */
  9. OC.Settings = OC.Settings || {};
  10. /**
  11. * The callback will be fired as soon as enter is pressed by the
  12. * user or 1 second after the last data entry
  13. *
  14. * @param callback
  15. * @param allowEmptyValue if this is set to true the callback is also called when the value is empty
  16. */
  17. jQuery.fn.keyUpDelayedOrEnter = function (callback, allowEmptyValue) {
  18. var cb = callback;
  19. var that = this;
  20. this.keyup(_.debounce(function (event) {
  21. // enter is already handled in keypress
  22. if (event.keyCode === 13) {
  23. return;
  24. }
  25. if (allowEmptyValue || that.val() !== '') {
  26. cb(event);
  27. }
  28. }, 1000));
  29. this.keypress(function (event) {
  30. if (event.keyCode === 13 && (allowEmptyValue || that.val() !== '')) {
  31. event.preventDefault();
  32. cb(event);
  33. }
  34. });
  35. this.bind('paste', null, function (event) {
  36. if(!event.keyCode){
  37. if (allowEmptyValue || that.val() !== '') {
  38. cb(event);
  39. }
  40. }
  41. });
  42. };
  43. function updateAvatar (hidedefault) {
  44. var $headerdiv = $('#header .avatardiv');
  45. var $displaydiv = $('#displayavatar .avatardiv');
  46. //Bump avatar avatarversion
  47. oc_userconfig.avatar.version = -(Math.floor(Math.random() * 1000));
  48. if (hidedefault) {
  49. $headerdiv.hide();
  50. $('#header .avatardiv').removeClass('avatardiv-shown');
  51. } else {
  52. $headerdiv.css({'background-color': ''});
  53. $headerdiv.avatar(OC.currentUser, 32, true);
  54. $('#header .avatardiv').addClass('avatardiv-shown');
  55. }
  56. $displaydiv.css({'background-color': ''});
  57. $displaydiv.avatar(OC.currentUser, 145, true, null, function() {
  58. $displaydiv.removeClass('loading');
  59. $('#displayavatar img').show();
  60. if($('#displayavatar img').length === 0) {
  61. $('#removeavatar').removeClass('inlineblock').addClass('hidden');
  62. } else {
  63. $('#removeavatar').removeClass('hidden').addClass('inlineblock');
  64. }
  65. });
  66. }
  67. function showAvatarCropper () {
  68. var $cropper = $('#cropper');
  69. var $cropperImage = $('<img/>');
  70. $cropperImage.css('opacity', 0); // prevent showing the unresized image
  71. $cropper.children('.inner-container').prepend($cropperImage);
  72. $cropperImage.attr('src',
  73. OC.generateUrl('/avatar/tmp') + '?requesttoken=' + encodeURIComponent(oc_requesttoken) + '#' + Math.floor(Math.random() * 1000));
  74. $cropperImage.load(function () {
  75. var img = $cropperImage.get()[0];
  76. var selectSize = Math.min(img.width, img.height);
  77. var offsetX = (img.width - selectSize) / 2;
  78. var offsetY = (img.height - selectSize) / 2;
  79. $cropperImage.Jcrop({
  80. onChange: saveCoords,
  81. onSelect: saveCoords,
  82. aspectRatio: 1,
  83. boxHeight: Math.min(500, $('#app-content').height() -100),
  84. boxWidth: Math.min(500, $('#app-content').width()),
  85. setSelect: [offsetX, offsetY, selectSize, selectSize]
  86. }, function() {
  87. $cropper.show();
  88. });
  89. });
  90. }
  91. function sendCropData () {
  92. cleanCropper();
  93. var cropperData = $('#cropper').data();
  94. var data = {
  95. x: cropperData.x,
  96. y: cropperData.y,
  97. w: cropperData.w,
  98. h: cropperData.h
  99. };
  100. $.post(OC.generateUrl('/avatar/cropped'), {crop: data}, avatarResponseHandler);
  101. }
  102. function saveCoords (c) {
  103. $('#cropper').data(c);
  104. }
  105. function cleanCropper () {
  106. var $cropper = $('#cropper');
  107. $('#displayavatar').show();
  108. $cropper.hide();
  109. $('.jcrop-holder').remove();
  110. $('#cropper img').removeData('Jcrop').removeAttr('style').removeAttr('src');
  111. $('#cropper img').remove();
  112. }
  113. function avatarResponseHandler (data) {
  114. if (typeof data === 'string') {
  115. data = JSON.parse(data);
  116. }
  117. var $warning = $('#avatarform .warning');
  118. $warning.hide();
  119. if (data.status === "success") {
  120. updateAvatar();
  121. } else if (data.data === "notsquare") {
  122. showAvatarCropper();
  123. } else {
  124. $warning.show();
  125. $warning.text(data.data.message);
  126. }
  127. }
  128. $(document).ready(function () {
  129. if($('#pass2').length) {
  130. $('#pass2').showPassword().keyup();
  131. }
  132. var removeloader = function () {
  133. setTimeout(function(){
  134. if ($('.password-state').length > 0) {
  135. $('.password-state').remove();
  136. }
  137. }, 5000)
  138. };
  139. $("#passwordbutton").click(function () {
  140. var isIE8or9 = $('html').hasClass('lte9');
  141. // FIXME - TODO - once support for IE8 and IE9 is dropped
  142. // for IE8 and IE9 this will check additionally if the typed in password
  143. // is different from the placeholder, because in IE8/9 the placeholder
  144. // is simply set as the value to look like a placeholder
  145. if ($('#pass1').val() !== '' && $('#pass2').val() !== ''
  146. && !(isIE8or9 && $('#pass2').val() === $('#pass2').attr('placeholder'))) {
  147. // Serialize the data
  148. var post = $("#passwordform").serialize();
  149. $('#passwordchanged').hide();
  150. $('#passworderror').hide();
  151. $("#passwordbutton").attr('disabled', 'disabled');
  152. $("#passwordbutton").after("<span class='password-loading icon icon-loading-small-dark password-state'></span>");
  153. $(".personal-show-label").hide();
  154. // Ajax foo
  155. $.post(OC.generateUrl('/settings/personal/changepassword'), post, function (data) {
  156. if (data.status === "success") {
  157. $("#passwordbutton").after("<span class='checkmark icon icon-checkmark password-state'></span>");
  158. removeloader();
  159. $(".personal-show-label").show();
  160. $('#pass1').val('');
  161. $('#pass2').val('').change();
  162. }
  163. if (typeof(data.data) !== "undefined") {
  164. OC.msg.finishedSaving('#password-error-msg', data);
  165. } else {
  166. OC.msg.finishedSaving('#password-error-msg',
  167. {
  168. 'status' : 'error',
  169. 'data' : {
  170. 'message' : t('core', 'Unable to change password')
  171. }
  172. }
  173. );
  174. }
  175. $(".password-loading").remove();
  176. $("#passwordbutton").removeAttr('disabled');
  177. });
  178. return false;
  179. } else {
  180. OC.msg.finishedSaving('#password-error-msg',
  181. {
  182. 'status' : 'error',
  183. 'data' : {
  184. 'message' : t('core', 'Unable to change password')
  185. }
  186. }
  187. );
  188. return false;
  189. }
  190. });
  191. var federationSettingsView = new OC.Settings.FederationSettingsView({
  192. el: '#personal-settings'
  193. });
  194. federationSettingsView.render();
  195. $("#languageinput").change(function () {
  196. // Serialize the data
  197. var post = $("#languageinput").serialize();
  198. // Ajax foo
  199. $.ajax(
  200. 'ajax/setlanguage.php',
  201. {
  202. method: 'POST',
  203. data: post
  204. }
  205. ).done(function() {
  206. location.reload();
  207. }).fail(function(jqXHR) {
  208. $('#passworderror').text(jqXHR.responseJSON.message);
  209. });
  210. return false;
  211. });
  212. var uploadparms = {
  213. pasteZone: null,
  214. done: function (e, data) {
  215. var response = data;
  216. if (typeof data.result === 'string') {
  217. response = JSON.parse(data.result);
  218. } else if (data.result && data.result.length) {
  219. // fetch response from iframe
  220. response = JSON.parse(data.result[0].body.innerText);
  221. } else {
  222. response = data.result;
  223. }
  224. avatarResponseHandler(response);
  225. },
  226. submit: function(e, data) {
  227. $('#displayavatar img').hide();
  228. $('#displayavatar .avatardiv').addClass('loading');
  229. data.formData = _.extend(data.formData || {}, {
  230. requesttoken: OC.requestToken
  231. });
  232. },
  233. fail: function (e, data){
  234. var msg = data.jqXHR.statusText + ' (' + data.jqXHR.status + ')';
  235. if (!_.isUndefined(data.jqXHR.responseJSON) &&
  236. !_.isUndefined(data.jqXHR.responseJSON.data) &&
  237. !_.isUndefined(data.jqXHR.responseJSON.data.message)
  238. ) {
  239. msg = data.jqXHR.responseJSON.data.message;
  240. }
  241. avatarResponseHandler({
  242. data: {
  243. message: msg
  244. }
  245. });
  246. }
  247. };
  248. $('#uploadavatar').fileupload(uploadparms);
  249. $('#selectavatar').click(function () {
  250. OC.dialogs.filepicker(
  251. t('settings', "Select a profile picture"),
  252. function (path) {
  253. $('#displayavatar img').hide();
  254. $('#displayavatar .avatardiv').addClass('loading');
  255. $.ajax({
  256. type: "POST",
  257. url: OC.generateUrl('/avatar/'),
  258. data: { path: path }
  259. }).done(avatarResponseHandler)
  260. .fail(function(jqXHR) {
  261. var msg = jqXHR.statusText + ' (' + jqXHR.status + ')';
  262. if (!_.isUndefined(jqXHR.responseJSON) &&
  263. !_.isUndefined(jqXHR.responseJSON.data) &&
  264. !_.isUndefined(jqXHR.responseJSON.data.message)
  265. ) {
  266. msg = jqXHR.responseJSON.data.message;
  267. }
  268. avatarResponseHandler({
  269. data: {
  270. message: msg
  271. }
  272. });
  273. });
  274. },
  275. false,
  276. ["image/png", "image/jpeg"]
  277. );
  278. });
  279. $('#removeavatar').click(function () {
  280. $.ajax({
  281. type: 'DELETE',
  282. url: OC.generateUrl('/avatar/'),
  283. success: function () {
  284. updateAvatar(true);
  285. }
  286. });
  287. });
  288. $('#abortcropperbutton').click(function () {
  289. $('#displayavatar .avatardiv').removeClass('loading');
  290. $('#displayavatar img').show();
  291. cleanCropper();
  292. });
  293. $('#sendcropperbutton').click(function () {
  294. sendCropData();
  295. });
  296. $('#pass2').strengthify({
  297. zxcvbn: OC.linkTo('core','vendor/zxcvbn/dist/zxcvbn.js'),
  298. titles: [
  299. t('core', 'Very weak password'),
  300. t('core', 'Weak password'),
  301. t('core', 'So-so password'),
  302. t('core', 'Good password'),
  303. t('core', 'Strong password')
  304. ],
  305. drawTitles: true,
  306. });
  307. // Load the big avatar
  308. $('#avatarform .avatardiv').avatar(OC.currentUser, 145, true, null, function() {
  309. if($('#displayavatar img').length === 0) {
  310. $('#removeavatar').removeClass('inlineblock').addClass('hidden');
  311. } else {
  312. $('#removeavatar').removeClass('hidden').addClass('inlineblock');
  313. }
  314. });
  315. // Show token views
  316. var collection = new OC.Settings.AuthTokenCollection();
  317. var view = new OC.Settings.AuthTokenView({
  318. collection: collection
  319. });
  320. view.reload();
  321. // 'redirect' to anchor sections
  322. // anchors are lost on redirects (e.g. while solving the 2fa challenge) otherwise
  323. // example: /settings/person?section=devices will result in /settings/person?#devices
  324. if (!window.location.hash) {
  325. var query = OC.parseQueryString(location.search);
  326. if (query && query.section) {
  327. OC.Util.History.replaceState({});
  328. window.location.hash = query.section;
  329. }
  330. }
  331. });
  332. if (!OC.Encryption) {
  333. OC.Encryption = {};
  334. }
  335. OC.Encryption.msg = {
  336. start: function (selector, msg) {
  337. var spinner = '<img src="' + OC.imagePath('core', 'loading-small.gif') + '">';
  338. $(selector)
  339. .html(msg + ' ' + spinner)
  340. .removeClass('success')
  341. .removeClass('error')
  342. .stop(true, true)
  343. .show();
  344. },
  345. finished: function (selector, data) {
  346. if (data.status === "success") {
  347. $(selector).html(data.data.message)
  348. .addClass('success')
  349. .stop(true, true)
  350. .delay(3000);
  351. } else {
  352. $(selector).html(data.data.message).addClass('error');
  353. }
  354. }
  355. };
  356. OC.Settings.updateAvatar = updateAvatar;