2828/**
2929 * CSSAgent keeps track of loaded style sheets and allows reloading them
3030 * from a {Document}.
31+ *
32+ * CSSAgent dispatches styleSheetAdded and styleSheetRemoved events, passing
33+ * the URL for the added/removed style sheet.
3134 */
32-
3335define ( function CSSAgent ( require , exports , module ) {
3436 "use strict" ;
3537
3638 require ( "thirdparty/path-utils/path-utils.min" ) ;
3739
3840 var Inspector = require ( "LiveDevelopment/Inspector/Inspector" ) ;
3941
40- var _load ; // {$.Deferred} load promise
41- var _urlToStyle ; // {url -> loaded} style definition
42+ /** @type {Object.<string, CSS.CSSStyleSheetHeader> } */
43+ var _urlToStyle = { } ;
44+
45+ /** @type {Object.<string, string> } */
46+ var _styleSheetIdToUrl ;
47+
48+ /** @type {boolean } */
49+ var _getAllStyleSheetsNotFound = false ;
4250
4351 /**
4452 * Create a canonicalized version of the given URL, stripping off query strings and hashes.
@@ -49,34 +57,31 @@ define(function CSSAgent(require, exports, module) {
4957 return PathUtils . parseUrl ( url ) . hrefNoSearch ;
5058 }
5159
52- // WebInspector Event: Page.loadEventFired
53- function _onLoadEventFired ( event , res ) {
54- // res = {timestamp}
60+ /**
61+ * @private
62+ * WebInspector Event: Page.frameNavigated
63+ * @param {jQuery.Event } event
64+ * @param {frame: Frame } res
65+ */
66+ function _onFrameNavigated ( event , res ) {
67+ // Clear maps when navigating to a new page
5568 _urlToStyle = { } ;
56- Inspector . CSS . enable ( ) . done ( function ( ) {
57- Inspector . CSS . getAllStyleSheets ( function onGetAllStyleSheets ( res ) {
58- var i , header ;
59- for ( i in res . headers ) {
60- header = res . headers [ i ] ;
61- _urlToStyle [ _canonicalize ( header . sourceURL ) ] = header ;
62- }
63- _load . resolve ( ) ;
64- } ) ;
65- } ) ;
69+ _styleSheetIdToUrl = { } ;
6670 }
6771
68- /** Get a style sheet for a url
72+ /**
73+ * Get a style sheet for a url
6974 * @param {string } url
75+ * @return {CSS.CSSStyleSheetHeader }
7076 */
7177 function styleForURL ( url ) {
72- if ( _urlToStyle ) {
73- return _urlToStyle [ _canonicalize ( url ) ] ;
74- }
75-
76- return null ;
78+ return _urlToStyle [ _canonicalize ( url ) ] ;
7779 }
7880
79- /** Get a list of all loaded stylesheet files by URL */
81+ /**
82+ * @deprecated Use styleSheetAdded and styleSheetRemoved events
83+ * Get a list of all loaded stylesheet files by URL
84+ */
8085 function getStylesheetURLs ( ) {
8186 var urls = [ ] , url ;
8287 for ( url in _urlToStyle ) {
@@ -87,37 +92,112 @@ define(function CSSAgent(require, exports, module) {
8792 return urls ;
8893 }
8994
90- /** Reload a CSS style sheet from a document
95+ /**
96+ * Reload a CSS style sheet from a document
9197 * @param {Document } document
98+ * @return {jQuery.Promise }
9299 */
93100 function reloadCSSForDocument ( doc ) {
94101 var style = styleForURL ( doc . url ) ;
95102 console . assert ( style , "Style Sheet for document not loaded: " + doc . url ) ;
96- Inspector . CSS . setStyleSheetText ( style . styleSheetId , doc . getText ( ) ) ;
103+ return Inspector . CSS . setStyleSheetText ( style . styleSheetId , doc . getText ( ) ) ;
97104 }
98105
99- /** Empties a CSS style sheet given a document that has been deleted
106+ /**
107+ * Empties a CSS style sheet given a document that has been deleted
100108 * @param {Document } document
109+ * @return {jQuery.Promise }
101110 */
102111 function clearCSSForDocument ( doc ) {
103112 var style = styleForURL ( doc . url ) ;
104113 console . assert ( style , "Style Sheet for document not loaded: " + doc . url ) ;
105- Inspector . CSS . setStyleSheetText ( style . styleSheetId , "" ) ;
114+ return Inspector . CSS . setStyleSheetText ( style . styleSheetId , "" ) ;
115+ }
116+
117+ /**
118+ * @private
119+ * @param {jQuery.Event } event
120+ * @param {header: CSSStyleSheetHeader }
121+ */
122+ function _styleSheetAdded ( event , res ) {
123+ var url = _canonicalize ( res . header . sourceURL ) ,
124+ existing = _urlToStyle [ url ] ;
125+
126+ // detect duplicates
127+ if ( existing && existing . styleSheetId === res . header . styleSheetId ) {
128+ return ;
129+ }
130+
131+ _urlToStyle [ url ] = res . header ;
132+ _styleSheetIdToUrl [ res . header . styleSheetId ] = url ;
133+
134+ $ ( exports ) . triggerHandler ( "styleSheetAdded" , [ url , res . header ] ) ;
135+ }
136+
137+ /**
138+ * @private
139+ * @param {jQuery.Event } event
140+ * @param {styleSheetId: StyleSheetId }
141+ */
142+ function _styleSheetRemoved ( event , res ) {
143+ var url = _styleSheetIdToUrl [ res . styleSheetId ] ,
144+ header = url && _urlToStyle [ url ] ;
145+
146+ if ( url ) {
147+ delete _urlToStyle [ url ] ;
148+ }
149+
150+ delete _styleSheetIdToUrl [ res . styleSheetId ] ;
151+
152+ $ ( exports ) . triggerHandler ( "styleSheetRemoved" , [ url , header ] ) ;
153+ }
154+
155+ /**
156+ * @private
157+ * Attempt to use deleted API CSS.getAllStyleSheets
158+ * @param {jQuery.Event } event
159+ * @param {frameId: Network.FrameId }
160+ */
161+ function _onFrameStoppedLoading ( event , res ) {
162+ // Manually fire getAllStyleSheets since it will be removed from
163+ // Inspector.json in a future update
164+ Inspector . send ( "CSS" , "getAllStyleSheets" ) . done ( function ( res ) {
165+ res . headers . forEach ( function ( header ) {
166+ // _styleSheetAdded will ignore duplicates
167+ _styleSheetAdded ( null , { header : header } ) ;
168+ } ) ;
169+ } ) . fail ( function ( err ) {
170+ // Disable getAllStyleSheets if the first call fails
171+ _getAllStyleSheetsNotFound = ( err . code === - 32601 ) ;
172+ $ ( Inspector . Page ) . off ( "frameStoppedLoading.CSSAgent" , _onFrameStoppedLoading ) ;
173+ } ) ;
174+ }
175+
176+ /** Enable the domain */
177+ function enable ( ) {
178+ return Inspector . CSS . enable ( ) ;
106179 }
107180
108181 /** Initialize the agent */
109182 function load ( ) {
110- _load = new $ . Deferred ( ) ;
111- $ ( Inspector . Page ) . on ( "loadEventFired.CSSAgent" , _onLoadEventFired ) ;
112- return _load . promise ( ) ;
183+ $ ( Inspector . Page ) . on ( "frameNavigated.CSSAgent" , _onFrameNavigated ) ;
184+ $ ( Inspector . CSS ) . on ( "styleSheetAdded.CSSAgent" , _styleSheetAdded ) ;
185+ $ ( Inspector . CSS ) . on ( "styleSheetRemoved.CSSAgent" , _styleSheetRemoved ) ;
186+
187+ // getAllStyleSheets was deleted beginning with Chrome 34
188+ if ( ! _getAllStyleSheetsNotFound ) {
189+ $ ( Inspector . Page ) . on ( "frameStoppedLoading.CSSAgent" , _onFrameStoppedLoading ) ;
190+ }
113191 }
114192
115193 /** Clean up */
116194 function unload ( ) {
117195 $ ( Inspector . Page ) . off ( ".CSSAgent" ) ;
196+ $ ( Inspector . CSS ) . off ( ".CSSAgent" ) ;
118197 }
119198
120199 // Export public functions
200+ exports . enable = enable ;
121201 exports . styleForURL = styleForURL ;
122202 exports . getStylesheetURLs = getStylesheetURLs ;
123203 exports . reloadCSSForDocument = reloadCSSForDocument ;
0 commit comments