Class: Dommy::CSSRule

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

Overview

CSSRule — one parsed stylesheet rule. cssText round-trips the source slice verbatim until the rule is mutated. The CSSOM subclass hierarchy (CSSStyleRule / CSSMediaRule / …) is collapsed into this one class, which exposes the accessors per type: selectorText + style for style rules, conditionText + cssRules for grouping rules (@media/@supports). The selector text and declaration block are derived lazily with Internal::CSSRuleText (a light scanner; the cascade's correctness still comes from lexbor).

Constant Summary collapse

STYLE_RULE =
1
CHARSET_RULE =
2
IMPORT_RULE =
3
MEDIA_RULE =
4
FONT_FACE_RULE =
5
PAGE_RULE =
6
KEYFRAMES_RULE =
7
KEYFRAME_RULE =
8
SUPPORTS_RULE =
12
AT_RULE_TYPES =
{
  "media" => MEDIA_RULE, "supports" => SUPPORTS_RULE, "import" => IMPORT_RULE,
  "charset" => CHARSET_RULE, "font-face" => FONT_FACE_RULE, "page" => PAGE_RULE,
  "keyframes" => KEYFRAMES_RULE
}.freeze
GROUPING_TYPES =
[MEDIA_RULE, SUPPORTS_RULE].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(css_text, parent_style_sheet = nil) ⇒ CSSRule

Returns a new instance of CSSRule.



456
457
458
459
# File 'lib/dommy/css.rb', line 456

def initialize(css_text, parent_style_sheet = nil)
  @css_text = css_text.to_s
  @parent_style_sheet = parent_style_sheet
end

Instance Attribute Details

#parent_style_sheetObject (readonly)

Returns the value of attribute parent_style_sheet.



454
455
456
# File 'lib/dommy/css.rb', line 454

def parent_style_sheet
  @parent_style_sheet
end

Instance Method Details

#__internal_rebuild_from_style__(block_text) ⇒ Object

Called by RuleStyleDeclaration after a property write: rebuild cssText from the (possibly new) selector and declaration block.



537
538
539
540
541
542
# File 'lib/dommy/css.rb', line 537

def __internal_rebuild_from_style__(block_text)
  @selector ||= prelude
  @css_text = block_text.empty? ? "#{@selector} {}" : "#{@selector} { #{block_text} }"
  @parent_style_sheet&.__internal_notify_rule_changed__
  nil
end

#__internal_set_media__(media_text) ⇒ Object

Called by the MediaList when its media text changes: rebuild the @media prelude (keeping the block body) and reflow the cascade.



546
547
548
549
550
551
552
# File 'lib/dommy/css.rb', line 546

def __internal_set_media__(media_text)
  @css_text = "@media #{media_text} { #{body} }"
  @prelude = nil
  @media_list = nil
  @parent_style_sheet&.__internal_notify_rule_changed__
  nil
end

#__js_get__(key) ⇒ Object



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
# File 'lib/dommy/css.rb', line 554

def __js_get__(key)
  case key
  when "cssText" then @css_text
  when "type" then type
  when "selectorText" then selector_text
  when "style" then style
  when "cssRules" then css_rules
  when "conditionText" then grouping? ? condition_text : nil
  when "media" then media
  when "parentStyleSheet" then @parent_style_sheet
  when "parentRule" then parent_rule
  when "STYLE_RULE" then STYLE_RULE
  when "MEDIA_RULE" then MEDIA_RULE
  when "IMPORT_RULE" then IMPORT_RULE
  when "FONT_FACE_RULE" then FONT_FACE_RULE
  when "PAGE_RULE" then PAGE_RULE
  when "KEYFRAMES_RULE" then KEYFRAMES_RULE
  when "KEYFRAME_RULE" then KEYFRAME_RULE
  when "SUPPORTS_RULE" then SUPPORTS_RULE
  when "CHARSET_RULE" then CHARSET_RULE
  else
    Bridge::ABSENT
  end
end

#__js_set__(key, value) ⇒ Object



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
# File 'lib/dommy/css.rb', line 579

def __js_set__(key, value)
  case key
  when "cssText" then self.css_text = value
  when "selectorText" then self.selector_text = value
  when "media"
    # CSSMediaRule#media is settable with a media-text string.
    __internal_set_media__(value.to_s) if type == MEDIA_RULE
  else
    # Signal "not a host property" so the bridge keeps the assignment as a
    # JS-side expando (WebIDL platform objects allow expandos; WPT's
    # [SameObject] tests stash a marker on cssRules[i] and read it back).
    return Bridge::UNHANDLED
  end

  nil
end

#condition_textObject

CSSConditionRule#conditionText — the condition text after the at-keyword.



518
519
520
# File 'lib/dommy/css.rb', line 518

def condition_text
  grouping? ? prelude.sub(/\A@[-a-z]+/i, "").strip : ""
end

#css_rulesObject

CSSGroupingRule#cssRules — the nested rules of an @media/@supports block.



505
506
507
508
509
510
511
512
513
514
515
# File 'lib/dommy/css.rb', line 505

def css_rules
  return nil unless grouping?

  @css_rules ||= begin
    list = CSSRuleList.new
    Internal::CSSRuleText.split_rules(body).each_with_index do |slice, i|
      list.__internal_insert__(i, CSSRule.new(slice, @parent_style_sheet))
    end
    list
  end
end

#css_textObject



461
462
463
# File 'lib/dommy/css.rb', line 461

def css_text
  @css_text
end

#css_text=(v) ⇒ Object



465
466
467
468
# File 'lib/dommy/css.rb', line 465

def css_text=(v)
  @css_text = v.to_s
  invalidate!
end

#grouping?Boolean

Returns:

  • (Boolean)


479
480
481
# File 'lib/dommy/css.rb', line 479

def grouping?
  GROUPING_TYPES.include?(type)
end

#mediaObject

CSSMediaRule#media — a live MediaList over the @media condition. nil for non-media rules. Mutations rebuild the rule's prelude and reflow the cascade.



525
526
527
528
529
# File 'lib/dommy/css.rb', line 525

def media
  return nil unless type == MEDIA_RULE

  @media_list ||= MediaList.new(condition_text, on_change: method(:__internal_set_media__))
end

#parent_ruleObject



531
532
533
# File 'lib/dommy/css.rb', line 531

def parent_rule
  nil
end

#selector_textObject

CSSStyleRule#selectorText — the rule's selector list ("" for at-rules).



484
485
486
# File 'lib/dommy/css.rb', line 484

def selector_text
  style_rule? ? prelude : ""
end

#selector_text=(value) ⇒ Object



488
489
490
491
492
493
# File 'lib/dommy/css.rb', line 488

def selector_text=(value)
  return unless style_rule?

  @selector = value.to_s
  rebuild_css_text!
end

#styleObject

CSSStyleRule#style — a live, mutable declaration block. nil for at-rules (matching the absent style member on CSSMediaRule etc.). Writes reserialize cssText and invalidate the document's computed-style cache.



498
499
500
501
502
# File 'lib/dommy/css.rb', line 498

def style
  return nil unless style_rule?

  @style ||= RuleStyleDeclaration.new(self, Internal::CSSRuleText.split_rule(@css_text).last)
end

#style_rule?Boolean

Returns:

  • (Boolean)


475
476
477
# File 'lib/dommy/css.rb', line 475

def style_rule?
  type == STYLE_RULE
end

#typeObject



470
471
472
473
# File 'lib/dommy/css.rb', line 470

def type
  keyword = Internal::CSSRuleText.at_keyword(prelude)
  keyword ? AT_RULE_TYPES.fetch(keyword, STYLE_RULE) : STYLE_RULE
end