personal.js 10 KB

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