Sencha Touch Chatter Mobile Application

Chatter Controller

public with sharing class ChatterController {

    public class Response {
        public Boolean success;
        public String errorMessage;
        public List<SObject> records;
        public Integer total;
        Response() {
            records = new List<SObject>();
            success = true;
        }
    }
    
    //One of the parameters supplied by the DirectProxy read method.
    public class QueryRequest {
        Integer start;
        Integer recordCount;
        List<Map<String, String>> sortParams;
        
        Public QueryRequest() {
            start = 1;
            recordCount = 1;
        }
 
        Public QueryRequest(Integer pStart, Integer pRecordCount) {
            start = pStart;
            recordCount = pRecordCount;
        }
 
    }
 
    @RemoteAction
    public static Response Add(List<FeedItem> chatterData){
        return insertLeadList(chatterData);
    }
    
    @RemoteAction
    public static Response Destroy(List<FeedItem> chatterData){
        return deleteChatterList(chatterData);
    }
    
    @RemoteAction
    public static Response Edit(List<FeedItem> chatterData){
        return editChatterList(chatterData);
    }
    
    @RemoteAction
    public static Response EditComment(List<String> chatterCommentData){
        return editCommentChatterList(chatterCommentData);
    }
    
    @RemoteAction
    public static Response Query(QueryRequest qr){
 
        Response resp = new Response();
 
        //Enforce a limit on the number of rows requested.
        final integer QUERY_LIMIT = 500;
        if( qr.start >= QUERY_LIMIT ){
            resp.success = false;
            resp.errorMessage = 'Maximum number of records (' + String.valueOf(QUERY_LIMIT) + ') exceeded!';
            return resp;
        }
 
        try {
            getAllChatter(qr, resp);
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Query failed: ' + e.getMessage();
        }
 
        return resp;
    }
    
    private static Response insertCommentOrLike(List<FeedComment> chatterComment, List<FeedLike> chatterLike)
    {
        Response resp = new Response();
        resp.success = true;
 
        try {
            insert chatterComment;
            insert chatterLike;
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Insert failed: ' + e.getMessage();
        }
        return resp;
    }
    
    private static void getAllChatter(QueryRequest qr, Response resp){
 
        //Page size is set in the Sencha store as recordCount.  
        Integer pageSize = qr.recordCount; 
 
        //Page number will be calculated.
        Integer pageNumber = 0;
    
        //Start is the record number indicating the start of the page.
        if( qr.start > 0 ){
            pageNumber = qr.start / pageSize;   
        }
 
        //Calculate the offset for SOQL.
        Integer offset = pageNumber * pageSize;
 
        //Build the query in pieces.
        String fieldList = 'Id, Title, Body, LikeCount,CommentCount';
 
        //Construct a base query to which the page offsets will be added.
        String baseQuery = 'SELECT ' + fieldList + ' FROM FeedItem Order By CreatedDate DESC';
 
        //Construct a count query to pass back the total records matching a search criteria.
        String baseCountQuery = 'SELECT COUNT() FROM FeedItem';
 
        //Construct the fetch query with the offset.
        String fetchQuery = baseQuery + ' LIMIT ' + pageSize + ' OFFSET ' + offset;
 
        try {
            //Set the count.
            resp.total = Database.countQuery(baseCountQuery);
 
            //Set the fetched recordset.
            resp.records = Database.query(fetchQuery);
            
            //Set the status flag.
            resp.success = true;
 
        } catch (Exception e) {
 
            //Set the total count of records matching the query.
            resp.total = 0;
            
            //Set the recordset to return.
            resp.records = new List<Lead>();
            
            //Set the status flag.            
            resp.success = false;
 
        }    
                                    
    }
    
    private static Response insertLeadList(List<FeedItem> chatterData){
        Response resp = new Response();
        resp.success = true;
 
        try {
            chatterData[0].ParentId = UserInfo.getUserId();
            insert chatterData;
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Insert failed: ' + e.getMessage();
        }
        return resp;
    }
    
    private static Response deleteChatterList(List<FeedItem> ChatterData){
 
        Response resp = new Response();
        resp.success = true;
 
        try {
            delete ChatterData;
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Deletion failed: ' + e.getMessage();
        } 
        return resp;
    }
    
    private static Response editChatterList(List<FeedItem> chatterData){
        Response resp = new Response();
        resp.success = true;
 
        try {
            System.debug('Hier: ' + chatterData);
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Deletion failed: ' + e.getMessage();
        } 
        return resp;
    }
    
    private static Response editCommentChatterList(List<String> chatterCommentData)
    {
        Response resp = new Response();
        resp.success = true;
 
        try {
            System.debug('Hier: ' + chatterCommentData);
        } catch (Exception e) {
            resp.success = false;
            resp.errorMessage = 'Deletion failed: ' + e.getMessage();
        } 
        return resp;
    }
}

