Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F2753593
ext.centralNotice.geoIP.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
ext.centralNotice.geoIP.js
View Options
/**
* Processes location data and sets up a promise that resolves with that data.
* Sets the global window.Geo and provides the public mw.geoIP object.
* TODO Deprecate global window.Geo
* TODO Move this out of CentralNotice. See https://phabricator.wikimedia.org/T102848
*/
(
function
()
{
var
COOKIE_NAME
=
'GeoIP'
,
geoPromise
;
/**
* Parse geo data in cookieValue and return an object with properties from
* the fields therein. Returns null if the value couldn't be parsed or
* doesn't contain location data.
*
* The cookie will look like one of the following:
* - "US:CO:Denver:39.6762:-104.887:v4"
* - ":::::v4"
*
* @param {string} cookieValue
* @return {?Object}
*/
function
parseCookieValue
(
cookieValue
)
{
// TODO Verify that these Regexes are optimal. (Why no anchors? Why the
// semicolon in the last group?)
var
matches
=
// Parse cookie format currently set by WMF servers
cookieValue
.
match
(
/([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^;]*)/
)
||
// If that didn't match, try the old cookie format (no region data).
// Even though these are session cookies, some might still be around.
cookieValue
.
match
(
/([^:]*):([^:]*):([^:]*):([^:]*):([^;]*)/
);
// No matches...? Boo, no data from geo cookie.
if
(
!
matches
)
{
return
null
;
}
// If the matches were from the old cookie format, add an empty region
// element.
if
(
matches
.
length
===
6
)
{
matches
=
matches
.
slice
(
0
,
2
).
concat
(
[
''
]
)
.
concat
(
matches
.
slice
(
2
)
);
}
// There was no info found if there's no country field, or if it's
// empty
if
(
(
typeof
matches
[
1
]
!==
'string'
)
||
(
matches
[
1
].
length
===
0
)
)
{
return
null
;
}
// Return a juicy Geo object
return
{
country
:
matches
[
1
],
region
:
matches
[
2
],
city
:
matches
[
3
],
lat
:
matches
[
4
]
&&
parseFloat
(
matches
[
4
]
),
lon
:
matches
[
5
]
&&
parseFloat
(
matches
[
5
]
),
af
:
matches
[
6
]
};
}
/**
* Serialize a geo object and store it in the cookie
*
* @param {Object} geo
*/
function
storeGeoInCookie
(
geo
)
{
var
parts
=
[
geo
.
country
,
geo
.
region
||
''
,
(
geo
.
city
&&
geo
.
city
.
replace
(
/[^a-z]/i
,
'_'
)
)
||
''
,
geo
.
lat
||
''
,
geo
.
lon
||
''
,
geo
.
af
||
''
],
cookieValue
=
parts
.
join
(
':'
);
$
.
cookie
(
COOKIE_NAME
,
cookieValue
,
{
path
:
'/'
}
);
}
/**
* Public geoIP object
*/
mw
.
geoIP
=
{
/**
* Don't call this function! It is only exposed for tests.
*
* Set a promise that resolves with geo. First try to get data from the
* GeoIP cookie. If that fails, and if a background lookup callback
* module is configured, try the background lookup.
*
* @private
*/
makeGeoWithPromise
:
function
()
{
var
cookieValue
=
$
.
cookie
(
COOKIE_NAME
),
geo
,
lookupModule
;
// Were we able to read the cookie?
if
(
cookieValue
)
{
geo
=
parseCookieValue
(
cookieValue
);
// All good? Resolve with geo and get outta here.
if
(
geo
)
{
geoPromise
=
$
.
Deferred
().
resolve
(
geo
).
promise
();
return
;
}
}
// Handle no geo data from the cookie.
// If there's a background lookup to fall back to, do that
lookupModule
=
mw
.
config
.
get
(
'wgCentralNoticeGeoIPBackgroundLookupModule'
);
if
(
lookupModule
)
{
geoPromise
=
mw
.
loader
.
using
(
lookupModule
)
.
then
(
function
()
{
var
lookupCallback
=
require
(
lookupModule
);
// Chaining lookup: here we return the promise provided by
// lookupCallback(). The result of that promise (geo object)
// will be what then() resolves to, and what future then()
// handlers get.
return
lookupCallback
();
}
);
// If the lookup was successful, store geo in a cookie
geoPromise
.
then
(
function
(
g
)
{
storeGeoInCookie
(
g
);
}
);
// If no background lookup is available, we don't have geo data
}
else
{
geoPromise
=
$
.
Deferred
().
reject
().
promise
();
}
},
/**
* Returns a promise that resolves with geo when it's available. While
* it's usually available right away, it may not be if a background
* call is performed.
*
* @return {jQuery.Promise}
*/
getPromise
:
function
()
{
return
geoPromise
;
}
};
mw
.
geoIP
.
makeGeoWithPromise
();
// For legacy code, set global window.Geo TODO: deprecate
geoPromise
.
done
(
function
(
geo
)
{
window
.
Geo
=
geo
;
}
);
}()
);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jul 3, 21:27 (20 h, 2 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
5c/af/fc7f8f67d19d497b964a854a2194
Default Alt Text
ext.centralNotice.geoIP.js (4 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment