balanced/balanced-dashboard

View on GitHub
app/models/core/model-array.js

Summary

Maintainability
C
1 day
Test Coverage
import LoadPromise from "./mixins/load-promise";
import TypeMappings from "./type-mappings";

var getAdapter = function() {
    return BalancedApp.__container__.lookup("adapter:main");
};

var ModelArray = Ember.ArrayProxy.extend(LoadPromise, {
    isLoaded: false,
    hasNextPage: false,
    loadingNextPage: false,

    loadNextPage: function() {
        var self = this;

        var promise = this.resolveOn('didLoad');
        self.set('loadingNextPage', true);

        if (this.get('hasNextPage')) {
            var typeClass = this.get('typeClass');
            getAdapter().get(typeClass, this.get('next_uri'), function(json) {
                var deserializedJson = typeClass.serializer.extractCollection(json);
                self._populateModels(deserializedJson);
                self.set('loadingNextPage', false);
            });
        } else {
            promise.reject(this);
            self.set('loadingNextPage', false);
        }

        return promise;
    },

    loadAll: function() {
        var self = this;
        var loadAll = _.bind(this.loadAll, this);

        if (this.get('isLoaded')) {
            _.defer(function() {
                if (self.get('hasNextPage') && !self.get('loadingNextPage')) {
                    self.loadNextPage().then(loadAll);
                }
            });
        } else {
            this.one('didLoad', loadAll);
        }
    },

    reload: function() {
        var deferred = Ember.RSVP.defer();
        if (!this.get('isLoaded')) {
            return this;
        }

        var self = this;
        this.set('isLoaded', false);
        var typeClass = this.get('typeClass');

        getAdapter().get(this.constructor, this.get('uri'), function(json) {
            // todo, maybe we should go through and reload each item rather
            // than nuking and re-adding
            self.clear();
            var deserializedJson = typeClass.serializer.extractCollection(json);
            self._populateModels(deserializedJson);
            deferred.resolve(self);
        }, function() {
            deferred.reject(self);
        });
        return deferred.promise;
    },

    _populateModels: function(json) {
        var self = this;

        var typeClass = this.get('typeClass');

        var itemsArray;
        if (json && $.isArray(json)) {
            itemsArray = json;
            this.setProperties({
                next_uri: undefined,
                hasNextPage: false,
                counts: {},
                total: json.length
            });
        } else {
            if (json && json.items && $.isArray(json.items)) {
                itemsArray = json.items;

                if (json.linked) {
                    this.set('linked', json.linked);
                }

                if (json.next_uri) {
                    this.set('next_uri', json.next_uri);
                    this.set('hasNextPage', true);
                } else {
                    this.set('next_uri', undefined);
                    this.set('hasNextPage', false);
                }

                this.set('counts', json.counts);
                this.set('total', json.total);
            } else {
                this.set('isError', true);
                return;
            }
        }

        var typedObjects = _.map(itemsArray, function(item) {
            var typedObj = typeClass._materializeLoadedObjectFromAPIResult(item);

            // if an object is deleted, remove it from the collection
            typedObj.on('didDelete', function() {
                self.removeObject(typedObj);
            });

            return typedObj;
        });

        this.addObjects(typedObjects);
        this.set('isLoaded', true);
        this.trigger('didLoad');
    },

    _handleError: function(jqXHR, textStatus, errorThrown) {
        if (jqXHR.status === 400) {
            this.set('isValid', false);
            this.trigger('becameInvalid', jqXHR.responseText);
        } else {
            this.set('isError', true);
            this.trigger('becameError', jqXHR.responseText);
        }
    }
});

ModelArray.reopenClass({
    newArrayLoadedFromUri: function(uri, defaultType) {
        var typeClass = TypeMappings.typeClass(defaultType);
        var modelObjectsArray = this.create({
            content: Ember.A(),
            typeClass: typeClass,
            uri: uri
        });

        if (!uri) {
            return modelObjectsArray;
        }

        modelObjectsArray.set('isLoaded', false);
        getAdapter().get(typeClass, uri, function(json) {
            var deserializedJson = typeClass.serializer.extractCollection(json);
            modelObjectsArray._populateModels(deserializedJson);
        }, function(jqXHR, textStatus, errorThrown) {
            modelObjectsArray._handleError(jqXHR, textStatus, errorThrown);
        });

        return modelObjectsArray;
    },

    newArrayCreatedFromJson: function(json, defaultType) {
        var typeClass = TypeMappings.typeClass(defaultType);
        var modelObjectsArray = this.create({
            content: Ember.A(),
            typeClass: typeClass,
            uri: null
        });

        if (!json) {
            return modelObjectsArray;
        }

        var deserializedJson = typeClass.serializer.extractCollection(json);
        modelObjectsArray._populateModels(deserializedJson);

        return modelObjectsArray;
    }
});

export default ModelArray;