ContentSection.jsx (11847B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import React from "react"; 6 import { actionCreators as ac } from "common/Actions.mjs"; 7 import { SectionsMgmtPanel } from "../SectionsMgmtPanel/SectionsMgmtPanel"; 8 import { WallpaperCategories } from "../../WallpaperCategories/WallpaperCategories"; 9 10 export class ContentSection extends React.PureComponent { 11 constructor(props) { 12 super(props); 13 this.onPreferenceSelect = this.onPreferenceSelect.bind(this); 14 15 // Refs are necessary for dynamically measuring drawer heights for slide animations 16 this.topSitesDrawerRef = React.createRef(); 17 this.pocketDrawerRef = React.createRef(); 18 } 19 20 inputUserEvent(eventSource, eventValue) { 21 this.props.dispatch( 22 ac.UserEvent({ 23 event: "PREF_CHANGED", 24 source: eventSource, 25 value: { status: eventValue, menu_source: "CUSTOMIZE_MENU" }, 26 }) 27 ); 28 } 29 30 onPreferenceSelect(e) { 31 // eventSource: WEATHER | TOP_SITES | TOP_STORIES | WIDGET_LISTS | WIDGET_TIMER 32 const { preference, eventSource } = e.target.dataset; 33 let value; 34 if (e.target.nodeName === "SELECT") { 35 value = parseInt(e.target.value, 10); 36 } else if (e.target.nodeName === "INPUT") { 37 value = e.target.checked; 38 if (eventSource) { 39 this.inputUserEvent(eventSource, value); 40 } 41 } else if (e.target.nodeName === "MOZ-TOGGLE") { 42 value = e.target.pressed; 43 if (eventSource) { 44 this.inputUserEvent(eventSource, value); 45 } 46 } 47 this.props.setPref(preference, value); 48 } 49 50 componentDidMount() { 51 this.setDrawerMargins(); 52 } 53 54 componentDidUpdate() { 55 this.setDrawerMargins(); 56 } 57 58 setDrawerMargins() { 59 this.setDrawerMargin( 60 `TOP_SITES`, 61 this.props.enabledSections.topSitesEnabled 62 ); 63 this.setDrawerMargin( 64 `TOP_STORIES`, 65 this.props.enabledSections.pocketEnabled 66 ); 67 } 68 69 setDrawerMargin(drawerID, isOpen) { 70 let drawerRef; 71 72 if (drawerID === `TOP_SITES`) { 73 drawerRef = this.topSitesDrawerRef.current; 74 } else if (drawerID === `TOP_STORIES`) { 75 drawerRef = this.pocketDrawerRef.current; 76 } else { 77 return; 78 } 79 80 if (drawerRef) { 81 // Use measured height if valid, otherwise use a large fallback 82 // since overflow:hidden on the parent safely hides the drawer 83 let drawerHeight = 84 parseFloat(window.getComputedStyle(drawerRef)?.height) || 100; 85 86 if (isOpen) { 87 drawerRef.style.marginTop = "var(--space-small)"; 88 } else { 89 drawerRef.style.marginTop = `-${drawerHeight + 3}px`; 90 } 91 } 92 } 93 94 render() { 95 const { 96 enabledSections, 97 enabledWidgets, 98 pocketRegion, 99 mayHaveInferredPersonalization, 100 mayHaveWeather, 101 mayHaveWidgets, 102 mayHaveTimerWidget, 103 mayHaveListsWidget, 104 openPreferences, 105 wallpapersEnabled, 106 activeWallpaper, 107 setPref, 108 mayHaveTopicSections, 109 exitEventFired, 110 onSubpanelToggle, 111 toggleSectionsMgmtPanel, 112 showSectionsMgmtPanel, 113 } = this.props; 114 const { 115 topSitesEnabled, 116 pocketEnabled, 117 weatherEnabled, 118 showInferredPersonalizationEnabled, 119 topSitesRowsCount, 120 } = enabledSections; 121 const { timerEnabled, listsEnabled } = enabledWidgets; 122 123 return ( 124 <div className="home-section"> 125 {wallpapersEnabled && ( 126 <> 127 <div className="wallpapers-section"> 128 <WallpaperCategories 129 setPref={setPref} 130 activeWallpaper={activeWallpaper} 131 exitEventFired={exitEventFired} 132 onSubpanelToggle={onSubpanelToggle} 133 /> 134 </div> 135 {/* If widgets section is visible, hide this divider */} 136 {!mayHaveWidgets && ( 137 <span className="divider" role="separator"></span> 138 )} 139 </> 140 )} 141 {mayHaveWidgets && ( 142 <div className="widgets-section"> 143 <div className="category-header"> 144 <h2 data-l10n-id="newtab-custom-widget-section-title"></h2> 145 </div> 146 <div className="settings-widgets"> 147 {/* Weather */} 148 {mayHaveWeather && ( 149 <div id="weather-section" className="section"> 150 <moz-toggle 151 id="weather-toggle" 152 pressed={weatherEnabled || null} 153 onToggle={this.onPreferenceSelect} 154 data-preference="showWeather" 155 data-eventSource="WEATHER" 156 data-l10n-id="newtab-custom-widget-weather-toggle" 157 /> 158 </div> 159 )} 160 161 {/* Lists */} 162 {mayHaveListsWidget && ( 163 <div id="lists-widget-section" className="section"> 164 <moz-toggle 165 id="lists-toggle" 166 pressed={listsEnabled || null} 167 onToggle={this.onPreferenceSelect} 168 data-preference="widgets.lists.enabled" 169 data-eventSource="WIDGET_LISTS" 170 data-l10n-id="newtab-custom-widget-lists-toggle" 171 /> 172 </div> 173 )} 174 175 {/* Timer */} 176 {mayHaveTimerWidget && ( 177 <div id="timer-widget-section" className="section"> 178 <moz-toggle 179 id="timer-toggle" 180 pressed={timerEnabled || null} 181 onToggle={this.onPreferenceSelect} 182 data-preference="widgets.focusTimer.enabled" 183 data-eventSource="WIDGET_TIMER" 184 data-l10n-id="newtab-custom-widget-timer-toggle" 185 /> 186 </div> 187 )} 188 <span className="divider" role="separator"></span> 189 </div> 190 </div> 191 )} 192 <div className="settings-toggles"> 193 {/* Note: If widgets are enabled, the weather toggle will be moved under Widgets subsection */} 194 {!mayHaveWidgets && mayHaveWeather && ( 195 <div id="weather-section" className="section"> 196 <moz-toggle 197 id="weather-toggle" 198 pressed={weatherEnabled || null} 199 onToggle={this.onPreferenceSelect} 200 data-preference="showWeather" 201 data-eventSource="WEATHER" 202 data-l10n-id="newtab-custom-weather-toggle" 203 /> 204 </div> 205 )} 206 207 <div id="shortcuts-section" className="section"> 208 <moz-toggle 209 id="shortcuts-toggle" 210 pressed={topSitesEnabled || null} 211 onToggle={this.onPreferenceSelect} 212 data-preference="feeds.topsites" 213 data-eventSource="TOP_SITES" 214 data-l10n-id="newtab-custom-shortcuts-toggle" 215 > 216 <div slot="nested"> 217 <div className="more-info-top-wrapper"> 218 <div 219 className="more-information" 220 ref={this.topSitesDrawerRef} 221 > 222 <select 223 id="row-selector" 224 className="selector" 225 name="row-count" 226 data-preference="topSitesRows" 227 value={topSitesRowsCount} 228 onChange={this.onPreferenceSelect} 229 disabled={!topSitesEnabled} 230 aria-labelledby="custom-shortcuts-title" 231 > 232 <option 233 value="1" 234 data-l10n-id="newtab-custom-row-selector" 235 data-l10n-args='{"num": 1}' 236 /> 237 <option 238 value="2" 239 data-l10n-id="newtab-custom-row-selector" 240 data-l10n-args='{"num": 2}' 241 /> 242 <option 243 value="3" 244 data-l10n-id="newtab-custom-row-selector" 245 data-l10n-args='{"num": 3}' 246 /> 247 <option 248 value="4" 249 data-l10n-id="newtab-custom-row-selector" 250 data-l10n-args='{"num": 4}' 251 /> 252 </select> 253 </div> 254 </div> 255 </div> 256 </moz-toggle> 257 </div> 258 259 {pocketRegion && ( 260 <div id="pocket-section" className="section"> 261 <moz-toggle 262 id="pocket-toggle" 263 pressed={pocketEnabled || null} 264 onToggle={this.onPreferenceSelect} 265 aria-describedby="custom-pocket-subtitle" 266 data-preference="feeds.section.topstories" 267 data-eventSource="TOP_STORIES" 268 {...(mayHaveInferredPersonalization 269 ? { 270 "data-l10n-id": 271 "newtab-custom-stories-personalized-toggle", 272 } 273 : { 274 "data-l10n-id": "newtab-custom-stories-toggle", 275 })} 276 > 277 <div slot="nested"> 278 {(mayHaveInferredPersonalization || mayHaveTopicSections) && ( 279 <div className="more-info-pocket-wrapper"> 280 <div 281 className="more-information" 282 ref={this.pocketDrawerRef} 283 > 284 {mayHaveInferredPersonalization && ( 285 <div className="check-wrapper" role="presentation"> 286 <input 287 id="inferred-personalization" 288 className="customize-menu-checkbox" 289 disabled={!pocketEnabled} 290 checked={showInferredPersonalizationEnabled} 291 type="checkbox" 292 onChange={this.onPreferenceSelect} 293 data-preference="discoverystream.sections.personalization.inferred.user.enabled" 294 data-eventSource="INFERRED_PERSONALIZATION" 295 /> 296 <label 297 className="customize-menu-checkbox-label" 298 htmlFor="inferred-personalization" 299 data-l10n-id="newtab-custom-stories-personalized-checkbox-label" 300 /> 301 </div> 302 )} 303 {mayHaveTopicSections && ( 304 <SectionsMgmtPanel 305 exitEventFired={exitEventFired} 306 pocketEnabled={pocketEnabled} 307 onSubpanelToggle={onSubpanelToggle} 308 togglePanel={toggleSectionsMgmtPanel} 309 showPanel={showSectionsMgmtPanel} 310 /> 311 )} 312 </div> 313 </div> 314 )} 315 </div> 316 </moz-toggle> 317 </div> 318 )} 319 </div> 320 321 <span className="divider" role="separator"></span> 322 323 <div> 324 <button 325 id="settings-link" 326 className="external-link" 327 onClick={openPreferences} 328 data-l10n-id="newtab-custom-settings" 329 /> 330 </div> 331 </div> 332 ); 333 } 334 }