<commit_before>/**
 * conjoon
 * (c) 2002-2009 siteartwork.de/conjoon.org
 * licensing@conjoon.org
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('com.conjoon.groupware.feeds');

/**
 * Controller for previewing Feed contents.
 * This is a singleton-object and used bycom.conjoon.groupware.feeds.FeedGrid
 * to enable previewing a feed in a panel sliding out left of the grid panel,
 * aligned to the current selected cell. The panel is closable and draggable.
 * Once a panel was created, it can not be closed such that the object gets
 * destroyed.
 *
 * The preview panel depends on record properties passed from the grid to the
 * showPreview-method. The needed properties are
 *
 *

 *
id - the id of the feed to preview

 *
title - the title of the feed

 *
link - the link of the feed  of the feed to preview

 *
pubDate - the publication date of the feed

 *

 *
 * @author Thorsten Suckow-Homberg <ts@siteartwork.de>
 */
com.conjoon.groupware.feeds.FeedPreview = function() {

// {{{ private members

    var LinkInterceptor = com.conjoon.groupware.util.LinkInterceptor;

    /**
     * The y position of the last clicked cell.
     * @param {Number} clkCellY
     */
    var clkCellY = 0;

    /**
     * @type {Ext.Element} gridEl The element of the grid the preview is attached to
     */
    var gridEl = null;

    /**
     * Initial width of the preview panel.
     * @param {Number}
     */
    var width = 330;

    /**
     * Initial height of the preview panel.
     * @param {Number}
     */
    var height = 250;

    /**
     * The id of the ajax-request loading a feed-item
     * @param {Object} requestId
     */
    var requestId = null;

    /**
     * The loadMask used to mask the previewWindow.
     * @param {Ext.LoadMask} loadMask
     */
    var loadMask =null;

    /**
     * The latest record that was fully loaded into a preview panel.
     * @param {com.conjoon.groupware.feeds.ItemRecord} lastRecord
     */
    var lastRecord = null;

    /**
     * Stores the id of the last previewed feed. If a preview panel gets closed,
     * the property will be reset to <tt>null</tt>.
     */
    var activeFeedId = null;

    /**
     * The html container that is responsible for enabling animation effects
     * of the preview panel.
     */
    var container = null;

    /**
     * The panel that is used for previewing a feed content. The property will
     * hold an instance of <tt>Ext.Panel</tt> which is being reused for previewing
     * until the panel was detached from the grid.
     */
    var previewPanel = null;

    /**
     * Any window that needs to be created after detaching a preview panel from
     * it's cell will be created using this window config.
     * @param {Ext.Window}
     */
    var tmpWindow = null;

    /**
     * Any preview panel that needs to be created uses a cloned version of this
     * tmpPreview property.
     * @param {Ext.Window}
     */
    var tmpPreview = null;

    /**
     * Stores the active cell to which the preview panel is aligned.
     */
    var clkCell = null;

    /**
     * Stores the row index of the cell to which the preview panel is aligned.
     */
    var clkRowIndex = -1;

    /**
     * Stores the record information of the cell's row associated with previewing.
     * The record needs to have a id-property that holds a unique id of the
     * grid's record that was selected.
     */
    var clkRecord = null;

// }}}

// {{{ private methods

    /**
     * Returns the first left outermost columnIndex of the first column
     * that is not hidden in the grid.
     * This method is guaranteed to return a value in the range of [0, columnIndex].
     *
     * @param {Ext.grid.GridPanel} grid
     * @param {Numbe} columnIndex
     *
     * @return {Number}
     */
    var _getColumnIndex = function(grid, columnIndex)
    {
        var colModel = grid.getColumnModel();
        i = 0;
        while (i < columnIndex) {
            if (!colModel.isHidden(i)) {
                return i;
            }
            i++;
        }

        return i;
    };

    /**
     * Inits any component that is needed for displaying/animating
     * the preview panel.
     * This method will only be called once.
     */
    var initComponents = function()
    {
        container = Ext.DomHelper.append(document.body, {
            id    : 'DOM:com.conjoon.groupware.feeds.FeedPreview.container',
            style : "overflow:hidden;height:"+(height+5)+"px;width:"+width+"px"
        }, true);

    };

    /**
     * Callback.
     * Called when the preview panel's hide-animation is finished.
     */
    var onHide = function(skipAlign)
    {
        if (requestId !== null) {
            Ext.Ajax.abort(requestId);
        }
        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading..."));
        previewPanel.body.update("");
        if (!skipAlign) {
            refreshAnimSettings();
        }
    };

    /**
     * Callback.
     * Called when the preview panel's show-animation is finished.
     */
    var onShow = function()
    {
        var viewHeight  = Ext.fly(document.body).getHeight();
        var panelHeight = previewPanel.el.getHeight();

        if (clkCellY + panelHeight > viewHeight) {
            container.shift({
                y : container.getY() - (((clkCellY + panelHeight) - viewHeight) + 4)
            });
        }
    };

    /**
     * Loads the feed's data into the preview panel.
     */
    var decoratePreviewPanel = function()
    {
        if (clkRecord == null) {
            return;
        }
        if (requestId !== null) {
            Ext.Ajax.abort(requestId);
        }
        loadMask.show();
        var feedTitle = clkRecord.get('title');
        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading"));

        requestId = Ext.Ajax.request({
            url       : './groupware/feeds/get.feed.content/format/json',
            params    : {
                id                       : clkRecord.id,
                groupwareFeedsAccountsId : clkRecord.get('groupwareFeedsAccountsId')
            },
            success   : onLoadSuccess,
            failure   : onLoadFailure,
            disableCaching : true
        });
    };

    var onLoadSuccess = function(response, options)
    {
        requestId = null;
        var json = com.conjoon.util.Json;

        var responseText = response.responseText;

        if (json.isError(responseText)) {
            onLoadFailure(response, options);
            return;
        }

        var values = json.getResponseValues(responseText);
        var item   = values.item;
        if (item == null) {
            onLoadFailure(response, options);
            return;
        }

        lastRecord = com.conjoon.util.Record.convertTo(
            com.conjoon.groupware.feeds.ItemRecord,
            item,
            item.id
        );

        Ext.ux.util.MessageBus.publish(
            'com.conjoon.groupware.feeds.FeedPreview.onLoadSuccess', {
            id : item.id
        });

        previewPanel.setTitle(lastRecord.get('title'));
        previewPanel.body.update(lastRecord.get('content'));

        loadMask.hide();
    };

    var onLoadFailure = function(response, options)
    {
        var responseInspector = com.conjoon.groupware.ResponseInspector;

        var success     = responseInspector.isSuccess(response);
        var authFailure = responseInspector.isAuthenticationFailure(response);

        if (success === false && !authFailure) {
            Ext.ux.util.MessageBus.publish(
                'com.conjoon.groupware.feeds.FeedPreview.onLoadFailure',
                {id : options.params.id}
            );
        }
        responseInspector.handleFailure(response, {
            onLogin: {
                fn : function(){
                    decoratePreviewPanel();
                }
            },
            title   :  com.conjoon.Gettext.gettext("Error while loading feed item")
        });

        if (!authFailure) {
            previewPanel.close();
            loadMask.hide();
        }
    };

    /**
     * Callback.
     * Called after the panel was detached from the grid and dropped anywhere
     * on the document body.
     * Sets <tt>previewPanel</tt> to <tt>null</tt> to notify the <tt>show</tt> method
     * to create a new preview panel.
     *
     */
    var onMove = function()
    {
        if (!lastRecord) {
            previewPanel.close();
            return;
        }

        var feedItem = lastRecord.copy();
        previewPanel.close();
        com.conjoon.groupware.feeds.FeedViewBaton.showFeed(feedItem);
    };

    var visitFeedEntry = function()
    {
        if (!lastRecord) {
            return;
        }

        var link = lastRecord.get('link');

        (function() {
            this.open(LinkInterceptor.getRedirectLink(link));
        }).defer(1, window);
    };

    var openEntryInNewTab = function()
    {
        if (!lastRecord) {
            return;
        }

        var feedItem = lastRecord.copy();
        previewPanel.close();
        com.conjoon.groupware.feeds.FeedViewBaton.showFeed(feedItem);
    };

    /**
     * Creates a window for displaying feed contents.
     *
     * @return {Ext.Window} The window used for previewing.
     */
    var createPreviewWindow = function()
    {
        var win = new Ext.Window({
            cls        : 'com-conjoon-groupware-feeds-FeedPreview-panel',
            autoScroll : true,
            title      : com.conjoon.Gettext.gettext("Loading..."),
            iconCls    : 'com-conjoon-groupware-feeds-FeedPreview-Icon',
            resizable  : false,
            shadow     : false,
            height     : height,
            width      : width,
            listeners  : com.conjoon.groupware.util.LinkInterceptor.getListener(),
            bbar       : [{
                cls      : 'x-btn-text-icon',
                iconCls  : 'com-conjoon-groupware-feeds-FeedPreview-visitEntryButton-icon',
                text     : ' '+com.conjoon.Gettext.gettext("Visit entry"),
                handler  : visitFeedEntry
            }, {
                cls      : 'x-btn-text-icon',
                iconCls  : 'com-conjoon-groupware-feeds-FeedPreview-openFeedButton-icon',
                text     : ' '+com.conjoon.Gettext.gettext("Open in new tab"),
                handler  : openEntryInNewTab
            }]
        });

        win.on('render', function() {
            this.mon(this.header, 'dblclick', function(){
                onMove();
            }, this);
        }, win, {single : true});

        win.initDraggable = function() {
            Ext.Window.prototype.initDraggable.call(this);

            this.dd.b4Drag = function(e) {
                container.dom.style.overflow = "visible";
            };

            this.dd.endDrag = function(e){
                this.win.unghost(true, false);
                this.win.setPosition(0, 0);
                this.win.saveState();
                container.dom.style.overflow = "hidden";
            };
        }

        return win;
    };

    var animConfig = 'r';

    var refreshAnimSettings = function()
    {
        var x = gridEl.getX();

        // this should work in most cases - determine if the panel is rendered
        // in the left side of the workbench
        if (x <= 50) {
            x += gridEl.getSize().width;
            animConfig = 'l';
        } else {
            x -= container.getSize().width;
            animConfig = 'r';
        }

        container.setY(clkCellY);
        container.setX(x);
    };

// }}}

    return {

        /**
         * Shows the preview panel using a slide-in animation effect.
         * The preview will not been shown if ctrl or shift was pressed while
         * calling this method.
         *
         * @param {Ext.grid.GridPanel} The grid panel that calls this method.
         * @param {Number} The row index of the cell the panel is aligned to.
         * @param {Number} The column index of the cell the panel is aligned to.
         * @param {Ext.EventObject} The raw event object that triggered this method.
         */
        show : function(grid, rowIndex, columnIndex, eventObject)
        {
            // ignore showPreview if the eventObject tells us that
            // shift or ctrl was pressed
            if (eventObject.shiftKey || eventObject.ctrlKey) {
                this.hide(false);
                return;
            }

            // get the record information of the current selected cell
            clkRecord = grid.getSelectionModel().getSelected().copy();

            var pId = clkRecord.id;
            if (activeFeedId == pId) {
                // previewing is already active for this record.
                return;
            }

            // lazy create needed components
            if (container == null) {
                initComponents();
            }

            clkRowIndex = rowIndex;
            clkCell     = grid.view.getCell(rowIndex, _getColumnIndex(grid, columnIndex));
            clkCellY    = Ext.fly(clkCell).getY();
            gridEl      = grid.el;

            if (previewPanel !== null) {
                // preview panel can be reused for previewing another feed.
                // abort all pending operations
                if (requestId !== null) {
                    Ext.Ajax.abort(requestId);
                }

                previewPanel.el.stopFx();

                if (activeFeedId != null) {
                    // if the activeFeedId does not equal to zero, the
                    // previewPanel was hidden using the animation effect.
                    previewPanel.el.slideOut(animConfig, {
                                        duration : .4,
                                        callback : function(){
                                            onHide();
                                            decoratePreviewPanel();},
                                        scope:this
                                   })
                                   .slideIn(animConfig, {callback: onShow});
                } else {
                    // the preview panel was hidden using the hide method
                    // reshow and slide in.
                    container.setDisplayed(true);
                    refreshAnimSettings();
                    decoratePreviewPanel();
                    previewPanel.el.slideIn(animConfig, {callback: onShow});
                }
            } else {
                previewPanel = createPreviewWindow();
                previewPanel.render(container);

                refreshAnimSettings();

                loadMask = new Ext.LoadMask(previewPanel.el.dom);
                previewPanel.show();
                decoratePreviewPanel();
                previewPanel.el.slideIn(animConfig, {callback: onShow});

                previewPanel.on('beforeclose', this.hide, this, [true]);
                previewPanel.on('move', onMove);
            }

            activeFeedId = pId;
        },

        /**
         * Hides the preview panel.
         * Returns <tt>false</tt> to prevents bubbling the <tt>close</tt> event
         * to the Ext.Window based on the passed argument <tt>preventBubbling</tt>.
         *
         * @param {boolean} <tt>true</tt> to skip animation, <tt>false</tt>
         *                  to show.
         *
         * @todo update every call since second paramter is now deprecated!
         */
        hide : function(skipAnimation)
        {
            if (previewPanel == null || activeFeedId == null) {
                return;
            }
            if (!skipAnimation) {
                previewPanel.el.slideOut(animConfig, {duration : .4,  callback : onHide});
            } else {
                container.setDisplayed(false);
                previewPanel.el.slideOut(animConfig, {useDisplay : false, duration : .1});
                onHide(true);
            }

            activeFeedId = null;

            return false;
        }

    };

}();<commit_msg> - fixed: fixed an issue where in very rare occasions no selected row would be available due to selected/deselect actions<commit_after>/**
 * conjoon
 * (c) 2002-2009 siteartwork.de/conjoon.org
 * licensing@conjoon.org
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('com.conjoon.groupware.feeds');

/**
 * Controller for previewing Feed contents.
 * This is a singleton-object and used bycom.conjoon.groupware.feeds.FeedGrid
 * to enable previewing a feed in a panel sliding out left of the grid panel,
 * aligned to the current selected cell. The panel is closable and draggable.
 * Once a panel was created, it can not be closed such that the object gets
 * destroyed.
 *
 * The preview panel depends on record properties passed from the grid to the
 * showPreview-method. The needed properties are
 *
 *

 *
id - the id of the feed to preview

 *
title - the title of the feed

 *
link - the link of the feed  of the feed to preview

 *
pubDate - the publication date of the feed

 *

 *
 * @author Thorsten Suckow-Homberg <ts@siteartwork.de>
 */
