SearchShortcutsForm.jsx (5413B)
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 { actionCreators as ac, actionTypes as at } from "common/Actions.mjs"; 6 import React from "react"; 7 import { TOP_SITES_SOURCE } from "./TopSitesConstants"; 8 9 export class SelectableSearchShortcut extends React.PureComponent { 10 render() { 11 const { shortcut, selected } = this.props; 12 const imageStyle = { backgroundImage: `url("${shortcut.tippyTopIcon}")` }; 13 return ( 14 <div className="top-site-outer search-shortcut"> 15 <input 16 type="checkbox" 17 id={shortcut.keyword} 18 name={shortcut.keyword} 19 checked={selected} 20 onChange={this.props.onChange} 21 /> 22 <label htmlFor={shortcut.keyword}> 23 <div className="top-site-inner"> 24 <span> 25 <div className="tile"> 26 <div 27 className="top-site-icon rich-icon" 28 style={imageStyle} 29 data-fallback="@" 30 /> 31 <div className="top-site-icon search-topsite" /> 32 </div> 33 <div className="title"> 34 <span dir="auto">{shortcut.keyword}</span> 35 </div> 36 </span> 37 </div> 38 </label> 39 </div> 40 ); 41 } 42 } 43 44 export class SearchShortcutsForm extends React.PureComponent { 45 constructor(props) { 46 super(props); 47 this.handleChange = this.handleChange.bind(this); 48 this.onCancelButtonClick = this.onCancelButtonClick.bind(this); 49 this.onSaveButtonClick = this.onSaveButtonClick.bind(this); 50 51 // clone the shortcuts and add them to the state so we can add isSelected property 52 const shortcuts = []; 53 const { rows, searchShortcuts } = props.TopSites; 54 searchShortcuts.forEach(shortcut => { 55 shortcuts.push({ 56 ...shortcut, 57 isSelected: !!rows.find( 58 row => 59 row && 60 row.isPinned && 61 row.searchTopSite && 62 row.label === shortcut.keyword 63 ), 64 }); 65 }); 66 this.state = { shortcuts }; 67 } 68 69 handleChange(event) { 70 const { target } = event; 71 const { name: targetName, checked } = target; 72 this.setState(prevState => { 73 const shortcuts = prevState.shortcuts.slice(); 74 let shortcut = shortcuts.find(({ keyword }) => keyword === targetName); 75 shortcut.isSelected = checked; 76 return { shortcuts }; 77 }); 78 } 79 80 onCancelButtonClick(ev) { 81 ev.preventDefault(); 82 this.props.onClose(); 83 } 84 85 onSaveButtonClick(ev) { 86 ev.preventDefault(); 87 88 // Check if there were any changes and act accordingly 89 const { rows } = this.props.TopSites; 90 const pinQueue = []; 91 const unpinQueue = []; 92 this.state.shortcuts.forEach(shortcut => { 93 const alreadyPinned = rows.find( 94 row => 95 row && 96 row.isPinned && 97 row.searchTopSite && 98 row.label === shortcut.keyword 99 ); 100 if (shortcut.isSelected && !alreadyPinned) { 101 pinQueue.push(this._searchTopSite(shortcut)); 102 } else if (!shortcut.isSelected && alreadyPinned) { 103 unpinQueue.push({ 104 url: alreadyPinned.url, 105 searchVendor: shortcut.shortURL, 106 }); 107 } 108 }); 109 110 // Tell the feed to do the work. 111 this.props.dispatch( 112 ac.OnlyToMain({ 113 type: at.UPDATE_PINNED_SEARCH_SHORTCUTS, 114 data: { 115 addedShortcuts: pinQueue, 116 deletedShortcuts: unpinQueue, 117 }, 118 }) 119 ); 120 121 // Send the Telemetry pings. 122 pinQueue.forEach(shortcut => { 123 this.props.dispatch( 124 ac.UserEvent({ 125 source: TOP_SITES_SOURCE, 126 event: "SEARCH_EDIT_ADD", 127 value: { search_vendor: shortcut.searchVendor }, 128 }) 129 ); 130 }); 131 unpinQueue.forEach(shortcut => { 132 this.props.dispatch( 133 ac.UserEvent({ 134 source: TOP_SITES_SOURCE, 135 event: "SEARCH_EDIT_DELETE", 136 value: { search_vendor: shortcut.searchVendor }, 137 }) 138 ); 139 }); 140 141 this.props.onClose(); 142 } 143 144 _searchTopSite(shortcut) { 145 return { 146 url: shortcut.url, 147 searchTopSite: true, 148 label: shortcut.keyword, 149 searchVendor: shortcut.shortURL, 150 }; 151 } 152 153 render() { 154 return ( 155 <form className="topsite-form"> 156 <div className="search-shortcuts-container"> 157 <h3 158 className="section-title grey-title" 159 data-l10n-id="newtab-topsites-add-search-engine-header" 160 /> 161 <div> 162 {this.state.shortcuts.map(shortcut => ( 163 <SelectableSearchShortcut 164 key={shortcut.keyword} 165 shortcut={shortcut} 166 selected={shortcut.isSelected} 167 onChange={this.handleChange} 168 /> 169 ))} 170 </div> 171 </div> 172 <section className="actions"> 173 <button 174 className="cancel" 175 type="button" 176 onClick={this.onCancelButtonClick} 177 data-l10n-id="newtab-topsites-cancel-button" 178 /> 179 <button 180 className="done" 181 type="submit" 182 onClick={this.onSaveButtonClick} 183 data-l10n-id="newtab-topsites-save-button" 184 /> 185 </section> 186 </form> 187 ); 188 } 189 }