Skip to content

Commit 3603fc8

Browse files
authored
Merge pull request #1016 from outoftime/click-outside
Clicking outside menus closes them
2 parents f1afcee + ce2a301 commit 3603fc8

32 files changed

Lines changed: 422 additions & 379 deletions

TEST_PLAN.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,46 @@ parts that seem relevant to your code changes.
2222
the message in the error list focuses the cursor on the location in the
2323
source.
2424
* Click the pop-out button. Ensure that a new tab opens with the rendered page.
25-
* Minimize various editors and the output column by clicking the appropriate
26-
label. Maximize them by clicking the button in the left column.
25+
* Minimize various editors by clicking the appropriate label. Maximize them by
26+
clicking the bar at the bottom of the editors column.
27+
* Click the zoom in button. Ensure that the text in the editors gets bigger.
28+
Click it again and ensure that the text returns to normal size.
29+
30+
### Persistence
31+
32+
* Log out if you are logged in.
33+
* Add some content to the HTML.
34+
* Refresh the browser tab. Verify that your content is still there.
35+
* Close the browser tab, then open Popcode in a new tab. Verify that your
36+
content is still there.
37+
* Without closing the current tab, open another Popcode instance in a new tab.
38+
Verify that the environment contains a fresh project.
2739

2840
### Libraries
2941

3042
* Type some JavaScript that requires jQuery. Ensure that an error message
31-
appears suggesting you enable jQuery. Enable jQuery and ensure that the page
32-
now renders and behaves as expected.
43+
appears suggesting you enable jQuery.
44+
* Enable jQuery and ensure that the page now renders and behaves as expected.
45+
The menu should stay visible after you select jQuery.
46+
47+
### Snapshots
48+
49+
* Add some content to the page. Click **Snapshot**. Click the prompt to
50+
copy.
51+
* Paste the URL from your clipboard into a new tab. Verify that the project
52+
contains the content that you exported.
3353

34-
### Gist import
54+
### Gist import & project instructions
3555

