mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Large refactor of accounts-ui
- Split login_buttons.html and login_buttons.js into multiple files - Specifically, make it easier to reason about the display of loginButtons whether it is in dropdown mode or not - Split templates into subtemplates to make it easier to read the login button .html files as "tables of contents" - Introduce Meteor._loginButtonsSession, which makes it easier to access internal session fields for loginButtons - Unify code that calls the various Meteor.loginWithFoo() functions Breaking change: rename "configureLoginServicesDialogForFoo" to "configureLoginServiceDialogForFoo" (in packages such as accounts-facebook)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<template name="configureLoginServicesDialogForFacebook">
|
||||
<template name="configureLoginServiceDialogForFacebook">
|
||||
<p>
|
||||
First, you'll need to register your app on Facebook. Follow these steps:
|
||||
</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Template.configureLoginServicesDialogForFacebook.siteUrl = function () {
|
||||
Template.configureLoginServiceDialogForFacebook.siteUrl = function () {
|
||||
return Meteor.absoluteUrl();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialogForFacebook.fields = function () {
|
||||
Template.configureLoginServiceDialogForFacebook.fields = function () {
|
||||
return [
|
||||
{property: 'appId', label: 'App ID'},
|
||||
{property: 'secret', label: 'App Secret'}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template name="configureLoginServicesDialogForGithub">
|
||||
<template name="configureLoginServiceDialogForGithub">
|
||||
<p>
|
||||
First, you'll need to get a Github Client ID. Follow these steps:
|
||||
</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Template.configureLoginServicesDialogForGithub.siteUrl = function () {
|
||||
Template.configureLoginServiceDialogForGithub.siteUrl = function () {
|
||||
return Meteor.absoluteUrl();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialogForGithub.fields = function () {
|
||||
Template.configureLoginServiceDialogForGithub.fields = function () {
|
||||
return [
|
||||
{property: 'clientId', label: 'Client ID'},
|
||||
{property: 'secret', label: 'Client Secret'}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template name="configureLoginServicesDialogForGoogle">
|
||||
<template name="configureLoginServiceDialogForGoogle">
|
||||
<p>
|
||||
First, you'll need to get a Google Client ID. Follow these steps:
|
||||
</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Template.configureLoginServicesDialogForGoogle.siteUrl = function () {
|
||||
Template.configureLoginServiceDialogForGoogle.siteUrl = function () {
|
||||
return Meteor.absoluteUrl();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialogForGoogle.fields = function () {
|
||||
Template.configureLoginServiceDialogForGoogle.fields = function () {
|
||||
return [
|
||||
{property: 'clientId', label: 'Client ID'},
|
||||
{property: 'secret', label: 'Client secret'}
|
||||
|
||||
@@ -156,6 +156,7 @@
|
||||
if (error || !result) {
|
||||
error = error || new Error("No result from call to resetPassword");
|
||||
callback && callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
Accounts._makeClientLoggedIn(result.id, result.token);
|
||||
@@ -178,6 +179,7 @@
|
||||
if (error || !result) {
|
||||
error = error || new Error("No result from call to validateUser");
|
||||
callback && callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
Accounts._makeClientLoggedIn(result.id, result.token);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template name="configureLoginServicesDialogForTwitter">
|
||||
<template name="configureLoginServiceDialogForTwitter">
|
||||
<p>
|
||||
First, you'll need to register your app on Twitter. Follow these steps:
|
||||
</p>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Template.configureLoginServicesDialogForTwitter.siteUrl = function () {
|
||||
Template.configureLoginServiceDialogForTwitter.siteUrl = function () {
|
||||
// Twitter doesn't recognize localhost as a domain name
|
||||
return Meteor.absoluteUrl({replaceLocalhost: true});
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialogForTwitter.fields = function () {
|
||||
Template.configureLoginServiceDialogForTwitter.fields = function () {
|
||||
return [
|
||||
{property: 'consumerKey', label: 'Consumer key'},
|
||||
{property: 'secret', label: 'Consumer secret'}
|
||||
|
||||
@@ -1,294 +1,50 @@
|
||||
<template name="loginButtons">
|
||||
<div id="login-buttons">
|
||||
{{#if currentUser}}
|
||||
{{#if dropdown}}
|
||||
{{> loginButtonsLoggedInDropdown}}
|
||||
{{else}}
|
||||
{{> loginButtonsLoggedInRow}}
|
||||
{{/if}}
|
||||
{{> loginButtonsLoggedIn}}
|
||||
{{else}}
|
||||
{{#if services}}
|
||||
{{#if configurationLoaded}}
|
||||
{{#if dropdown}}
|
||||
{{> loginButtonsServicesDropdown}}
|
||||
{{else}}
|
||||
{{> loginButtonsServicesRow}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="no-services">No login services configured</div>
|
||||
{{/if}}
|
||||
{{> loginButtonsLoggedOut}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsLoggedInDropdown">
|
||||
<div class="login-link-and-dropdown-list">
|
||||
{{#if currentUser.loading}}
|
||||
<div class="loading"></div>
|
||||
{{else}}
|
||||
<a class="login-link-text" id="login-name-link">
|
||||
{{displayName}} ▾
|
||||
</a>
|
||||
{{#if dropdownVisible}}
|
||||
<div id="login-dropdown-list" class="accounts-dialog">
|
||||
<a class="login-close-text">Close</a>
|
||||
<div class="login-close-text-clear"></div>
|
||||
|
||||
{{#if inChangePasswordFlow}}
|
||||
{{> loginButtonsChangePassword}}
|
||||
<template name="loginButtonsLoggedIn">
|
||||
{{#if dropdown}}
|
||||
{{> loginButtonsLoggedInDropdown}}
|
||||
{{else}}
|
||||
<div class="login-header">
|
||||
{{#if currentUser.loading}} {{! XXX this will change }}
|
||||
<div class="loading"></div>
|
||||
{{else}}
|
||||
{{#if allowChangingPassword}}
|
||||
<div class="login-button" id="login-buttons-open-change-password">Change password</div>
|
||||
{{/if}}
|
||||
<div class="login-button" id="login-buttons-logout">Logout</div>
|
||||
{{displayName}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="login-button" id="login-buttons-logout">Logout</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsLoggedInRow">
|
||||
<div class="login-header">
|
||||
{{#if currentUser.loading}}
|
||||
<div class="loading"></div>
|
||||
{{else}}
|
||||
{{displayName}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="login-button" id="login-buttons-logout">Logout</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsServicesRow">
|
||||
{{#each services}}
|
||||
{{#if isPasswordService}}
|
||||
{{#if hasOtherServices}}
|
||||
<div class="or">
|
||||
<span class="hline"> </span>
|
||||
<span class="or-text">or</span>
|
||||
<span class="hline"> </span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if inForgotPasswordFlow}}
|
||||
{{> forgotPasswordForm}}
|
||||
<template name="loginButtonsLoggedOut">
|
||||
{{#if services}} {{! if at least one service is configured }}
|
||||
{{#if configurationLoaded}}
|
||||
{{#if dropdown}} {{! if more than one service configured, or password is configured}}
|
||||
{{> loginButtonsLoggedOutDropdown}}
|
||||
{{else}}
|
||||
<div class="login-form login-password-form">
|
||||
{{#each fields}}
|
||||
{{> loginButtonsFormField}}
|
||||
{{/each}}
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-password">
|
||||
{{#if inSignupFlow}}
|
||||
Create account
|
||||
{{else}}
|
||||
Sign in
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if inLoginFlow}}
|
||||
<div class="additional-link-container">
|
||||
<a id="signup-link" class="additional-link">Create account</a>
|
||||
</div>
|
||||
|
||||
{{#if showForgotPasswordLink}}
|
||||
<div class="additional-link-container">
|
||||
<a id="forgot-password-link" class="additional-link">Forgot password</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if configured}}
|
||||
<div class="login-button" id="login-buttons-{{name}}">
|
||||
<div class="login-image" id="login-buttons-image-{{name}}"></div>
|
||||
Sign in with {{capitalizedName}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="login-button configure-button" id="login-buttons-{{name}}">
|
||||
<div class="login-image" id="login-buttons-image-{{name}}"></div>
|
||||
Configure {{capitalizedName}} Login
|
||||
</div>
|
||||
{{#with singleService}} {{! at this point there must be only one configured services }}
|
||||
{{> loginButtonsLoggedOutSingleLoginButton}}
|
||||
{{/with}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsFormField">
|
||||
<label id="login-{{fieldName}}-label" for="login-{{fieldName}}">
|
||||
{{fieldLabel}}
|
||||
</label>
|
||||
<input id="login-{{fieldName}}" type="{{inputType}}" />
|
||||
{{else}}
|
||||
<div class="no-services">No login services configured</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<!-- used in various places to display messages to user -->
|
||||
<template name="loginButtonsMessages">
|
||||
{{#if errorMessage}}
|
||||
<div class="message error-message">{{errorMessage}}</div>
|
||||
<div class="message error-message">{{errorMessage}}</div>
|
||||
{{/if}}
|
||||
{{#if infoMessage}}
|
||||
<div class="message info-message">{{infoMessage}}</div>
|
||||
<div class="message info-message">{{infoMessage}}</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsServicesDropdown">
|
||||
<div class="login-link-and-dropdown-list">
|
||||
<a class="login-link-text" id="login-sign-in-link">Sign in ▾</a>
|
||||
{{#if dropdownVisible}}
|
||||
<div id="login-dropdown-list" class="accounts-dialog">
|
||||
<a class="login-close-text">Close</a>
|
||||
<div class="login-close-text-clear"></div>
|
||||
{{> loginButtonsServicesRow}}
|
||||
|
||||
{{#unless hasPasswordService}}
|
||||
{{> loginButtonsMessages}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="forgotPasswordForm">
|
||||
<div class="login-form">
|
||||
<label id="forgot-password-email-label" for="forgot-password-email">Email</label>
|
||||
<input id="forgot-password-email"/>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-forgot-password">
|
||||
Reset password
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsChangePassword">
|
||||
{{#each fields}}
|
||||
{{> loginButtonsFormField}}
|
||||
{{/each}}
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-do-change-password">
|
||||
Change password
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="resetPasswordForm">
|
||||
{{#if inResetPasswordFlow}}
|
||||
<div class="hide-background"></div>
|
||||
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
<label id="reset-password-new-password-label" for="reset-password-new-password">
|
||||
New password
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<input id="reset-password-new-password" type="password" />
|
||||
</div>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-reset-password-button">
|
||||
Reset password
|
||||
</div>
|
||||
|
||||
<a class="additional-link" id="login-buttons-cancel-reset-password">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="enrollAccountForm">
|
||||
{{#if inEnrollAccountFlow}}
|
||||
<div class="hide-background"></div>
|
||||
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
<label id="enroll-account-password-label" for="enroll-account-password">
|
||||
Choose a password
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<input id="enroll-account-password" type="password" />
|
||||
</div>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-enroll-account-button">
|
||||
Create account
|
||||
</div>
|
||||
|
||||
<a class="additional-link" id="login-buttons-cancel-enroll-account">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="justValidatedUserForm">
|
||||
{{#if visible}}
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
Email validated
|
||||
<div class="login-button" id="just-validated-dismiss-button">Dismiss</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<!-- if we're not showing a dropdown, we need some other place to show messages -->
|
||||
<template name="loginButtonsMessagesDialog">
|
||||
{{#if visible}}
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
{{> loginButtonsMessages}}
|
||||
<div class="login-button" id="messages-dialog-dismiss-button">Dismiss</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="configureLoginServicesDialog">
|
||||
{{#if visible}}
|
||||
<div id="configure-login-services-dialog" class="accounts-dialog accounts-centered-dialog">
|
||||
{{{configurationSteps}}}
|
||||
|
||||
<p>
|
||||
Now, copy over some details.
|
||||
</p>
|
||||
<p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" class="configuration_labels">
|
||||
<col span="1" class="configuration_inputs">
|
||||
</colgroup>
|
||||
{{#each configurationFields}}
|
||||
<tr>
|
||||
<td>
|
||||
<label for="configure-login-services-dialog-{{property}}">{{label}}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="configure-login-services-dialog-{{property}}" />
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
</p>
|
||||
<div class="new-section">
|
||||
<div class="login-button" id="configure-login-services-dismiss-button">I'll do this later</div>
|
||||
{{#isolate}}
|
||||
<div class="login-button login-button-configure {{#if saveDisabled}}login-button-disabled{{/if}}"
|
||||
id="configure-login-services-dialog-save-configuration">
|
||||
Save Configuration
|
||||
</div>
|
||||
{{/isolate}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<body>
|
||||
{{> resetPasswordForm}}
|
||||
{{> enrollAccountForm}}
|
||||
{{> justValidatedUserForm}}
|
||||
{{> loginButtonsMessagesDialog}}
|
||||
{{> configureLoginServicesDialog}}
|
||||
</body>
|
||||
|
||||
@@ -1,324 +1,59 @@
|
||||
(function () {
|
||||
//
|
||||
// Session
|
||||
//
|
||||
if (!Accounts._loginButtons)
|
||||
Accounts._loginButtons = {};
|
||||
|
||||
var DROPDOWN_VISIBLE_KEY = 'Meteor.loginButtons.dropdownVisible';
|
||||
|
||||
// XXX consider replacing these with one key that has an enum for values.
|
||||
var IN_SIGNUP_FLOW_KEY = 'Meteor.loginButtons.inSignupFlow';
|
||||
var IN_FORGOT_PASSWORD_FLOW_KEY = 'Meteor.loginButtons.inForgotPasswordFlow';
|
||||
var IN_CHANGE_PASSWORD_FLOW_KEY = 'Meteor.loginButtons.inChangePasswordFlow';
|
||||
|
||||
var ERROR_MESSAGE_KEY = 'Meteor.loginButtons.errorMessage';
|
||||
var INFO_MESSAGE_KEY = 'Meteor.loginButtons.infoMessage';
|
||||
var SHOW_MESSAGES_DIALOG_KEY = 'Meteor.loginButtons.showMessagesDialog';
|
||||
|
||||
var RESET_PASSWORD_TOKEN_KEY = 'Meteor.loginButtons.resetPasswordToken';
|
||||
var ENROLL_ACCOUNT_TOKEN_KEY = 'Meteor.loginButtons.enrollAccountToken';
|
||||
var JUST_VALIDATED_USER_KEY = 'Meteor.loginButtons.justValidatedUser';
|
||||
var CONFIGURE_LOGIN_SERVICES_DIALOG_VISIBLE = 'Meteor.loginButtons.configureLoginServicesDialogVisible';
|
||||
var CONFIGURE_LOGIN_SERVICES_DIALOG_SERVICE_NAME = "Meteor.loginButtons.configureLoginServicesDialogServiceName";
|
||||
var CONFIGURE_LOGIN_SERVICES_DIALOG_SAVE_ENABLED = "Meteor.loginButtons.saveEnabled";
|
||||
|
||||
|
||||
var resetSession = function () {
|
||||
Session.set(IN_SIGNUP_FLOW_KEY, false);
|
||||
Session.set(IN_FORGOT_PASSWORD_FLOW_KEY, false);
|
||||
Session.set(IN_CHANGE_PASSWORD_FLOW_KEY, false);
|
||||
Session.set(DROPDOWN_VISIBLE_KEY, false);
|
||||
resetMessages();
|
||||
};
|
||||
|
||||
var resetMessages = function () {
|
||||
Session.set(ERROR_MESSAGE_KEY, null);
|
||||
Session.set(INFO_MESSAGE_KEY, null);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtons template
|
||||
//
|
||||
|
||||
configureService = function(name) {
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_VISIBLE, true);
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_SERVICE_NAME, name);
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_SAVE_ENABLED, false);
|
||||
};
|
||||
|
||||
Template.loginButtons.events = {
|
||||
'click #login-buttons-facebook': function () {
|
||||
resetMessages();
|
||||
Meteor.loginWithFacebook(makeLoginCallback('facebook'));
|
||||
},
|
||||
|
||||
'click #login-buttons-google': function () {
|
||||
resetMessages();
|
||||
Meteor.loginWithGoogle(makeLoginCallback('google'));
|
||||
},
|
||||
|
||||
'click #login-buttons-github': function () {
|
||||
resetMessages();
|
||||
Meteor.loginWithGithub(makeLoginCallback('github'))
|
||||
},
|
||||
|
||||
'click #login-buttons-weibo': function () {
|
||||
resetMessages();
|
||||
Meteor.loginWithWeibo(makeLoginCallback('weibo'));
|
||||
},
|
||||
|
||||
'click #login-buttons-twitter': function () {
|
||||
resetMessages();
|
||||
Meteor.loginWithTwitter(makeLoginCallback('twitter'));
|
||||
},
|
||||
|
||||
'click #login-name-link': function () {
|
||||
Session.set(DROPDOWN_VISIBLE_KEY, true);
|
||||
Meteor.flush();
|
||||
correctDropdownZIndexes();
|
||||
},
|
||||
|
||||
'click .login-close-text': function () {
|
||||
resetSession();
|
||||
},
|
||||
|
||||
'click #login-buttons-open-change-password': function() {
|
||||
resetMessages();
|
||||
Session.set(IN_CHANGE_PASSWORD_FLOW_KEY, true);
|
||||
},
|
||||
// for convenience
|
||||
var loginButtonsSession = Accounts._loginButtonsSession;
|
||||
|
||||
// shared between dropdown and single mode
|
||||
Template.loginButtons.events({
|
||||
'click #login-buttons-logout': function() {
|
||||
Meteor.logout(resetSession);
|
||||
Meteor.logout(function () {
|
||||
loginButtonsSession.closeDropdown();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// loginButtonLoggedOut template
|
||||
//
|
||||
|
||||
Template.loginButtonsLoggedOut.dropdown = function () {
|
||||
return Accounts._loginButtons.dropdown();
|
||||
};
|
||||
|
||||
var makeLoginCallback = function(service) {
|
||||
return function (err) {
|
||||
if (!err) {
|
||||
resetSession();
|
||||
} else if (err instanceof Accounts.LoginCancelledError) {
|
||||
// do nothing
|
||||
} else if (err instanceof Accounts.ConfigError) {
|
||||
configureService(service);
|
||||
} else {
|
||||
Session.set(ERROR_MESSAGE_KEY, err.reason || "Unknown error");
|
||||
}
|
||||
};
|
||||
Template.loginButtonsLoggedOut.services = function () {
|
||||
return Accounts._loginButtons.getLoginServices();
|
||||
};
|
||||
|
||||
// decide whether we should show a dropdown rather than a row of
|
||||
// buttons
|
||||
Template.loginButtons.dropdown = function () {
|
||||
return dropdown();
|
||||
Template.loginButtonsLoggedOut.singleService = function () {
|
||||
var services = Accounts._loginButtons.getLoginServices();
|
||||
if (services.length !== 1)
|
||||
throw new Error(
|
||||
"Shouldn't be rendering this template with more than one configured service");
|
||||
return services[0];
|
||||
};
|
||||
|
||||
Template.loginButtons.services = function () {
|
||||
return getLoginServices();
|
||||
};
|
||||
|
||||
Template.loginButtons.configurationLoaded = function () {
|
||||
Template.loginButtonsLoggedOut.configurationLoaded = function () {
|
||||
return Accounts.loginServicesConfigured();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsLoggedInRow template
|
||||
//
|
||||
Template.loginButtonsLoggedInRow.displayName = function () {
|
||||
return displayName();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsLoggedInDropdown template
|
||||
// loginButtonsLoggedIn template
|
||||
//
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.displayName = function () {
|
||||
return displayName();
|
||||
// decide whether we should show a dropdown rather than a row of
|
||||
// buttons
|
||||
Template.loginButtonsLoggedIn.dropdown = function () {
|
||||
return Accounts._loginButtons.dropdown();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.inChangePasswordFlow = function () {
|
||||
return Session.get(IN_CHANGE_PASSWORD_FLOW_KEY);
|
||||
Template.loginButtonsLoggedIn.displayName = function () {
|
||||
return Accounts._loginButtons.displayName();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.dropdownVisible = function () {
|
||||
return Session.get(DROPDOWN_VISIBLE_KEY);
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.allowChangingPassword = function () {
|
||||
// it would be more correct to check whether the user has a password set,
|
||||
// but in order to do that we'd have to send more data down to the client,
|
||||
// and it'd be preferable not to send down the entire service.password document.
|
||||
//
|
||||
// instead we use the heuristic: if the user has a username or email set.
|
||||
var user = Meteor.user();
|
||||
return user.username || (user.emails && user.emails[0] && user.emails[0].address);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsServiceRow template
|
||||
//
|
||||
|
||||
Template.loginButtonsServicesRow.events = {
|
||||
'click #login-buttons-password': function () {
|
||||
loginOrSignup();
|
||||
},
|
||||
'click #signup-link': function () {
|
||||
resetMessages();
|
||||
|
||||
// store values of fields before swtiching to the signup form
|
||||
var username = elementValueById('login-username');
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
var password = elementValueById('login-password');
|
||||
|
||||
Session.set(IN_SIGNUP_FLOW_KEY, true);
|
||||
Session.set(IN_FORGOT_PASSWORD_FLOW_KEY, false);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (username !== null)
|
||||
document.getElementById('login-username').value = username;
|
||||
else if (email !== null)
|
||||
document.getElementById('login-email').value = email;
|
||||
else if (usernameOrEmail !== null)
|
||||
if (usernameOrEmail.indexOf('@') === -1)
|
||||
document.getElementById('login-username').value = usernameOrEmail;
|
||||
else
|
||||
document.getElementById('login-email').value = usernameOrEmail;
|
||||
|
||||
document.getElementById('login-password').value = password;
|
||||
|
||||
// Forge redrawing the `login-dropdown-list` element because of
|
||||
// a bizarre Chrome bug in which part of the DIV is not redrawn
|
||||
// in case you had tried to unsuccessfully log in before
|
||||
// switching to the signup form.
|
||||
//
|
||||
// Found tip on how to force a redraw on
|
||||
// http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes/3485654#3485654
|
||||
var redraw = document.getElementById('login-dropdown-list');
|
||||
redraw.style.display = 'none';
|
||||
redraw.offsetHeight; // it seems that this line does nothing but is necessary for the redraw to work
|
||||
redraw.style.display = 'block';
|
||||
},
|
||||
'click #forgot-password-link': function () {
|
||||
resetMessages();
|
||||
|
||||
// store values of fields before swtiching to the signup form
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
|
||||
Session.set(IN_SIGNUP_FLOW_KEY, false);
|
||||
Session.set(IN_FORGOT_PASSWORD_FLOW_KEY, true);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (email !== null)
|
||||
document.getElementById('forgot-password-email').value = email;
|
||||
else if (usernameOrEmail !== null)
|
||||
if (usernameOrEmail.indexOf('@') !== -1)
|
||||
document.getElementById('forgot-password-email').value = usernameOrEmail;
|
||||
|
||||
},
|
||||
'keypress #login-username, keypress #login-email, keypress #login-username-or-email, keypress #login-password, keypress #login-password-again': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
loginOrSignup();
|
||||
}
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.fields = function () {
|
||||
var loginFields = [
|
||||
{fieldName: 'username-or-email', fieldLabel: 'Username or Email',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'username', fieldLabel: 'Username',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& !Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'email', fieldLabel: 'Email',
|
||||
visible: function () {
|
||||
return !Accounts._options.requireUsername;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}}
|
||||
];
|
||||
|
||||
var signupFields = [
|
||||
{fieldName: 'username', fieldLabel: 'Username',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername;
|
||||
}},
|
||||
{fieldName: 'email', fieldLabel: 'Email',
|
||||
visible: function () {
|
||||
return !Accounts._options.requireUsername
|
||||
|| Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password-again', fieldLabel: 'Password (again)',
|
||||
inputType: 'password',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& !Accounts._options.requireEmail;
|
||||
}}
|
||||
];
|
||||
|
||||
var fields = Session.get(IN_SIGNUP_FLOW_KEY) ? signupFields : loginFields;
|
||||
return _.filter(fields, function(info) {
|
||||
return info.visible();
|
||||
});
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.services = function () {
|
||||
return getLoginServices();
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.isPasswordService = function () {
|
||||
return this.name === 'password';
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.hasOtherServices = function () {
|
||||
return getLoginServices().length > 1;
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.hasPasswordService = function () {
|
||||
return hasPasswordService();
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.inForgotPasswordFlow = function () {
|
||||
return Session.get(IN_FORGOT_PASSWORD_FLOW_KEY);
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.inLoginFlow = function () {
|
||||
return !Session.get(IN_SIGNUP_FLOW_KEY) && !Session.get(IN_FORGOT_PASSWORD_FLOW_KEY);
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.inSignupFlow = function () {
|
||||
return Session.get(IN_SIGNUP_FLOW_KEY);
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.showForgotPasswordLink = function () {
|
||||
return Accounts._options.requireEmail
|
||||
|| !Accounts._options.requireUsername;
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.configured = function () {
|
||||
return !!Accounts.configuration.findOne({service: this.name.toLowerCase()});
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesRow.capitalizedName = function () {
|
||||
return capitalize(this.name);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
@@ -326,328 +61,19 @@
|
||||
//
|
||||
|
||||
Template.loginButtonsMessages.errorMessage = function () {
|
||||
return Session.get(ERROR_MESSAGE_KEY);
|
||||
return loginButtonsSession.get('errorMessage');
|
||||
};
|
||||
|
||||
Template.loginButtonsMessages.infoMessage = function () {
|
||||
return Session.get(INFO_MESSAGE_KEY);
|
||||
return loginButtonsSession.get('infoMessage');
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// forgotPasswordForm template
|
||||
//
|
||||
Template.forgotPasswordForm.events = {
|
||||
'keypress #forgot-password-email': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
forgotPassword();
|
||||
},
|
||||
'click #login-buttons-forgot-password': function () {
|
||||
forgotPassword();
|
||||
}
|
||||
};
|
||||
|
||||
var forgotPassword = function () {
|
||||
resetMessages();
|
||||
|
||||
var email = document.getElementById("forgot-password-email").value;
|
||||
if (email.indexOf('@') !== -1) {
|
||||
Accounts.forgotPassword({email: email}, function (error) {
|
||||
if (error)
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
else
|
||||
Session.set(INFO_MESSAGE_KEY, "Email sent");
|
||||
});
|
||||
} else {
|
||||
Session.set(ERROR_MESSAGE_KEY, "Invalid email");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsServicesDropdown template
|
||||
//
|
||||
|
||||
Template.loginButtonsServicesDropdown.events = {
|
||||
'click #login-sign-in-link': function () {
|
||||
Session.set(DROPDOWN_VISIBLE_KEY, true);
|
||||
Meteor.flush();
|
||||
correctDropdownZIndexes();
|
||||
},
|
||||
'click .login-close-text': function () {
|
||||
resetSession();
|
||||
}
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesDropdown.dropdownVisible = function () {
|
||||
return Session.get(DROPDOWN_VISIBLE_KEY);
|
||||
};
|
||||
|
||||
Template.loginButtonsServicesDropdown.hasPasswordService = function () {
|
||||
return hasPasswordService();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// resetPasswordForm template
|
||||
//
|
||||
|
||||
Template.resetPasswordForm.events = {
|
||||
'click #login-buttons-reset-password-button': function () {
|
||||
resetPassword();
|
||||
},
|
||||
'keypress #reset-password-new-password': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
resetPassword();
|
||||
},
|
||||
'click #login-buttons-cancel-reset-password': function () {
|
||||
Session.set(RESET_PASSWORD_TOKEN_KEY, null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
};
|
||||
|
||||
var resetPassword = function () {
|
||||
resetMessages();
|
||||
var newPassword = document.getElementById('reset-password-new-password').value;
|
||||
if (!validatePassword(newPassword))
|
||||
return;
|
||||
|
||||
Accounts.resetPassword(
|
||||
Session.get(RESET_PASSWORD_TOKEN_KEY), newPassword,
|
||||
function (error) {
|
||||
if (error) {
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
} else {
|
||||
Session.set(RESET_PASSWORD_TOKEN_KEY, null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Template.resetPasswordForm.inResetPasswordFlow = function () {
|
||||
return Session.get(RESET_PASSWORD_TOKEN_KEY);
|
||||
};
|
||||
|
||||
if (Accounts._resetPasswordToken) {
|
||||
Session.set(RESET_PASSWORD_TOKEN_KEY, Accounts._resetPasswordToken);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// enrollAccountForm template
|
||||
//
|
||||
|
||||
Template.enrollAccountForm.events = {
|
||||
'click #login-buttons-enroll-account-button': function () {
|
||||
enrollAccount();
|
||||
},
|
||||
'keypress #enroll-account-password': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
enrollAccount();
|
||||
},
|
||||
'click #login-buttons-cancel-enroll-account': function () {
|
||||
Session.set(ENROLL_ACCOUNT_TOKEN_KEY, null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
};
|
||||
|
||||
var enrollAccount = function () {
|
||||
resetMessages();
|
||||
var password = document.getElementById('enroll-account-password').value;
|
||||
if (!validatePassword(password))
|
||||
return;
|
||||
|
||||
Accounts.resetPassword(
|
||||
Session.get(ENROLL_ACCOUNT_TOKEN_KEY), password,
|
||||
function (error) {
|
||||
if (error) {
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
} else {
|
||||
Session.set(ENROLL_ACCOUNT_TOKEN_KEY, null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Template.enrollAccountForm.inEnrollAccountFlow = function () {
|
||||
return Session.get(ENROLL_ACCOUNT_TOKEN_KEY);
|
||||
};
|
||||
|
||||
if (Accounts._enrollAccountToken) {
|
||||
Session.set(ENROLL_ACCOUNT_TOKEN_KEY, Accounts._enrollAccountToken);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// justValidatedUserForm template
|
||||
//
|
||||
|
||||
Template.justValidatedUserForm.events = {
|
||||
'click #just-validated-dismiss-button': function () {
|
||||
Session.set(JUST_VALIDATED_USER_KEY, false);
|
||||
}
|
||||
};
|
||||
|
||||
Template.justValidatedUserForm.visible = function () {
|
||||
return Session.get(JUST_VALIDATED_USER_KEY);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsMessagesDialog template
|
||||
//
|
||||
|
||||
Template.loginButtonsMessagesDialog.events({
|
||||
'click #messages-dialog-dismiss-button': function () {
|
||||
resetMessages();
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsMessagesDialog.visible = function () {
|
||||
var hasMessage = Session.get(INFO_MESSAGE_KEY) || Session.get(ERROR_MESSAGE_KEY);
|
||||
return !dropdown() && hasMessage;
|
||||
};
|
||||
|
||||
// Needs to be in Meteor.startup because of a package loading order
|
||||
// issue. We can't be sure that accounts-password is loaded earlier
|
||||
// than accounts-ui so Accounts.validateEmail might not be defined.
|
||||
Meteor.startup(function () {
|
||||
if (Accounts._validateEmailToken) {
|
||||
Accounts.validateEmail(Accounts._validateEmailToken, function(error) {
|
||||
Accounts._enableAutoLogin();
|
||||
if (!error)
|
||||
Session.set(JUST_VALIDATED_USER_KEY, true);
|
||||
// XXX show something if there was an error.
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// loginButtonsChangePassword template
|
||||
//
|
||||
|
||||
Template.loginButtonsChangePassword.events({
|
||||
'keypress #login-old-password, keypress #login-password, keypress #login-password-again': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
changePassword();
|
||||
},
|
||||
'click #login-buttons-do-change-password': function () {
|
||||
changePassword();
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsChangePassword.fields = function () {
|
||||
return [
|
||||
{fieldName: 'old-password', fieldLabel: 'Current Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'New Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password-again', fieldLabel: 'New Password (again)',
|
||||
inputType: 'password',
|
||||
visible: function () {
|
||||
return Meteor.accounts._options.requireUsername
|
||||
&& !Meteor.accounts._options.requireEmail;
|
||||
}}
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// configureLoginServicesDialog template
|
||||
//
|
||||
|
||||
Template.configureLoginServicesDialog.events({
|
||||
'click #configure-login-services-dismiss-button': function () {
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_VISIBLE, false);
|
||||
},
|
||||
'click #configure-login-services-dialog-save-configuration': function () {
|
||||
if (Session.get(CONFIGURE_LOGIN_SERVICES_DIALOG_SAVE_ENABLED)) {
|
||||
// Prepare the configuration document for this login service
|
||||
var serviceName = Session.get(CONFIGURE_LOGIN_SERVICES_DIALOG_SERVICE_NAME);
|
||||
var configuration = {
|
||||
service: serviceName
|
||||
};
|
||||
_.each(configurationFields(), function(field) {
|
||||
configuration[field.property] = document.getElementById(
|
||||
'configure-login-services-dialog-' + field.property).value;
|
||||
});
|
||||
|
||||
// Configure this login service
|
||||
Meteor.call("configureLoginService", configuration, function (error, result) {
|
||||
if (error)
|
||||
Meteor._debug("Error configurating login service " + serviceName, error);
|
||||
else
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_VISIBLE, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.configureLoginServicesDialog.events({
|
||||
'input': function (event) {
|
||||
// if the event fired on one of the configuration input fields,
|
||||
// check whether we should enable the 'save configuration' button
|
||||
if (event.target.id.indexOf('configure-login-services-dialog') === 0)
|
||||
updateSaveDisabled();
|
||||
}
|
||||
});
|
||||
|
||||
// check whether the 'save configuration' button should be enabled.
|
||||
// this is a really strange way to implement this and a Forms
|
||||
// Abstraction would make all of this reactive, and simpler.
|
||||
var updateSaveDisabled = function () {
|
||||
var saveEnabled = true;
|
||||
_.any(configurationFields(), function(field) {
|
||||
if (document.getElementById(
|
||||
'configure-login-services-dialog-' + field.property).value === '') {
|
||||
saveEnabled = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Session.set(CONFIGURE_LOGIN_SERVICES_DIALOG_SAVE_ENABLED, saveEnabled);
|
||||
};
|
||||
|
||||
// Returns the appropriate template for this login service. This
|
||||
// template should be defined in the service's package
|
||||
var configureLoginServicesDialogTemplateForService = function () {
|
||||
var serviceName = Session.get(CONFIGURE_LOGIN_SERVICES_DIALOG_SERVICE_NAME);
|
||||
return Template['configureLoginServicesDialogFor' + capitalize(serviceName)];
|
||||
};
|
||||
|
||||
var configurationFields = function () {
|
||||
var template = configureLoginServicesDialogTemplateForService();
|
||||
return template.fields();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialog.configurationFields = function () {
|
||||
return configurationFields();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialog.visible = function () {
|
||||
return Session.get(CONFIGURE_LOGIN_SERVICES_DIALOG_VISIBLE);
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialog.configurationSteps = function () {
|
||||
// renders the appropriate template
|
||||
return configureLoginServicesDialogTemplateForService()();
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialog.saveDisabled = function () {
|
||||
return !Session.get(CONFIGURE_LOGIN_SERVICES_DIALOG_SAVE_ENABLED);
|
||||
};
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
|
||||
var displayName = function () {
|
||||
Accounts._loginButtons.displayName = function () {
|
||||
var user = Meteor.user();
|
||||
if (!user)
|
||||
return '';
|
||||
@@ -662,141 +88,7 @@
|
||||
return '';
|
||||
};
|
||||
|
||||
var elementValueById = function(id) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element)
|
||||
return null;
|
||||
else
|
||||
return element.value;
|
||||
};
|
||||
|
||||
var login = function () {
|
||||
resetMessages();
|
||||
|
||||
var username = elementValueById('login-username');
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
var password = elementValueById('login-password');
|
||||
|
||||
var loginSelector;
|
||||
if (username !== null)
|
||||
loginSelector = {username: username};
|
||||
else if (email !== null)
|
||||
loginSelector = {email: email};
|
||||
else if (usernameOrEmail !== null)
|
||||
loginSelector = usernameOrEmail;
|
||||
else
|
||||
throw new Error("Unexpected -- no element to use as a login user selector");
|
||||
|
||||
Meteor.loginWithPassword(loginSelector, password, function (error, result) {
|
||||
if (error) {
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
} else {
|
||||
resetSession();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var signup = function () {
|
||||
resetMessages();
|
||||
|
||||
var options = {}; // to be passed to Meteor.createUser
|
||||
|
||||
var username = elementValueById('login-username');
|
||||
if (username !== null) {
|
||||
if (!validateUsername(username))
|
||||
return;
|
||||
else
|
||||
options.username = username;
|
||||
}
|
||||
|
||||
var email = elementValueById('login-email');
|
||||
if (email !== null) {
|
||||
if (!validateEmail(email))
|
||||
return;
|
||||
else
|
||||
options.email = email;
|
||||
}
|
||||
|
||||
var password = elementValueById('login-password');
|
||||
if (!validatePassword(password))
|
||||
return;
|
||||
else
|
||||
options.password = password;
|
||||
|
||||
if (!matchPasswordAgainIfPresent())
|
||||
return;
|
||||
|
||||
if (Accounts._options.validateEmails)
|
||||
options.validation = true;
|
||||
|
||||
Accounts.createUser(options, function (error) {
|
||||
if (error) {
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
} else {
|
||||
resetSession();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var loginOrSignup = function () {
|
||||
if (Session.get(IN_SIGNUP_FLOW_KEY))
|
||||
signup();
|
||||
else
|
||||
login();
|
||||
};
|
||||
|
||||
var changePassword = function () {
|
||||
resetMessages();
|
||||
|
||||
var oldPassword = elementValueById('login-old-password');
|
||||
|
||||
var password = elementValueById('login-password');
|
||||
if (!validatePassword(password))
|
||||
return;
|
||||
|
||||
if (!matchPasswordAgainIfPresent())
|
||||
return;
|
||||
|
||||
Accounts.changePassword(oldPassword, password, function (error) {
|
||||
if (error) {
|
||||
Session.set(ERROR_MESSAGE_KEY, error.reason || "Unknown error");
|
||||
} else {
|
||||
Session.set(INFO_MESSAGE_KEY, "Password changed");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var matchPasswordAgainIfPresent = function () {
|
||||
var passwordAgain = elementValueById('login-password-again');
|
||||
if (passwordAgain !== null) {
|
||||
var password = elementValueById('login-password');
|
||||
if (password !== passwordAgain) {
|
||||
Session.set(ERROR_MESSAGE_KEY, "Passwords don't match");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var correctDropdownZIndexes = function () {
|
||||
// IE <= 7 has a z-index bug that means we can't just give the
|
||||
// dropdown a z-index and expect it to stack above the rest of
|
||||
// the page even if nothing else has a z-index. The nature of
|
||||
// the bug is that all positioned elements are considered to
|
||||
// have z-index:0 (not auto) and therefore start new stacking
|
||||
// contexts, with ties broken by page order.
|
||||
//
|
||||
// The fix, then is to give z-index:1 to all ancestors
|
||||
// of the dropdown having z-index:0.
|
||||
for(var n = document.getElementById('login-dropdown-list').parentNode;
|
||||
n.nodeName !== 'BODY';
|
||||
n = n.parentNode)
|
||||
if (n.style.zIndex === 0)
|
||||
n.style.zIndex = 1;
|
||||
};
|
||||
|
||||
var getLoginServices = function () {
|
||||
Accounts._loginButtons.getLoginServices = function () {
|
||||
var ret = [];
|
||||
// make sure to put password last, since this is how it is styled
|
||||
// in the ui as well.
|
||||
@@ -810,50 +102,42 @@
|
||||
return ret;
|
||||
};
|
||||
|
||||
var hasPasswordService = function () {
|
||||
return _.any(getLoginServices(), function (service) {
|
||||
return service.name === 'password';
|
||||
});
|
||||
Accounts._loginButtons.hasPasswordService = function () {
|
||||
return Accounts.password;
|
||||
};
|
||||
|
||||
var dropdown = function () {
|
||||
return hasPasswordService() || getLoginServices().length > 1;
|
||||
Accounts._loginButtons.dropdown = function () {
|
||||
return Accounts._loginButtons.hasPasswordService() || Accounts._loginButtons.getLoginServices().length > 1;
|
||||
};
|
||||
|
||||
|
||||
// XXX improve these? should this be in accounts-password instead?
|
||||
// XXX improve these. should this be in accounts-password instead?
|
||||
//
|
||||
// XXX these will become configurable, and will be validated on
|
||||
// the server as well.
|
||||
var validateUsername = function (username) {
|
||||
Accounts._loginButtons.validateUsername = function (username) {
|
||||
if (username.length >= 3) {
|
||||
return true;
|
||||
} else {
|
||||
Session.set(ERROR_MESSAGE_KEY, "Username must be at least 3 characters long");
|
||||
loginButtonsSession.set('errorMessage', "Username must be at least 3 characters long");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var validateEmail = function (email) {
|
||||
Accounts._loginButtons.validateEmail = function (email) {
|
||||
if (email.indexOf('@') !== -1) {
|
||||
return true;
|
||||
} else {
|
||||
Session.set(ERROR_MESSAGE_KEY, "Invalid email");
|
||||
loginButtonsSession.set('errorMessage', "Invalid email");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var validatePassword = function (password) {
|
||||
Accounts._loginButtons.validatePassword = function (password) {
|
||||
if (password.length >= 6) {
|
||||
return true;
|
||||
} else {
|
||||
Session.set(ERROR_MESSAGE_KEY, "Password must be at least 6 characters long");
|
||||
loginButtonsSession.set('errorMessage', "Password must be at least 6 characters long");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX from http://epeli.github.com/underscore.string/lib/underscore.string.js
|
||||
var capitalize = function(str){
|
||||
str = str == null ? '' : String(str);
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
122
packages/accounts-ui-unstyled/login_buttons_dialogs.html
Normal file
122
packages/accounts-ui-unstyled/login_buttons_dialogs.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<body>
|
||||
{{> resetPasswordDialog}}
|
||||
{{> enrollAccountDialog}}
|
||||
{{> justValidatedUserDialog}}
|
||||
{{> configureLoginServiceDialog}}
|
||||
|
||||
<!-- if we're not showing a dropdown, we need some other place to show messages -->
|
||||
{{> loginButtonsMessagesDialog}}
|
||||
</body>
|
||||
|
||||
<template name="resetPasswordDialog">
|
||||
{{#if inResetPasswordFlow}}
|
||||
<div class="hide-background"></div>
|
||||
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
<label id="reset-password-new-password-label" for="reset-password-new-password">
|
||||
New password
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<input id="reset-password-new-password" type="password" />
|
||||
</div>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-reset-password-button">
|
||||
Set password
|
||||
</div>
|
||||
|
||||
<a class="additional-link" id="login-buttons-cancel-reset-password">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="enrollAccountDialog">
|
||||
{{#if inEnrollAccountFlow}}
|
||||
<div class="hide-background"></div>
|
||||
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
<label id="enroll-account-password-label" for="enroll-account-password">
|
||||
Choose a password
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<input id="enroll-account-password" type="password" />
|
||||
</div>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-enroll-account-button">
|
||||
Create account
|
||||
</div>
|
||||
|
||||
<a class="additional-link" id="login-buttons-cancel-enroll-account">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="justValidatedUserDialog">
|
||||
{{#if visible}}
|
||||
<div class="accounts-dialog accounts-centered-dialog">
|
||||
Email validated
|
||||
<div class="login-button" id="just-validated-dismiss-button">Dismiss</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="configureLoginServiceDialog">
|
||||
{{#if visible}}
|
||||
<div id="configure-login-service-dialog" class="accounts-dialog accounts-centered-dialog">
|
||||
{{{configurationSteps}}}
|
||||
|
||||
<p>
|
||||
Now, copy over some details.
|
||||
</p>
|
||||
<p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" class="configuration_labels">
|
||||
<col span="1" class="configuration_inputs">
|
||||
</colgroup>
|
||||
{{#each configurationFields}}
|
||||
<tr>
|
||||
<td>
|
||||
<label for="configure-login-service-dialog-{{property}}">{{label}}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="configure-login-service-dialog-{{property}}" />
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
</p>
|
||||
<div class="new-section">
|
||||
<div class="login-button" id="configure-login-service-dismiss-button">
|
||||
I'll do this later
|
||||
</div>
|
||||
{{#isolate}}
|
||||
<div class="login-button login-button-configure {{#if saveDisabled}}login-button-disabled{{/if}}"
|
||||
id="configure-login-service-dialog-save-configuration">
|
||||
Save Configuration
|
||||
</div>
|
||||
{{/isolate}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsMessagesDialog">
|
||||
{{#if visible}}
|
||||
<div class="accounts-dialog accounts-centered-dialog" id="login-buttons-message-dialog">
|
||||
{{> loginButtonsMessages}}
|
||||
<div class="login-button" id="messages-dialog-dismiss-button">Dismiss</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
|
||||
234
packages/accounts-ui-unstyled/login_buttons_dialogs.js
Normal file
234
packages/accounts-ui-unstyled/login_buttons_dialogs.js
Normal file
@@ -0,0 +1,234 @@
|
||||
(function () {
|
||||
// for convenience
|
||||
var loginButtonsSession = Accounts._loginButtonsSession;
|
||||
|
||||
|
||||
//
|
||||
// populate the session so that the appropriate dialogs are
|
||||
// displayed by reading variables set by accounts-urls, which parses
|
||||
// special URLs. since accounts-ui depends on accounts-urls, we are
|
||||
// guaranteed to have these set at this point.
|
||||
//
|
||||
|
||||
if (Accounts._resetPasswordToken) {
|
||||
loginButtonsSession.set('resetPasswordToken', Accounts._resetPasswordToken);
|
||||
}
|
||||
|
||||
if (Accounts._enrollAccountToken) {
|
||||
loginButtonsSession.set('enrollAccountToken', Accounts._enrollAccountToken);
|
||||
}
|
||||
|
||||
// Needs to be in Meteor.startup because of a package loading order
|
||||
// issue. We can't be sure that accounts-password is loaded earlier
|
||||
// than accounts-ui so Accounts.validateEmail might not be defined.
|
||||
Meteor.startup(function () {
|
||||
if (Accounts._validateEmailToken) {
|
||||
Accounts.validateEmail(Accounts._validateEmailToken, function(error) {
|
||||
Accounts._enableAutoLogin();
|
||||
if (!error)
|
||||
loginButtonsSession.set('justValidatedUser', true);
|
||||
// XXX show something if there was an error.
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// resetPasswordDialog template
|
||||
//
|
||||
|
||||
Template.resetPasswordDialog.events({
|
||||
'click #login-buttons-reset-password-button': function () {
|
||||
resetPassword();
|
||||
},
|
||||
'keypress #reset-password-new-password': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
resetPassword();
|
||||
},
|
||||
'click #login-buttons-cancel-reset-password': function () {
|
||||
loginButtonsSession.set('resetPasswordToken', null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
|
||||
var resetPassword = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
var newPassword = document.getElementById('reset-password-new-password').value;
|
||||
if (!Accounts._loginButtons.validatePassword(newPassword))
|
||||
return;
|
||||
|
||||
Accounts.resetPassword(
|
||||
loginButtonsSession.get('resetPasswordToken'), newPassword,
|
||||
function (error) {
|
||||
if (error) {
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
} else {
|
||||
loginButtonsSession.set('resetPasswordToken', null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Template.resetPasswordDialog.inResetPasswordFlow = function () {
|
||||
return loginButtonsSession.get('resetPasswordToken');
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// enrollAccountDialog template
|
||||
//
|
||||
|
||||
Template.enrollAccountDialog.events({
|
||||
'click #login-buttons-enroll-account-button': function () {
|
||||
enrollAccount();
|
||||
},
|
||||
'keypress #enroll-account-password': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
enrollAccount();
|
||||
},
|
||||
'click #login-buttons-cancel-enroll-account': function () {
|
||||
loginButtonsSession.set('enrollAccountToken', null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
|
||||
var enrollAccount = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
var password = document.getElementById('enroll-account-password').value;
|
||||
if (!Accounts._loginButtons.validatePassword(password))
|
||||
return;
|
||||
|
||||
Accounts.resetPassword(
|
||||
loginButtonsSession.get('enrollAccountToken'), password,
|
||||
function (error) {
|
||||
if (error) {
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
} else {
|
||||
loginButtonsSession.set('enrollAccountToken', null);
|
||||
Accounts._enableAutoLogin();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Template.enrollAccountDialog.inEnrollAccountFlow = function () {
|
||||
return loginButtonsSession.get('enrollAccountToken');
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// justValidatedUserDialog template
|
||||
//
|
||||
|
||||
Template.justValidatedUserDialog.events({
|
||||
'click #just-validated-dismiss-button': function () {
|
||||
loginButtonsSession.set('justValidatedUser', false);
|
||||
}
|
||||
});
|
||||
|
||||
Template.justValidatedUserDialog.visible = function () {
|
||||
return loginButtonsSession.get('justValidatedUser');
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsMessagesDialog template
|
||||
//
|
||||
|
||||
Template.loginButtonsMessagesDialog.events({
|
||||
'click #messages-dialog-dismiss-button': function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsMessagesDialog.visible = function () {
|
||||
var hasMessage = loginButtonsSession.get('infoMessage') || loginButtonsSession.get('errorMessage');
|
||||
return !Accounts._loginButtons.dropdown() && hasMessage;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// configureLoginServiceDialog template
|
||||
//
|
||||
|
||||
Template.configureLoginServiceDialog.events({
|
||||
'click #configure-login-service-dismiss-button': function () {
|
||||
loginButtonsSession.set('configureLoginServiceDialogVisible', false);
|
||||
},
|
||||
'click #configure-login-service-dialog-save-configuration': function () {
|
||||
if (loginButtonsSession.get('configureLoginServiceDialogVisible')) {
|
||||
// Prepare the configuration document for this login service
|
||||
var serviceName = loginButtonsSession.get('configureLoginServiceDialogServiceName');
|
||||
var configuration = {
|
||||
service: serviceName
|
||||
};
|
||||
_.each(configurationFields(), function(field) {
|
||||
configuration[field.property] = document.getElementById(
|
||||
'configure-login-service-dialog-' + field.property).value;
|
||||
});
|
||||
|
||||
// Configure this login service
|
||||
Meteor.call("configureLoginService", configuration, function (error, result) {
|
||||
if (error)
|
||||
Meteor._debug("Error configurating login service " + serviceName, error);
|
||||
else
|
||||
loginButtonsSession.set('configureLoginServiceDialogVisible', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
'input': function (event) {
|
||||
// if the event fired on one of the configuration input fields,
|
||||
// check whether we should enable the 'save configuration' button
|
||||
if (event.target.id.indexOf('configure-login-service-dialog') === 0)
|
||||
updateSaveDisabled();
|
||||
}
|
||||
});
|
||||
|
||||
// check whether the 'save configuration' button should be enabled.
|
||||
// this is a really strange way to implement this and a Forms
|
||||
// Abstraction would make all of this reactive, and simpler.
|
||||
var updateSaveDisabled = function () {
|
||||
var anyFieldEmpty = _.any(configurationFields(), function(field) {
|
||||
return document.getElementById(
|
||||
'configure-login-service-dialog-' + field.property).value === '';
|
||||
});
|
||||
|
||||
loginButtonsSession.set('configureLoginServiceDialogSaveDisabled', anyFieldEmpty);
|
||||
};
|
||||
|
||||
// Returns the appropriate template for this login service. This
|
||||
// template should be defined in the service's package
|
||||
var configureLoginServiceDialogTemplateForService = function () {
|
||||
var serviceName = loginButtonsSession.get('configureLoginServiceDialogServiceName');
|
||||
return Template['configureLoginServiceDialogFor' + capitalize(serviceName)];
|
||||
};
|
||||
|
||||
var configurationFields = function () {
|
||||
var template = configureLoginServiceDialogTemplateForService();
|
||||
return template.fields();
|
||||
};
|
||||
|
||||
Template.configureLoginServiceDialog.configurationFields = function () {
|
||||
return configurationFields();
|
||||
};
|
||||
|
||||
Template.configureLoginServiceDialog.visible = function () {
|
||||
return loginButtonsSession.get('configureLoginServiceDialogVisible');
|
||||
};
|
||||
|
||||
Template.configureLoginServiceDialog.configurationSteps = function () {
|
||||
// renders the appropriate template
|
||||
return configureLoginServiceDialogTemplateForService()();
|
||||
};
|
||||
|
||||
Template.configureLoginServiceDialog.saveDisabled = function () {
|
||||
return loginButtonsSession.get('configureLoginServiceDialogSaveDisabled');
|
||||
};
|
||||
|
||||
|
||||
// XXX from http://epeli.github.com/underscore.string/lib/underscore.string.js
|
||||
var capitalize = function(str){
|
||||
str = str == null ? '' : String(str);
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
|
||||
}) ();
|
||||
145
packages/accounts-ui-unstyled/login_buttons_dropdown.html
Normal file
145
packages/accounts-ui-unstyled/login_buttons_dropdown.html
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- -->
|
||||
<!-- LOGGED IN -->
|
||||
<!-- -->
|
||||
<template name="loginButtonsLoggedInDropdown">
|
||||
<div class="login-link-and-dropdown-list">
|
||||
{{#if currentUser.loading}}
|
||||
<div class="loading"></div>
|
||||
{{else}}
|
||||
<a class="login-link-text" id="login-name-link">
|
||||
{{displayName}} ▾
|
||||
</a>
|
||||
|
||||
{{#if dropdownVisible}}
|
||||
<div id="login-dropdown-list" class="accounts-dialog">
|
||||
<a class="login-close-text">Close</a>
|
||||
<div class="login-close-text-clear"></div>
|
||||
|
||||
{{#if inChangePasswordFlow}}
|
||||
{{> loginButtonsChangePassword}}
|
||||
{{else}}
|
||||
{{> loginButtonsLoggedInDropdownActions}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsLoggedInDropdownActions">
|
||||
{{#if allowChangingPassword}}
|
||||
<div class="login-button" id="login-buttons-open-change-password">
|
||||
Change password
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="login-button" id="login-buttons-logout">
|
||||
Logout
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- -->
|
||||
<!-- LOGGED OUT -->
|
||||
<!-- -->
|
||||
<template name="loginButtonsLoggedOutDropdown">
|
||||
<div class="login-link-and-dropdown-list">
|
||||
<a class="login-link-text" id="login-sign-in-link">Sign in ▾</a>
|
||||
{{#if dropdownVisible}}
|
||||
<div id="login-dropdown-list" class="accounts-dialog">
|
||||
<a class="login-close-text">Close</a>
|
||||
<div class="login-close-text-clear"></div>
|
||||
{{> loginButtonsLoggedOutAllServices}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsLoggedOutAllServices">
|
||||
{{#each services}}
|
||||
{{#if isPasswordService}}
|
||||
{{#if hasOtherServices}} {{! the password service will always come last }}
|
||||
<div class="or">
|
||||
<span class="hline"> </span>
|
||||
<span class="or-text">or</span>
|
||||
<span class="hline"> </span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{> loginButtonsLoggedOutPasswordService}}
|
||||
{{else}}
|
||||
{{> loginButtonsLoggedOutSingleLoginButton}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
{{#unless hasPasswordService}}
|
||||
{{> loginButtonsMessages}}
|
||||
{{/unless}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsLoggedOutPasswordService">
|
||||
{{#if inForgotPasswordFlow}}
|
||||
{{> forgotPasswordForm}}
|
||||
{{else}}
|
||||
<div class="login-form login-password-form">
|
||||
{{#each fields}}
|
||||
{{> loginButtonsFormField}}
|
||||
{{/each}}
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-password">
|
||||
{{#if inSignupFlow}}
|
||||
Create account
|
||||
{{else}}
|
||||
Sign in
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if inLoginFlow}}
|
||||
<div class="additional-link-container">
|
||||
<a id="signup-link" class="additional-link">Create account</a>
|
||||
</div>
|
||||
|
||||
{{#if showForgotPasswordLink}}
|
||||
<div class="additional-link-container">
|
||||
<a id="forgot-password-link" class="additional-link">Forgot password</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsFormField">
|
||||
{{#if visible}}
|
||||
<label id="login-{{fieldName}}-label" for="login-{{fieldName}}">
|
||||
{{fieldLabel}}
|
||||
</label>
|
||||
<input id="login-{{fieldName}}" type="{{inputType}}" />
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="forgotPasswordForm">
|
||||
<div class="login-form">
|
||||
<label id="forgot-password-email-label" for="forgot-password-email">Email</label>
|
||||
<input id="forgot-password-email"/>
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-forgot-password">
|
||||
Reset password
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loginButtonsChangePassword">
|
||||
{{#each fields}}
|
||||
{{> loginButtonsFormField}}
|
||||
{{/each}}
|
||||
|
||||
{{> loginButtonsMessages}}
|
||||
|
||||
<div class="login-button login-button-form-submit" id="login-buttons-do-change-password">
|
||||
Change password
|
||||
</div>
|
||||
</template>
|
||||
414
packages/accounts-ui-unstyled/login_buttons_dropdown.js
Normal file
414
packages/accounts-ui-unstyled/login_buttons_dropdown.js
Normal file
@@ -0,0 +1,414 @@
|
||||
(function () {
|
||||
// for convenience
|
||||
var loginButtonsSession = Accounts._loginButtonsSession;
|
||||
|
||||
// events shared between loginButtonsLoggedOutDropdown and
|
||||
// loginButtonsLoggedInDropdown
|
||||
Template.loginButtons.events({
|
||||
'click #login-name-link, click #login-sign-in-link': function () {
|
||||
loginButtonsSession.set('dropdownVisible', true);
|
||||
Meteor.flush();
|
||||
correctDropdownZIndexes();
|
||||
},
|
||||
'click .login-close-text': function () {
|
||||
loginButtonsSession.closeDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsLoggedInDropdown template and related
|
||||
//
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.events({
|
||||
'click #login-buttons-open-change-password': function() {
|
||||
loginButtonsSession.resetMessages();
|
||||
loginButtonsSession.set('inChangePasswordFlow', true);
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.displayName = function () {
|
||||
return Accounts._loginButtons.displayName();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.inChangePasswordFlow = function () {
|
||||
return loginButtonsSession.get('inChangePasswordFlow');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdown.dropdownVisible = function () {
|
||||
return loginButtonsSession.get('dropdownVisible');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedInDropdownActions.allowChangingPassword = function () {
|
||||
// it would be more correct to check whether the user has a password set,
|
||||
// but in order to do that we'd have to send more data down to the client,
|
||||
// and it'd be preferable not to send down the entire service.password document.
|
||||
//
|
||||
// instead we use the heuristic: if the user has a username or email set.
|
||||
var user = Meteor.user();
|
||||
return user.username || (user.emails && user.emails[0] && user.emails[0].address);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsLoggedOutDropdown template and related
|
||||
//
|
||||
|
||||
Template.loginButtonsLoggedOutDropdown.events({
|
||||
'click #login-buttons-password': function () {
|
||||
loginOrSignup();
|
||||
},
|
||||
|
||||
'keypress #forgot-password-email': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
forgotPassword();
|
||||
},
|
||||
|
||||
'click #login-buttons-forgot-password': function () {
|
||||
forgotPassword();
|
||||
},
|
||||
|
||||
'click #signup-link': function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
// store values of fields before swtiching to the signup form
|
||||
var username = elementValueById('login-username');
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
var password = elementValueById('login-password');
|
||||
|
||||
loginButtonsSession.set('inSignupFlow', true);
|
||||
loginButtonsSession.set('inForgotPasswordFlow', false);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (username !== null)
|
||||
document.getElementById('login-username').value = username;
|
||||
else if (email !== null)
|
||||
document.getElementById('login-email').value = email;
|
||||
else if (usernameOrEmail !== null)
|
||||
if (usernameOrEmail.indexOf('@') === -1)
|
||||
document.getElementById('login-username').value = usernameOrEmail;
|
||||
else
|
||||
document.getElementById('login-email').value = usernameOrEmail;
|
||||
|
||||
document.getElementById('login-password').value = password;
|
||||
|
||||
// Forge redrawing the `login-dropdown-list` element because of
|
||||
// a bizarre Chrome bug in which part of the DIV is not redrawn
|
||||
// in case you had tried to unsuccessfully log in before
|
||||
// switching to the signup form.
|
||||
//
|
||||
// Found tip on how to force a redraw on
|
||||
// http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes/3485654#3485654
|
||||
var redraw = document.getElementById('login-dropdown-list');
|
||||
redraw.style.display = 'none';
|
||||
redraw.offsetHeight; // it seems that this line does nothing but is necessary for the redraw to work
|
||||
redraw.style.display = 'block';
|
||||
},
|
||||
'click #forgot-password-link': function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
// store values of fields before swtiching to the signup form
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
|
||||
loginButtonsSession.set('inSignupFlow', false);
|
||||
loginButtonsSession.set('inForgotPasswordFlow', true);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (email !== null)
|
||||
document.getElementById('forgot-password-email').value = email;
|
||||
else if (usernameOrEmail !== null)
|
||||
if (usernameOrEmail.indexOf('@') !== -1)
|
||||
document.getElementById('forgot-password-email').value = usernameOrEmail;
|
||||
|
||||
},
|
||||
'keypress #login-username, keypress #login-email, keypress #login-username-or-email, keypress #login-password, keypress #login-password-again': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
loginOrSignup();
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsLoggedOutDropdown.dropdownVisible = function () {
|
||||
return loginButtonsSession.get('dropdownVisible');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutDropdown.hasPasswordService = function () {
|
||||
return Accounts._loginButtons.hasPasswordService();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutAllServices.services = function () {
|
||||
return Accounts._loginButtons.getLoginServices();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutAllServices.isPasswordService = function () {
|
||||
return this.name === 'password';
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutAllServices.hasOtherServices = function () {
|
||||
return Accounts._loginButtons.getLoginServices().length > 1;
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutAllServices.hasPasswordService = function () {
|
||||
return Accounts._loginButtons.hasPasswordService();
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutPasswordService.fields = function () {
|
||||
var loginFields = [
|
||||
{fieldName: 'username-or-email', fieldLabel: 'Username or Email',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'username', fieldLabel: 'Username',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& !Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'email', fieldLabel: 'Email',
|
||||
visible: function () {
|
||||
return !Accounts._options.requireUsername;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}}
|
||||
];
|
||||
|
||||
var signupFields = [
|
||||
{fieldName: 'username', fieldLabel: 'Username',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername;
|
||||
}},
|
||||
{fieldName: 'email', fieldLabel: 'Email',
|
||||
visible: function () {
|
||||
return !Accounts._options.requireUsername
|
||||
|| Accounts._options.requireEmail;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password-again', fieldLabel: 'Password (again)',
|
||||
inputType: 'password',
|
||||
visible: function () {
|
||||
return Accounts._options.requireUsername
|
||||
&& !Accounts._options.requireEmail;
|
||||
}}
|
||||
];
|
||||
|
||||
return loginButtonsSession.get('inSignupFlow') ? signupFields : loginFields;
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutPasswordService.inForgotPasswordFlow = function () {
|
||||
return loginButtonsSession.get('inForgotPasswordFlow');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutPasswordService.inLoginFlow = function () {
|
||||
return !loginButtonsSession.get('inSignupFlow') && !loginButtonsSession.get('inForgotPasswordFlow');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutPasswordService.inSignupFlow = function () {
|
||||
return loginButtonsSession.get('inSignupFlow');
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutPasswordService.showForgotPasswordLink = function () {
|
||||
return Accounts._options.requireEmail
|
||||
|| !Accounts._options.requireUsername;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// loginButtonsChangePassword template
|
||||
//
|
||||
|
||||
Template.loginButtonsChangePassword.events({
|
||||
'keypress #login-old-password, keypress #login-password, keypress #login-password-again': function (event) {
|
||||
if (event.keyCode === 13)
|
||||
changePassword();
|
||||
},
|
||||
'click #login-buttons-do-change-password': function () {
|
||||
changePassword();
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsChangePassword.fields = function () {
|
||||
return [
|
||||
{fieldName: 'old-password', fieldLabel: 'Current Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password', fieldLabel: 'New Password', inputType: 'password',
|
||||
visible: function () {
|
||||
return true;
|
||||
}},
|
||||
{fieldName: 'password-again', fieldLabel: 'New Password (again)',
|
||||
inputType: 'password',
|
||||
visible: function () {
|
||||
return Meteor.accounts._options.requireUsername
|
||||
&& !Meteor.accounts._options.requireEmail;
|
||||
}}
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
|
||||
var elementValueById = function(id) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element)
|
||||
return null;
|
||||
else
|
||||
return element.value;
|
||||
};
|
||||
|
||||
var loginOrSignup = function () {
|
||||
if (loginButtonsSession.get('inSignupFlow'))
|
||||
signup();
|
||||
else
|
||||
login();
|
||||
};
|
||||
|
||||
var login = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
var username = elementValueById('login-username');
|
||||
var email = elementValueById('login-email');
|
||||
var usernameOrEmail = elementValueById('login-username-or-email');
|
||||
var password = elementValueById('login-password');
|
||||
|
||||
var loginSelector;
|
||||
if (username !== null)
|
||||
loginSelector = {username: username};
|
||||
else if (email !== null)
|
||||
loginSelector = {email: email};
|
||||
else if (usernameOrEmail !== null)
|
||||
loginSelector = usernameOrEmail;
|
||||
else
|
||||
throw new Error("Unexpected -- no element to use as a login user selector");
|
||||
|
||||
Meteor.loginWithPassword(loginSelector, password, function (error, result) {
|
||||
if (error) {
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
} else {
|
||||
loginButtonsSession.closeDropdown();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var signup = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
var options = {}; // to be passed to Meteor.createUser
|
||||
|
||||
var username = elementValueById('login-username');
|
||||
if (username !== null) {
|
||||
if (!Accounts._loginButtons.validateUsername(username))
|
||||
return;
|
||||
else
|
||||
options.username = username;
|
||||
}
|
||||
|
||||
var email = elementValueById('login-email');
|
||||
if (email !== null) {
|
||||
if (!Accounts._loginButtons.validateEmail(email))
|
||||
return;
|
||||
else
|
||||
options.email = email;
|
||||
}
|
||||
|
||||
var password = elementValueById('login-password');
|
||||
if (!Accounts._loginButtons.validatePassword(password))
|
||||
return;
|
||||
else
|
||||
options.password = password;
|
||||
|
||||
if (!matchPasswordAgainIfPresent())
|
||||
return;
|
||||
|
||||
if (Accounts._options.validateEmails)
|
||||
options.validation = true;
|
||||
|
||||
Accounts.createUser(options, function (error) {
|
||||
if (error) {
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
} else {
|
||||
loginButtonsSession.closeDropdown();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var forgotPassword = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
var email = document.getElementById("forgot-password-email").value;
|
||||
if (email.indexOf('@') !== -1) {
|
||||
Accounts.forgotPassword({email: email}, function (error) {
|
||||
if (error)
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
else
|
||||
loginButtonsSession.set('infoMessage', "Email sent");
|
||||
});
|
||||
} else {
|
||||
loginButtonsSession.set('errorMessage', "Invalid email");
|
||||
}
|
||||
};
|
||||
|
||||
var changePassword = function () {
|
||||
loginButtonsSession.resetMessages();
|
||||
|
||||
var oldPassword = elementValueById('login-old-password');
|
||||
|
||||
var password = elementValueById('login-password');
|
||||
if (!Accounts._loginButtons.validatePassword(password))
|
||||
return;
|
||||
|
||||
if (!matchPasswordAgainIfPresent())
|
||||
return;
|
||||
|
||||
Accounts.changePassword(oldPassword, password, function (error) {
|
||||
if (error) {
|
||||
loginButtonsSession.set('errorMessage', error.reason || "Unknown error");
|
||||
} else {
|
||||
loginButtonsSession.set('infoMessage', "Password changed");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var matchPasswordAgainIfPresent = function () {
|
||||
var passwordAgain = elementValueById('login-password-again');
|
||||
if (passwordAgain !== null) {
|
||||
var password = elementValueById('login-password');
|
||||
if (password !== passwordAgain) {
|
||||
loginButtonsSession.set('errorMessage', "Passwords don't match");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var correctDropdownZIndexes = function () {
|
||||
// IE <= 7 has a z-index bug that means we can't just give the
|
||||
// dropdown a z-index and expect it to stack above the rest of
|
||||
// the page even if nothing else has a z-index. The nature of
|
||||
// the bug is that all positioned elements are considered to
|
||||
// have z-index:0 (not auto) and therefore start new stacking
|
||||
// contexts, with ties broken by page order.
|
||||
//
|
||||
// The fix, then is to give z-index:1 to all ancestors
|
||||
// of the dropdown having z-index:0.
|
||||
for(var n = document.getElementById('login-dropdown-list').parentNode;
|
||||
n.nodeName !== 'BODY';
|
||||
n = n.parentNode)
|
||||
if (n.style.zIndex === 0)
|
||||
n.style.zIndex = 1;
|
||||
};
|
||||
|
||||
|
||||
}) ();
|
||||
60
packages/accounts-ui-unstyled/login_buttons_session.js
Normal file
60
packages/accounts-ui-unstyled/login_buttons_session.js
Normal file
@@ -0,0 +1,60 @@
|
||||
(function () {
|
||||
var VALID_KEYS = [
|
||||
'dropdownVisible',
|
||||
|
||||
// XXX consider replacing these with one key that has an enum for values.
|
||||
'inSignupFlow',
|
||||
'inForgotPasswordFlow',
|
||||
'inChangePasswordFlow',
|
||||
|
||||
'errorMessage',
|
||||
'infoMessage',
|
||||
|
||||
'resetPasswordToken',
|
||||
'enrollAccountToken',
|
||||
'justValidatedUser',
|
||||
|
||||
'configureLoginServiceDialogVisible',
|
||||
'configureLoginServiceDialogServiceName',
|
||||
'configureLoginServiceDialogSaveDisabled'
|
||||
];
|
||||
|
||||
var validateKey = function (key) {
|
||||
if (!_.contains(VALID_KEYS, key))
|
||||
throw new Error("Invalid key in loginButtonsSession: " + key);
|
||||
};
|
||||
|
||||
KEY_PREFIX = "Meteor.loginButtons.";
|
||||
|
||||
// XXX we should have a better pattern for code private to a package like this one
|
||||
Accounts._loginButtonsSession = {
|
||||
set: function(key, value) {
|
||||
validateKey(key);
|
||||
Session.set(KEY_PREFIX + key, value);
|
||||
},
|
||||
|
||||
get: function(key) {
|
||||
validateKey(key);
|
||||
return Session.get(KEY_PREFIX + key);
|
||||
},
|
||||
|
||||
closeDropdown: function () {
|
||||
this.set('inSignupFlow', false);
|
||||
this.set('inForgotPasswordFlow', false);
|
||||
this.set('inChangePasswordFlow', false);
|
||||
this.set('dropdownVisible', false);
|
||||
this.resetMessages();
|
||||
},
|
||||
|
||||
resetMessages: function () {
|
||||
this.set("errorMessage", null);
|
||||
this.set("infoMessage", null);
|
||||
},
|
||||
|
||||
configureService: function (name) {
|
||||
this.set('configureLoginServiceDialogVisible', true);
|
||||
this.set('configureLoginServiceDialogServiceName', name);
|
||||
this.set('configureLoginServiceDialogSaveDisabled', true);
|
||||
}
|
||||
};
|
||||
}) ();
|
||||
11
packages/accounts-ui-unstyled/login_buttons_single.html
Normal file
11
packages/accounts-ui-unstyled/login_buttons_single.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<template name="loginButtonsLoggedOutSingleLoginButton">
|
||||
<div class="login-button {{#unless configured}}configure-button{{/unless}}"
|
||||
id="login-buttons-{{name}}">
|
||||
<div class="login-image" id="login-buttons-image-{{name}}"></div>
|
||||
{{#if configured}}
|
||||
<span class="sign-in-text-{{name}}">Sign in with {{capitalizedName}}</span>
|
||||
{{else}}
|
||||
<span class="configure-text-{{name}}">Configure {{capitalizedName}} Login</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
40
packages/accounts-ui-unstyled/login_buttons_single.js
Normal file
40
packages/accounts-ui-unstyled/login_buttons_single.js
Normal file
@@ -0,0 +1,40 @@
|
||||
(function () {
|
||||
// for convenience
|
||||
var loginButtonsSession = Accounts._loginButtonsSession;
|
||||
|
||||
Template.loginButtonsLoggedOutSingleLoginButton.events({
|
||||
'click .login-button': function () {
|
||||
var serviceName = this.name;
|
||||
loginButtonsSession.resetMessages();
|
||||
Meteor["loginWith" + capitalize(serviceName)](function (err) {
|
||||
if (!err) {
|
||||
loginButtonsSession.closeDropdown();
|
||||
} else if (err instanceof Accounts.LoginCancelledError) {
|
||||
// do nothing
|
||||
} else if (err instanceof Accounts.ConfigError) {
|
||||
loginButtonsSession.configureService(serviceName);
|
||||
} else {
|
||||
loginButtonsSession.set('errorMessage', err.reason || "Unknown error");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.loginButtonsLoggedOutSingleLoginButton.configured = function () {
|
||||
return !!Accounts.configuration.findOne({service: this.name});
|
||||
};
|
||||
|
||||
Template.loginButtonsLoggedOutSingleLoginButton.capitalizedName = function () {
|
||||
if (this.name === 'github')
|
||||
// XXX we should allow service packages to set their capitalized name
|
||||
return 'GitHub';
|
||||
else
|
||||
return capitalize(this.name);
|
||||
};
|
||||
|
||||
// XXX from http://epeli.github.com/underscore.string/lib/underscore.string.js
|
||||
var capitalize = function(str){
|
||||
str = str == null ? '' : String(str);
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
}) ();
|
||||
@@ -8,5 +8,14 @@ Package.on_use(function (api) {
|
||||
api.add_files([
|
||||
'login_buttons_images.css',
|
||||
'login_buttons.html',
|
||||
'login_buttons.js'], 'client');
|
||||
'login_buttons_single.html',
|
||||
'login_buttons_dropdown.html',
|
||||
'login_buttons_dialogs.html',
|
||||
|
||||
'login_buttons_session.js',
|
||||
|
||||
'login_buttons.js',
|
||||
'login_buttons_single.js',
|
||||
'login_buttons_dropdown.js',
|
||||
'login_buttons_dialogs.js'], 'client');
|
||||
});
|
||||
|
||||
@@ -152,11 +152,16 @@
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#login-buttons .message {
|
||||
.accounts-dialog .message {
|
||||
font-size: 80%;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#login-buttons-message-dialog .message {
|
||||
/* we intentionally want it bigger on this dialog since it's the only thing displayed */
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.accounts-dialog .error-message {
|
||||
color: red;
|
||||
}
|
||||
@@ -197,15 +202,15 @@
|
||||
margin-top: -40px; /* = approximately -height/2, though height can change */
|
||||
}
|
||||
|
||||
@configure-login-services-dialog-width: 530px;
|
||||
#configure-login-services-dialog {
|
||||
width: @configure-login-services-dialog-width;
|
||||
margin-left: -(@configure-login-services-dialog-width
|
||||
@configure-login-service-dialog-width: 530px;
|
||||
#configure-login-service-dialog {
|
||||
width: @configure-login-service-dialog-width;
|
||||
margin-left: -(@configure-login-service-dialog-width
|
||||
+ @login-buttons-accounts-dialog-padding-left) / 2;
|
||||
margin-top: -180px; /* = approximately -height/2, though height can change */
|
||||
}
|
||||
|
||||
#configure-login-services-dialog .login-button-configure {
|
||||
#configure-login-service-dialog .login-button-configure {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -227,37 +232,37 @@
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
#configure-login-services-dialog table {
|
||||
#configure-login-service-dialog table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog .configuration_labels {
|
||||
#configure-login-service-dialog .configuration_labels {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog .configuration_inputs {
|
||||
#configure-login-service-dialog .configuration_inputs {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog input {
|
||||
#configure-login-service-dialog input {
|
||||
width: 100%;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog ol {
|
||||
#configure-login-service-dialog ol {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog .new-section {
|
||||
#configure-login-service-dialog .new-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog ol li {
|
||||
#configure-login-service-dialog ol li {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
#configure-login-services-dialog .url {
|
||||
#configure-login-service-dialog .url {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template name="configureLoginServicesDialogForWeibo">
|
||||
<template name="configureLoginServiceDialogForWeibo">
|
||||
<p>
|
||||
First, you'll need to register your app on Weibo. Follow these steps:
|
||||
</p>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Template.configureLoginServicesDialogForWeibo.siteUrl = function () {
|
||||
Template.configureLoginServiceDialogForWeibo.siteUrl = function () {
|
||||
// Weibo doesn't recognize localhost as a domain
|
||||
return Meteor.absoluteUrl({replaceLocalhost: true});
|
||||
};
|
||||
|
||||
Template.configureLoginServicesDialogForWeibo.fields = function () {
|
||||
Template.configureLoginServiceDialogForWeibo.fields = function () {
|
||||
return [
|
||||
{property: 'clientId', label: 'App Key'},
|
||||
{property: 'secret', label: 'App Secret'}
|
||||
|
||||
Reference in New Issue
Block a user