From a555dc9f5ec0bd69948947d27e3ed6fb54b48231 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 13 Feb 2014 14:05:12 -0500 Subject: [PATCH] FIX: Incorrect post number following a link. Updated ember-cloaking. --- .../discourse/templates/topic.js.handlebars | 9 +- vendor/assets/javascripts/ember-cloaking.js | 84 ++++++++++++++++--- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/topic.js.handlebars b/app/assets/javascripts/discourse/templates/topic.js.handlebars index ac742a8df6b..912ef4cee19 100644 --- a/app/assets/javascripts/discourse/templates/topic.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic.js.handlebars @@ -67,7 +67,14 @@ {{/if}} {{#unless postStream.loadingFilter}} - {{cloaked-collection cloakView="post" idProperty="post_number" defaultHeight="200" content=postStream.posts slackRatio=slackRatio loadingHTML=controller.loadingHTML}} + {{cloaked-collection cloakView="post" + idProperty="post_number" + defaultHeight="200" + content=postStream.posts + slackRatio=slackRatio + loadingHTML=controller.loadingHTML + preservesContext="true" + offsetFixed="header"}} {{/unless}} {{#if postStream.loadingBelow}} diff --git a/vendor/assets/javascripts/ember-cloaking.js b/vendor/assets/javascripts/ember-cloaking.js index c7d3062734d..64eebdba009 100644 --- a/vendor/assets/javascripts/ember-cloaking.js +++ b/vendor/assets/javascripts/ember-cloaking.js @@ -10,10 +10,11 @@ Ember.CloakedCollectionView = Ember.CollectionView.extend({ topVisible: null, bottomVisible: null, + offsetFixedElement: null, init: function() { var cloakView = this.get('cloakView'), - idProperty = this.get('idProperty') || 'id'; + idProperty = this.get('idProperty'); // Set the slack ratio differently to allow for more or less slack in preloading var slackRatio = parseFloat(this.get('slackRatio')); @@ -22,11 +23,16 @@ this.set('itemViewClass', Ember.CloakedView.extend({ classNames: [cloakView + '-cloak'], cloaks: cloakView, + preservesContext: this.get('preservesContext') === "true", + cloaksController: this.get('itemController'), defaultHeight: this.get('defaultHeight') || 100, init: function() { this._super(); - this.set('elementId', cloakView + '-cloak-' + this.get('content.' + idProperty)); + + if (idProperty) { + this.set('elementId', cloakView + '-cloak-' + this.get('content.' + idProperty)); + } } })); @@ -34,6 +40,7 @@ Ember.run.next(this, 'scrolled'); }, + /** If the topmost visible view changed, we will notify the controller if it has an appropriate hook. @@ -70,8 +77,10 @@ if (max < min) { return min; } var mid = Math.floor((min + max) / 2), + // in case of not full-window scrolling + scrollOffset = this.get('wrapperTop') >> 0, $view = childViews[mid].$(), - viewBottom = $view.offset().top + $view.height(); + viewBottom = $view.position().top + scrollOffset + $view.height(); if (viewBottom > viewportTop) { return this.findTopView(childViews, viewportTop, min, mid-1); @@ -90,26 +99,33 @@ if ((!childViews) || (childViews.length === 0)) { return; } var toUncloak = [], + onscreen = [], + // calculating viewport edges $w = $(window), - windowHeight = window.innerHeight ? window.innerHeight : $w.height(), - windowTop = $w.scrollTop(), + windowHeight = this.get('wrapperHeight') || ( window.innerHeight ? window.innerHeight : $w.height() ), + windowTop = this.get('wrapperTop') || $w.scrollTop(), slack = Math.round(windowHeight * this.get('slackRatio')), viewportTop = windowTop - slack, windowBottom = windowTop + windowHeight, viewportBottom = windowBottom + slack, topView = this.findTopView(childViews, viewportTop, 0, childViews.length-1), - bodyHeight = $('body').height(), + bodyHeight = this.get('wrapperHeight') ? this.$().height() : $('body').height(), bottomView = topView, - onscreen = []; + offsetFixedElement = this.get('offsetFixedElement'); if (windowBottom > bodyHeight) { windowBottom = bodyHeight; } if (viewportBottom > bodyHeight) { viewportBottom = bodyHeight; } + if (offsetFixedElement) { + windowTop += (offsetFixedElement.outerHeight(true) || 0); + } // Find the bottom view and what's onscreen while (bottomView < childViews.length) { var view = childViews[bottomView], $view = view.$(), - viewTop = $view.offset().top, + // in case of not full-window scrolling + scrollOffset = this.get('wrapperTop') >> 0, + viewTop = $view.position().top + scrollOffset, viewBottom = viewTop + $view.height(); if (viewTop > viewportBottom) { break; } @@ -158,20 +174,27 @@ Em.run.scheduleOnce('afterRender', this, 'scrolled'); }, - didInsertElement: function() { + _startEvents: function() { var self = this, + offsetFixed = this.get('offsetFixed'), onScrollMethod = function() { Ember.run.debounce(self, 'scrollTriggered', 10); }; + if (offsetFixed) { + this.set('offsetFixedElement', $(offsetFixed)); + } + $(document).bind('touchmove.ember-cloak', onScrollMethod); $(window).bind('scroll.ember-cloak', onScrollMethod); - }, + this.addObserver('wrapperTop', self, onScrollMethod); + this.addObserver('wrapperHeight', self, onScrollMethod); + }.on('didInsertElement'), - willDestroyElement: function() { + _endEvents: function() { $(document).unbind('touchmove.ember-cloak'); $(window).unbind('scroll.ember-cloak'); - } + }.on('willDestroyElement') }); @@ -198,11 +221,46 @@ uncloak: function() { var containedView = this.get('containedView'); if (!containedView) { + var model = this.get('content'), + controller = null, + container = this.get('container'); + // Wire up the itemController if necessary + var controllerName = this.get('cloaksController'); + if (controllerName) { + var controllerFullName = 'controller:' + controllerName, + factory = container.lookupFactory(controllerFullName), + parentController = this.get('controller'); + + // let ember generate controller if needed + if (factory === undefined) { + factory = Ember.generateControllerFactory(container, controllerName, model); + + // inform developer about typo + Ember.Logger.warn('ember-cloacking: can\'t lookup controller by name "' + controllerFullName + '".'); + Ember.Logger.warn('ember-cloacking: using ' + factory.toString() + '.'); + } + + controller = factory.create({ + model: model, + parentController: parentController, + target: parentController + }); + } + + var createArgs = {}, + target = controller || model; + + if (this.get('preservesContext')) { + createArgs.content = target; + } else { + createArgs.context = target; + } + if (controller) { createArgs.controller = controller; } this.setProperties({ style: null, loading: false, - containedView: this.createChildView(this.get('cloaks'), {content: this.get('content') }) + containedView: this.createChildView(this.get('cloaks'), createArgs) }); this.rerender();