SpontaneousCMS/spontaneous

View on GitHub
application/js/content.js

Summary

Maintainability
D
2 days
Test Coverage
// console.log('Loading Content...')

Spontaneous.Content = (function($, S) {
    'use strict';
    var dom = S.Dom;

    var Content = new JS.Class({
        include: Spontaneous.Properties,

        initialize: function(content) {
            this.content = content;
            this.update(content);
        },

        update: function(content) {
            this.set('hidden', content.hidden);
            this.set('has_unpublished_changes', content.has_unpublished_changes);
        },

        uid: function() {
            return (this.container ? this.container.uid() : '') + '/' + this.content.id;
        },
        id: function() {
            return this.content.id;
        },

        is_page: function() {
            return this.type().is_page();
        },

        target: function() {
            return this.content.target;
        },
        developer_description: function() {
            return this.type().type + '['+this.id()+']';
        },
        developer_edit_url: function() {
            return this.type().edit_url();
        },
        type: function() {
            return S.Types.type(this.content.type);
        }.cache(),

        slug: function() {
            return this.content.slug;
        },

        constantize: function(type) {
            var parts = type.split(/\./), obj = window;
            for (var i = 0, ii = parts.length; i < ii; i++) {
                obj = obj[parts[i]];
            }
            return obj;
        },

        unload: function() {
            $.each(this.field_list(), function(i, f) { f.unload(); });
            $.each(this.entries(), function(i, e) { e.unload(); });
        },

        field_list: function() {
            var type = this.type(), prototypes = type.field_prototypes, names = type.field_names;
            var fields = this.fields(), list = [];
            for (var i = 0, ii = names.length; i < ii; i++) {
                list.push(fields[names[i]]);
            }
            return list;
        }.cache(),

        // fields that should be listed in the main field column
        text_fields: function() {
            return this.filter_fields(function(f) { return !f.is_image(); });
        },
        // fields that should be saved as strings
        string_values: function() {
            var i, ii, v, values = [], fields = this.field_list();
            for (i = 0, ii = fields.length; i < ii; i++) {
                v = fields[i].stringValue();
                if (v) {
                    values.push(v);
                }
            }
            // return this.filter_fields(function(f) { return !f.is_file(); });
            return values;
        },
        image_fields: function() {
            return this.filter_fields(function(f) { return f.is_image(); });
        },
        file_fields: function() {
            return this.filter_fields(function(f) { return f.is_file(); });
        },
        filter_fields: function(filter) {
            var fields = [], all_fields = this.field_list();
            for (var i = 0, ii = all_fields.length; i < ii; i++) {
                var f = all_fields[i];
                if (filter(f)) { fields.push(f); }
            }
            return fields;
        },
        fields: function() {
            var fields = {}, type = this.type(), prototypes = type.field_prototypes;

            for (var i = 0, ii = this.content.fields.length; i < ii; i++) {
                var f = this.content.fields[i], prototype, type_class;
                prototype = prototypes[f.name];
                if (f && prototype) {
                    type_class = this.constantize(prototype.type);
                    if (!type_class) {
                        console.warn(
                            'Content#fields:',
                            'Field has invalid type', prototype.type,
                            'content_id:', this.content.id,
                            'type:', "'"+type.title+"'",
                            'field_name:', f.name
                        );
                        type_class = Spontaneous.Field.String;
                    }
                    var field = new type_class(this, f); // jshint ignore:line
                    // field.watch('value', this.field_updated.bind(this, field));
                    fields[f.name] = field;
                }
            }
            return fields;
        }.cache(),

        field: function(name) {
            return this.fields()[name];
        },
        field_updated: function(field, value) {
            this.save_field(field);
        },

        save_field: function(field) {
            var params = { field: {} };
            params.field[field.name] = {value: field.value()};
            Spontaneous.Ajax.put(this.save_path(), params, this.save_complete.bind(this));
        },

        save_path: function() {
            return ['/content', this.content.id].join('/');
        },

        save_complete: function(response) {
            if (response) {
                this.update(response);
                var fields = response.fields;
                for (var i = 0, ii = fields.length; i < ii; i++) {
                    var values = fields[i], field = this.field(values.name);
                    if (field) { field.update(values); }
                }
            }
        },

        has_fields: function() {
            return this.field_list().length > 0;
        },

        title: function() {
            return this.title_field().value();
        },

        title_field: function() {
            var self = this, title_field = self.fields()[self.type().title_field_name];
            // if we're aliasing a page with a page then it's likely that the alias type
            // won't have a title field (falling back to its target's value instead)
            // so we need to fall back to the target's title field in that base
            if (!title_field && self.type().is_alias()) {
                var target = new Content(self.target());
                title_field = target.title_field();
            }
            return title_field;
        },

        hidden: function() {
            return this.get('hidden');
        },

        hasUnpublishedChanges: function() {
            return this.content.has_unpublished_changes;
        },

        contentHashChangedAt: function() {
            // return Date.parse(this.content.content_hash_changed_at);
            return this.content.content_hash_changed_at;
        },

        entries: function() {
            if (!this.content.entries) {
                return [];
            }
            var _entries = [];
            for (var i = 0, ee = this.content.entries, ii = ee.length; i < ii; i++) {
                var entry = this.wrap_entry(ee[i]);
                _entries.push(entry);
            }
            return _entries;
        }.cache(),

        boxes: function() {
            var _boxes = [];
            if (this.content.boxes) {
                for (var i = 0, ee = this.content.boxes, ii = ee.length; i < ii; i++) {
                    _boxes.push(new S.Box(ee[i], this));
                }
            }
            return _boxes;
        }.cache(),

        has_boxes: function() {
            return (this.boxes().length > 0);
        },

        wrap_entry: function(entry) {
            var entry_class = Spontaneous.Entry;
            if (entry.is_page) {
                entry_class = Spontaneous.PageEntry;
            }
            return new entry_class(entry, this); // jshint ignore:line
        },

        allowed_types: function() {
            return this.type().allowed_types();
        },

        depth: function() {
            return this.content.depth;
        },

        destroy: function() {
            Spontaneous.Ajax.del(['/content', this.content.id].join('/'), {}, this.destroyed.bind(this));
        },
        toggle_visibility: function() {
            Spontaneous.Ajax.patch(['/content', this.content.id, 'toggle'].join('/'), {}, this.visibility_toggled.bind(this));
        },
        visibility_toggled: function(result) {
            var affected = {};
            result.forEach(function(a) {
                affected[a.id] = a.hidden;
            });
            S.page().contentVisibilityToggle(affected);
        },
        contentVisibilityToggle: function(affected) {
            var id = this.id();
            if (affected.hasOwnProperty(id)) {
                this.set('hidden', !!affected[id]);
            }
        },
        destroyed: function() {
            var page = S.Editing.get('page');
            this.trigger('destroyed', this);
            page.trigger('removed_entry', this);
        },
        reposition: function(position) {
            Spontaneous.Ajax.patch(['/content', this.content.id, 'position', position].join('/'), {}, function() {
                this.repositioned();
            }.bind(this));
        },
        repositioned: function() {
            this.trigger('repositioned');
        },
        state: function() {
            return S.State.get(this);
        },
        setFieldMetadata: function(field, key, value) {
            this.state().setFieldMetadata(field, key, value);
        },
        getFieldMetadata: function(field, key, value) {
            return this.state().getFieldMetadata(field, key);
        }
    });

    return Content;
}(jQuery, Spontaneous));