Class: Dommy::CSSStyleSheet

Inherits:
Object
  • Object
show all
Includes:
Bridge::Methods
Defined in:
lib/dommy/css.rb

Overview

CSSStyleSheet — the sheet itself doesn't interpret rule text; it acts as an ordered list of opaque CSSRule-like wrappers. The cascade consumes the sheet through cascade_text (all rule texts in document order), so insertRule/deleteRule/replaceSync and disabled are reflected in computed styles for <style>-owned sheets (Internal::CSS::RuleIndex re-parses on the next lookup).

sheet.insertRule("p { color: red }", 0);
for (const r of sheet.cssRules) console.log(r.cssText);

href, media, title, type mirror the owner node's attributes when present.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Bridge::Methods

included

Constructor Details

#initialize(owner_node:, href: nil, media: nil, title: nil, type: "text/css", source_text: nil) ⇒ CSSStyleSheet

Returns a new instance of CSSStyleSheet.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/dommy/css.rb', line 21

def initialize(owner_node:, href: nil, media: nil, title: nil, type: "text/css", source_text: nil)
  @owner_node = owner_node
  @href = href
  @media = media
  @title = title
  @type = type
  @disabled = false
  @css_rules = CSSRuleList.new
  # The owner node's CSS text at sheet creation, split into one CSSRule
  # per top-level rule (source order) so cssRules mirrors the parsed
  # sheet — selectorText / style / nested cssRules read off each slice.
  # insertRule(0) lands before them, appends after, as a real sheet would.
  Internal::CSSRuleText.split_rules(source_text).each_with_index do |slice, i|
    @css_rules.__internal_insert__(i, CSSRule.new(slice, self))
  end
end

Instance Attribute Details

#css_rulesObject (readonly)

Returns the value of attribute css_rules.



19
20
21
# File 'lib/dommy/css.rb', line 19

def css_rules
  @css_rules
end

#owner_nodeObject (readonly)

Returns the value of attribute owner_node.



19
20
21
# File 'lib/dommy/css.rb', line 19

def owner_node
  @owner_node
end

Instance Method Details

#__internal_notify_rule_changed__Object

A child CSSRule whose text changed (e.g. rule.style.color = ...) invalidates the owner document's computed style the same way insertRule/deleteRule do — its rebuilt cssText feeds cascade_text.



199
200
201
# File 'lib/dommy/css.rb', line 199

def __internal_notify_rule_changed__
  __internal_bump_owner_style_generation__
end

#__js_call__(method, args) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/dommy/css.rb', line 179

def __js_call__(method, args)
  case method
  when "insertRule"
    insert_rule(args[0], args[1])
  when "deleteRule"
    delete_rule(args[0])
  when "addRule"
    add_rule(args[0], args[1], args[2])
  when "removeRule"
    remove_rule(args[0])
  when "replaceSync"
    replace_sync(args[0])
  when "replace"
    replace(args[0])
  end
end

#__js_get__(key) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/dommy/css.rb', line 141

def __js_get__(key)
  case key
  when "cssRules", "rules"
    @css_rules
  when "disabled"
    @disabled
  when "href"
    @href
  when "media"
    media
  when "title"
    @title
  when "type"
    @type
  when "ownerNode"
    @owner_node
  when "parentStyleSheet"
    parent_style_sheet
  when "ownerRule"
    owner_rule
  else
    Bridge::ABSENT
  end
end

#__js_set__(key, value) ⇒ Object



166
167
168
169
170
171
172
173
174
175
# File 'lib/dommy/css.rb', line 166

def __js_set__(key, value)
  case key
  when "disabled"
    self.disabled = value
  else
    return Bridge::UNHANDLED
  end

  nil
end

#add_rule(selector = nil, style = nil, index = nil) ⇒ Object

addRule(selector, style, index) — the legacy IE-era editing API (still in CSSOM). Builds selector { style }, inserts it (default: at the end), and returns -1. Omitted selector/style stringify to "undefined", matching the spec's coercion.



110
111
112
113
114
115
116
# File 'lib/dommy/css.rb', line 110