com.conjoon.groupware.feeds.FeedPreview = function() {

// {{{ private members

    var LinkInterceptor = com.conjoon.groupware.util.LinkInterceptor;

    /**
     * The y position of the last clicked cell.
     * @param {Number} clkCellY
     */
    var clkCellY = 0;

    /**
     * @type {Ext.Element} gridEl The element of the grid the preview is attached to
     */
    var gridEl = null;

    /**
     * Initial width of the preview panel.
     * @param {Number}
     */
    var width = 330;

    /**
     * Initial height of the preview panel.
     * @param {Number}
     */
    var height = 250;

    /**
     * The id of the ajax-request loading a feed-item
     * @param {Object} requestId
     */
    var requestId = null;

    /**
     * The loadMask used to mask the previewWindow.
     * @param {Ext.LoadMask} loadMask
     */
    var loadMask =null;

    /**
     * The latest record that was fully loaded into a preview panel.
     * @param {com.conjoon.groupware.feeds.ItemRecord} lastRecord
     */
    var lastRecord = null;

    /**
     * Stores the id of the last previewed feed. If a preview panel gets closed,
     * the property will be reset to <tt>null</tt>.
     */
    var activeFeedId = null;

    /**
     * The html container that is responsible for enabling animation effects
     * of the preview panel.
     */
    var container = null;

    /**
     * The panel that is used for previewing a feed content. The property will
     * hold an instance of <tt>Ext.Panel</tt> which is being reused for previewing
     * until the panel was detached from the grid.
     */
    var previewPanel = null;

    /**
     * Any window that needs to be created after detaching a preview panel from
     * it's cell will be created using this window config.
     * @param {Ext.Window}
     */
    var tmpWindow = null;

    /**
     * Any preview panel that needs to be created uses a cloned version of this
     * tmpPreview property.
     * @param {Ext.Window}
     */
    var tmpPreview = null;

    /**
     * Stores the active cell to which the preview panel is aligned.
     */
    var clkCell = null;

    /**
     * Stores the row index of the cell to which the preview panel is aligned.
     */
    var clkRowIndex = -1;

    /**
     * Stores the record information of the cell's row associated with previewing.
     * The record needs to have a id-property that holds a unique id of the
     * grid's record that was selected.
     */
    var clkRecord = null;

// }}}

// {{{ private methods

    /**
     * Returns the first left outermost columnIndex of the first column
     * that is not hidden in the grid.
     * This method is guaranteed to return a value in the range of [0, columnIndex].
     *
     * @param {Ext.grid.GridPanel} grid
     * @param {Numbe} columnIndex
     *
     * @return {Number}
     */
    var _getColumnIndex = function(grid, columnIndex)
    {
        var colModel = grid.getColumnModel();
        i = 0;
        while (i < columnIndex) {
            if (!colModel.isHidden(i)) {
                return i;
            }
            i++;
        }

        return i;
    };

    /**
     * Inits any component that is needed for displaying/animating
     * the preview panel.
     * This method will only be called once.
     */
    var initComponents = function()
    {
        container = Ext.DomHelper.append(document.body, {
            id    : 'DOM:com.conjoon.groupware.feeds.FeedPreview.container',
            style : "overflow:hidden;height:"+(height+5)+"px;width:"+width+"px"
        }, true);

    };

    /**
     * Callback.
     * Called when the preview panel's hide-animation is finished.
     */
    var onHide = function(skipAlign)
    {
        if (requestId !== null) {
            Ext.Ajax.abort(requestId);
        }
        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading..."));
        previewPanel.body.update("");
        if (!skipAlign) {
            refreshAnimSettings();
        }
    };

    /**
     * Callback.
     * Called when the preview panel's show-animation is finished.
     */
    var onShow = function()
    {
        var viewHeight  = Ext.fly(document.body).getHeight();
        var panelHeight = previewPanel.el.getHeight();

        if (clkCellY + panelHeight > viewHeight) {
            container.shift({
                y : container.getY() - (((clkCellY + panelHeight) - viewHeight) + 4)
            });
        }
    };

    /**
     * Loads the feed's data into the preview panel.
     */
    var decoratePreviewPanel = function()
    {
        if (clkRecord == null) {
            return;
        }
        if (requestId !== null) {
            Ext.Ajax.abort(requestId);
        }
        loadMask.show();
        var feedTitle = clkRecord.get('title');
        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading"));

        requestId = Ext.Ajax.request({
            url       : './groupware/feeds/get.feed.content/format/json',
            params    : {
                id                       : clkRecord.id,
                groupwareFeedsAccountsId : clkRecord.get('groupwareFeedsAccountsId')
            },
            success   : onLoadSuccess,
            failure   : onLoadFailure,
            disableCaching : true
        });
    };

    var onLoadSuccess = function(response, options)
    {
        requestId = null;
        var json = com.conjoon.util.Json;

        var responseText = response.responseText;

        if (json.isError(responseText)) {
            onLoadFailure(response, options);
            return;
        }

        var values = json.getResponseValues(responseText);
        var item   = values.item;
        if (item == null) {
            onLoadFailure(response, options);
            return;
        }

        lastRecord = com.conjoon.util.Record.convertTo(
            com.conjoon.groupware.feeds.ItemRecord,
            item,
            item.id
        );

        Ext.ux.util.MessageBus.publish(
            'com.conjoon.groupware.feeds.FeedPreview.onLoadSuccess', {
            id : item.id
        });

        previewPanel.setTitle(lastRecord.get('title'));
        previewPanel.body.update(lastRecord.get('content'));

        loadMask.hide();
    };

    var onLoadFailure = function(response, options)
    {
        var responseInspector = com.conjoon.groupware.ResponseInspector;

        var success     = responseInspector.isSuccess(response);
        var authFailure = responseInspector.isAuthenticationFailure(response);

        if (success === false && !authFailure) {
            Ext.ux.util.MessageBus.publish(
                'com.conjoon.groupware.feeds.FeedPreview.onLoadFailure',
                {id : options.params.id}
            );
        }
        responseInspector.handleFailure(response, {
            onLogin: {
                fn : function(){
                    decoratePreviewPanel();
                }
            },
            title   :  com.conjoon.Gettext.gettext("Error while loading feed item")
        });

        if (!authFailure) {
            previewPanel.close();
            loadMask.hide();
        }
    };

    /**
     * Callback.
     * Called after the panel was detached from the grid and dropped anywhere
     * on the document body.
     * Sets <tt>previewPanel</tt> to <tt>null</tt> to notify the <tt>show</tt> method
     * to create a new preview panel.
     *
     */
    var onMove = function()
    {
        if (!lastRecord) {
            previewPanel.close();
            return;
        }

        var feedItem = lastRecord.copy();
        previewPanel.close();
        com.conjoon.groupware.feeds.FeedViewBaton.showFeed(feedItem);
    };

    var visitFeedEntry = function()
    {
        if (!lastRecord) {
            return;
        }

        var link = lastRecord.get('link');

        (function() {
            this.open(LinkInterceptor.getRedirectLink(link));
        }).defer(1, window);
    };

    var openEntryInNewTab = function()
    {
        if (!lastRecord) {
            return;
        }

        var feedItem = lastRecord.copy();
        previewPanel.close();
        com.conjoon.groupware.feeds.FeedViewBaton.showFeed(feedItem);
    };

    /**
     * Creates a window for displaying feed contents.
     *
     * @return {Ext.Window} The window used for previewing.
     */
    var createPreviewWindow = function()
    {
        var win = new Ext.Window({
            cls        : 'com-conjoon-groupware-feeds-FeedPreview-panel',
            autoScroll : true,
            title      : com.conjoon.Gettext.gettext("Loading..."),
            iconCls    : 'com-conjoon-groupware-feeds-FeedPreview-Icon',
            resizable  : false,
            shadow     : false,
            height     : height,
            width      : width,
            listeners  : com.conjoon.groupware.util.LinkInterceptor.getListener(),
            bbar       : [{
                cls      : 'x-btn-text-icon',
                iconCls  : 'com-conjoon-groupware-feeds-FeedPreview-visitEntryButton-icon',
                text     : ' '+com.conjoon.Gettext.gettext("Visit entry"),
                handler  : visitFeedEntry
            }, {
                cls      : 'x-btn-text-icon',
                iconCls  : 'com-conjoon-groupware-feeds-FeedPreview-openFeedButton-icon',
                text     : ' '+com.conjoon.Gettext.gettext("Open in new tab"),
                handler  : openEntryInNewTab
            }]
        });

        win.on('render', function() {
            this.mon(this.header, 'dblclick', function(){
                onMove();
            }, this);
        }, win, {single : true});

        win.initDraggable = function() {
            Ext.Window.prototype.initDraggable.call(this);

            this.dd.b4Drag = function(e) {
                container.dom.style.overflow = "visible";
            };

            this.dd.endDrag = function(e){
                this.win.unghost(true, false);
                this.win.setPosition(0, 0);
                this.win.saveState();
                container.dom.style.overflow = "hidden";
            };
        }

        return win;
    };

    var animConfig = 'r';

    var refreshAnimSettings = function()
    {
        var x = gridEl.getX();

        // this should work in most cases - determine if the panel is rendered
        // in the left side of the workbench
        if (x <= 50) {
            x += gridEl.getSize().width;
            animConfig = 'l';
        } else {
            x -= container.getSize().width;
            animConfig = 'r';
        }

        container.setY(clkCellY);
        container.setX(x);
    };

// }}}

    return {

        /**
         * Shows the preview panel using a slide-in animation effect.
         * The preview will not been shown if ctrl or shift was pressed while
         * calling this method.
         *
         * @param {Ext.grid.GridPanel} The grid panel that calls this method.
         * @param {Number} The row index of the cell the panel is aligned to.
         * @param {Number} The column index of the cell the panel is aligned to.
         * @param {Ext.EventObject} The raw event object that triggered this method.
         */
        show : function(grid, rowIndex, columnIndex, eventObject)
        {
            // ignore showPreview if the eventObject tells us that
            // shift or ctrl was pressed
            if (eventObject.shiftKey || eventObject.ctrlKey) {
                this.hide(false);
                return;
            }

            // get the record information of the current selected cell
            var t = grid.getSelectionModel().getSelected();
            if (!t) {
                return;
            }
            clkRecord = t.copy();

            var pId = clkRecord.id;
            if (activeFeedId == pId) {
                // previewing is already active for this record.
                return;
            }

            // lazy create needed components
            if (container == null) {
                initComponents();
            }

            clkRowIndex = rowIndex;
            clkCell     = grid.view.getCell(rowIndex, _getColumnIndex(grid, columnIndex));
            clkCellY    = Ext.fly(clkCell).getY();
            gridEl      = grid.el;

            if (previewPanel !== null) {
                // preview panel can be reused for previewing another feed.
                // abort all pending operations
                if (requestId !== null) {
                    Ext.Ajax.abort(requestId);
                }

                previewPanel.el.stopFx();

                if (activeFeedId != null) {
                    // if the activeFeedId does not equal to zero, the
                    // previewPanel was hidden using the animation effect.
                    previewPanel.el.slideOut(animConfig, {
                                        duration : .4,
                                        callback : function(){
                                            onHide();
                                            decoratePreviewPanel();},
                                        scope:this
                                   })
                                   .slideIn(animConfig, {callback: onShow});
                } else {
                    // the preview panel was hidden using the hide method
                    // reshow and slide in.
                    container.setDisplayed(true);
                    refreshAnimSettings();
                    decoratePreviewPanel();
                    previewPanel.el.slideIn(animConfig, {callback: onShow});
                }
            } else {
                previewPanel = createPreviewWindow();
                previewPanel.render(container);

                refreshAnimSettings();

                loadMask = new Ext.LoadMask(previewPanel.el.dom);
                previewPanel.show();
                decoratePreviewPanel();
                previewPanel.el.slideIn(animConfig, {callback: onShow});

                previewPanel.on('beforeclose', this.hide, this, [true]);
                previewPanel.on('move', onMove);
            }

            activeFeedId = pId;
        },

        /**
         * Hides the preview panel.
         * Returns <tt>false</tt> to prevents bubbling the <tt>close</tt> event
         * to the Ext.Window based on the passed argument <tt>preventBubbling</tt>.
         *
         * @param {boolean} <tt>true</tt> to skip animation, <tt>false</tt>
         *                  to show.
         *
         * @todo update every call since second paramter is now deprecated!
         */
        hide : function(skipAnimation)
        {
            if (previewPanel == null || activeFeedId == null) {
                return;
            }
            if (!skipAnimation) {
                previewPanel.el.slideOut(animConfig, {duration : .4,  callback : onHide});
            } else {
                container.setDisplayed(false);
                previewPanel.el.slideOut(animConfig, {useDisplay : false, duration : .1});
                onHide(true);
            }

            activeFeedId = null;

            return false;
        }

    };

}();<|endoftext|>


