44
55import * as Common from '../../core/common/common.js' ;
66import * as i18n from '../../core/i18n/i18n.js' ;
7+ import * as Platform from '../../core/platform/platform.js' ;
78import * as SDK from '../../core/sdk/sdk.js' ;
9+ import * as Lit from '../../ui/lit/lit.js' ;
10+ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js' ;
811
9- import { ThrottlingPresets , type NetworkThrottlingConditionsGroup } from './ThrottlingPresets.js' ;
12+ import { ThrottlingManager } from './ThrottlingManager.js' ;
13+ import { type NetworkThrottlingConditionsGroup , ThrottlingPresets } from './ThrottlingPresets.js' ;
14+
15+ const { render, html, Directives} = Lit ;
1016
1117const UIStrings = {
1218 /**
@@ -21,66 +27,198 @@ const UIStrings = {
2127 * @description Text in Network Throttling Selector of the Network panel
2228 */
2329 custom : 'Custom' ,
30+ /**
31+ *@description Text with two placeholders separated by a colon
32+ *@example {Node removed} PH1
33+ *@example {div#id1} PH2
34+ */
35+ sS : '{PH1}: {PH2}' ,
36+ /**
37+ *@description Accessibility label for custom add network throttling option
38+ *@example {Custom} PH1
39+ */
40+ addS : 'Add {PH1}' ,
41+ /**
42+ *@description Text in Throttling Manager of the Network panel
43+ */
44+ add : 'Add…' ,
45+ /**
46+ * @description Text label for a selection box showing that a specific option is recommended for CPU or Network throttling.
47+ * @example {Fast 4G} PH1
48+ * @example {4x slowdown} PH1
49+ */
50+ recommendedThrottling : '{PH1} – recommended' ,
2451} as const ;
2552const str_ = i18n . i18n . registerUIStrings ( 'panels/mobile_throttling/NetworkThrottlingSelector.ts' , UIStrings ) ;
2653const i18nString = i18n . i18n . getLocalizedString . bind ( undefined , str_ ) ;
27- export class NetworkThrottlingSelector {
28- private populateCallback : ( arg0 : NetworkThrottlingConditionsGroup [ ] ) => Array < SDK . NetworkManager . Conditions | null > ;
29- private readonly selectCallback : ( arg0 : number ) => void ;
30- private readonly customNetworkConditionsSetting : Common . Settings . Setting < SDK . NetworkManager . Conditions [ ] > ;
31- private options ! : Array < SDK . NetworkManager . Conditions | null > ;
3254
33- constructor (
34- populateCallback : ( arg0 : NetworkThrottlingConditionsGroup [ ] ) => Array < SDK . NetworkManager . Conditions | null > ,
35- selectCallback : ( arg0 : number ) => void ,
36- customNetworkConditionsSetting : Common . Settings . Setting < SDK . NetworkManager . Conditions [ ] > ) {
37- this . populateCallback = populateCallback ;
38- this . selectCallback = selectCallback ;
39- this . customNetworkConditionsSetting = customNetworkConditionsSetting ;
40- this . customNetworkConditionsSetting . addChangeListener ( this . populateOptions , this ) ;
55+ interface ViewInput {
56+ recommendedConditions : SDK . NetworkManager . Conditions | null ;
57+ selectedConditions : SDK . NetworkManager . Conditions ;
58+ throttlingGroups : NetworkThrottlingConditionsGroup [ ] ;
59+ customConditionsGroup : NetworkThrottlingConditionsGroup ;
60+ jslogContext : string ;
61+ title : string ;
62+ onSelect : ( conditions : SDK . NetworkManager . Conditions ) => void ;
63+ onAddCustomConditions : ( ) => void ;
64+ }
65+ export type ViewFunction = ( input : ViewInput , output : object , target : HTMLElement ) => void ;
66+
67+ export const DEFAULT_VIEW : ViewFunction = ( input , output , target ) => {
68+ // The title is usually an i18nLazyString except for custom values that are stored in the local storage in the form of a string.
69+ const title = ( conditions : SDK . NetworkManager . Conditions ) : string =>
70+ typeof conditions . title === 'function' ? conditions . title ( ) : conditions . title ;
71+ const jslog = ( group : NetworkThrottlingConditionsGroup , condition : SDK . NetworkManager . Conditions ) : string =>
72+ `${ VisualLogging . item ( Platform . StringUtilities . toKebabCase ( condition . i18nTitleKey || title ( condition ) ) ) . track ( {
73+ click : true
74+ } ) } `;
75+ const optionsMap = new WeakMap < HTMLOptionElement , SDK . NetworkManager . Conditions > ( ) ;
76+ let selectedConditions = input . selectedConditions ;
77+ function onSelect ( event : Event ) : void {
78+ const element = ( event . target as HTMLSelectElement | null ) ;
79+ if ( ! element ) {
80+ return ;
81+ }
82+ const option = element . selectedOptions [ 0 ] ;
83+ if ( ! option ) {
84+ return ;
85+ }
86+ if ( option === element . options [ element . options . length - 1 ] ) {
87+ input . onAddCustomConditions ( ) ;
88+ event . consume ( true ) ;
89+ element . value = title ( selectedConditions ) ;
90+ } else {
91+ const conditions = optionsMap . get ( option ) ;
92+ if ( conditions ) {
93+ selectedConditions = conditions ;
94+ input . onSelect ( conditions ) ;
95+ }
96+ }
97+ }
98+ render (
99+ // clang-format off
100+ html `< select
101+ aria-label =${ input . title }
102+ jslog =${ VisualLogging . dropDown ( ) . track ( { change : true } ) . context ( input . jslogContext ) }
103+ @change=${ onSelect } >
104+ ${ input . throttlingGroups . map (
105+ group =>
106+ html `< optgroup
107+ label =${ group . title } >
108+ ${ group . items . map ( condition => html `< option
109+ ${ Directives . ref ( option => option && optionsMap . set ( option as HTMLOptionElement , condition ) ) }
110+ ?selected =${ SDK . NetworkManager . networkConditionsEqual ( condition , selectedConditions ) }
111+ value =${ title ( condition ) }
112+ aria-label=${ i18nString ( UIStrings . sS , { PH1 : group . title , PH2 : title ( condition ) } ) }
113+ jslog=${ jslog ( group , condition ) } >
114+ ${ condition === input . recommendedConditions ?
115+ i18nString ( UIStrings . recommendedThrottling , { PH1 : title ( condition ) } ) :
116+ title ( condition ) }
117+ </ option > ` ) }
118+ </ optgroup > ` ) }
119+ < optgroup label =${ input . customConditionsGroup . title } >
120+ ${ input . customConditionsGroup . items . map ( condition => html `< option
121+ ${ Directives . ref ( option => option && optionsMap . set ( option as HTMLOptionElement , condition ) ) }
122+ ?selected =${ SDK . NetworkManager . networkConditionsEqual ( condition , selectedConditions ) }
123+ value =${ title ( condition ) }
124+ aria-label=${ i18nString ( UIStrings . sS , { PH1 : input . customConditionsGroup . title , PH2 : title ( condition ) } ) }
125+ jslog=${ VisualLogging . item ( 'custom-network-throttling-item' ) . track ( { click : true } ) } >
126+ ${ condition === input . recommendedConditions ?
127+ i18nString ( UIStrings . recommendedThrottling , { PH1 : title ( condition ) } ) :
128+ title ( condition ) }
129+ </ option > ` ) }
130+ < option
131+ value =${ i18nString ( UIStrings . add ) }
132+ aria-label =${ i18nString ( UIStrings . addS , { PH1 : input . customConditionsGroup . title } ) }
133+ jslog=${ VisualLogging . action ( 'add' ) . track ( { click : true } ) } >
134+ ${ i18nString ( UIStrings . add ) }
135+ </ option >
136+ </ optgroup >
137+ </ select > ` , // clang-format on
138+ target ) ;
139+ } ;
140+
141+ export const enum Events {
142+ CONDITIONS_CHANGED = 'conditionsChanged' ,
143+ }
144+
145+ export interface EventTypes {
146+ [ Events . CONDITIONS_CHANGED ] : SDK . NetworkManager . Conditions ;
147+ }
148+
149+ export class NetworkThrottlingSelect extends Common . ObjectWrapper . ObjectWrapper < EventTypes > {
150+ #recommendedConditions: SDK . NetworkManager . Conditions | null = null ;
151+ readonly #element: HTMLElement ;
152+ readonly #jslogContext: string ;
153+ #currentConditions: SDK . NetworkManager . Conditions ;
154+ readonly #title: string ;
155+ readonly #view: ViewFunction ;
156+
157+ static createForGlobalConditions ( element : HTMLElement , title : string ) : NetworkThrottlingSelect {
158+ ThrottlingManager . instance ( ) ; // Instantiate the throttling manager to connect network manager with the setting
159+ const select = new NetworkThrottlingSelect (
160+ element , title , SDK . NetworkManager . activeNetworkThrottlingKeySetting ( ) . name ,
161+ SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . networkConditions ( ) ) ;
162+ select . addEventListener (
163+ Events . CONDITIONS_CHANGED ,
164+ ev => SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . setNetworkConditions ( ev . data ) ) ;
41165 SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . addEventListener (
42166 SDK . NetworkManager . MultitargetNetworkManager . Events . CONDITIONS_CHANGED , ( ) => {
43- this . networkConditionsChanged ( ) ;
44- } , this ) ;
45- this . populateOptions ( ) ;
167+ select . currentConditions = SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . networkConditions ( ) ;
168+ } ) ;
169+ return select ;
46170 }
47171
48- revealAndUpdate ( ) : void {
49- void Common . Revealer . reveal ( this . customNetworkConditionsSetting ) ;
50- this . networkConditionsChanged ( ) ;
172+ constructor (
173+ element : HTMLElement , title : string , jslogContext : string , currentConditions : SDK . NetworkManager . Conditions ,
174+ view = DEFAULT_VIEW ) {
175+ super ( ) ;
176+ SDK . NetworkManager . customUserNetworkConditionsSetting ( ) . addChangeListener ( this . #performUpdate, this ) ;
177+ this . #element = element ;
178+ this . #jslogContext = jslogContext ;
179+ this . #currentConditions = currentConditions ;
180+ this . #title = title ;
181+ this . #view = view ;
182+
183+ this . #performUpdate( ) ;
51184 }
52185
53- optionSelected ( conditions : SDK . NetworkManager . Conditions ) : void {
54- SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . setNetworkConditions ( conditions ) ;
186+ set recommendedConditions ( recommendedConditions : SDK . NetworkManager . Conditions | null ) {
187+ this . #recommendedConditions = recommendedConditions ;
188+ this . #performUpdate( ) ;
55189 }
56190
57- private populateOptions ( ) : void {
58- const disabledGroup = { title : i18nString ( UIStrings . disabled ) , items : [ SDK . NetworkManager . NoThrottlingConditions ] } ;
59- const presetsGroup = { title : i18nString ( UIStrings . presets ) , items : ThrottlingPresets . networkPresets } ;
60- const customGroup = { title : i18nString ( UIStrings . custom ) , items : this . customNetworkConditionsSetting . get ( ) } ;
61- this . options = this . populateCallback ( [ disabledGroup , presetsGroup , customGroup ] ) ;
62- if ( ! this . networkConditionsChanged ( ) ) {
63- for ( let i = this . options . length - 1 ; i >= 0 ; i -- ) {
64- if ( this . options [ i ] ) {
65- this . optionSelected ( this . options [ i ] as SDK . NetworkManager . Conditions ) ;
66- break ;
67- }
68- }
69- }
191+ set currentConditions ( currentConditions : SDK . NetworkManager . Conditions ) {
192+ this . #currentConditions = currentConditions ;
193+ this . #performUpdate( ) ;
70194 }
71195
72- /**
73- * returns false if selected condition no longer exists
74- */
75- private networkConditionsChanged ( ) : boolean {
76- const value = SDK . NetworkManager . MultitargetNetworkManager . instance ( ) . networkConditions ( ) ;
77- for ( let index = 0 ; index < this . options . length ; ++ index ) {
78- const option = this . options [ index ] ;
79- if ( option && SDK . NetworkManager . networkConditionsEqual ( value , option ) ) {
80- this . selectCallback ( index ) ;
81- return true ;
82- }
83- }
84- return false ;
196+ #performUpdate( ) : void {
197+ const customNetworkConditionsSetting = SDK . NetworkManager . customUserNetworkConditionsSetting ( ) ;
198+ const customNetworkConditions = customNetworkConditionsSetting . get ( ) ;
199+ const onAddCustomConditions = ( ) : void => {
200+ void Common . Revealer . reveal ( SDK . NetworkManager . customUserNetworkConditionsSetting ( ) ) ;
201+ } ;
202+
203+ const onSelect = ( conditions : SDK . NetworkManager . Conditions ) : void => {
204+ this . dispatchEventToListeners ( Events . CONDITIONS_CHANGED , conditions ) ;
205+ } ;
206+
207+ const throttlingGroups = [
208+ { title : i18nString ( UIStrings . disabled ) , items : [ SDK . NetworkManager . NoThrottlingConditions ] } ,
209+ { title : i18nString ( UIStrings . presets ) , items : ThrottlingPresets . networkPresets } ,
210+ ] ;
211+ const customConditionsGroup = { title : i18nString ( UIStrings . custom ) , items : customNetworkConditions } ;
212+ const viewInput : ViewInput = {
213+ recommendedConditions : this . #recommendedConditions,
214+ selectedConditions : this . #currentConditions,
215+ jslogContext : this . #jslogContext,
216+ title : this . #title,
217+ onSelect,
218+ onAddCustomConditions,
219+ throttlingGroups,
220+ customConditionsGroup,
221+ } ;
222+ this . #view( viewInput , { } , this . #element) ;
85223 }
86224}
0 commit comments