CSSStyleModel.js 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. /*
  2. * Copyright (C) 2010 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @extends {WebInspector.Object}
  33. * @param {WebInspector.Workspace} workspace
  34. */
  35. WebInspector.CSSStyleModel = function(workspace)
  36. {
  37. this._workspace = workspace;
  38. this._pendingCommandsMajorState = [];
  39. /** @type {Array.<WebInspector.CSSStyleModel.LiveLocation>} */
  40. this._locations = [];
  41. this._sourceMappings = {};
  42. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoRequested, this._undoRedoRequested, this);
  43. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoCompleted, this._undoRedoCompleted, this);
  44. this._resourceBinding = new WebInspector.CSSStyleModelResourceBinding();
  45. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameCreatedOrNavigated, this._mainFrameCreatedOrNavigated, this);
  46. this._namedFlowCollections = {};
  47. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._resetNamedFlowCollections, this);
  48. InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this));
  49. CSSAgent.enable();
  50. }
  51. /**
  52. * @param {Array.<CSSAgent.CSSRule>} ruleArray
  53. */
  54. WebInspector.CSSStyleModel.parseRuleArrayPayload = function(ruleArray)
  55. {
  56. var result = [];
  57. for (var i = 0; i < ruleArray.length; ++i)
  58. result.push(WebInspector.CSSRule.parsePayload(ruleArray[i]));
  59. return result;
  60. }
  61. /**
  62. * @param {Array.<CSSAgent.RuleMatch>} matchArray
  63. */
  64. WebInspector.CSSStyleModel.parseRuleMatchArrayPayload = function(matchArray)
  65. {
  66. var result = [];
  67. for (var i = 0; i < matchArray.length; ++i)
  68. result.push(WebInspector.CSSRule.parsePayload(matchArray[i].rule, matchArray[i].matchingSelectors));
  69. return result;
  70. }
  71. WebInspector.CSSStyleModel.Events = {
  72. StyleSheetChanged: "StyleSheetChanged",
  73. MediaQueryResultChanged: "MediaQueryResultChanged",
  74. NamedFlowCreated: "NamedFlowCreated",
  75. NamedFlowRemoved: "NamedFlowRemoved",
  76. RegionLayoutUpdated: "RegionLayoutUpdated"
  77. }
  78. WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"];
  79. WebInspector.CSSStyleModel.prototype = {
  80. /**
  81. * @param {DOMAgent.NodeId} nodeId
  82. * @param {boolean} needPseudo
  83. * @param {boolean} needInherited
  84. * @param {function(?*)} userCallback
  85. */
  86. getMatchedStylesAsync: function(nodeId, needPseudo, needInherited, userCallback)
  87. {
  88. /**
  89. * @param {function(?*)} userCallback
  90. * @param {?Protocol.Error} error
  91. * @param {Array.<CSSAgent.RuleMatch>=} matchedPayload
  92. * @param {Array.<CSSAgent.PseudoIdMatches>=} pseudoPayload
  93. * @param {Array.<CSSAgent.InheritedStyleEntry>=} inheritedPayload
  94. */
  95. function callback(userCallback, error, matchedPayload, pseudoPayload, inheritedPayload)
  96. {
  97. if (error) {
  98. if (userCallback)
  99. userCallback(null);
  100. return;
  101. }
  102. var result = {};
  103. if (matchedPayload)
  104. result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(matchedPayload);
  105. if (pseudoPayload) {
  106. result.pseudoElements = [];
  107. for (var i = 0; i < pseudoPayload.length; ++i) {
  108. var entryPayload = pseudoPayload[i];
  109. result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(entryPayload.matches) });
  110. }
  111. }
  112. if (inheritedPayload) {
  113. result.inherited = [];
  114. for (var i = 0; i < inheritedPayload.length; ++i) {
  115. var entryPayload = inheritedPayload[i];
  116. var entry = {};
  117. if (entryPayload.inlineStyle)
  118. entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(entryPayload.inlineStyle);
  119. if (entryPayload.matchedCSSRules)
  120. entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(entryPayload.matchedCSSRules);
  121. result.inherited.push(entry);
  122. }
  123. }
  124. if (userCallback)
  125. userCallback(result);
  126. }
  127. CSSAgent.getMatchedStylesForNode(nodeId, needPseudo, needInherited, callback.bind(null, userCallback));
  128. },
  129. /**
  130. * @param {DOMAgent.NodeId} nodeId
  131. * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
  132. */
  133. getComputedStyleAsync: function(nodeId, userCallback)
  134. {
  135. /**
  136. * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
  137. */
  138. function callback(userCallback, error, computedPayload)
  139. {
  140. if (error || !computedPayload)
  141. userCallback(null);
  142. else
  143. userCallback(WebInspector.CSSStyleDeclaration.parseComputedStylePayload(computedPayload));
  144. }
  145. CSSAgent.getComputedStyleForNode(nodeId, callback.bind(null, userCallback));
  146. },
  147. /**
  148. * @param {DOMAgent.NodeId} nodeId
  149. * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
  150. */
  151. getInlineStylesAsync: function(nodeId, userCallback)
  152. {
  153. /**
  154. * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
  155. * @param {?Protocol.Error} error
  156. * @param {?CSSAgent.CSSStyle=} inlinePayload
  157. * @param {?CSSAgent.CSSStyle=} attributesStylePayload
  158. */
  159. function callback(userCallback, error, inlinePayload, attributesStylePayload)
  160. {
  161. if (error || !inlinePayload)
  162. userCallback(null, null);
  163. else
  164. userCallback(WebInspector.CSSStyleDeclaration.parsePayload(inlinePayload), attributesStylePayload ? WebInspector.CSSStyleDeclaration.parsePayload(attributesStylePayload) : null);
  165. }
  166. CSSAgent.getInlineStylesForNode(nodeId, callback.bind(null, userCallback));
  167. },
  168. /**
  169. * @param {DOMAgent.NodeId} nodeId
  170. * @param {?Array.<string>|undefined} forcedPseudoClasses
  171. * @param {function()=} userCallback
  172. */
  173. forcePseudoState: function(nodeId, forcedPseudoClasses, userCallback)
  174. {
  175. CSSAgent.forcePseudoState(nodeId, forcedPseudoClasses || [], userCallback);
  176. },
  177. /**
  178. * @param {DOMAgent.NodeId} documentNodeId
  179. * @param {function(?WebInspector.NamedFlowCollection)} userCallback
  180. */
  181. getNamedFlowCollectionAsync: function(documentNodeId, userCallback)
  182. {
  183. var namedFlowCollection = this._namedFlowCollections[documentNodeId];
  184. if (namedFlowCollection) {
  185. userCallback(namedFlowCollection);
  186. return;
  187. }
  188. /**
  189. * @param {function(?WebInspector.NamedFlowCollection)} userCallback
  190. * @param {?Protocol.Error} error
  191. * @param {?Array.<CSSAgent.NamedFlow>} namedFlowPayload
  192. */
  193. function callback(userCallback, error, namedFlowPayload)
  194. {
  195. if (error || !namedFlowPayload)
  196. userCallback(null);
  197. else {
  198. var namedFlowCollection = new WebInspector.NamedFlowCollection(namedFlowPayload);
  199. this._namedFlowCollections[documentNodeId] = namedFlowCollection;
  200. userCallback(namedFlowCollection);
  201. }
  202. }
  203. CSSAgent.getNamedFlowCollection(documentNodeId, callback.bind(this, userCallback));
  204. },
  205. /**
  206. * @param {DOMAgent.NodeId} documentNodeId
  207. * @param {string} flowName
  208. * @param {function(?WebInspector.NamedFlow)} userCallback
  209. */
  210. getFlowByNameAsync: function(documentNodeId, flowName, userCallback)
  211. {
  212. var namedFlowCollection = this._namedFlowCollections[documentNodeId];
  213. if (namedFlowCollection) {
  214. userCallback(namedFlowCollection.flowByName(flowName));
  215. return;
  216. }
  217. /**
  218. * @param {function(?WebInspector.NamedFlow)} userCallback
  219. * @param {?WebInspector.NamedFlowCollection} namedFlowCollection
  220. */
  221. function callback(userCallback, namedFlowCollection)
  222. {
  223. if (!namedFlowCollection)
  224. userCallback(null);
  225. else
  226. userCallback(namedFlowCollection.flowByName(flowName));
  227. }
  228. this.getNamedFlowCollectionAsync(documentNodeId, callback.bind(this, userCallback));
  229. },
  230. /**
  231. * @param {CSSAgent.CSSRuleId} ruleId
  232. * @param {DOMAgent.NodeId} nodeId
  233. * @param {string} newSelector
  234. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  235. * @param {function()} failureCallback
  236. */
  237. setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback)
  238. {
  239. /**
  240. * @param {DOMAgent.NodeId} nodeId
  241. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  242. * @param {CSSAgent.CSSRule} rulePayload
  243. * @param {?Array.<DOMAgent.NodeId>} selectedNodeIds
  244. */
  245. function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
  246. {
  247. if (!selectedNodeIds)
  248. return;
  249. var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
  250. var rule = WebInspector.CSSRule.parsePayload(rulePayload);
  251. successCallback(rule, doesAffectSelectedNode);
  252. }
  253. /**
  254. * @param {DOMAgent.NodeId} nodeId
  255. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  256. * @param {function()} failureCallback
  257. * @param {?Protocol.Error} error
  258. * @param {string} newSelector
  259. * @param {?CSSAgent.CSSRule} rulePayload
  260. */
  261. function callback(nodeId, successCallback, failureCallback, newSelector, error, rulePayload)
  262. {
  263. this._pendingCommandsMajorState.pop();
  264. if (error)
  265. failureCallback();
  266. else {
  267. WebInspector.domAgent.markUndoableState();
  268. var ownerDocumentId = this._ownerDocumentId(nodeId);
  269. if (ownerDocumentId)
  270. WebInspector.domAgent.querySelectorAll(ownerDocumentId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
  271. else
  272. failureCallback();
  273. }
  274. }
  275. this._pendingCommandsMajorState.push(true);
  276. CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector));
  277. },
  278. /**
  279. * @param {DOMAgent.NodeId} nodeId
  280. * @param {string} selector
  281. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  282. * @param {function()} failureCallback
  283. */
  284. addRule: function(nodeId, selector, successCallback, failureCallback)
  285. {
  286. /**
  287. * @param {DOMAgent.NodeId} nodeId
  288. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  289. * @param {CSSAgent.CSSRule} rulePayload
  290. * @param {?Array.<DOMAgent.NodeId>} selectedNodeIds
  291. */
  292. function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
  293. {
  294. if (!selectedNodeIds)
  295. return;
  296. var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
  297. var rule = WebInspector.CSSRule.parsePayload(rulePayload);
  298. successCallback(rule, doesAffectSelectedNode);
  299. }
  300. /**
  301. * @param {function(WebInspector.CSSRule, boolean)} successCallback
  302. * @param {function()} failureCallback
  303. * @param {string} selector
  304. * @param {?Protocol.Error} error
  305. * @param {?CSSAgent.CSSRule} rulePayload
  306. */
  307. function callback(successCallback, failureCallback, selector, error, rulePayload)
  308. {
  309. this._pendingCommandsMajorState.pop();
  310. if (error) {
  311. // Invalid syntax for a selector
  312. failureCallback();
  313. } else {
  314. WebInspector.domAgent.markUndoableState();
  315. var ownerDocumentId = this._ownerDocumentId(nodeId);
  316. if (ownerDocumentId)
  317. WebInspector.domAgent.querySelectorAll(ownerDocumentId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
  318. else
  319. failureCallback();
  320. }
  321. }
  322. this._pendingCommandsMajorState.push(true);
  323. CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector));
  324. },
  325. mediaQueryResultChanged: function()
  326. {
  327. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged);
  328. },
  329. /**
  330. * @param {DOMAgent.NodeId} nodeId
  331. */
  332. _ownerDocumentId: function(nodeId)
  333. {
  334. var node = WebInspector.domAgent.nodeForId(nodeId);
  335. if (!node)
  336. return null;
  337. return node.ownerDocument ? node.ownerDocument.id : null;
  338. },
  339. /**
  340. * @param {CSSAgent.StyleSheetId} styleSheetId
  341. */
  342. _fireStyleSheetChanged: function(styleSheetId)
  343. {
  344. if (!this._pendingCommandsMajorState.length)
  345. return;
  346. var majorChange = this._pendingCommandsMajorState[this._pendingCommandsMajorState.length - 1];
  347. if (!majorChange || !styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged))
  348. return;
  349. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, majorChange: majorChange });
  350. },
  351. /**
  352. * @param {CSSAgent.NamedFlow} namedFlowPayload
  353. */
  354. _namedFlowCreated: function(namedFlowPayload)
  355. {
  356. var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload);
  357. var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId];
  358. if (!namedFlowCollection)
  359. return;
  360. namedFlowCollection._appendNamedFlow(namedFlow);
  361. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowCreated, namedFlow);
  362. },
  363. /**
  364. * @param {DOMAgent.NodeId} documentNodeId
  365. * @param {string} flowName
  366. */
  367. _namedFlowRemoved: function(documentNodeId, flowName)
  368. {
  369. var namedFlowCollection = this._namedFlowCollections[documentNodeId];
  370. if (!namedFlowCollection)
  371. return;
  372. namedFlowCollection._removeNamedFlow(flowName);
  373. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, { documentNodeId: documentNodeId, flowName: flowName });
  374. },
  375. /**
  376. * @param {CSSAgent.NamedFlow} namedFlowPayload
  377. */
  378. _regionLayoutUpdated: function(namedFlowPayload)
  379. {
  380. var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload);
  381. var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId];
  382. if (!namedFlowCollection)
  383. return;
  384. namedFlowCollection._appendNamedFlow(namedFlow);
  385. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, namedFlow);
  386. },
  387. /**
  388. * @param {CSSAgent.StyleSheetId} styleSheetId
  389. * @param {string} newText
  390. * @param {boolean} majorChange
  391. * @param {function(?string)} userCallback
  392. */
  393. setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback)
  394. {
  395. function callback(error)
  396. {
  397. this._pendingCommandsMajorState.pop();
  398. if (!error && majorChange)
  399. WebInspector.domAgent.markUndoableState();
  400. if (!error && userCallback)
  401. userCallback(error);
  402. }
  403. this._pendingCommandsMajorState.push(majorChange);
  404. CSSAgent.setStyleSheetText(styleSheetId, newText, callback.bind(this));
  405. },
  406. _undoRedoRequested: function()
  407. {
  408. this._pendingCommandsMajorState.push(true);
  409. },
  410. _undoRedoCompleted: function()
  411. {
  412. this._pendingCommandsMajorState.pop();
  413. },
  414. /**
  415. * @param {WebInspector.CSSRule} rule
  416. * @param {function(?WebInspector.Resource)} callback
  417. */
  418. getViaInspectorResourceForRule: function(rule, callback)
  419. {
  420. if (!rule.id) {
  421. callback(null);
  422. return;
  423. }
  424. this._resourceBinding._requestViaInspectorResource(rule.id.styleSheetId, callback);
  425. },
  426. /**
  427. * @return {WebInspector.CSSStyleModelResourceBinding}
  428. */
  429. resourceBinding: function()
  430. {
  431. return this._resourceBinding;
  432. },
  433. /**
  434. * @param {WebInspector.Event} event
  435. */
  436. _mainFrameCreatedOrNavigated: function(event)
  437. {
  438. this._resetSourceMappings();
  439. this._resourceBinding._reset();
  440. },
  441. /**
  442. * @param {string} url
  443. * @param {WebInspector.SourceMapping} sourceMapping
  444. */
  445. setSourceMapping: function(url, sourceMapping)
  446. {
  447. if (sourceMapping)
  448. this._sourceMappings[url] = sourceMapping;
  449. else
  450. delete this._sourceMappings[url];
  451. this._updateLocations();
  452. },
  453. _resetSourceMappings: function()
  454. {
  455. this._sourceMappings = {};
  456. },
  457. _resetNamedFlowCollections: function()
  458. {
  459. this._namedFlowCollections = {};
  460. },
  461. _updateLocations: function()
  462. {
  463. for (var i = 0; i < this._locations.length; ++i)
  464. this._locations[i].update();
  465. },
  466. /**
  467. * @param {WebInspector.CSSRule} cssRule
  468. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  469. * @return {?WebInspector.LiveLocation}
  470. */
  471. createLiveLocation: function(cssRule, updateDelegate)
  472. {
  473. if (!cssRule._rawLocation)
  474. return null;
  475. var location = new WebInspector.CSSStyleModel.LiveLocation(cssRule._rawLocation, updateDelegate);
  476. if (!location.uiLocation())
  477. return null;
  478. this._locations.push(location);
  479. location.update();
  480. return location;
  481. },
  482. /**
  483. * @param {WebInspector.CSSLocation} rawLocation
  484. * @return {?WebInspector.UILocation}
  485. */
  486. rawLocationToUILocation: function(rawLocation)
  487. {
  488. var sourceMapping = this._sourceMappings[rawLocation.url];
  489. if (sourceMapping) {
  490. var uiLocation = sourceMapping.rawLocationToUILocation(rawLocation);
  491. if (uiLocation)
  492. return uiLocation;
  493. }
  494. var uiSourceCode = this._workspace.uiSourceCodeForURL(rawLocation.url);
  495. if (!uiSourceCode)
  496. return null;
  497. return new WebInspector.UILocation(uiSourceCode, rawLocation.lineNumber, rawLocation.columnNumber);
  498. },
  499. __proto__: WebInspector.Object.prototype
  500. }
  501. /**
  502. * @constructor
  503. * @extends {WebInspector.LiveLocation}
  504. * @param {WebInspector.CSSLocation} rawLocation
  505. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  506. */
  507. WebInspector.CSSStyleModel.LiveLocation = function(rawLocation, updateDelegate)
  508. {
  509. WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
  510. }
  511. WebInspector.CSSStyleModel.LiveLocation.prototype = {
  512. /**
  513. * @return {WebInspector.UILocation}
  514. */
  515. uiLocation: function()
  516. {
  517. var cssLocation = /** @type WebInspector.CSSLocation */ (this.rawLocation());
  518. return WebInspector.cssModel.rawLocationToUILocation(cssLocation);
  519. },
  520. dispose: function()
  521. {
  522. WebInspector.LiveLocation.prototype.dispose.call(this);
  523. var locations = WebInspector.cssModel._locations;
  524. if (locations)
  525. locations.remove(this);
  526. },
  527. __proto__: WebInspector.LiveLocation.prototype
  528. }
  529. /**
  530. * @constructor
  531. * @implements {WebInspector.RawLocation}
  532. * @param {string} url
  533. * @param {number} lineNumber
  534. * @param {number=} columnNumber
  535. */
  536. WebInspector.CSSLocation = function(url, lineNumber, columnNumber)
  537. {
  538. this.url = url;
  539. this.lineNumber = lineNumber;
  540. this.columnNumber = columnNumber || 0;
  541. }
  542. /**
  543. * @constructor
  544. * @param {CSSAgent.CSSStyle} payload
  545. */
  546. WebInspector.CSSStyleDeclaration = function(payload)
  547. {
  548. this.id = payload.styleId;
  549. this.width = payload.width;
  550. this.height = payload.height;
  551. this.range = payload.range;
  552. this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries);
  553. this._livePropertyMap = {}; // LIVE properties (source-based or style-based) : { name -> CSSProperty }
  554. this._allProperties = []; // ALL properties: [ CSSProperty ]
  555. this.__disabledProperties = {}; // DISABLED properties: { index -> CSSProperty }
  556. var payloadPropertyCount = payload.cssProperties.length;
  557. var propertyIndex = 0;
  558. for (var i = 0; i < payloadPropertyCount; ++i) {
  559. var property = WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]);
  560. this._allProperties.push(property);
  561. if (property.disabled)
  562. this.__disabledProperties[i] = property;
  563. if (!property.active && !property.styleBased)
  564. continue;
  565. var name = property.name;
  566. this[propertyIndex] = name;
  567. this._livePropertyMap[name] = property;
  568. ++propertyIndex;
  569. }
  570. this.length = propertyIndex;
  571. if ("cssText" in payload)
  572. this.cssText = payload.cssText;
  573. }
  574. /**
  575. * @param {Array.<CSSAgent.ShorthandEntry>} shorthandEntries
  576. * @return {Object}
  577. */
  578. WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries)
  579. {
  580. var result = {};
  581. for (var i = 0; i < shorthandEntries.length; ++i)
  582. result[shorthandEntries[i].name] = shorthandEntries[i].value;
  583. return result;
  584. }
  585. /**
  586. * @param {CSSAgent.CSSStyle} payload
  587. * @return {WebInspector.CSSStyleDeclaration}
  588. */
  589. WebInspector.CSSStyleDeclaration.parsePayload = function(payload)
  590. {
  591. return new WebInspector.CSSStyleDeclaration(payload);
  592. }
  593. /**
  594. * @param {Array.<CSSAgent.CSSComputedStyleProperty>} payload
  595. * @return {WebInspector.CSSStyleDeclaration}
  596. */
  597. WebInspector.CSSStyleDeclaration.parseComputedStylePayload = function(payload)
  598. {
  599. var newPayload = /** @type {CSSAgent.CSSStyle} */ ({ cssProperties: [], shorthandEntries: [], width: "", height: "" });
  600. if (payload)
  601. newPayload.cssProperties = payload;
  602. return new WebInspector.CSSStyleDeclaration(newPayload);
  603. }
  604. WebInspector.CSSStyleDeclaration.prototype = {
  605. get allProperties()
  606. {
  607. return this._allProperties;
  608. },
  609. /**
  610. * @param {string} name
  611. * @return {WebInspector.CSSProperty|undefined}
  612. */
  613. getLiveProperty: function(name)
  614. {
  615. return this._livePropertyMap[name];
  616. },
  617. /**
  618. * @param {string} name
  619. * @return {string}
  620. */
  621. getPropertyValue: function(name)
  622. {
  623. var property = this._livePropertyMap[name];
  624. return property ? property.value : "";
  625. },
  626. /**
  627. * @param {string} name
  628. * @return {string}
  629. */
  630. getPropertyPriority: function(name)
  631. {
  632. var property = this._livePropertyMap[name];
  633. return property ? property.priority : "";
  634. },
  635. /**
  636. * @param {string} name
  637. * @return {boolean}
  638. */
  639. isPropertyImplicit: function(name)
  640. {
  641. var property = this._livePropertyMap[name];
  642. return property ? property.implicit : "";
  643. },
  644. /**
  645. * @param {string} name
  646. * @return {Array.<WebInspector.CSSProperty>}
  647. */
  648. longhandProperties: function(name)
  649. {
  650. var longhands = WebInspector.CSSMetadata.cssPropertiesMetainfo.longhands(name);
  651. var result = [];
  652. for (var i = 0; longhands && i < longhands.length; ++i) {
  653. var property = this._livePropertyMap[longhands[i]];
  654. if (property)
  655. result.push(property);
  656. }
  657. return result;
  658. },
  659. /**
  660. * @param {string} shorthandProperty
  661. * @return {string}
  662. */
  663. shorthandValue: function(shorthandProperty)
  664. {
  665. return this._shorthandValues[shorthandProperty];
  666. },
  667. /**
  668. * @param {number} index
  669. * @return {?WebInspector.CSSProperty}
  670. */
  671. propertyAt: function(index)
  672. {
  673. return (index < this.allProperties.length) ? this.allProperties[index] : null;
  674. },
  675. /**
  676. * @return {number}
  677. */
  678. pastLastSourcePropertyIndex: function()
  679. {
  680. for (var i = this.allProperties.length - 1; i >= 0; --i) {
  681. var property = this.allProperties[i];
  682. if (property.active || property.disabled)
  683. return i + 1;
  684. }
  685. return 0;
  686. },
  687. /**
  688. * @param {number=} index
  689. */
  690. newBlankProperty: function(index)
  691. {
  692. index = (typeof index === "undefined") ? this.pastLastSourcePropertyIndex() : index;
  693. return new WebInspector.CSSProperty(this, index, "", "", "", "active", true, false, "");
  694. },
  695. /**
  696. * @param {number} index
  697. * @param {string} name
  698. * @param {string} value
  699. * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
  700. */
  701. insertPropertyAt: function(index, name, value, userCallback)
  702. {
  703. /**
  704. * @param {?string} error
  705. * @param {CSSAgent.CSSStyle} payload
  706. */
  707. function callback(error, payload)
  708. {
  709. WebInspector.cssModel._pendingCommandsMajorState.pop();
  710. if (!userCallback)
  711. return;
  712. if (error) {
  713. console.error(error);
  714. userCallback(null);
  715. } else {
  716. userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload));
  717. }
  718. }
  719. if (!this.id)
  720. throw "No style id";
  721. WebInspector.cssModel._pendingCommandsMajorState.push(true);
  722. CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(this));
  723. },
  724. /**
  725. * @param {string} name
  726. * @param {string} value
  727. * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
  728. */
  729. appendProperty: function(name, value, userCallback)
  730. {
  731. this.insertPropertyAt(this.allProperties.length, name, value, userCallback);
  732. }
  733. }
  734. /**
  735. * @constructor
  736. * @param {CSSAgent.CSSRule} payload
  737. * @param {Array.<number>=} matchingSelectors
  738. */
  739. WebInspector.CSSRule = function(payload, matchingSelectors)
  740. {
  741. this.id = payload.ruleId;
  742. if (matchingSelectors)
  743. this.matchingSelectors = matchingSelectors;
  744. this.selectors = payload.selectorList.selectors;
  745. this.selectorText = this.selectors.join(", ");
  746. this.selectorRange = payload.selectorList.range;
  747. this.sourceLine = payload.sourceLine;
  748. this.sourceURL = payload.sourceURL;
  749. this.origin = payload.origin;
  750. this.style = WebInspector.CSSStyleDeclaration.parsePayload(payload.style);
  751. this.style.parentRule = this;
  752. if (payload.media)
  753. this.media = WebInspector.CSSMedia.parseMediaArrayPayload(payload.media);
  754. this._setRawLocation(payload);
  755. }
  756. /**
  757. * @param {CSSAgent.CSSRule} payload
  758. * @param {Array.<number>=} matchingIndices
  759. * @return {WebInspector.CSSRule}
  760. */
  761. WebInspector.CSSRule.parsePayload = function(payload, matchingIndices)
  762. {
  763. return new WebInspector.CSSRule(payload, matchingIndices);
  764. }
  765. WebInspector.CSSRule.prototype = {
  766. _setRawLocation: function(payload)
  767. {
  768. if (!payload.sourceURL)
  769. return;
  770. if (this.selectorRange) {
  771. var resource = WebInspector.resourceTreeModel.resourceForURL(payload.sourceURL);
  772. if (resource && resource.type === WebInspector.resourceTypes.Stylesheet) {
  773. this._rawLocation = new WebInspector.CSSLocation(payload.sourceURL, this.selectorRange.startLine, this.selectorRange.startColumn);
  774. return;
  775. }
  776. }
  777. this._rawLocation = new WebInspector.CSSLocation(payload.sourceURL, payload.sourceLine);
  778. },
  779. get isUserAgent()
  780. {
  781. return this.origin === "user-agent";
  782. },
  783. get isUser()
  784. {
  785. return this.origin === "user";
  786. },
  787. get isViaInspector()
  788. {
  789. return this.origin === "inspector";
  790. },
  791. get isRegular()
  792. {
  793. return this.origin === "regular";
  794. },
  795. /**
  796. * @return {boolean}
  797. */
  798. isSourceNavigable: function()
  799. {
  800. if (!this.sourceURL)
  801. return false;
  802. var resource = WebInspector.resourceTreeModel.resourceForURL(this.sourceURL);
  803. return !!resource && resource.contentType() === WebInspector.resourceTypes.Stylesheet;
  804. }
  805. }
  806. /**
  807. * @constructor
  808. * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
  809. * @param {number} index
  810. * @param {string} name
  811. * @param {string} value
  812. * @param {?string} priority
  813. * @param {string} status
  814. * @param {boolean} parsedOk
  815. * @param {boolean} implicit
  816. * @param {?string=} text
  817. * @param {CSSAgent.SourceRange=} range
  818. */
  819. WebInspector.CSSProperty = function(ownerStyle, index, name, value, priority, status, parsedOk, implicit, text, range)
  820. {
  821. this.ownerStyle = ownerStyle;
  822. this.index = index;
  823. this.name = name;
  824. this.value = value;
  825. this.priority = priority;
  826. this.status = status;
  827. this.parsedOk = parsedOk;
  828. this.implicit = implicit;
  829. this.text = text;
  830. this.range = range;
  831. }
  832. /**
  833. * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
  834. * @param {number} index
  835. * @param {CSSAgent.CSSProperty} payload
  836. * @return {WebInspector.CSSProperty}
  837. */
  838. WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload)
  839. {
  840. // The following default field values are used in the payload:
  841. // priority: ""
  842. // parsedOk: true
  843. // implicit: false
  844. // status: "style"
  845. var result = new WebInspector.CSSProperty(
  846. ownerStyle, index, payload.name, payload.value, payload.priority || "", payload.status || "style", ("parsedOk" in payload) ? !!payload.parsedOk : true, !!payload.implicit, payload.text, payload.range);
  847. return result;
  848. }
  849. WebInspector.CSSProperty.prototype = {
  850. get propertyText()
  851. {
  852. if (this.text !== undefined)
  853. return this.text;
  854. if (this.name === "")
  855. return "";
  856. return this.name + ": " + this.value + (this.priority ? " !" + this.priority : "") + ";";
  857. },
  858. get isLive()
  859. {
  860. return this.active || this.styleBased;
  861. },
  862. get active()
  863. {
  864. return this.status === "active";
  865. },
  866. get styleBased()
  867. {
  868. return this.status === "style";
  869. },
  870. get inactive()
  871. {
  872. return this.status === "inactive";
  873. },
  874. get disabled()
  875. {
  876. return this.status === "disabled";
  877. },
  878. /**
  879. * Replaces "propertyName: propertyValue [!important];" in the stylesheet by an arbitrary propertyText.
  880. *
  881. * @param {string} propertyText
  882. * @param {boolean} majorChange
  883. * @param {boolean} overwrite
  884. * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
  885. */
  886. setText: function(propertyText, majorChange, overwrite, userCallback)
  887. {
  888. /**
  889. * @param {?WebInspector.CSSStyleDeclaration} style
  890. */
  891. function enabledCallback(style)
  892. {
  893. if (userCallback)
  894. userCallback(style);
  895. }
  896. /**
  897. * @param {?string} error
  898. * @param {?CSSAgent.CSSStyle} stylePayload
  899. */
  900. function callback(error, stylePayload)
  901. {
  902. WebInspector.cssModel._pendingCommandsMajorState.pop();
  903. if (!error) {
  904. if (majorChange)
  905. WebInspector.domAgent.markUndoableState();
  906. this.text = propertyText;
  907. var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
  908. var newProperty = style.allProperties[this.index];
  909. if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) {
  910. newProperty.setDisabled(false, enabledCallback);
  911. return;
  912. }
  913. if (userCallback)
  914. userCallback(style);
  915. } else {
  916. if (userCallback)
  917. userCallback(null);
  918. }
  919. }
  920. if (!this.ownerStyle)
  921. throw "No ownerStyle for property";
  922. if (!this.ownerStyle.id)
  923. throw "No owner style id";
  924. // An index past all the properties adds a new property to the style.
  925. WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
  926. CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, overwrite, callback.bind(this));
  927. },
  928. /**
  929. * @param {string} newValue
  930. * @param {boolean} majorChange
  931. * @param {boolean} overwrite
  932. * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
  933. */
  934. setValue: function(newValue, majorChange, overwrite, userCallback)
  935. {
  936. var text = this.name + ": " + newValue + (this.priority ? " !" + this.priority : "") + ";"
  937. this.setText(text, majorChange, overwrite, userCallback);
  938. },
  939. /**
  940. * @param {boolean} disabled
  941. * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
  942. */
  943. setDisabled: function(disabled, userCallback)
  944. {
  945. if (!this.ownerStyle && userCallback)
  946. userCallback(null);
  947. if (disabled === this.disabled && userCallback)
  948. userCallback(this.ownerStyle);
  949. /**
  950. * @param {?string} error
  951. * @param {CSSAgent.CSSStyle} stylePayload
  952. */
  953. function callback(error, stylePayload)
  954. {
  955. WebInspector.cssModel._pendingCommandsMajorState.pop();
  956. if (error) {
  957. if (userCallback)
  958. userCallback(null);
  959. return;
  960. }
  961. WebInspector.domAgent.markUndoableState();
  962. if (userCallback) {
  963. var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
  964. userCallback(style);
  965. }
  966. }
  967. if (!this.ownerStyle.id)
  968. throw "No owner style id";
  969. WebInspector.cssModel._pendingCommandsMajorState.push(false);
  970. CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this));
  971. },
  972. /**
  973. * @param {boolean} forName
  974. * @return {WebInspector.UILocation}
  975. */
  976. uiLocation: function(forName)
  977. {
  978. if (!this.range || !this.ownerStyle || !this.ownerStyle.parentRule || !this.ownerStyle.parentRule.sourceURL)
  979. return null;
  980. var range = this.range;
  981. var line = forName ? range.startLine : range.endLine;
  982. // End of range is exclusive, so subtract 1 from the end offset.
  983. var column = forName ? range.startColumn : range.endColumn - 1;
  984. var rawLocation = new WebInspector.CSSLocation(this.ownerStyle.parentRule.sourceURL, line, column);
  985. return WebInspector.cssModel.rawLocationToUILocation(rawLocation);
  986. }
  987. }
  988. /**
  989. * @constructor
  990. * @param {CSSAgent.CSSMedia} payload
  991. */
  992. WebInspector.CSSMedia = function(payload)
  993. {
  994. this.text = payload.text;
  995. this.source = payload.source;
  996. this.sourceURL = payload.sourceURL || "";
  997. this.sourceLine = typeof payload.sourceLine === "undefined" || this.source === "linkedSheet" ? -1 : payload.sourceLine;
  998. }
  999. WebInspector.CSSMedia.Source = {
  1000. LINKED_SHEET: "linkedSheet",
  1001. INLINE_SHEET: "inlineSheet",
  1002. MEDIA_RULE: "mediaRule",
  1003. IMPORT_RULE: "importRule"
  1004. };
  1005. /**
  1006. * @param {CSSAgent.CSSMedia} payload
  1007. * @return {WebInspector.CSSMedia}
  1008. */
  1009. WebInspector.CSSMedia.parsePayload = function(payload)
  1010. {
  1011. return new WebInspector.CSSMedia(payload);
  1012. }
  1013. /**
  1014. * @param {Array.<CSSAgent.CSSMedia>} payload
  1015. * @return {Array.<WebInspector.CSSMedia>}
  1016. */
  1017. WebInspector.CSSMedia.parseMediaArrayPayload = function(payload)
  1018. {
  1019. var result = [];
  1020. for (var i = 0; i < payload.length; ++i)
  1021. result.push(WebInspector.CSSMedia.parsePayload(payload[i]));
  1022. return result;
  1023. }
  1024. /**
  1025. * @constructor
  1026. * @param {CSSAgent.CSSStyleSheetBody} payload
  1027. */
  1028. WebInspector.CSSStyleSheet = function(payload)
  1029. {
  1030. this.id = payload.styleSheetId;
  1031. this.rules = [];
  1032. this.styles = {};
  1033. for (var i = 0; i < payload.rules.length; ++i) {
  1034. var rule = WebInspector.CSSRule.parsePayload(payload.rules[i]);
  1035. this.rules.push(rule);
  1036. if (rule.style)
  1037. this.styles[rule.style.id] = rule.style;
  1038. }
  1039. if ("text" in payload)
  1040. this._text = payload.text;
  1041. }
  1042. /**
  1043. * @param {CSSAgent.StyleSheetId} styleSheetId
  1044. * @param {function(?WebInspector.CSSStyleSheet)} userCallback
  1045. */
  1046. WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback)
  1047. {
  1048. /**
  1049. * @param {?string} error
  1050. * @param {CSSAgent.CSSStyleSheetBody} styleSheetPayload
  1051. */
  1052. function callback(error, styleSheetPayload)
  1053. {
  1054. if (error)
  1055. userCallback(null);
  1056. else
  1057. userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload));
  1058. }
  1059. CSSAgent.getStyleSheet(styleSheetId, callback.bind(this));
  1060. }
  1061. WebInspector.CSSStyleSheet.prototype = {
  1062. /**
  1063. * @return {string|undefined}
  1064. */
  1065. getText: function()
  1066. {
  1067. return this._text;
  1068. },
  1069. /**
  1070. * @param {string} newText
  1071. * @param {boolean} majorChange
  1072. * @param {function(?string)=} userCallback
  1073. */
  1074. setText: function(newText, majorChange, userCallback)
  1075. {
  1076. /**
  1077. * @param {?string} error
  1078. */
  1079. function callback(error)
  1080. {
  1081. if (!error)
  1082. WebInspector.domAgent.markUndoableState();
  1083. WebInspector.cssModel._pendingCommandsMajorState.pop();
  1084. if (userCallback)
  1085. userCallback(error);
  1086. }
  1087. WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
  1088. CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this));
  1089. }
  1090. }
  1091. /**
  1092. * @constructor
  1093. */
  1094. WebInspector.CSSStyleModelResourceBinding = function()
  1095. {
  1096. this._reset();
  1097. }
  1098. WebInspector.CSSStyleModelResourceBinding.prototype = {
  1099. /**
  1100. * @param {WebInspector.Resource} resource
  1101. * @param {function(?CSSAgent.StyleSheetId)} callback
  1102. */
  1103. requestStyleSheetIdForResource: function(resource, callback)
  1104. {
  1105. function innerCallback()
  1106. {
  1107. callback(this._styleSheetIdForResource(resource));
  1108. }
  1109. if (this._styleSheetIdForResource(resource))
  1110. innerCallback.call(this);
  1111. else
  1112. this._loadStyleSheetHeaders(innerCallback.bind(this));
  1113. },
  1114. /**
  1115. * @param {CSSAgent.StyleSheetId} styleSheetId
  1116. * @param {function(?string)} callback
  1117. */
  1118. requestResourceURLForStyleSheetId: function(styleSheetId, callback)
  1119. {
  1120. function innerCallback()
  1121. {
  1122. var header = this._styleSheetIdToHeader[styleSheetId];
  1123. if (!header) {
  1124. callback(null);
  1125. return;
  1126. }
  1127. var frame = WebInspector.resourceTreeModel.frameForId(header.frameId);
  1128. if (!frame) {
  1129. callback(null);
  1130. return;
  1131. }
  1132. var styleSheetURL = header.origin === "inspector" ? this._viaInspectorResourceURL(header.sourceURL) : header.sourceURL;
  1133. callback(styleSheetURL);
  1134. }
  1135. if (this._styleSheetIdToHeader[styleSheetId])
  1136. innerCallback.call(this);
  1137. else
  1138. this._loadStyleSheetHeaders(innerCallback.bind(this));
  1139. },
  1140. /**
  1141. * @param {WebInspector.Resource} resource
  1142. * @return {CSSAgent.StyleSheetId}
  1143. */
  1144. _styleSheetIdForResource: function(resource)
  1145. {
  1146. return this._frameAndURLToStyleSheetId[resource.frameId + ":" + resource.url];
  1147. },
  1148. /**
  1149. * @param {function(?string)} callback
  1150. */
  1151. _loadStyleSheetHeaders: function(callback)
  1152. {
  1153. /**
  1154. * @param {?string} error
  1155. * @param {Array.<CSSAgent.CSSStyleSheetHeader>} infos
  1156. */
  1157. function didGetAllStyleSheets(error, infos)
  1158. {
  1159. if (error) {
  1160. callback(error);
  1161. return;
  1162. }
  1163. for (var i = 0; i < infos.length; ++i) {
  1164. var info = infos[i];
  1165. if (info.origin === "inspector") {
  1166. this._getOrCreateInspectorResource(info);
  1167. continue;
  1168. }
  1169. this._frameAndURLToStyleSheetId[info.frameId + ":" + info.sourceURL] = info.styleSheetId;
  1170. this._styleSheetIdToHeader[info.styleSheetId] = info;
  1171. }
  1172. callback(null);
  1173. }
  1174. CSSAgent.getAllStyleSheets(didGetAllStyleSheets.bind(this));
  1175. },
  1176. /**
  1177. * @param {CSSAgent.StyleSheetId} styleSheetId
  1178. * @param {function(?WebInspector.Resource)} callback
  1179. */
  1180. _requestViaInspectorResource: function(styleSheetId, callback)
  1181. {
  1182. var header = this._styleSheetIdToHeader[styleSheetId];
  1183. if (header) {
  1184. callback(this._getOrCreateInspectorResource(header));
  1185. return;
  1186. }
  1187. function headersLoaded()
  1188. {
  1189. var header = this._styleSheetIdToHeader[styleSheetId];
  1190. if (header)
  1191. callback(this._getOrCreateInspectorResource(header));
  1192. else
  1193. callback(null);
  1194. }
  1195. this._loadStyleSheetHeaders(headersLoaded.bind(this));
  1196. },
  1197. /**
  1198. * @param {CSSAgent.CSSStyleSheetHeader} header
  1199. * @return {?WebInspector.Resource}
  1200. */
  1201. _getOrCreateInspectorResource: function(header)
  1202. {
  1203. var frame = WebInspector.resourceTreeModel.frameForId(header.frameId);
  1204. if (!frame)
  1205. return null;
  1206. var viaInspectorURL = this._viaInspectorResourceURL(header.sourceURL);
  1207. var inspectorResource = frame.resourceForURL(viaInspectorURL);
  1208. if (inspectorResource)
  1209. return inspectorResource;
  1210. var resource = frame.resourceForURL(header.sourceURL);
  1211. if (!resource)
  1212. return null;
  1213. this._frameAndURLToStyleSheetId[header.frameId + ":" + viaInspectorURL] = header.styleSheetId;
  1214. this._styleSheetIdToHeader[header.styleSheetId] = header;
  1215. inspectorResource = new WebInspector.Resource(null, viaInspectorURL, resource.documentURL, resource.frameId, resource.loaderId, WebInspector.resourceTypes.Stylesheet, "text/css", true);
  1216. /**
  1217. * @param {function(?string, boolean, string)} callback
  1218. */
  1219. function overrideRequestContent(callback)
  1220. {
  1221. function callbackWrapper(error, content)
  1222. {
  1223. callback(error ? "" : content, false, "text/css");
  1224. }
  1225. CSSAgent.getStyleSheetText(header.styleSheetId, callbackWrapper);
  1226. }
  1227. inspectorResource.requestContent = overrideRequestContent;
  1228. frame.addResource(inspectorResource);
  1229. return inspectorResource;
  1230. },
  1231. /**
  1232. * @param {string} documentURL
  1233. * @return {string}
  1234. */
  1235. _viaInspectorResourceURL: function(documentURL)
  1236. {
  1237. var parsedURL = new WebInspector.ParsedURL(documentURL);
  1238. var fakeURL = "inspector://" + parsedURL.host + parsedURL.folderPathComponents;
  1239. if (!fakeURL.endsWith("/"))
  1240. fakeURL += "/";
  1241. fakeURL += "inspector-stylesheet";
  1242. return fakeURL;
  1243. },
  1244. _reset: function()
  1245. {
  1246. // Main frame navigation - clear history.
  1247. this._frameAndURLToStyleSheetId = {};
  1248. this._styleSheetIdToHeader = {};
  1249. }
  1250. }
  1251. /**
  1252. * @constructor
  1253. * @implements {CSSAgent.Dispatcher}
  1254. * @param {WebInspector.CSSStyleModel} cssModel
  1255. */
  1256. WebInspector.CSSDispatcher = function(cssModel)
  1257. {
  1258. this._cssModel = cssModel;
  1259. }
  1260. WebInspector.CSSDispatcher.prototype = {
  1261. mediaQueryResultChanged: function()
  1262. {
  1263. this._cssModel.mediaQueryResultChanged();
  1264. },
  1265. /**
  1266. * @param {CSSAgent.StyleSheetId} styleSheetId
  1267. */
  1268. styleSheetChanged: function(styleSheetId)
  1269. {
  1270. this._cssModel._fireStyleSheetChanged(styleSheetId);
  1271. },
  1272. /**
  1273. * @param {CSSAgent.NamedFlow} namedFlowPayload
  1274. */
  1275. namedFlowCreated: function(namedFlowPayload)
  1276. {
  1277. this._cssModel._namedFlowCreated(namedFlowPayload);
  1278. },
  1279. /**
  1280. * @param {DOMAgent.NodeId} documentNodeId
  1281. * @param {string} flowName
  1282. */
  1283. namedFlowRemoved: function(documentNodeId, flowName)
  1284. {
  1285. this._cssModel._namedFlowRemoved(documentNodeId, flowName);
  1286. },
  1287. /**
  1288. * @param {CSSAgent.NamedFlow} namedFlowPayload
  1289. */
  1290. regionLayoutUpdated: function(namedFlowPayload)
  1291. {
  1292. this._cssModel._regionLayoutUpdated(namedFlowPayload);
  1293. }
  1294. }
  1295. /**
  1296. * @constructor
  1297. * @param {CSSAgent.NamedFlow} payload
  1298. */
  1299. WebInspector.NamedFlow = function(payload)
  1300. {
  1301. this.documentNodeId = payload.documentNodeId;
  1302. this.name = payload.name;
  1303. this.overset = payload.overset;
  1304. this.content = payload.content;
  1305. this.regions = payload.regions;
  1306. }
  1307. /**
  1308. * @param {CSSAgent.NamedFlow} payload
  1309. * @return {WebInspector.NamedFlow}
  1310. */
  1311. WebInspector.NamedFlow.parsePayload = function(payload)
  1312. {
  1313. return new WebInspector.NamedFlow(payload);
  1314. }
  1315. /**
  1316. * @constructor
  1317. * @param {Array.<CSSAgent.NamedFlow>} payload
  1318. */
  1319. WebInspector.NamedFlowCollection = function(payload)
  1320. {
  1321. /** @type {Object.<string, WebInspector.NamedFlow>} */
  1322. this.namedFlowMap = {};
  1323. for (var i = 0; i < payload.length; ++i) {
  1324. var namedFlow = WebInspector.NamedFlow.parsePayload(payload[i]);
  1325. this.namedFlowMap[namedFlow.name] = namedFlow;
  1326. }
  1327. }
  1328. WebInspector.NamedFlowCollection.prototype = {
  1329. /**
  1330. * @param {WebInspector.NamedFlow} namedFlow
  1331. */
  1332. _appendNamedFlow: function(namedFlow)
  1333. {
  1334. this.namedFlowMap[namedFlow.name] = namedFlow;
  1335. },
  1336. /**
  1337. * @param {string} flowName
  1338. */
  1339. _removeNamedFlow: function(flowName)
  1340. {
  1341. delete this.namedFlowMap[flowName];
  1342. },
  1343. /**
  1344. * @param {string} flowName
  1345. * @return {WebInspector.NamedFlow}
  1346. */
  1347. flowByName: function(flowName)
  1348. {
  1349. var namedFlow = this.namedFlowMap[flowName];
  1350. if (!namedFlow)
  1351. return null;
  1352. return namedFlow;
  1353. }
  1354. }
  1355. /**
  1356. * @type {WebInspector.CSSStyleModel}
  1357. */
  1358. WebInspector.cssModel = null;