diff --git a/docs/applicationState.md b/docs/applicationState.md
index c25a0da23d2..b4401080452 100644
--- a/docs/applicationState.md
+++ b/docs/applicationState.md
@@ -9,6 +9,8 @@ Child components should not modify top level state directly, instead they should
{
activeFrameKey: number,
frames: [{
+ audioMuted: boolean, // frame is muted
+ audioPlaybackActive: boolean, // frame is playing audio
canGoBack: boolean,
canGoForward: boolean,
icon: string, // url to favicon
diff --git a/js/actions/appActions.js b/js/actions/appActions.js
index 2f09fcf90d7..31e630ceaf0 100644
--- a/js/actions/appActions.js
+++ b/js/actions/appActions.js
@@ -20,7 +20,7 @@ const AppActions = {
* In general, an iframe's src should not be updated when navigating within the frame to a new page,
* but the location should. For user entered new URLs, both should be updated.
*
- * @param location The URL of the page to load
+ * @param {string} location - The URL of the page to load
*/
loadUrl: function (location) {
if (UrlUtil.isURL(location)) {
@@ -37,8 +37,8 @@ const AppActions = {
* This differs from the above in that it will not change the webview's (iframe's) src.
* This should be used for inter-page navigation but not user initiated loads.
*
- * @param location The URL of the page to load
- * @param key The frame key to modify, it is checked against the active frame and if
+ * @param {string} location - The URL of the page to load
+ * @param {string} key - The frame key to modify, it is checked against the active frame and if
* it is active the URL text will also be changed.
*/
setLocation: function (location, key) {
@@ -56,7 +56,7 @@ const AppActions = {
* Dispatches a message to the store to set the user entered text for the URL bar.
* Unlike setLocation and loadUrl, this does not modify the state of src and location.
*
- * @param location The text to set as the new navbar URL input
+ * @param {string} location - The text to set as the new navbar URL input
*/
setNavBarUserInput: function (location) {
AppDispatcher.dispatch({
@@ -69,8 +69,8 @@ const AppActions = {
* Dispatches a message to the store to set the current frame's title.
* This should be called in response to the webview encountering a
tag.
*
- * @param frameProps The frame properties to modify
- * @param title The title to set for the frame
+ * @param {Object} frameProps - The frame properties to modify
+ * @param {string} title - The title to set for the frame
*/
setFrameTitle: function (frameProps, title) {
AppDispatcher.dispatch({
@@ -83,7 +83,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the webview is loading.
*
- * @param frameProps The frame properties for the webview in question.
+ * @param {Object} frameProps - The frame properties for the webview in question.
*/
onWebviewLoadStart: function (frameProps) {
AppDispatcher.dispatch({
@@ -95,7 +95,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the webview is done loading.
*
- * @param frameProps The frame properties for the webview in question.
+ * @param {Object} frameProps - The frame properties for the webview in question.
*/
onWebviewLoadEnd: function (frameProps) {
AppDispatcher.dispatch({
@@ -107,7 +107,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate if the navigation bar is focused.
*
- * @param focused true if the navigation bar should be considered as focused
+ * @param {boolean} focused - true if the navigation bar should be considered as focused
*/
setNavBarFocused: function (focused) {
AppDispatcher.dispatch({
@@ -119,9 +119,9 @@ const AppActions = {
/**
* Dispatches a message to the store to create a new frame
*
- * @param frameOpts An object of frame options such as isPrivate, element, and tab features.
+ * @param {Object} frameOpts - An object of frame options such as isPrivate, element, and tab features.
* These may not all be hooked up in Electron yet.
- * @param openInForeground true if the new frame should become the new active frame
+ * @param {boolean} openInForeground - true if the new frame should become the new active frame
*/
newFrame: function (frameOpts = {}, openInForeground = true) {
frameOpts.location = frameOpts.location || Config.defaultUrl
@@ -185,7 +185,7 @@ const AppActions = {
/**
* Dispatches a message to the store to set a new frame as the active frame.
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
setActiveFrame: function (frameProps) {
if (!frameProps) {
@@ -200,7 +200,7 @@ const AppActions = {
/**
* Dispatches a message to the store to set the tab page index.
*
- * @param index the tab page index to change to
+ * @param {number} index - the tab page index to change to
*/
setTabPageIndex: function (index) {
AppDispatcher.dispatch({
@@ -212,9 +212,9 @@ const AppActions = {
/**
* Dispatches a message to the store to update the back-forward information.
*
- * @param frameProps the frame properties for the webview in question.
- * @param canGoBack Specifies if the active frame has previous entries in its history
- * @param canGoForward Specifies if the active frame has next entries in its history (i.e. the user pressed back at least once)
+ * @param {Object} frameProps - the frame properties for the webview in question.
+ * @param {boolean} canGoBack - Specifies if the active frame has previous entries in its history
+ * @param {boolean} canGoForward - Specifies if the active frame has next entries in its history (i.e. the user pressed back at least once)
*/
updateBackForwardState: function (frameProps, canGoBack, canGoForward) {
AppDispatcher.dispatch({
@@ -228,7 +228,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has started for that frame.
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragStart: function (frameProps) {
AppDispatcher.dispatch({
@@ -240,7 +240,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has stopped for that frame.
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragStop: function (frameProps) {
AppDispatcher.dispatch({
@@ -252,7 +252,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that something is dragging over the left half of this tab.
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragDraggingOverLeftHalf: function (frameProps) {
AppDispatcher.dispatch({
@@ -264,7 +264,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that something is dragging over the right half of this tab.
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragDraggingOverRightHalf: function (frameProps) {
AppDispatcher.dispatch({
@@ -276,7 +276,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has exited the frame
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragExit: function (frameProps) {
AppDispatcher.dispatch({
@@ -288,7 +288,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has exited the right half of the frame
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragExitRightHalf: function (frameProps) {
AppDispatcher.dispatch({
@@ -300,7 +300,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging started on the tab
*
- * @param frameProps the frame properties for the webview in question.
+ * @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDraggingOn: function (frameProps) {
AppDispatcher.dispatch({
@@ -312,9 +312,9 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the specified frame should move locations.
*
- * @param sourceFrameProps the frame properties for the webview to move.
- * @param destinationFrameProps the frame properties for the webview to move to.
- * @param prepend Whether or not to prepend to the destinationFrameProps
+ * @param {Object} sourceFrameProps - the frame properties for the webview to move.
+ * @param {Object} destinationFrameProps - the frame properties for the webview to move to.
+ * @param {boolean} prepend - Whether or not to prepend to the destinationFrameProps
*/
moveTab: function (sourceFrameProps, destinationFrameProps, prepend) {
AppDispatcher.dispatch({
@@ -325,11 +325,11 @@ const AppActions = {
})
},
- /*
+ /**
* Sets the URL bar suggestions and selected index.
*
- * @param suggestionList The list of suggestions for the entered URL bar text. This can be generated from history, bookmarks, etc.
- * @param selectedIndex The index for the selected item (users can select items with down arrow on their keyboard)
+ * @param {Object[]} suggestionList - The list of suggestions for the entered URL bar text. This can be generated from history, bookmarks, etc.
+ * @param {number} selectedIndex - The index for the selected item (users can select items with down arrow on their keyboard)
*/
setUrlBarSuggestions: function (suggestionList, selectedIndex) {
AppDispatcher.dispatch({
@@ -369,7 +369,7 @@ const AppActions = {
/**
* Marks the URL bar text as selected or not
*
- * @param isSelected Whether or not the URL bar should be autoselected
+ * @param {boolean} isSelected - Whether or not the URL bar should be autoselected
*/
setUrlBarAutoselected: function (isAutoselected) {
AppDispatcher.dispatch({
@@ -381,7 +381,7 @@ const AppActions = {
/**
* Marks the URL bar as active or not
*
- * @param isActive Whether or not the URL bar should be marked as active
+ * @param {boolean} isActive - Whether or not the URL bar should be marked as active
*/
setUrlBarActive: function (isActive) {
AppDispatcher.dispatch({
@@ -393,7 +393,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the pending frame shortcut info should be updated.
*
- * @param activeShortcut The text for the new shortcut. Usually this is null to clear info which was previously
+ * @param {string} activeShortcut - The text for the new shortcut. Usually this is null to clear info which was previously
* set from an IPC call.
*/
setActiveFrameShortcut: function (activeShortcut) {
@@ -405,7 +405,7 @@ const AppActions = {
/**
* Dispatches a message to set the search engine details.
- * @param searchDetail the search details
+ * @param {Object} searchDetail - the search details
*/
setSearchDetail: function (searchDetail) {
AppDispatcher.dispatch({
@@ -416,8 +416,8 @@ const AppActions = {
/**
* Adds a site to the site list
- * @param frameProps the frameProps for the frame in to bookmark
- * @param tag A tag to associate with the site. e.g. bookmarks.
+ * @param {Object} frameProps - Properties of the frame in question
+ * @param {string} tag - A tag to associate with the site. e.g. bookmarks.
*/
addSite: function (frameProps, tag) {
AppDispatcher.dispatch({
@@ -429,8 +429,8 @@ const AppActions = {
/**
* Removes a site from the site list
- * @param frameProps the frameProps for the frame in to bookmark
- * @param tag A tag to associate with the site. e.g. bookmarks.
+ * @param {Object} frameProps - Properties of the frame in question
+ * @param {string} tag - A tag to associate with the site. e.g. bookmarks.
*/
removeSite: function (frameProps, tag) {
AppDispatcher.dispatch({
@@ -438,6 +438,34 @@ const AppActions = {
frameProps,
tag
})
+ },
+
+ /**
+ * Dispatches a message to indicate that the frame should be muted
+ *
+ * @param {Object} frameProps - Properties of the frame in question
+ * @param {boolean} muted - true if the frame is muted
+ */
+ setAudioMuted: function (frameProps, muted) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_SET_AUDIO_MUTED,
+ frameProps,
+ muted
+ })
+ },
+
+ /**
+ * Dispatches a message to indicate that audio is playing
+ *
+ * @param {Object} frameProps - Properties of the frame in question
+ * @param {boolean} audioPlaybackActive - true if audio is playing in the frame
+ */
+ setAudioPlaybackActive: function (frameProps, audioPlaybackActive) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_SET_AUDIO_PLAYBACK_ACTIVE,
+ frameProps,
+ audioPlaybackActive
+ })
}
}
diff --git a/js/components/frame.js b/js/components/frame.js
index ac752def78a..f6ae8c8e4d3 100644
--- a/js/components/frame.js
+++ b/js/components/frame.js
@@ -107,6 +107,17 @@ class Frame extends ImmutableComponent {
this.webview.canGoBack(),
this.webview.canGoForward())
})
+ this.webview.addEventListener('media-started-playing', ({title}) => {
+ AppActions.setAudioPlaybackActive(this.props.frame, true)
+ })
+ this.webview.addEventListener('media-paused', ({title}) => {
+ AppActions.setAudioPlaybackActive(this.props.frame, false)
+ })
+ // Ensure we mute appropriately, the initial value could be set
+ // from persisted state.
+ if (this.props.frame.get('audioMuted')) {
+ this.webview.setAudioMuted(true)
+ }
}
insertAds (currentLocation) {
@@ -125,6 +136,16 @@ class Frame extends ImmutableComponent {
this.webview.goForward()
}
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.frame.get('audioMuted') &&
+ this.props.frame.get('audioMuted') !== true) {
+ this.webview.setAudioMuted(true)
+ } else if (!nextProps.frame.get('audioMuted') &&
+ this.props.frame.get('audioMuted') === true) {
+ this.webview.setAudioMuted(false)
+ }
+ }
+
render () {
return
+ onClick={this.onMuteFrame.bind(this, !this.props.frameProps.get('audioMuted'))} />
}
return {
appState = appState.set('sites', SiteUtil.removeSite(appState.get('sites'), action.frameProps, action.tag))
appStore.emitChange()
break
+ case AppConstants.APP_SET_AUDIO_MUTED:
+ appState = appState.setIn(['frames', FrameStateUtil.getFramePropsIndex(appState.get('frames'), action.frameProps), 'audioMuted'], action.muted)
+ appStore.emitChange()
+ break
+ case AppConstants.APP_SET_AUDIO_PLAYBACK_ACTIVE:
+ appState = appState.setIn(['frames', FrameStateUtil.getFramePropsIndex(appState.get('frames'), action.frameProps), 'audioPlaybackActive'], action.audioPlaybackActive)
+ appStore.emitChange()
+ break
default:
}
})
diff --git a/less/tabs.less b/less/tabs.less
index fad2fca6629..566d257b217 100644
--- a/less/tabs.less
+++ b/less/tabs.less
@@ -60,7 +60,7 @@
vertical-align: middle;
}
.playIcon {
- cursor: default;
+ cursor: pointer;
margin-right: 4px;
}