You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2012/09/11 05:25:59 UTC
svn commit: r1383233 [1/2] - in /incubator/ambari/branches/AMBARI-666: ./
ambari-web/app/ ambari-web/app/controllers/ ambari-web/app/routes/
ambari-web/app/templates/ ambari-web/app/templates/installer/
ambari-web/app/utils/ ambari-web/app/views/instal...
Author: yusaku
Date: Tue Sep 11 03:25:58 2012
New Revision: 1383233
URL: http://svn.apache.org/viewvc?rev=1383233&view=rev
Log:
AMBARI-711. Create utility functions related to localStorage for first two steps: cluster name and Install options. Also develop view logic with preliminary validations for these two steps. (Contributed by Jaimin Jetly)
Modified:
incubator/ambari/branches/AMBARI-666/.gitignore
incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/login.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/initialize.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step1.hbs
incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step2.hbs
incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step3.hbs
incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main.hbs
incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step1.js
incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step2.js
incubator/ambari/branches/AMBARI-666/ambari-web/vendor/scripts/bootstrap.js
incubator/ambari/branches/AMBARI-666/ambari-web/vendor/styles/bootstrap.css
Modified: incubator/ambari/branches/AMBARI-666/.gitignore
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/.gitignore?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/.gitignore (original)
+++ incubator/ambari/branches/AMBARI-666/.gitignore Tue Sep 11 03:25:58 2012
@@ -1,4 +1,9 @@
.classpath
.project
.settings
+.idea/
+.iml/
+.DS_Store
target
+/ambari-web/public/
+/ambari-web/node_modules/
Modified: incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt (original)
+++ incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt Tue Sep 11 03:25:58 2012
@@ -12,6 +12,10 @@ AMBARI-666 branch (unreleased changes)
NEW FEATURES
+ AMBARI-711. Create utility functions related to localStorage for first two
+ steps: cluster name and Install options. Also develop view logic with
+ preliminary validations for these two steps. (Jaimin Jetly via yusaku)
+
AMBARI-715. Integrate domain objects and Rest serialized objects. (mahadev)
AMBARI-713. Initial work on Job FSM. (hitesh)
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer.js Tue Sep 11 03:25:58 2012
@@ -24,10 +24,217 @@ App.InstallerController = Em.Controller.
name: 'installerController',
clusterName: '',
+ validClusterName: true,
+ hostNames: '',
+ hostNameArr: [],
+ errorMsg_clusterName: '',
+ hostNameEmptyError: false,
+
+ hostNameErr: false,
+ manualInstall: false,
+ hostNameNotRequireErr: false,
+ InstallType: 'ambariDriven',
+ sshKey: '',
+ passphrase: '',
+ confirmPassphrase: '',
+ sshKeyNullErr: false,
+ passphraseNullErr: false,
+ passphraseMatchErr: false,
+ localRepo: false,
+ softRepo: 'remote',
+ localRepoPath: '',
+ softRepoLocalPathNullErr: false,
+
+ hideRepoErrMsg: function () {
+ if (this.get('localRepo') === false) {
+ this.set('softRepoLocalPathNullErr', false);
+ }
+ }.observes('localRepo'),
+
+ hostManageErr: function () {
+ if (this.get('hostNameEmptyError') || this.get('hostNameNotRequireErr') || this.get('hostNameErr') || this.get('sshKeyNullErr') || this.get('passphraseMatchErr')) {
+ return true;
+ } else {
+ return false
+ }
+ }.property('hostNameEmptyError', 'hostNameNotRequireErr', 'hostNameErr', 'sshKeyNullErr', 'passphraseMatchErr'),
+
+ advOptErr: function () {
+ if (this.get('softRepoLocalPathNullErr')) {
+ return true;
+ } else {
+ return false
+ }
+ }.property('softRepoLocalPathNullErr'),
+
+ evaluateStep1: function () {
+ //TODO: Done
+ //task1 = checks on valid cluster name
+ //task2 (prereq(task1 says it's a valid cluster name)) = storing cluster name in localstorage
+ var result;
+ console.log('TRACE: Entering controller:Installer:evaluateStep1 function');
+ if (this.get('clusterName') == '') {
+ this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_null);
+ this.set('validClusterName', false);
+ result = false;
+ } else if (/\s/.test(this.get('clusterName'))) {
+ console.log('White spaces not allowed for cluster name');
+ this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_Whitespaces);
+ this.set('validClusterName', false);
+ result = false;
+ } else if (/[^\w\s]/gi.test(this.get('clusterName'))) {
+ console.log('Special characters are not allowed for the cluster name');
+ this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_specialChar);
+ this.set('validClusterName', false);
+ result = false;
+ } else {
+ console.log('value of clusterNmae is: ' + this.get('clusterName'));
+ this.set('validClusterName', true);
+ result = true;
+ }
+ if (result === true) {
+ App.db.setClusterName(this.get('clusterName'));
+ }
+ console.log('Exiting the evaluatestep1 function');
+ return result;
+ },
+
+ evaluateStep2: function () {
+ // TODO: evaluation/manipulation at the end of step2
+ //task1 = do primary validations on whole step before executing any further steps
+ //task2 = parsing hostnames string to hostnames json array
+ //task3 = check validation for every hostname and store it in localstorage
+ //task4 = Storing ambari agent Install type in localStorage (InstallType maps at host level and so every host will have this as an property)
+ //task5 = Storing path of software repository(remote/local repo) to localStorage
+ //task6 = call to rest API: @Post http://ambari_server/api/bootstrap
+ //task7 = On faliure of the previous call, show 'error injecting host information in server db'
+ //task8 = On success of the previous call, go to step 3(awesome....)
+
+ console.log('TRACE: Entering controller:Installer:evaluateStep2 function');
+ /** task1 **/
+ console.log('value of manual install is: ' + this.get('manualInstall'));
+ if (this.get('hostNames') === '' && this.get('manualInstall') === false) {
+ this.set('hostNameEmptyError', true);
+ this.set('hostNameNotRequireErr', false);
+ return false;
+ } else if (this.get('hostNames') !== '' && this.get('manualInstall') === true) {
+ this.set('hostNameNotRequireErr', true);
+ this.set('hostNameEmptyError', false);
+ return false;
+ } else {
+ this.set('hostNameEmptyError', false);
+ this.set('hostNameNotRequireErr', false);
+ }
+
+ if (this.get('manualInstall') === false) {
+ if (this.get('sshKey') === '') {
+ this.set('sshKeyNullErr', true);
+ return false;
+ }
+ else {
+ this.set('sshKeyNullErr', false);
+ }
+ if (this.get('passphrase') !== this.get('confirmPassphrase')) {
+ this.set('passphraseMatchErr', true);
+ return false;
+ } else {
+ this.set('passphraseMatchErr', false);
+ }
+ }
+
+ if (this.get('localRepo') === true) {
+ if (this.get('localRepoPath') === '') {
+ this.set('softRepoLocalPathNullErr', true);
+ return false;
+ } else {
+ this.set('softRepoLocalPathNullErr', false);
+ }
+ } else {
+ this.set('softRepoLocalPathNullErr', false);
+ }
+
+
+ /** task2 task3 task4 **/
+ this.hostNameArr = this.get('hostNames').split('\s');
+ for (var i = 0; i < this.hostNameArr.length; i++) {
+ //TODO: other validation for hostnames will be covered over here
+ // For now hostname that are starting or ending with '-' are not allowed
+ if (/^\-/.test(this.hostNameArr[i]) || /\-$/.test(this.hostNameArr[i])) {
+ console.log('Invalide host name' + this.hostNameArr[i]);
+ alert('Invalide host name: ' + this.hostNameArr[i]);
+ this.set('hostNameErr', true);
+ return false;
+ } else {
+ this.set('hostNameErr', false);
+ }
+ }
+ var hostInfo = {};
+ for (var i = 0; i < this.hostNameArr.length; i++) {
+ hostInfo[this.hostNameArr[i]] = {'name': this.hostNameArr[i]};
+ // hostInfo[this.hostNameArr[i]].name = this.hostNameArr[i];
+ hostInfo[this.hostNameArr[i]].installType = this.get('InstallType');
+ }
+ App.db.setHosts(hostInfo);
+
+
+ /** task4 **/
+ var softRepoInfo = {'type': this.get('softRepo'), 'path': ''};
+
+ if ('success' == 'success') {
+ return true;
+ } else {
+ return false;
+ }
+
+ },
+ evaluateStep3: function () {
+ // TODO: evaluation at the end of step3
+ /* Not sure if below tasks are to be covered over here
+ * as these functions are meant to be called at the end of a step
+ * and the following tasks are interactive to the page and not on clicking next button.
+ *
+ * task1 will be a function called on entering step3 from step3 connectoutlet or init function in InstallerStep3 View.
+ * task2 will be a parsing function that on reaching a particular condition(all hosts are in success or faliue status) will stop task1
+ * task3 will be a function binded to remove button
+ * task4 will be a function binded to retry button
+ *
+ *
+ * keeping it over here for now
+ */
+
+
+ //task1 = start polling with rest API @Get http://ambari_server/api/bootstrap.
+ //task2 = stop polling when all the hosts have either success or failure status.
+ //task3(prerequisite = remove) = Remove set of selected hosts from the localStorage
+ //task4(prerequisite = retry) = temporarily store list of checked host and call to rest API: @Post http://ambari_server/api/bootstrap
+
+
+ },
+ evaluateStep4: function () {
+ // TODO: evaluation at the end of step4
+
+ },
+ evaluateStep5: function () {
+ // TODO: evaluation at the end of step5
+
+ },
+ evaluateStep6: function () {
+ // TODO: evaluation at the end of step6
+
+ },
+ evaluateStep7: function () {
+ // TODO: evaluation at the end of step7
+
+ },
+ evaluateStep8: function () {
+ // TODO: evaluation at the end of step8
+
+ },
prevInstallStatus: function () {
console.log('Inside the prevInstallStep function: The name is ' + App.router.get('loginController.loginName'));
- if (localStorage.getItem(App.router.get('loginController.loginName') + 'Installer' + 'isCompleted') == '1') {
+ var result = App.db.isCompleted()
+ if (result == '1') {
return true;
}
}.property('App.router.loginController.loginName'),
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/login.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/login.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/login.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/login.js Tue Sep 11 03:25:58 2012
@@ -29,10 +29,10 @@ App.LoginController = Em.Object.extend({
this.set('errorMessage', '');
if (this.validateCredentials()) {
- console.log("Logging in as: " + this.get('loginName'));
+ console.log('Logging in as: ' + this.get('loginName'));
App.get('router').login(this.get('loginName'));
} else {
- console.log("Failed to login as: " + this.get('loginName'));
+ console.log('Failed to login as: ' + this.get('loginName'));
this.set('errorMessage', App.messages.login_error);
}
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/initialize.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/initialize.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/initialize.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/initialize.js Tue Sep 11 03:25:58 2012
@@ -20,6 +20,7 @@
window.App = require('app');
require('messages');
+require('utils/db');
require('templates');
require('models');
require('controllers');
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js Tue Sep 11 03:25:58 2012
@@ -20,35 +20,55 @@
var App = require('app');
App.messages = {
- "app_name": "Ambari",
- "page_title": "Ambari",
- "installer_welcome": "Welcome to Ambari installation wizard",
- "login_error": "Invalid username/password combination.",
- "login_header": "Ambari Login",
- "username_label": "Username",
- "password_label": "Password",
- "login_button": "Login",
+ 'app_name': 'Ambari',
+ 'page_title': 'Ambari',
+ 'installer_welcome': 'Welcome to Ambari installation wizard',
+ 'login_error': 'Invalid username/password combination.',
+ 'login_header': 'Ambari Login',
+ 'username_label': 'Username',
+ 'password_label': 'Password',
+ 'login_button': 'Login',
- "step1_header": "Welcome",
- "step2_header": "Install Options",
- "step3_header": "Confirm Hosts",
- "step4_header": "Choose Services",
- "step5_header": "Assign Services",
- "step6_header": "Customize Services",
- "step7_header": "Review",
- "step8_header": "Install, Start and Test",
- "step9_header": "Summary",
- "page_footer_body": "<a href = \"http://www.apache.org/licenses/LICENSE-2.0\" target = \"_blank\">Licensed under the Apache License, Version 2.0</a>.<br><a href = \"/licenses/NOTICE.txt\" target = \"_blank\">See third-party tools/resources that Ambari uses and their respective authors</a>",
-
- "topnav_help_link": "http://incubator.apache.org/ambari/install.html",
- "welcome_header": "Welcome to Ambari!",
- "welcome_body": "<p>Ambari makes it easy for you to install, configure, and manage your Hadoop cluster.<br>First, we will walk you through setting up your cluster with a step-by-step wizard.</p>",
- "welcome_note": "Before you proceed, make sure you have performed all the pre-installation steps.",
- "welcome_submit_label": "Get started",
- "installFailed_header": "Cluster installation failed",
- "installFailed_body": "Cluster installation failed. To continue, you will need to uninstall the cluster first and re-install the cluster.",
- "installFailed_submit_label": "Start the uninstall process",
- "uninstallFailed_header": "Cluster uninstallation failed",
- "uninstallFailed_body": "Failed to uninstall the cluster"
+ 'step1_header': 'Welcome',
+ 'step2_header': 'Install Options',
+ 'step3_header': 'Confirm Hosts',
+ 'step4_header': 'Choose Services',
+ 'step5_header': 'Assign Services',
+ 'step6_header': 'Customize Services',
+ 'step7_header': 'Review',
+ 'step8_header': 'Install, Start and Test',
+ 'step9_header': 'Summary',
+ 'page_footer_body': '<a href = \"http://www.apache.org/licenses/LICENSE-2.0\" target = \"_blank\">Licensed under the ' +
+ 'Apache License, Version 2.0</a>.<br><a href = \"/licenses/NOTICE.txt\" target = \"_blank\">See third-party ' +
+ 'tools/resources that Ambari uses and their respective authors</a>',
+ 'step1_clusterName_error_null': 'Cluster Name cannot be null value',
+ 'step1_clusterName_error_Whitespaces': 'Cluster Name cannot contain white spaces',
+ 'step1_clusterName_error_specialChar': 'Cluster Name cannot have hyphen as first or last alphabet',
+ 'topnav_help_link': 'http://incubator.apache.org/ambari/install.html',
+ 'welcome_header': 'Welcome to Ambari!',
+ 'step2_targetHosts': '<p>Enter a list of host names, one per line. Or use <a href=\"javascript:void 0\"> ' +
+ 'Pattern expression</a> </p>',
+ 'step2_targetHosts_label': 'Specify Hosts to Manage',
+ 'step2_hostNameEmptyError': 'host names cannot be left empty',
+ 'step2_sshKeyNullErr': 'ssh key cannot be empty' ,
+ 'step2_passphraseMatchErr': '\"Confirm passphrase\" doesn\'t matches \"passphrase\" value',
+ 'step2_hostNameNotRequireErr' : 'Host names not required for manual install of ambari agents',
+ 'step2_softRepo_default_localPath': '/etc/yum/repos.d/hdp',
+ 'step2_softRepo_remotePath': '',
+ 'step2_advancedOption_label': 'Advanced Options',
+ 'step2_repoConf_label': 'Yum Repository Configuration File Path',
+ 'step2_localRepoExplan': '<p>The repository configuration file should be installed on each host in your cluster. ' +
+ 'This file instructs package manager to use your local software repository to retrieve software packages,instead of ' +
+ 'using internet.</p>',
+ 'welcome_body': '<p>Ambari makes it easy for you to install, configure, and manage your Hadoop cluster.<br>First, ' +
+ 'we will walk you through setting up your cluster with a step-by-step wizard.</p>',
+ 'welcome_note': 'Before you proceed, make sure you have performed all the pre-installation steps.',
+ 'welcome_submit_label': 'Get started',
+ 'installFailed_header': 'Cluster installation failed',
+ 'installFailed_body': 'Cluster installation failed. To continue, you will need to uninstall the cluster first and ' +
+ 're-install the cluster.',
+ 'installFailed_submit_label': 'Start the uninstall process',
+ 'uninstallFailed_header': 'Cluster uninstallation failed',
+ 'uninstallFailed_body': 'Failed to uninstall the cluster'
};
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js Tue Sep 11 03:25:58 2012
@@ -22,14 +22,13 @@ App.Router = Em.Router.extend({
setInstallerCurrentStep: function (currentStep, completed) {
var loginName = this.getLoginName();
- localStorage.setItem(loginName + 'Installer' + 'currentStep', currentStep);
- localStorage.setItem(loginName + 'Installer' + 'completed', completed);
+ App.db.setInstallerCurrentStep(currentStep, completed);
this.set('installerController.currentStep', currentStep);
},
getInstallerCurrentStep: function () {
var loginName = this.getLoginName();
- var currentStep = localStorage.getItem(loginName + 'Installer' + 'currentStep');
+ var currentStep = App.db.getInstallerCurrentStep();
console.log('getInstallerCurrentStep: loginName=' + loginName + ", currentStep=" + currentStep);
if (!currentStep) {
currentStep = '1';
@@ -42,44 +41,53 @@ App.Router = Em.Router.extend({
getAuthenticated: function () {
// TODO: this needs to be hooked up with server authentication
- var auth = localStorage.getItem('Ambari' + 'authenticated');
- var authResp = (auth && auth === 'true');
+ var auth = App.db.getAuthenticated();
+ var authResp = (auth && auth === true);
this.set('loggedIn', authResp);
return authResp;
},
setAuthenticated: function (authenticated) {
// TODO: this needs to be hooked up with server authentication
- localStorage.setItem('Ambari' + 'authenticated', authenticated);
+ console.log("TRACE: Entering router:setAuthenticated function");
+ App.db.setAuthenticated(authenticated);
this.set('loggedIn', authenticated);
},
getLoginName: function () {
// TODO: this needs to be hooked up with server authentication
- return localStorage.getItem('Ambari' + 'loginName');
+ return App.db.getLoginName();
+ //return localStorage.getItem('Ambari' + 'loginName');
},
setLoginName: function (loginName) {
// TODO: this needs to be hooked up with server authentication
- localStorage.setItem('Ambari' + 'loginName', loginName);
+ App.db.setLoginName(loginName);
+ //localStorage.setItem('Ambari' + 'loginName', loginName);
},
login: function (loginName) {
// TODO: this needs to be hooked up with server authentication
+ console.log("In login function");
this.setAuthenticated(true);
this.setLoginName(loginName);
this.transitionTo(this.getSection());
+
},
defaultSection: 'installer',
getSection: function () {
+ var section = App.db.getSection();
+ console.log("The section is: " + section);
var section = localStorage.getItem(this.getLoginName() + 'section');
+
return section || this.defaultSection;
+
},
- setSection: function(section) {
- localStorage.setItem(this.getLoginName() + 'section', section);
+ setSection: function (section) {
+ App.db.setSection(section);
},
root: Em.Route.extend({
@@ -107,7 +115,6 @@ App.Router = Em.Router.extend({
console.log('/login:connectOutlet');
console.log('currentStep is: ' + router.getInstallerCurrentStep());
console.log('authenticated is: ' + router.getAuthenticated());
-
router.get('applicationController').connectOutlet('login', App.LoginView);
}
}),
@@ -118,8 +125,7 @@ App.Router = Em.Router.extend({
logoff: function (router, context) {
console.log('logging off');
- router.setAuthenticated(false);
- router.setLoginName('');
+ App.db.cleanUp();
router.set('loginController.loginName', '');
router.set('loginController.password', '');
router.transitionTo('login', context);
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js Tue Sep 11 03:25:58 2012
@@ -23,10 +23,13 @@ module.exports = Em.Route.extend({
console.log('in /installer:enter');
if (router.getAuthenticated()) {
+ console.log('In installer and its authenticated!!!');
Ember.run.next(function () {
router.transitionTo('step' + router.getInstallerCurrentStep());
});
} else {
+ console.log('In installer but its not authenticated');
+ console.log('value of authenticated is: ' + router.getAuthenticated());
Ember.run.next(function () {
router.transitionTo('login');
});
@@ -45,7 +48,16 @@ module.exports = Em.Route.extend({
router.setInstallerCurrentStep('1', false);
router.get('installerController').connectOutlet('installerStep1');
},
- next: Em.Router.transitionTo('step2')
+ next: function (router, context) {
+ console.log('In step1 transiting to step2');
+ var result = router.get('installerController').evaluateStep1();
+ if (result === true) {
+ App.InstallerStep1View.remove;
+ router.transitionTo('step2');
+ } else {
+ router.get('installerController').connectOutlet('installerStep1');
+ }
+ }
}),
step2: Em.Route.extend({
@@ -55,7 +67,13 @@ module.exports = Em.Route.extend({
router.get('installerController').connectOutlet('installerStep2');
},
back: Em.Router.transitionTo('step1'),
- next: Em.Router.transitionTo('step3')
+ next: function (router, context) {
+ console.log('In step2 transiting to step3');
+ var result = router.get('installerController').evaluateStep2();
+ if (result) {
+ router.transitionTo('step3');
+ }
+ }
}),
step3: Em.Route.extend({
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js Tue Sep 11 03:25:58 2012
@@ -29,10 +29,10 @@ module.exports = Em.Route.extend({
if (router.getAuthenticated()) {
// TODO: redirect to last known state
/*
- Ember.run.next(function () {
- router.transitionTo('step' + router.getInstallerCurrentStep());
- });
- */
+ Ember.run.next(function () {
+ router.transitionTo('step' + router.getInstallerCurrentStep());
+ });
+ */
} else {
Ember.run.next(function () {
router.transitionTo('login');
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step1.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step1.hbs?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step1.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step1.hbs Tue Sep 11 03:25:58 2012
@@ -18,10 +18,31 @@
<h2>{{App.messages.step1_header}}</h2>
+{{#view App.Step1ParentView}}
+
+{{#if validClusterName}}
+{{#view App.Step1ChildView}}
<div>
- Name of your cluster
+ <label><strong>Name of Your Cluster</strong></label>
+ {{view Ember.TextField valueBinding="clusterName" target="controller"}}
+</div>
+{{/view}}
+
+{{else}}
+{{#view App.Step1ChildErrView}}
+<div class="control-group error">
+ <label class="control-label" for="inputError"><strong>Name of Your Cluster</strong></label>
+
+ <div class="controls">
+ {{view Ember.TextField id="inputError" valueBinding="clusterName" target="controller"}}
+ <p class="help-inline">{{errorMsg_clusterName}}</p>
+ </div>
</div>
-{{view Ember.TextField valueBinding="clusterName" target="controller"}}
+{{/view}}
+{{/if}}
+
+
<div>
-<a class="btn btn-success" {{action submit target="view"}}>Next</a>
+ <a class="btn btn-success" {{action next}}>Next</a>
</div>
+{{/view}}
\ No newline at end of file
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step2.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step2.hbs?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step2.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step2.hbs Tue Sep 11 03:25:58 2012
@@ -16,7 +16,85 @@
* limitations under the License.
-->
-
<h2>{{App.messages.step2_header}}</h2>
-<a class="btn" {{action back}}>Back</a>
-<a class="btn btn-success" {{action next}}>Next</a>
\ No newline at end of file
+{{#view App.Step2_parentView}}
+
+
+{{#view App.Step2_child_HostManageView}}
+
+<h5 {{bindAttr class="hostManageErr:text-error"}}> {{App.messages.step2_targetHosts_label}}</h5>
+{{{App.messages.step2_targetHosts}}}
+{{view Ember.TextArea valueBinding="hostNames" rows="5"}}
+{{#if hostNameEmptyError}}
+<p class="text-error">{{App.messages.step2_hostNameEmptyError}}</p>
+{{/if}}
+{{#if hostNameNotRequireErr}}
+<p class="text-error">{{App.messages.step2_hostNameNotRequireErr}}</p>
+{{/if}}
+
+<div id="hostConnectId">
+
+ <p>Install Ambari agents automatically via passwordless SSH</p>
+
+ <div class="ambari-agents">
+ <ul class="unstyled">
+ <li>{{view Ember.TextField type="text" placeholder="ssh private key" valueBinding="sshKey"}}</li>
+ {{#if chooseFile}}
+ <form name='hostConnectOption' enctype="multipart/form-data" method="post">
+ <fieldset>
+ <input type="file" name="clusterDeployUserIdentityFile" id="clusterDeployUserIdentityFileId"
+ value="">
+ </fieldset>
+ </form>
+ {{/if}}
+
+ {{#if sshKeyNullErr}}
+ <p class="text-error">{{App.messages.step2_sshKeyNullErr}}</p>
+ {{/if}}
+
+ <li>{{view Ember.TextField type="text" placeholder="passphrase" valueBinding="passphrase"}} </li>
+
+
+ <li>{{view Ember.TextField type="text" placeholder="confirm passphrase" valueBinding="confirmPassphrase"}}</li>
+
+ {{#if passphraseMatchErr}}
+ <p class="text-error">{{App.messages.step2_passphraseMatchErr}}</p>
+ {{/if}}
+ </ul>
+ </div>
+
+</div>
+{{/view}}
+
+
+<!--style="position:relative;"-->
+{{#view App.Step2_child_AdvOpt}}
+
+<h5 {{bindAttr class="advOptErr:text-error"}}>{{App.messages.step2_advancedOption_label}}</h5>
+<label class="checkbox">
+ Manually install Ambari agents on all the hosts <a href="javascript:void 0">Learn more</a>
+ {{view Ember.Checkbox checkedBinding="manualInstall"}}
+</label>
+<label class="checkbox">
+ use a local software repository <a href="javascript:void 0">Learn more</a>
+ {{view Ember.Checkbox checkedBinding="localRepo"}}
+</label>
+{{#if localRepo}}
+<div>
+ <label>{{App.messages.step2_repoConf_label}}</label>
+ {{view Ember.TextField type="text" placeholder="/etc/yum/repos.d/hdp" valueBinding="localRepoPath"}}
+ {{#if softRepoLocalPathNullErr}}
+ <p class="text-error">Local repository file path cannot be null</p>
+ {{/if}}
+ {{{App.messages.step2_localRepoExplan}}}
+</div>
+{{/if}}
+{{/view}}
+
+{{/view}}
+<a class="btn" {{action back}}>Previous</a>
+<a class="btn btn-success" {{action next}}>Discover and Validate</a>
+
+
+
+
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step3.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step3.hbs?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step3.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step3.hbs Tue Sep 11 03:25:58 2012
@@ -18,5 +18,7 @@
<h2>{{App.messages.step3_header}} </h2>
+<a class="btn" {{action retry}}>Retry</a>
+<a class="btn" {{action remove}}>Remove</a> <br/>
<a class="btn" {{action back}}>Back</a>
<a class="btn btn-success" {{action next}}>Next</a>
\ No newline at end of file
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main.hbs?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main.hbs Tue Sep 11 03:25:58 2012
@@ -16,5 +16,5 @@
* limitations under the License.
-->
-
+ <!--Monitoring and managing services -->
<h2>Main Application</h2>
\ No newline at end of file
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js Tue Sep 11 03:25:58 2012
@@ -16,10 +16,10 @@
* limitations under the License.
*/
var App = require('app');
+App.db = {};
-
-Storage.prototype.setObject = function(key, value) {
+Storage.prototype.setObject = function(key,value) {
this.setItem(key, JSON.stringify(value));
}
@@ -28,30 +28,183 @@ Storage.prototype.getObject = function(k
return value && JSON.parse(value);
}
-App.DB = {
- name: '',
- work_id: ''
+
+App.db.cleanUp = function() {
+ console.log('TRACE: Entering db:cleanup function');
+ App.db.data = {
+ 'app' : {
+ 'loginName' : '',
+ 'authenticated' : false
+ }
+ }
+ localStorage.setObject('ambari',App.db.data);
+}
+
+// called whenever user logs in
+if(localStorage.getObject('ambari') == null) {
+ console.log('doing a cleanup');
+ App.db.cleanUp();
}
-App.storage = Ember.Object.extend ({
- /*
- getter methods
- */
+/*
+ * setter methods
+ */
+
+App.db.setLoginName = function(name) {
+ console.log('TRACE: Entering db:setLoginName function');
+ App.db.data = localStorage.getObject('ambari');
+ App.db.data.app.loginName = name;
+ localStorage.setObject('ambari',App.db.data);
+}
+
+App.db.setAuthenticated = function(authenticated) {
+ console.log('TRACE: Entering db:setAuthenticated function');
+
+ App.db.data = localStorage.getObject('ambari');
+ console.log('present value of authentication is: ' + App.db.data.app.authenticated);
+ console.log('desired value of authentication is: ' + authenticated) ;
+ App.db.data.app.authenticated = authenticated;
+ localStorage.setObject('ambari',App.db.data);
+ App.db.data = localStorage.getObject('ambari');
+ console.log('Now present value of authentication is: ' + App.db.data.app.authenticated);
+}
- setInitialVal: function() {
+App.db.setSection = function(section) {
+ console.log('TRACE: Entering db:setSection function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined) {
+ App.db.data[user] = {'name':user};
+ }
+ if (App.db.data[user].ClusterName == undefined) {
+ App.db.data[user].ClusterName = {};
+ }
+ App.db.data[user].section = section;
+ localStorage.setObject('ambari',App.db.data);
+}
- },
- getAuthVal: function() {
+App.db.setInstallerCurrentStep = function (currentStep, completed) {
+ console.log('TRACE: Entering db:setInstallerCurrentStep function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined) {
+ console.log('In data[user] condition');
+ App.db.data[user] = {'name':user};
+ console.log('value of data[user].name: '+ App.db.data[user].name);
+ }
+ if (App.db.data[user].Installer == undefined) {
+ App.db.data[user].Installer = {};
+ console.log('');
+ }
+ App.db.data[user].Installer.currentStep = currentStep;
+ App.db.data[user].Installer.completed = completed;
+ localStorage.setObject('ambari',App.db.data);
+}
+App.db.setClusterName = function(name) {
+ console.log('TRACE: Entering db:setClusterName function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ // all information from Installer.ClusterName will be transferred to clusters[ClusterName] when app migrates from installer to main
+ if(App.db.data[user] == undefined) {
+ App.db.data[user] = {'name':user};
+ }
+ if (App.db.data[user].clusters == undefined) {
+ App.db.data[user].clusters = {};
}
+ if (App.db.data[user].Installer == undefined) {
+ App.db.data[user].Installer = {};
+ }
+ App.db.data[user].Installer.ClusterName = name;
+ localStorage.setObject('ambari',App.db.data);
+}
- /*
- setter methods
- */
+App.db.setHosts = function(hostInfo) {
+ console.log('TRACE: Entering db:setHosts function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined) {
+ App.db.data[user] = {'name':user};
+ }
+ App.db.data[user].Installer.hostInfo = hostInfo;
+ localStorage.setObject('ambari',App.db.data);
+}
+App.db.setSoftRepo = function(softRepo) {
+ console.log('TRACE: Entering db:setSoftRepo function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined) {
+ App.db.data[user] = {'name':user};
+ App.db.data[user].Installer.softRepo = softRepo;
+ localStorage.setObject('ambari',App.db.data);
+ }
+}
+
+
+/*
+ * getter methods
+ */
+
+App.db.getLoginName = function() {
+ console.log('Trace: Entering db:getLoginName function');
+ App.db.data = localStorage.getObject('ambari');
+ return App.db.data.app.loginName;
+}
+
+App.db.getAuthenticated = function() {
+ console.log('Trace: Entering db:getAuthenticated function');
+ App.db.data = localStorage.getObject('ambari');
+ return App.db.data.app.authenticated;
+}
+
+App.db.getSection = function() {
+ console.log('Trace: Entering db:getSection function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName
+ if(App.db.data[user] == undefined || App.db.data[user] == '') {
+ return 0;
+ }
+ return App.db.data[user].section;
+}
+
+App.db.getClusterName = function() {
+ console.log('Trace: Entering db:getClusterName function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(user) {
+ return App.db.data[user].Installer.ClusterName;
+ }
+}
+
+App.db.getInstallerCurrentStep = function() {
+ console.log('Trace: Entering db:getInstallerCurrentStep function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined || App.db.data[user] == '') {
+ return 0;
+ }
+ return App.db.data[user].Installer.currentStep;
+}
+
+App.db.isCompleted = function() {
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ return App.db.data[user].Installer.completed;
+}
+
+App.db.getHosts = function(name,hostInfo) {
+ console.log('TRACE: Entering db:getHosts function');
+ App.db.data = localStorage.getObject('ambari');
+ var user = App.db.data.app.loginName;
+ if(App.db.data[user] == undefined || App.db.data[user] == '') {
+ console.log('ERROR: loginName required for storing host info');
+ return 0;
+ }
+ return App.db.data[user].Installer.hostInfo;
+}
-});
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step1.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step1.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step1.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step1.js Tue Sep 11 03:25:58 2012
@@ -21,10 +21,21 @@ var App = require('app');
App.InstallerStep1View = Em.View.extend({
- templateName: require('templates/installer/step1'),
+ templateName: require('templates/installer/step1')
- submit: function(e) {
- //alert(this.get('controller.clusterName'));
- App.router.transitionTo('step2');
- }
+});
+
+App.Step1ParentView = Em.View.extend({
+
+});
+
+App.Step1ChildView = Em.View.extend({
+ classNameBindings: ['isEnabled::disabled'],
+ isEnabled: false
+
+});
+
+App.Step1ChildErrView = Em.View.extend({
+ classNameBindings: ['isEnabled::enabled'],
+ isEnabled: true
});
\ No newline at end of file
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step2.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step2.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step2.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step2.js Tue Sep 11 03:25:58 2012
@@ -4,13 +4,13 @@
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
+ * 'License'); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
+ * distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
@@ -21,10 +21,50 @@ var App = require('app');
App.InstallerStep2View = Em.View.extend({
- templateName: require('templates/installer/step2'),
+ templateName: require('templates/installer/step2'),
- submit: function(router, event) {
- alert('form2 submitted');
- }
+ doManualInstall: function (router, event) {
+ if (typeof jQuery != 'undefined') {
+
+ console.log('jQuery library is loaded!');
-});
\ No newline at end of file
+ }
+ console.log('value is: ' + $('#hostConnectId h2').text());
+ console.log('over here');
+ //alert('value is:' + $('hostConnectId').('connect-opt').value);
+ }
+
+});
+
+App.Step2_parentView = Em.View.extend({
+ isVisible: true,
+ click: function () {
+ console.log('parent of step2');
+ }
+});
+
+App.Step2_parent_TargetHostView = Em.View.extend({
+ ///
+
+ ///
+ isVisible: true,
+ click: function () {
+ console.log('target hosts: child of step2');
+ }
+});
+
+App.Step2_child_HostManageView = Em.View.extend({
+ isVisible: true,
+ click: function () {
+ console.log('host management: child of step2');
+ }
+
+});
+
+
+App.Step2_child_AdvOpt = Em.View.extend({
+ isVisible: true,
+ click: function () {
+ console.log('Soft Repo: parent of step2');
+ }
+});
Modified: incubator/ambari/branches/AMBARI-666/ambari-web/vendor/scripts/bootstrap.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/vendor/scripts/bootstrap.js?rev=1383233&r1=1383232&r2=1383233&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/vendor/scripts/bootstrap.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/vendor/scripts/bootstrap.js Tue Sep 11 03:25:58 2012
@@ -1,5 +1,5 @@
/* ===================================================
- * bootstrap-transition.js v2.0.4
+ * bootstrap-transition.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#transitions
* ===================================================
* Copyright 2012 Twitter, Inc.
@@ -36,8 +36,7 @@
, transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd'
, 'MozTransition' : 'transitionend'
- , 'OTransition' : 'oTransitionEnd'
- , 'msTransition' : 'MSTransitionEnd'
+ , 'OTransition' : 'oTransitionEnd otransitionend'
, 'transition' : 'transitionend'
}
, name
@@ -59,7 +58,7 @@
})
}(window.jQuery);/* ==========================================================
- * bootstrap-alert.js v2.0.4
+ * bootstrap-alert.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#alerts
* ==========================================================
* Copyright 2012 Twitter, Inc.
@@ -148,7 +147,7 @@
})
}(window.jQuery);/* ============================================================
- * bootstrap-button.js v2.0.4
+ * bootstrap-button.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#buttons
* ============================================================
* Copyright 2012 Twitter, Inc.
@@ -200,7 +199,7 @@
}
Button.prototype.toggle = function () {
- var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
+ var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
$parent && $parent
.find('.active')
@@ -243,7 +242,7 @@
})
}(window.jQuery);/* ==========================================================
- * bootstrap-carousel.js v2.0.4
+ * bootstrap-carousel.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#carousel
* ==========================================================
* Copyright 2012 Twitter, Inc.
@@ -290,7 +289,7 @@
}
, to: function (pos) {
- var $active = this.$element.find('.active')
+ var $active = this.$element.find('.item.active')
, children = $active.parent().children()
, activePos = children.index($active)
, that = this
@@ -312,6 +311,10 @@
, pause: function (e) {
if (!e) this.paused = true
+ if (this.$element.find('.next, .prev').length && $.support.transition.end) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle()
+ }
clearInterval(this.interval)
this.interval = null
return this
@@ -328,13 +331,15 @@
}
, slide: function (type, next) {
- var $active = this.$element.find('.active')
+ var $active = this.$element.find('.item.active')
, $next = next || $active[type]()
, isCycling = this.interval
, direction = type == 'next' ? 'left' : 'right'
, fallback = type == 'next' ? 'first' : 'last'
, that = this
- , e = $.Event('slide')
+ , e = $.Event('slide', {
+ relatedTarget: $next[0]
+ })
this.sliding = true
@@ -382,9 +387,10 @@
var $this = $(this)
, data = $this.data('carousel')
, options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
+ , action = typeof option == 'string' ? option : options.slide
if (!data) $this.data('carousel', (data = new Carousel(this, options)))
if (typeof option == 'number') data.to(option)
- else if (typeof option == 'string' || (option = options.slide)) data[option]()
+ else if (action) data[action]()
else if (options.interval) data.cycle()
})
}
@@ -411,7 +417,7 @@
})
}(window.jQuery);/* =============================================================
- * bootstrap-collapse.js v2.0.4
+ * bootstrap-collapse.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#collapse
* =============================================================
* Copyright 2012 Twitter, Inc.
@@ -479,7 +485,7 @@
this.$element[dimension](0)
this.transition('addClass', $.Event('show'), 'shown')
- this.$element[dimension](this.$element[0][scroll])
+ $.support.transition && this.$element[dimension](this.$element[0][scroll])
}
, hide: function () {
@@ -556,18 +562,19 @@
* ==================== */
$(function () {
- $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
+ $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
var $this = $(this), href
, target = $this.attr('data-target')
|| e.preventDefault()
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
, option = $(target).data('collapse') ? 'toggle' : $this.data()
+ $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
$(target).collapse(option)
})
})
}(window.jQuery);/* ============================================================
- * bootstrap-dropdown.js v2.0.4
+ * bootstrap-dropdown.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#dropdowns
* ============================================================
* Copyright 2012 Twitter, Inc.
@@ -594,7 +601,7 @@
/* DROPDOWN CLASS DEFINITION
* ========================= */
- var toggle = '[data-toggle="dropdown"]'
+ var toggle = '[data-toggle=dropdown]'
, Dropdown = function (element) {
var $el = $(element).on('click.dropdown.data-api', this.toggle)
$('html').on('click.dropdown.data-api', function () {
@@ -609,34 +616,82 @@
, toggle: function (e) {
var $this = $(this)
, $parent
- , selector
, isActive
if ($this.is('.disabled, :disabled')) return
- selector = $this.attr('data-target')
+ $parent = getParent($this)
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ $parent.toggleClass('open')
+ $this.focus()
}
- $parent = $(selector)
- $parent.length || ($parent = $this.parent())
+ return false
+ }
+
+ , keydown: function (e) {
+ var $this
+ , $items
+ , $active
+ , $parent
+ , isActive
+ , index
+
+ if (!/(38|40|27)/.test(e.keyCode)) return
+
+ $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ $parent = getParent($this)
isActive = $parent.hasClass('open')
- clearMenus()
+ if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
- if (!isActive) $parent.toggleClass('open')
+ $items = $('[role=menu] li:not(.divider) a', $parent)
- return false
+ if (!$items.length) return
+
+ index = $items.index($items.filter(':focus'))
+
+ if (e.keyCode == 38 && index > 0) index-- // up
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items
+ .eq(index)
+ .focus()
}
}
function clearMenus() {
- $(toggle).parent().removeClass('open')
+ getParent($(toggle))
+ .removeClass('open')
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+ , $parent
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.length || ($parent = $this.parent())
+
+ return $parent
}
@@ -659,14 +714,16 @@
* =================================== */
$(function () {
- $('html').on('click.dropdown.data-api', clearMenus)
+ $('html')
+ .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)
$('body')
- .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
+ .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
})
}(window.jQuery);/* =========================================================
- * bootstrap-modal.js v2.0.4
+ * bootstrap-modal.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#modals
* =========================================================
* Copyright 2012 Twitter, Inc.
@@ -693,10 +750,11 @@
/* MODAL CLASS DEFINITION
* ====================== */
- var Modal = function (content, options) {
+ var Modal = function (element, options) {
this.options = options
- this.$element = $(content)
+ this.$element = $(element)
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+ this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
}
Modal.prototype = {
@@ -719,8 +777,9 @@
this.isShown = true
- escape.call(this)
- backdrop.call(this, function () {
+ this.escape()
+
+ this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
@@ -734,7 +793,12 @@
that.$element[0].offsetWidth // force reflow
}
- that.$element.addClass('in')
+ that.$element
+ .addClass('in')
+ .attr('aria-hidden', false)
+ .focus()
+
+ that.enforceFocus()
transition ?
that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
@@ -758,90 +822,98 @@
$('body').removeClass('modal-open')
- escape.call(this)
+ this.escape()
+
+ $(document).off('focusin.modal')
- this.$element.removeClass('in')
+ this.$element
+ .removeClass('in')
+ .attr('aria-hidden', true)
$.support.transition && this.$element.hasClass('fade') ?
- hideWithTransition.call(this) :
- hideModal.call(this)
+ this.hideWithTransition() :
+ this.hideModal()
}
- }
-
-
- /* MODAL PRIVATE METHODS
- * ===================== */
+ , enforceFocus: function () {
+ var that = this
+ $(document).on('focusin.modal', function (e) {
+ if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
+ that.$element.focus()
+ }
+ })
+ }
- function hideWithTransition() {
- var that = this
- , timeout = setTimeout(function () {
- that.$element.off($.support.transition.end)
- hideModal.call(that)
- }, 500)
+ , escape: function () {
+ var that = this
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keyup.dismiss.modal', function ( e ) {
+ e.which == 27 && that.hide()
+ })
+ } else if (!this.isShown) {
+ this.$element.off('keyup.dismiss.modal')
+ }
+ }
- this.$element.one($.support.transition.end, function () {
- clearTimeout(timeout)
- hideModal.call(that)
- })
- }
+ , hideWithTransition: function () {
+ var that = this
+ , timeout = setTimeout(function () {
+ that.$element.off($.support.transition.end)
+ that.hideModal()
+ }, 500)
- function hideModal(that) {
- this.$element
- .hide()
- .trigger('hidden')
+ this.$element.one($.support.transition.end, function () {
+ clearTimeout(timeout)
+ that.hideModal()
+ })
+ }
- backdrop.call(this)
- }
+ , hideModal: function (that) {
+ this.$element
+ .hide()
+ .trigger('hidden')
- function backdrop(callback) {
- var that = this
- , animate = this.$element.hasClass('fade') ? 'fade' : ''
+ this.backdrop()
+ }
- if (this.isShown && this.options.backdrop) {
- var doAnimate = $.support.transition && animate
+ , removeBackdrop: function () {
+ this.$backdrop.remove()
+ this.$backdrop = null
+ }
- this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
- .appendTo(document.body)
+ , backdrop: function (callback) {
+ var that = this
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
- if (this.options.backdrop != 'static') {
- this.$backdrop.click($.proxy(this.hide, this))
- }
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+ .appendTo(document.body)
- this.$backdrop.addClass('in')
+ if (this.options.backdrop != 'static') {
+ this.$backdrop.click($.proxy(this.hide, this))
+ }
- doAnimate ?
- this.$backdrop.one($.support.transition.end, callback) :
- callback()
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
- } else if (!this.isShown && this.$backdrop) {
- this.$backdrop.removeClass('in')
+ this.$backdrop.addClass('in')
- $.support.transition && this.$element.hasClass('fade')?
- this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
- removeBackdrop.call(this)
+ doAnimate ?
+ this.$backdrop.one($.support.transition.end, callback) :
+ callback()
- } else if (callback) {
- callback()
- }
- }
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
- function removeBackdrop() {
- this.$backdrop.remove()
- this.$backdrop = null
- }
+ $.support.transition && this.$element.hasClass('fade')?
+ this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) :
+ this.removeBackdrop()
- function escape() {
- var that = this
- if (this.isShown && this.options.keyboard) {
- $(document).on('keyup.dismiss.modal', function ( e ) {
- e.which == 27 && that.hide()
- })
- } else if (!this.isShown) {
- $(document).off('keyup.dismiss.modal')
- }
+ } else if (callback) {
+ callback()
+ }
+ }
}
@@ -873,17 +945,23 @@
$(function () {
$('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
- var $this = $(this), href
- , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
- , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
+ var $this = $(this)
+ , href = $this.attr('href')
+ , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+ , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
e.preventDefault()
- $target.modal(option)
+
+ $target
+ .modal(option)
+ .one('hide', function () {
+ $this.focus()
+ })
})
})
}(window.jQuery);/* ===========================================================
- * bootstrap-tooltip.js v2.0.4
+ * bootstrap-tooltip.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#tooltips
* Inspired by the original jQuery.tipsy by Jason Frame
* ===========================================================
@@ -928,11 +1006,13 @@
this.options = this.getOptions(options)
this.enabled = true
- if (this.options.trigger != 'manual') {
- eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
+ if (this.options.trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (this.options.trigger != 'manual') {
+ eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
- this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
this.options.selector ?
@@ -1032,20 +1112,11 @@
}
}
- , isHTML: function(text) {
- // html string detection logic adapted from jQuery
- return typeof text != 'string'
- || ( text.charAt(0) === "<"
- && text.charAt( text.length - 1 ) === ">"
- && text.length >= 3
- ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
- }
-
, setContent: function () {
var $tip = this.tip()
, title = this.getTitle()
- $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
$tip.removeClass('fade in top bottom left right')
}
@@ -1069,6 +1140,8 @@
$.support.transition && this.$tip.hasClass('fade') ?
removeWithAnimation() :
$tip.remove()
+
+ return this
}
, fixTitle: function () {
@@ -1128,6 +1201,10 @@
this[this.tip().hasClass('in') ? 'hide' : 'show']()
}
+ , destroy: function () {
+ this.hide().$element.off('.' + this.type).removeData(this.type)
+ }
+
}
@@ -1154,11 +1231,12 @@
, trigger: 'hover'
, title: ''
, delay: 0
+ , html: true
}
}(window.jQuery);
/* ===========================================================
- * bootstrap-popover.js v2.0.4
+ * bootstrap-popover.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#popovers
* ===========================================================
* Copyright 2012 Twitter, Inc.
@@ -1185,7 +1263,7 @@
/* POPOVER PUBLIC CLASS DEFINITION
* =============================== */
- var Popover = function ( element, options ) {
+ var Popover = function (element, options) {
this.init('popover', element, options)
}
@@ -1202,8 +1280,8 @@
, title = this.getTitle()
, content = this.getContent()
- $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
- $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)
$tip.removeClass('fade top bottom left right in')
}
@@ -1230,6 +1308,10 @@
return this.$tip
}
+ , destroy: function () {
+ this.hide().$element.off('.' + this.type).removeData(this.type)
+ }
+
})
@@ -1250,12 +1332,13 @@
$.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
placement: 'right'
+ , trigger: 'click'
, content: ''
, template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
})
}(window.jQuery);/* =============================================================
- * bootstrap-scrollspy.js v2.0.4
+ * bootstrap-scrollspy.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
* =============================================================
* Copyright 2012 Twitter, Inc.
@@ -1279,15 +1362,15 @@
"use strict"; // jshint ;_;
- /* SCROLLSPY CLASS DEFINITION
- * ========================== */
+ /* SCROLLSPY CLASS DEFINITION
+ * ========================== */
- function ScrollSpy( element, options) {
+ function ScrollSpy(element, options) {
var process = $.proxy(this.process, this)
, $element = $(element).is('body') ? $(window) : $(element)
, href
this.options = $.extend({}, $.fn.scrollspy.defaults, options)
- this.$scrollElement = $element.on('scroll.scroll.data-api', process)
+ this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
this.selector = (this.options.target
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|| '') + ' .nav li > a'
@@ -1314,7 +1397,7 @@
, href = $el.data('target') || $el.attr('href')
, $href = /^#\w/.test(href) && $(href)
return ( $href
- && href.length
+ && $href.length
&& [[ $href.position().top, href ]] ) || null
})
.sort(function (a, b) { return a[0] - b[0] })
@@ -1364,7 +1447,7 @@
.parent('li')
.addClass('active')
- if (active.parent('.dropdown-menu')) {
+ if (active.parent('.dropdown-menu').length) {
active = active.closest('li.dropdown').addClass('active')
}
@@ -1377,7 +1460,7 @@
/* SCROLLSPY PLUGIN DEFINITION
* =========================== */
- $.fn.scrollspy = function ( option ) {
+ $.fn.scrollspy = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('scrollspy')
@@ -1397,7 +1480,7 @@
/* SCROLLSPY DATA-API
* ================== */
- $(function () {
+ $(window).on('load', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
$spy.scrollspy($spy.data())
@@ -1405,7 +1488,7 @@
})
}(window.jQuery);/* ========================================================
- * bootstrap-tab.js v2.0.4
+ * bootstrap-tab.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#tabs
* ========================================================
* Copyright 2012 Twitter, Inc.
@@ -1432,7 +1515,7 @@
/* TAB CLASS DEFINITION
* ==================== */
- var Tab = function ( element ) {
+ var Tab = function (element) {
this.element = $(element)
}
@@ -1539,7 +1622,7 @@
})
}(window.jQuery);/* =============================================================
- * bootstrap-typeahead.js v2.0.4
+ * bootstrap-typeahead.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#typeahead
* =============================================================
* Copyright 2012 Twitter, Inc.
@@ -1617,17 +1700,23 @@
}
, lookup: function (event) {
- var that = this
- , items
- , q
+ var items
this.query = this.$element.val()
- if (!this.query) {
+ if (!this.query || this.query.length < this.options.minLength) {
return this.shown ? this.hide() : this
}
- items = $.grep(this.source, function (item) {
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
+
+ return items ? this.process(items) : this
+ }
+
+ , process: function (items) {
+ var that = this
+
+ items = $.grep(items, function (item) {
return that.matcher(item)
})
@@ -1708,8 +1797,8 @@
.on('keypress', $.proxy(this.keypress, this))
.on('keyup', $.proxy(this.keyup, this))
- if ($.browser.webkit || $.browser.msie) {
- this.$element.on('keydown', $.proxy(this.keypress, this))
+ if ($.browser.chrome || $.browser.webkit || $.browser.msie) {
+ this.$element.on('keydown', $.proxy(this.keydown, this))
}
this.$menu
@@ -1717,6 +1806,40 @@
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
}
+ , move: function (e) {
+ if (!this.shown) return
+
+ switch(e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ e.preventDefault()
+ break
+
+ case 38: // up arrow
+ e.preventDefault()
+ this.prev()
+ break
+
+ case 40: // down arrow
+ e.preventDefault()
+ this.next()
+ break
+ }
+
+ e.stopPropagation()
+ }
+
+ , keydown: function (e) {
+ this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])
+ this.move(e)
+ }
+
+ , keypress: function (e) {
+ if (this.suppressKeyPressRepeat) return
+ this.move(e)
+ }
+
, keyup: function (e) {
switch(e.keyCode) {
case 40: // down arrow
@@ -1742,32 +1865,6 @@
e.preventDefault()
}
- , keypress: function (e) {
- if (!this.shown) return
-
- switch(e.keyCode) {
- case 9: // tab
- case 13: // enter
- case 27: // escape
- e.preventDefault()
- break
-
- case 38: // up arrow
- if (e.type != 'keydown') break
- e.preventDefault()
- this.prev()
- break
-
- case 40: // down arrow
- if (e.type != 'keydown') break
- e.preventDefault()
- this.next()
- break
- }
-
- e.stopPropagation()
- }
-
, blur: function (e) {
var that = this
setTimeout(function () { that.hide() }, 150)
@@ -1805,12 +1902,13 @@
, items: 8
, menu: '<ul class="typeahead dropdown-menu"></ul>'
, item: '<li><a href="#"></a></li>'
+ , minLength: 1
}
$.fn.typeahead.Constructor = Typeahead
- /* TYPEAHEAD DATA-API
+ /* TYPEAHEAD DATA-API
* ================== */
$(function () {
@@ -1822,4 +1920,108 @@
})
})
+}(window.jQuery);
+/* ==========================================================
+ * bootstrap-affix.js v2.1.1
+ * http://twitter.github.com/bootstrap/javascript.html#affix
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* AFFIX CLASS DEFINITION
+ * ====================== */
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, $.fn.affix.defaults, options)
+ this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
+ this.$element = $(element)
+ this.checkPosition()
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var scrollHeight = $(document).height()
+ , scrollTop = this.$window.scrollTop()
+ , position = this.$element.offset()
+ , offset = this.options.offset
+ , offsetBottom = offset.bottom
+ , offsetTop = offset.top
+ , reset = 'affix affix-top affix-bottom'
+ , affix
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top()
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
+
+ affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
+ false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
+ 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
+ 'top' : false
+
+ if (this.affixed === affix) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? position.top - scrollTop : null
+
+ this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
+ }
+
+
+ /* AFFIX PLUGIN DEFINITION
+ * ======================= */
+
+ $.fn.affix = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('affix')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.affix.Constructor = Affix
+
+ $.fn.affix.defaults = {
+ offset: 0
+ }
+
+
+ /* AFFIX DATA-API
+ * ============== */
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ , data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ data.offsetBottom && (data.offset.bottom = data.offsetBottom)
+ data.offsetTop && (data.offset.top = data.offsetTop)
+
+ $spy.affix(data)
+ })
+ })
+
+
}(window.jQuery);
\ No newline at end of file