API Docs for: 1.0.0
Show:

File: Resources/public/js/views/services/ez-locationviewviewservice.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-locationviewviewservice', function (Y) {
    "use strict";
    /**
     * Provides the view service component for the location view
     *
     * @module ez-locationviewviewservice
     */
    Y.namespace('eZ');

    /**
     * Location view view service.
     *
     * Loads the models needed by the location view
     *
     * @namespace eZ
     * @class LocationViewViewService
     * @constructor
     * @extends eZ.ViewService
     */
    Y.eZ.LocationViewViewService = Y.Base.create('locationViewViewService', Y.eZ.ViewService, [Y.eZ.DraftConflict], {
        initializer: function () {
            this.on('*:editAction', this._editContent);
            this.on('*:sendToTrashAction', this._sendContentToTrashConfirmBox);
            this.on('*:deleteContentAction', this._confirmDeleteContent);
            this.on('*:moveAction', this._selectLocation);
            this.on('*:translateContent', this._translateContent);
            this.on('*:sortUpdate', this._updateSorting);
            this.after('*:requestChange', this._setLanguageCode);

            this._setLanguageCode();
        },

        /**
         * editAction event handler, makes the application navigate to edit the
         * content available in the event facade
         *
         * @method _editContent
         * @protected
         * @param {Object} e event facade of the editAction event
         */
        _editContent: function (e) {
            this._fireEditContentRequest(
                this.get('location').get('contentInfo'),
                this.get('contentType')
            );
        },

        /**
         * `sendToTrashAction` event handler,
         * it asks confirmation to the user before sending the location to the trash.
         *
         * @method _sendContentToTrashConfirmBox
         * @protected
         * @param {Object} e event facade of the sendToTrashAction event
         */
        _sendContentToTrashConfirmBox: function (e) {
            e.preventDefault();
            this.fire('confirmBoxOpen', {
                config: {
                    title: Y.eZ.trans('confirmed.send.to.trash', {}, 'locationview'),
                    confirmHandler: Y.bind(function () {
                        this._sendToTrash(e.content);
                    }, this)
                },
            });
        },

        /**
         * `deleteContentAction` event handler,
         * it asks confirmation to the user before delete the content item.
         *
         * @method _confirmDeleteContent
         * @protected
         * @param {Object} e event facade of the deleteAction event
         */
        _confirmDeleteContent: function (e) {
            e.preventDefault();
            this.fire('confirmBoxOpen', {
                config: {
                    title: Y.eZ.trans('confirmed.delete', {}, 'locationview'),
                    confirmHandler: Y.bind(this._deleteContent, this),
                },
            });
        },

        /**
         * moveAction event handler, launch the universal discovery widget
         * to choose a location to move the content
         *
         * @method _selectLocation
         * @protected
         * @param {EventFacade} e
         */
        _selectLocation: function (e) {
            this.fire('contentDiscover', {
                config: {
                    title: Y.eZ.trans('select.location.move.to', {}, 'locationview'),
                    contentDiscoveredHandler: Y.bind(this._moveContent, this),
                    isSelectable: function (contentStruct) {
                        return contentStruct.contentType.get('isContainer');
                    },
                },
            });
        },

        /**
         * Sends location to trash, triggering loading parent location and notifications
         *
         * @method _sendToTrash
         * @protected
         */
        _sendToTrash: function () {
            var that = this,
                location = this.get('location'),
                locationId = location.get('id'),
                path = this.get('path'),
                content = this.get('content'),
                parentLocation = path[path.length - 1];

            this._notify(
                Y.eZ.trans('sending.to.trash', {name: content.get('name')}, 'locationview'),
                'send-to-trash-' + locationId,
                'started',
                0
            );

            location.trash({api: this.get('capi')}, Y.bind(that._afterSendToTrashCallback, that, parentLocation, content));
        },

        /**
         * Deletes the the content item, triggering loading parent location and notifications
         *
         * @method _deleteContent
         * @protected
         */
        _deleteContent: function () {
            var path = this.get('path'),
                content = this.get('content'),
                parentLocation = path[path.length - 1];

            this._notify(
                Y.eZ.trans('deleting.content', {name: content.get('name')}, 'locationview'),
                'delete-' + content.get('id'),
                'started',
                0
            );

            content.delete({api: this.get('capi')}, Y.bind(this._afterDeleteCallback, this, parentLocation, content));
        },

        /**
         * Send to trash callback triggering notifications and making app to navigate to parent location
         *
         * @method _afterSendToTrashCallback
         * @protected
         * @param {eZ.Location} parentLocation the parent location to which app will navigate to
         * @param {eZ.Content} content the content to be trashed
         * @param {Boolean} error
         */
        _afterSendToTrashCallback: function (parentLocation, content, error) {
            var app = this.get('app'),
                location = this.get('location'),
                locationId = location.get('id'),
                contentName = content.get('name');

            if (error) {
                this._notify(
                    Y.eZ.trans('failed.sending.to.trash', {name: contentName}, 'locationview'),
                    'send-to-trash-' + locationId,
                    'error',
                    0
                );
                return;
            }

            this._notify(
                Y.eZ.trans('sent.to.trash', {name: contentName}, 'locationview'),
                'send-to-trash-' + locationId,
                'done',
                5
            );

            /**
             * Fired when the content is sent to trash
             *
             * @event sentToTrash
             * @param {eZ.Location} location
             */
            this.fire('sentToTrash', {location: location});

            app.navigateTo('viewLocation', {
                id: parentLocation.get('id'),
                languageCode: content.get('mainLanguageCode')
            });
        },

        /**
         * Delete content item callback triggering notifications and making app to navigate to parent location
         *
         * @method _afterDeleteCallback
         * @protected
         * @param {eZ.Location} parentLocation the parent location to which app will navigate to
         * @param {eZ.Content} content the content item that has been deleted
         * @param {Boolean} error
         */
        _afterDeleteCallback: function (parentLocation, content, error) {
            var app = this.get('app'),
                contentName = content.get('name');

            if (error) {
                this._notify(
                    Y.eZ.trans('failed.deleting.content', {name: contentName}, 'locationview'),
                    'delete-' + content.get('id'),
                    'error',
                    0
                );
                return;
            }

            this._notify(
                Y.eZ.trans('deleted.content', {name: contentName}, 'locationview'),
                'delete-' + content.get('id'),
                'done',
                5
            );

            /**
             * Fired when the content has been deleted
             *
             * @event deletedContent
             * @param {eZ.Content} content
             */
            this.fire('deletedContent', {content: content});

            app.navigateTo('viewLocation', {
                id: parentLocation.get('id'),
                languageCode: content.get('mainLanguageCode')
            });
        },

        /**
         * Move the content to the selected location
         *
         * @method _moveContent
         * @protected
         * @param {EventFacade} e
         */
        _moveContent: function (e) {
            var app = this.get('app'),
                initialActiveView = app.get('activeView'),
                parentLocationId = e.selection.location.get('id'),
                oldParentLocationId = this.get('location').get('id'),
                locationId = this.get('location').get('id'),
                that = this,
                content = this.get('content'),
                contentName =  content.get('name'),
                parentContentName = e.selection.contentInfo.get('name'),
                notificationIdentifier =  'move-notification-' + parentLocationId + '-' + locationId;

            this._notify(
                Y.eZ.trans('being.moved.under', {name: contentName, parentName: parentContentName}, 'locationview'),
                notificationIdentifier,
                'started', 5
            );

            this.get('location').move({api: this.get('capi')},  parentLocationId, function (error, response) {
                if (error) {
                    that._notify(
                        Y.eZ.trans('failed.moving', {}, 'locationview'),
                        notificationIdentifier, 'error', 0
                    );
                    return;
                }

                that._notify(
                    Y.eZ.trans('moved.under', {name: contentName, parentName: parentContentName}, 'locationview'),
                    notificationIdentifier,
                    'done',
                    5
                );
                /**
                 * Fired when the content is moved
                 *
                 * @event movedContent
                 * @param {eZ.Location} location
                 * @param {String} oldParentLocationId
                 */
                that.fire('movedContent', {location: that.get('location'), oldParentLocationId: oldParentLocationId});
                if ( app.get('activeView') === initialActiveView ) {
                    app.navigateTo(
                        'viewLocation',
                        {id: response.getHeader('location'), languageCode: content.get('mainLanguageCode')}
                    );
                }
            });
        },

        /**
         * translate event handler, makes the application to navigate to edit content available
         * in the facade with given language and base language
         *
         * @method _translateContent
         * @protected
         * @param {EventFacade} e
         */
        _translateContent: function (e) {
            var app = this.get('app'),
                routeName = 'editContent',
                routeParams = {
                    id: e.content.get('id'),
                    languageCode: e.toLanguageCode,
                };

            if (e.baseLanguageCode) {
                routeParams.baseLanguageCode = e.baseLanguageCode;
                routeName = 'translateContent';
            }

            app.navigate(
                app.routeUri(routeName, routeParams)
            );
        },

        /**
         * Update the sort methods of the location
         *
         * @method _updateSorting
         * @protected
         * @param {EventFacade} e
         */
        _updateSorting: function (e) {
            var loadOptions = {api: this.get('capi')},
                location = this.get('location'),
                notificationIdentifier = 'sort-change-' + e.sortType + '-' + e.sortOrder;

            this._notify(
                Y.eZ.trans('updating.sort.method', {}, 'locationview'),
                notificationIdentifier,
                'started',
                5
            );

            location.updateSorting(loadOptions, e.sortType, e.sortOrder, Y.bind(function (error, response) {
                if (!error) {
                    this._notify(
                        Y.eZ.trans('updated.sort.method', {}, 'locationview'),
                        notificationIdentifier,
                        'done',
                        5
                    );
                    /**
                     * Fired when the sortOrder and/or sortField have been
                     * successfully updated.
                     *
                     * @event updatedLocationSorting
                     * @param {eZ.Location} location the Location that has been
                     * updated
                     */
                    this.fire('updatedLocationSorting', {
                        location: location,
                    });
                } else {
                    this._notify(
                        Y.eZ.trans('failed.updating.sort.method', {}, 'locationview'),
                        notificationIdentifier,
                        'error',
                        0
                    );
                }
            }, this));
        },

        /**
         * Fire 'notify' event
         *
         * @method _notify
         * @protected
         * @param {String} text the text shown during the notification
         * @param {String} identifier the identifier of the notification
         * @param {String} state the state of the notification
         * @param {Integer} timeout the number of second, the notification will be shown
         */
        _notify: function (text, identifier, state, timeout) {
            this.fire('notify', {
                notification: {
                    text: text,
                    identifier: identifier,
                    state: state,
                    timeout: timeout,
                }
            });
        },

        /**
         * Loads the location, the content and the path for the location id
         * available in the request and calls the next callback once it's done.
         *
         * @method _load
         * @protected
         * @param {Function} next
         */
        _load: function (next) {
            var loadOptions = {
                    api: this.get('capi')
                },
                request = this.get('request'),
                service = this,
                location = this.get('location'), content = this.get('content'),
                type = this.get('contentType');

            location.set('id', request.params.id);
            location.load(loadOptions, function (error) {
                var tasks, endLoadPath, endMainContentLoad,
                    loadContentOptions = Y.merge(loadOptions);

                loadContentOptions.languageCode = service.get('languageCode');
                if ( error ) {
                    service._error(
                        Y.eZ.trans('failed.to.load.location', {id: location.get('id')}, 'locationview')
                    );
                    return;
                }

                tasks = new Y.Parallel();

                endMainContentLoad = tasks.add();
                content.set('id', location.get('resources').Content);
                content.load(loadContentOptions, function (error) {
                    if ( error ) {
                        service._error(
                            Y.eZ.trans('failed.to.load.content', {id: content.get('id')}, 'locationview')
                        );
                        return;
                    }
                    type.set('id', content.get('resources').ContentType);
                    type.load(Y.merge(loadOptions, {loadGroups: true}), function (error) {
                        if ( error ) {
                            service._error(
                                Y.eZ.trans('failed.to.load.content.type', {id: type.get('id')}, 'locationview')
                            );
                            return;
                        }
                        endMainContentLoad();
                    });
                });

                endLoadPath = tasks.add();
                location.loadPath(loadOptions, function(error, path) {
                    if ( error ) {
                        service._error(
                            Y.eZ.trans('failed.to.load.location.path', {}, 'locationview')
                        );
                        return;
                    }

                    service.set('path', path);
                    endLoadPath();
                });

                tasks.done(function () {
                    service.get('response').view = {
                        path: service.get('path'),
                        location: service.get('location'),
                        content: service.get('content'),
                    };
                    next(service);
                });
            });
        },

        /**
         * Set languageCode attribute based on parameter from request
         *
         * @method _setLanguageCode
         * @protected
         */
        _setLanguageCode: function () {
            this.set('languageCode', this.get('request').params.languageCode);
        },

        _getViewParameters: function () {
            return {
                content: this.get('content'),
                contentType: this.get('contentType'),
                location: this.get('location'),
                path: this.get('path'),
                config: this.get('config'),
                languageCode: this.get('request').params.languageCode,
            };
        },
    }, {
        ATTRS: {
            /**
             * The viewed location
             *
             * @attribute location
             * @type Y.eZ.Location
             */
            location: {
                cloneDefaultValue: false,
                value: new Y.eZ.Location()
            },

            /**
             * The content associated with the location
             *
             * @attribute content
             * @type Y.eZ.Content
             */
            content: {
                cloneDefaultValue: false,
                value: new Y.eZ.Content()
            },

            /**
             * The content type of the content
             *
             * @attribute contentType
             * @type Y.eZ.ContentType
             */
            contentType: {
                cloneDefaultValue: false,
                value: new Y.eZ.ContentType()
            },

            /**
             * The path from the root location to the current location. Each
             * entry of the path consists of the location sorted by location depth
             *
             * @attribute path
             * @type Array
             */
            path: {
                value: []
            },

            /**
             * The language code in which the content is being viewed
             *
             * @attribute languageCode
             * @type String
             */
            languageCode: {}
        }
    });
});