1. #1
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default EditorGrid - working example (php/mysql backend)

    EditorGrid - working example (php/mysql backend)


    Mar 22 2008:
    I've attached an updated php file. Demonstrates how you might do filtering, sorting, etc. server side. The filtering isn't tested too much, so please relay any bug fixes.

    Original:
    I thought I'd share an EditorGrid example that I've been learning with. The code provided works with a php/mysql backend with Ext2.0rc1.

    I'll just include the code for the files, the commenting within the code is pretty excessive so I don't know that adding any additional commentary is needed. The .zip is attached. The following posts for each file are shown for an advance view and commenting (but do not reflect the current attached file any longer).

    In order for the relative paths and css to work out of the box you should extract the attachment to the examples/ directory of your default download package.

    Code:
    L ext
        L adapter
        L build
        L docs
        L examples
            L grid-php <--Here
    There is a companion tutorial for this thread, but currently it just points back to this thread.

    The provided code is far from perfect (use at your own risk, etc.), but it does showcase some of the things you can do with the grids. When this code was done there were several things I had not quite figured out yet, but I figured sharing something less than perfect was better than sharing nothing at all.

    I would not use this code as is in a production environment. Instead I would suggest just reading and learning from this code.

    Constructive criticism is appreciated......

    Features
    • filtering - filter what is shown in the grid (local or remote filtering)
    • configurable paging
    • context menu - right click in the grid to see options (see Bugs)
    • dropdowns - editable dropdowns (client and server side sources - see Bugs)
    • check box - column with checkable field
    • date - date updates on server (see Issues)
    • code cleanup (looks much longer because I've tried to keep each line to 80 characters)

    Bugs / Known Issues
    • dropdowns
      • dropdown when using server side store is finicky (additional comments in file)
    • date - there's probably a better way to deal with the date object?
    • selectFirstRow - this should be done from grid 'render' listener

    Future Plans
    • printing - implement TCPDF/FPDF (another suggestion here; see Grid FAQ for other extensions)
    • improve organization, speed?

    I've posted a grid FAQ that might be of some help as well.

    Download Problems: If you have any problems downloading try firefox instead of internet explorer (IE has problems sometimes).
    Attached Images
    Attached Files
    Last edited by mjlecomte; 19 Oct 2008 at 5:47 AM. Reason: minor edits

  2. #2
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default sql file

    sql file


    Code:
    create database if not exists `test`;
    
    USE `test`;
    
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    
    /*Table structure for table `industry` */
    
    DROP TABLE IF EXISTS `industry`;
    
    CREATE TABLE `industry` (
      `industryID` int(10) unsigned NOT NULL auto_increment,
      `industryName` varchar(40) NOT NULL default '',
      PRIMARY KEY  (`industryID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
    
    /*Data for the table `industry` */
    
    insert  into `industry`(`industryID`,`industryName`) values (1,'automotive'),(2,'computer'),(3,'finance'),(4,'food'),(5,'manufacturing'),(6,'medical'),(7,'retail'),(8,'services');
    
    /*Table structure for table `stock` */
    
    DROP TABLE IF EXISTS `stock`;
    
    CREATE TABLE `stock` (
      `companyID` int(10) unsigned NOT NULL auto_increment,
      `company` varchar(40) default '',
      `price` float default NULL,
      `change` float default NULL,
      `pctChange` float default NULL,
      `lastChange` datetime default NULL,
      `industryID` int(10) default NULL,
      `risk` enum('low','medium','high') default NULL,
      `stars` enum('1','2','3','4','5') default NULL,
      `check` tinyint(1) default NULL,
      PRIMARY KEY  (`companyID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2036 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
    
    /*Data for the table `stock` */
    
    insert  into `stock`(`companyID`,`company`,`price`,`change`,`pctChange`,`lastChange`,`industryID`,`risk`,`stars`,`check`) values (1,'Alcoa',23.33,0.42,1.47,'2007-10-02 00:00:00',5,'low','5',0),(2,'General Electric Company',22,-0.08,-0.23,'2007-10-02 00:00:00',5,'high','3',1),(144,'Altria Group Inc',10,0.28,0.34,'2007-02-02 00:00:00',5,'low','4',1),(145,'American Express Company',51,0.01,0.02,'2007-10-26 00:00:00',4,'low','2',1),(146,'AT&T',31.63,-0.48,-1.54,'2007-12-25 00:00:00',8,'medium','3',1),(148,'Caterpillar Inc.',67.27,0.92,1.39,'2007-10-02 00:00:00',5,'low','3',1),(149,'E.I. du Pont de Nemours and Company',10,0.51,1.28,'2007-10-02 00:00:00',5,'low','2',0),(150,'Exxon Mobil Corp',68.1,-0.43,-0.64,'2007-10-02 00:00:00',5,'medium','2',0),(152,'General Motors Corporation',30.27,1.09,3.74,'2007-10-02 00:00:00',1,'high','4',1),(154,'Honeywell Intl Inc',38.77,0.05,0.13,'2007-10-02 00:00:00',5,'high','5',0),(155,'Intel Corporation',19.88,0.31,1.58,'2007-10-02 00:00:00',2,'medium','2',0),(156,'International Business Machines',81.41,0.44,0.54,'2007-10-02 00:00:00',2,'medium','1',0),(157,'Johnson & Johnson',64.72,0.06,0.09,'2007-10-02 00:00:00',6,'high','2',0),(158,'JP Morgan & Chase & Co',45.73,0.07,0.15,'2007-10-02 00:00:00',3,'low','3',0),(162,'The Coca-Cola Company',45.07,0.26,0.58,'2007-10-02 00:00:00',4,'medium','2',0),(163,'The Procter & Gamble Company',61.91,0.01,0.02,'2007-10-02 00:00:00',5,'low','4',0),(164,'United Technologies Corporation',63.26,0.55,0.88,'2007-10-02 00:00:00',2,'high','5',1),(165,'Verizon Communications',35.57,0.39,1.11,'2007-10-02 00:00:00',8,'medium','4',0),(166,'3m Company',44,0.02,0.03,'2007-08-01 00:00:00',5,'low','1',1),(2009,'Boeing Co.',75.43,0.53,0.71,'2007-08-01 00:00:00',5,'low','3',1),(2015,'Hewlett-Packard Co.',36.54,-0.03,-0.08,'2007-08-01 00:00:00',2,'low','1',1),(2021,'McDonald\'s Corporation',36.76,0.86,2.4,'2007-08-01 00:00:00',4,'high','5',0),(2022,'Microsoft Corporation',25.84,0.14,0.54,'2007-08-01 00:00:00',2,'high','3',1),(2023,'Pfizer Inc',27.96,0.4,1.45,'2007-08-01 00:00:00',6,'high','5',0),(2030,'Citigroup',49.37,0.02,0.04,'2007-10-05 00:00:00',3,'high','3',0),(2031,'Merck & Co., Inc.',40.96,0.41,1.01,'2007-10-09 00:00:00',6,'medium','2',0),(2032,'Walt Disney Company (The) (Holding Compa',29.89,0.24,0.81,'2007-10-05 00:00:00',8,'low','2',1),(2033,'Wal-Mart Stores, Inc.',45.45,0.73,1.63,'2007-05-09 00:00:00',7,'medium','2',1),(2034,'American International Group, Inc.',10,0.31,0.49,'2007-06-09 00:00:00',2,'high','2',1),(2035,'The Home Depot',34.64,0.35,1.02,'2007-08-05 00:00:00',7,'medium','4',0);
    Last edited by mjlecomte; 23 Nov 2007 at 10:32 PM. Reason: added table, added column(s)

  3. #3
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default html

    html


    Note has some inline css for some of the rendering.


    HTML Code:
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Grid Example (MySQL/php)</title>
    
        <link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
    
        <!-- GC -->
         <!-- LIBS -->
         <script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
         <!-- ENDLIBS -->
    
        <script type="text/javascript" src="../../ext-all-debug.js"></script>
    
    
        <script type="text/javascript" src="RowExpander.js"></script>
        <script type="text/javascript" src="grid-editor-mysql-php.js"></script>
    
        <link rel="stylesheet" type="text/css" href="grid-examples.css" />
    
        <!-- Common Styles for the examples -->
    
        <link rel="stylesheet" type="text/css" href="../examples.css" />
    
        <style type="text/css">
            body .x-panel {
                margin-bottom:20px;
            }
            .icon-grid {
                background-image:url(../../examples/shared/icons/fam/grid.png) !important;
            }
            #button-grid .x-panel-body {
                border:1px solid #99bbe8;
                border-top:0 none;
            }
            .add {
                background-image:url(../../examples/shared/icons/fam/add.gif) !important;
            }
            .option {
                background-image:url(../../examples/shared/icons/fam/plugin.gif) !important;
            }
            .remove {
                background-image:url(../../examples/shared/icons/fam/delete.gif) !important;
            }
            .refresh {
                background-image:url(../../examples/shared/icons/fam/table_refresh.png) !important;
            }
            .save {
                background-image:url(../../examples/shared/icons/save.gif) !important;
            }
    
            .red { color: red;}
        	.redcell { background-color:#FFE5E5 !important;}
    
    		.greenrow { background-color:#C3FF8F !important;}
    		.yellowrow { background-color:#FFFF66 !important;}
    		.pinkrow { background-color:#FFE6CC !important;}
        	.x-grid3-col-classCompanyID { background-color:#F2F2F2 !important;}
     /*  	.x-grid3-col-classCompany { background-color:#FEFFE5 !important;} this shades the column but covers the red triangles*/
    
        	.stars1 { 
               background-image:url(../../examples/shared/icons/fam/user_suit.png) !important;
    		   background-repeat: no-repeat;
    		   background-position: center;
     		}
        	.stars2 { 
               background-image:url(../../examples/shared/icons/fam/user_red.png) !important;
    		   background-repeat: no-repeat;
    		   background-position: center;
     		}
        	.stars3 { 
               background-image:url(../../examples/shared/icons/fam/user_orange.png) !important;
    		   background-repeat: no-repeat;
    		   background-position: center;
     		}
        	.stars4 { 
               background-image:url(../../examples/shared/icons/fam/user_green.png) !important;
    		   background-repeat: no-repeat;
    		   background-position: center;
     		}
        	.stars5 { 
               background-image:url(../../examples/shared/icons/fam/user_gray.png) !important;
    		   background-repeat: no-repeat;
    		   background-position: center;
     		}
        </style>
    </head>
    <body>
    <script type="text/javascript" src="../../examples/examples.js"></script><!-- EXAMPLES -->
    <h1>Grid Example using MySQL and php</h1>
    <p>This example shows how to create a grid from MySQL data with php backend.</p>
    <p>Note that the js is not minified so it is readable. See <a href="grid-mysql-php.js" target="_blank">grid-mysql-php.js</a> and the <a href="../../docs/" target="_blank">API Docs</a>.</p>
    
    
    <!-- you must define the select box here, as the custom editor for the 'Light' column will require it -->
    <select name="riskName" id="riskID" style="display: none;">
    	<option value="low">Low</option>
    	<option value="medium">Medium</option>
    	<option value="high">High</option>
    </select>
       
    <div id="grid-example"></div>
     <!---->
    </body>
    </html>

  4. #4
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default php file

    php file


    Just enough to make it work basically. Uses post requests (mostly), no validation etc. is done.

    You'll notice the tax function is very trivial. I basically just wanted to test out running to the server to update the grid, similar to using a php library or something.

    Note if you're working with less than php5.2 the json.php library is required, but is included in the zip package.

    PHP Code:

    <?php   

    //database parameters
    $user='test';   //user
    $pw='test';     //user password
    $db='test';     //name of database
    $table='stock'//name of table data stored in

    $taxRate 0.06;
        
    //make database connection
    $connection mysql_connect("localhost"$user$pw) or
       die(
    "Could not connect: " mysql_error());
    mysql_select_db($db) or die("Could not select database");

    $task = ($_POST['task']) ? ($_POST['task']) : null;

    //switchboard for the CRUD task requested
    switch($task){
        case 
    "create":
            
    addData();
            break;
        case 
    "readStock":
            
    showData('stock');
            break;
        case 
    "readIndustry":
            
    getData('industry');
            break;
        case 
    "update":
            
    saveData();
            break;
        case 
    "delete":
            
    removeData();
            break;
        case 
    "calcTax":
            
    getTax();
            break;
        default:
            echo 
    "{failure:true}";
            break;
    }
    //end switch

        
    function showData($table
    {
        global 
    $taxRate;
        
         
    /* By specifying the start/limit params in ds.load 
          * the values are passed here
          * if using ScriptTagProxy the values will be in $_GET
          * if using HttpProxy      the values will be in $_POST (or $_REQUEST)
          * the following two lines check either location, but might be more
          * secure to use the appropriate one according to the Proxy being used
          */
        
    $start = (integer) (isset($_POST['start']) ? $_POST['start'] : $_GET['start']);
        
    $end = (integer) (isset($_POST['limit']) ? $_POST['limit'] : $_GET['limit']);  
        
        
    $sql_count 'SELECT * FROM ' $table;
        
    $sql $sql_count ' LIMIT ' $start ', '$end;
        
        
    $result_count mysql_query($sql_count);
        
    $rows mysql_num_rows($result_count);
        
        
    $result mysql_query($sql);
        
        while(
    $rec mysql_fetch_array($resultMYSQL_ASSOC)){
            
    //these lines are to populate the tax column for the initial display
            //of the grid, any updates to the price are handled by another function below
            
    $price $rec['price'];
            
    $rec['tax'] = round($price * ($taxRate),2);
            
            
    $arr[] = $rec;
        };

        if (
    version_compare(PHP_VERSION,"5.2","<"))
        {    
            require_once(
    "./JSON.php"); //if php<5.2 need JSON class
            
    $json = new Services_JSON();//instantiate new json object
            
    $data=$json->encode($arr);  //encode the data in json format
        
    } else
        {
            
    $data json_encode($arr);  //encode the data in json format
        
    }

        
    /* If using ScriptTagProxy:  In order for the browser to process the returned
           data, the server must wrap te data object with a call to a callback function,
           the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
           If using HttpProxy no callback reference is to be specified*/
        
    $cb = isset($_GET['callback']) ? $_GET['callback'] : '';
           
         echo 
    $cb '({"total":"' $rows '","results":' $data '})';

    }
    //end showData



    function getData($table
    {

        
    $sql 'SELECT * FROM ' $table;
        
    $result mysql_query($sql);

        while(
    $rec mysql_fetch_array($resultMYSQL_ASSOC)){
            
    $arr[] = $rec;
        };

        if (
    version_compare(PHP_VERSION,"5.2","<"))
        {    
            require_once(
    "./JSON.php"); //if php<5.2 need JSON class
            
    $json = new Services_JSON();//instantiate new json object
            
    $data=$json->encode($arr);  //encode the data in json format
        
    } else
        {
            
    $data json_encode($arr);  //encode the data in json format
        
    }

        
    /* If using ScriptTagProxy:  In order for the browser to process the returned
           data, the server must wrap te data object with a call to a callback function,
           the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
           If using HttpProxy no callback reference is to be specified*/
        
    $cb = isset($_GET['callback']) ? $_GET['callback'] : '';
           
         echo 
    $cb '({"results":' $data '})';

    }
    //end getData

                    
    function saveData()
    {
        
    /*
         * $key:   db primary key label
         * $id:    db primary key value
         * $field: column or field name that is being updated (see data.Record mapping)
         * $value: the new value of $field
         */ 

        
    global $table;
        
    $key $_POST['key'];
        
    $id    = (integer) mysql_real_escape_string($_POST['keyID']);
        
    $field $_POST['field'];
        
    $value $_POST['value'];
        
    $newRecord $id == 'yes' 'no';                   
        
        
    //should validate and clean data prior to posting to the database

        
    if ($newRecord == 'yes'){
            
    //INSERT INTO `stock` (`company`) VALUES ('a new company');
            
    $query 'INSERT INTO `'.$table.'` (`'.$field.'`) VALUES (\''.$value.'\')';
        } else {
            
    $query 'UPDATE `'.$table.'` SET `'.$field.'` = \''.$value.'\' WHERE `'.$key.'` = '.$id;
        }

        
    //save data to database                                                    
        
    $result mysql_query($query);
        
    $rows mysql_affected_rows();
        
        if (
    $rows 0) {
            if(
    $newRecord == 'yes'){
                
    $newID mysql_insert_id();
                echo 
    "{success:true, newID:$newID}";
            } else {
                echo 
    "{success:true}";
            }
        } else {
            echo 
    "{success:false}"//if we want to trigger the false block we should redirect somewhere to get a 404 page
        
    }
    }
    //end saveData


    function removeData()
    {
        
    /*
         * $key:   db primary key label
         * $id:    db primary key value
         */ 

        
    global $table;
        
    $key $_POST['key'];
        
    $arr    $_POST['companyID'];
        
    $count 0;


        if (
    version_compare(PHP_VERSION,"5.2","<"))
        {    
            require_once(
    "./JSON.php"); //if php<5.2 need JSON class
            
    $json = new Services_JSON();//instantiate new json object
            
    $selectedRows $json->decode(stripslashes($arr));//decode the data from json format
        
    } else
        {
            
    $selectedRows json_decode(stripslashes($arr));//decode the data from json format
        
    }

        
    //should validate and clean data prior to posting to the database
        
    foreach($selectedRows as $row_id)
        {
            
    $id = (integer) $row_id;
            
    $query 'DELETE FROM `'.$table.'` WHERE `'.$key.'` = '.$id;
            
    $result mysql_query($query); //returns number of rows deleted
            
    if ($result$count++;
        }
        
        if (
    $count) { //only checks if the last record was deleted, others may have failed

            /* If using ScriptTagProxy:  In order for the browser to process the returned
               data, the server must wrap te data object with a call to a callback function,
               the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
               If using HttpProxy no callback reference is to be specified*/
            
    $cb = isset($_GET['callback']) ? $_GET['callback'] : '';
               
            
    $response = array('success'=>$count'del_count'=>$count);


            if (
    version_compare(PHP_VERSION,"5.2","<"))
            {    
                
    $json_response $json->encode($response);
            } else
            {
                
    $json_response json_encode($response);
            }

            echo 
    $cb $json_response;
    //        echo '{success: true, del_count: '.$count.'}';
        
    } else {
            echo 
    '{failure: true}';
        }
    }
    //end saveData

    /**
     * Get Tax
     * Determine tax based on price
     */
    function getTax()
    {                              
        
    $price $_POST['price'];

        if (
    $price >= 0) {
            global 
    $taxRate;

            
    $tax round($price * ($taxRate),2);

            
    $cb = isset($_GET['callback']) ? $_GET['callback'] : '';

            
    $response = array('success'=>'true''tax'=>$tax);

            if (
    version_compare(PHP_VERSION,"5.2","<"))
            {    
                require_once(
    "./JSON.php"); //if php<5.2 need JSON class
                
    $json = new Services_JSON();//instantiate new json object
                
    $json_response $json->encode($response);
            } else
            {
                
    $json_response json_encode($response);
            }

            echo 
    $cb $json_response;
        } else {
            echo 
    '{failure: true}';
        }
    }
    //end getTotal
    ?>
    Last edited by mjlecomte; 23 Nov 2007 at 10:35 PM. Reason: updated

  5. #5
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default js code

    js code


    Last but not least is the js code. As mentioned, this is probably overly commented. It's basically a compilation of what I've picked up from the various tutorials, screencasts, manual, api, forums, etc.
    I've tested on FF2.0.0.8 and IE7 and it appears to work ok.


    PHP Code:
    /**
     * Editor Grid
     * Interacts with server side php/MySQL
     * November 18, 2007
     * Michael LeComte
     */

    /**
     * Ext JS Library 2.0 RC 1
     * Copyright(c) 2006-2007, Ext JS, LLC.
     * licensing@extjs.com
     * http://extjs.com/license
     */

       /**
        * Three main things to do:
        * 1.0 Setup the Data Source (setupDataSource)
        * 2.0 Create the Column Model (getColumnModel)
        * 3.0 Build the Grid (buildGrid)
        */    

    // Reference local blank image to prevent link back to extjs.com
    Ext.BLANK_IMAGE_URL '../../resources/images/default/s.gif';
    //-> this = window

    // Create a namespace Object
    /* By specifying our own namespace we encapsulate all variables and methods in one 
       global object in order to avoid any conflicts or changes when working with other
       javascript files. This pattern scales well as the project becomes more complex 
       and as its API grows. It stays out of the global namespace, provides publicly 
       addressable API methods, and supports protected or “private” data and methods 
       along the way.*/
    Ext.namespace('myNameSpace'); //define namespace with some 'name'
    /* This assigns an empty object myNameSpace as a member of the Ext object (but 
       doesn’t overwrite myNameSpace if it already exists).*/

       ////////////////////////////////////////////////////////////////////////////////////////
       
    // Now we can begin adding members to the Ext.myNameSpace application using the Module Pattern
    myNameSpace.myModule = function(){//creates a property 'myModule' of the namespace object

    //-> this = window
        
        /******************/
        /*--Private Area--*/
        //  can only access this area via the Public Area
        
        /*--Private Variables--*/
        //  Not accessible directly from outside of the module 
        //  These lines executed before document fully loaded, so don't access DOM 
        //  from here (elements do not exist yet)
        
    var myPrivateVar "I can be accessed only from within Ext.myNameSpace.myModule.";
        var 
    ds;
        var 
    dsIndustry;
        var 
    grid//component
        
    var colModel// definition of the columns
        
    var gridForm;
        var 
    myRecordObj;
        var 
    myReader;
        var 
    primaryKey='companyID';
        
        
        
    /*--Private Functions--*/  
        //  Not accessible directly from outside of the module 
        
    var myPrivateMethod = function () {
            
    Ext.log("I can be accessed only from within Ext.myNameSpace.myModule");
        }
        

       
    ////////////////////////////////////////////////////////////////////////////////////////

       /**
        * 1.0 Setup the Data Source (setupDataSource)
        * 1.1 Create Data Record
        * 1.2 Define Reader
        * 1.3 Create Data Store(s)
        * 1.4 Load Data Store(s)
        */
        
    function setupDataSource() {


            
    /*1.1 Create data Record
              This creates a constructor for a specific record layout defining the fields
              that make up an individual row of data.  The Reader is what links the Data Object
              (server side source or other static variable) with the DataStore.  The data
              Record tells the Reader how to associate or map the data from the Data Object
              with the Data Store.
              You can create the data record inline during creation of the reader, but creating
              the object separately here offers us the ability to add records dynamically, as
              an example see the addRecord() function below.
              To create a data record, we pass in an array of field definition objects specifying
              how to reference the data in your Data Object (the source of your data, ie. a
              database or static variable 'myData') */
            
    myRecordObj Ext.data.Record.create([
                {
    name'company'mapping'company'sortDir'ASC'sortType'asUCString'},
                    
    /* name:    'name' by which the field is referenced within the Record.
                     *          It will match the columnModel "dataIndex" property
                     * mapping: required only if the 'reference' != mapping
                     *          where reference is the key in the source data file
                     *          eg. db field name, xml tag name, etc.
                     * sortDir: initial sort direction
                     * sortType: defines explicitly how to perform sort, see Ext.data.SortTypes
                     */
                
    {name'price'type'float'},  //type = how the data should be displayed
                
    {name'tax'type'float'},  //type = how the data should be displayed
                
    {name'change'type'float'}, //will use mapping = 'change'
                
    {name'pctChange'type'float'},
                
    //in the following line dateFormat must match that from the data source (see 'Class Date' in API)
                
    {name'lastChange'type'date'dateFormat'Y-m-d H:i:s'},
                {
    name'industryID'},
                {
    name'risk'},
                {
    name'stars'},
                {
    name'check'},
                {
    nameprimaryKey}//Note the order of fields defined here does not matter, it doesn't relate
                                  //to the order of the fields in your source, nor the order displayed in the grid
                                  //You also do not have to include every field in your data source here
                                  //So if your database table has 10 columns, you can specify 2 here if you want
            
    ]);

         
            
    /*1.2. Define Reader
              The reader extracts the field's value from the data object creating an Array
              of Ext.data.Record objects.
              We need to specify where the reader should look in the response for the data,
              aka the 'root'.  We can also optionally tell the reader where to look for the
              total number of records the Data Object has in case we don't pass all of the
              data in one go (pagination, etc.).
              The Data Object can be in several different base formats, so we need to use
              the proper reader that knows how to deal with the data format, so we specify
              the reader based on the format of the data returned (Xml, Json, Array)
              */
            
    myReader = new Ext.data.JsonReader({ //creates array from JSON response
            /* 
            var myReader = new Ext.data.ArrayReader({//creates array from static array
            var myReader = new Ext.data.XmlReader({  //creates array from XML response
            */
                //1st parameter for reader constructor is to specify config options for reader:
                
    root'results'// name of the property that is container for an Array of row objects
                
    totalProperty'total'/*name of the property from which to retrieve the
                                          total number of records in the dataset.  This is 
                                          only needed if the whole dataset is not passed in
                                          one go, but is being paged from the remote server.*/
                /* The response should come back like this (using Firebug, click on 'Net' tab, click line
                   corresponding to serverside script, then click "Response" to view the response; can
                   also get same information using the "Console" tab):
                ({"total":"29",  <----the 'totalProperty'
                  "results":[    <----the 'root'
                    {"0":"Alcoa Inc","company":"Alcoa Inc",
                     "1":"29.01","price":"29.01",
                     "2":"0.42","change":"0.42",
                     "3":"1.47","pctChange":"1.47",
                     "4":"2007-10-02 00:00:00","lastChange":"2007-10-02 00:00:00",
                     "5":"143","id":"143"},
                    {next record},
                    {next record}]})
                */
                //record: 'item' //the XML delimiter tag for each record (row of data)
                
    idprimaryKey //the property within each row object that provides an ID for the record (optional)
            
    },  //2nd parameter for reader constructor is record constructor object
                //that specifies the record definition (the recordType object containing the field mapping)                                                       
                
    myRecordObj //instead of defining inline just pass a reference to the object 
            
    );

            
    /**
             * 1.3. Create Data Store(s)
             * Set up the data Store object
             * A 'Store' is a client side cache of Ext.data.Record objects which
             * provide input data for widgets.
             * Basically you create this representation of your server side data
             * by defining the objects which specify:
             * 1. proxy - 
             *             how to the read the raw data (which proxy type)
             *          where to read data (the url to the data source)
             *          method to read data (GET or POST request) 
             * 2. reader - takes data and breaks into columns
             */ 

            // Data Store #1
            
    ds = new Ext.data.GroupingStore({ //if grouping
          //ds = new Ext.data.Store({ //if not grouping
                /*1. specify how and where to access data.
                  If data is specified within this file this argument is null
                  Otherwise there are a few options for pulling the data you'd use:
                  a. HttpProxy      reads data from the same domain/server
                  b. ScriptTagProxy reads data object from different domain/server
                  c. MemoryProxy    passes data specified in constructor
                  */
                //set the proxy (method to get the raw data) - required for ScriptTagProxy   
                //note if using HttpProxy you can just specify the url property (HttpProxy is created):
                
    proxy: new Ext.data.HttpProxy({
                    
    //where to retrieve data
                    
    url'grid-editor-mysql-php.php'//url to data object (server side script)
                    
    method'POST'
                
    }),   
                
    baseParams:{task"readStock"},//this parameter is passed for any HTTP request
                /*2. specify the reader
                  The Store object doesn't know what the data looks like or or what
                  format it is in, so a 'reader' is used to read the data into Records
                  The reader object defined here will process the data object and return
                  an array of Ext.data.Record objects which are cached and keyed per 
                  their id property mapping the data we need*/
                
    readermyReader,
                
    sortInfo:{field'company'direction"ASC"}
                
    //remoteSort: true,//true if sort from server (false = sort from cache only)
                //groupField:'industry', //added for GroupingStore, specifies initial group sort
            
    });

            
    // Data Store #2
            // This store will hold the data for the dropdown options
            
    dsIndustry = new Ext.data.Store({
                
    proxy: new Ext.data.HttpProxy({
                    
    //where to retrieve data
                    
    url'grid-editor-mysql-php.php'//url to data object (server side script)
                    
    method'POST'
                
    }),   
                
    baseParams:{task"readIndustry"},//this parameter is passed for any HTTP request
                /*2. specify the reader*/
                
    reader:  new Ext.data.JsonReader(
                    {
                        
    root'results',//name of the property that is container for an Array of row objects
                        
    id'industryID'//the property within each row object that provides an ID for the record (optional)
                    
    },
                    [
                        {
    name'industryID'},//name of the field in the stock table (not the industry table)
                        
    {name'industryName'}
                    ]
                ),
                
    sortInfo:{field'industryName'direction"ASC"}
            }
            );
    //end dsIndustry        


            /*1.4 Load Data Store(s)
              Use ds.loadData to load data directly from static data block array 'myData'
                 ds.loadData(myData); 
              Use ds.load to load data from dynamic data source*/
            
    dsIndustry.load(); //load data store holding our data for the industry column dropdown options
                               //note originally I had this store load second.  But when I did that
                               //the grid was apparently getting rendered the first time before the dsIndustry
                               //store was loaded so the rendered wasn't working (because the 'poop' portion
                               //of the if statement below was invoked since the store didn't exist yet
                               //After playing around I've noticed that the store must get returned before
                               //the execution gets to the grid render() line, otherwise it will still render
                               //the grid but the store will be empty and thus display an empty grid.  If you
                               //use the paging toolbar refresh that will probably show all the data because
                               //it just refreshes the page from the cached data store        
            
    ds.load({params: { //parameters for the FIRST page load, use baseParams above for ALL pages.
                
    start0//pass start/limit parameters for paging
                
    limitmyNameSpace.myModule.perPage//
            
    }}); //it is at this point that we'll request the data from the server.
                 //note that this file keeps going independent of the server, thus
                 //making this an asynchronous process, hopefully the server will respond
                 //prior to calling render() on the grid, otherwise we'll have a blank grid.
                 //If you're stepping through firebug, it's at this point you'll see the
                 //XHR get sent out.

        
    // end setupDataSource
        
       ////////////////////////////////////////////////////////////////////////////////////////

       /**
        * 2.0 Get the Column Model (getColumnModel)
        *     We have all of this data that came from the source (possibly server side) and then
        *     we read that data into a client side cache (store).  Now we have to decide what
        *     parts of that data we want to display and how we want to display it.  We may have
        *     some data we don't want displayed, or want some of it shown in a particular way. 
        * 2.1 Create Custom Renderers
        * 2.2 Create the Column Model
        */
        
    function getColumnModel() {
            if(!
    colModel) { //only need to create columnModel if it doesn't already exist

                /*2.1. Create Custom Renderers*/

                  /** 
                   * Italic Custom renderer function
                   * val rendered in italics
                   * @param {Object} val
                   */
                
    function italic(val){
                    return 
    '<i>' val '</i>';
                };

                
    /** 
                 * Red/Green Custom renderer function
                 * renders red if <0 otherwise renders green 
                 * @param {Object} val
                 */
                
    function renderPosNeg(val){
                    if(
    val >= 0){
                    
    //-> this = obj (row from grid, properties of id, name='change', style)
                        
    return '<span style="color:green;">' val '</span>';
                    }else if(
    val 0){
                        return 
    '<span style="color:red;">' val '</span>';
                    }
                    return 
    val;
                };

                
    /** 
                 * Percent Custom renderer function
                 * Renders red or green with %
                 * @param {Object} val
                 */
                
    function renderPctChange(val){
                    if(
    val >= 0){
                    
    //-> this = obj (row from grid, properties of id, name='pctChange', style)
                        
    return '<span style="color:green;">' val '%</span>';
                    }else if(
    val 0){
                        return 
    '<span style="color:red;">' val '%</span>';
                    }
                    return 
    val;
                };

                
    /** 
                 * Risk Custom renderer function
                 * Renders according to risk level
                 * @param {Object} val
                 */
                
    function renderRisk(datacellrecordrowIndexcolumnIndexstore){
                    switch(
    data) {
                        case 
    "high":
                            
    cell.css "redcell";
                            return 
    "high";
                        case 
    "medium":
                            return 
    "medium";
                        case 
    "low":
                            return 
    "low";
                    }
                };

                
    /** 
                 * Star Custom renderer function
                 * Renders a picture according to value
                 * @param {Object} val
                 */
                
    function renderStars(datacellrecordrowIndexcolumnIndexstore){
                    switch(
    data) {
                        case 
    "1":    cell.css "stars1";   return 1;//returns text over the background image
                        
    case "2":    cell.css "stars2";   return;//just shows the background image
                        
    case "3":    cell.css "stars3";   return;
                        case 
    "4":    cell.css "stars4";   return;
                        case 
    "5":    cell.css "stars5";   return;
                    }
                };


                
    /** 
                 * Date renderer function
                 * Renders a date
                 * @param {Object} val
                 */
                
    function renderDate(value){
                    
    //Ext.util.Format.dateRenderer('m/d/Y')
                    
    return value value.dateFormat('M d, Y') : '';
                };


                
    // custom column plugin example
                //var checkColumn = new Ext.grid.CheckColumn({
                
    this.checkColumn = new Ext.grid.CheckColumn({
                    
    header"Check",
                    
    dataIndex'check'
                    
    width9
                    
    sortabletrue
                
    });
        
                
    /**
                 * Check Column event listener
                 * @param {Object} element
                 * @param {Object} e
                 * @param {Object} record
                 */
                
    this.checkColumn.on('click', function(elementerecord) {
                      
    //alert(record.get('check'));
                    
    var myField this.dataIndex;//the field name
                    
    var check record.data[this.dataIndex];//same as record.data.check (but more abstract)
                    
    var checkStatus check 'checked' 'unchecked';
                    var 
    checkItem record.data.company;
                    var 
    checkID record.data.companyID;
                    
    Ext.example.msg('Item Check''You {0} the "{1}" check box, ID = {2}.'checkStatuscheckItemcheckID);
                    var 
    myMsg 'You <b>'checkStatus '</b> the "<i>' checkItem '</i>" check box, ID = ' '<span style="color:blue;">' checkID '</span>.';
                    
    Ext.MessageBox.alert('Item Check'myMsg);
                    var 
    checkBoolean check 0;

                    
    //update the database
                    
    Ext.Ajax.request(
                        { 
    //ajax request configuration  
                            
    waitMsg'Saving changes...',
                            
    url'grid-editor-mysql-php.php'//url to server side script
                            
    params: { //these will be available via $_POST or $_REQUEST:
                                
    task"update"//pass task to do to the server script
                                
    keyprimaryKey,//pass to server same 'id' that the reader used
                                
    keyIDcheckID,//for existing records this is the unique id (we need this one to relate to the db)
                                //newRecord: isNewRecord,//pass the new Record status indicator to server for special handling
                                
    fieldmyField,//the column name
                                
    valuecheckBoolean,//the updated value
                                
    originalValue: !checkBoolean//the original value (oGrid_Event.orginalValue does not work for some reason)
                            
    },//end params
                            
    failure:function(response,options){
                                
    Ext.MessageBox.alert('Warning','Oops...');
                            },
    //end failure block                                      
                            
    success:function(response,options){
                                
    //Ext.MessageBox.alert('Success','Yeah...');
                                
    if(checkID == 0){
                                    var 
    responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                                    
    var newID responseData.newID;//extract the ID provided by the server
                                    
    record.set('newRecord','no');//reset the indicator since update succeeded
                                    
    record.set('companyID',newID);//assign the id to the record
                                    
    ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                                
    } else {
                                    
    ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                                
    }
                            }
    //end success block                                      
                         
    }//end ajax request config
                    
    ); //end ajax request  
                
    });


                
    /** 
                 * 2.2. Create the Column Model
                 * Set up the ColumnModel object to define the initial layout/display of the grid.
                 * The order specified here defines the order of initial column display.
                 * We also define how each column in the grid correlates (maps) to our 
                 * DataStore with dataIndex. 
                 *   "mapping"   specifies how the data object relates/maps to the DataStore (client side cache of data).
                 *   "dataIndex" specifies how the DataStore   relates/maps to the ColumnModel (actual display).
                 * It can be extended to provide custom or reusable ColumnModels 
                 */
                
    colModel = new Ext.grid.ColumnModel([ //instantiate ColumnModel
                       //Here we give comma separated definitions of the fields we want
                       //displayable (some may be initially hidden) in the grid.
                       //Note you need not display every column in your data store here;
                       //you can include fields here and have them be hidden or
                       //you can just not include some fields in your grid whatsoever (maybe
                       //you just retrieved them to do other behind the scenes processing
                       //client side instead of server side)
                    
    {  
                        
    id:    'classCompanyID',//by placing an id on this column we can later reference the column specifically
                                         //For instance we could set a css style to highlight the column (.x-grid3-col-classCompanyID)
                                         //This doesn't work well with an editor grid though, as the red triangle gets covered up.
                                         //Perhaps something with the z-index could be changed so the red triangle remained on top?
                                         //Another use might be to select an entire column and do something with it
                                         //Example anyone?
                        
    header:"ID",//header = text that appears at top of column
                        
    width9,      //column width
                        
    sortabletrue,//false (default) to disable sorting by this column
                        
    lockedfalse,
                        
    align'right',//default is to align to the left
                        //hidden: true, //true to initially hide the column
                        
    dataIndex'companyID'//the DataStore field "name" this column draws its data from
                                            //dataIndex = rt name
                     
    },{                         
                        
    id:    'classCompany',//by placing an id on this column we can later reference the column specifically
                                         //currently the html page sets a css style to highlight the column (.x-grid3-col-classCompany)
                                         //we may be able to select an entire column and do something with it
                                         //example anyone?
                        
    header:"Company",//header = text that appears at top of column
                        
    width40,      //column width
                        
    sortabletrue,//false (default) to disable sorting by this column
                        
    lockedfalse,
                        
    //resizable: false, //disable column resizing (can also used fixed = true)
                        
    dataIndex'company',//the DataStore field "name" this column draws its data from
                                            //dataIndex = rt name
                        
    editor: new Ext.form.TextField({ //TextField editor - for an editable field add an editor
                            //specify options
                            
    allowBlankfalse //default is true (nothing entered)
                        
    })                           
                    },{                         
                        
    header"Price"
                        
    width12
                        
    sortabletrue,
                        
    //hidden: true,//true to initially hide the column 
                                       //(NOTE: as of Ext2.0-rc1 the GroupingStore has problems sizing the grid when columns are hidden)  
                        
    rendererExt.util.Format.usMoney,//optional rendering function to provide customized data formatting 
                        
    dataIndex'price',
                        
    align'right',//default is to align to the left
                        
    editor: new Ext.form.NumberField({
                            
    //specify options
                            
    allowBlankfalse,  //default is true (nothing entered)
                            
    allowNegativefalse//could also use minValue
                            
    maxValue100
                        
    })
                    },{                         
                        
    header"Tax"
                        
    width12
                        
    sortabletrue,
                        
    rendererExt.util.Format.usMoney,//optional rendering function to provide customized data formatting 
                        
    dataIndex'tax',
                        
    align'right'//default is to align to the left
                    
    },{
                        
    header"Change"
                        
    width12
                        
    sortabletrue
                        
    rendererrenderPosNeg
                        
    dataIndex'change',
                        
    align'center'
                    
    },
                    {
    header"% Change"width15sortabletruerendererrenderPctChangedataIndex'pctChange'},
                    {
                        
    header"Last Updated"
                        
    width20
                        
    sortabletrue
                        
    rendererrenderDate
                        
    dataIndex'lastChange',
                        
    editor: new Ext.form.DateField({ //DateField editor
                            //specify options
                            
    allowBlankfalse,  //default is true (nothing entered)
                            //format: 'd/m/y', //defaults to 'm/d/y', if there is a renderer 
                                               //specified it will render whatever this form
                                               //returns according to the renderer
                            
    minValue'10/15/07'//anything prior to is greyed out/unclicklable
                                                 //validator prevents typing a new date violating criteria 
                            
    disabledDays: [036],
                            
    disabledDaysText'Closed on this day'
                        
    })
                    },{
                        
    header"Industry",
                        
    width23
                        
    sortabletrue
                        
    dataIndex'industryID',//this is what is specified in the reader
                        
    editor: new Ext.form.ComboBox({ //dropdown based on server side data (from db)
                            
    typeAheadfalse//will be querying database so may not want typeahead consuming resources
                            
    triggerAction'all',
                            
    lazyRendertrue,//prevents combo box from rendering until requested, should always be true for editor
                            
    storeds,//Industry,//where to get the data for our combobox
                            
    displayField'industryName',//the underlying data  field name to bind to this ComboBox
                                                         //(defaults to undefined if mode = 'remote' or 'text' if transforming a select)
                            
    valueField'industryID'     //the underlying value field name to bind to this ComboBox
                        
    }),
                        
    renderer:
                                function(
    data) {
                                    
    record dsIndustry.getById(data);//same as accessing this.data.key(id)
                                    
    if(record) {
                                        return 
    record.data.industryName;
                                    } else {
                                        
    //return data;
                                        
    return 'poop';
                                    }
                                }
                    },{
                        
    header"Risk",
                        
    width11
                        
    sortabletrue
                        
    rendererrenderRisk
                        
    dataIndex'risk',
                        
    editor: new Ext.form.ComboBox({ //dropdown based on client side data (from html)
                            
    typeAheadtrue,
                            
    triggerAction'all',
                            
    transform:'riskID',//look for this id to transform the html option values to a dropdown
                            
    lazyRender:true,//prevents combo box from rendering until requested, should always be true for editor
                            
    listClass'x-combo-list-small' //css class to apply to the dropdown list element
                        
    })
                    },{
                        
    header"Stars",
                        
    width8
                        
    sortabletrue
                        
    rendererrenderStars
                        
    dataIndex'stars',
                        
    align'center'
                    
    },
                    
    checkColumn //defined above
                
    ]);//end colModel
                
                //instead of specifying sorting permission by individual columns can also specify for entire grid
                //colModel.defaultSortable = false;

            
    }//end if colModel
            
    return colModel;
        }
    //getColumnModel

       ////////////////////////////////////////////////////////////////////////////////////////

       /**
        * 3.0 Build the Grid (buildGrid)
        * 3.1 Create Handlers 
        * 3.2 Create (instantiate) the Grid 
        * 3.3 Render the Grid (make it lazy if you want) 
        * 3.4 Add listeners to the Grid 
        */
        
    function buildGrid() {    
    /*
            gridForm = new Ext.BasicForm(
                Ext.get("updategrid"),
                {
                    
                }
            ); //end gridForm
    */            

            /**
             * 3.1. Create Handlers
             * Create functions to handle various events
             */

            /**
             * Function for Refreshing Grid
             */ 
            
    function refreshGrid() {
                
    ds.reload();//
            
    }; // end refresh 

            /**
             * Handler for Adding a Record
             */
            
    function addRecord() {
                var 
    = new myRecordObj({
                    
    //specify default values
                    
    companyID0,//use this to trigger special handling when updating 
                    
    company''//you can't comment out this line if you want the editor
                                 //to start there, as it will show the html tags
                    
    price0.00,
                    
    tax0.00,
                    
    change0.00,
                    
    pctChange0.00,
                    
    lastChange: (new Date()).clearTime(),
                    
    industry'',
                    
    risk'',
                    
    stars'0',
                    
    //newRecord:'yes',//use this to trigger special handling when updating
                    //id: 0//this is not helpful, 
                
    });
                
    grid.stopEditing();//stops any acitve editing
                
    ds.insert(0r); //1st arg is index,
                                 //2nd arg is Ext.data.Record[] records
                //very similar to ds.add, with ds.insert we can specify the insertion point
                
    grid.startEditing(01);//starts editing the specified rowIndex, colIndex
                                        //make sure you pick an editable location in the line above
                                        //otherwise it won't initiate the editor
            
    }; // end addRecord 

            
            //add an event to handle any updates to grid
            
            
            /**
             * Handler to control grid editing
             * @param {Object} oGrid_Event
             */
            
    function handleEdit(editEvent) {
                var 
    gridField editEvent.field;//determine what column is being edited
                
    updateDB(editEvent);//start the process to update the db with cell contents
                
                //I don't want to wait for server update to update the Total Column
                
    if (gridField == 'price'){
                    
    getTax(editEvent);//start the process to update the Tax Field
                
    }
            }
            
            
    /**
             * Function for updating database
             * @param {Object} oGrid_Event
             */
            
    function updateDB(oGrid_Event) {
                
                
    /*Do we need to disable a new record from further editing while the first request
                  is being made since the record may not have the new companyID in time
                  to use to properly handle other updates of the same record? 
                  
                  Dates come through as an object instead of a string or numerical
                  value, so do a check to prep the new value for transfer to the
                  server side script*/
                
    if (oGrid_Event.value instanceof Date)
                {   
    //format the value for easy insertion into MySQL
                    
    var fieldValue oGrid_Event.value.format('Y-m-d H:i:s');
                } else
                {
                    var 
    fieldValue oGrid_Event.value;
                }    
                        
                
    //submit to server
                
    Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm
                    
    {   //specify options (note success/failure below that receives these same options)
                        
    waitMsg'Saving changes...',
                        
    //url where to send request
                        
    url'grid-editor-mysql-php.php'//url to server side script
                        //method: 'POST', //if specify params default is 'POST' instead of 'GET'
                        
    params: { //these will be available via $_POST or $_REQUEST:
                            
    task"update"//pass task to do to the server script
                            
    keyprimaryKey,//pass to server same 'id' that the reader used
                            
    keyIDoGrid_Event.record.data.companyID,//for existing records this is the unique id (we need this one to relate to the db)
                                                                     //we'll check this server side to see if it is a new record                    
                         //   bogusID: oGrid_Event.record.id,//for new records Ext creates a number here unrelated to the database
                         //   newRecord: isNewRecord,//pass the new Record status indicator to server for special handling
                            
    fieldoGrid_Event.field,//the column name
                            
    valuefieldValue,//the updated value
                            
    originalValueoGrid_Event.record.modified//the original value (oGrid_Event.orginalValue does not work for some reason)
                                                                      //this might(?) be a way to 'undo' changes other than by cookie?
                                                                      //when the response comes back from the server can we make an undo array?                         
                        
    },//end params
                        //the function to be called upon failure of the request (404 error etc, NOT success=false)
                        
    failure:function(response,options){
                            
    Ext.MessageBox.alert('Warning','Oops...');
                            
    //ds.rejectChanges();//undo any changes
                        
    },//end failure block                                      
                        
    success:function(response,options){
                            
    //Ext.MessageBox.alert('Success','Yeah...');
                            
    if(oGrid_Event.record.data.companyID == 0){
                                var 
    responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                                
    var newID responseData.newID;//extract the ID provided by the server
                                //oGrid_Event.record.id = newID;
                                
    oGrid_Event.record.set('newRecord','no');//reset the indicator since update succeeded
                                
    oGrid_Event.record.set('companyID',newID);//assign the id to the record
                                //note the set() calls do not trigger everything since you may need to update multiple fields for example
                                //so you still need to call commitChanges() to start the event flow to fire things like refreshRow()
                                
    ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                                //var whatIsTheID = oGrid_Event.record.modified;
                            
    } else {
                                
    ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                            
    }
                        }
    //end success block                                      
                     
    }//end request config
                
    ); //end request  
            
    }; //end updateDB 


            /**
             * Function for updating Tax shown in grid
             * @param {Object} oGrid_Event
             */
            
    function getTax(oGrid_Event) {
                
                
    //submit to server
                
    Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm
                    
    {   //specify options (note success/failure below that receives these same options)
                        //waitMsg: 'Saving changes...',
                        //url where to send request
                        
    url'grid-editor-mysql-php.php'//url to server side script
                        //method: 'POST', //if specify params default is 'POST' instead of 'GET'
                        
    params: { //these will be available via $_POST or $_REQUEST:
                            
    task"calcTax"//pass task to do to the server script
                            
    priceoGrid_Event.value//the updated value
                        
    },//end params
                        //the function to be called upon failure of the request
                        
    failure:function(response,options){
                            
    Ext.MessageBox.alert('Warning','Oops...');
                            
    //ds.rejectChanges();//undo any changes
                        
    },//end failure block                                      
                        
    success:function(response,options){
                            
    //Ext.MessageBox.alert('Success','Yeah...');
                            
    var responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                            
    var myTax responseData.tax;//extract the value provided by the server
                            //oGrid_Event.record.data.tax = myTax;//assign the tax to the record
                            //oGrid_Event.record.tax= myTax;//assign the id to the record
                            
    oGrid_Event.record.set('tax',myTax);
                            
    ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                        
    }//end success block                                      
                     
    }//end request config
                
    ); //end request  
            
    }; //end getTax 

            
            /**
             * Handler for Deleting record(s)
             */ 
            
    function handleDelete() {
                var 
    selectedKeys grid.selModel.selections.keys//returns array of selected rows ids only
                
    if(selectedKeys.length 0)
                {
                    
    Ext.MessageBox.confirm('Message','Do you really want to delete selection?'deleteRecord);
                }
                else
                {
                    
    Ext.MessageBox.alert('Message','Please select at least one item to delete');
                }
    //end if/else block
            
    }; // end handleDelete 

            /**
             * Function for Deleting record(s)
             * @param {Object} btn
             */ 
            
    function deleteRecord(btn) {
                if(
    btn=='yes')
                {
                    
    /* block if just want to remove 1 row
                    var selectedRow = grid.getSelectionModel().getSelected();//returns record object for the most recently selected
                                                                         //row that is in data store for grid
                    if(selectedRow){
                        ds.remove(selectedRow);
                    } //end of block to remove 1 row
                    */
                    
    var selectedRows grid.selModel.selections.items;//returns record objects for selected rows (all info for row)
                    
    var selectedKeys grid.selModel.selections.keys//returns array of selected rows ids only

                    //note we already did an if(selectedKeys) to get here

                    
    var encoded_keys Ext.encode(selectedKeys);//encode array into json
                    //submit to server
                    
    Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm.submit
                        
    {   //specify options (note success/failure below that receives these same options)
                            
    waitMsg'Saving changes...',
                            
    //url where to send request
                            
    url'grid-editor-mysql-php.php'//url to server side script
                            
    params: { //these will be available via $_POST or $_REQUEST:
                                
    task"delete"//pass task to do to the server script
                                
    companyIDencoded_keys,//the unique id(s)
                                
    keyprimaryKey//pass to server same 'id' that the reader used
                            
    },
                            
    /* you can also specify a callback (instead of or in addition to 
                            success/failure) for custom handling.  If you have success/failure
                            defined, those will fire before 'callback'.  This callback will fire
                            regardless of success or failure.*/
                            
    callback: function (optionssuccessresponse) {
                                if (
    success) { //success will be true if the request succeeded
                                    
    Ext.MessageBox.alert('OK',response.responseText);//you won't see this alert if the next one pops up fast
                                    
    var json Ext.util.JSON.decode(response.responseText);
                                    
    Ext.MessageBox.alert('OK',json.del_count ' record(s) deleted.');//need to move this to an after
                                    //event because it will fire before the grid is re-rendered (while the deleted row(s) are still there
                                    //You could update an element on your page with the result 
                                    //from the server (e.g.<div id='total'></div>)
                                    //var total = Ext.get('total');
                                    //total.update(json.sum);
                                
    } else {
                                    
    Ext.MessageBox.alert('Sorry, please try again. [Q304]',response.responseText);
                                }
                            },
                            
    /* */
                            //the function to be called upon failure of the request (server script, 404, or 403 errors)
                            
    failure:function(response,options){
                                
    Ext.MessageBox.alert('Warning','Oops...');
                                
    //ds.rejectChanges();//undo any changes
                            
    },                                      
                            
    success:function(response,options){
                                
    //Ext.MessageBox.alert('Success','Yeah...');
                                
    ds.reload();//commit changes and remove the red triangle which indicates a 'dirty' field
                            
    }                                      
                         } 
    //end Ajax request config
                    
    );// end Ajax request initialization
                
    };//end if click 'yes' on button
            
    }; // end deleteRecord 


            /**
             * 3.2. Create (instantiate) the Grid
             * This creates the actual GUI for the Grid.
             * We specify here where, how, and when to render the Grid.
             */
          //grid = new Ext.grid.GridPanel({ //to instantiate normal grid
            
    grid = new Ext.grid.EditorGridPanel({ //to instantiate editor grid
                //el:'grid-example', //html element (id of the div) where the grid will be rendered
                //'renderTo' does the same as 'el', except eliminated the need to explicitly call render() 
                //renderTo: 'grid-example',//could also render it directly to document.body 
                 
    iconCls'icon-grid',//we create our own css with a class called 'icon-grid'
                
    storeds,       //the DataStore object to use (ds: is shorthand)
                
    colModelgetColumnModel(), //gets the ColumnModel object to use (cm: is shorthand)
                
    autoExpandColumn'company'//which column to stretch in width to fill up the grid width and not leave blank space
              //autoSizeColumns: true,//deprecated as of Ext2.0
                //Enable a Selection Model.  The Selection Model defines the selection behavior,
                //(single vs. multiple select, row or cell selection, etc.)
                
    selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),//true to limit row selection to 1 row})
               //footer: true,
                
    height:350,//you must specify height or autoHeight
                //autoHeight:true,//autoHeight resizes the height to show all records
                
    width:740,
                
    title:'This is the Grid Title',
                
    clicksToEdit:2,//number of clicks to activate cell editor, default = 2        
                
    plugins:this.checkColumn,
                
    //frame:true,//add a frame around the grid; defaults to no frame 
                
    cellclick: function()
                {
                    var 
    record grid.getStore().getAt(rowIndex); //get the record
                    
    var fieldName grid.getColumnModel().getDataIndex(columnIndex);//get field name
                    
    var data record.get(fieldName);
                    
    Ext.MessageBox.alert('title','inside function');
                       
    //title: 'My Title Here',
                       //msg: 'outside the function...'
                       //fn: myCallBackFunction,//the callback function after the msg box is closed
                       //scope:this//scope of callback function   
                
    },
                
    stripeRowstrue,//applies css classname to alternate rows, defaults to false
                //trackMouseOver: true,//highligts rows on mousever
                //Add a bottom bar      
                
    bbar: new Ext.PagingToolbar({
                    
    pageSizemyNameSpace.myModule.perPage,//default is 20
                    
    storeds,
                    
    displayInfotrue,//default is false (to not show displayMsg)
                    
    displayMsg'Displaying topics {0} - {1} of {2}',
                    
    emptyMsg"No data to display",//display message when no records found
                    
    items:[
                        
    '-', {
                        
    pressedtrue,
                        
    enableToggle:true,
                        
    text'Show Preview',
                        
    cls'x-btn-text-icon details'
                        
    //toggleHandler: toggleDetails  
                    
    }]
                }),
                
    //Add a top bar      
                
    tbar: [
                    {
                        
    text'Add Record',
                        
    tooltip'Click to Add a row',
                        
    iconCls:'add'//we create our own css with a class called 'add'
                                       //custom class not included in ext-all.css by default
                        
    handleraddRecord //what happens when user clicks on it
                    
    }, '-'//add a separator
                    
    {
                        
    text'Delete Selected',
                        
    tooltip'Click to Delete selected row(s)',
                        
    handlerhandleDelete//what happens when user clicks on it
                        
    iconCls:'remove' //we create our own css with a class called 'add'
                    
    }, '-'//add a separator
                    
    {
                        
    text'Refresh',
                        
    tooltip'Click to Refresh the table',
                        
    handlerrefreshGrid//what happens when user clicks on it
                        
    iconCls:'refresh' //we create our own css with a class called 'add'
                    
    }
                ],
                
    //this is the key to showing the GroupingStore
                
    view: new Ext.grid.GroupingView({
                    
    forceFit:true,
                    
    //custom grouping text template to display the number of items per group
                    
    groupTextTpl'{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
                
    }) /**/
            
    });//end grid
         
            // ## THIS DOES NOT WORK ## //
            /*  
            var rz = new Ext.Resizable("grid-example",{
                wrap:true,
                minHeight:100,
                pinned: true,
                handles:'all'
            });
            rz.on("resize", grid.autosize, grid);
            */ 

            /**
             * 3.3 Render the Grid (make it lazy if you want)
             * Explicitly rendering the grid is only required if "renderTo" is not specified
             * in the configuration of the grid object above.
             * In Ext2.0, every component automatically supports "lazy" (on demand) rendering.
             * The rendering pipeline is managed automatically if you use "renderTo" in the
             * grid constructor.  Instead of using "renderTo" you can explicitly render the grid
             * when you want using render(). This gives you the flexibility or power to control
             * the rendering process.  In addition to render() you can also use the beforerender()
             * event (see Ext.Component).
             * 3.4 Add listeners to the Grid
             */
            
    grid.render('grid-example');//1st argument is the container, 2nd argument is the position within
                                        //the div (defaults to end of the container)
            
            /**
             * 3.4 Add listeners to the Grid
             */

            /**
             * Add right click event
             * rowcontextmenu fires when a row is right clicked
             */ 
            
    grid.addListener('rowcontextmenu'onMessageContextMenu);

            
    //callback function for the right click event 
            
    function onMessageContextMenu(gridrowIndexe) {
                
    e.stopEvent();
                var 
    coords e.getXY();
                var 
    record grid.getStore().getAt(rowIndex);//OK, we have our record, now how do we pass
                                                             //it to the referenced handler?

                
    var messageContextMenu = new Ext.menu.Menu({
                    
    id'messageContextMenu',
                    
    items: [
                    {
                        
    text'Properties',
                        
    handleronMessageContextItemClick
                        
    //handler: showRecord(record)
                    
    },
                    {
                        
    text'I like Ext',
                        
    checkedtrue,       // when checked has a boolean value, it is assumed to be a CheckItem
                        
    checkHandleronItemCheck
                    
    }
                    ]
                });
                
                
    //predefine a menu item
                
    var menuItem = new Ext.menu.Item({text'<i>New Item</i>'});

                 
    //shows how to add items dynamically
                
    var item messageContextMenu.add(
                    
    '-',
                    
    menuItem//add item by reference
                    
    {    
                        
    text'<u>View in new tab</u>',
                        
    //handler: onMessageContextItemClick(this,['open']),
                        
    handler: function(){
                            
    this.viewer.openTab(this.ctxRecord);
                        },
                        
    iconCls:'add'
                    
    },
                        {
    text'<b>Print</b>'menu: new Ext.menu.Menu({// <-- submenu by nested config object
                            
    items: [
                                {
    text'PDF',  handler:function(){callPrintPreview("PDF");} },
                                {
    text'EXCEL',handler:function(){callPrintPreview("EXCEL ");} },
                                {
    text'HTML'handler:function(){callPrintPreview("HTML") ;} },
                                {
    text'WORD'handler:function(){callPrintPreview("WORD") ;} }
                            ]
                        })},
                        {
    text'<b>Save Preferences</b>',handler: function(){saveUserPref(Ext.encode(colModel.config));}}
                );

                
    messageContextMenu.showAt([coords[0], coords[1]]);
                
    e.preventDefault();//to disable the standard browser context menu
            
    }


            
    /**
             * Handlers for right clicks
             */ 
            
    function onMessageContextItemClick(item) {
                
    //Ext.MessageBox.alert('Request','You selected the {0} menu item',item.text);
                
    Ext.MessageBox.alert('Request','You selected '+this.text);
            }; 
    // end right click handler 

            
    function onItemCheck(itemchecked){
                
    Ext.example.msg('Item Check''You {1} the "{0}" menu item.'item.textchecked 'checked' 'unchecked');
            }

            function 
    SaveToExcel(item) {
                
    Ext.MessageBox.alert('Request','You selected '+this.text);
            }; 
            function 
    callDelete(item) {
                
    Ext.MessageBox.alert('Request','You selected '+this.text);
            }; 
            function 
    callTrade(item) {
                
    Ext.MessageBox.alert('Request','You selected '+this.text);
            }; 
            function 
    callPrintPreview(item) {
                
    Ext.MessageBox.alert('Request','You selected '+this.text);
            }; 


            
    /**
             * Add an event to handle any updates to grid
             */ 
            
    grid.addListener('afteredit'handleEdit);//give event name, handler (can use 'on' shorthand for addListener) 
            
            
            //instead of adding listeners individually could have also loaded together like so:   
            /*
            grid.addListener({  //same as saying grid.on
                'rowcontextmenu': onMessageContextMenu,
                'afteredit': handleEdit
                //note other listeners are same just without the 'on' (mousever, mouseout, click, etc.)
            });
            */


                
            /**
             * Grid rendering effects
             * if we want to render rows depending on values in row
             */ 
            
    grid.getView().getRowClass = function(recordindex) {
                switch (
    record.data.stars) {
                    case 
    '0'
                    
    //right now just keying off of stars = '0' to signify the row has
                    //not been saved yet, might be better to key from when the 'id' is no longer zero
                    //but for now I just chose the last column thinking that would be the last to get updated
                        
    return "yellowrow"
                        
    break
                    case 
    '5':
                        return 
    "greenrow"
                        
    break
                    case 
    '4':
                        return 
    "pinkrow"
                        
    break
                    default:
                        
    //something else?
                
    }
            };
    //end row rendering


            // This line to highlight the first row of the grid is quite finicky.  There's probably
            // a better way to do this that is more reliable.  It seems like this next line may get
            // executed before the grid is rendered and may not fire depending on the timing.
            
    grid.getSelectionModel().selectFirstRow();
        
            
        }
    //end function buildGrid

        
        /*--Private Area--*/
        /******************/
     
        /*****************/
        /*--Public Area--*/
        
    return {//returns an object Ext.myNameSpace.module1 with the following methods:
            /*--Public Properties--*/
            // it's good practice to put the following in the public area of the module:
            //   text used by module, default dmensions, styles, customizable options, etc.
            
    myPublicProperty"I'm accessible as myNameSpace.myModule.myPublicProperty.",
        
            
    perPage50//page limit

            /*--Public Methods--*/
            //  Public methods can be called from outside
            //  Public methods can access Private Area
            
    myPublicMethod: function(){//accessible as myNameSpace.myModule.myPublicMethod
                
    var myOtherProperty this.myPublicProperty //use 'this' to refer to Public Property
                
    return myPrivateVar//note reference to Private variable does NOT use 'this'
            
    },
            
    init : function(){ //this method is called by the last line below that looks like this:
                               //Ext.onReady(myNameSpace.myModule.init, myNameSpace.myModule, true);
                               //So once the document is fully loaded that line gets executed and we
                               //end up here.  As a result, this is a good place to put DOM dependent tasks 

                /* Put initialization code here */

                /**
                 * Set up plugin for a check column
                 * @param {Object} config
                 */
                
    Ext.grid.CheckColumn = function(config){
                    
    this.addEvents({
                        
    clicktrue
                    
    });
                    
    Ext.grid.CheckColumn.superclass.constructor.call(this);
                    
                    
    Ext.apply(thisconfig, {
                        
    init : function(grid){
                            
    this.grid grid;
                            
    this.grid.on('render', function(){
                                var 
    view this.grid.getView();
                                
    view.mainBody.on('mousedown'this.onMouseDownthis);
                            }, 
    this);
                        },
                    
                        
    onMouseDown : function(et){
                            if(
    t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
                                
    e.stopEvent();
                                var 
    index this.grid.getView().findRowIndex(t);
                                var 
    record this.grid.store.getAt(index);
                                
    record.set(this.dataIndex, !record.data[this.dataIndex]);
                                
    this.fireEvent('click'thiserecord);
                            }
                        },

                        
    renderer : function(vprecord){
                            var 
    checkState = (+v) ? '-on' '';//the +v type converts to a number (json returns a string which always evaluates true)
                            
    p.css += ' x-grid3-check-col-td'
                          
    //return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
                            
    return '<div class="x-grid3-check-col'checkState +' x-grid3-cc-'+this.id+'"> </div>';
                        }
                    });
                    
                  if(!
    this.id){
                      
    this.id Ext.id();
                  }
                  
    this.renderer this.renderer.createDelegate(this);
                };
                
                
    Ext.extend(Ext.grid.CheckColumnExt.util.Observable);// extend Ext.util.Observable

                //done with plugin setup        
                /////////////////////////////////////////////////////////////////
        
        
                 // get our Grid!
                
    this.getMyGrid();// this = refers to properties and methods inside the public area
        
                // Works without this, used for state awareness...
                //Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
            
    },//end of init
           
            /**
             * getMyGrid
             * Call after initialization to get our Grid
             */
            
    getMyGrid: function() {  
                
    Ext.QuickTips.init();// Enable Quicktips
                
    setupDataSource();
                
    buildGrid();
            },
            
    //a method we can call from Firebug console to check what is in our Data Store
            
    getDataSource: function() {  
                return 
    ds;
            }
        }
        
    /*--Public Area--*/
        /*****************/
    }(); /* End of application. Note the parentheses () — this notation causes the anonymous
            function to execute immediately, returning the object containing myPublicProperty 
            and myPublicMethod. As soon as the anonymous function returns, that returned object
            is addressable as myNameSpace.myModule.   */


    // Since the above code has already executed, we can access the init method immediately:
    Ext.onReady(myNameSpace.myModule.initmyNameSpace.myModuletrue);
    /* This line executes the myModule.init method after the document has been completely
       loaded. This line also sets the myModule.init method scope to myModule, which means
       you can call Public attributes (methods and properties) with a preceding 'this'.*/ 
    Last edited by mjlecomte; 23 Nov 2007 at 10:36 PM. Reason: various edits and updates

  6. #6
    Ext User anbutu's Avatar
    Join Date
    Sep 2007
    Posts
    7
    Vote Rating
    0
    anbutu is on a distinguished road

      0  

    Default


    great

  7. #7
    Ext User
    Join Date
    Nov 2007
    Posts
    17
    Vote Rating
    0
    banesto is on a distinguished road

      0  

    Question no response from proxy

    no response from proxy


    Hi! in your comments it is said, that using HttpProxy you can see response in firebug NET view. Well your example works, but i can't seem to understand, why does my php file doesn't even appear on Net list? Any thoughts?

  8. #8
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default try the XHR filter

    try the XHR filter


    Quote Originally Posted by banesto View Post
    Hi! in your comments it is said, that using HttpProxy you can see response in firebug NET view. Well your example works, but i can't seem to understand, why does my php file doesn't even appear on Net list? Any thoughts?
    Just above where it says "NET", there is another set of buttons you can select from that essentially act as a filter (see attached firebug image). Check which one you have selected. If you just select XHR it will only show the XHR (XMLHttpRequest).

    I found looking at all of the other buttons and "NET" in general interesting because it shows links in red that were invalid, so this pointed me towards other things that might be wrong (like missing images to render the css, etc.).
    Attached Images

  9. #9
    Ext User
    Join Date
    Nov 2007
    Posts
    17
    Vote Rating
    0
    banesto is on a distinguished road

      0  
    Last edited by banesto; 17 Nov 2007 at 3:50 PM. Reason: misuse

  10. #10
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default


    I think you're hijacking my thread!? It's fine for you to inquire here, but you should probably just post your question in it's own thread and ask people monitoring this thread to go to your thread?

    My intent for this thread was to show a working example (I should probably not have posted this in the 'help' section) and get critiques, even supporting people having questions with the files provided.

    The above aside, if your html page doesn't get a response (which is I think what you're saying...that you have no response)....then the grid certainly won't display the data. You might try simplifying what you're doing. Have your php file just send back {success: true}. Then have your js display a message box in your success: block.

    If I change my php to have the last (or only) line as

    PHP Code:
    echo "{success: true}"
    I'll get a blank grid as well. But my php file still shows up on the Console Tab and I can see the Response. Double check you have a file called "data.php" that is in the SAME directory as your js file. Also, check the CONSOLE tab, if I intentionally relocate file or rename it, the console tab still shows the request looking for that file, but it shows up in red because it can't find it (see my earlier post about this being a nice check to see your page is getting all the content you expected). [Edit:...and by the way, with the wrong filename the file shows up in red on the Console tab and not at all on the Net tab.]

    Your js file is quite different from the example I have provided here. So I don't know what else you have that is different.

Thread Participants: 109

  1. jay@moduscreate.com (2 Posts)
  2. LorenzoW (2 Posts)
  3. mystix (3 Posts)
  4. rsuplido (1 Post)
  5. LiXin (1 Post)
  6. gwyn (1 Post)
  7. crafter (1 Post)
  8. Phunky (1 Post)
  9. ddanatzko (1 Post)
  10. lychorojostone (1 Post)
  11. lkasdorf (2 Posts)
  12. modelracer (1 Post)
  13. hendricd (1 Post)
  14. vibez (4 Posts)
  15. Iveco (1 Post)
  16. .andy (1 Post)
  17. anbutu (1 Post)
  18. murrah (1 Post)
  19. Pytte (1 Post)
  20. battisti (1 Post)
  21. dqzonline (1 Post)
  22. fwabbly (3 Posts)
  23. david555 (1 Post)
  24. shalewagner (1 Post)
  25. WoLpH (1 Post)
  26. mbravo (2 Posts)
  27. banesto (3 Posts)
  28. flipthefrog (4 Posts)
  29. mjcon (2 Posts)
  30. gend (1 Post)
  31. kasas (1 Post)
  32. ash (1 Post)
  33. Ephicient (1 Post)
  34. mzagzoog (3 Posts)
  35. benjam72 (2 Posts)
  36. hurrican (2 Posts)
  37. verbi (1 Post)
  38. mbenothmane (1 Post)
  39. smagen (1 Post)
  40. cuchoes (1 Post)
  41. allampraveen (1 Post)
  42. Starfall (3 Posts)
  43. quocanh83 (1 Post)
  44. ClausThaler (4 Posts)
  45. jcastaneda (3 Posts)
  46. killerangel (5 Posts)
  47. Richie1985 (4 Posts)
  48. cobrob (2 Posts)
  49. tonig84 (1 Post)
  50. SevenCube (1 Post)
  51. tannax (1 Post)
  52. nickweavers (1 Post)
  53. nienow (2 Posts)
  54. jignesh (1 Post)
  55. vagabond-fr (1 Post)
  56. TheTinkeringToad (9 Posts)
  57. spectrus (1 Post)
  58. abnfire (2 Posts)
  59. vwongkm (4 Posts)
  60. buntyindia (1 Post)
  61. shahulhameed (1 Post)
  62. Jacsoft (1 Post)
  63. angeldimitrov (1 Post)
  64. ahchuan (1 Post)
  65. technicaltitch (3 Posts)
  66. man_hn_2003 (2 Posts)
  67. t2t2 (2 Posts)
  68. Samp (2 Posts)
  69. jeremy.hennegrave (1 Post)
  70. suwater (3 Posts)
  71. Judy (2 Posts)
  72. STUDIOETC (2 Posts)
  73. chandraextjs (2 Posts)
  74. rams128kb (1 Post)
  75. vladok (3 Posts)
  76. tfee (1 Post)
  77. rajakrishnamca (1 Post)
  78. wizgabriel18 (1 Post)
  79. kristalgic (2 Posts)
  80. savant (2 Posts)
  81. la_ka (1 Post)
  82. henryadam (1 Post)
  83. Pachat (1 Post)
  84. alejandrayepez (3 Posts)
  85. lhmwzy (1 Post)
  86. martinsky (1 Post)
  87. pimo (1 Post)
  88. bjsmith3 (2 Posts)
  89. fredfredland (1 Post)
  90. dreicon (1 Post)
  91. pierretim (1 Post)
  92. cychan (1 Post)
  93. enjoyfrancis (1 Post)
  94. fruitwerks (4 Posts)
  95. Dustin Graham (1 Post)
  96. calrek (1 Post)
  97. untiptun (3 Posts)
  98. separatis (1 Post)
  99. undgerman (1 Post)
  100. oshacorgi (1 Post)
  101. aaqee (1 Post)
  102. meristatha (1 Post)
  103. mischmi (1 Post)
  104. Laahari (1 Post)
  105. scottmartin (1 Post)
  106. phenomfx (1 Post)
  107. stevwinata (1 Post)
  108. keenie (1 Post)
  109. flowertown (2 Posts)

film izle

hd film izle

film sitesi

takipci kazanma sitesi

takipci kazanma sitesi

güzel olan herşey

takipci alma sitesi

komik eğlenceli videolar