From 76b9982e04ef436549b442a40703f88e68e4c604 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 5 May 2014 18:54:22 -0600 Subject: [PATCH] Emit stylesheet-added/removed from ThemeManager w/ CSSStyleSheet objects This enables subscribers to detect not just that stylesheets have changed, but specifically how they have changed. This is used by the React editor component to only refresh scrollbars when a stylesheet that actually contains selectors for scrollbar elements is added or removed. --- spec/theme-manager-spec.coffee | 37 +++++++++++++++++++++++++++++----- src/theme-manager.coffee | 24 ++++++++++++++-------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 1eaaf0a0b..831b34ee6 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -131,15 +131,21 @@ describe "ThemeManager", -> describe "requireStylesheet(path)", -> it "synchronously loads css at the given path and installs a style tag for it in the head", -> + themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler") + themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler") cssPath = atom.project.resolve('css.css') lengthBefore = $('head style').length themeManager.requireStylesheet(cssPath) expect($('head style').length).toBe lengthBefore + 1 + expect(stylesheetAddedHandler).toHaveBeenCalled() + expect(stylesheetsChangedHandler).toHaveBeenCalled() + element = $('head style[id*="css.css"]') expect(element.attr('id')).toBe themeManager.stringToId(cssPath) expect(element.text()).toBe fs.readFileSync(cssPath, 'utf8') + expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0] # doesn't append twice themeManager.requireStylesheet(cssPath) @@ -187,9 +193,18 @@ describe "ThemeManager", -> themeManager.requireStylesheet(cssPath) expect($(document.body).css('font-weight')).toBe("bold") + themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler") themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler") + themeManager.removeStylesheet(cssPath) + expect($(document.body).css('font-weight')).not.toBe("bold") + + expect(stylesheetRemovedHandler).toHaveBeenCalled() + stylesheet = stylesheetRemovedHandler.argsForCall[0][0] + expect(stylesheet instanceof CSSStyleSheet).toBe true + expect(stylesheet.cssRules[0].selectorText).toBe 'body' + expect(stylesheetsChangedHandler).toHaveBeenCalled() describe "base stylesheet loading", -> @@ -219,20 +234,21 @@ describe "ThemeManager", -> describe "when the user stylesheet changes", -> it "reloads it", -> + [stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = [] userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less') fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}') - spyOn(themeManager, 'getUserStylesheetPath').andReturn userStylesheetPath - themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler") waitsForPromise -> themeManager.activateThemes() runs -> - expect($(document.body).css('border-style')).toBe 'dotted' - expect(stylesheetsChangedHandler).toHaveBeenCalled() - stylesheetsChangedHandler.reset() + themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler") + themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler") + themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler") spyOn(themeManager, 'loadUserStylesheet').andCallThrough() + + expect($(document.body).css('border-style')).toBe 'dotted' fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}') waitsFor -> @@ -240,7 +256,16 @@ describe "ThemeManager", -> runs -> expect($(document.body).css('border-style')).toBe 'dashed' + + expect(stylesheetRemovedHandler).toHaveBeenCalled() + expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted' + + expect(stylesheetAddedHandler).toHaveBeenCalled() + expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed' + expect(stylesheetsChangedHandler).toHaveBeenCalled() + + stylesheetRemovedHandler.reset() stylesheetsChangedHandler.reset() fs.removeSync(userStylesheetPath) @@ -248,6 +273,8 @@ describe "ThemeManager", -> themeManager.loadUserStylesheet.callCount is 2 runs -> + expect(stylesheetRemovedHandler).toHaveBeenCalled() + expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed' expect($(document.body).css('border-style')).toBe 'none' expect(stylesheetsChangedHandler).toHaveBeenCalled() diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 3570bef69..6ec9bd282 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -158,10 +158,10 @@ class ThemeManager # load path. # # Returns the absolute path to the required stylesheet. - requireStylesheet: (stylesheetPath, ttype = 'bundled', htmlElement) -> + requireStylesheet: (stylesheetPath, type = 'bundled', htmlElement) -> if fullPath = @resolveStylesheet(stylesheetPath) content = @loadStylesheet(fullPath) - @applyStylesheet(fullPath, content, ttype = 'bundled', htmlElement) + @applyStylesheet(fullPath, content, type = 'bundled', htmlElement) else throw new Error("Could not find a file at path '#{stylesheetPath}'") @@ -192,16 +192,24 @@ class ThemeManager removeStylesheet: (stylesheetPath) -> fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath - @stylesheetElementForId(@stringToId(fullPath)).remove() - @emit 'stylesheets-changed' + element = @stylesheetElementForId(@stringToId(fullPath)) + if element.length > 0 + stylesheet = element[0].sheet + element.remove() + @emit 'stylesheet-removed', stylesheet + @emit 'stylesheets-changed' - applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) -> + applyStylesheet: (path, text, type = 'bundled', htmlElement=$('html')) -> styleElement = @stylesheetElementForId(@stringToId(path), htmlElement) if styleElement.length + @emit 'stylesheet-removed', styleElement[0].sheet styleElement.text(text) else - if htmlElement.find("head style.#{ttype}").length - htmlElement.find("head style.#{ttype}:last").after "" + styleElement = $("") + if htmlElement.find("head style.#{type}").length + htmlElement.find("head style.#{type}:last").after(styleElement) else - htmlElement.find("head").append "" + htmlElement.find("head").append(styleElement) + + @emit 'stylesheet-added', styleElement[0].sheet @emit 'stylesheets-changed'