TextMateGrammar = require 'text-mate-grammar' Package = require 'package' fsUtils = require 'fs-utils' path = require 'path' _ = require 'underscore' $ = require 'jquery' CSON = require 'season' ### Internal: Loads and resolves packages. ### module.exports = class AtomPackage extends Package metadata: null keymaps: null stylesheets: null grammars: null scopedProperties: null mainModulePath: null resolvedMainModulePath: false mainModule: null load: -> try @metadata = Package.loadMetadata(@path) @loadKeymaps() @loadStylesheets() @loadGrammars() @loadScopedProperties() if @metadata.activationEvents? @registerDeferredDeserializers() else @requireMainModule() catch e console.warn "Failed to load package named '#{@name}'", e.stack ? e this activate: ({immediate}={}) -> @activateResources() if @metadata.activationEvents? and not immediate @subscribeToActivationEvents() else @activateNow() activateNow: -> try if @requireMainModule() config.setDefaults(@name, @mainModule.configDefaults) @mainModule.activate(atom.getPackageState(@name) ? {}) catch e console.warn "Failed to activate package named '#{@name}'", e.stack activateConfig: -> @activateResources() if @requireMainModule() config.setDefaults(@name, @mainModule.configDefaults) @mainModule?.activateConfig?() activateResources: -> keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps applyStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets syntax.addGrammar(grammar) for grammar in @grammars for [propertiesPath, selector, properties] in @scopedProperties syntax.addProperties(propertiesPath, selector, properties) loadKeymaps: -> @keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath)] getKeymapPaths: -> keymapsDirPath = path.join(@path, 'keymaps') if @metadata.keymaps @metadata.keymaps.map (name) -> fsUtils.resolve(keymapsDirPath, name, ['json', 'cson', '']) else fsUtils.list(keymapsDirPath, ['cson', 'json']) loadStylesheets: -> @stylesheets = @getStylesheetPaths().map (stylesheetPath) -> [stylesheetPath, loadStylesheet(stylesheetPath)] getStylesheetPaths: -> stylesheetDirPath = path.join(@path, 'stylesheets') if @metadata.stylesheets @metadata.stylesheets.map (name) -> fsUtils.resolve(stylesheetDirPath, name, ['css', 'less', '']) else fsUtils.list(stylesheetDirPath, ['css', 'less']) loadGrammars: -> @grammars = [] grammarsDirPath = path.join(@path, 'grammars') for grammarPath in fsUtils.list(grammarsDirPath, ['.json', '.cson']) @grammars.push(TextMateGrammar.loadSync(grammarPath)) loadScopedProperties: -> @scopedProperties = [] scopedPropertiessDirPath = path.join(@path, 'scoped-properties') for scopedPropertiesPath in fsUtils.list(scopedPropertiessDirPath, ['.json', '.cson']) for selector, properties of fsUtils.readObject(scopedPropertiesPath) @scopedProperties.push([scopedPropertiesPath, selector, properties]) serialize: -> try @mainModule?.serialize?() catch e console.error "Error serializing package '#{@name}'", e.stack deactivate: -> @unsubscribeFromActivationEvents() @deactivateResources() @mainModule?.deactivate?() deactivateConfig: -> @deactivateResources() @mainModule?.deactivateConfig?() deactivateResources: -> syntax.removeGrammar(grammar) for grammar in @grammars syntax.removeProperties(path) for [path] in @scopedProperties keymap.remove(keymapPath) for [keymapPath] in @keymaps removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets requireMainModule: -> return @mainModule if @mainModule mainModulePath = @getMainModulePath() @mainModule = require(mainModulePath) if fsUtils.isFile(mainModulePath) getMainModulePath: -> return @mainModulePath if @resolvedMainModulePath @resolvedMainModulePath = true mainModulePath = if @metadata.main path.join(@path, @metadata.main) else path.join(@path, 'index') @mainModulePath = fsUtils.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...]) registerDeferredDeserializers: -> for deserializerName in @metadata.deferredDeserializers ? [] registerDeferredDeserializer deserializerName, => @requireMainModule() subscribeToActivationEvents: -> return unless @metadata.activationEvents? if _.isArray(@metadata.activationEvents) rootView.command(event, @handleActivationEvent) for event in @metadata.activationEvents else if _.isString(@metadata.activationEvents) rootView.command(@metadata.activationEvents, @handleActivationEvent) else rootView.command(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents handleActivationEvent: (event) => bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event) @activateNow() $(event.target).trigger(event) @restoreEventHandlersOnBubblePath(bubblePathEventHandlers) @unsubscribeFromActivationEvents() unsubscribeFromActivationEvents: -> if _.isArray(@metadata.activationEvents) rootView.off(event, @handleActivationEvent) for event in @metadata.activationEvents else if _.isString(@metadata.activationEvents) rootView.off(@metadata.activationEvents, @handleActivationEvent) else rootView.off(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents disableEventHandlersOnBubblePath: (event) -> bubblePathEventHandlers = [] disabledHandler = -> element = $(event.target) while element.length if eventHandlers = element.data('events')?[event.type] for eventHandler in eventHandlers eventHandler.disabledHandler = eventHandler.handler eventHandler.handler = disabledHandler bubblePathEventHandlers.push(eventHandler) element = element.parent() bubblePathEventHandlers restoreEventHandlersOnBubblePath: (eventHandlers) -> for eventHandler in eventHandlers eventHandler.handler = eventHandler.disabledHandler delete eventHandler.disabledHandler