<commit_before>module.exports = function(grunt) {
    'use strict';

    var config = {
            dev: {
                path: 'dev',
                assets: 'dev/assets',
                partials: 'dev/partials'
            },
            staging: {
                path: 'staging',
                assets: 'staging/assets',
                partials: 'staging/partials'
            },
            build: {
                path: 'build',
                assets: 'build/assets',
                partials: 'build/partials'
            }
        },
        js = {
            project: [
                config.dev.assets + '/js/main.js'
            ],
            vendor: [
                config.dev.assets + '/js/vendor/plugins/*.js'
            ]
        };

    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        config: config,
        uglify_files: js.vendor.concat(js.project),
        banner: '/*! <%= pkg.projectName %> - v<%= pkg.version %> - by <%= pkg.developers %> - <%= grunt.template.today("dd-mm-yyyy") %> */\n',
        clean: {
            staging: [
                '<%= config.staging.path %>/**/*',
                '!<%= config.staging.path %>/**/.git',
                '!<%= config.staging.path %>/**/.svn'
            ],
            build: [
                '<%= config.build.path %>/**/*',
                '!<%= config.build.path %>/**/.git',
                '!<%= config.build.path %>/**/.svn'
            ],
            joycss: ['<%= config.build.assets %>/css/main.min.joy']
        },
        less: {
            staging: {
                files: {
                    '<%= config.staging.assets %>/css/main.min.css': '<%= config.dev.assets %>/less/main.less'
                },
                options: {
                    yuicompress: false
                }
            },
            build: {
                files: {
                    '<%= config.build.assets %>/css/main.min.css': '<%= config.dev.assets %>/less/main.less'
                },
                options: {
                    yuicompress: false
                }
            }
        },
        jshint: {
            files: js.project,
            options: {
                globals: {
                    jQuery: true,
                    console: true,
                    module: true
                },
                bitwise: true,
                expr: true
            }
        },
        uglify: {
            /*options: {
                banner: '<%= banner %>',
                mangle: {
                    except: ['jQuery', 'Backbone']
                }
            },
            build: {
                files: {
                    '<%= config.build.assets %>/js/main.min.js': '<%= uglify_files %>'
                }
            }*/
        },
        concat: {
            /*options: {
                separator: ';'
            },
            staging: {
                src: ['<%= uglify_files %>'],
                dest: '<%= config.staging.assets %>/js/main.min.js',
            }*/
        },
        modernizr: {
            'devFile': '<%= config.dev.assets %>/js/vendor/lib/modernizr.min.js',
            'outputFile': '<%= config.build.assets %>/js/vendor/lib/modernizr.min.js',
            'matchCommunityTests': true,
            'files': [
                '<%= uglify_files %>',
                '<%= config.dev.assets %>/js/vendor/*'
            ],
            'excludeFiles': [
                '<%= config.dev.assets %>/js/vendor/modernizr.min.js'
            ],
            'tests' : [],
        },
        joycss: {
            build: {
                options: {
                    layout: 'auto',
                    alpha: true
                },
                cwd: '<%= config.build.assets %>/css/',
                src: ['main.min.css'],
                dest: '<%= config.build.assets %>/css/'
            }
        },
        rename: {
            main: {
                files: [{
                    src: ['<%= config.build.assets %>/img/main.min-sprite.png'],
                    dest: '<%= config.build.assets %>/img/main-sprite.png'
                }]
            }
        },
        replace: {
            sprite: {
                src: ['<%= config.build.assets %>/css/*.css'],
                overwrite: true,
                replacements: [{
                    from: 'main.min-sprite.png',
                    to: 'main-sprite.png?' + '<%= new Date().getTime() %>'
                }]
            },
            esc_sprite: {
                src: ['<%= config.build.assets %>/css/*.css'],
                overwrite: true,
                replacements: [{
                    from: '?esc)',
                    to: '?<%= new Date().getTime() %>)'
                }]
            }
        },
        imagemin: {
            options: {
                optimizationLevel: 7
            },
            build: {
                expand: true,
                cwd: '<%= config.build.assets %>/img',
                src: '{,*/}*.{png,jpg,jpeg}',
                dest: '<%= config.build.assets %>/img'
            }
        },
        imageEmbed: {
            build: {
                src: ['<%= config.build.assets %>/css/main.min.css'],
                dest: '<%= config.build.assets %>/css/main.min.css',
                options: {
                    deleteAfterEncoding: true,
                    maxImageSize: 20480
                }
            }
        },
        svgmin: {
            build: {
                files: [{
                    expand: true,
                    cwd: '<%= config.dev.assets %>/svg',
                    src: ['**/*.svg'],
                    dest: '<%= config.build.assets %>/svg'
                }, {
                    expand: true,
                    cwd: '<%= config.dev.assets %>/font',
                    src: ['**/*.svg'],
                    dest: '<%= config.build.assets %>/font'
                }]
            }
        },
        htmlbuild: {
            staging: {
                src: '<%= config.dev.path %>/*.html',
                dest: '<%= config.staging.path %>/',
                options: {
                    sections: {
                        header: '<%= config.dev.partials %>/header.html',
                        footer: '<%= config.dev.partials %>/footer.html'
                    }
                }
            },
            build: {
                src: '<%= config.dev.path %>/*.html',
                dest: '<%= config.build.path %>/',
                options: {
                    sections: {
                        header: '<%= config.dev.partials %>/header.html',
                        footer: '<%= config.dev.partials %>/footer.html'
                    }
                }
            }
        },
        useminPrepare: {
            options: {
                dest: '<%= config.build.path %>',
                root: '<%= config.dev.path %>'
            },
            html: '<%= config.build.path %>/index.html'
        },
        usemin: {
            options: {
                assetsDirs: ['<%= config.dev.path %>'],
                dirs: ['<%= config.build.path %>']
            },
            html: ['<%= config.build.path %>/{,*/}*.html']
        },
        htmlmin: {
            build: {
                options: {
                    removeComments: true,
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeRedundantAttributes: false,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true
                },
                expand: true,
                cwd: '<%= config.build.path %>',
                src: ['**/*.html'],
                dest: '<%= config.build.path %>'
            }
        },
        htmlcompressor: {
            build: {
                options: {
                    type: 'html',
                    preserveServerScript: true,
                    compressJs: true
                },
                expand: true,
                cwd: '<%= config.build.path %>',
                src: ['**/*.html'],
                dest: '<%= config.build.path %>'
            }
        },
        cmq: {
            build: {
                options: {
                    log: 'true'
                },
                files: {
                    '<%= config.build.assets %>/css/': ['<%= config.build.assets %>/css/*.css']
                }
            }
        },
        csso: {
            build: {
                options: {
                    report: 'gzip',
                    banner: '<%= banner %>'
                },
                files: {
                    '<%= config.build.assets %>/css/main.min.css': ['<%= config.build.assets %>/css/main.min.css']
                }
            }
        },
        cachebreaker: {
            js: {
                asset_url: 'assets/js/main.min.js',
                files: {
                    src: '<%= config.build.path %>/*.html'
                }
            },
            css: {
                asset_url: 'assets/css/main.min.css',
                files: {
                    src: '<%= config.build.path %>/*.html'
                }
            }
        },
        copy: {
            staging: {
                files: [{
                    expand: true,
                    //dot: true,
                    cwd: '<%= config.dev.assets %>',
                    dest: '<%= config.staging.assets %>',
                    src: [
                        '*.{ico,png,txt,json}',
                        '.htaccess',
                        'img/**/*',
                        'swf/**/*',
                        'css/**/*',
                        'js/**/*',
                        'font/**/*'
                    ]
                }]
            },
            build: {
                files: [{
                    expand: true,
                    //dot: true,
                    cwd: '<%= config.dev.assets %>',
                    dest: '<%= config.build.assets %>',
                    src: [
                        '*.{ico,png,txt,json}',
                        '.htaccess',
                        'img/**/*',
                        'swf/**/*',
                        'css/**/*',
                        'font/**/*'
                    ]
                }]
            }
        },
        watch: {
            scripts: {
                files: [
                    '<%= config.dev.assets %>/js/*.js',
                    '<%= config.dev.assets %>/js/**/*.js'
                ],
                tasks: ['jshint', 'concat']
            },
            less: {
                files: [
                    '<%= config.dev.assets %>/less/**/*.less',
                    '<%= config.dev.assets %>/less/*.less'
                ],
                tasks: ['less:staging'],
                options: {
                    livereload: true
                }
            },
            css: {
                files: [
                    '<%= config.dev.assets %>/css/**/*.css',
                    '<%= config.dev.assets %>/css/*.css'
                ],
                tasks: ['copy:cssStaging']
            },
            img: {
                files: [
                    '<%= config.dev.assets %>/img/**/*',
                    '<%= config.dev.assets %>/img/*'
                ],
                tasks: ['copy:imgStaging']
            },
            svg: {
                files: [
                    '<%= config.dev.assets %>/svg/**/*.svg',
                    '<%= config.dev.assets %>/svg/*.svg'
                ],
                tasks: ['copy:svgStaging']
            },
            swf: {
                files: [
                    '<%= config.dev.assets %>/swf/**/*',
                    '<%= config.dev.assets %>/swf/*'
                ],
                tasks: ['copy:swfStaging']
            },
            html: {
                files: [
                    '<%= config.dev.path %>/**/*.html',
                    '<%= config.dev.path %>/*.html'
                ],
                tasks: ['htmlbuild:staging'],
                options: {
                    livereload: true
                }
            }
        },
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                hostname: '0.0.0.0'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        config.staging.path
                    ]
                }
            }
        }
    });

    grunt.registerTask('default', [
        'clean:staging',
        'copy:fontsStaging',
        'copy:scriptsStaging',
        'copy:swfStaging',
        'copy:imgStaging',
        'copy:filesStaging',
        'htmlbuild:staging',
        'less:staging',
        'connect:livereload',
        'watch'
    ]);

    grunt.registerTask('build', [
        'clean:build',
        'copy:fontsBuild',
        'copy:scriptsBuild',
        'copy:swfBuild',
        'copy:imgBuild',
        'copy:filesBuild',
        'svgmin',
        'less:build',
        'cmq',
        'joycss',
        'rename',
        'replace',
        'imageEmbed',
        'csso',
        'imagemin',
        'modernizr',
        'htmlbuild:build',
        'useminPrepare',
        'concat',
        'uglify',
        'usemin',
        'cachebreaker',
        'htmlmin',
        'htmlcompressor',
        'clean:joycss'
    ]);
};
<commit_msg>Otimiza deteccão do Modernizr<commit_after>module.exports = function(grunt) {
    'use strict';

    var config = {
            dev: {
                path: 'dev',
                assets: 'dev/assets',
                partials: 'dev/partials'
            },
            staging: {
                path: 'staging',
                assets: 'staging/assets',
                partials: 'staging/partials'
            },
            build: {
                path: 'build',
                assets: 'build/assets',
                partials: 'build/partials'
            }
        },
        js = {
            project: [
                config.dev.assets + '/js/main.js'
            ],
            vendor: [
                config.dev.assets + '/js/vendor/plugins/*.js'
            ]
        };

    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        config: config,
        uglify_files: js.vendor.concat(js.project),
        banner: '/*! <%= pkg.projectName %> - v<%= pkg.version %> - by <%= pkg.developers %> - <%= grunt.template.today("dd-mm-yyyy") %> */\n',
        clean: {
            staging: [
                '<%= config.staging.path %>/**/*',
                '!<%= config.staging.path %>/**/.git',
                '!<%= config.staging.path %>/**/.svn'
            ],
            build: [
                '<%= config.build.path %>/**/*',
                '!<%= config.build.path %>/**/.git',
                '!<%= config.build.path %>/**/.svn'
            ],
            joycss: ['<%= config.build.assets %>/css/main.min.joy']
        },
        less: {
            staging: {
                files: {
                    '<%= config.staging.assets %>/css/main.min.css': '<%= config.dev.assets %>/less/main.less'
                },
                options: {
                    yuicompress: false
                }
            },
            build: {
                files: {
                    '<%= config.build.assets %>/css/main.min.css': '<%= config.dev.assets %>/less/main.less'
                },
                options: {
                    yuicompress: false
                }
            }
        },
        jshint: {
            files: js.project,
            options: {
                globals: {
                    jQuery: true,
                    console: true,
                    module: true
                },
                bitwise: true,
                expr: true
            }
        },
        uglify: {
            /*options: {
                banner: '<%= banner %>',
                mangle: {
                    except: ['jQuery', 'Backbone']
                }
            },
            build: {
                files: {
                    '<%= config.build.assets %>/js/main.min.js': '<%= uglify_files %>'
                }
            }*/
        },
        concat: {
            /*options: {
                separator: ';'
            },
            staging: {
                src: ['<%= uglify_files %>'],
                dest: '<%= config.staging.assets %>/js/main.min.js',
            }*/
        },
        modernizr: {
            'devFile': '<%= config.dev.assets %>/js/vendor/lib/modernizr.min.js',
            'outputFile': '<%= config.build.assets %>/js/vendor/lib/modernizr.min.js',
            'matchCommunityTests': true,
            'files': [
                '<%= uglify_files %>',
                '<%= config.build.assets %>/css/{,*/}*.css',
                '<%= config.dev.assets %>/js/vendor/*'
            ],
            'excludeFiles': [
                '<%= config.dev.assets %>/js/vendor/modernizr.min.js'
            ],
            'tests' : [],
        },
        joycss: {
            build: {
                options: {
                    layout: 'auto',
                    alpha: true
                },
                cwd: '<%= config.build.assets %>/css/',
                src: ['main.min.css'],
                dest: '<%= config.build.assets %>/css/'
            }
        },
        rename: {
            main: {
                files: [{
                    src: ['<%= config.build.assets %>/img/main.min-sprite.png'],
                    dest: '<%= config.build.assets %>/img/main-sprite.png'
                }]
            }
        },
        replace: {
            sprite: {
                src: ['<%= config.build.assets %>/css/*.css'],
                overwrite: true,
                replacements: [{
                    from: 'main.min-sprite.png',
                    to: 'main-sprite.png?' + '<%= new Date().getTime() %>'
                }]
            },
            esc_sprite: {
                src: ['<%= config.build.assets %>/css/*.css'],
                overwrite: true,
                replacements: [{
                    from: '?esc)',
                    to: '?<%= new Date().getTime() %>)'
                }]
            }
        },
        imagemin: {
            options: {
                optimizationLevel: 7
            },
            build: {
                expand: true,
                cwd: '<%= config.build.assets %>/img',
                src: '{,*/}*.{png,jpg,jpeg}',
                dest: '<%= config.build.assets %>/img'
            }
        },
        imageEmbed: {
            build: {
                src: ['<%= config.build.assets %>/css/main.min.css'],
                dest: '<%= config.build.assets %>/css/main.min.css',
                options: {
                    deleteAfterEncoding: true,
                    maxImageSize: 20480
                }
            }
        },
        svgmin: {
            build: {
                files: [{
                    expand: true,
                    cwd: '<%= config.dev.assets %>/svg',
                    src: ['**/*.svg'],
                    dest: '<%= config.build.assets %>/svg'
                }, {
                    expand: true,
                    cwd: '<%= config.dev.assets %>/font',
                    src: ['**/*.svg'],
                    dest: '<%= config.build.assets %>/font'
                }]
            }
        },
        htmlbuild: {
            staging: {
                src: '<%= config.dev.path %>/*.html',
                dest: '<%= config.staging.path %>/',
                options: {
                    sections: {
                        header: '<%= config.dev.partials %>/header.html',
                        footer: '<%= config.dev.partials %>/footer.html'
                    }
                }
            },
            build: {
                src: '<%= config.dev.path %>/*.html',
                dest: '<%= config.build.path %>/',
                options: {
                    sections: {
                        header: '<%= config.dev.partials %>/header.html',
                        footer: '<%= config.dev.partials %>/footer.html'
                    }
                }
            }
        },
        useminPrepare: {
            options: {
                dest: '<%= config.build.path %>',
                root: '<%= config.dev.path %>'
            },
            html: '<%= config.build.path %>/index.html'
        },
        usemin: {
            options: {
                assetsDirs: ['<%= config.dev.path %>'],
                dirs: ['<%= config.build.path %>']
            },
            html: ['<%= config.build.path %>/{,*/}*.html']
        },
        htmlmin: {
            build: {
                options: {
                    removeComments: true,
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeRedundantAttributes: false,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true
                },
                expand: true,
                cwd: '<%= config.build.path %>',
                src: ['**/*.html'],
                dest: '<%= config.build.path %>'
            }
        },
        htmlcompressor: {
            build: {
                options: {
                    type: 'html',
                    preserveServerScript: true,
                    compressJs: true
                },
                expand: true,
                cwd: '<%= config.build.path %>',
                src: ['**/*.html'],
                dest: '<%= config.build.path %>'
            }
        },
        cmq: {
            build: {
                options: {
                    log: 'true'
                },
                files: {
                    '<%= config.build.assets %>/css/': ['<%= config.build.assets %>/css/*.css']
                }
            }
        },
        csso: {
            build: {
                options: {
                    report: 'gzip',
                    banner: '<%= banner %>'
                },
                files: {
                    '<%= config.build.assets %>/css/main.min.css': ['<%= config.build.assets %>/css/main.min.css']
                }
            }
        },
        cachebreaker: {
            js: {
                asset_url: 'assets/js/main.min.js',
                files: {
                    src: '<%= config.build.path %>/*.html'
                }
            },
            css: {
                asset_url: 'assets/css/main.min.css',
                files: {
                    src: '<%= config.build.path %>/*.html'
                }
            }
        },
        copy: {
            staging: {
                files: [{
                    expand: true,
                    //dot: true,
                    cwd: '<%= config.dev.assets %>',
                    dest: '<%= config.staging.assets %>',
                    src: [
                        '*.{ico,png,txt,json}',
                        '.htaccess',
                        'img/**/*',
                        'swf/**/*',
                        'css/**/*',
                        'js/**/*',
                        'font/**/*'
                    ]
                }]
            },
            build: {
                files: [{
                    expand: true,
                    //dot: true,
                    cwd: '<%= config.dev.assets %>',
                    dest: '<%= config.build.assets %>',
                    src: [
                        '*.{ico,png,txt,json}',
                        '.htaccess',
                        'img/**/*',
                        'swf/**/*',
                        'css/**/*',
                        'font/**/*'
                    ]
                }]
            }
        },
        watch: {
            scripts: {
                files: [
                    '<%= config.dev.assets %>/js/*.js',
                    '<%= config.dev.assets %>/js/**/*.js'
                ],
                tasks: ['jshint', 'concat']
            },
            less: {
                files: [
                    '<%= config.dev.assets %>/less/**/*.less',
                    '<%= config.dev.assets %>/less/*.less'
                ],
                tasks: ['less:staging'],
                options: {
                    livereload: true
                }
            },
            css: {
                files: [
                    '<%= config.dev.assets %>/css/**/*.css',
                    '<%= config.dev.assets %>/css/*.css'
                ],
                tasks: ['copy:cssStaging']
            },
            img: {
                files: [
                    '<%= config.dev.assets %>/img/**/*',
                    '<%= config.dev.assets %>/img/*'
                ],
                tasks: ['copy:imgStaging']
            },
            svg: {
                files: [
                    '<%= config.dev.assets %>/svg/**/*.svg',
                    '<%= config.dev.assets %>/svg/*.svg'
                ],
                tasks: ['copy:svgStaging']
            },
            swf: {
                files: [
                    '<%= config.dev.assets %>/swf/**/*',
                    '<%= config.dev.assets %>/swf/*'
                ],
                tasks: ['copy:swfStaging']
            },
            html: {
                files: [
                    '<%= config.dev.path %>/**/*.html',
                    '<%= config.dev.path %>/*.html'
                ],
                tasks: ['htmlbuild:staging'],
                options: {
                    livereload: true
                }
            }
        },
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                hostname: '0.0.0.0'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        config.staging.path
                    ]
                }
            }
        }
    });

    grunt.registerTask('default', [
        'clean:staging',
        'copy:fontsStaging',
        'copy:scriptsStaging',
        'copy:swfStaging',
        'copy:imgStaging',
        'copy:filesStaging',
        'htmlbuild:staging',
        'less:staging',
        'connect:livereload',
        'watch'
    ]);

    grunt.registerTask('build', [
        'clean:build',
        'copy:fontsBuild',
        'copy:scriptsBuild',
        'copy:swfBuild',
        'copy:imgBuild',
        'copy:filesBuild',
        'svgmin',
        'less:build',
        'cmq',
        'joycss',
        'rename',
        'replace',
        'imageEmbed',
        'csso',
        'imagemin',
        'modernizr',
        'htmlbuild:build',
        'useminPrepare',
        'concat',
        'uglify',
        'usemin',
        'cachebreaker',
        'htmlmin',
        'htmlcompressor',
        'clean:joycss'
    ]);
};
<|endoftext|>


