1/*
2 * Copyright (C) 2013 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26WebInspector.CSSRule = function(nodeStyles, ownerStyleSheet, id, type, sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList)
27{
28    WebInspector.Object.call(this);
29
30    console.assert(nodeStyles);
31    this._nodeStyles = nodeStyles;
32
33    this._ownerStyleSheet = ownerStyleSheet || null;
34    this._id = id || null;
35    this._type = type || null;
36
37    this.update(sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList, true);
38};
39
40WebInspector.Object.addConstructorFunctions(WebInspector.CSSRule);
41
42WebInspector.CSSRule.Event = {
43    Changed: "css-rule-changed"
44};
45
46WebInspector.CSSRule.Type = {
47    Author: "css-rule-type-author",
48    User: "css-rule-type-user",
49    UserAgent: "css-rule-type-user-agent",
50    Inspector: "css-rule-type-inspector"
51};
52
53WebInspector.CSSRule.prototype = {
54    constructor: WebInspector.CSSRule,
55
56    // Public
57
58    get id()
59    {
60        return this._id;
61    },
62
63    get ownerStyleSheet()
64    {
65        return this._ownerStyleSheet;
66    },
67
68    get editable()
69    {
70        return !!this._id && (this._type === WebInspector.CSSRule.Type.Author || this._type === WebInspector.CSSRule.Type.Inspector);
71    },
72
73    update: function(sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList, dontFireEvents)
74    {
75        sourceCodeLocation = sourceCodeLocation || null;
76        selectorText = selectorText || "";
77        selectors = selectors || [];
78        matchedSelectorIndices = matchedSelectorIndices || [];
79        style = style || null;
80        mediaList = mediaList || [];
81
82        var changed = false;
83        if (!dontFireEvents) {
84            changed = this._selectorText !== selectorText || !Object.shallowEqual(this._selectors, selectors) ||
85                !Object.shallowEqual(this._matchedSelectorIndices, matchedSelectorIndices) || this._style !== style ||
86                !!this._sourceCodeLocation !== !!sourceCodeLocation || this._mediaList.length !== mediaList.length;
87            // FIXME: Look for differences in the media list arrays.
88        }
89
90        if (this._style)
91            this._style.ownerRule = null;
92
93        this._sourceCodeLocation = sourceCodeLocation;
94        this._selectorText = selectorText;
95        this._selectors = selectors;
96        this._matchedSelectorIndices = matchedSelectorIndices;
97        this._style = style;
98        this._mediaList = mediaList;
99
100        delete this._matchedSelectors;
101        delete this._matchedSelectorText;
102
103        if (this._style)
104            this._style.ownerRule = this;
105
106        if (changed)
107            this.dispatchEventToListeners(WebInspector.CSSRule.Event.Changed);
108    },
109
110    get type()
111    {
112        return this._type;
113    },
114
115    get sourceCodeLocation()
116    {
117        return this._sourceCodeLocation;
118    },
119
120    get selectorText()
121    {
122        return this._selectorText;
123    },
124
125    set selectorText(selectorText)
126    {
127        console.assert(this.editable);
128        if (!this.editable)
129            return;
130
131        if (this._selectorText === selectorText)
132            return;
133
134        this._nodeStyles.changeRuleSelector(this, selectorText);
135    },
136
137    get selectors()
138    {
139        return this._selectors;
140    },
141
142    set selectors(selectors)
143    {
144        this.selectorText = (selectors || []).join(", ");
145    },
146
147    get matchedSelectorIndices()
148    {
149        return this._matchedSelectorIndices;
150    },
151
152    get matchedSelectors()
153    {
154        // COMPATIBILITY (iOS 6): The selectors array is always empty, so just return an empty array.
155        if (!this._selectors.length) {
156            console.assert(!this._matchedSelectorIndices.length);
157            return [];
158        }
159
160        if (this._matchedSelectors)
161            return this._matchedSelectors;
162
163        this._matchedSelectors = this._selectors.filter(function(element, index) {
164            return this._matchedSelectorIndices.contains(index);
165        }, this);
166
167        return this._matchedSelectors;
168    },
169
170    get matchedSelectorText()
171    {
172        // COMPATIBILITY (iOS 6): The selectors array is always empty, so just return the whole selector.
173        if (!this._selectors.length) {
174            console.assert(!this._matchedSelectorIndices.length);
175            return this._selectorText;
176        }
177
178        if ("_matchedSelectorText" in this)
179            return this._matchedSelectorText;
180
181        this._matchedSelectorText = this.matchedSelectors.join(", ");
182
183        return this._matchedSelectorText;
184    },
185
186    get style()
187    {
188        return this._style;
189    },
190
191    get mediaList()
192    {
193        return this._mediaList;
194    },
195
196    // Protected
197
198    get nodeStyles()
199    {
200        return this._nodeStyles;
201    }
202};
203
204WebInspector.CSSRule.prototype.__proto__ = WebInspector.Object.prototype;
205