PageSourceSearch

https://static.4shared.com/js/bottomSheets/BS_signIn.4min.js?ver=-693238496

js 4shared.com collected 2026-09-24 07:16:44 UTC 20,923 bytes, 613 lines download raw bytes

1$(function() {
2
3  let xhr, captchaWidgetElement, signInInitiatorName;
4  // Captcha state shared by the proactive (mandatory sign-up) and reactive (429.0107) flows — one
5  // grecaptcha widget whose callback branches on captchaMode (DEV-13809).
6  let captchaMode, captchaRetryRegistration, captchaResponseText;
7  const fileName = $('.jsParams').find('.jsFileName').val();
8  const isLoggedIn = Config.isUserLoggedIn;
9  const pageBody = $('body');
10
11
12// --------------------- SIGN IN bottom sheet ---------------------
13  const signInButton = $('.jsShowSignIn', pageBody);
14  const signInBS = $('.jsSignInBottomSheet', pageBody);
15  const signInBack = $('.jsBottomSheetBack', signInBS);
16  const signInForm = $('.jsSignInForm', signInBS);
17  let returnTo = $('.jsReturnTo', signInBS).val();
18  const mandatorySignupCaptcha = $('.jsMandatorySignupCaptcha', signInBS).val() === 'true';
19  const analyticsPageName = $('.jsAnalyticsPageName').val();
20  let postLoginAction = localStorage.getItem('post-login-action');
21  const postLoginActionItemId = localStorage.getItem('post-login-action-item-id');
22
23// structure
24
25  const facebookSignInButton = $('.jsFBLoginButton', signInBS);
26  const googleSignInButton = $('.jsGPLoginButton', signInBS);
27  const showSecondaryScreen = $('.jsGoEmailLogic', signInBS);
28  const continueSignInButton = $('.jsContinueSignInButton', signInBS);
29  const remindPasswordButton = $('.jsRemindPassword', signInBS);
30  const emailPasswordBlock = $('.jsEmailPasswordBlock', signInBS);
31  const signInLogin = $('.jsInputLogin', signInBS);
32  const signInPassword = $('.jsInputPassword', signInBS);
33  const signInUserName = $('.jsInputUsername', signInBS);
34  const showHidePassword = $('.jsShowPassword', signInBS);
35  const privacyBlock = $('.jsPrivacyBlock', signInBS);
36
37// errors
38  const allErrors = $('.jsError', signInBS);
39  const errorInvalidEmail = $(".jsEmailNotValid", signInBS);
40  const errorEmptyEmail = $(".jsEmailRequired", signInBS);
41  const errorEmptyPassword = $(".jsPasswordRequired", signInBS);
42  const errorEmptyName = $(".jsFirstNameRequired", signInBS);
43  const errorConcernRequired = $(".jsGDPRAgreeRequired", signInBS);
44  const errorFromServer = $(".jsErrorFromServer", signInBS);
45  const errorInvalidPassword = $(".jsInvalidPassword", signInBS);
46
47// hints
48  const remindPasswordHint = $('.jsRemindPasswordHint', signInBS);
49  const remindPasswordEmail = $('.jsEmailForInstructions', signInBS);
50
51// params for login from www.4s.io
52  const SIGNIN_PARAMS_PREFIX = "signInParams=";
53  const postLoginHash = window.location.hash !== '' ? window.location.hash : window.location.search;
54  const postLoginHashIndex = postLoginHash.indexOf(SIGNIN_PARAMS_PREFIX);
55
56
57  signInButton.click(function () {
58    if (isLoggedIn) {
59      window.location.href = `${window.location.origin}/account/home.jsp`;
60      return;
61    }
62    window.showSignInBottomSheet({screenNumber: 1, initiator: 'header'});
63  });
64
65// screen 1 - main login buttons (via social or via email)
66// screen 2 - enter email
67// screen 3 - enter user name
68// screen 4 - enter password
69// screen 5 - privacy checkboxes
70// screen 6 - verify email
71// screen 7 - validate captcha
72
73  window.showSignInBottomSheet = function (options) {
74    let { screenNumber, initiator, postAuthenticateAction, postAuthenticateItemId, linkReturnTo } = options;
75
76    postAuthenticateItemId = typeof postAuthenticateItemId === 'object' ? JSON.stringify(postAuthenticateItemId) : postAuthenticateItemId;
77
78    if (pageBody.hasClass("site4sIo")) {
79      const siteOptions = {
80        screenNumber,
81        initiator,
82        postAuthenticateAction,
83        postAuthenticateItemId: postAuthenticateAction === "add_folder_to_library" ? JSON.parse(postAuthenticateItemId) : postAuthenticateItemId,
84        linkReturnTo
85      }
86
87      const url = window.location.href.replace(`${window.location.origin}/`, Config.mainSiteUrlHttpsPath);
88
89      if (siteOptions && siteOptions.linkReturnTo) {
90        siteOptions.linkReturnTo = siteOptions.linkReturnTo.replace(`${window.location.origin}/`, Config.mainSiteUrlHttpsPath);
91      }
92
93      const stringJSONParams = JSON.stringify(siteOptions);
94      const paramsURLEncoded = encodeURIComponent(encodeURIComponent(stringJSONParams).replace(/'/g, "%27"));
95
96      window.location.href = url + (siteOptions ? (url.indexOf("?") !== -1 && "&" || "?") + SIGNIN_PARAMS_PREFIX + paramsURLEncoded : "");
97
98      return;
99    }
100
101    localStorage.setItem('post-login-signin-initiator-element', initiator);
102
103    if (postAuthenticateAction) {
104      localStorage.setItem('post-login-action', postAuthenticateAction);
105    }
106
107    if (postAuthenticateItemId) {
108      localStorage.setItem('post-login-action-item-id', postAuthenticateItemId);
109    }
110
111    setCurrentScreen(screenNumber || 1);
112    signInInitiatorName = initiator ? initiator : 'header';
113
114    window.showBottomSheet('signIn');
115    pageBody.attr('data-signin-initiator', signInInitiatorName);
116
117    if (pageBody.hasClass('type-music') && !linkReturnTo) {
118      linkReturnTo = window.location.href;
119    }
120
121    trackAnalyticsEventClicks('Login_Popup', 'login_popup_view');
122
123    setReturnTo(googleSignInButton, linkReturnTo);
124    setReturnTo(facebookSignInButton, linkReturnTo);
125    returnTo = linkReturnTo || $('.jsReturnTo', signInBS).val();
126  }
127
128
129
130
131// --------------------- post login actions analytics -------------------
132  if (waitConfirmAdultContent && waitConfirmAdultContent(Config.isUserLoggedIn ? $('#jsCurUserId').val(): false)) {
133    return;
134  }
135
136  if (!pageBody.hasClass('jsSocialLogin')) {
137    localStorage.removeItem('post-login-action');
138    localStorage.removeItem('post-login-action-item-id');
139  }
140
141  if (isLoggedIn && postLoginAction) {
142    setTimeout(function() {
143      Events.fireEvent(postLoginAction, postLoginActionItemId);
144      postLoginAction = false;
145    }, 200);
146  }
147
148// check sign-in prompt params in url
149  if (postLoginHashIndex !== -1) {
150    if (isLoggedIn) { // check for redirect after social sign-in
151      window.history.pushState('', document.title, (window.location.href).replace(postLoginHash.substring(postLoginHashIndex-1), ''));
152      return;
153    }
154
155    const paramsURLEncoded = postLoginHash.substring(postLoginHashIndex + SIGNIN_PARAMS_PREFIX.length, postLoginHash.length);
156
157    if (paramsURLEncoded) {
158      const stringJSONParams = decodeURIComponent(decodeURIComponent(paramsURLEncoded).replace("%27", "'"));
159
160      try {
161        const postLoginParams = JSON.parse(stringJSONParams);
162
163        window.showSignInBottomSheet(postLoginParams);
164      } catch (e){
165        Utils.log(`Something wrong happened during execute hash-callback, ${e}`);
166      }
167    }
168  }
169
170
171  $('.jsCloseBottomSheet', signInBS).click(function () {
172    localStorage.removeItem('post-login-action');
173    localStorage.removeItem('post-login-action-item-id');
174
175    trackAnalyticsEventClicks('Login_Popup', 'login_popup_close');
176  })
177
178  function setReturnTo(el, linkReturnTo) {
179    if  (!linkReturnTo) {
180      //el.attr('data-href', encodeURIComponent(el.attr('data-def')));
181      el.attr('data-href', encodeUrl(el.attr('data-def')));
182
183      return;
184    }
185    const href = new URL(el.attr('data-def'));
186    href.searchParams.set('fp', encodeURIComponent(linkReturnTo));
187    el.attr('data-href', href);
188  }
189
190  function encodeUrl(url) {
191    const urlObj = new URL(url);
192    const params = new URLSearchParams(urlObj.search);
193
194    for (let [key, value] of params.entries()) {
195      params.set(key, encodeURIComponent(value));
196    }
197
198    return `${urlObj.origin}${urlObj.pathname}?${params.toString()}`;
199  }
200
201  function getCurrentScreen() {
202    return signInBS.attr('data-screen');
203  }
204
205  function setCurrentScreen(val) {
206    signInBS.attr('data-screen', val);
207    $('input:visible', emailPasswordBlock).focus();
208  }
209
210  googleSignInButton.click(function () {
211    trackAnalyticsEventClicks('Login_Popup', 'login_popup_google');
212    window.location.href = googleSignInButton.attr('data-href');
213  });
214
215  facebookSignInButton.click(function () {
216    trackAnalyticsEventClicks('Login_Popup', 'login_popup_facebook');
217    window.location.href = facebookSignInButton.attr('data-href');
218  });
219
220  showSecondaryScreen.click(function () {
221    setCurrentScreen(2);
222    signInLogin.focus();
223
224    trackAnalyticsEventClicks('Login_Popup', 'login_popup_email');
225  });
226
227  signInBack.click(function () {
228    if (getCurrentScreen() === '4' && signInBS.hasClass('jsUserExists')) {
229      setCurrentScreen(2);
230    } else {
231      setCurrentScreen(1 * getCurrentScreen() - 1);
232    }
233
234    allErrors.hide();
235  });
236
237  continueSignInButton.click(function () {
238    if (!validateTextInputs()) return;
239
240    trackAnalyticsContinueClickEvent(getCurrentScreen());
241
242    if (getCurrentScreen() === '2') {
243      checkGoLoginOrRegistration();
244      return;
245    }
246
247    if (getCurrentScreen() === '4' && signInBS.hasClass('jsUserExists')) {
248      validateUserLogin();
249      return;
250    }
251
252    if (getCurrentScreen() === '5') {
253      // Mandatory captcha as the final registration step (DEV-13809): show the captcha instead of
254      // creating the account directly; its callback runs doSignIn(true, token). Property off → old flow.
255      if (mandatorySignupCaptcha) {
256        showSignupCaptcha();
257      } else {
258        doSignIn(true);
259      }
260      return;
261    }
262
263    setCurrentScreen(1 * getCurrentScreen() + 1);
264  });
265
266  $('input', emailPasswordBlock).on('keydown change', function (e) {
267    allErrors.hide();
268
269    if (e.keyCode === 13) { // Enter key
270      continueSignInButton.click();
271    }
272  });
273
274  function checkGoLoginOrRegistration() {
275    if (xhr) xhr.abort();
276
277    xhr = $.ajax({
278      type: 'GET',
279      url: '/web/rest/usersWeb/validate',
280      data: {
281        email: signInLogin.val()
282      },
283      success: function () {
284        console.log('unregistered user, proceed registration');
285        signInBS.removeClass('jsUserExists');
286        signInLogin.attr('name', 'email');
287        setCurrentScreen(3);
288      },
289      error: function () {
290        console.log('user exists, go to login');
291        signInBS.addClass('jsUserExists');
292        signInLogin.attr('name', 'login');
293        setCurrentScreen(4);
294      }
295    });
296  }
297
298  function validateTextInputs() {
299    if (getCurrentScreen() === '2' && !signInLogin[0].checkValidity()) {
300      if (signInLogin.val().trim() === '') {
301        errorEmptyEmail.show();
302      } else {
303        errorInvalidEmail.show();
304      }
305      return false;
306    } else if (getCurrentScreen() === '4' && !signInPassword[0].checkValidity()) {
307      errorEmptyPassword.show();
308      return false;
309    } else if (getCurrentScreen() === '3' && !signInUserName[0].checkValidity()) {
310      errorEmptyName.show();
311      return false;
312    } else if (getCurrentScreen() === '5' && !validatePrivacyCheckboxes()) {
313      errorConcernRequired.show();
314      return false;
315    } else {
316      allErrors.hide();
317      return true;
318    }
319  }
320
321  function validatePrivacyCheckboxes() {
322    const inputsCount = $('input[type="checkbox"]', privacyBlock).length;
323    const checkedCount = $(':checked', privacyBlock).length;
324
325    return inputsCount === checkedCount;
326  }
327
328  showHidePassword.click(function () {
329    $(this).toggleClass('is-visible');
330    signInPassword.attr('type', function (index, attr) {
331      return attr === 'password' ? 'text' : 'password';
332    })
333  });
334
335  function doSignIn(newRegistration, captchaToken) {
336    signInBS.addClass('isLoading');
337
338    let postData = signInForm.serialize() + "&addHeaderForSpecial=true";
339    if (captchaToken) postData += "&captchaResponse=" + encodeURIComponent(captchaToken);
340
341    $.ajax({
342      type: 'POST',
343      url: newRegistration ? '/web/rest/usersWeb/signUp' : '/web/login',
344      data: postData,
345      success: function (resp, state, xhr) {
346
347        //redirect for addHeaderForSpecial
348        const xLocation = xhr && xhr.getResponseHeader('x-location');
349        if (xLocation) {
350          window.location.href = xLocation;
351          return;
352        }
353
354        signInBS.removeClass('isLoading');
355        window.hideAllBottomSheets();
356        localStorage.setItem('email-login-in-process', newRegistration ? 'signup' : 'email');
357
358        if (returnTo === "") {
359          window.location.href = `${window.location.origin}/account/home.jsp`;
360          return;
361        }
362
363        if (postLoginHashIndex !== -1) { // only for www.4s.io case
364          window.history.pushState('', document.title, (window.location.href).replace(postLoginHash.substring(postLoginHashIndex-1), ''));
365          returnTo = returnTo.replace(postLoginHash.substring(postLoginHashIndex-1), '');
366        }
367
368        if (window.location.hash) {
369          window.location.reload();
370        } else {
371          window.location.href = decodeURIComponent(returnTo);
372        }
373
374      },
375      error: function (data) {
376        signInBS.removeClass('isLoading');
377
378        trackAnalyticsEventLogins('Login_Fail', newRegistration ? 'signup_fail' : 'email_fail');
379
380        const parsedJSON = JSON.parse(data.responseText);
381        const errorCode = parsedJSON.code ? parsedJSON.code.split('.')[1] : '';
382        if (errorCode === '0107') {
383          // Reactive rate-limit captcha (unchanged mechanism); retry the SAME endpoint after solve (AC #6).
384          const msg1 = fileName && fileName.length ? $('.jsMsgToDownload').val() : $('.jsMsgForFree').val();
385          const msg2 = fileName && fileName.length ? fileName : $('.jsMsgFreeSpace').val();
386          showCaptchaScreen(data.responseText, msg1, msg2, newRegistration);
387        } else if (errorCode === '0325') {
388          // ERROR_INVALID_CAPTCHA from signUp — re-show the mandatory captcha for a fresh token AND
389          // surface the server message ("Captcha is invalid…") so it isn't a silent loop (DEV-13809 QA
390          // Major 3). Entered form data is preserved (it lives on the earlier sign-up screens).
391          showSignupCaptcha(parsedJSON.message);
392        } else {
393          // A non-captcha server error raised after the mandatory sign-up captcha (we're on screen 7,
394          // which has no error area) — return to the last form step so the message is visible. Form
395          // data is preserved. Reactive flow hides the sheet before retrying, so it doesn't apply.
396          if (captchaMode === 'signup') setCurrentScreen(5);
397          showServerError(data);
398        }
399      }
400    });
401  }
402
403  function validateUserLogin() {
404    signInBS.addClass('isLoading');
405
406    $.ajax({
407      type: "get",
408      url: Config.mainSiteUrlHttpsPath + "web/login/validate",
409      data: {
410        login: signInLogin.val(),
411        password: signInPassword.val()
412      },
413      dataType: "jsonp",
414      success: function (data) {
415        if (!data.success) {
416          errorInvalidPassword.show();
417          signInBS.removeClass('isLoading');
418        } else {
419          doSignIn(false);
420        }
421      },
422      error: function (data) {
423        errorFromServer.text(data.responseText).show();
424        signInBS.removeClass('isLoading');
425      }
426    });
427  }
428
429  remindPasswordButton.click(function () {
430    trackAnalyticsEventClicks('Login_Popup', 'login_page_password_forgot');
431
432    $.ajax({
433      type: 'POST',
434      url: '/remindPassword.jsp',
435      data: signInForm.serialize(),
436      success: function () {
437        allErrors.hide();
438        remindPasswordHint.show();
439        remindPasswordEmail.text(signInLogin.val());
440        remindPasswordButton.hide();
441      },
442      error: function (data) {
443        console.log(data);
444      }
445    });
446  })
447
448  signInBS.click(function () {
449    if (remindPasswordHint.is(':visible')) {
450      remindPasswordHint.hide();
451      remindPasswordButton.removeAttr('style');
452    }
453  })
454
455  function showServerError(data) {
456    if (data.responseText && data.responseText.length) {
457      const parsedJSON = JSON.parse(data.responseText);
458      const msg = (!parsedJSON.message) ? data.statusText : parsedJSON.message;
459      const errorCode = parsedJSON.code.substring(4);
460      if (errorCode === '0228') {
461        msg.replace('$[p1]', signInLogin.val())
462      }
463      errorFromServer.text(msg).show();
464    }
465  }
466
467  // Renders (or resets) the shared reCAPTCHA widget on the captcha screen and shows it. Its callback branches on captchaMode:
468  // 'signup'  : proactive mandatory captcha — token goes straight to signUp (DEV-13809).
469  // 'reactive': existing 429.0107 flow — validate limitKey via /web/rest/api/reCaptcha, then retry the ORIGINATING endpoint. Mechanism unchanged.
470
471  function renderOrResetCaptcha() {
472    // Scope to the sign-in BS + unique id: .jsContentCaptchaBlock / #reCaptchaBlock are shared with
473    // the comments captcha, so an unscoped lookup could render into another screen (DEV-13809 QA Minor 4).
474    const wrapElement = $(".jsContentCaptchaBlock", signInBS);
475
476    setCurrentScreen(7);
477    $('.jsCaptchaError', signInBS).hide().empty();
478
479    if (typeof captchaWidgetElement != 'undefined') {
480      grecaptcha.reset(captchaWidgetElement);
481    } else {
482      captchaWidgetElement = grecaptcha.render(wrapElement.find('#signInReCaptchaBlock')[0], {
483        'sitekey': Config.captchaSiteKey,
484        'theme': 'light',
485        'size': Config.isMobile ? 'compact' : 'normal',
486        'callback': onCaptchaSolved
487      });
488    }
489  }
490
491  function onCaptchaSolved() {
492    // Read from THIS widget (DEV-13809 QA Minor 4): pages can host multiple reCAPTCHA widgets
493    // (comments), so a hardcoded #g-recaptcha-response may pick another widget's token.
494    const token = grecaptcha.getResponse(captchaWidgetElement);
495
496    if (captchaMode === 'signup') {
497      doSignIn(true, token);
498      return;
499    }
500
501    // reactive 429.0107 — clear the rate limit, then retry whichever endpoint hit it.
502    $.post('/web/rest/api/reCaptcha',
503        {
504          limitKey: Utils.parseResponseText(captchaResponseText, 'limitKey'),
505          response: token
506        },
507        function (data) {
508          if (data && data.valid) {
509            window.hideAllBottomSheets();
510            doSignIn(captchaRetryRegistration);
511          }
512        }
513    );
514  }
515
516  // Proactive mandatory captcha shown before the account is created. errorMsg (optional) surfaces a
517  // server rejection (ERROR_INVALID_CAPTCHA) instead of a silent re-render (DEV-13809 QA Major 3).
518  function showSignupCaptcha(errorMsg) {
519    captchaMode = 'signup';
520    renderOrResetCaptcha();
521    if (errorMsg) $('.jsCaptchaError', signInBS).text(errorMsg).show();
522  }
523
524  // Reactive captcha shown when the backend returns 429.0107 (rate limit).
525  function showCaptchaScreen(responseText, msg1, msg2, newRegistration) {
526    captchaMode = 'reactive';
527    captchaResponseText = responseText;
528    captchaRetryRegistration = newRegistration;
529    renderOrResetCaptcha();
530  }
531
532  $('.jsResendVerification').click(function () {
533    const self = $(this);
534
535    $.ajax({
536      type: 'get',
537      dataType: 'jsonp',
538      url: '/account/sendEmailVerification.jsp',
539      success: function (data) {
540        if (data.ok) {
541          self.hide();
542          signInBS.find('.jsConfirmationResent').show();
543        } else {
544          signInBS.find('.jsSendingError').text(data.errorMessage);
545        }
546      }
547    });
548  });
549
550
551
552
553
554
555
556
557
558  // --------------------- sign-in analytics ---------------------
559
560  function trackAnalyticsEventClicks(eventName, action) {
561    gtag('event', eventName, {
562      'action': action,
563      'source': `${eventName.toLowerCase()}_${analyticsPageName}
563_${signInInitiatorName}`,
564    });
565  }
566
567  function trackAnalyticsEventLogins(eventName, action) {
568    gtag('event', eventName, {
569      'login': action,
570      'source': `${eventName.toLowerCase()}_${analyticsPageName}_${signInInitiatorName}`,
571    });
572  }
573
574  function trackAnalyticsContinueClickEvent(screenNumber) {
575    let eventName = '';
576
577    switch (screenNumber) {
578      case '2':
579        eventName = 'login_popup_email_continue'
580        break;
581      case '3':
582        eventName = 'login_popup_name_view_continue'
583        break;
584      case '4':
585        eventName = 'login_popup_password_continue'
586        break;
587      case '5':
588        eventName = 'login_popup_policy_continue'
589        break;
590    }
591
592    if (eventName !== '') {
593      trackAnalyticsEventClicks('Login_Popup', eventName);
594    }
595  }
596
597  const facebookLoginFlag = localStorage.getItem('facebook-login-in-process');
598  const googleLoginFlag = localStorage.getItem('google-login-in-process');
599  const emailLoginFlag = localStorage.getItem('email-login-in-process');
600
601  if (emailLoginFlag || googleLoginFlag || facebookLoginFlag) {
602    signInInitiatorName = localStorage.getItem('post-login-signin-initiator-element');
603
604    const eventName = googleLoginFlag ? 'google' : (facebookLoginFlag ? 'facebook' : emailLoginFlag);
605
606    trackAnalyticsEventLogins('Login', eventName);
607
608    localStorage.removeItem('email-login-in-process')
609    localStorage.removeItem('facebook-login-in-process')
610    localStorage.removeItem('google-login-in-process');
611    localStorage.removeItem('post-login-signin-initiator-element');
612  }
613})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.