API Docs for: 1.0.0
Show:

File: Resources/public/js/models/ez-locationmodel.js

/*
 * Copyright (C) eZ Systems AS. All rights reserved.
 * For full copyright and license information view LICENSE file distributed with this source code.
 */
YUI.add('ez-locationmodel', function (Y) {
    "use strict";
    /**
     * Provides the Location model cass
     *
     * @module ez-locationmodel
     */

    Y.namespace('eZ');

    /**
     * Location model
     *
     * @namespace eZ
     * @class Location
     * @constructor
     * @extends Model
     */
    Y.eZ.Location = Y.Base.create('locationModel', Y.eZ.RestModel, [], {
        /**
         * Override of the eZ.RestModel _parseStruct method to also read the content info
         *
         * @protected
         * @method _parseStruct
         * @param {Object} struct the struct to transform
         * @return {Object}
         */
        _parseStruct: function (struct) {
            var attrs;

            attrs = this.constructor.superclass._parseStruct.call(this, struct);
            attrs.contentInfo = struct.ContentInfo;

            return attrs;
        },

        /**
         * sync implementation that relies on the JS REST client.
         * For now, it supports the 'read' and 'delete' actions. The callback is
         * directly passed to the ContentService.loadLocation method.
         *
         * @method sync
         * @param {String} action the action, currently 'read' and 'delete' are supported
         * @param {Object} options the options for the sync.
         * @param {Object} options.api (required) the JS REST client instance
         * @param {Function} callback a callback executed when the operation is finished
         */
        sync: function (action, options, callback) {
            var api = options.api;

            if ( action === 'read' ) {
                api.getContentService().loadLocation(
                    this.get('id'), callback
                );
            } else if ( action === 'delete' ) {
                this._deleteLocation(options, callback);
            } else {
                callback("Only read operation is supported at the moment");
            }
        },

        /**
         * Moves location to trash. Callback is directly passed to ContentService.moveSubtree location
         *
         * @method trash
         * @param {Object} options the options for moving to trash
         * @param {Object} options.api (required) the JS REST client instance
         * @param {Function} callback
         */
        trash: function (options, callback) {
            var trashPath,
                api = options.api,
                location = this;

            api.getDiscoveryService().getInfoObject('trash', function (error, response) {
                if (error) {
                    callback(error);
                    return;
                }

                trashPath = response._href;
                api.getContentService().moveSubtree(
                    location.get('id'), trashPath, callback
                );
            });
        },

        /**
         * Moves the location under the given parenLocationId.
         *
         * @method move
         * @param {Object} options the options for the move.
         * @param {Object} options.api (required) the JS REST client instance
         * @param {String} parentLocationId the location id where we should move the content
         * @param {Function} callback a callback executed when the operation is finished
         */
        move: function (options, parentLocationId, callback) {
            options.api.getContentService().moveSubtree(this.get('id'), parentLocationId, callback);
        },

        /**
         * Updates the sortfield and sortOrder of the location
         *
         * @method _updateSorting
         * @param {Object} options the required for the update
         * @param {Object} options.api (required) the JS REST client instance
         * @param {String} sortField
         * @param {String} sortOrder
         * @param {Function} callback a callback executed when the operation is finished
         */
        updateSorting: function (options, sortField, sortOrder, callback) {
            var locationUpdateStruct = options.api.getContentService().newLocationUpdateStruct();

            locationUpdateStruct.body.LocationUpdate.sortField = sortField;
            locationUpdateStruct.body.LocationUpdate.sortOrder = sortOrder;
            options.api.getContentService().updateLocation(this.get('id'), locationUpdateStruct,
                Y.bind(function (error, response) {
                    if (!error) {
                        this.set('sortField', sortField);
                        this.set('sortOrder', sortOrder);
                    }
                    callback(error, response);
                }, this)
            );
        },

        /**
         * Updates the hidden status of the location
         *
         * @protected
         * @method _updatehidden
         * @param {Object} options the required for the update
         * @param {Object} options.api (required) the JS REST client instance
         * @param {String} hidden `true` or `false` value to be set on the hidden attribute
         * @param {Function} callback a callback executed when the operation is finished
         */
        _updateHidden: function (options, hidden, callback) {
            var locationUpdateStruct = options.api.getContentService().newLocationUpdateStruct();

            locationUpdateStruct.body.LocationUpdate.hidden = hidden;
            //Remove the 2 line bellow once EZP-24899 is fixed and update unit test
            locationUpdateStruct.body.LocationUpdate.sortField = this.get('sortField');
            locationUpdateStruct.body.LocationUpdate.sortOrder = this.get('sortOrder');
            options.api.getContentService().updateLocation(this.get('id'), locationUpdateStruct,
                Y.bind(function (error, response) {
                    var updatedLocation;

                    if (!error) {
                        updatedLocation = this.parse(response);
                        this.set('hidden', updatedLocation.hidden);
                        this.set('invisible', updatedLocation.invisible);
                    }
                    callback(error, response);
                }, this)
            );
        },

        /**
         * Hides the location
         *
         * @method hide
         * @param {Object} options the required for the update
         * @param {Object} options.api (required) the JS REST client instance
         * @param {Function} callback a callback executed when the operation is finished
         */
        hide: function (options, callback) {
            this._updateHidden(options, 'true', callback);
        },

        /**
         * Reverse the hidden status of the location
         *
         * @method unhide
         * @param {Object} options the required for the update
         * @param {Object} options.api (required) the JS REST client instance
         * @param {Function} callback a callback executed when the operation is finished
         */
        unhide: function (options, callback) {
            this._updateHidden(options, 'false', callback);
        },

        /**
         * Swap the location with other location
         *
         * @method swap
         * @param {Object} options the required for the swap         *
         * @param {Object} options.api (required) the JS REST client instance
         * @param {eZ.Location} destinationLocation Location where the given one will be relocated
         * @param {Function} callback a callback executed when the operation is finished
         */
        swap: function(options, destinationLocation, callback) {
            var contentService = options.api.getContentService();

            contentService.swapLocation(this.get('id'), destinationLocation.get('id'), callback);
        },

        /**
         * Deletes the location in the repository.
         *
         * @protected
         * @method _deleteLocation
         * @param {Object} options
         * @param {Object} options.api the JS REST client instance
         * @param {Function} callback
         */
        _deleteLocation: function (options, callback) {
            var contentService = options.api.getContentService(),
                location = this;

            if ( !this.get('id') ) {
                callback(false);
                return;
            }
            contentService.deleteLocation(this.get('id'), function (error, response) {
                if ( error ) {
                    callback(error);
                    return;
                }
                location.reset();
                callback(error, response);
            });
        },

        /**
         * Update the priority of the location.
         *
         * @protected
         * @method _updatePriority
         * @param {Object} options
         * @param {Object} options.api the JS REST client instance
         * @param {Number} priority the new priority
         * @param {Function} callback
         */
        updatePriority: function (options, priority, callback) {
            var locationUpdateStruct = options.api.getContentService().newLocationUpdateStruct();

            locationUpdateStruct.body.LocationUpdate.priority = priority;
            locationUpdateStruct.body.LocationUpdate.sortField = this.get('sortField');
            locationUpdateStruct.body.LocationUpdate.sortOrder = this.get('sortOrder');
            options.api.getContentService().updateLocation(this.get('id'), locationUpdateStruct,
                Y.bind(function (error, response) {
                    if (!error) {
                        this.set('priority',priority);
                    }
                    callback(error, response);
                }, this)
            );
        },

        /**
         * Loads path of the current location. The result is the array containing
         * eZ.Location objects present on the path sorted by depth.
         * The array doesn't contain current location.
         * The result is available in the `path` attribute or in the `callback`.
         *
         * @method loadPath
         * @param {Object} options
         * @param {Object} options.api the JS REST client instance
         * @param {Function} callback
         * @param {false|Error} callback.error
         * @param {Array} callback.locations the array of Locations
         */
        loadPath: function (options, callback) {
            var locations = [],
                that = this;

            this._loadAncestors(options, function (error, response) {
                var hits;

                if (error) {
                    callback(error);
                    return;
                }

                hits = response.document.View.Result.searchHits.searchHit;

                Y.Array.each(hits, function (hit) {
                    if (hit.value.Location._href !== this.get('id')) {
                        var location = new Y.eZ.Location();

                        location.setAttrs(location.parse({document: hit.value}));
                        locations.push(location);
                    }
                }, that);

                locations.sort(function (a, b) {
                    return (a.get('depth') - b.get('depth'));
                });

                that._set('path', locations);

                callback(error, locations);
            });
        },

        /**
         * Loads ancestors of the location based on the `pathString`. The result is the REST API view
         * containing locations from the path.
         *
         * @method _loadAncestors
         * @protected
         * @param {Object} options
         * @param {Object} options.api the JS REST client instance
         * @param {Function} callback
         */
        _loadAncestors: function (options, callback) {
            var contentService = options.api.getContentService(),
                query = contentService.newViewCreateStruct('ancestors-' + this.get('locationId'), 'LocationQuery');

            query.setFilter({
                AncestorCriterion: this.get('pathString')
            });

            contentService.createView(
                query,
                callback
            );
        },

        /**
         * Returns if the location is a root one
         *
         * @method isRootLocation
         * @return {boolean}
         */
        isRootLocation: function() {
            return this.get('depth') === 1;
        },

        /**
         * Overrides the RestModel implementation to also deal with the `path` attribute
         *
         * @method toJSON
         * @return {Object}
         */
        toJSON: function () {
            var attrs = Y.eZ.RestModel.prototype.toJSON.call(this);

            if (attrs.path) {
                attrs.path = Y.Array.map(attrs.path, function (value) {
                    return value.toJSON();
                });
            }

            return attrs;
        },

        /**
         * Returns the REST API sort order based on the sortOrder attribute
         *
         * @method _getSortDirection
         * @protected
         * @deprecated Use `getSortClauseIdentifier` in the search plugin
         * @return 'ascending' or 'descending'
         */
        _getSortDirection: function () {
            return this.get('sortOrder') === 'ASC' ? 'ascending' : 'descending';
        },

        /**
         * Returns the REST API sort clause identifier based on the sortField
         * attribute.
         *
         * @method _getSortClauseIdentifier
         * @protected
         * @deprecated Use `_getSortClauseIdentifier` in the search plugin
         * @return {String|Null}
         */
        _getSortClauseIdentifier: function () {
            var sortField = this.get('sortField');

            switch(sortField) {
                case 'MODIFIED':
                    return 'DateModified';
                case 'PUBLISHED':
                    return 'DatePublished';
                case 'PATH':
                    return 'LocationPath';
                case 'SECTION':
                    return 'SectionIdentifier';
                case 'DEPTH':
                    return 'LocationDepth';
                case 'CLASS_IDENTIFIER':
                case 'CLASS_NAME':
                    console.warn(sortField + ' sort order is unsupported');
                    return null;
                case 'PRIORITY':
                    return 'LocationPriority';
                case 'NAME':
                    return 'ContentName';
                default:
                    console.warn("Unknow sortField '" + this.get('sortField') + "'");
                    return 'DateModified';
            }
        },

        /**
         * Returns the sort clause suitable for the Search Plugin based on the
         * Location's sortOrder and sortField attribute.
         *
         * @method getSortClause
         * @deprecated Use `getSortClause` in the search plugin
         * @return {Object}
         */
        getSortClause: function () {
            var clause = {},
                identifier = this._getSortClauseIdentifier();

            console.log('[DEPRECATED] `Location#getSortClause` is deprecated and will be removed from PlatformUI 2.0');
            console.log('[DEPRECATED] Please use the search plugin instead');

            if ( identifier ) {
                clause[this._getSortClauseIdentifier()] = this._getSortDirection();
            }
            return clause;
        },
    }, {
        REST_STRUCT_ROOT: "Location",
        ATTRS_REST_MAP: [
            'childCount', 'depth', 'hidden', 'invisible', 'pathString',
            'priority', 'remoteId', 'sortField', 'sortOrder',
            {'id': 'locationId'}, {'_href': 'id'},
        ],
        LINKS_MAP: ['ParentLocation', 'Content'],
        ATTRS: {
            /**
             * The location's number of child
             *
             * @attribute childCount
             * @default 0
             * @type integer
             */
            childCount: {
                value: 0
            },

            /**
             * The location's depth
             *
             * @attribute depth
             * @default 1
             * @type integer
             */
            depth: {
                value: 1
            },

            /**
             * The location's hidden flag
             *
             * @attribute hidden
             * @default false
             * @type boolean
             */
            hidden: {
                value: false
            },

            /**
             * The location's invisible flag
             *
             * @attribute invisible
             * @default false
             * @type boolean
             */
            invisible: {
                value: false
            },

            /**
             * The location's id in the eZ Publish content repository
             *
             * @attribute locationId
             * @default ''
             * @type string
             */
            locationId: {
                value: ''
            },

            /**
             * The location's path string
             *
             * @attribute pathString
             * @default ''
             * @type string
             */
            pathString: {
                value: ""
            },

            /**
             * The location's priority
             *
             * @attribute priority
             * @default 0
             * @type integer
             */
            priority: {
                value: 0
            },

            /**
             * The location's remote id
             *
             * @attribute remoteId
             * @default ''
             * @type string
             */
            remoteId: {
                value: ""
            },

            /**
             * The location's sort field
             *
             * @attribute sortField
             * @default "PATH"
             * @type string
             */
            sortField: {
                value: "PATH"
            },

            /**
             * The location's sort order
             *
             * @attribute sortOrder
             * @default "ASC"
             * @type string
             */
            sortOrder: {
                value: "ASC"
            },

            /**
             * The content info
             *
             * @attribute contentInfo
             * @type eZ.ContentInfo
             */
            contentInfo: {
                getter: function (value) {
                    var contentInfo = new Y.eZ.ContentInfo();

                    if ( value ) {
                        contentInfo.setAttrs(contentInfo.parse({document: value}));
                    }
                    return contentInfo;
                }
            },

            /**
             * The location's path. By default it is empty. You need to call the loadPath method to set this attribute.
             *
             * @attribute path
             * @default false
             * @type array
             * @readOnly
             */
            path: {
                value: false,
                readOnly: true
            },
        }
    });
});