Home | History | Annotate | Download | only in front-end
      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 WebInspector.CSSStyleModel = function()
     32 {
     33     new WebInspector.CSSStyleModelResourceBinding(this);
     34 }
     35 
     36 WebInspector.CSSStyleModel.parseRuleArrayPayload = function(ruleArray)
     37 {
     38     var result = [];
     39     for (var i = 0; i < ruleArray.length; ++i)
     40         result.push(WebInspector.CSSRule.parsePayload(ruleArray[i]));
     41     return result;
     42 }
     43 
     44 WebInspector.CSSStyleModel.Events = {
     45     StyleSheetChanged: 0
     46 }
     47 
     48 WebInspector.CSSStyleModel.prototype = {
     49     getStylesAsync: function(nodeId, userCallback)
     50     {
     51         function callback(userCallback, error, payload)
     52         {
     53             if (error) {
     54                 if (userCallback)
     55                     userCallback(null);
     56                 return;
     57             }
     58 
     59             var result = {};
     60             if ("inlineStyle" in payload)
     61                 result.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(payload.inlineStyle);
     62 
     63             result.computedStyle = WebInspector.CSSStyleDeclaration.parsePayload(payload.computedStyle);
     64             result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(payload.matchedCSSRules);
     65 
     66             result.styleAttributes = {};
     67             var payloadStyleAttributes = payload.styleAttributes;
     68             for (var i = 0; i < payloadStyleAttributes.length; ++i) {
     69                 var name = payloadStyleAttributes[i].name;
     70                 result.styleAttributes[name] = WebInspector.CSSStyleDeclaration.parsePayload(payloadStyleAttributes[i].style);
     71             }
     72 
     73             result.pseudoElements = [];
     74             for (var i = 0; i < payload.pseudoElements.length; ++i) {
     75                 var entryPayload = payload.pseudoElements[i];
     76                 result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.rules) });
     77             }
     78 
     79             result.inherited = [];
     80             for (var i = 0; i < payload.inherited.length; ++i) {
     81                 var entryPayload = payload.inherited[i];
     82                 var entry = {};
     83                 if ("inlineStyle" in entryPayload)
     84                     entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(entryPayload.inlineStyle);
     85                 if ("matchedCSSRules" in entryPayload)
     86                     entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.matchedCSSRules);
     87                 result.inherited.push(entry);
     88             }
     89 
     90             if (userCallback)
     91                 userCallback(result);
     92         }
     93 
     94         CSSAgent.getStylesForNode(nodeId, callback.bind(null, userCallback));
     95     },
     96 
     97     getComputedStyleAsync: function(nodeId, userCallback)
     98     {
     99         function callback(userCallback, error, stylePayload)
    100         {
    101             if (error)
    102                 userCallback(null);
    103             else
    104                 userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload));
    105         }
    106 
    107         CSSAgent.getComputedStyleForNode(nodeId, callback.bind(null, userCallback));
    108     },
    109 
    110     getInlineStyleAsync: function(nodeId, userCallback)
    111     {
    112         function callback(userCallback, error, stylePayload)
    113         {
    114             if (error)
    115                 userCallback(null);
    116             else
    117                 userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload));
    118         }
    119 
    120         CSSAgent.getInlineStyleForNode(nodeId, callback.bind(null, userCallback));
    121     },
    122 
    123     setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback)
    124     {
    125         function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
    126         {
    127             if (!selectedNodeIds)
    128                 return;
    129             var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
    130             var rule = WebInspector.CSSRule.parsePayload(rulePayload);
    131             successCallback(rule, doesAffectSelectedNode);
    132             this._fireStyleSheetChanged(rule.id.styleSheetId, true);
    133         }
    134 
    135         function callback(nodeId, successCallback, failureCallback, error, newSelector, rulePayload)
    136         {
    137             // FIXME: looks like rulePayload is always null.
    138             if (error)
    139                 failureCallback();
    140             else {
    141                 var documentElementId = this._documentElementId(nodeId);
    142                 if (documentElementId)
    143                     WebInspector.domAgent.querySelectorAll(documentElementId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
    144                 else
    145                     failureCallback();
    146             }
    147         }
    148 
    149         CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector));
    150     },
    151 
    152     addRule: function(nodeId, selector, successCallback, failureCallback)
    153     {
    154         function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
    155         {
    156             if (!selectedNodeIds)
    157                 return;
    158             var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
    159             var rule = WebInspector.CSSRule.parsePayload(rulePayload);
    160             successCallback(rule, doesAffectSelectedNode);
    161             this._fireStyleSheetChanged(rule.id.styleSheetId, true);
    162         }
    163 
    164         function callback(successCallback, failureCallback, selector, error, rulePayload)
    165         {
    166             if (error) {
    167                 // Invalid syntax for a selector
    168                 failureCallback();
    169             } else {
    170                 var documentElementId = this._documentElementId(nodeId);
    171                 if (documentElementId)
    172                     WebInspector.domAgent.querySelectorAll(documentElementId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
    173                 else
    174                     failureCallback();
    175             }
    176         }
    177 
    178         CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector));
    179     },
    180 
    181     _documentElementId: function(nodeId)
    182     {
    183         var node = WebInspector.domAgent.nodeForId(nodeId);
    184         if (!node)
    185             return null;
    186         return node.ownerDocumentElement().id;
    187     },
    188 
    189     _fireStyleSheetChanged: function(styleSheetId, majorChange, callback)
    190     {
    191         callback = callback || function() {};
    192 
    193         if (!majorChange || !styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged)) {
    194             callback();
    195             return;
    196         }
    197 
    198         function mycallback(error, content)
    199         {
    200             if (!error)
    201                 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, content: content, majorChange: majorChange });
    202             callback();
    203         }
    204 
    205         CSSAgent.getStyleSheetText(styleSheetId, mycallback.bind(this));
    206     },
    207 
    208     setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback)
    209     {
    210         function callback(error)
    211         {
    212              if (!error)
    213                  this._fireStyleSheetChanged(styleSheetId, majorChange, userCallback ? userCallback.bind(this, error) : null);
    214         }
    215         CSSAgent.setStyleSheetText(styleSheetId, newText, callback.bind(this));
    216     }
    217 }
    218 
    219 WebInspector.CSSStyleModel.prototype.__proto__ = WebInspector.Object.prototype;
    220 
    221 WebInspector.CSSStyleDeclaration = function(payload)
    222 {
    223     this.id = payload.styleId;
    224     this.width = payload.width;
    225     this.height = payload.height;
    226     this.range = payload.range;
    227     this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries);
    228     this._livePropertyMap = {}; // LIVE properties (source-based or style-based) : { name -> CSSProperty }
    229     this._allProperties = []; // ALL properties: [ CSSProperty ]
    230     this._longhandProperties = {}; // shorthandName -> [ CSSProperty ]
    231     this.__disabledProperties = {}; // DISABLED properties: { index -> CSSProperty }
    232     var payloadPropertyCount = payload.cssProperties.length;
    233 
    234     var propertyIndex = 0;
    235     for (var i = 0; i < payloadPropertyCount; ++i) {
    236         var property = new WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]);
    237         this._allProperties.push(property);
    238         if (property.disabled)
    239             this.__disabledProperties[i] = property;
    240         if (!property.active && !property.styleBased)
    241             continue;
    242         var name = property.name;
    243         this[propertyIndex] = name;
    244         this._livePropertyMap[name] = property;
    245 
    246         // Index longhand properties.
    247         if (property.shorthand) { // only for parsed
    248             var longhands = this._longhandProperties[property.shorthand];
    249             if (!longhands) {
    250                 longhands = [];
    251                 this._longhandProperties[property.shorthand] = longhands;
    252             }
    253             longhands.push(property);
    254         }
    255         ++propertyIndex;
    256     }
    257     this.length = propertyIndex;
    258     if ("cssText" in payload)
    259         this.cssText = payload.cssText;
    260 }
    261 
    262 WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries)
    263 {
    264     var result = {};
    265     for (var i = 0; i < shorthandEntries.length; ++i)
    266         result[shorthandEntries[i].name] = shorthandEntries[i].value;
    267     return result;
    268 }
    269 
    270 WebInspector.CSSStyleDeclaration.parsePayload = function(payload)
    271 {
    272     return new WebInspector.CSSStyleDeclaration(payload);
    273 }
    274 
    275 WebInspector.CSSStyleDeclaration.prototype = {
    276     get allProperties()
    277     {
    278         return this._allProperties;
    279     },
    280 
    281     getLiveProperty: function(name)
    282     {
    283         return this._livePropertyMap[name];
    284     },
    285 
    286     getPropertyValue: function(name)
    287     {
    288         var property = this._livePropertyMap[name];
    289         return property ? property.value : "";
    290     },
    291 
    292     getPropertyPriority: function(name)
    293     {
    294         var property = this._livePropertyMap[name];
    295         return property ? property.priority : "";
    296     },
    297 
    298     getPropertyShorthand: function(name)
    299     {
    300         var property = this._livePropertyMap[name];
    301         return property ? property.shorthand : "";
    302     },
    303 
    304     isPropertyImplicit: function(name)
    305     {
    306         var property = this._livePropertyMap[name];
    307         return property ? property.implicit : "";
    308     },
    309 
    310     styleTextWithShorthands: function()
    311     {
    312         var cssText = "";
    313         var foundProperties = {};
    314         for (var i = 0; i < this.length; ++i) {
    315             var individualProperty = this[i];
    316             var shorthandProperty = this.getPropertyShorthand(individualProperty);
    317             var propertyName = (shorthandProperty || individualProperty);
    318 
    319             if (propertyName in foundProperties)
    320                 continue;
    321 
    322             if (shorthandProperty) {
    323                 var value = this.getShorthandValue(shorthandProperty);
    324                 var priority = this.getShorthandPriority(shorthandProperty);
    325             } else {
    326                 var value = this.getPropertyValue(individualProperty);
    327                 var priority = this.getPropertyPriority(individualProperty);
    328             }
    329 
    330             foundProperties[propertyName] = true;
    331 
    332             cssText += propertyName + ": " + value;
    333             if (priority)
    334                 cssText += " !" + priority;
    335             cssText += "; ";
    336         }
    337 
    338         return cssText;
    339     },
    340 
    341     getLonghandProperties: function(name)
    342     {
    343         return this._longhandProperties[name] || [];
    344     },
    345 
    346     getShorthandValue: function(shorthandProperty)
    347     {
    348         var property = this.getLiveProperty(shorthandProperty);
    349         return property ? property.value : this._shorthandValues[shorthandProperty];
    350     },
    351 
    352     getShorthandPriority: function(shorthandProperty)
    353     {
    354         var priority = this.getPropertyPriority(shorthandProperty);
    355         if (priority)
    356             return priority;
    357 
    358         var longhands = this._longhandProperties[shorthandProperty];
    359         return longhands ? this.getPropertyPriority(longhands[0]) : null;
    360     },
    361 
    362     propertyAt: function(index)
    363     {
    364         return (index < this.allProperties.length) ? this.allProperties[index] : null;
    365     },
    366 
    367     pastLastSourcePropertyIndex: function()
    368     {
    369         for (var i = this.allProperties.length - 1; i >= 0; --i) {
    370             var property = this.allProperties[i];
    371             if (property.active || property.disabled)
    372                 return i + 1;
    373         }
    374         return 0;
    375     },
    376 
    377     newBlankProperty: function()
    378     {
    379         return new WebInspector.CSSProperty(this, this.pastLastSourcePropertyIndex(), "", "", "", "active", true, false, false, "");
    380     },
    381 
    382     insertPropertyAt: function(index, name, value, userCallback)
    383     {
    384         function callback(userCallback, error, payload)
    385         {
    386             if (!userCallback)
    387                 return;
    388 
    389             if (error) {
    390                 console.error(JSON.stringify(error));
    391                 userCallback(null);
    392             } else {
    393                 userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload));
    394                 WebInspector.cssModel._fireStyleSheetChanged(this.id.styleSheetId, true);
    395             }
    396         }
    397 
    398         CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback));
    399     },
    400 
    401     appendProperty: function(name, value, userCallback)
    402     {
    403         this.insertPropertyAt(this.allProperties.length, name, value, userCallback);
    404     }
    405 }
    406 
    407 WebInspector.CSSRule = function(payload)
    408 {
    409     this.id = payload.ruleId;
    410     this.selectorText = payload.selectorText;
    411     this.sourceLine = payload.sourceLine;
    412     this.sourceURL = payload.sourceURL;
    413     this.origin = payload.origin;
    414     this.style = WebInspector.CSSStyleDeclaration.parsePayload(payload.style);
    415     this.style.parentRule = this;
    416     this.selectorRange = payload.selectorRange;
    417 }
    418 
    419 WebInspector.CSSRule.parsePayload = function(payload)
    420 {
    421     return new WebInspector.CSSRule(payload);
    422 }
    423 
    424 WebInspector.CSSRule.prototype = {
    425     get isUserAgent()
    426     {
    427         return this.origin === "user-agent";
    428     },
    429 
    430     get isUser()
    431     {
    432         return this.origin === "user";
    433     },
    434 
    435     get isViaInspector()
    436     {
    437         return this.origin === "inspector";
    438     },
    439 
    440     get isRegular()
    441     {
    442         return this.origin === "";
    443     }
    444 }
    445 
    446 WebInspector.CSSProperty = function(ownerStyle, index, name, value, priority, status, parsedOk, implicit, shorthand, text)
    447 {
    448     this.ownerStyle = ownerStyle;
    449     this.index = index;
    450     this.name = name;
    451     this.value = value;
    452     this.priority = priority;
    453     this.status = status;
    454     this.parsedOk = parsedOk;
    455     this.implicit = implicit;
    456     this.shorthand = shorthand;
    457     this.text = text;
    458 }
    459 
    460 WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload)
    461 {
    462     // The following default field values are used in the payload:
    463     // priority: ""
    464     // parsedOk: true
    465     // implicit: false
    466     // status: "style"
    467     // shorthandName: ""
    468     var result = new WebInspector.CSSProperty(
    469         ownerStyle, index, payload.name, payload.value, payload.priority || "", payload.status || "style", ("parsedOk" in payload) ? payload.parsedOk : true, !!payload.implicit, payload.shorthandName || "", payload.text);
    470     return result;
    471 }
    472 
    473 WebInspector.CSSProperty.prototype = {
    474     get propertyText()
    475     {
    476         if (this.text !== undefined)
    477             return this.text;
    478 
    479         if (this.name === "")
    480             return "";
    481         return this.name + ": " + this.value + (this.priority ? " !" + this.priority : "") + ";";
    482     },
    483 
    484     get isLive()
    485     {
    486         return this.active || this.styleBased;
    487     },
    488 
    489     get active()
    490     {
    491         return this.status === "active";
    492     },
    493 
    494     get styleBased()
    495     {
    496         return this.status === "style";
    497     },
    498 
    499     get inactive()
    500     {
    501         return this.status === "inactive";
    502     },
    503 
    504     get disabled()
    505     {
    506         return this.status === "disabled";
    507     },
    508 
    509     // Replaces "propertyName: propertyValue [!important];" in the stylesheet by an arbitrary propertyText.
    510     setText: function(propertyText, majorChange, userCallback)
    511     {
    512         function enabledCallback(style)
    513         {
    514             if (style)
    515                 WebInspector.cssModel._fireStyleSheetChanged(style.id.styleSheetId, majorChange);
    516             if (userCallback)
    517                 userCallback(style);
    518         }
    519 
    520         function callback(error, stylePayload)
    521         {
    522             if (!error) {
    523                 this.text = propertyText;
    524                 var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
    525                 var newProperty = style.allProperties[this.index];
    526 
    527                 if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) {
    528                     newProperty.setDisabled(false, enabledCallback);
    529                     return;
    530                 }
    531 
    532                 WebInspector.cssModel._fireStyleSheetChanged(style.id.styleSheetId, majorChange, userCallback.bind(this, style));
    533             } else {
    534                 console.error(JSON.stringify(error));
    535                 if (userCallback)
    536                     userCallback(null);
    537             }
    538         }
    539 
    540         if (!this.ownerStyle)
    541             throw "No ownerStyle for property";
    542 
    543         // An index past all the properties adds a new property to the style.
    544         CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this));
    545     },
    546 
    547     setValue: function(newValue, userCallback)
    548     {
    549         var text = this.name + ": " + newValue + (this.priority ? " !" + this.priority : "") + ";"
    550         this.setText(text, userCallback);
    551     },
    552 
    553     setDisabled: function(disabled, userCallback)
    554     {
    555         if (!this.ownerStyle && userCallback)
    556             userCallback(null);
    557         if (disabled === this.disabled && userCallback)
    558             userCallback(this.ownerStyle);
    559 
    560         function callback(error, stylePayload)
    561         {
    562             if (!userCallback)
    563                 return;
    564             if (error)
    565                 userCallback(null);
    566             else {
    567                 var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
    568                 userCallback(style);
    569                 WebInspector.cssModel._fireStyleSheetChanged(this.ownerStyle.id.styleSheetId, false);
    570             }
    571         }
    572 
    573         CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this));
    574     }
    575 }
    576 
    577 WebInspector.CSSStyleSheet = function(payload)
    578 {
    579     this.id = payload.styleSheetId;
    580     this.rules = [];
    581     this.styles = {};
    582     for (var i = 0; i < payload.rules.length; ++i) {
    583         var rule = WebInspector.CSSRule.parsePayload(payload.rules[i]);
    584         this.rules.push(rule);
    585         if (rule.style)
    586             this.styles[rule.style.id] = rule.style;
    587     }
    588     if ("text" in payload)
    589         this._text = payload.text;
    590 }
    591 
    592 WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback)
    593 {
    594     function callback(error, styleSheetPayload)
    595     {
    596         if (error)
    597             userCallback(null);
    598         else
    599             userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload));
    600     }
    601     CSSAgent.getStyleSheet(styleSheetId, callback.bind(this));
    602 }
    603 
    604 WebInspector.CSSStyleSheet.prototype = {
    605     getText: function()
    606     {
    607         return this._text;
    608     },
    609 
    610     setText: function(newText, majorChange, userCallback)
    611     {
    612         function callback(error)
    613         {
    614              if (userCallback)
    615                  userCallback(error);
    616              if (!error)
    617                  WebInspector.cssModel._fireStyleSheetChanged(this.id, majorChange);
    618         }
    619 
    620         CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this));
    621     }
    622 }
    623 
    624 WebInspector.CSSStyleModelResourceBinding = function(cssModel)
    625 {
    626     this._cssModel = cssModel;
    627     this._urlToStyleSheetId = {};
    628     this._styleSheetIdToURL = {};
    629     this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._styleSheetChanged, this);
    630     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
    631     WebInspector.Resource.registerDomainModelBinding(WebInspector.Resource.Type.Stylesheet, this);
    632 }
    633 
    634 WebInspector.CSSStyleModelResourceBinding.prototype = {
    635     setContent: function(resource, content, majorChange, userCallback)
    636     {
    637         if (this._urlToStyleSheetId[resource.url]) {
    638             this._innerSetContent(resource.url, content, majorChange, userCallback);
    639             return;
    640         }
    641         this._loadStyleSheetHeaders(this._innerSetContent.bind(this, resource.url, content, majorChange, userCallback));
    642     },
    643 
    644     _frameNavigated: function(event)
    645     {
    646         var frameId = event.data;
    647         if (!frameId) {
    648             // Main frame navigation - clear history.
    649             this._urlToStyleSheetId = {};
    650             this._styleSheetIdToURL = {};
    651         }
    652     },
    653 
    654     _innerSetContent: function(url, content, majorChange, userCallback, error)
    655     {
    656         if (error) {
    657             userCallback(error);
    658             return;
    659         }
    660 
    661         var styleSheetId = this._urlToStyleSheetId[url];
    662         if (!styleSheetId) {
    663             if (userCallback)
    664                 userCallback("No stylesheet found: " + url);
    665             return;
    666         }
    667         this._cssModel.setStyleSheetText(styleSheetId, content, majorChange, userCallback);
    668     },
    669 
    670     _loadStyleSheetHeaders: function(callback)
    671     {
    672         function didGetAllStyleSheets(error, infos)
    673         {
    674             if (error) {
    675                 callback(error);
    676                 return;
    677             }
    678 
    679             for (var i = 0; i < infos.length; ++i) {
    680                 var info = infos[i];
    681                 this._urlToStyleSheetId[info.sourceURL] = info.styleSheetId;
    682                 this._styleSheetIdToURL[info.styleSheetId] = info.sourceURL;
    683             }
    684             callback();
    685         }
    686         CSSAgent.getAllStyleSheets(didGetAllStyleSheets.bind(this));
    687     },
    688 
    689     _styleSheetChanged: function(event)
    690     {
    691         var styleSheetId = event.data.styleSheetId;
    692         function setContent()
    693         {
    694             var url = this._styleSheetIdToURL[styleSheetId];
    695             if (!url)
    696                 return;
    697 
    698             var resource = WebInspector.resourceForURL(url);
    699             if (!resource)
    700                 return;
    701 
    702             var majorChange = event.data.majorChange;
    703             if (majorChange)
    704                 resource.addRevision(event.data.content);
    705         }
    706 
    707         if (!this._styleSheetIdToURL[styleSheetId]) {
    708             this._loadStyleSheetHeaders(setContent.bind(this));
    709             return;
    710         }
    711         setContent.call(this);
    712     }
    713 }
    714 
    715 WebInspector.CSSStyleModelResourceBinding.prototype.__proto__ = WebInspector.ResourceDomainModelBinding.prototype;
    716