1 /*
  2  *  Copyright © 2009 Apple Inc. All rights reserved.
  3  */
  4 
  5 TKPositioningController.inherits = TKController;
  6 TKPositioningController.synthetizes = ['positioningViewData'];
  7 
  8 function TKPositioningController (data) {
  9   this.previousButton = null;
 10   this.nextButton = null;
 11   this.movesWithElementHighlight = true;
 12   // set up the positioning view
 13   this.positioningView = new TKPositioningView();
 14   this.positioningView.delegate = this;
 15   this.positioningView.ready = false;
 16   // set up default pointers for arrows
 17   this._previousButton = null;
 18   this._nextButton = null;
 19   //
 20   this.callSuper(data);
 21 };
 22 
 23 TKPositioningController.prototype.processView = function () {
 24   this.callSuper();
 25   // wire up actions if we have a previous and next button wired
 26   if (this.previousButton !== null) {
 27     this._previousButton = this.view.querySelector(this.previousButton);
 28     if (this._previousButton !== null) {
 29       this._previousButton.addEventListener('click', this, false);
 30       this.addNavigableElement(this._previousButton);
 31     }
 32   }
 33   if (this.nextButton !== null) {
 34     this._nextButton = this.view.querySelector(this.nextButton);
 35     if (this._nextButton !== null) {
 36       this._nextButton.addEventListener('click', this, false);
 37       this.addNavigableElement(this._nextButton);
 38     }
 39   }
 40   // ensure our first page gets told about its being highlighted
 41   this.syncPageButtons();
 42   // highlight the first page in case we have no explicit highlighted element
 43   if (this.highlightedElement === null && this.positioningView.ready && this.movesWithElementHighlight) {
 44     this.highlightedElement = this.positioningView._elements[this.positioningView.activeElementIndex];
 45   }
 46 };
 47 
 48 TKPositioningController.prototype.setPositioningViewData = function (data) {
 49   // set up the data source if we have .elements on the data object
 50   if (!TKUtils.objectIsUndefined(data.elements)) {
 51     this.positioningView.dataSource = new TKPositioningViewDataSourceHelper(data.elements);
 52     // FIXME: huh?
 53     //delete data.element;
 54   }
 55   // copy properties
 56   TKUtils.copyPropertiesFromSourceToTarget(data, this.positioningView);
 57   // init our view
 58   this.positioningView.init();
 59   this.syncPageButtons();
 60   //
 61   if (this.movesWithElementHighlight) {
 62     for (var i = 0; i < this.positioningView._elements.length; i++) {
 63       var element = this.positioningView._elements[i];
 64       element.addEventListener('focus', this, false);
 65       this.addNavigableElement(element);
 66     }
 67   }
 68   //
 69   this.positioningView.ready = true;
 70   // add the currently focused element to the list of keyboard elements and highlight it
 71   // if we're not directly a child of the navigation controller
 72   if (this.viewWasProcessed && this.movesWithElementHighlight && this.parentController === TKNavigationController.sharedNavigation) {
 73     TKSpatialNavigationManager.sharedManager.highlightElement(this.positioningView._elements[this.positioningView.activeElementIndex]);
 74   }
 75   //
 76   this._view.appendChild(this.positioningView.element);
 77 };
 78 
 79 TKPositioningController.prototype.syncPageButtons = function () {
 80   if (this._previousButton !== null) {
 81     this._previousButton[(this.positioningView.activeElementIndex <= 0 ? 'add' : 'remove') + 'ClassName']('inactive');
 82   }
 83   if (this._nextButton !== null) {
 84     this._nextButton[(this.positioningView.activeElementIndex >= this.positioningView.numberOfElements - 1 ? 'add' : 'remove') + 'ClassName']('inactive');
 85   }
 86 };
 87 
 88 
 89 /* ==================== Event Handling ==================== */
 90 
 91 TKPositioningController.prototype.elementWasActivated = function (element) {
 92   // see if we hit one of the previous / next buttons
 93   if (event.currentTarget === this._previousButton) {
 94     this.positioningView.activeElementIndex--;
 95     TKSpatialNavigationManager.soundToPlay = (this.positioningView.activeElementIndex > 0) ? SOUND_MOVED : SOUND_LIMIT;
 96   }
 97   else if (event.currentTarget === this._nextButton) {
 98     this.positioningView.activeElementIndex++;
 99     TKSpatialNavigationManager.soundToPlay = (this.positioningView.activeElementIndex < this.positioningView.numberOfElements - 1) ? SOUND_MOVED : SOUND_LIMIT;
100   }
101   // focused element in the positioning view
102   else if (element.hasClassName(TKPositioningViewCSSFocusedClass)) {
103     // we only need to trigger selection on activation when running on Apple TV
104     if (IS_APPLE_TV) {
105       this.elementWasSelected(this.positioningView.activeElementIndex);
106     }
107   }
108   else {
109     this.callSuper(element);
110   }
111 };
112 
113 TKPositioningController.prototype.handleEvent = function (event) {
114   this.callSuper(event);
115   //
116   if (event.currentTarget._positioningViewIndex !== undefined) {
117     if (event.type == 'highlight') {
118       this.positioningView.activeElementIndex = event.currentTarget._positioningViewIndex;
119     }
120   }
121 };
122 
123 /* ==================== TKPositioningView Protocol ==================== */
124 
125 TKPositioningController.prototype.positioningViewDidFocusElementAtIndex = function (view, index) {
126   // update the states of previous and next buttons
127   this.syncPageButtons();
128 };
129 
130 TKPositioningController.prototype.positioningViewDidBlurElementAtIndex = function (view, index) {};
131 
132 TKPositioningController.prototype.positioningViewDidSelectActiveElement = function (view, index) {
133   this.elementWasSelected(index);
134 };
135 
136 // placeholders to be over-riden by instance
137 TKPositioningController.prototype.elementWasSelected = function (index) {};
138 
139 TKClass(TKPositioningController);
140