From 4e99d003ee7afb1fef5e267e1af1f25d60c139a5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 9 Jan 2014 09:53:14 -0700 Subject: [PATCH] Add Focusable mixin and FocusContext Focusable objects have ::focus and ::blur methods and a ::focused property. Focusable objects can be assigned a ::focusContext, and the ::focused property will only be true for at most one object with the same context. --- spec/focusable-spec.coffee | 36 ++++++++++++++++++++++++++++++++++++ src/focus-context.coffee | 5 +++++ src/focusable.coffee | 18 ++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 spec/focusable-spec.coffee create mode 100644 src/focus-context.coffee create mode 100644 src/focusable.coffee diff --git a/spec/focusable-spec.coffee b/spec/focusable-spec.coffee new file mode 100644 index 000000000..0cb26b908 --- /dev/null +++ b/spec/focusable-spec.coffee @@ -0,0 +1,36 @@ +{Model} = require 'theorist' +Focusable = require '../src/focusable' +FocusContext = require '../src/focus-context' + +describe "Focusable mixin", -> + it "ensures that only a single model is focused for a given focus manager", -> + class Item extends Model + Focusable.includeInto(this) + + focusContext = new FocusContext + item1 = new Item({focusContext}) + item2 = new Item({focusContext}) + item3 = new Item({focusContext}) + + expect(focusContext.focusedObject).toBe null + expect(item1.focused).toBe false + expect(item2.focused).toBe false + expect(item3.focused).toBe false + + item1.focus() + expect(focusContext.focusedObject).toBe item1 + expect(item1.focused).toBe true + expect(item2.focused).toBe false + expect(item3.focused).toBe false + + item2.focus() + expect(focusContext.focusedObject).toBe item2 + expect(item1.focused).toBe false + expect(item2.focused).toBe true + expect(item3.focused).toBe false + + item2.blur() + expect(focusContext.focusedObject).toBe null + expect(item1.focused).toBe false + expect(item2.focused).toBe false + expect(item3.focused).toBe false diff --git a/src/focus-context.coffee b/src/focus-context.coffee new file mode 100644 index 000000000..e52b0487f --- /dev/null +++ b/src/focus-context.coffee @@ -0,0 +1,5 @@ +{Model} = require 'theorist' + +module.exports = +class FocusContext extends Model + @property 'focusedObject', null diff --git a/src/focusable.coffee b/src/focusable.coffee new file mode 100644 index 000000000..6441a74eb --- /dev/null +++ b/src/focusable.coffee @@ -0,0 +1,18 @@ +Mixin = require 'mixto' + +module.exports = +class Focusable extends Mixin + @included: -> + @property 'focusContext' + @behavior 'focused', -> + @$focusContext + .flatMapLatest((context) -> context?.$focusedObject) + .map((focusedObject) => focusedObject is this) + + focus: -> + throw new Error("Object must be assigned a focusContext to be focus") unless @focusContext + @focusContext.focusedObject = this + + blur: -> + throw new Error("Object must be assigned a focusContext to be blurred") unless @focusContext + @focusContext.focusedObject = null if @focused