Chatter Component

<apex:component controller="ChatterController">
 <script type="text/javascript">
    Ext.application({
    name: "ChatterPlus",
    models: ["Chatter"],
    stores: ["Chatter"],
    controllers: ["Chatter"],
    views: ["ChatterList", "ChatterEditor", "ChatterLikeCommentEditor"],
   
    launch: function () {
        var chatterListView = {
            xtype: "chatterlistview"
        };
        
        var chatterEditorView = {
            xtype: "chattereditorview"
        };
        
        var chatterLikeCommentEditor = {
            xtype: "chatterlikecommentview"
        };
        
        Ext.Viewport.add([chatterListView, chatterEditorView, chatterLikeCommentEditor]);
    }
});
Ext.define("ChatterPlus.view.ChatterList", {
    extend: "Ext.Container",
    requires: "Ext.dataview.List", 
    alias: "widget.chatterlistview",
    
    config: {
 
        //Take up the full space available in the parent container.
        layout: {
            type: 'fit'
        },
 
 
        //Add the components to include within the list view. 
        items: [
        {
            xtype: "toolbar",
            title: "Chatter",
            docked: "top",
 
            items: [
                { 
                    xtype: 'spacer' 
                },
                {
                    xtype: "button",
                    text: 'New',
                    ui: 'action',
                    itemId: "newButton"
                }
            ]
        }, 
        {
            xtype: "toolbar",
            docked: "bottom",
            itemId: "bottomToolBar",
                        
            items: [
               
            ]
        },
        {
            //The main list and its properties. 
            xtype: "list",
            store: "Chatter",
            itemId:"chatterList",
            
            onItemDisclosure: true,
            indexBar: true,
            grouped: false,
            disableSelection: false,
 
            plugins: [
                {
                    xclass: 'Ext.plugin.ListPaging',
                    autoPaging: true
                }
            ],

            loadingText: "Loading Feed...",
            emptyText: '<div class="chatter-list-empty-text">No feeds found.</div>',
            
            itemTpl: '<div class="list-item-line-main">{Title}</div>' + 
                     '<div class="list-item-line-main">{Body}</div>',                   
        }],
        
        listeners: [{
            delegate: "#newButton",
            event: "tap",
            fn: "onNewButtonTap"
        }, {
            delegate: "#syncButton",
            event: "tap",
            fn: "onSyncButtonTap"
        }, {        
            delegate: "#chatterList",
            event: "disclose",
            fn: "onChatterListDisclose"
        },
        {
            delegate: "#chatterList",
            event: "refresh",
            fn: "onChatterListRefresh",
        },
        {
            //Listener on the view's Activate event fires when redisplayed by transition.
            event: "activate",
            fn: "onChatterListViewActivate",
        }]  
    },
    onSyncButtonTap: function () {
        console.log("syncChatterCommand");
        this.fireEvent("syncChatterCommand", this);
    },
 
    onNewButtonTap: function () {
        console.log("newChatterCommand");
        this.fireEvent("newChatterCommand", this);
    },
 
    onChatterListDisclose: function (list, record, target, index, evt, options) {
        console.log("editChatterCommand");
        this.fireEvent('editChatterCommand', this, record);
    }, 
    onChatterListRefresh: function () {
        console.log("onChatterListRefresh");
        this.updateListCounter();
    },
 
    onChatterListViewActivate: function () {
        console.log("onChatterListViewActivate");
        this.updateListCounter();
    },
 
    //Function to get count of records in the list and show on the search button's badge. 
    updateListCounter: function () {
        var listCount = Ext.getStore("Chatter").getCount();
        //this.getComponent("bottomToolBar").getComponent("syncButton").setBadgeText(listCount);
    }  

});