<commit_before>module.exports = function (grunt) {

   'use strict';

   grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),

      nodeunit: {
         all: ['test/test*.js']
      },

      release: {
         options: {
            file: 'package.json',
            tagName: '<%= version %>', //default: '<%= version %>'
            commitMessage: 'Release <%= version %>', //default: 'release <%= version %>'
            tagMessage: 'Tag version <%= version %>' //default: 'Version <%= version %>'
         }
      }
   });

   grunt.loadNpmTasks('grunt-contrib-nodeunit');
   grunt.loadNpmTasks('grunt-release-steps');

   grunt.registerTask('-to-npm', ['release:npm']);
   grunt.registerTask('-to-git', ['release:add:commit:push']);
   grunt.registerTask('-tag',    ['release:tag:pushTags']);

   grunt.registerTask('patch', ['test', 'release:bump:patch', '-to-git']);
   grunt.registerTask('minor', ['test', 'release:bump:minor', '-tag', '-to-git', '-to-npm']);
   grunt.registerTask('major', ['test', 'release:bump:major', '-tag', '-to-git', '-to-npm']);

   grunt.registerTask('default', ['patch']);
   grunt.registerTask('test', ['nodeunit:all']);

};
<commit_msg>Always tag and push to npm when creating a new version (ie: including patches)<commit_after>module.exports = function (grunt) {

   'use strict';

   grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),

      nodeunit: {
         all: ['test/test*.js']
      },

      release: {
         options: {
            file: 'package.json',
            tagName: '<%= version %>', //default: '<%= version %>'
            commitMessage: 'Release <%= version %>', //default: 'release <%= version %>'
            tagMessage: 'Tag version <%= version %>' //default: 'Version <%= version %>'
         }
      }
   });

   grunt.loadNpmTasks('grunt-contrib-nodeunit');
   grunt.loadNpmTasks('grunt-release-steps');

   grunt.registerTask('-to-npm', ['release:npm']);
   grunt.registerTask('-to-git', ['release:add:commit:push']);
   grunt.registerTask('-tag',    ['release:tag:pushTags']);

   'patch minor major'.split(' ').forEach(function (type) {
      grunt.registerTask(type, ['test', 'release:bump:' + type, '-tag', '-to-git', '-to-npm']);
   });

   grunt.registerTask('default', ['patch']);
   grunt.registerTask('test', ['nodeunit:all']);

};
<|endoftext|>


