Skip to content

Commit b1f1e59

Browse files
author
Dean Sofer
committed
Completely rewrite the whole damn thing in react
1 parent 234135e commit b1f1e59

File tree

125 files changed

+71889
-90
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+71889
-90
lines changed

app.js

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,50 @@ app.config(function($stateProvider, $urlRouterProvider){
55
url: '/',
66
templateUrl: 'home'
77
});
8+
89
$stateProvider.state('script', {
9-
url: '/{scriptId:.+}',
10+
url: '/:scriptId',
1011
views: {
1112
'nav': {
1213
templateUrl: 'nav.html',
1314
controller: 'Script',
1415
},
1516
'': {
16-
templateUrl: 'script.html',
17+
template: '<script data="script"></script>',
1718
controller: 'Script',
1819
}
1920
},
2021
resolve: {
21-
script: function($stateParams){
22-
return new Firebase("https://screenwrite.firebaseio.com/"+$stateParams.scriptId);
22+
script: function($stateParams, $rootScope, $firebase){
23+
var fb = new Firebase("https://screenwrite.firebaseio.com/"+$stateParams.scriptId);
24+
25+
script = $firebase(fb).$asObject();
26+
return script.$bindTo($rootScope, 'script');
27+
}
28+
},
29+
onEnter: function($rootScope) {
30+
if (!$rootScope.script)
31+
$rootScope.script = {};
32+
if (!$rootScope.script.lines)
33+
$rootScope.script.lines = [{type:'scene' }];
34+
},
35+
onExit: function(script) {
36+
script(); // unbind firebase
37+
}
38+
});
39+
40+
$stateProvider.state('script.view', {
41+
url: '/view',
42+
views: {
43+
'nav@script': {
44+
templateUrl: 'readonly-nav.html',
45+
},
46+
'@script': {
47+
templateUrl: 'readonly.html',
2348
}
2449
}
2550
});
51+
2652
});
2753
app.run(function($rootScope, $state, types, $timeout, $window){
2854
$rootScope.edit = function(line){
@@ -58,19 +84,14 @@ app.run(function($rootScope, $state, types, $timeout, $window){
5884
$state.go('script', { scriptId: guid() });
5985
};
6086

87+
$rootScope.$on('$stateChangeError', function(){
88+
console.log('Error:', arguments);
89+
});
90+
6191
});
6292
app.constant('types', ['scene', 'action', 'character', 'dialogue', 'parenthetical', 'transition', 'shot', 'text']);
63-
app.controller('Script', function($scope, types, script, $localStorage, $stateParams, $firebase, cursorPos){
64-
script = $firebase(script).$asObject();
65-
script.$bindTo($scope, 'script').then(function(unbind){
66-
if (!$scope.script)
67-
$scope.script = {};
68-
if (!$scope.script.lines)
69-
$scope.script.lines = [{type:'scene' }];
70-
$localStorage[$stateParams.scriptId] = $scope.script;
71-
document.title = 'Screenwriter: ' + $scope.script.title;
72-
return unbind;
73-
});
93+
app.controller('Script', function($scope, types, $localStorage, $stateParams, $firebase, cursorPos){
94+
document.title = 'Screenwriter: ' + $scope.script.title;
7495

7596
$scope.$watch('script.title', function(newVal, oldVal){
7697
document.title = 'Screenwriter: ' + newVal;
@@ -305,3 +326,14 @@ app.filter('unique', function(){
305326
});
306327
};
307328
});
329+
330+
app.directive('script', function($timeout){
331+
return {
332+
restrict: 'E',
333+
link: function($scope, $element, $attrs) {
334+
$timeout(function(){
335+
React.renderComponent(Script({ script: $scope.$eval($attrs.data) }), $element[0]);
336+
}, true);
337+
}
338+
};
339+
});

bower.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
"firebase": "~1",
2626
"ngstorage": "~0",
2727
"underscore": "~1",
28-
"angular": "~1"
28+
"angular": "~1",
29+
"react": "~0.12.2",
30+
"reactfire": "~0.4.0",
31+
"react-router": "~0.11.6",
32+
"react-bootstrap": "~0.13.0"
2933
}
3034
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "react-bootstrap",
3+
"version": "0.13.0",
4+
"homepage": "http://react-bootstrap.github.io/",
5+
"author": "Stephen J. Collings <[email protected]>",
6+
"license": "MIT",
7+
"main": [
8+
"react-bootstrap.js"
9+
],
10+
"keywords": [
11+
"react",
12+
"react-component",
13+
"boostrap"
14+
],
15+
"ignore": [
16+
"**/.*"
17+
],
18+
"dependencies": {
19+
"react": ">= 0.12.0"
20+
},
21+
"_release": "0.13.0",
22+
"_resolution": {
23+
"type": "version",
24+
"tag": "v0.13.0",
25+
"commit": "56230617a6ee68f02fcab7de6d2f69167c70541b"
26+
},
27+
"_source": "git://github.com/react-bootstrap/react-bootstrap-bower.git",
28+
"_target": "~0.13.0",
29+
"_originalSource": "react-bootstrap",
30+
"_direct": true
31+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
define(function (require, exports, module) {var React = require('react');
2+
var PanelGroup = require('./PanelGroup');
3+
4+
var Accordion = React.createClass({displayName: 'Accordion',
5+
render: function () {
6+
return (
7+
React.createElement(PanelGroup, React.__spread({}, this.props, {accordion: true}),
8+
this.props.children
9+
)
10+
);
11+
}
12+
});
13+
14+
module.exports = Accordion;
15+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
define(function (require, exports, module) {var React = require('react');
2+
var joinClasses = require('./utils/joinClasses');
3+
var AffixMixin = require('./AffixMixin');
4+
var domUtils = require('./utils/domUtils');
5+
6+
var Affix = React.createClass({displayName: 'Affix',
7+
statics: {
8+
domUtils: domUtils
9+
},
10+
11+
mixins: [AffixMixin],
12+
13+
render: function () {
14+
var holderStyle = {top: this.state.affixPositionTop};
15+
return (
16+
React.createElement("div", React.__spread({}, this.props, {className: joinClasses(this.props.className, this.state.affixClass), style: holderStyle}),
17+
this.props.children
18+
)
19+
);
20+
}
21+
});
22+
23+
module.exports = Affix;
24+
});
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
define(function (require, exports, module) {/* global window, document */
2+
3+
var React = require('react');
4+
var domUtils = require('./utils/domUtils');
5+
var EventListener = require('./utils/EventListener');
6+
7+
var AffixMixin = {
8+
propTypes: {
9+
offset: React.PropTypes.number,
10+
offsetTop: React.PropTypes.number,
11+
offsetBottom: React.PropTypes.number
12+
},
13+
14+
getInitialState: function () {
15+
return {
16+
affixClass: 'affix-top'
17+
};
18+
},
19+
20+
getPinnedOffset: function (DOMNode) {
21+
if (this.pinnedOffset) {
22+
return this.pinnedOffset;
23+
}
24+
25+
DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, '');
26+
DOMNode.className += DOMNode.className.length ? ' affix' : 'affix';
27+
28+
this.pinnedOffset = domUtils.getOffset(DOMNode).top - window.pageYOffset;
29+
30+
return this.pinnedOffset;
31+
},
32+
33+
checkPosition: function () {
34+
var DOMNode, scrollHeight, scrollTop, position, offsetTop, offsetBottom,
35+
affix, affixType, affixPositionTop;
36+
37+
// TODO: or not visible
38+
if (!this.isMounted()) {
39+
return;
40+
}
41+
42+
DOMNode = this.getDOMNode();
43+
scrollHeight = document.documentElement.offsetHeight;
44+
scrollTop = window.pageYOffset;
45+
position = domUtils.getOffset(DOMNode);
46+
offsetTop;
47+
offsetBottom;
48+
49+
if (this.affixed === 'top') {
50+
position.top += scrollTop;
51+
}
52+
53+
offsetTop = this.props.offsetTop != null ?
54+
this.props.offsetTop : this.props.offset;
55+
offsetBottom = this.props.offsetBottom != null ?
56+
this.props.offsetBottom : this.props.offset;
57+
58+
if (offsetTop == null && offsetBottom == null) {
59+
return;
60+
}
61+
if (offsetTop == null) {
62+
offsetTop = 0;
63+
}
64+
if (offsetBottom == null) {
65+
offsetBottom = 0;
66+
}
67+
68+
if (this.unpin != null && (scrollTop + this.unpin <= position.top)) {
69+
affix = false;
70+
} else if (offsetBottom != null && (position.top + DOMNode.offsetHeight >= scrollHeight - offsetBottom)) {
71+
affix = 'bottom';
72+
} else if (offsetTop != null && (scrollTop <= offsetTop)) {
73+
affix = 'top';
74+
} else {
75+
affix = false;
76+
}
77+
78+
if (this.affixed === affix) {
79+
return;
80+
}
81+
82+
if (this.unpin != null) {
83+
DOMNode.style.top = '';
84+
}
85+
86+
affixType = 'affix' + (affix ? '-' + affix : '');
87+
88+
this.affixed = affix;
89+
this.unpin = affix === 'bottom' ?
90+
this.getPinnedOffset(DOMNode) : null;
91+
92+
if (affix === 'bottom') {
93+
DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, 'affix-bottom');
94+
affixPositionTop = scrollHeight - offsetBottom - DOMNode.offsetHeight - domUtils.getOffset(DOMNode).top;
95+
}
96+
97+
this.setState({
98+
affixClass: affixType,
99+
affixPositionTop: affixPositionTop
100+
});
101+
},
102+
103+
checkPositionWithEventLoop: function () {
104+
setTimeout(this.checkPosition, 0);
105+
},
106+
107+
componentDidMount: function () {
108+
this._onWindowScrollListener =
109+
EventListener.listen(window, 'scroll', this.checkPosition);
110+
this._onDocumentClickListener =
111+
EventListener.listen(document, 'click', this.checkPositionWithEventLoop);
112+
},
113+
114+
componentWillUnmount: function () {
115+
if (this._onWindowScrollListener) {
116+
this._onWindowScrollListener.remove();
117+
}
118+
119+
if (this._onDocumentClickListener) {
120+
this._onDocumentClickListener.remove();
121+
}
122+
},
123+
124+
componentDidUpdate: function (prevProps, prevState) {
125+
if (prevState.affixClass === this.state.affixClass) {
126+
this.checkPositionWithEventLoop();
127+
}
128+
}
129+
};
130+
131+
module.exports = AffixMixin;
132+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
define(function (require, exports, module) {var React = require('react');
2+
var joinClasses = require('./utils/joinClasses');
3+
var classSet = require('./utils/classSet');
4+
var BootstrapMixin = require('./BootstrapMixin');
5+
6+
7+
var Alert = React.createClass({displayName: 'Alert',
8+
mixins: [BootstrapMixin],
9+
10+
propTypes: {
11+
onDismiss: React.PropTypes.func,
12+
dismissAfter: React.PropTypes.number
13+
},
14+
15+
getDefaultProps: function () {
16+
return {
17+
bsClass: 'alert',
18+
bsStyle: 'info'
19+
};
20+
},
21+
22+
renderDismissButton: function () {
23+
return (
24+
React.createElement("button", {
25+
type: "button",
26+
className: "close",
27+
onClick: this.props.onDismiss,
28+
'aria-hidden': "true"},
29+
"×"
30+
)
31+
);
32+
},
33+
34+
render: function () {
35+
var classes = this.getBsClassSet();
36+
var isDismissable = !!this.props.onDismiss;
37+
38+
classes['alert-dismissable'] = isDismissable;
39+
40+
return (
41+
React.createElement("div", React.__spread({}, this.props, {className: joinClasses(this.props.className, classSet(classes))}),
42+
isDismissable ? this.renderDismissButton() : null,
43+
this.props.children
44+
)
45+
);
46+
},
47+
48+
componentDidMount: function() {
49+
if (this.props.dismissAfter && this.props.onDismiss) {
50+
this.dismissTimer = setTimeout(this.props.onDismiss, this.props.dismissAfter);
51+
}
52+
},
53+
54+
componentWillUnmount: function() {
55+
clearTimeout(this.dismissTimer);
56+
}
57+
});
58+
59+
module.exports = Alert;
60+
});

0 commit comments

Comments
 (0)