2017-09-13 03:18:12 -07:00
'use strict' ;
2020-08-05 03:13:33 -07:00
const DCSI = 'firefox-default' ;
2018-08-16 23:16:10 -07:00
document . body . dataset . android = navigator . userAgent . indexOf ( 'Android' ) !== - 1 ;
2020-08-04 23:29:57 -07:00
let tab = { } ;
chrome . tabs . query ( {
active : true ,
currentWindow : true
} , tbs => {
if ( tbs . length ) {
tab = tbs [ 0 ] ;
if ( 'cookieStoreId' in tab ) {
const apply = document . querySelector ( '[data-cmd="apply"]' ) ;
2020-08-05 03:13:33 -07:00
apply . value = 'Apply (container)' ;
2020-08-04 23:29:57 -07:00
apply . title = 'Set this user-agent string as the current container\'s User-Agent string' ;
const w = document . querySelector ( '[data-cmd="window"]' ) ;
2020-08-05 03:13:33 -07:00
w . value = 'Apply (container on window)' ;
2020-08-04 23:29:57 -07:00
w . title = 'Set this user-agent string for all tabs inside the current window\'s container' ;
const reset = document . querySelector ( '[data-cmd="reset"]' ) ;
2020-08-05 03:13:33 -07:00
reset . value = 'Reset (container)' ;
2020-08-04 23:29:57 -07:00
reset . title = 'Reset the container\'s user-agent string to the default one. This will not reset window-based UA strings. To reset them, use the \'Restart\' button' ;
}
}
} ) ;
2019-07-31 22:41:28 -07:00
const map = { } ;
2017-09-13 03:18:12 -07:00
function sort ( arr ) {
function sort ( a = '' , b = '' ) {
const pa = a . split ( '.' ) ;
const pb = b . split ( '.' ) ;
for ( let i = 0 ; i < 3 ; i ++ ) {
const na = Number ( pa [ i ] ) ;
const nb = Number ( pb [ i ] ) ;
if ( na > nb ) {
return 1 ;
}
if ( nb > na ) {
return - 1 ;
}
if ( ! isNaN ( na ) && isNaN ( nb ) ) {
return 1 ;
}
if ( isNaN ( na ) && ! isNaN ( nb ) ) {
return - 1 ;
}
}
return 0 ;
}
const list = arr . sort ( ( a , b ) => sort ( a . browser . version , b . browser . version ) ) ;
2020-03-15 05:20:18 -07:00
if ( document . getElementById ( 'sort' ) . value === 'descending' ) {
2017-09-13 03:18:12 -07:00
return list . reverse ( ) ;
}
return list ;
}
2020-08-03 22:02:57 -07:00
function get ( path ) {
2020-08-05 22:14:37 -07:00
const cf = Promise . resolve ( {
match ( ) {
return Promise . resolve ( ) ;
} ,
add ( ) {
return Promise . resolve ( ) ;
}
} ) ;
2020-08-03 22:52:40 -07:00
return ( typeof caches !== 'undefined' ? caches : {
open ( ) {
2020-08-05 22:14:37 -07:00
return cf ;
2020-08-03 22:52:40 -07:00
}
2020-08-05 22:14:37 -07:00
} ) . open ( 'agents' ) . catch ( ( ) => cf ) . then ( cache => {
2020-08-03 22:02:57 -07:00
const link = 'https://cdn.jsdelivr.net/gh/ray-lothian/UserAgent-Switcher/node/' + path ;
2020-08-03 22:52:40 -07:00
// updating agents once per 7 days
chrome . storage . local . get ( {
[ 'cache.' + path ] : 0
} , prefs => {
const now = Date . now ( ) ;
if ( now - prefs [ 'cache.' + path ] > 7 * 24 * 60 * 60 * 1000 ) {
cache . add ( link ) . then ( ( ) => chrome . storage . local . set ( {
[ 'cache.' + path ] : now
} ) ) ;
}
2020-08-03 22:02:57 -07:00
} ) ;
2020-08-03 22:52:40 -07:00
return cache . match ( link ) . then ( resp => resp || fetch ( path ) ) ;
2020-08-03 22:02:57 -07:00
} ) ;
}
2019-07-31 22:41:28 -07:00
function update ( ua ) {
2019-03-12 02:50:52 -07:00
const browser = document . getElementById ( 'browser' ) . value ;
const os = document . getElementById ( 'os' ) . value ;
2017-09-13 03:18:12 -07:00
const t = document . querySelector ( 'template' ) ;
const parent = document . getElementById ( 'list' ) ;
const tbody = parent . querySelector ( 'tbody' ) ;
tbody . textContent = '' ;
2019-03-12 02:50:52 -07:00
2017-09-13 03:18:12 -07:00
parent . dataset . loading = true ;
2020-08-03 22:02:57 -07:00
get ( 'browsers/' + browser . toLowerCase ( ) + '-' + os . toLowerCase ( ) . replace ( /\//g , '-' ) + '.json' )
2020-08-03 21:47:39 -07:00
. then ( r => r . json ( ) ) . catch ( e => {
console . error ( e ) ;
return [ ] ;
} ) . then ( list => {
if ( list ) {
const fragment = document . createDocumentFragment ( ) ;
let radio ;
for ( const o of sort ( list ) ) {
const clone = document . importNode ( t . content , true ) ;
const second = clone . querySelector ( 'td:nth-child(2)' ) ;
2020-08-04 03:16:03 -07:00
if ( o . browser . name && o . browser . version ) {
second . title = second . textContent = o . browser . name + ' ' + ( o . browser . version || ' ' ) ;
}
else {
second . title = second . textContent = '-' ;
}
2020-08-03 21:47:39 -07:00
const third = clone . querySelector ( 'td:nth-child(3)' ) ;
2020-08-04 03:16:03 -07:00
if ( o . os . name && o . os . version ) {
third . title = third . textContent = o . os . name + ' ' + ( o . os . version || ' ' ) ;
}
else {
third . title = third . textContent = '-' ;
}
2020-08-03 21:47:39 -07:00
const forth = clone . querySelector ( 'td:nth-child(4)' ) ;
forth . title = forth . textContent = o . ua ;
if ( o . ua === ua ) {
radio = clone . querySelector ( 'input[type=radio]' ) ;
}
fragment . appendChild ( clone ) ;
2019-07-31 22:41:28 -07:00
}
2020-08-03 21:47:39 -07:00
tbody . appendChild ( fragment ) ;
if ( radio ) {
radio . checked = true ;
radio . scrollIntoView ( {
block : 'center' ,
inline : 'nearest'
} ) ;
}
document . getElementById ( 'custom' ) . placeholder = ` Filter among ${ list . length } ` ;
[ ... document . getElementById ( 'os' ) . querySelectorAll ( 'option' ) ] . forEach ( option => {
option . disabled = ( map . matching [ browser . toLowerCase ( ) ] || [ ] ) . indexOf ( option . value . toLowerCase ( ) ) === - 1 ;
2019-07-31 22:41:28 -07:00
} ) ;
}
2020-08-03 21:47:39 -07:00
else {
throw Error ( 'OS is not found' ) ;
}
2020-09-06 00:57:47 -07:00
// FF 55.0 does not support finally
} ) . catch ( ( ) => { } ) . then ( ( ) => {
2020-08-03 21:47:39 -07:00
parent . dataset . loading = false ;
} ) ;
2017-09-13 03:18:12 -07:00
}
2020-03-15 05:20:18 -07:00
document . getElementById ( 'browser' ) . addEventListener ( 'change' , e => chrome . storage . local . set ( {
'popup-browser' : e . target . value
} ) ) ;
document . getElementById ( 'os' ) . addEventListener ( 'change' , e => chrome . storage . local . set ( {
'popup-os' : e . target . value
} ) ) ;
document . getElementById ( 'sort' ) . addEventListener ( 'change' , e => chrome . storage . local . set ( {
'popup-sort' : e . target . value
} ) ) ;
2017-09-13 03:18:12 -07:00
document . addEventListener ( 'change' , ( { target } ) => {
if ( target . closest ( '#filter' ) ) {
2019-07-31 23:53:48 -07:00
chrome . storage . local . get ( {
ua : ''
} , prefs => update ( prefs . ua || navigator . userAgent ) ) ;
2017-09-13 03:18:12 -07:00
}
2018-04-10 00:50:58 -07:00
if ( target . type === 'radio' ) {
2017-09-13 03:18:12 -07:00
document . getElementById ( 'ua' ) . value = target . closest ( 'tr' ) . querySelector ( 'td:nth-child(4)' ) . textContent ;
2018-08-16 03:14:11 -07:00
document . getElementById ( 'ua' ) . dispatchEvent ( new Event ( 'input' ) ) ;
2017-09-13 03:18:12 -07:00
}
} ) ;
2019-06-25 03:22:49 -07:00
2020-08-03 22:52:40 -07:00
document . addEventListener ( 'DOMContentLoaded' , ( ) => fetch ( './map.json' ) . then ( r => r . json ( ) ) . then ( o => {
Object . assign ( map , o ) ;
2019-06-25 03:22:49 -07:00
2020-08-03 22:52:40 -07:00
const f1 = document . createDocumentFragment ( ) ;
for ( const browser of map . browser ) {
const option = document . createElement ( 'option' ) ;
option . value = option . textContent = browser ;
f1 . appendChild ( option ) ;
}
const f2 = document . createDocumentFragment ( ) ;
for ( const os of map . os ) {
const option = document . createElement ( 'option' ) ;
option . value = option . textContent = os ;
f2 . appendChild ( option ) ;
}
2019-06-25 03:22:49 -07:00
2020-08-03 22:52:40 -07:00
document . querySelector ( '#browser optgroup:last-of-type' ) . appendChild ( f1 ) ;
document . querySelector ( '#os optgroup:last-of-type' ) . appendChild ( f2 ) ;
2020-03-15 05:20:18 -07:00
2020-08-03 22:52:40 -07:00
chrome . storage . local . get ( {
'popup-browser' : 'Chrome' ,
'popup-os' : 'Windows' ,
'popup-sort' : 'descending'
} , prefs => {
document . getElementById ( 'browser' ) . value = prefs [ 'popup-browser' ] ;
document . getElementById ( 'os' ) . value = prefs [ 'popup-os' ] ;
document . getElementById ( 'sort' ) . value = prefs [ 'popup-sort' ] ;
2020-03-15 05:20:18 -07:00
2020-08-04 01:22:18 -07:00
chrome . runtime . getBackgroundPage ( bg => {
2020-08-07 21:49:30 -07:00
// Firefox in private mode -> there is no bg!
const ua = ( bg ? bg . prefs . ua : '' ) || navigator . userAgent ;
2020-08-04 01:22:18 -07:00
update ( ua ) ;
document . getElementById ( 'ua' ) . value = ua ;
document . getElementById ( 'ua' ) . dispatchEvent ( new Event ( 'input' ) ) ;
} ) ;
2020-08-03 22:52:40 -07:00
} ) ;
} ) ) ;
2017-09-13 03:18:12 -07:00
document . getElementById ( 'list' ) . addEventListener ( 'click' , ( { target } ) => {
2019-11-05 03:02:26 -08:00
const tr = target . closest ( 'tbody tr' ) ;
2017-09-13 03:18:12 -07:00
if ( tr ) {
const input = tr . querySelector ( 'input' ) ;
if ( input && input !== target ) {
2019-11-05 03:02:26 -08:00
input . checked = true ;
2017-09-13 03:18:12 -07:00
input . dispatchEvent ( new Event ( 'change' , {
bubbles : true
} ) ) ;
}
}
} ) ;
document . getElementById ( 'custom' ) . addEventListener ( 'keyup' , ( { target } ) => {
const value = target . value ;
2019-11-05 03:02:26 -08:00
[ ... document . querySelectorAll ( '#list tbody tr' ) ]
2017-09-13 03:18:12 -07:00
. forEach ( tr => tr . dataset . matched = tr . textContent . toLowerCase ( ) . indexOf ( value . toLowerCase ( ) ) !== - 1 ) ;
} ) ;
chrome . storage . onChanged . addListener ( prefs => {
if ( prefs . ua ) {
document . getElementById ( 'ua' ) . value = prefs . ua . newValue || navigator . userAgent ;
2018-08-16 03:14:11 -07:00
document . getElementById ( 'ua' ) . dispatchEvent ( new Event ( 'input' ) ) ;
2017-09-13 03:18:12 -07:00
}
} ) ;
2017-11-22 04:35:22 -08:00
function msg ( msg ) {
2019-11-05 03:02:26 -08:00
const toast = document . getElementById ( 'toast' ) ;
toast . textContent = msg ;
window . setTimeout ( ( ) => toast . textContent = '' , 2000 ) ;
2017-11-22 04:35:22 -08:00
}
2017-09-13 03:18:12 -07:00
// commands
document . addEventListener ( 'click' , ( { target } ) => {
const cmd = target . dataset . cmd ;
if ( cmd ) {
if ( cmd === 'apply' ) {
2017-11-22 04:35:22 -08:00
const value = document . getElementById ( 'ua' ) . value ;
if ( value === navigator . userAgent ) {
2018-08-16 03:14:11 -07:00
msg ( 'Default UA, press the reset button instead' ) ;
2017-11-22 04:35:22 -08:00
}
else {
2019-11-05 03:02:26 -08:00
msg ( 'User-Agent is Set' ) ;
2017-11-22 04:35:22 -08:00
}
2020-08-04 23:29:57 -07:00
if ( value !== navigator . userAgent ) {
2020-08-05 03:13:33 -07:00
// prevent a container ua string from overwriting the default one
if ( 'cookieStoreId' in tab && tab . cookieStoreId !== DCSI ) {
chrome . runtime . getBackgroundPage ( bg => bg . ua . update ( value , undefined , tab . cookieStoreId ) ) ;
chrome . storage . local . get ( {
'container-uas' : { }
} , prefs => {
prefs [ 'container-uas' ] [ tab . cookieStoreId ] = value ;
chrome . storage . local . set ( prefs ) ;
} ) ;
}
else {
chrome . storage . local . set ( {
ua : value
} ) ;
}
2020-08-04 23:29:57 -07:00
}
2017-09-13 03:18:12 -07:00
}
2020-08-04 23:29:57 -07:00
else if ( cmd === 'window' ) {
2018-08-16 03:14:11 -07:00
const value = document . getElementById ( 'ua' ) . value ;
2020-08-04 23:29:57 -07:00
chrome . runtime . getBackgroundPage ( bg => bg . ua . update ( value , tab . windowId , tab . cookieStoreId ) ) ;
2018-08-16 03:14:11 -07:00
}
2017-09-13 03:18:12 -07:00
else if ( cmd === 'reset' ) {
const input = document . querySelector ( '#list :checked' ) ;
if ( input ) {
input . checked = false ;
}
2020-08-05 03:13:33 -07:00
// prevent a container ua string from overwriting the default one
if ( 'cookieStoreId' in tab && tab . cookieStoreId !== DCSI ) {
chrome . runtime . getBackgroundPage ( bg => {
delete bg . ua . _obj [ tab . cookieStoreId ] ;
bg . ua . update ( '' , undefined , tab . cookieStoreId ) ;
} ) ;
chrome . storage . local . get ( {
'container-uas' : { }
} , prefs => {
delete prefs [ 'container-uas' ] [ tab . cookieStoreId ] ;
chrome . storage . local . set ( prefs ) ;
} ) ;
msg ( 'Disabled on this container. Uses the default user-agent string' ) ;
}
else {
chrome . storage . local . set ( {
ua : ''
} ) ;
msg ( 'Disabled. Uses the default user-agent string' ) ;
}
2017-09-13 03:18:12 -07:00
}
2017-11-19 01:32:13 -08:00
else if ( cmd === 'refresh' ) {
chrome . tabs . query ( {
active : true ,
currentWindow : true
} , ( [ tab ] ) => chrome . tabs . reload ( tab . id , {
bypassCache : true
} ) ) ;
}
2018-05-15 00:54:51 -07:00
else if ( cmd === 'options' ) {
chrome . runtime . openOptionsPage ( ) ;
}
2018-08-16 03:14:11 -07:00
else if ( cmd === 'reload' ) {
chrome . runtime . reload ( ) ;
}
2019-05-15 22:18:58 -07:00
else if ( cmd === 'test' ) {
chrome . storage . local . get ( {
2020-08-03 22:52:40 -07:00
'test' : 'https://webbrowsertools.com/useragent/?method=normal&verbose=false'
2019-05-15 22:18:58 -07:00
} , prefs => chrome . tabs . create ( {
url : prefs . test
} ) ) ;
}
if ( cmd ) {
target . classList . add ( 'active' ) ;
window . setTimeout ( ( ) => target . classList . remove ( 'active' ) , 500 ) ;
}
2017-09-13 03:18:12 -07:00
}
} ) ;
2018-08-16 03:14:11 -07:00
document . getElementById ( 'ua' ) . addEventListener ( 'input' , e => {
2019-11-05 03:02:26 -08:00
const value = e . target . value ;
document . querySelector ( '[data-cmd=apply]' ) . disabled = value === '' ;
document . querySelector ( '[data-cmd=window]' ) . disabled = value === '' ;
if ( value ) {
chrome . runtime . getBackgroundPage ( bg => {
const o = bg . ua . parse ( value ) ;
document . getElementById ( 'appVersion' ) . value = o . appVersion ;
document . getElementById ( 'platform' ) . value = o . platform ;
document . getElementById ( 'vendor' ) . value = o . vendor ;
document . getElementById ( 'product' ) . value = o . product ;
document . getElementById ( 'oscpu' ) . value = o . oscpu ;
} ) ;
}
2018-08-16 03:14:11 -07:00
} ) ;
2020-08-04 23:29:57 -07:00
document . getElementById ( 'ua' ) . addEventListener ( 'keyup' , e => {
if ( e . key === 'Enter' ) {
document . querySelector ( '[data-cmd="apply"]' ) . click ( ) ;
}
} ) ;
/* container support */
document . querySelector ( '[data-cmd="container"]' ) . addEventListener ( 'click' , e => {
chrome . permissions . request ( {
permissions : [ 'cookies' ]
} , granted => {
if ( granted ) {
2020-08-05 03:13:33 -07:00
window . close ( ) ;
2020-08-04 23:29:57 -07:00
}
} ) ;
} ) ;
if ( /Firefox/ . test ( navigator . userAgent ) ) {
chrome . permissions . contains ( {
permissions : [ 'cookies' ]
} , granted => {
if ( granted === false ) {
document . querySelector ( '[data-cmd="container"]' ) . classList . remove ( 'hide' ) ;
}
} ) ;
}