Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Improved DocumentLens implementation.

  • Loading branch information...
commit a561d68fcb2a8662ff79ba1505fc5761ff6cf8b7 1 parent 6879e09
Michael Aufreiter authored March 17, 2012
2  layouts/app.html
@@ -41,7 +41,7 @@
41 41
       use for everyone. <a href="/substance/contribute">Support</a> us!
42 42
     </div>
43 43
     <div class="credits"><a href="http://substance.io/substance/substance">About</a> &middot; <a href="http://twitter.com/_substance" target="_blank">Twitter</a> &middot; <a href="http://github.com/substance/substance" target="_blank">Source Code</a> &middot; <a href="https://groups.google.com/group/substance_" target="_blank">Discuss</a></div>
44  
-    <div class="version"><a href="http://substance.io/substance/release-notes">Substance 0.4.0</a></div>
  44
+    <div class="version"><a href="http://substance.io/substance/release-notes">Substance 0.4.1</a></div>
45 45
   </div>
46 46
 </body>
47 47
 
47  src/client/views/application.js
@@ -50,7 +50,8 @@ s.views.Application = Backbone.View.extend({
50 50
 
51 51
   scrollTo: function (id) {
52 52
     var offset = $('#'+id).offset();
53  
-    offset ? $('html, body').animate({scrollTop: offset.top-90}, 'slow') : null;
  53
+    // offset ? $('html, body').animate({scrollTop: offset.top-90}, 'fast') : null;
  54
+    offset ? $('html, body').scrollTop(offset.top-90) : null;
54 55
     return false;
55 56
   },
56 57
 
@@ -142,50 +143,6 @@ s.views.Application = Backbone.View.extend({
142 143
   loadDocument: function (username, docname, version, nodeid, commentid) {
143 144
     var render = _.bind(function (options) {
144 145
       this.replaceMainView("document", new s.views.Document(_.extend(options, {id: 'document_view' })).render());
145  
-
146  
-      // TODO: move code to document view
147  
-      var bounds;
148  
-      var sections;
149  
-
150  
-      // Calculate boundaries
151  
-      function calcBounds() {
152  
-        bounds = [];
153  
-        sections = [];
154  
-        $('#document .content-node.section').each(function() {
155  
-          bounds.push($(this).offset().top);
156  
-          sections.push(graph.get(this.id.replace(/_/g, '/')));
157  
-        });
158  
-      }
159  
-
160  
-      function getActiveSection() {
161  
-        var active = 0;
162  
-        _.each(bounds, function(bound, index) {
163  
-          if ($(window).scrollTop() >= bound-90) {
164  
-            active = index;
165  
-          }
166  
-        });
167  
-        return active;
168  
-      }
169  
-
170  
-      var prevSection = null;
171  
-
172  
-      function updateToc(e) {
173  
-        var activeSection = getActiveSection();
174  
-        if (activeSection !== prevSection) {
175  
-          prevSection = activeSection;
176  
-          app.mainView.documentLens.selectedItem = activeSection;
177  
-          // TODO: no re-render required here
178  
-          app.mainView.documentLens.render();
179  
-        }
180  
-      }
181  
-
182  
-      window.calcBounds = calcBounds;
183  
-      window.getActiveSection = getActiveSection;
184  
-      window.updateToc = updateToc;
185  
-
186  
-      setTimeout(calcBounds, 400);
187  
-      $(window).scroll(updateToc);
188  
-
189 146
     }, this);
190 147
     
191 148
     var id = '/document/'+username+'/'+docname;
61  src/client/views/document.js
... ...
@@ -1,6 +1,4 @@
1 1
 
2  
-
3  
-
4 2
 // Document
5 3
 // -------------
6 4
 
@@ -12,21 +10,22 @@ s.views.Document = Backbone.View.extend({
12 10
     this.authorized   = options.authorized;
13 11
     this.published    = options.published;
14 12
     this.version      = options.version;
15  
-    
16  
-    var sections = [];
17 13
 
  14
+    var sections;
18 15
     function collectSections (node, level) {
  16
+      if (level === 1) sections = [];
19 17
       node.get('children').each(function (child) {
20 18
         if (child.type.key !== '/type/section') return;
21 19
         sections.push({id: child._id, html_id: child.html_id, name: child.get('name'), level: level});
22 20
         collectSections(child, level+1);
23 21
       });
  22
+      return sections;
24 23
     }
25 24
 
26 25
     collectSections(this.model, 1);
27 26
 
28 27
     this.node         = s.views.Node.create({ model: this.model, document: this });
29  
-    this.documentLens = new s.views.DocumentLens({ model: {items: sections}, authorized: this.authorized });
  28
+    this.documentLens = new s.views.DocumentLens({ model: {items: sections, document: this}, authorized: this.authorized });
30 29
     this.settings     = new s.views.DocumentSettings({ model: this.model, authorized: this.authorized });
31 30
     this.publish      = new s.views.Publish({ model: this.model, docView: this, authorized: this.authorized });
32 31
     this.invite       = new s.views.Invite({ model: this.model, authorized: this.authorized });
@@ -35,14 +34,26 @@ s.views.Document = Backbone.View.extend({
35 34
     this.versions     = new s.views.Versions({ model: this.model, authorized: this.authorized });
36 35
     
37 36
     // TODO: Instead listen for a document-changed event
38  
-    graph.bind('dirty', _.bind(function() {
  37
+    graph.bind('dirty', _.bind(function(node) {
39 38
       this.updatePublishState();
  39
+
  40
+      // Update TOC
  41
+      if (node.type._id === "/type/section") {
  42
+        // Recalc bounds every time content is changed
  43
+        this.calcBounds();
  44
+        setTimeout(_.bind(function() {
  45
+          this.documentLens.model.items = collectSections(this.model, 1);        
  46
+          this.documentLens.render();
  47
+        }, this), 2);
  48
+      }
40 49
     }, this));
41 50
 
42 51
     this.currentView = null;
43 52
     
44 53
     _.bindAll(this, 'deselect', 'onKeydown');
45 54
     $(document.body).keydown(this.onKeydown);
  55
+    if (!this.bounds) setTimeout(this.calcBounds, 400);
  56
+    $(window).scroll(this.markActiveSection);
46 57
   },
47 58
 
48 59
   render: function () {
@@ -134,19 +145,53 @@ s.views.Document = Backbone.View.extend({
134 145
     }
135 146
   },
136 147
 
  148
+  // Calculate section bounds
  149
+  calcBounds: function() {
  150
+    var that = this;
  151
+    this.bounds = [];
  152
+    this.sections = [];
  153
+    $('#document .content-node.section').each(function() {
  154
+      that.bounds.push($(this).offset().top);
  155
+      that.sections.push(graph.get(this.id.replace(/_/g, '/')));
  156
+    });
  157
+  },
  158
+
  159
+  markActiveSection: function() {
  160
+    var that = this;
  161
+    function getActiveSection() {
  162
+      var active = 0;
  163
+      _.each(that.bounds, function(bound, index) {
  164
+        if ($(window).scrollTop() >= bound-90) {
  165
+          active = index;
  166
+        }
  167
+      });
  168
+      return active;
  169
+    }
  170
+
  171
+    function update(e) {
  172
+      that.activeSection = getActiveSection();
  173
+      if (that.activeSection !== that.prevSection) {
  174
+        that.prevSection = that.activeSection;
  175
+        that.documentLens.selectSection(that.activeSection);
  176
+      }
  177
+    }
  178
+    update();
  179
+  },
  180
+
137 181
   resizeShelf: function () {
138 182
     var shelfHeight   = this.currentView ? $(this.currentView.el).outerHeight() : 0
139 183
     ,   contentMargin = shelfHeight + 100;
140 184
     this.$('#document_shelf').css({ height: shelfHeight + 'px' });
141 185
     this.$('#document_content').css({ 'margin-top': contentMargin + 'px' });
  186
+    this.$('#document_lens').css({ 'top': (contentMargin+40) + 'px' });
142 187
   },
143 188
 
144 189
   closeShelf: function() {
145 190
     if (!this.currentView) return;
146 191
     this.currentView.unbind('resize', this.resizeShelf);
147 192
 
148  
-    // It's important to use detach (not remove) to retain the view's event
149  
-    // handlers
  193
+    // It's important to use detach (not remove) to retain
  194
+    // the view's event handlers
150 195
     $(this.currentView.el).detach();
151 196
 
152 197
     this.currentView = null;
29  src/client/views/document_lens.js
@@ -14,13 +14,20 @@ s.views.DocumentLens = Backbone.View.extend({
14 14
     
15 15
     this.selectedItem = 0;
16 16
     this.start = 0;
17  
-    this.windowSize = 9;
18  
-    this.height = 270;
  17
+    this.windowSize = 12;
  18
+    this.height = this.windowSize * 30;
19 19
   },
20 20
 
21 21
   scrollTo: function (e) {
22 22
     var node = $(e.currentTarget).attr('href').slice(1);
  23
+    var index = $(e.currentTarget).attr('data-index');
23 24
     app.scrollTo(node);
  25
+    setTimeout(_.bind(function() {
  26
+      this.selectSection(index);
  27
+      // TODO: view dependency alert
  28
+      this.model.document.prevSection = index;
  29
+    }, this), 40);
  30
+    
24 31
     return false;
25 32
   },
26 33
 
@@ -33,6 +40,16 @@ s.views.DocumentLens = Backbone.View.extend({
33 40
     return [start, start+this.windowSize-1];
34 41
   },
35 42
 
  43
+  selectSection: function(item) {
  44
+    this.selectedItem = item;
  45
+
  46
+    this.$('.items .item.selected').removeClass('selected');
  47
+    this.$($('.items .item')[item]).addClass('selected');
  48
+    this.$('.outline .outline-item').removeClass('selected');
  49
+    this.$($('.outline .outline-item')[item]).addClass('selected');
  50
+    this.$('.items').scrollTop(this.getBounds()[0]*30);
  51
+  },
  52
+
36 53
   render: function () {
37 54
     var bounds = this.getBounds();
38 55
     var that = this;
@@ -42,11 +59,6 @@ s.views.DocumentLens = Backbone.View.extend({
42 59
       selectedItem: this.selectedItem
43 60
     }));
44 61
 
45  
-    // Good?
46  
-    this.$('.items').mouseleave(function() {
47  
-      that.render();
48  
-    });
49  
-
50 62
     this.$('.items').scroll(function(e) {
51 63
       e.preventDefault();
52 64
       e.stopPropagation();
@@ -61,8 +73,7 @@ s.views.DocumentLens = Backbone.View.extend({
61 73
     });
62 74
 
63 75
     this.$('.items').scrollTop(bounds[0]*30);
64  
-
65  
-    var delta = this.height/this.model.items.length;
  76
+    var delta = Math.min(this.height/this.model.items.length, 30);
66 77
     this.$('.outline .outline-item').height(delta);
67 78
 
68 79
     return this;
6  styles/document/document.less
@@ -14,7 +14,7 @@
14 14
 }
15 15
 
16 16
 #document_identifier {
17  
-  margin: 9px 80px;
  17
+  margin: 9px 40px;
18 18
   margin-right: 20px;
19 19
   float: left;
20 20
 
@@ -174,7 +174,9 @@
174 174
   width: 920px;
175 175
   color: #000;
176 176
   position:relative;
177  
-  margin: 0 auto;
  177
+  margin: 0;
  178
+  margin-left: 320px;
  179
+
178 180
   padding: 0px 0 0px 0;
179 181
   -webkit-box-shadow: 0px 1px 4px rgba(0,0,0,0.35), inset 0px 0px 1px rgba(255,255,255,0.15);
180 182
   -moz-box-shadow:    0px 1px 4px rgba(0,0,0,0.35), inset 0px 0px 1px rgba(255,255,255,0.15);
48  styles/document/lens.less
... ...
@@ -1,32 +1,39 @@
1 1
 #document #document_lens {
  2
+  -webkit-transition-property: top;
  3
+  -webkit-transition-duration: 0.6s;
2 4
   position: fixed;
  5
+  overflow: hidden;
3 6
   width: 250px;
4  
-  left: 10px;
5  
-  top: 100px;
6  
-  height: 800px;
7  
-  
  7
+  left: 40px;
  8
+  top: 120px;
  9
+  height: 600px;
  10
+
8 11
   .ui-font;
9 12
   font-weight: bold;
10 13
   font-size: 12px;
11 14
 
12  
-
13  
-  overflow: auto;
14  
-
15 15
   .items {
16  
-    height: 270px;
  16
+    height: 360px; // 15x30 make dynamic
  17
+    position: absolute;
  18
+    top: 0px;
  19
+    left: 0px;
  20
+    width: 600px;
17 21
     overflow-y: auto;
18 22
     overflow-x: hidden;
19  
-    margin-left: 30px;
  23
+    
20 24
     .item {
  25
+      whitespace: nowrap;
21 26
       height: 30px;
22  
-      width: 300px;
  27
+      width: 230px;
  28
+      
23 29
       line-height: 30px;
24 30
 
25  
-      &.level-1 { font-weight: bold; font-size: 16px;}
  31
+      &.level-1 { font-weight: bold; font-size: 14px; }
26 32
       &.level-2 { padding-left: 10px; }
27 33
       &.level-3 { padding-left: 20px; }
28 34
       
29  
-      a { border: none; color: #939393;}
  35
+      a { border: none; color: #939393; }
  36
+      a:hover { color: #444; }
30 37
 
31 38
       &.selected {
32 39
         a { color: #2D2D2D;}
@@ -35,23 +42,26 @@
35 42
   }
36 43
 
37 44
   .outline {
38  
-    float: left;
  45
+    margin-right: 5px;
  46
+    float: right;
39 47
     width: 5px;
40  
-    height: 270px;
  48
+    /*height: 270px;*/
41 49
 
42 50
     .outline-item {
43 51
       width: 4px;
44 52
       margin-left: 1px;
45  
-      background: #8C8C8C;
  53
+      background: #ccc;
46 54
       margin-bottom: 1px;
47 55
 
48  
-      &.selected {
49  
-        background: #383838;
50  
-      }
51 56
       &.active {
  57
+        background: #8C8C8C;
52 58
         padding: 0 3px;
53 59
         margin-left: 0;
54 60
       }
  61
+
  62
+      &.selected {
  63
+        background: #383838;
  64
+      }
55 65
     }
56 66
   }
57  
-}
  67
+}
2  styles/document/shelf-content.less
... ...
@@ -1,6 +1,6 @@
1 1
 .shelf-content {
2 2
   padding: 20px;
3  
-  padding-left: 80px;
  3
+  padding-left: 40px;
4 4
   a { border-bottom: none; }
5 5
   .settings-title {}
6 6
 }
2  styles/header.less
@@ -20,7 +20,7 @@ body:not(.document) #header {
20 20
   #header_title {
21 21
     .document-font;
22 22
     float: left;
23  
-    margin: 0 80px;
  23
+    margin: 0 40px;
24 24
 
25 25
     a {
26 26
       text-decoration: none;
7  styles/layout.less
@@ -20,13 +20,14 @@ body {
20 20
   border-top: 1px solid #C1C1C1;
21 21
   background: #E9EAE5;
22 22
   color: #7C6E60;
23  
-  height: 142x; margin-top: -142px;
24  
-  padding: 30px 80px 30px 80px;
  23
+  height: 142px; margin-top: -142px;
  24
+  padding: 30px 40px;
25 25
   overflow: auto;
26 26
   
  27
+  z-index: 1000;
  28
+
27 29
   .did-you-know {
28 30
     .document-font;
29  
-
30 31
     padding: 20px 0;
31 32
     font-size: 22px;
32 33
     font-style: italic;
2  templates/document_lens.ejs
@@ -6,6 +6,6 @@
6 6
 
7 7
 <div class="items">
8 8
   <% _.each(items, function(item, i) { %>
9  
-    <div class="item level-<%= item.level %><%= selectedItem === i ? " selected" : ""%>"><a href="#<%= item.html_id %>"><%= item.name %></a></div>
  9
+    <div class="item level-<%= item.level %><%= selectedItem === i ? " selected" : ""%>"><a data-index="<%= i %>" href="#<%= item.html_id %>"><%= item.name %></a></div>
10 10
   <% }); %>
11 11
 </div>

0 notes on commit a561d68

Please sign in to comment.
Something went wrong with that request. Please try again.