Guest User

Untitled

a guest
Jun 19th, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.79 KB | None | 0 0
  1. Proposed View-layer changes
  2. =============
  3.  
  4. Friday, Juan, Tom, Yehuda and I had a meeting where we discussed the renderer APIs
  5. and some ideas we had for the view layer. Here is what we came up with:
  6.  
  7. Overview
  8. ------------
  9. The purpose of these proposed changes is to lower the learning curve for users entering the
  10. SproutCore world and who are looking for quick feedback and an easy way to create custom views
  11. and a facility to create complex, themable views.
  12.  
  13.  
  14. Name Changes
  15. -------------
  16.  
  17. - Renderer => RenderDelegate
  18.  
  19.  
  20. Views
  21. ---------------
  22. Our goal for the next version of SproutCore is to streamline the process of creating custom
  23. views. We've received a lot of feedback from the community regarding this process and we
  24. believe that simplifying it will be a huge benefit for people starting out with SproutCore.
  25.  
  26. For the purpose of this discussion, we will talk about 3 levels of custom view generation from
  27. the most basic, to the most complex:
  28.  
  29. 1) The one-off view:
  30.  
  31. This kind of custom view is the most basic, has some displayProperties associated with it,
  32. and has a custom render() implementation. The user doesn't have to implement firstTime,
  33. and doesn't have to worry about updating the view when the displayProperty changes.
  34. each displayProperty will have an observer on it, and when it changes, we will update that DOM
  35. element's val with the new value of the displayProperty. The mapping between selector and
  36. displayProperty is an API that still has to be worked out, but the idea is that you can create
  37. a custom view like this:
  38.  
  39. // THIS SAMPLE IS A WORK IN PROGRESS, THE API IS NOT FINAL
  40.  
  41. myView: SC.View.design({
  42.  
  43. displayProperties: 'fullName'.w(),
  44.  
  45. render: function(context){
  46. context.push('<div class="fullName">Default Value</div>');
  47. }
  48.  
  49. })
  50.  
  51.  
  52. As I mentioned, the API for mapping '.fullName' to the innerHTML is still an API that has to be
  53. worked out, it could be a simple mapping between a css selector and a displayProperty. We could
  54. use WebKit DOM bindings to create the mapping between displayProperty and DOM element, or it could
  55. use the classname of the div to associate it with a displayProperty.
  56.  
  57. 2) A basic view, but with more complex handling
  58.  
  59. In this case, the user is still building a basic view, but he wants to more closely manage how
  60. the view behaves when one of its displayProperties change.
  61.  
  62.  
  63. myView: SC.View.design({
  64.  
  65. displayProperties: 'fullName'.w(),
  66.  
  67. fullNameDidChange: function(newValue){
  68. this.$('.fullName').val(newValue);
  69. // THIS IS WHERE EXTRA PROCESSING WOULD GO
  70. }.observes('fullName'),
  71.  
  72. render: function(context){
  73. context.push('<div class="fullName">Default Value</div>');
  74. }
  75.  
  76. })
  77.  
  78. 3) A complex, themable view
  79.  
  80. When the user wants to make a re-usalbe, and/or themable view, then they start have to take more
  81. control over its generation and updates. This is where RenderDelegates come into play, discussed
  82. in the next section.
  83.  
  84.  
  85. RenderDelegates
  86. ---------------
  87. At a macro level, RenderDelegates separate the generation of a view from the business logic
  88. of the view. This allows us to modify how views are being generated based on the theme.
  89. By default, a view's renderDelegate would be null. In the base render function, SC.View
  90. will call the render method if possible.
  91.  
  92. This is the only way to ensure backwards compatibility, since views _do_ frequently
  93. extend from other views (such as SC.ButtonView) and override the render() method,
  94. yet call sc\_super()—they do this, for instance, if they only want to modify certain
  95. styles rather than change everything.
  96.  
  97. This is how we would implement SC.ButtonView in SproutCore, as a themeable view.
  98.  
  99. SC.ButtonView = SC.View.extend({
  100. // Render delegate can be a string, object, or computed property.
  101. renderDelegate: 'button',
  102.  
  103. mouseUp: function(evt) {
  104. ...
  105. },
  106.  
  107. ...
  108.  
  109. /* SC.View's init method: */
  110. init: function() {
  111. ...
  112. if (typeof this.renderDelegate === "string") {
  113. this.renderDelegate = this._renderDelegateLookupFor(this.renderDelegate);
  114. }
  115. },
  116.  
  117. /* SC.View's render method: */
  118. render: function(context, firstTime) {
  119. var del = this.get('renderDelegate');
  120. if (del && firstTime) del.render(context);
  121. else if (del) del.update(context);
  122.  
  123. if (!del) this.renderChildViews(context, firstTime);
  124. }
  125. });
  126.  
  127. // Example 1, using an alternate style of button from the current theme.
  128. myRoundedButtonView = SC.ButtonView.extend({
  129. // you should NOT have to have a different renderDelegate just because
  130. // you are changing appearance. The theme will decide if that is needed.
  131. theme: 'rounded'
  132. });
  133.  
  134.  
  135. // Example 2, dynamically choosing a render delegate at runtime depending on
  136. // the browser's capabilities.
  137. myCanvasButtonView = SC.ButtonView.extend({
  138. // changing the theme will vary the renderDelegate as the theme feels is needed.
  139. theme: SC.platform.supportsCanvas ? 'mytheme-canvas' : 'mytheme'
  140. });
  141.  
  142. // Example 3, the user just wants a quick override of SC.ButtonView without
  143. // implementing their own render delegate.
  144.  
  145. myCustomButtonView = SC.ButtonView.extend({
  146. render: function(context, firstTime) {
  147. context.push('<div class="my-sweet-button">Click!</div>');
  148. }
  149. });
  150.  
  151.  
  152. What RenderDelegates Look Like
  153. --------------------------------
  154.  
  155. Theme.Button = SC.RenderDelegate.extend({
  156. render: function(context) {
  157. context.text(this.get('title'));
  158. },
  159. update: function($) {
  160. $.text(this.get('title'));
  161. }
  162. }
  163.  
  164. The .get() method will look at the RenderDelegate itself, and if the
  165. property on the renderDelegate is "undefined", will look up the property
  166. on the theme's dataDelegate if present (which would, if instantiated by
  167. an SC.View, be the view itself).
Add Comment
Please, Sign In to add comment