3656
* Open [a gist import
3757
URL](http://localhost:3000/?gist=339c841617fb50c98420d9f37654039d) and ensure
3858
that the gist is imported into the environment
59+
* Open [a gist with
60+
instructions](http://localhost:3000/?gist=911a82a17a280545858d2d8ecc557ef3).
61+
Verify that the instructions appear in the left pane of the environment.
62+
* Click the dark gray bar to the right of the instructions. Ensure that the
63+
instructions are hidden.
64+
* Click it again. Ensure that the instructions are visible.
3965

4066
### Login
4167

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
"react-dom": "^15.4.1",
132132
"react-draggable": "^2.2.6",
133133
"react-ga": "^2.1.2",
134+
"react-onclickoutside": "^6.5.0",
134135
"react-prevent-clickthrough": "^0.0.3",
135136
"react-redux": "^5.0.3",
136137
"reduce-reducers": "^0.1.2",
@@ -178,6 +179,7 @@
178179
"browser-sync": "^2.14.3",
179180
"bulkify": "^1.4.2",
180181
"check-dependencies": "^1.0.1",
182+
"circular-dependency-plugin": "^4.2.0",
181183
"cloudflare": "^2.1.1",
182184
"cssnano": "^3.10.0",
183185
"doctoc": "^1.2.0",

src/actions/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
popOutProject,
3535
toggleEditorTextSize,
3636
toggleTopBarMenu,
37+
closeTopBarMenu,
3738
} from './ui';
3839

3940
import {
@@ -77,4 +78,5 @@ export {
7778
repoExportNotDisplayed,
7879
toggleEditorTextSize,
7980
toggleTopBarMenu,
81+
closeTopBarMenu,
8082
};

src/actions/ui.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,7 @@ export const toggleEditorTextSize = createAction(
5959
export const toggleTopBarMenu = createAction(
6060
'TOGGLE_TOP_BAR_MENU',
6161
);
62+
63+
export const closeTopBarMenu = createAction(
64+
'CLOSE_TOP_BAR_MENU',
65+
);

src/components/Output.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import {ErrorReport, Preview} from '../containers';
3+
import ErrorReport from '../containers/ErrorReport';
4+
import Preview from '../containers/Preview';
45

56
export default function Output({
6-
isDraggingColumnDivider,
7+
ignorePointerEvents,
78
style,
89
onRef,
910
}) {
@@ -12,7 +13,7 @@ export default function Output({
1213
className="environment__column"
1314
ref={onRef}
1415
style={Object.assign({}, style, {
15-
pointerEvents: isDraggingColumnDivider ? 'none' : 'all',
16+
pointerEvents: ignorePointerEvents ? 'none' : 'all',
1617
})}
1718
>
1819
<div className="environment__columnContents output">
@@ -24,7 +25,7 @@ export default function Output({
2425
}
2526

2627
Output.propTypes = {
27-
isDraggingColumnDivider: PropTypes.bool.isRequired,
28+
ignorePointerEvents: PropTypes.bool.isRequired,
2829
style: PropTypes.object.isRequired,
2930
onRef: PropTypes.func.isRequired,
3031
};

src/components/ProjectPreview.jsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,12 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import classnames from 'classnames';
43
import moment from 'moment';
54

65
const MAX_LENGTH = 50;
76

8-
export default function ProjectPreview({
9-
isSelected,
10-
preview,
11-
project,
12-
onProjectSelected,
13-
}) {
7+
export default function ProjectPreview({preview, project}) {
148
return (
15-
<div
16-
className={classnames(
17-
'project-preview',
18-
'top-bar__menu-item',
19-
{'top-bar__menu-item_active': isSelected},
20-
)}
21-
key={project.projectKey}
22-
onClick={onProjectSelected}
23-
>
9+
<div>
2410
<div className="project-preview__label">
2511
{preview.slice(0, MAX_LENGTH)}
2612
</div>
@@ -32,8 +18,6 @@ export default function ProjectPreview({
3218
}
3319

3420
ProjectPreview.propTypes = {
35-
isSelected: PropTypes.bool.isRequired,
3621
preview: PropTypes.string.isRequired,
3722
project: PropTypes.object.isRequired,
38-
onProjectSelected: PropTypes.func.isRequired,
3923
};
Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,15 @@
1-
import classnames from 'classnames';
21
import React from 'react';
32
import PropTypes from 'prop-types';
43
import {t} from 'i18next';
54
import CurrentUserMenu from './CurrentUserMenu';
65

76
export default function CurrentUser({
8-
isOpen,
97
user,
10-
onClick,
118
onLogOut,
129
onStartLogIn,
1310
}) {
1411
if (user.authenticated) {
15-
const name = user.displayName;
16-
17-
return (
18-
<div
19-
className={classnames(
20-
'top-bar__menu-button',
21-
'top-bar__current-user',
22-
{'top-bar__menu-button_active': isOpen},
23-
)}
24-
onClick={onClick}
25-
>
26-
<img
27-
className="top-bar__avatar"
28-
src={user.avatarUrl}
29-
/>
30-
<span className="top-bar__username">{name}</span>
31-
<span className="top-bar__drop-down-button u__icon">
32-
&#xf0d7;
33-
</span>
34-
<CurrentUserMenu isOpen={isOpen} onLogOut={onLogOut} />
35-
</div>
36-
);
12+
return <CurrentUserMenu user={user} onLogOut={onLogOut} />;
3713
}
3814
return (
3915
<div className="top-bar__current-user">
@@ -48,11 +24,9 @@ export default function CurrentUser({
4824
}
4925

5026
CurrentUser.propTypes = {
51-
isOpen: PropTypes.bool.isRequired,
5227
user: PropTypes.shape({
5328
authenticated: PropTypes.boolean,
5429
}).isRequired,
55-
onClick: PropTypes.func.isRequired,
5630
onLogOut: PropTypes.func.isRequired,
5731
onStartLogIn: PropTypes.func.isRequired,
5832
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
export default function CurrentUserButton({user: {avatarUrl, displayName}}) {
5+
return (
6+
<div className="top-bar__current-user">
7+
<img
8+
className="top-bar__avatar"
9+
src={avatarUrl}
10+
/>
11+
<span className="top-bar__username">{displayName}</span>
12+
<span className="top-bar__drop-down-button u__icon">
13+
&#xf0d7;
14+
</span>
15+
</div>
16+
);
17+
}
18+
19+
CurrentUserButton.propTypes = {
20+
user: PropTypes.shape({
21+
avatarUrl: PropTypes.string.isRequired,
22+
displayName: PropTypes.string.isRequired,
23+
}).isRequired,
24+
};
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
import React from 'react';
21
import PropTypes from 'prop-types';
2+
import React from 'react';
33
import {t} from 'i18next';
4+
import createMenu, {MenuItem} from './createMenu';
5+
import CurrentUserButton from './CurrentUserButton';
46

5-
export default function CurrentUserMenu({isOpen, onLogOut}) {
6-
if (!isOpen) {
7-
return null;
8-
}
7+
const CurrentUserMenu = createMenu({
8+
name: 'currentUser',
99

10-
return (
11-
<div className="top-bar__menu">
12-
<div className="top-bar__menu-item" onClick={onLogOut}>
10+
// eslint-disable-next-line react/prop-types
11+
renderItems({onLogOut}) {
12+
return (
13+
<MenuItem onClick={onLogOut}>
1314
{t('top-bar.session.log-out-prompt')}
14-
</div>
15-
</div>
16-
);
17-
}
15+
</MenuItem>
16+
);
17+
},
18+
})(CurrentUserButton);
1819

1920
CurrentUserMenu.propTypes = {
20-
isOpen: PropTypes.bool.isRequired,
2121
onLogOut: PropTypes.func.isRequired,
2222
};
23+
24+
export default CurrentUserMenu;

0 commit comments

Comments
 (0)