diff --git a/app/assets/javascripts/discourse/routes/discourse_location.js b/app/assets/javascripts/discourse/routes/discourse_location.js index 40377a5d0..25af43558 100644 --- a/app/assets/javascripts/discourse/routes/discourse_location.js +++ b/app/assets/javascripts/discourse/routes/discourse_location.js @@ -226,7 +226,7 @@ Ember.DiscourseLocation = Ember.Object.extend({ eject itself when the popState occurs. This results in better back button behavior. **/ -Ember.CloakedCollectionView.reopen({ +Discourse.CloakedCollectionView.reopen({ _watchForPopState: function() { var self = this, cb = function() { diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index 32445b9c9..f6c8ec8be 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -67,6 +67,16 @@ {{conditional-loading-spinner condition=model.postStream.loadingAbove}} {{#unless model.postStream.loadingFilter}} + {{cloaked-collection itemViewClass="post" + idProperty="post_number" + defaultHeight="200" + content=model.postStream.posts + slackRatio="15" + loadingHTML="" + preservesContext="true" + uncloakDefault="true" + offsetFixedTop="header" + offsetFixedBottom="#reply-control"}} {{/unless}} {{conditional-loading-spinner condition=model.postStream.loadingBelow}} diff --git a/app/assets/javascripts/discourse/views/cloaked-collection.js.es6 b/app/assets/javascripts/discourse/views/cloaked-collection.js.es6 new file mode 100644 index 000000000..3993fc912 --- /dev/null +++ b/app/assets/javascripts/discourse/views/cloaked-collection.js.es6 @@ -0,0 +1,286 @@ +import CloakedView from 'discourse/views/cloaked'; + +const CloakedCollectionView = Ember.CollectionView.extend({ + cloakView: Ember.computed.alias('itemViewClass'), + topVisible: null, + bottomVisible: null, + offsetFixedTopElement: null, + offsetFixedBottomElement: null, + loadingHTML: 'Loading...', + scrollDebounce: 10, + + init: function() { + const cloakView = this.get('cloakView'), + idProperty = this.get('idProperty'), + uncloakDefault = !!this.get('uncloakDefault'); + + // Set the slack ratio differently to allow for more or less slack in preloading + const slackRatio = parseFloat(this.get('slackRatio')); + if (!slackRatio) { this.set('slackRatio', 1.0); } + + this.set('itemViewClass', CloakedView.extend({ + classNames: [cloakView + '-cloak'], + cloaks: cloakView, + preservesContext: this.get('preservesContext') === 'true', + cloaksController: this.get('itemController'), + defaultHeight: this.get('defaultHeight'), + + init: function() { + this._super(); + + if (idProperty) { + this.set('elementId', cloakView + '-cloak-' + this.get('content.' + idProperty)); + } + if (uncloakDefault) { + this.uncloak(); + } else { + this.cloak(); + } + } + })); + + this._super(); + Ember.run.next(this, 'scrolled'); + }, + + /** + If the topmost visible view changed, we will notify the controller if it has an appropriate hook. + + @method _topVisibleChanged + @observes topVisible + **/ + _topVisibleChanged: function() { + const controller = this.get('controller'); + if (controller.topVisibleChanged) { controller.topVisibleChanged(this.get('topVisible')); } + }.observes('topVisible'), + + /** + If the bottommost visible view changed, we will notify the controller if it has an appropriate hook. + + @method _bottomVisible + @observes bottomVisible + **/ + _bottomVisible: function() { + const controller = this.get('controller'); + if (controller.bottomVisibleChanged) { controller.bottomVisibleChanged(this.get('bottomVisible')); } + }.observes('bottomVisible'), + + /** + Binary search for finding the topmost view on screen. + + @method findTopView + @param {Array} childViews the childViews to search through + @param {Number} windowTop The top of the viewport to search against + @param {Number} min The minimum index to search through of the child views + @param {Number} max The max index to search through of the child views + @returns {Number} the index into childViews of the topmost view + **/ + findTopView(childViews, viewportTop, min, max) { + if (max < min) { return min; } + + const wrapperTop = this.get('wrapperTop')>>0; + + while(max>min){ + const mid = Math.floor((min + max) / 2), + // in case of not full-window scrolling + $view = childViews[mid].$(), + viewBottom = $view.position().top + wrapperTop + $view.height(); + + if (viewBottom > viewportTop) { + max = mid-1; + } else { + min = mid+1; + } + } + + return min; + }, + + + /** + Determine what views are onscreen and cloak/uncloak them as necessary. + + @method scrolled + **/ + scrolled() { + if (!this.get('scrollingEnabled')) { return; } + + const childViews = this.get('childViews'); + if ((!childViews) || (childViews.length === 0)) { return; } + + const self = this, + toUncloak = [], + onscreen = [], + onscreenCloaks = [], + $w = $(window), + windowHeight = this.get('wrapperHeight') || ( window.innerHeight ? window.innerHeight : $w.height() ), + slack = Math.round(windowHeight * this.get('slackRatio')), + offsetFixedTopElement = this.get('offsetFixedTopElement'), + offsetFixedBottomElement = this.get('offsetFixedBottomElement'), + bodyHeight = this.get('wrapperHeight') ? this.$().height() : $('body').height(); + + let windowTop = this.get('wrapperTop') || $w.scrollTop(); + + const viewportTop = windowTop - slack, + topView = this.findTopView(childViews, viewportTop, 0, childViews.length-1); + + let windowBottom = windowTop + windowHeight, + viewportBottom = windowBottom + slack; + if (windowBottom > bodyHeight) { windowBottom = bodyHeight; } + if (viewportBottom > bodyHeight) { viewportBottom = bodyHeight; } + + if (offsetFixedTopElement) { + windowTop += (offsetFixedTopElement.outerHeight(true) || 0); + } + + if (offsetFixedBottomElement) { + windowBottom -= (offsetFixedBottomElement.outerHeight(true) || 0); + } + + // Find the bottom view and what's onscreen + let bottomView = topView; + while (bottomView < childViews.length) { + const view = childViews[bottomView], + $view = view.$(); + + if (!$view) { break; } + + // in case of not full-window scrolling + const scrollOffset = this.get('wrapperTop') || 0, + viewTop = $view.offset().top + scrollOffset, + viewBottom = viewTop + $view.height(); + + if (viewTop > viewportBottom) { break; } + toUncloak.push(view); + + if (viewBottom > windowTop && viewTop <= windowBottom) { + onscreen.push(view.get('content')); + onscreenCloaks.push(view); + } + + bottomView++; + } + if (bottomView >= childViews.length) { bottomView = childViews.length - 1; } + + // If our controller has a `sawObjects` method, pass the on screen objects to it. + const controller = this.get('controller'); + if (onscreen.length) { + this.setProperties({topVisible: onscreen[0], bottomVisible: onscreen[onscreen.length-1]}); + if (controller && controller.sawObjects) { + Em.run.schedule('afterRender', function() { + controller.sawObjects(onscreen); + }); + } + } else { + this.setProperties({topVisible: null, bottomVisible: null}); + } + + const toCloak = childViews.slice(0, topView).concat(childViews.slice(bottomView+1)); + + this._uncloak = toUncloak; + if(this._nextUncloak){ + Em.run.cancel(this._nextUncloak); + this._nextUncloak = null; + } + + Em.run.schedule('afterRender', this, function() { + onscreenCloaks.forEach(function (v) { + if(v && v.uncloak) { + v.uncloak(); + } + }); + toCloak.forEach(function (v) { v.cloak(); }); + if (self._nextUncloak) { Em.run.cancel(self._nextUncloak); } + self._nextUncloak = Em.run.later(self, self.uncloakQueue,50); + }); + + for (let j=bottomView; j0){ + const view = this._uncloak.shift(); + if(view && view.uncloak && !view._containedView){ + Em.run.schedule('afterRender', view, view.uncloak); + processed++; + } + } + if(this._uncloak.length === 0){ + this._uncloak = null; + } else { + Em.run.schedule('afterRender', self, function(){ + if(self._nextUncloak){ + Em.run.cancel(self._nextUncloak); + } + self._nextUncloak = Em.run.next(self, function(){ + if(self._nextUncloak){ + Em.run.cancel(self._nextUncloak); + } + self._nextUncloak = Em.run.later(self,self.uncloakQueue,delay); + }); + }); + } + } + }, + + scrollTriggered() { + Em.run.scheduleOnce('afterRender', this, 'scrolled'); + }, + + _startEvents: function() { + if (this.get('offsetFixed')) { + Em.warn("Cloaked-collection's `offsetFixed` is deprecated. Use `offsetFixedTop` instead."); + } + + const self = this, + offsetFixedTop = this.get('offsetFixedTop') || this.get('offsetFixed'), + offsetFixedBottom = this.get('offsetFixedBottom'), + scrollDebounce = this.get('scrollDebounce'), + onScrollMethod = function() { + Ember.run.debounce(self, 'scrollTriggered', scrollDebounce); + }; + + if (offsetFixedTop) { + this.set('offsetFixedTopElement', $(offsetFixedTop)); + } + + if (offsetFixedBottom) { + this.set('offsetFixedBottomElement', $(offsetFixedBottom)); + } + + $(document).bind('touchmove.ember-cloak', onScrollMethod); + $(window).bind('scroll.ember-cloak', onScrollMethod); + this.addObserver('wrapperTop', self, onScrollMethod); + this.addObserver('wrapperHeight', self, onScrollMethod); + this.addObserver('content.@each', self, onScrollMethod); + this.scrollTriggered(); + + this.set('scrollingEnabled', true); + }.on('didInsertElement'), + + cleanUp() { + $(document).unbind('touchmove.ember-cloak'); + $(window).unbind('scroll.ember-cloak'); + this.set('scrollingEnabled', false); + }, + + _endEvents: function() { + this.cleanUp(); + }.on('willDestroyElement') +}); + +Ember.Handlebars.helper('cloaked-collection', CloakedCollectionView); +export default CloakedCollectionView; diff --git a/app/assets/javascripts/discourse/views/cloaked.js.es6 b/app/assets/javascripts/discourse/views/cloaked.js.es6 new file mode 100644 index 000000000..ddb3a00ae --- /dev/null +++ b/app/assets/javascripts/discourse/views/cloaked.js.es6 @@ -0,0 +1,138 @@ +export default Ember.View.extend({ + attributeBindings: ['style'], + _containedView: null, + _scheduled: null, + + init: function() { + this._super(); + this._scheduled = false; + this._childViews = []; + }, + + setContainedView(cv) { + if (this._childViews[0]) { + this._childViews[0].destroy(); + this._childViews[0] = cv; + } + + if (cv) { + cv.set('_parentView', this); + cv.set('templateData', this.get('templateData')); + this._childViews[0] = cv; + } else { + this._childViews.clear(); + } + + if (this._scheduled) return; + this._scheduled = true; + this.set('_containedView', cv); + Ember.run.schedule('render', this, this.updateChildView); + }, + + render(buffer) { + const element = buffer.element(); + const dom = buffer.dom; + + this._childViewsMorph = dom.appendMorph(element); + }, + + updateChildView() { + this._scheduled = false; + if (!this._elementCreated || this.isDestroying || this.isDestroyed) { return; } + + const childView = this._containedView; + if (childView && !childView._elementCreated) { + this._renderer.renderTree(childView, this, 0); + } + }, + + /** + Triggers the set up for rendering a view that is cloaked. + + @method uncloak + */ + uncloak() { + const state = this._state || this.state; + if (state !== 'inDOM' && state !== 'preRender') { return; } + + if (!this._containedView) { + const model = this.get('content'), + container = this.get('container'); + + let controller; + + // Wire up the itemController if necessary + const controllerName = this.get('cloaksController'); + if (controllerName) { + const controllerFullName = 'controller:' + controllerName; + let factory = container.lookupFactory(controllerFullName); + + // let ember generate controller if needed + if (!factory) { + factory = Ember.generateControllerFactory(container, controllerName, model); + + // inform developer about typo + Ember.Logger.warn('ember-cloaking: can\'t lookup controller by name "' + controllerFullName + '".'); + Ember.Logger.warn('ember-cloaking: using ' + factory.toString() + '.'); + } + + const parentController = this.get('controller'); + controller = factory.create({ model, parentController, target: parentController }); + } + + const 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 + }); + + this.setContainedView(this.createChildView(this.get('cloaks'), createArgs)); + } + }, + + /** + Removes the view from the DOM and tears down all observers. + + @method cloak + */ + cloak() { + const self = this; + + if (this._containedView && (this._state || this.state) === 'inDOM') { + const style = 'height: ' + this.$().height() + 'px;'; + this.set('style', style); + this.$().prop('style', style); + + + // We need to remove the container after the height of the element has taken + // effect. + Ember.run.schedule('afterRender', function() { + self.setContainedView(null); + }); + } + }, + + _setHeights: function(){ + if (!this._containedView) { + // setting default height + // but do not touch if height already defined + if(!this.$().height()){ + let defaultHeight = 100; + if(this.get('defaultHeight')) { + defaultHeight = this.get('defaultHeight'); + } + + this.$().css('height', defaultHeight); + } + } + }.on('didInsertElement') +}); + diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index a7113b3c8..cf5bbda7b 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -42,6 +42,7 @@ //= require ./discourse/views/container //= require ./discourse/views/modal-body //= require ./discourse/views/flag +//= require ./discourse/views/cloaked //= require ./discourse/components/combo-box //= require ./discourse/views/button //= require ./discourse/components/dropdown-button diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js index 12667f354..a76153ed7 100644 --- a/app/assets/javascripts/vendor.js +++ b/app/assets/javascripts/vendor.js @@ -36,7 +36,6 @@ //= require rsvp.js //= require show-html.js //= require lock-on.js -//= require ember-cloaking //= require break_string //= require buffered-proxy //= require jquery.autoellipsis-1.0.10.min.js diff --git a/vendor/assets/javascripts/ember-cloaking.js b/vendor/assets/javascripts/ember-cloaking.js deleted file mode 100644 index e47030abc..000000000 --- a/vendor/assets/javascripts/ember-cloaking.js +++ /dev/null @@ -1,451 +0,0 @@ -(function () { - - /** - Display a list of cloaked items - - @class CloakedCollectionView - @extends Ember.CollectionView - @namespace Ember - **/ - Ember.CloakedCollectionView = Ember.CollectionView.extend({ - cloakView: Ember.computed.alias('itemViewClass'), - topVisible: null, - bottomVisible: null, - offsetFixedTopElement: null, - offsetFixedBottomElement: null, - loadingHTML: 'Loading...', - scrollDebounce: 10, - - init: function() { - var cloakView = this.get('cloakView'), - idProperty = this.get('idProperty'), - uncloakDefault = !!this.get('uncloakDefault'); - - // Set the slack ratio differently to allow for more or less slack in preloading - var slackRatio = parseFloat(this.get('slackRatio')); - if (!slackRatio) { this.set('slackRatio', 1.0); } - - this.set('itemViewClass', Ember.CloakedView.extend({ - classNames: [cloakView + '-cloak'], - cloaks: cloakView, - preservesContext: this.get('preservesContext') === 'true', - cloaksController: this.get('itemController'), - defaultHeight: this.get('defaultHeight'), - - init: function() { - this._super(); - - if (idProperty) { - this.set('elementId', cloakView + '-cloak-' + this.get('content.' + idProperty)); - } - if (uncloakDefault) { - this.uncloak(); - } else { - this.cloak(); - } - } - })); - - this._super(); - Ember.run.next(this, 'scrolled'); - }, - - - /** - If the topmost visible view changed, we will notify the controller if it has an appropriate hook. - - @method _topVisibleChanged - @observes topVisible - **/ - _topVisibleChanged: function() { - var controller = this.get('controller'); - if (controller.topVisibleChanged) { controller.topVisibleChanged(this.get('topVisible')); } - }.observes('topVisible'), - - /** - If the bottommost visible view changed, we will notify the controller if it has an appropriate hook. - - @method _bottomVisible - @observes bottomVisible - **/ - _bottomVisible: function() { - var controller = this.get('controller'); - if (controller.bottomVisibleChanged) { controller.bottomVisibleChanged(this.get('bottomVisible')); } - }.observes('bottomVisible'), - - /** - Binary search for finding the topmost view on screen. - - @method findTopView - @param {Array} childViews the childViews to search through - @param {Number} windowTop The top of the viewport to search against - @param {Number} min The minimum index to search through of the child views - @param {Number} max The max index to search through of the child views - @returns {Number} the index into childViews of the topmost view - **/ - findTopView: function(childViews, viewportTop, min, max) { - if (max < min) { return min; } - - var wrapperTop = this.get('wrapperTop')>>0; - - while(max>min){ - var mid = Math.floor((min + max) / 2), - // in case of not full-window scrolling - $view = childViews[mid].$(), - viewBottom = $view.position().top + wrapperTop + $view.height(); - - if (viewBottom > viewportTop) { - max = mid-1; - } else { - min = mid+1; - } - } - - return min; - }, - - - /** - Determine what views are onscreen and cloak/uncloak them as necessary. - - @method scrolled - **/ - scrolled: function() { - if (!this.get('scrollingEnabled')) { return; } - - var childViews = this.get('childViews'); - if ((!childViews) || (childViews.length === 0)) { return; } - - var self = this, - toUncloak = [], - onscreen = [], - onscreenCloaks = [], - // calculating viewport edges - $w = $(window), - 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 = this.get('wrapperHeight') ? this.$().height() : $('body').height(), - bottomView = topView, - offsetFixedTopElement = this.get('offsetFixedTopElement'), - offsetFixedBottomElement = this.get('offsetFixedBottomElement'); - - if (windowBottom > bodyHeight) { windowBottom = bodyHeight; } - if (viewportBottom > bodyHeight) { viewportBottom = bodyHeight; } - - if (offsetFixedTopElement) { - windowTop += (offsetFixedTopElement.outerHeight(true) || 0); - } - - if (offsetFixedBottomElement) { - windowBottom -= (offsetFixedBottomElement.outerHeight(true) || 0); - } - - // Find the bottom view and what's onscreen - while (bottomView < childViews.length) { - var view = childViews[bottomView], - $view = view.$(); - - if (!$view) { break; } - - // in case of not full-window scrolling - var scrollOffset = this.get('wrapperTop') || 0, - viewTop = $view.offset().top + scrollOffset, - viewBottom = viewTop + $view.height(); - - if (viewTop > viewportBottom) { break; } - toUncloak.push(view); - - if (viewBottom > windowTop && viewTop <= windowBottom) { - onscreen.push(view.get('content')); - onscreenCloaks.push(view); - } - - bottomView++; - } - if (bottomView >= childViews.length) { bottomView = childViews.length - 1; } - - // If our controller has a `sawObjects` method, pass the on screen objects to it. - var controller = this.get('controller'); - if (onscreen.length) { - this.setProperties({topVisible: onscreen[0], bottomVisible: onscreen[onscreen.length-1]}); - if (controller && controller.sawObjects) { - Em.run.schedule('afterRender', function() { - controller.sawObjects(onscreen); - }); - } - } else { - this.setProperties({topVisible: null, bottomVisible: null}); - } - - var toCloak = childViews.slice(0, topView).concat(childViews.slice(bottomView+1)); - - this._uncloak = toUncloak; - if(this._nextUncloak){ - Em.run.cancel(this._nextUncloak); - this._nextUncloak = null; - } - - Em.run.schedule('afterRender', this, function() { - onscreenCloaks.forEach(function (v) { - if(v && v.uncloak) { - v.uncloak(); - } - }); - toCloak.forEach(function (v) { v.cloak(); }); - if (self._nextUncloak) { Em.run.cancel(self._nextUncloak); } - self._nextUncloak = Em.run.later(self, self.uncloakQueue,50); - }); - - for (var j=bottomView; j0){ - var view = this._uncloak.shift(); - if(view && view.uncloak && !view._containedView){ - Em.run.schedule('afterRender', view, view.uncloak); - processed++; - } - } - if(this._uncloak.length === 0){ - this._uncloak = null; - } else { - Em.run.schedule('afterRender', self, function(){ - if(self._nextUncloak){ - Em.run.cancel(self._nextUncloak); - } - self._nextUncloak = Em.run.next(self, function(){ - if(self._nextUncloak){ - Em.run.cancel(self._nextUncloak); - } - self._nextUncloak = Em.run.later(self,self.uncloakQueue,delay); - }); - }); - } - } - }, - - scrollTriggered: function() { - Em.run.scheduleOnce('afterRender', this, 'scrolled'); - }, - - _startEvents: function() { - if (this.get('offsetFixed')) { - Em.warn("Cloaked-collection's `offsetFixed` is deprecated. Use `offsetFixedTop` instead."); - } - - var self = this, - offsetFixedTop = this.get('offsetFixedTop') || this.get('offsetFixed'), - offsetFixedBottom = this.get('offsetFixedBottom'), - scrollDebounce = this.get('scrollDebounce'), - onScrollMethod = function() { - Ember.run.debounce(self, 'scrollTriggered', scrollDebounce); - }; - - if (offsetFixedTop) { - this.set('offsetFixedTopElement', $(offsetFixedTop)); - } - - if (offsetFixedBottom) { - this.set('offsetFixedBottomElement', $(offsetFixedBottom)); - } - - $(document).bind('touchmove.ember-cloak', onScrollMethod); - $(window).bind('scroll.ember-cloak', onScrollMethod); - this.addObserver('wrapperTop', self, onScrollMethod); - this.addObserver('wrapperHeight', self, onScrollMethod); - this.addObserver('content.@each', self, onScrollMethod); - this.scrollTriggered(); - - this.set('scrollingEnabled', true); - }.on('didInsertElement'), - - cleanUp: function() { - $(document).unbind('touchmove.ember-cloak'); - $(window).unbind('scroll.ember-cloak'); - this.set('scrollingEnabled', false); - }, - - _endEvents: function() { - this.cleanUp(); - }.on('willDestroyElement') - }); - - - /** - A cloaked view is one that removes its content when scrolled off the screen - - @class CloakedView - @extends Ember.View - @namespace Ember - **/ - Ember.CloakedView = Ember.View.extend({ - attributeBindings: ['style'], - _containedView: null, - _scheduled: null, - - init: function() { - this._super(); - this._scheduled = false; - this._childViews = []; - }, - - setContainedView: function(cv) { - if (this._childViews[0]) { - this._childViews[0].destroy(); - this._childViews[0] = cv; - } - - if (cv) { - cv.set('_parentView', this); - cv.set('templateData', this.get('templateData')); - this._childViews[0] = cv; - } else { - this._childViews.clear(); - } - - if (this._scheduled) return; - this._scheduled = true; - this.set('_containedView', cv); - Ember.run.schedule('render', this, this.updateChildView); - }, - - render: function (buffer) { - var el = buffer.element(); - this._childViewsMorph = buffer.dom.createMorph(el, null, null, el); - }, - - updateChildView: function () { - this._scheduled = false; - if (!this._elementCreated || this.isDestroying || this.isDestroyed) { return; } - - var childView = this._containedView; - if (childView && !childView._elementCreated) { - this._renderer.renderTree(childView, this, 0); - } - }, - - /** - Triggers the set up for rendering a view that is cloaked. - - @method uncloak - */ - uncloak: function() { - var state = this._state || this.state; - if (state !== 'inDOM' && state !== 'preRender') { return; } - - if (!this._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-cloaking: can\'t lookup controller by name "' + controllerFullName + '".'); - Ember.Logger.warn('ember-cloaking: 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 - }); - - this.setContainedView(this.createChildView(this.get('cloaks'), createArgs)); - } - }, - - /** - Removes the view from the DOM and tears down all observers. - - @method cloak - */ - cloak: function() { - var self = this; - - if (this._containedView && (this._state || this.state) === 'inDOM') { - var style = 'height: ' + this.$().height() + 'px;'; - this.set('style', style); - this.$().prop('style', style); - - - // We need to remove the container after the height of the element has taken - // effect. - Ember.run.schedule('afterRender', function() { - self.setContainedView(null); - }); - } - }, - - _setHeights: function(){ - if (!this._containedView) { - // setting default height - // but do not touch if height already defined - if(!this.$().height()){ - var defaultHeight = 100; - if(this.get('defaultHeight')) { - defaultHeight = this.get('defaultHeight'); - } - - this.$().css('height', defaultHeight); - } - } - }.on('didInsertElement') - }); - - Ember.Handlebars.registerHelper('cloaked-collection', function(options) { - var hash = options.hash, - types = options.hashTypes; - - for (var prop in hash) { - if (types[prop] === 'ID') { - hash[prop + 'Binding'] = hash[prop]; - delete hash[prop]; - } - } - return Ember.Handlebars.helpers.view.call(this, Ember.CloakedCollectionView, options); - }); - -})();