def add_rule(selector = nil, style = nil, index = nil)
  selector = selector.nil? ? "undefined" : selector.to_s
  style = style.nil? ? "undefined" : style.to_s
  idx = index.nil? ? @css_rules.length : index.to_i
  insert_rule("#{selector} { #{style} }", idx)
  -1
end

#cascade_textObject

The sheet's full CSS text in document order — what the cascade parses in place of the owner <style>'s raw text once the sheet has been mutated through the CSSOM.



53
54
55
# File 'lib/dommy/css.rb', line 53

def cascade_text
  @css_rules.map(&:css_text).join("\n")
end

#delete_rule(index) ⇒ Object

deleteRule(index)index is required.

Raises:



95
96
97
98
99
100
101
102
103
104
# File 'lib/dommy/css.rb', line 95

def delete_rule(index)
  raise Bridge::TypeError, "deleteRule requires an index" if index.nil?

  idx = index.to_i
  raise DOMException::IndexSizeError, "out of range" if idx < 0 || idx >= @css_rules.length

  @css_rules.__internal_delete_at__(idx)
  __internal_bump_owner_style_generation__
  nil
end

#disabledObject



38
39
40
# File 'lib/dommy/css.rb', line 38

def disabled
  @disabled
end

#disabled=(v) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/dommy/css.rb', line 42

def disabled=(v)
  v = !!v
  changed = @disabled != v
  @disabled = v
  __internal_bump_owner_style_generation__ if changed
  v
end

#hrefObject



57
58
59
# File 'lib/dommy/css.rb', line 57

def href
  @href
end

#insert_rule(rule_text, index = nil) ⇒ Object

insertRule(rule, index)rule is required; inserts a CSSRule at the given position (Dommy defaults to the end). Returns the index used.

Raises:



83
84
85
86
87
88
89
90
91
92
# File 'lib/dommy/css.rb', line 83

def insert_rule(rule_text, index = nil)
  raise Bridge::TypeError, "insertRule requires a rule" if rule_text.nil?

  idx = index.nil? ? @css_rules.length : index.to_i
  raise DOMException::IndexSizeError, "out of range" if idx < 0 || idx > @css_rules.length

  @css_rules.__internal_insert__(idx, CSSRule.new(rule_text.to_s, self))
  __internal_bump_owner_style_generation__
  idx
end

#mediaObject



69
70
71
# File 'lib/dommy/css.rb', line 69

def media
  @media.to_s
end

#owner_ruleObject



77
78
79
# File 'lib/dommy/css.rb', line 77

def owner_rule
  nil
end

#parent_style_sheetObject



73
74
75
# File 'lib/dommy/css.rb', line 73

def parent_style_sheet
  nil
end

#remove_rule(index = 0) ⇒ Object

removeRule(index = 0) — the legacy alias for deleteRule (its index defaults to 0, unlike deleteRule's required argument).



120
121
122
# File 'lib/dommy/css.rb', line 120

def remove_rule(index = 0)
  delete_rule(index.nil? ? 0 : index)
end

#replace(text) ⇒ Object

replace(text) — spec returns a Promise resolved with self. We can't return a JS-bridge Promise from here without a Window, so we mirror the sync behavior and return self.



136
137
138
139
# File 'lib/dommy/css.rb', line 136

def replace(text)
  replace_sync(text)
  self
end

#replace_sync(text) ⇒ Object

replaceSync(text) — replace all rules with a single rule blob (no parsing — we keep it as one opaque entry).



126
127
128
129
130
131
# File 'lib/dommy/css.rb', line 126

def replace_sync(text)
  @css_rules.__internal_clear__
  @css_rules.__internal_insert__(0, CSSRule.new(text.to_s, self)) unless text.to_s.empty?
  __internal_bump_owner_style_generation__
  nil
end

#titleObject



61
62
63
# File 'lib/dommy/css.rb', line 61

def title
  @title
end

#typeObject



65
66
67
# File 'lib/dommy/css.rb', line 65

def type
  @type
end