Ext.define("ChatterPlus.view.ChatterEditor", {
    extend: "Ext.form.Panel",
    requires: "Ext.form.FieldSet",
    alias: "widget.chattereditorview",
 
    config: {
     scrollable: 'vertical',
 
        items: [
            {
                xtype: "toolbar",
                docked: "top",
                title: "Edit Chatter",
        
                items: [
                    {
                        xtype: "button",
                        ui: "back",
                        text: "Home",
                        itemId: "backButton"
                    },
                    { xtype: "spacer" },
                    {
                        xtype: "button",
                        ui: "action",
                        text: "Save",
                        itemId: "saveButton"
                    }
                ]
            },
            {
                xtype: "toolbar",
                docked: "bottom",
                items: [
                    {
                        xtype: "button",
                        iconCls: "trash",
                        iconMask: true,
                        itemId: "deleteButton"
                    }
                ]
            },
            { xtype: "fieldset",
                title: 'Chatter Info',
                items: [
                    {
                        xtype: 'textfield',
                        name: 'Title',
                        label: 'Title',
                        required: true
                    },
                    {
                        xtype: 'textareafield',
                        name: 'Body',
                        label: 'Body',
                        maxRows: 1,
                        required: true
                    },
                    {
                        xtype: 'textfield',
                        name: 'CommentCount',
                        label: 'Comment Count',
                        disabled: true
                        
                    },
                    {
                        xtype: 'textfield',
                        name: 'LikeCount',
                        label: 'Like Count',
                        disabled: true
                    },
                ]           
            },
            { xtype: "fieldset",
                title: 'Chatter Comment & Like',
                items: [
                    { 
                         xtype : 'textareafield',
                         name : 'Comment',
                         label : 'Comment',
                         maxRows: 1
                    },          
                    { 
                         xtype : 'checkboxfield',
                         name : 'Like',
                         label : 'Like'
                    },
                ]
            },      
        ],
        listeners: [
            {
                delegate: "#backButton",
                event: "tap",
                fn: "onBackButtonTap"
            },
            {
                delegate: "#saveButton",
                event: "tap",
                fn: "onSaveButtonTap"
            },
            {
                delegate: "#deleteButton",
                event: "tap",
                fn: "onDeleteButtonTap"
            }
        ]
    },
    
    onSaveButtonTap: function () {
        console.log("saveChatterCommand");
        this.fireEvent("saveChatterCommand", this);
    },
 
    onDeleteButtonTap: function () {
        console.log("deleteChatterCommand");
        Ext.Msg.confirm("Delete Feed", "Are you sure?", function(button){
            if (button == 'yes') {
                this.fireEvent("deleteChatterCommand", this);
            } else {
                return false;
            }
        }, this);
    },
 
    onBackButtonTap: function () {
        console.log("backToHomeCommand");
        this.fireEvent("backToHomeCommand", this);
    }
 
});


Ext.define("ChatterPlus.view.ChatterLikeCommentEditor", {
    extend: "Ext.form.Panel",
    requires: "Ext.form.FieldSet",
    alias: "widget.chatterlikecommentview",
 
    config: {
    }
 
 });
    
    
    
