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