2012-08-20 01:14:33 +00:00
chrome . extension . onMessage . addListener ( function ( request , sender , sendResponse ) {
switch ( request . method ) {
case "getStyles" :
getStyles ( request , function ( r ) {
2012-04-16 01:56:12 +00:00
sendResponse ( r ) ;
2014-02-08 02:04:06 +00:00
if ( localStorage [ "show-badge" ] == "true" ) {
if ( request . updateBadge ) {
var t = getBadgeText ( r ) ;
console . log ( "Tab " + sender . tab . id + " (" + sender . tab . url + ") badge text set to '" + t + "'." ) ;
chrome . browserAction . setBadgeText ( { text : t , tabId : sender . tab . id } ) ;
} else {
console . log ( "Tab " + sender . tab . id + " (" + sender . tab . url + ") doesn't get badge text." ) ;
}
2012-08-20 01:14:33 +00:00
}
2012-04-16 01:56:12 +00:00
} ) ;
2012-08-20 01:14:33 +00:00
return true ;
2012-04-16 01:56:12 +00:00
case "getStyleApplies" :
2012-08-20 01:14:33 +00:00
sendResponse ( getApplicableSections ( request . style , request . url ) ) ;
return true ;
case "saveStyle" :
saveStyle ( request , sendResponse ) ;
return true ;
2012-04-16 01:56:12 +00:00
case "styleChanged" :
2012-08-20 01:14:33 +00:00
cachedStyles = null ;
2012-04-16 01:56:12 +00:00
break ;
2013-06-26 04:25:04 +00:00
case "healthCheck" :
getDatabase ( function ( ) { sendResponse ( true ) ; } , function ( ) { sendResponse ( false ) ; } ) ;
break ;
2012-04-16 01:56:12 +00:00
}
} ) ;
2012-08-20 01:14:33 +00:00
function getStyles ( options , callback ) {
var enabled = fixBoolean ( options . enabled ) ;
var url = "url" in options ? options . url : null ;
var id = "id" in options ? options . id : null ;
var matchUrl = "matchUrl" in options ? options . matchUrl : null ;
var callCallback = function ( ) {
callback ( cachedStyles . filter ( function ( style ) {
if ( enabled != null && fixBoolean ( style . enabled ) != enabled ) {
return false ;
}
if ( url != null && style . url != url ) {
return false ;
}
if ( id != null && style . id != id ) {
return false ;
}
if ( matchUrl != null && getApplicableSections ( style , matchUrl ) == 0 ) {
return false ;
}
return true ;
} ) ) ;
}
if ( cachedStyles ) {
callCallback ( ) ;
return ;
}
getDatabase ( function ( db ) {
db . readTransaction ( function ( t ) {
var where = "" ;
var params = [ ] ;
t . executeSql ( 'SELECT DISTINCT s.*, se.id section_id, se.code, sm.name metaName, sm.value metaValue FROM styles s LEFT JOIN sections se ON se.style_id = s.id LEFT JOIN section_meta sm ON sm.section_id = se.id WHERE 1' + where + ' ORDER BY s.id, se.id, sm.id' , params , function ( t , r ) {
cachedStyles = [ ] ;
var currentStyle = null ;
var currentSection = null ;
for ( var i = 0 ; i < r . rows . length ; i ++ ) {
var values = r . rows . item ( i ) ;
var metaName = null ;
switch ( values . metaName ) {
case null :
break ;
case "url" :
metaName = "urls" ;
break ;
case "url-prefix" :
metaName = "urlPrefixes" ;
break ;
case "domain" :
var metaName = "domains" ;
break ;
case "regexps" :
var metaName = "regexps" ;
break ;
default :
var metaName = values . metaName + "s" ;
}
var metaValue = values . metaValue ;
if ( currentStyle == null || currentStyle . id != values . id ) {
2014-02-06 21:05:31 +00:00
currentStyle = { id : values . id , url : values . url , updateUrl : values . updateUrl , md5Url : values . md5Url , name : values . name , enabled : values . enabled , originalMd5 : values . originalMd5 , sections : [ ] } ;
2012-08-20 01:14:33 +00:00
cachedStyles . push ( currentStyle ) ;
}
if ( currentSection == null || currentSection . id != values . section _id ) {
currentSection = { id : values . section _id , code : values . code } ;
currentStyle . sections . push ( currentSection ) ;
}
if ( metaName && metaValue ) {
if ( currentSection [ metaName ] ) {
currentSection [ metaName ] . push ( metaValue ) ;
} else {
currentSection [ metaName ] = [ metaValue ] ;
}
}
}
callCallback ( ) ;
} , reportError ) ;
} , reportError ) ;
} , reportError ) ;
}
function fixBoolean ( b ) {
if ( typeof b != "undefined" ) {
return b != "false" ;
}
return null ;
}
const namespacePattern = /^\s*@namespace\s+([a-zA-Z]+\s+)?url\(\"?http:\/\/www.w3.org\/1999\/xhtml\"?\);?\s*$/ ;
function getApplicableSections ( style , url ) {
var sections = style . sections . filter ( function ( section ) {
2012-04-16 01:56:12 +00:00
return sectionAppliesToUrl ( section , url ) ;
} ) ;
2012-08-20 01:14:33 +00:00
// ignore if it's just a namespace
if ( sections . length == 1 && namespacePattern . test ( sections [ 0 ] . code ) ) {
return [ ] ;
2012-04-16 01:56:12 +00:00
}
2012-08-20 01:14:33 +00:00
return sections ;
2012-04-16 01:56:12 +00:00
}
function sectionAppliesToUrl ( section , url ) {
2012-08-20 01:14:33 +00:00
// only http and https allowed
if ( url . indexOf ( "http" ) != 0 ) {
return false ;
}
2012-04-16 01:56:12 +00:00
if ( ! section . urls && ! section . domains && ! section . urlPrefixes && ! section . regexps ) {
2012-08-20 01:14:33 +00:00
console . log ( section . id + " is global" ) ;
2012-04-16 01:56:12 +00:00
return true ;
}
if ( section . urls && section . urls . indexOf ( url ) != - 1 ) {
2012-08-20 01:14:33 +00:00
console . log ( section . id + " applies to " + url + " due to URL rules" ) ;
2012-04-16 01:56:12 +00:00
return true ;
}
if ( section . urlPrefixes && section . urlPrefixes . some ( function ( prefix ) {
return url . indexOf ( prefix ) == 0 ;
} ) ) {
2012-08-20 01:14:33 +00:00
console . log ( section . id + " applies to " + url + " due to URL prefix rules" ) ;
2012-04-16 01:56:12 +00:00
return true ;
}
if ( section . domains && getDomains ( url ) . some ( function ( domain ) {
return section . domains . indexOf ( domain ) != - 1 ;
} ) ) {
2012-08-20 01:14:33 +00:00
console . log ( section . id + " applies due to " + url + " due to domain rules" ) ;
2012-04-16 01:56:12 +00:00
return true ;
}
if ( section . regexps && section . regexps . some ( function ( regexp ) {
2012-08-20 01:14:33 +00:00
// we want to match the full url, so add ^ and $ if not already present
if ( regexp [ 0 ] != "^" ) {
regexp = "^" + regexp ;
}
if ( regexp [ regexp . length - 1 ] != "$" ) {
regexp += "$" ;
}
2012-11-03 03:25:04 +00:00
try {
var re = new RegExp ( regexp ) ;
} catch ( ex ) {
console . log ( section . id + "'s regexp '" + regexp + "' is not valid" ) ;
return false ;
}
return ( re ) . test ( url ) ;
2012-04-16 01:56:12 +00:00
} ) ) {
2012-08-20 01:14:33 +00:00
console . log ( section . id + " applies to " + url + " due to regexp rules" ) ;
2012-04-16 01:56:12 +00:00
return true ;
}
2012-08-20 01:14:33 +00:00
console . log ( section . id + " does not apply due to " + url ) ;
2012-04-16 01:56:12 +00:00
return false ;
}
2012-08-20 01:14:33 +00:00
var cachedStyles = null ;
function saveStyle ( o , callback ) {
getDatabase ( function ( db ) {
db . transaction ( function ( t ) {
if ( o . id ) {
// update whatever's been passed
if ( "name" in o ) {
t . executeSql ( 'UPDATE styles SET name = ? WHERE id = ?;' , [ o . name , o . id ] ) ;
}
if ( "enabled" in o ) {
t . executeSql ( 'UPDATE styles SET enabled = ? WHERE id = ?;' , [ o . enabled , o . id ] ) ;
}
if ( "url" in o ) {
t . executeSql ( 'UPDATE styles SET url = ? WHERE id = ?;' , [ o . url , o . id ] ) ;
}
if ( "updateUrl" in o ) {
t . executeSql ( 'UPDATE styles SET updateUrl = ? WHERE id = ?;' , [ o . updateUrl , o . id ] ) ;
}
if ( "md5Url" in o ) {
t . executeSql ( 'UPDATE styles SET md5Url = ? WHERE id = ?;' , [ o . md5Url , o . id ] ) ;
}
2014-02-06 21:05:31 +00:00
if ( "originalMd5" in o ) {
t . executeSql ( 'UPDATE styles SET originalMd5 = ? WHERE id = ?;' , [ o . originalMd5 , o . id ] ) ;
}
2012-08-20 01:14:33 +00:00
} else {
// create a new record
2013-06-24 04:16:48 +00:00
// set optional things to null if they're undefined
2014-02-06 21:05:31 +00:00
[ "updateUrl" , "md5Url" , "url" , "originalMd5" ] . filter ( function ( att ) {
2013-06-24 04:16:48 +00:00
return ! ( att in o ) ;
} ) . forEach ( function ( att ) {
o [ att ] = null ;
} ) ;
2014-02-06 21:05:31 +00:00
t . executeSql ( 'INSERT INTO styles (name, enabled, url, updateUrl, md5Url, originalMd5) VALUES (?, ?, ?, ?, ?, ?);' , [ o . name , true , o . url , o . updateUrl , o . md5Url , o . originalMd5 ] ) ;
2012-08-20 01:14:33 +00:00
}
if ( "sections" in o ) {
if ( o . id ) {
// clear existing records
t . executeSql ( 'DELETE FROM section_meta WHERE section_id IN (SELECT id FROM sections WHERE style_id = ?);' , [ o . id ] ) ;
t . executeSql ( 'DELETE FROM sections WHERE style_id = ?;' , [ o . id ] ) ;
}
o . sections . forEach ( function ( section ) {
if ( o . id ) {
t . executeSql ( 'INSERT INTO sections (style_id, code) VALUES (?, ?);' , [ o . id , section . code ] ) ;
} else {
t . executeSql ( 'INSERT INTO sections (style_id, code) SELECT id, ? FROM styles ORDER BY id DESC LIMIT 1;' , [ section . code ] ) ;
}
if ( section . urls ) {
section . urls . forEach ( function ( u ) {
t . executeSql ( "INSERT INTO section_meta (section_id, name, value) SELECT id, 'url', ? FROM sections ORDER BY id DESC LIMIT 1;" , [ u ] ) ;
} ) ;
}
if ( section . urlPrefixes ) {
section . urlPrefixes . forEach ( function ( u ) {
t . executeSql ( "INSERT INTO section_meta (section_id, name, value) SELECT id, 'url-prefix', ? FROM sections ORDER BY id DESC LIMIT 1;" , [ u ] ) ;
} ) ;
}
if ( section . domains ) {
section . domains . forEach ( function ( u ) {
t . executeSql ( "INSERT INTO section_meta (section_id, name, value) SELECT id, 'domain', ? FROM sections ORDER BY id DESC LIMIT 1;" , [ u ] ) ;
} ) ;
}
if ( section . regexps ) {
section . regexps . forEach ( function ( u ) {
t . executeSql ( "INSERT INTO section_meta (section_id, name, value) SELECT id, 'regexp', ? FROM sections ORDER BY id DESC LIMIT 1;" , [ u ] ) ;
} ) ;
}
} ) ;
}
} , reportError , function ( ) { saveFromJSONComplete ( o . id , callback ) } ) ;
} , reportError ) ;
}
function saveFromJSONComplete ( id , callback ) {
cachedStyles = null ;
if ( id ) {
getStyles ( { method : "getStyles" , id : id } , function ( styles ) {
saveFromJSONStyleReloaded ( "styleUpdated" , styles [ 0 ] , callback ) ;
} ) ;
return ;
}
// we need to load the id for new ones
getDatabase ( function ( db ) {
db . readTransaction ( function ( t ) {
t . executeSql ( 'SELECT id FROM styles ORDER BY id DESC LIMIT 1' , [ ] , function ( t , r ) {
var id = r . rows . item ( 0 ) . id ;
getStyles ( { method : "getStyles" , id : id } , function ( styles ) {
saveFromJSONStyleReloaded ( "styleAdded" , styles [ 0 ] , callback ) ;
} ) ;
} , reportError )
} , reportError )
} ) ;
}
function saveFromJSONStyleReloaded ( updateType , style , callback ) {
notifyAllTabs ( { name : updateType , style : style } ) ;
if ( callback ) {
callback ( style ) ;
}
}
function getDomains ( url ) {
var d = /.*?:\/*([^\/]+)/ . exec ( url ) [ 1 ] ;
var domains = [ d ] ;
while ( d . indexOf ( "." ) != - 1 ) {
d = d . substring ( d . indexOf ( "." ) + 1 ) ;
domains . push ( d ) ;
}
return domains ;
}
2014-02-08 02:04:06 +00:00
// Get the DB so that any first run actions will be performed immediately when the background page loads.
getDatabase ( function ( ) { } , reportError ) ;