Ext.define("ChatterPlus.controller.Chatter", {
    extend: "Ext.app.Controller",
 
    config: {
 
        refs: {
            chatterListView: "chatterlistview",
            chatterEditorView: "chattereditorview",
            chatterList: "#chatterList",         
        },
 
        control: {
            chatterListView: {
                // The commands fired by the list container.
                syncChatterCommand: "onSyncChatterCommand",
                newChatterCommand: "onNewChatterCommand",
                editChatterCommand: "onEditChatterCommand",
            },
            chatterEditorView: {
                // The commands fired by the note editor.
                saveChatterCommand: "onSaveChatterCommand",
                deleteChatterCommand: "onDeleteChatterCommand",
                backToHomeCommand: "onBackToHomeCommand"
            }
        }
    },
 
    //View Transitions
    slideLeftTransition: { type: 'slide', direction: 'left' },
    slideRightTransition: { type: 'slide', direction: 'right' },
    
    activateChatterEditor: function (record) {
        var chatterEditorView = this.getChatterEditorView();
        chatterEditorView.setRecord(record); 
        Ext.Viewport.animateActiveItem(chatterEditorView, this.slideLeftTransition);
    },
 
    activateChatterList: function () {
        Ext.Viewport.animateActiveItem(this.getChatterListView(), this.slideRightTransition);
    },
 
    onSyncChatterCommand: function () {
        console.log("onSyncChatterCommand");
        this.loadList();
    },
     
    onNewChatterCommand: function () {
        console.log("onNewChatterCommand");
        var newChatter = Ext.create("ChatterPlus.model.Chatter");
        this.activateChatterEditor(newChatter);
    },
    
     onEditChatterCommand: function (list, record) {
        console.log("onEditChatterCommand");
        this.activateChatterEditor(record);
    },
    
    loadList: function () {
 
        //Get a ref to the store and remove it.
        var chatterStore = Ext.getStore("Chatter");
 
        var model = Ext.ModelMgr.getModel('ChatterPlus.model.Chatter');
        model.getProxy();
        
        chatterStore.getData().clear();   
        chatterStore.loadPage(1); 
        
        //Reshow the list.
        this.activateChatterList();
    },
    
    // Base Class functions.
    launch: function () {
        console.log("launch");
        this.callParent(arguments);
        
        //Load up the Store associated with the controller and its views. 
        console.log("load Chatter");
        this.loadList();
        
   },
   
   onSaveChatterCommand: function () {
        console.log("onSaveChatterCommand");
       
        var chatterEditorView = this.getChatterEditorView();
        var currentChatter = chatterEditorView.getRecord();
        var newValues = chatterEditorView.getValues();
        this.getChatterEditorView().updateRecord(currentChatter);     
 
        var errors = currentChatter.validate();
        if (!errors.isValid()) {
            var msg = '';
            errors.each(function(error) {
                msg += error.getMessage() + '<br/>';
            });
            console.log('Errors: ' + msg);
            Ext.Msg.alert('Please correct errors!', msg, Ext.emptyFn);
            currentChatter.reject();
            return;
        }
 
        //Get a ref to the store.
        var chatterStore = Ext.getStore("Chatter");
        var chatterCommentStore = Ext.getStore("ChatterComment");
        //var newChatterComment = Ext.create("ChatterPlus.model.ChatterComment");
        
        //Add new record to the store.
        if (null == chatterStore.findRecord('id', currentChatter.data.id)) {
            chatterStore.add(currentChatter);
           //chatterCommentStore.add(newChatterComment);
        }
        
        chatterCommentStore.sync();
        //Resync the proxy and activate the list.   
        chatterStore.sync();
        this.activateChatterList();
    },
 
    onDeleteChatterCommand: function () {
        console.log("onDeleteChatterCommand");
        
        //Get a ref to the form and its record. 
        var chatterEditorView = this.getChatterEditorView();
        var currentChatter = chatterEditorView.getRecord();

        var chatterStore = Ext.getStore("Chatter");
        chatterStore.remove(currentChatter);
              
        chatterStore.sync();
        this.activateChatterList();
    },
 
    onBackToHomeCommand: function () {
        console.log("onBackToHomeCommand");
        this.activateChatterList();
    },
 
    init: function() {
 
        this.callParent(arguments);
        console.log("init");
 
        //Listen for exceptions observed by the proxy so we can report them and clean up.
        Ext.getStore('Chatter').getProxy().addListener('exception', function (proxy, response, operation, options) {
            // only certain kinds of errors seem to have useful information returned from the server
            if (response) {
                if (response.errorMessage) {
                    Ext.Msg.alert('Error', response.errorMessage);
                } else {
                    Ext.Msg.alert('Error', operation.config.action + ' failed: ' + response.errorMessage);
                }
            } else {
                Ext.Msg.alert('Error', operation.config.action + ' failed for an unknown reason: proxy = ' + proxy);
            }
        });
 
    },
 
});

