blossom
Version:
Modern, Cross-Platform Application Framework
189 lines (144 loc) • 5.91 kB
JavaScript
// ==========================================================================
// Project: Blossom - Modern, Cross-Platform Application Framework
// Copyright: ©2012 Fohr Motion Picture Studios. All rights reserved.
// License: Licensed under the GPLv3 license (see BLOSSOM-LICENSE).
// ==========================================================================
/*globals sc_assert */
sc_require('surfaces/view');
var base03 = "#002b36";
var base02 = "#073642";
var base01 = "#586e75";
var base00 = "#657b83";
var base0 = "#839496";
var base1 = "#93a1a1";
var base2 = "#eee8d5";
var base3 = "#fdf6e3";
var yellow = "#b58900";
var orange = "#cb4b16";
var red = "#dc322f";
var magenta = "#d33682";
var violet = "#6c71c4";
var blue = "#268bd2";
var cyan = "#2aa198";
var green = "#859900";
var white = "white";
/** @class
`SC.ScrollView` implements a scrollable view. You can use it
interchangeably with `SC.View`, the only difference is the scrolling.
Setting the bounds of the scroll is important.
@extends SC.CompositeSurface
@since Blossom 1.0
*/
SC.ScrollView = SC.View.extend({
__tagName__: 'div',
__useContentSize__: false,
isCompositeSurface: true, // Walk like a duck.
subsurfaces: [],
/**
true if the view should maintain a horizontal scroller. This property
must be set when the view is created.
@property {Boolean}
*/
hasHorizontalScroller: true,
/**
true if the view should maintain a horizontal scroller. This property
must be set when the view is created.
@property {Boolean}
*/
hasVerticalScroller: true,
// ..........................................................
// PSURFACE SUPPORT (Private)
//
updatePsurface: function(psurface, surfaces) {
// console.log('SC.ScrollView#updatePsurface()');
sc_assert(this === SC.surfaces[this.__id__], "SC.Surface#updatePsurface() can only be called on active surfaces.");
// Sanity check the Psurface.
sc_assert(psurface);
sc_assert(psurface instanceof SC.Psurface);
sc_assert(psurface.__element__);
sc_assert(psurface.__element__ === document.getElementById(this.__id__));
var surface = this._sc_scrollingCanvas;
if (surfaces) surfaces[surface.__id__] = surface;
psurface.push(surface);
},
didCreateElement: function(div) {
// We don't want SC.View's implementation; don't call it.
div.style.overflowX = this.get('hasHorizontalScroller')? 'scroll' : 'hidden';
div.style.overflowY = this.get('hasVerticalScroller')? 'scroll' : 'hidden';
// FIXME: This should be done dynamically, per scrollview. I'm not doing
// it now because the CSS has pseudo-selectors, so I have to generate
// stylesheet code specially. (Here and a few other places, actually.)
//
// For now, I'll specially customize the CSS to work with Postbooks' UI
// correctly.
div.className = 'frame';
// This should probably only be set on mobile Safari/Google Chrome for
// Android.
//
// See http://stackoverflow.com/questions/7763458/ios5-webkit-overflow-scrolling-causes-touch-events-stopping-work
// for a fix I haven't yet implemented, too.
div.style.webkitOverflowScrolling = 'touch';
},
adjustLayout: function() {
// console.log('SC.ScrollView#adjustLayout()', SC.guidFor(this));
var benchKey = 'SC.ScrollView#adjustLayout()';
SC.Benchmark.start(benchKey);
// Our layers have been been updated. Calculate the union of the the
// AABB of all their frames in our own coordinate system.
var frame = SC.MakeRect(this.get('frame')),
extent = SC.MakeRect(frame);
var layers = this.get('layers'), idx, len, f;
for (idx=0, len=layers.get('length'); idx<len; ++idx) {
f = layers[idx].get('frame');
extent[0]/*x*/ = Math.min(f[0]/*x*/, extent[0]/*x*/);
extent[1]/*y*/ = Math.min(f[1]/*y*/, extent[1]/*y*/);
extent[2]/*w*/ = Math.max(f[2]/*w*/, extent[2]/*w*/);
extent[3]/*h*/ = Math.max(f[3]/*h*/, extent[3]/*h*/);
}
// `extent` is now big enough to cover our direct sublayers
var scrollTranslation = this._sc_scrollTranslation;
scrollTranslation[0]/*x*/ = -Math.min(extent[0]/*x*/, 0);
scrollTranslation[1]/*y*/ = -Math.min(extent[1]/*y*/, 0);
frame[0]/*x*/ = 0;
frame[1]/*y*/ = 0;
frame[2]/*w*/ = Math.max(extent[2]/*w*/, frame[2]/*w*/) + scrollTranslation[0]/*x*/;
frame[3]/*h*/ = Math.max(extent[3]/*h*/, frame[3]/*h*/) + scrollTranslation[1]/*y*/;
this._sc_scrollingCanvas.set('frame', frame);
SC.Benchmark.end(benchKey);
},
updateLayout: function() {
arguments.callee.base.apply(this, arguments);
this.adjustLayout();
},
_sc_scrollingCanvas: null,
init: function() {
arguments.callee.base.apply(this, arguments);
var scrollingCanvas;
scrollingCanvas = this._sc_scrollingCanvas = SC.InternalScrollViewCanvas.create({
__scrollView__: this
});
this._sc_scrollTranslation = SC.MakePoint();
}
});
/** @private */
SC.InternalScrollViewCanvas = SC.LeafSurface.extend({
__tagName__: 'canvas',
__useContentSize__: true, // we need our width and height attributes set
__scrollView__: null,
surface: function() {
// console.log('SC.InternalScrollViewCanvas@surface');
return this.__scrollView__;
}.property().cacheable(),
didCreateElement: function(canvas) {
// console.log('SC.InternalScrollViewCanvas#didCreateElement()', SC.guidFor(this));
arguments.callee.base.apply(this, arguments);
var ctx = canvas.getContext('2d');
// Enables ctx.width and ctx.height to work.
ctx.__sc_canvas__ = canvas;
this.__scrollView__._sc_context = ctx;
this.__scrollView__.triggerRendering();
},
targetResponderForEvent: function(evt) {
return this.get('surface').targetResponderForEvent(evt);
}
});