<commit_before>/*
 * All source files are created and managed by type in `src`.
 *
 * There three output directories:
 *
 *  - `local` - Development and testing
 *  - `build` - Intermediate directory prior to optimizations and/or
 *      concatentation
 *  - `dist` - Final output for release purposes. This carries over
 *      to the master branch to be copied in the root of the repo.
 *
 *  Each Grunt task has a target named `local` which performs copying,
 *  compiling or symlinking in the `local` directory for development.
 *  Additional targets may be defined for `build` or `dist` depending on
 *  the requirements.
 *
 *  Shared options for a task should be defined first, followed by each
 *  task entry. Each task can define it's own set of options to override
 *  the shared ones defined for the task.
 *
 */

module.exports = function(grunt) {
    'use strict';

    var pkg = grunt.file.readJSON('package.json');

    grunt.initConfig({

        pkg: pkg,

        srcDir: 'src',
        specDir: 'spec',

        localDir: 'local',
        buildDir: 'build',
        distDir: 'dist',

        connect: {
            server: {
                options: {
                    host: '127.0.0.1',
                    port: 8125
                }
            }
        },

        watch: {
            coffee: {
                tasks: ['coffee:local'],
                files: [
                    '<%= srcDir %>/coffee/**/*'
                ]
            },

            tests: {
                tasks: ['jasmine:local:build'],
                files: ['<%= specDir %>/**/*']
            },

            sass: {
                tasks: ['sass:local'],
                files: ['<%= srcDir %>/scss/**/*']
            }
        },

        coffee: {
            options: {
                bare: true,
            },

            // Output to 'local' for development
            local: {
                options: {
                    sourceMap: true
                },
                expand: true,
                cwd: '<%= srcDir %>/coffee',
                dest: '<%= localDir %>/js',
                src: '**/*.coffee',
                rename: function(dest, src) {
                    return dest + '/' + src.replace('.coffee', '.js');
                }
            },

            // Compiles files to the 'build' directory for distribution
            build: {
                expand: true,
                cwd: '<%= srcDir %>/coffee',
                dest: '<%= buildDir %>/js',
                src: '**/*.coffee',
                rename: function(dest, src) {
                    return dest + '/' + src.replace('.coffee', '.js');
                }
            }
        },

        sass: {
            local: {
                options: {
                    trace: true,
                    sourcemap: true
                },
                files: {
                    '<%= localDir %>/css/style.css': '<%= srcDir %>/scss/style.scss'
                }
            },

            dist: {
                options: {
                    quiet: true,
                    style: 'compressed'
                },
                files: {
                    '<%= distDir %>/css/style.css': '<%= srcDir %>/scss/style.scss'
                }
            }
        },

        copy: {
            local: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/js',
                        src: ['**/*'],
                        dest: '<%= localDir %>/js'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/css',
                        src: ['**/*'],
                        dest: '<%= localDir %>/css'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/font',
                        src: ['**/*'],
                        dest: '<%= localDir %>/font'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/img',
                        src: ['**/*'],
                        dest: '<%= localDir %>/img'
                    }
                ]
            },

            build: {
                files: [
                     {
                        expand: true,
                        cwd: '<%= srcDir %>/templates',
                        src: ['**/*'],
                        dest: '<%= buildDir %>/js/templates'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/js',
                        src: ['**/*'],
                        dest: '<%= buildDir %>/js'
                    }
                ]
            },

            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/css',
                        src: ['**/*'],
                        dest: '<%= distDir %>/css'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/font',
                        src: ['**/*'],
                        dest: '<%= distDir %>/font'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/img',
                        src: ['**/*'],
                        dest: '<%= distDir %>/img'
                    },
                    {
                        expand: true,
                        src: ['bower.json', 'package.json'],
                        dest: '<%= distDir %>'
                    }
                ]
            }
        },

        // Only applicable for development, e.g. local
        symlink: {
            options: {
                type: 'dir'
            },

            templates: {
                relativeSrc: '../../<%= srcDir %>/templates',
                dest: '<%= localDir %>/js/templates'
            },

            extensions: {
                relativeSrc: '../../<%= srcDir %>/extensions',
                dest: '<%= localDir %>/js/extensions'
            }
        },

        requirejs: {
            options: {
                baseUrl: '.',
                inlineText: true,
                preserveLicenseComments: false,
                wrap: false,
                logLevel: 1,
                throwWhen: {
                    optimize: true
                },

                // RequireJS plugin configs
                config: {
                    tpl: {
                        variable: 'data'
                    }
                },

                modules: [{
                    name: 'cilantro',
                    include: ['cilantro/ui']
                }],

                // Post analysis of built files
                done: function(done, output) {
                    var dups = require('rjs-build-analysis').duplicates(output);

                    if (dups.length > 0) {
                        grunt.log.subhead('Duplicates found in RequireJS build:');
                        grunt.log.warn(dups);
                        done(new Error('r.js built duplicate modules, please check the `excludes` option.'));
                    }

                    done();
                }
            },

            dist: {
                options: {
                    appDir: 'build/js',
                    dir: 'dist/js',
                    optimize: 'uglify2',
                    removeCombined: true
                }
            }
        },

        // Removes output directories
        clean: {
            local: ['local'],
            build: ['build'],
            dist: ['dist'],
            postdist: [
                '<%= distDir %>/js/templates',
                '<%= distDir %>/js/build.txt'
            ]
        },

        jasmine : {
            options : {
                specs : '<%= specDir %>/**/*',
                host: 'http://127.0.0.1:8125',
                keepRunner: true,
                template: require('grunt-template-jasmine-requirejs'),
            },

            local: {
                options: {
                    templateOptions: {
                        requireConfig: {
                            baseUrl: '<%= localDir %>/js',
                            config: {
                                tpl: {
                                    variable: 'data'
                                }
                            }
                        }
                    }
                }
            },

            dist: {
                options: {
                    templateOptions: {
                        requireConfig: {
                            baseUrl: '<%= distDir %>/js',
                            config: {
                                tpl: {
                                    variable: 'data'
                                }
                            }
                        }
                    }
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-coffee');
    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-symlink');

    grunt.registerTask('local', [
        'sass:local',
        'coffee:local',
        'copy:local',
        'symlink',
        'jasmine:local:build'
    ]);

    grunt.registerTask('dist', [
        'clean:build',
        'coffee:build',
        'copy:build',
        'clean:dist',
        'requirejs:dist',
        'sass:dist',
        'copy:dist',
        'clean:postdist'
    ]);

    grunt.registerTask('work', [
        'local',
        'watch'
    ]);

    grunt.registerTask('test', [
        'connect',
        'jasmine:local'
    ]);

    var shell = require('shelljs');

    function run(cmd) {
        grunt.log.ok(cmd);
        shell.exec(cmd);
    }

    grunt.registerTask('tag-release', 'Create a release on master', function() {
        run('git checkout master');
        run('rm -rf font css img js');
        run('cp -r dist/* .');
        run('git add .');
        run('git commit -m "' + pkg.version + ' Release"');
        run('git tag ' + pkg.version);
    });

    grunt.registerTask('release', [
        'dist',
        'tag-release'
    ]);

};
<commit_msg>Ensure local files are built prior to running tests<commit_after>/*
 * All source files are created and managed by type in `src`.
 *
 * There three output directories:
 *
 *  - `local` - Development and testing
 *  - `build` - Intermediate directory prior to optimizations and/or
 *      concatentation
 *  - `dist` - Final output for release purposes. This carries over
 *      to the master branch to be copied in the root of the repo.
 *
 *  Each Grunt task has a target named `local` which performs copying,
 *  compiling or symlinking in the `local` directory for development.
 *  Additional targets may be defined for `build` or `dist` depending on
 *  the requirements.
 *
 *  Shared options for a task should be defined first, followed by each
 *  task entry. Each task can define it's own set of options to override
 *  the shared ones defined for the task.
 *
 */

module.exports = function(grunt) {
    'use strict';

    var pkg = grunt.file.readJSON('package.json');

    grunt.initConfig({

        pkg: pkg,

        srcDir: 'src',
        specDir: 'spec',

        localDir: 'local',
        buildDir: 'build',
        distDir: 'dist',

        connect: {
            server: {
                options: {
                    host: '127.0.0.1',
                    port: 8125
                }
            }
        },

        watch: {
            coffee: {
                tasks: ['coffee:local'],
                files: [
                    '<%= srcDir %>/coffee/**/*'
                ]
            },

            tests: {
                tasks: ['jasmine:local:build'],
                files: ['<%= specDir %>/**/*']
            },

            sass: {
                tasks: ['sass:local'],
                files: ['<%= srcDir %>/scss/**/*']
            }
        },

        coffee: {
            options: {
                bare: true,
            },

            // Output to 'local' for development
            local: {
                options: {
                    sourceMap: true
                },
                expand: true,
                cwd: '<%= srcDir %>/coffee',
                dest: '<%= localDir %>/js',
                src: '**/*.coffee',
                rename: function(dest, src) {
                    return dest + '/' + src.replace('.coffee', '.js');
                }
            },

            // Compiles files to the 'build' directory for distribution
            build: {
                expand: true,
                cwd: '<%= srcDir %>/coffee',
                dest: '<%= buildDir %>/js',
                src: '**/*.coffee',
                rename: function(dest, src) {
                    return dest + '/' + src.replace('.coffee', '.js');
                }
            }
        },

        sass: {
            local: {
                options: {
                    trace: true,
                    sourcemap: true
                },
                files: {
                    '<%= localDir %>/css/style.css': '<%= srcDir %>/scss/style.scss'
                }
            },

            dist: {
                options: {
                    quiet: true,
                    style: 'compressed'
                },
                files: {
                    '<%= distDir %>/css/style.css': '<%= srcDir %>/scss/style.scss'
                }
            }
        },

        copy: {
            local: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/js',
                        src: ['**/*'],
                        dest: '<%= localDir %>/js'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/css',
                        src: ['**/*'],
                        dest: '<%= localDir %>/css'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/font',
                        src: ['**/*'],
                        dest: '<%= localDir %>/font'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/img',
                        src: ['**/*'],
                        dest: '<%= localDir %>/img'
                    }
                ]
            },

            build: {
                files: [
                     {
                        expand: true,
                        cwd: '<%= srcDir %>/templates',
                        src: ['**/*'],
                        dest: '<%= buildDir %>/js/templates'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/js',
                        src: ['**/*'],
                        dest: '<%= buildDir %>/js'
                    }
                ]
            },

            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/css',
                        src: ['**/*'],
                        dest: '<%= distDir %>/css'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/font',
                        src: ['**/*'],
                        dest: '<%= distDir %>/font'
                    },
                    {
                        expand: true,
                        cwd: '<%= srcDir %>/img',
                        src: ['**/*'],
                        dest: '<%= distDir %>/img'
                    },
                    {
                        expand: true,
                        src: ['bower.json', 'package.json'],
                        dest: '<%= distDir %>'
                    }
                ]
            }
        },

        // Only applicable for development, e.g. local
        symlink: {
            options: {
                type: 'dir'
            },

            templates: {
                relativeSrc: '../../<%= srcDir %>/templates',
                dest: '<%= localDir %>/js/templates'
            },

            extensions: {
                relativeSrc: '../../<%= srcDir %>/extensions',
                dest: '<%= localDir %>/js/extensions'
            }
        },

        requirejs: {
            options: {
                baseUrl: '.',
                inlineText: true,
                preserveLicenseComments: false,
                wrap: false,
                logLevel: 1,
                throwWhen: {
                    optimize: true
                },

                // RequireJS plugin configs
                config: {
                    tpl: {
                        variable: 'data'
                    }
                },

                modules: [{
                    name: 'cilantro',
                    include: ['cilantro/ui']
                }],

                // Post analysis of built files
                done: function(done, output) {
                    var dups = require('rjs-build-analysis').duplicates(output);

                    if (dups.length > 0) {
                        grunt.log.subhead('Duplicates found in RequireJS build:');
                        grunt.log.warn(dups);
                        done(new Error('r.js built duplicate modules, please check the `excludes` option.'));
                    }

                    done();
                }
            },

            dist: {
                options: {
                    appDir: 'build/js',
                    dir: 'dist/js',
                    optimize: 'uglify2',
                    removeCombined: true
                }
            }
        },

        // Removes output directories
        clean: {
            local: ['local'],
            build: ['build'],
            dist: ['dist'],
            postdist: [
                '<%= distDir %>/js/templates',
                '<%= distDir %>/js/build.txt'
            ]
        },

        jasmine : {
            options : {
                specs : '<%= specDir %>/**/*',
                host: 'http://127.0.0.1:8125',
                keepRunner: true,
                template: require('grunt-template-jasmine-requirejs'),
            },

            local: {
                options: {
                    templateOptions: {
                        requireConfig: {
                            baseUrl: '<%= localDir %>/js',
                            config: {
                                tpl: {
                                    variable: 'data'
                                }
                            }
                        }
                    }
                }
            },

            dist: {
                options: {
                    templateOptions: {
                        requireConfig: {
                            baseUrl: '<%= distDir %>/js',
                            config: {
                                tpl: {
                                    variable: 'data'
                                }
                            }
                        }
                    }
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-coffee');
    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-symlink');

    grunt.registerTask('local', [
        'sass:local',
        'coffee:local',
        'copy:local',
        'symlink',
        'jasmine:local:build'
    ]);

    grunt.registerTask('dist', [
        'clean:build',
        'coffee:build',
        'copy:build',
        'clean:dist',
        'requirejs:dist',
        'sass:dist',
        'copy:dist',
        'clean:postdist'
    ]);

    grunt.registerTask('work', [
        'local',
        'watch'
    ]);

    grunt.registerTask('test', [
        'local',
        'connect',
        'jasmine:local'
    ]);

    var shell = require('shelljs');

    function run(cmd) {
        grunt.log.ok(cmd);
        shell.exec(cmd);
    }

    grunt.registerTask('tag-release', 'Create a release on master', function() {
        run('git checkout master');
        run('rm -rf font css img js');
        run('cp -r dist/* .');
        run('git add .');
        run('git commit -m "' + pkg.version + ' Release"');
        run('git tag ' + pkg.version);
    });

    grunt.registerTask('release', [
        'dist',
        'tag-release'
    ]);

};
<|endoftext|>