Ext.define("ChatterPlus.model.Chatter", {
    extend: "Ext.data.Model",
 
    config: {
        idProperty: 'Id',
 
        fields: [
            { name: 'Id', type: 'string', persist: false},
            { name: 'Title', type: 'string'},
            { name: 'Body', type: 'string'},
            { name: 'LikeCount', type: 'string', persist: false},
            { name: 'CommentCount', type: 'string', persist: false},
            { name: 'Comment', type: 'string', persist: false},
            { name: 'Like', type: 'string', persist: false},
            { name: 'ParentId', type: 'string'}
        ],
 
        validations: [
             { type: 'presence', field: 'Title', message: 'Enter a Title' },
             { type: 'presence', field: 'Body', message: 'Enter a Body' } 
        ],
 
        //Bind each CRUD functions to a @RemoteAction method in the Apex controller
        proxy: {
            type: 'direct',
            api: {
                read:     ChatterController.Query,
                create:   ChatterController.Add,
                update:   ChatterController.Edit,
                destroy:  ChatterController.Destroy
            },
            limitParam: 'recordCount',   // because "limit" is an Apex keyword
            sortParam: 'sortParams',     // because "sort" is a keyword too
            pageParam: false,            // we don't use this in the controller, so don't send it
            reader: {
                type: 'json',
                rootProperty: 'records',
                messageProperty: 'errorMessage'
            },
            writer: {
                type: 'json',
                root: 'records',
                writeAllFields: false,   // otherwise empty fields will transmit as empty strings, instead of "null"/not present
                allowSingle: false,      // need to always be an array for code simplification
                encode:  false           // docs say "set this to false when using DirectProxy"
            }
 
        }
    },
 
});

Ext.define("ChatterPlus.model.ChatterComment", {
    extend: "Ext.data.Model",
 
    config: {
        idProperty: 'Id',
 
        fields: [
            { name: 'Comment', type: 'string'}
        ],
 
        validations: [
            
        ],
 
        //Bind each CRUD functions to a @RemoteAction method in the Apex controller
        proxy: {
            type: 'direct',
            api: {
                update:   ChatterController.EditComment
            },
            writer: {
                type: 'json',
                root: 'records',
                writeAllFields: false,   // otherwise empty fields will transmit as empty strings, instead of "null"/not present
                allowSingle: false,      // need to always be an array for code simplification
                encode:  false           // docs say "set this to false when using DirectProxy"
            }
 
        }
    },
 
});



ChatterController.Query.directCfg.method.getArgs = 
    function (params, paramOrder, paramsAsHash) {
        console.log('getArgs: ' + params.data);
        return [params]; 
    }
 
Ext.data.proxy.Direct.prototype.createRequestCallback =
    function(request, operation, callback, scope){
        var me = this;
        return function(data, event){
             console.log('createRequestCallback: ' + operation);    
             me.processResponse(event.status, operation, request, data, callback, scope);
    };
    
};

Ext.define("ChatterPlus.store.Chatter", {
    extend: "Ext.data.Store",
    requires: "Ext.data.proxy.LocalStorage",
    config: {
        model: "ChatterPlus.model.Chatter",
        autoLoad: true,
        pageSize: 25,     
    },
 
    listeners: {
        load: function(){
             console.log('store.load(): loaded!');                
        },
    }
 
});

</script>
</apex:component>

1 Comment

  1. Johng850 says:

    Heya im for the first time here. I discovered this board and I to uncover It truly helpful &amp it helped me out a whole lot. I hope to supply something back and aid other people such as you helped me. decgdeaffkgk

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s