Skip to content

Instantly share code, notes, and snippets.

@brigand
Forked from daimagine/LoginForm
Created June 27, 2015 18:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brigand/9b8b6986a72cff43b4cf to your computer and use it in GitHub Desktop.
Save brigand/9b8b6986a72cff43b4cf to your computer and use it in GitHub Desktop.
import React from 'react/addons';
import ReactMixin from 'react-mixin';
import ReactScriptLoaderMixin from 'react-script-loader';
export default class LoginForm extends React.Component {
constructor() {
super();
this.state = {
user: '',
password: '',
scriptLoading: true,
scriptLoadError: false,
};
}
// this function tells ReactScriptLoaderMixin where to load the script from
getScriptURL() {
return 'https://www.google.com/recaptcha/api.js';
}
// ReactScriptLoaderMixin calls this function when the script has loaded
// successfully.
onScriptLoaded() {
console.log('ReactScriptLoaderMixin: onScriptLoaded');
this.setState({scriptLoading: false});
}
// ReactScriptLoaderMixin calls this function when the script has failed to load.
onScriptError() {
console.log('ReactScriptLoaderMixin: onScriptLoaded');
this.setState({scriptLoading: false, scriptLoadError: true});
}
onScriptTagCreated() {
console.log('ReactScriptLoaderMixin: onScriptTagCreated');
}
login(e) {
e.preventDefault();
alert('will login');
}
render() {
var message = "react script loader: "
if (this.state.scriptLoading) {
message += 'loading script...';
} else if (this.state.scriptLoadError) {
message += 'loading failed';
} else {
message += 'loading succeeded';
}
console.log(message);
return(
<form role="form" id="login-form" className="login-form">
<div className="row">
<div className="form-group col-md-12">
<label className="form-label">Username</label>
<div className="controls">
<div className="input-with-icon right">
<i></i>
<input id="txtusername" type="text" name="txtusername" className="form-control"
valueLink={this.linkState('user')} />
</div>
</div>
</div>
</div>
<div className="row">
<div className="form-group col-md-12">
<label className="form-label">Password</label><span className="help"></span>
<div className="controls">
<div className="input-with-icon right"><i></i>
<input id="txtpassword" type="password" name="txtpassword" className="form-control"
valueLink={this.linkState('password')} />
</div>
</div>
</div>
</div>
<div className="row">
<div className="form-group col-md-12">
<label className="form-label">Captcha</label><span className="help"></span>
<div className="controls">
<div className="input-with-icon right"><i></i>
<div className="g-recaptcha" data-sitekey="6Lc4zggTAAAAAIQhg0kFlMA0qpy4PLyulMaPt-8-"></div>
</div>
</div>
</div>
</div>
<div className="row">
<div className="control-group col-md-12">
<div className="checkbox checkbox check-success"><a href="#">Trouble login in?</a>
<br/><br/>
<input id="checkbox1" type="checkbox" value="1" />
<label htmlFor="checkbox1">Keep me reminded</label>
</div>
</div>
</div>
<div className="row">
<div className="col-md-12">
<button type="submit" className="btn btn-primary btn-cons pull-right"
onClick={this.login.bind(this)}>Login</button>
</div>
</div>
</form>
);
}
}
ReactMixin(LoginForm.prototype, React.addons.LinkedStateMixin);
ReactMixin(LoginForm.prototype, ReactScriptLoaderMixin);
// A dictionary mapping script URLs to a dictionary mapping
// component key to component for all components that are waiting
// for the script to load.
var scriptObservers = {};
// A dictionary mapping script URL to a boolean value indicating if the script
// has already been loaded.
var loadedScripts = {};
// A dictionary mapping script URL to a boolean value indicating if the script
// has failed to load.
var erroredScripts = {};
// A counter used to generate a unique id for each component that uses
// ScriptLoaderMixin.
var idCount = 0;
var ReactScriptLoader = {
componentDidMount: function(key, component, scriptURL) {
if (typeof component.onScriptLoaded !== 'function') {
throw new Error('ScriptLoader: Component class must implement onScriptLoaded()');
}
if (typeof component.onScriptError !== 'function') {
throw new Error('ScriptLoader: Component class must implement onScriptError()');
}
if (loadedScripts[scriptURL]) {
component.onScriptLoaded();
return;
}
if (erroredScripts[scriptURL]) {
component.onScriptError();
return;
}
// If the script is loading, add the component to the script's observers
// and return. Otherwise, initialize the script's observers with the component
// and start loading the script.
if (scriptObservers[scriptURL]) {
console.log('ReactScriptLoaderMixin: add component to scriptObservers');
scriptObservers[scriptURL][key] = component;
return;
}
var observers = {};
observers[key] = component;
scriptObservers[scriptURL] = observers;
console.log('ReactScriptLoaderMixin: creating script tag');
var script = document.createElement('script');
if (typeof component.onScriptTagCreated === 'function') {
component.onScriptTagCreated(script);
}
script.src = scriptURL;
script.async = 1;
var callObserverFuncAndRemoveObserver = function(func) {
var observers = scriptObservers[scriptURL];
for (var key in observers) {
observer = observers[key];
var removeObserver = func(observer);
if (removeObserver) {
delete scriptObservers[scriptURL][key];
}
}
//delete scriptObservers[scriptURL];
}
script.onload = function() {
loadedScripts[scriptURL] = true;
callObserverFuncAndRemoveObserver(function(observer) {
if (observer.deferOnScriptLoaded && observer.deferOnScriptLoaded()) {
return false;
}
observer.onScriptLoaded();
return true;
});
};
script.onerror = function(event) {
erroredScripts[scriptURL] = true;
callObserverFuncAndRemoveObserver(function(observer) {
observer.onScriptError();
return true;
});
};
// (old) MSIE browsers may call 'onreadystatechange' instead of 'onload'
script.onreadystatechange = function() {
if (this.readyState == 'loaded') {
// wait for other events, then call onload if default onload hadn't been called
window.setTimeout(function() {
if (loadedScripts[scriptURL] !== true) script.onload();
}, 0);
}
};
console.log('append script', script);
document.body.appendChild(script);
},
componentWillUnmount: function(key, scriptURL) {
// If the component is waiting for the script to load, remove the
// component from the script's observers before unmounting the component.
var observers = scriptObservers[scriptURL];
if (observers) {
delete observers[key];
}
},
triggerOnScriptLoaded: function(scriptURL) {
if (!loadedScripts[scriptURL]) {
throw new Error('Error: only call this function after the script has in fact loaded.');
}
var observers = scriptObservers[scriptURL];
for (var key in observers) {
var observer = observers[key];
observer.onScriptLoaded();
}
delete scriptObservers[scriptURL];
}
};
var ReactScriptLoaderMixin = {
componentDidMount: function() {
if (typeof this.getScriptURL !== 'function') {
throw new Error("ScriptLoaderMixin: Component class must implement getScriptURL().")
}
console.log('ReactScriptLoaderMixin: componentDidMount');
if (this.getScriptURL() instanceof Array) {
console.log('ReactScriptLoaderMixin: load array of scripts', this.getScriptURL());
for (var i in this.getScriptURL()) {
ReactScriptLoader.componentDidMount(this.__getScriptLoaderID(), this, this.getScriptURL()[i]);
}
} else {
ReactScriptLoader.componentDidMount(this.__getScriptLoaderID(), this, this.getScriptURL());
}
},
componentWillUnmount: function() {
console.log('ReactScriptLoaderMixin: componentWillUnmount');
if (this.getScriptURL() instanceof Array) {
for (var i in this.getScriptURL()) {
ReactScriptLoader.componentWillUnmount(this.__getScriptLoaderID(), this, this.getScriptURL()[i]);
}
} else {
ReactScriptLoader.componentWillUnmount(this.__getScriptLoaderID(), this.getScriptURL());
}
},
__getScriptLoaderID: function() {
if (typeof this.__reactScriptLoaderID === 'undefined') {
this.__reactScriptLoaderID = 'id' + idCount++;
}
return this.__reactScriptLoaderID;
},
};
exports.ReactScriptLoaderMixin = ReactScriptLoaderMixin;
exports.ReactScriptLoader = ReactScriptLoader;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment