Settings.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import{ObjectWrapper}from'./Object.js';export class Settings{constructor(globalStorage,localStorage){this._globalStorage=globalStorage;this._localStorage=localStorage;this._sessionStorage=new SettingsStorage({});this._eventSupport=new ObjectWrapper();this._registry=new Map();this._moduleSettings=new Map();self.runtime.extensions('setting').forEach(this._registerModuleSetting.bind(this));}
  2. _registerModuleSetting(extension){const descriptor=extension.descriptor();const settingName=descriptor['settingName'];const isRegex=descriptor['settingType']==='regex';const defaultValue=descriptor['defaultValue'];let storageType;switch(descriptor['storageType']){case('local'):storageType=SettingStorageType.Local;break;case('session'):storageType=SettingStorageType.Session;break;case('global'):storageType=SettingStorageType.Global;break;default:storageType=SettingStorageType.Global;}
  3. const setting=isRegex?this.createRegExpSetting(settingName,defaultValue,undefined,storageType):this.createSetting(settingName,defaultValue,storageType);if(extension.title()){setting.setTitle(extension.title());}
  4. if(descriptor['userActionCondition']){setting.setRequiresUserAction(!!Root.Runtime.queryParam(descriptor['userActionCondition']));}
  5. setting._extension=extension;this._moduleSettings.set(settingName,setting);}
  6. moduleSetting(settingName){const setting=this._moduleSettings.get(settingName);if(!setting){throw new Error('No setting registered: '+settingName);}
  7. return setting;}
  8. settingForTest(settingName){const setting=this._registry.get(settingName);if(!setting){throw new Error('No setting registered: '+settingName);}
  9. return setting;}
  10. createSetting(key,defaultValue,storageType){const storage=this._storageFromType(storageType);if(!this._registry.get(key)){this._registry.set(key,new Setting(this,key,defaultValue,this._eventSupport,storage));}
  11. return(this._registry.get(key));}
  12. createLocalSetting(key,defaultValue){return this.createSetting(key,defaultValue,SettingStorageType.Local);}
  13. createRegExpSetting(key,defaultValue,regexFlags,storageType){if(!this._registry.get(key)){this._registry.set(key,new RegExpSetting(this,key,defaultValue,this._eventSupport,this._storageFromType(storageType),regexFlags));}
  14. return(this._registry.get(key));}
  15. clearAll(){this._globalStorage.removeAll();this._localStorage.removeAll();const versionSetting=Common.settings.createSetting(VersionController._currentVersionName,0);versionSetting.set(VersionController.currentVersion);}
  16. _storageFromType(storageType){switch(storageType){case(SettingStorageType.Local):return this._localStorage;case(SettingStorageType.Session):return this._sessionStorage;case(SettingStorageType.Global):return this._globalStorage;}
  17. return this._globalStorage;}}
  18. export class SettingsStorage{constructor(object,setCallback,removeCallback,removeAllCallback,storagePrefix){this._object=object;this._setCallback=setCallback||function(){};this._removeCallback=removeCallback||function(){};this._removeAllCallback=removeAllCallback||function(){};this._storagePrefix=storagePrefix||'';}
  19. set(name,value){name=this._storagePrefix+name;this._object[name]=value;this._setCallback(name,value);}
  20. has(name){name=this._storagePrefix+name;return name in this._object;}
  21. get(name){name=this._storagePrefix+name;return this._object[name];}
  22. remove(name){name=this._storagePrefix+name;delete this._object[name];this._removeCallback(name);}
  23. removeAll(){this._object={};this._removeAllCallback();}
  24. _dumpSizes(){Common.console.log('Ten largest settings: ');const sizes={__proto__:null};for(const key in this._object){sizes[key]=this._object[key].length;}
  25. const keys=Object.keys(sizes);function comparator(key1,key2){return sizes[key2]-sizes[key1];}
  26. keys.sort(comparator);for(let i=0;i<10&&i<keys.length;++i){Common.console.log('Setting: \''+keys[i]+'\', size: '+sizes[keys[i]]);}}}
  27. export class Setting{constructor(settings,name,defaultValue,eventSupport,storage){this._settings=settings;this._name=name;this._defaultValue=defaultValue;this._eventSupport=eventSupport;this._storage=storage;this._title='';this._extension=null;}
  28. addChangeListener(listener,thisObject){return this._eventSupport.addEventListener(this._name,listener,thisObject);}
  29. removeChangeListener(listener,thisObject){this._eventSupport.removeEventListener(this._name,listener,thisObject);}
  30. get name(){return this._name;}
  31. title(){return this._title;}
  32. setTitle(title){this._title=title;}
  33. setRequiresUserAction(requiresUserAction){this._requiresUserAction=requiresUserAction;}
  34. get(){if(this._requiresUserAction&&!this._hadUserAction){return this._defaultValue;}
  35. if(typeof this._value!=='undefined'){return this._value;}
  36. this._value=this._defaultValue;if(this._storage.has(this._name)){try{this._value=JSON.parse(this._storage.get(this._name));}catch(e){this._storage.remove(this._name);}}
  37. return this._value;}
  38. set(value){this._hadUserAction=true;this._value=value;try{const settingString=JSON.stringify(value);try{this._storage.set(this._name,settingString);}catch(e){this._printSettingsSavingError(e.message,this._name,settingString);}}catch(e){Common.console.error('Cannot stringify setting with name: '+this._name+', error: '+e.message);}
  39. this._eventSupport.dispatchEventToListeners(this._name,value);}
  40. remove(){this._settings._registry.delete(this._name);this._settings._moduleSettings.delete(this._name);this._storage.remove(this._name);}
  41. extension(){return this._extension;}
  42. _printSettingsSavingError(message,name,value){const errorMessage='Error saving setting with name: '+this._name+', value length: '+value.length+'. Error: '+message;console.error(errorMessage);Common.console.error(errorMessage);this._storage._dumpSizes();}}
  43. export class RegExpSetting extends Setting{constructor(settings,name,defaultValue,eventSupport,storage,regexFlags){super(settings,name,defaultValue?[{pattern:defaultValue}]:[],eventSupport,storage);this._regexFlags=regexFlags;}
  44. get(){const result=[];const items=this.getAsArray();for(let i=0;i<items.length;++i){const item=items[i];if(item.pattern&&!item.disabled){result.push(item.pattern);}}
  45. return result.join('|');}
  46. getAsArray(){return super.get();}
  47. set(value){this.setAsArray([{pattern:value}]);}
  48. setAsArray(value){delete this._regex;super.set(value);}
  49. asRegExp(){if(typeof this._regex!=='undefined'){return this._regex;}
  50. this._regex=null;try{const pattern=this.get();if(pattern){this._regex=new RegExp(pattern,this._regexFlags||'');}}catch(e){}
  51. return this._regex;}}
  52. export class VersionController{static get _currentVersionName(){return'inspectorVersion';}
  53. static get currentVersion(){return 28;}
  54. updateVersion(){const localStorageVersion=window.localStorage?window.localStorage[VersionController._currentVersionName]:0;const versionSetting=Common.settings.createSetting(VersionController._currentVersionName,0);const currentVersion=VersionController.currentVersion;const oldVersion=versionSetting.get()||parseInt(localStorageVersion||'0',10);if(oldVersion===0){versionSetting.set(currentVersion);return;}
  55. const methodsToRun=this._methodsToRunToUpdateVersion(oldVersion,currentVersion);for(let i=0;i<methodsToRun.length;++i){this[methodsToRun[i]].call(this);}
  56. versionSetting.set(currentVersion);}
  57. _methodsToRunToUpdateVersion(oldVersion,currentVersion){const result=[];for(let i=oldVersion;i<currentVersion;++i){result.push('_updateVersionFrom'+i+'To'+(i+1));}
  58. return result;}
  59. _updateVersionFrom0To1(){this._clearBreakpointsWhenTooMany(Common.settings.createLocalSetting('breakpoints',[]),500000);}
  60. _updateVersionFrom1To2(){Common.settings.createSetting('previouslyViewedFiles',[]).set([]);}
  61. _updateVersionFrom2To3(){Common.settings.createSetting('fileSystemMapping',{}).set({});Common.settings.createSetting('fileMappingEntries',[]).remove();}
  62. _updateVersionFrom3To4(){const advancedMode=Common.settings.createSetting('showHeaSnapshotObjectsHiddenProperties',false);Common.moduleSetting('showAdvancedHeapSnapshotProperties').set(advancedMode.get());advancedMode.remove();}
  63. _updateVersionFrom4To5(){const settingNames={'FileSystemViewSidebarWidth':'fileSystemViewSplitViewState','elementsSidebarWidth':'elementsPanelSplitViewState','StylesPaneSplitRatio':'stylesPaneSplitViewState','heapSnapshotRetainersViewSize':'heapSnapshotSplitViewState','InspectorView.splitView':'InspectorView.splitViewState','InspectorView.screencastSplitView':'InspectorView.screencastSplitViewState','Inspector.drawerSplitView':'Inspector.drawerSplitViewState','layerDetailsSplitView':'layerDetailsSplitViewState','networkSidebarWidth':'networkPanelSplitViewState','sourcesSidebarWidth':'sourcesPanelSplitViewState','scriptsPanelNavigatorSidebarWidth':'sourcesPanelNavigatorSplitViewState','sourcesPanelSplitSidebarRatio':'sourcesPanelDebuggerSidebarSplitViewState','timeline-details':'timelinePanelDetailsSplitViewState','timeline-split':'timelinePanelRecorsSplitViewState','timeline-view':'timelinePanelTimelineStackSplitViewState','auditsSidebarWidth':'auditsPanelSplitViewState','layersSidebarWidth':'layersPanelSplitViewState','profilesSidebarWidth':'profilesPanelSplitViewState','resourcesSidebarWidth':'resourcesPanelSplitViewState'};const empty={};for(const oldName in settingNames){const newName=settingNames[oldName];const oldNameH=oldName+'H';let newValue=null;const oldSetting=Common.settings.createSetting(oldName,empty);if(oldSetting.get()!==empty){newValue=newValue||{};newValue.vertical={};newValue.vertical.size=oldSetting.get();oldSetting.remove();}
  64. const oldSettingH=Common.settings.createSetting(oldNameH,empty);if(oldSettingH.get()!==empty){newValue=newValue||{};newValue.horizontal={};newValue.horizontal.size=oldSettingH.get();oldSettingH.remove();}
  65. if(newValue){Common.settings.createSetting(newName,{}).set(newValue);}}}
  66. _updateVersionFrom5To6(){const settingNames={'debuggerSidebarHidden':'sourcesPanelSplitViewState','navigatorHidden':'sourcesPanelNavigatorSplitViewState','WebInspector.Drawer.showOnLoad':'Inspector.drawerSplitViewState'};for(const oldName in settingNames){const oldSetting=Common.settings.createSetting(oldName,null);if(oldSetting.get()===null){oldSetting.remove();continue;}
  67. const newName=settingNames[oldName];const invert=oldName==='WebInspector.Drawer.showOnLoad';const hidden=oldSetting.get()!==invert;oldSetting.remove();const showMode=hidden?'OnlyMain':'Both';const newSetting=Common.settings.createSetting(newName,{});const newValue=newSetting.get()||{};newValue.vertical=newValue.vertical||{};newValue.vertical.showMode=showMode;newValue.horizontal=newValue.horizontal||{};newValue.horizontal.showMode=showMode;newSetting.set(newValue);}}
  68. _updateVersionFrom6To7(){const settingNames={'sourcesPanelNavigatorSplitViewState':'sourcesPanelNavigatorSplitViewState','elementsPanelSplitViewState':'elementsPanelSplitViewState','stylesPaneSplitViewState':'stylesPaneSplitViewState','sourcesPanelDebuggerSidebarSplitViewState':'sourcesPanelDebuggerSidebarSplitViewState'};const empty={};for(const name in settingNames){const setting=Common.settings.createSetting(name,empty);const value=setting.get();if(value===empty){continue;}
  69. if(value.vertical&&value.vertical.size&&value.vertical.size<1){value.vertical.size=0;}
  70. if(value.horizontal&&value.horizontal.size&&value.horizontal.size<1){value.horizontal.size=0;}
  71. setting.set(value);}}
  72. _updateVersionFrom7To8(){}
  73. _updateVersionFrom8To9(){const settingNames=['skipStackFramesPattern','workspaceFolderExcludePattern'];for(let i=0;i<settingNames.length;++i){const setting=Common.settings.createSetting(settingNames[i],'');let value=setting.get();if(!value){return;}
  74. if(typeof value==='string'){value=[value];}
  75. for(let j=0;j<value.length;++j){if(typeof value[j]==='string'){value[j]={pattern:value[j]};}}
  76. setting.set(value);}}
  77. _updateVersionFrom9To10(){if(!window.localStorage){return;}
  78. for(const key in window.localStorage){if(key.startsWith('revision-history')){window.localStorage.removeItem(key);}}}
  79. _updateVersionFrom10To11(){const oldSettingName='customDevicePresets';const newSettingName='customEmulatedDeviceList';const oldSetting=Common.settings.createSetting(oldSettingName,undefined);const list=oldSetting.get();if(!Array.isArray(list)){return;}
  80. const newList=[];for(let i=0;i<list.length;++i){const value=list[i];const device={};device['title']=value['title'];device['type']='unknown';device['user-agent']=value['userAgent'];device['capabilities']=[];if(value['touch']){device['capabilities'].push('touch');}
  81. if(value['mobile']){device['capabilities'].push('mobile');}
  82. device['screen']={};device['screen']['vertical']={width:value['width'],height:value['height']};device['screen']['horizontal']={width:value['height'],height:value['width']};device['screen']['device-pixel-ratio']=value['deviceScaleFactor'];device['modes']=[];device['show-by-default']=true;device['show']='Default';newList.push(device);}
  83. if(newList.length){Common.settings.createSetting(newSettingName,[]).set(newList);}
  84. oldSetting.remove();}
  85. _updateVersionFrom11To12(){this._migrateSettingsFromLocalStorage();}
  86. _updateVersionFrom12To13(){this._migrateSettingsFromLocalStorage();Common.settings.createSetting('timelineOverviewMode','').remove();}
  87. _updateVersionFrom13To14(){const defaultValue={'throughput':-1,'latency':0};Common.settings.createSetting('networkConditions',defaultValue).set(defaultValue);}
  88. _updateVersionFrom14To15(){const setting=Common.settings.createLocalSetting('workspaceExcludedFolders',{});const oldValue=setting.get();const newValue={};for(const fileSystemPath in oldValue){newValue[fileSystemPath]=[];for(const entry of oldValue[fileSystemPath]){newValue[fileSystemPath].push(entry.path);}}
  89. setting.set(newValue);}
  90. _updateVersionFrom15To16(){const setting=Common.settings.createSetting('InspectorView.panelOrder',{});const tabOrders=setting.get();for(const key of Object.keys(tabOrders)){tabOrders[key]=(tabOrders[key]+1)*10;}
  91. setting.set(tabOrders);}
  92. _updateVersionFrom16To17(){const setting=Common.settings.createSetting('networkConditionsCustomProfiles',[]);const oldValue=setting.get();const newValue=[];if(Array.isArray(oldValue)){for(const preset of oldValue){if(typeof preset.title==='string'&&typeof preset.value==='object'&&typeof preset.value.throughput==='number'&&typeof preset.value.latency==='number'){newValue.push({title:preset.title,value:{download:preset.value.throughput,upload:preset.value.throughput,latency:preset.value.latency}});}}}
  93. setting.set(newValue);}
  94. _updateVersionFrom17To18(){const setting=Common.settings.createLocalSetting('workspaceExcludedFolders',{});const oldValue=setting.get();const newValue={};for(const oldKey in oldValue){let newKey=oldKey.replace(/\\/g,'/');if(!newKey.startsWith('file://')){if(newKey.startsWith('/')){newKey='file://'+newKey;}else{newKey='file:///'+newKey;}}
  95. newValue[newKey]=oldValue[oldKey];}
  96. setting.set(newValue);}
  97. _updateVersionFrom18To19(){const defaultColumns={status:true,type:true,initiator:true,size:true,time:true};const visibleColumnSettings=Common.settings.createSetting('networkLogColumnsVisibility',defaultColumns);const visibleColumns=visibleColumnSettings.get();visibleColumns.name=true;visibleColumns.timeline=true;const configs={};for(const columnId in visibleColumns){if(!visibleColumns.hasOwnProperty(columnId)){continue;}
  98. configs[columnId.toLowerCase()]={visible:visibleColumns[columnId]};}
  99. const newSetting=Common.settings.createSetting('networkLogColumns',{});newSetting.set(configs);visibleColumnSettings.remove();}
  100. _updateVersionFrom19To20(){const oldSetting=Common.settings.createSetting('InspectorView.panelOrder',{});const newSetting=Common.settings.createSetting('panel-tabOrder',{});newSetting.set(oldSetting.get());oldSetting.remove();}
  101. _updateVersionFrom20To21(){const networkColumns=Common.settings.createSetting('networkLogColumns',{});const columns=(networkColumns.get());delete columns['timeline'];delete columns['waterfall'];networkColumns.set(columns);}
  102. _updateVersionFrom21To22(){const breakpointsSetting=Common.settings.createLocalSetting('breakpoints',[]);const breakpoints=breakpointsSetting.get();for(const breakpoint of breakpoints){breakpoint['url']=breakpoint['sourceFileId'];delete breakpoint['sourceFileId'];}
  103. breakpointsSetting.set(breakpoints);}
  104. _updateVersionFrom22To23(){}
  105. _updateVersionFrom23To24(){const oldSetting=Common.settings.createSetting('searchInContentScripts',false);const newSetting=Common.settings.createSetting('searchInAnonymousAndContentScripts',false);newSetting.set(oldSetting.get());oldSetting.remove();}
  106. _updateVersionFrom24To25(){const defaultColumns={status:true,type:true,initiator:true,size:true,time:true};const networkLogColumnsSetting=Common.settings.createSetting('networkLogColumns',defaultColumns);const columns=networkLogColumnsSetting.get();delete columns.product;networkLogColumnsSetting.set(columns);}
  107. _updateVersionFrom25To26(){const oldSetting=Common.settings.createSetting('messageURLFilters',{});const urls=Object.keys(oldSetting.get());const textFilter=urls.map(url=>`-url:${url}`).join(' ');if(textFilter){const textFilterSetting=Common.settings.createSetting('console.textFilter','');const suffix=textFilterSetting.get()?` ${textFilterSetting.get()}`:'';textFilterSetting.set(`${textFilter}${suffix}`);}
  108. oldSetting.remove();}
  109. _updateVersionFrom26To27(){function renameKeyInObjectSetting(settingName,from,to){const setting=Common.settings.createSetting(settingName,{});const value=setting.get();if(from in value){value[to]=value[from];delete value[from];setting.set(value);}}
  110. function renameInStringSetting(settingName,from,to){const setting=Common.settings.createSetting(settingName,'');const value=setting.get();if(value===from){setting.set(to);}}
  111. renameKeyInObjectSetting('panel-tabOrder','audits2','audits');renameKeyInObjectSetting('panel-closeableTabs','audits2','audits');renameInStringSetting('panel-selectedTab','audits2','audits');}
  112. _updateVersionFrom27To28(){const setting=Common.settings.createSetting('uiTheme','systemPreferred');if(setting.get()==='default'){setting.set('systemPreferred');}}
  113. _migrateSettingsFromLocalStorage(){const localSettings=new Set(['advancedSearchConfig','breakpoints','consoleHistory','domBreakpoints','eventListenerBreakpoints','fileSystemMapping','lastSelectedSourcesSidebarPaneTab','previouslyViewedFiles','savedURLs','watchExpressions','workspaceExcludedFolders','xhrBreakpoints']);if(!window.localStorage){return;}
  114. for(const key in window.localStorage){if(localSettings.has(key)){continue;}
  115. const value=window.localStorage[key];window.localStorage.removeItem(key);Common.settings._globalStorage[key]=value;}}
  116. _clearBreakpointsWhenTooMany(breakpointsSetting,maxBreakpointsCount){if(breakpointsSetting.get().length>maxBreakpointsCount){breakpointsSetting.set([]);}}}
  117. export const SettingStorageType={Global:Symbol('Global'),Local:Symbol('Local'),Session:Symbol('Session')};export function moduleSetting(settingName){return Common.settings.moduleSetting(settingName);}
  118. export function settingForTest(settingName){return Common.settings.settingForTest(settingName);}
  119. self.Common=self.Common||{};Common=Common||{};Common.Settings=Settings;Common.SettingsStorage=SettingsStorage;Common.Setting=Setting;Common.RegExpSetting=RegExpSetting;Common.settingForTest=settingForTest;Common.VersionController=VersionController;Common.moduleSetting=moduleSetting;Common.SettingStorageType=SettingStorageType;Common.settings;