2012-08-13 33 views
1

我正在嘗試編寫一個拉力賽應用程序,它將顯示選定用戶素材的前級/後級層級。爲了說明,用戶將從Chooser UI元素中選擇一個用戶故事。然後,將生成一個三列Cardboard UI元素 - 最左邊的列將包含所有選定的用戶故事的預處理器(以卡片形式),中間列將包含選定的用戶故事的卡片,最右邊的列將包含所有所選用戶故事的後繼者(以卡片形式)。從那裏,前輩和後繼卡可以被移除(表示他們不會是所選用戶故事的先行者或後繼者),並且可以添加新的先行者/後繼者卡(表示他們將成爲所選的新前輩/後繼者用戶故事)。使用拉力賽紙板UI顯示前級/後續層級

但是,我的問題是這樣的:Cardboard UI被設計爲顯示一組特定屬性的不同值,但是「Predecessor」和「Successor」不屬於這個類別。是否有可能讓我展示用戶故事,然後獲取其前身和後繼者,並填充董事會的其餘部分?我意識到它將會對原版電路板進行大量修改。

回答

1

我發現了一種方法來破解它,以便您可以進行顯示。不知道它是否值得,以及您想要添加/刪除的操作,但這可能會幫助您設置正確的路徑。

總之,問題在於紙板/色譜柱類被設計爲使用單個值字段,每個創建的列都根據色譜柱配置對Rally進行單獨查詢。你需要重寫rallycardboard和rallycolumn。我將給出完整的html,你可以在下面粘貼,但是我們一次只能打一個。

如果沒有別的,這可能是一個很好的例子,如何採取集會類的源代碼,並做出重寫它們的東西。

數據:

現有紙板被賦予一個記錄類型,字段和逃跑步驟中對字段中的每個有效的值創建一列。它通過向Rally查詢故事和屬性定義來獲取這些信息。但我們希望以稍微不同的方式使用我們的數據,因此我們必須創建一個不同的數據存儲並將其提供。因此,我們希望使用wsapidatastore繼續並獲取我們要求的記錄(在此示例中,我有一個叫做US37的故事,有前輩和後繼者)。在某種程度上,這就像在Excel中做一個交叉表。我們希望創建一個包含所有故事的數據集,並在一個新字段中定義它們的關係,我稱其爲「_column」,而不是有一條記錄(37)。就像這樣:

Ext.create('Rally.data.WsapiDataStore', { 
      model: "hierarchicalrequirement", 
      autoLoad: true, 
      fetch: ['Name','Predecessors','Successors','FormattedID','ObjectID','_ref'], 
      filters: [ { 
       property: 'FormattedID', operator: 'contains', value: '37' 
      } ] /* get the record US37 */, 
      listeners: { 
       load: function(store,data,success) { 
        if (data.length === 1) { 
         var base_story = data[0].data; 
         var modified_records = []; 

         base_story._column = "base"; 
         modified_records.push(base_story); 

         Ext.Array.each(base_story.Predecessors, function(story) { 
          story._column = "predecessor"; 
          modified_records.push(story); 
         }); 

         Ext.Array.each(base_story.Successors, function(story) { 
          story._column = "successor"; 
          modified_records.push(story); 
         }); 

我們推到數據對象的數組,每個都具有一個新的領域來定義它應該在哪一列但這還遠遠不夠,因爲我們需要把數據放到。一家商店。商店需要一個模型 - 我們必須以梳理者知道如何訪問數據的方式定義字段。似乎並沒有簡單的方法來將一個字段定義添加到現有的拉力賽模型中,所以這應該做到這一點(拉力賽模型有獨特的字段信息和一個名爲getField()的方法,所以我們必須添加:現在

     Ext.define('CardModel', { 
          extend: 'Ext.data.Model', 
          fields: [ 
           { name: '_ref', type: 'string' }, 
           { name: 'ObjectID', type: 'number'}, 
           { name: 'Name', type: 'string', attributeDefinition: { AttributeType: 'STRING'} }, 
           { name: 'FormattedID', type: 'string'}, 
           { name: '_column', type: 'string' }, 
           { name: 'ScheduleState', type: 'string' } ] , 
          getField: function(name) { 
           if (this.data[name]) { 
            var return_field = null; 
            Ext.Array.each(this.store.model.getFields(), function(field) { 
             if (field.name === name) { 
              return_field = field; 
             } 
            }); 

            return return_field; 
           } else { 
            return null; 
           } 
          } 
         }); 

         var cardStore = Ext.create('Ext.data.Store',{ 
          model: 'CardModel', 
          data: modified_records 
         }); 

,我們將創建一個硬紙板,但不是反彈紙板,我們會讓一個從我們將會在下面進行定義(「DependencyCardboard」)的一類。此外,我們將傳遞我們將在下面定義的列的新定義('dependencycolumn')。

     var cardboard = Ext.create('DependencyCardboard', { 
          attribute: '_column', 
          store: cardStore, /* special to our new cardboard type */ 
          height: 500, 
          columns: [{ 
           xtype: 'dependencycolumn', 
           displayValue: 'predecessor', 
           value: 'predecessor', 
           store: cardStore 
          }, 
          { 
           xtype: 'dependencycolumn', 
           displayValue: 'base', 
           value: 'base', 
           store: cardStore 
          }, 
          { 
           xtype: 'dependencycolumn', 
           displayValue: 'successor', 
           value: 'successor', 
           store: cardStore 
          }] 
         }); 

紙板:

大多數情況下,現有的拉力紙板可以處理我們的需求,因爲所有的查詢在列本身做下來。但是我們仍然必須重寫它,因爲有一個函數會導致我們遇到問題:_retrieveModels。該功能通常採用記錄類型(例如,用戶故事),並基於該記錄創建基於拉力定義的數據模型。但是,我們並未直接使用UserStory記錄;我們必須定義我們自己的模型,所以我們可以添加「_columns」字段。所以,我們做了一個新的定義(我們在上面的創建語句中使用「DependencyCardboard」)。

(請記住,我們就可以通過點擊標題查看源代碼,所有的拉力賽API中的對象,所以我們可以在下面的方法比作一個基類。)

我們可以保留所有的東西,拉力紙板確實,只有通過這樣重寫一個方法:

Ext.define('DependencyCardboard', { 
    extend: 'Rally.ui.cardboard.CardBoard', 
    alias: 'widget.dependencycardboard', 
    constructor: function(config) { 
     this.mergeConfig(config); 
     this.callParent([this.config]); 
    }, 
    initComponent: function() { 
     this.callParent(arguments); 
    }, 
    _retrieveModels: function(success) { 
     if (this.store) { 
      this.models = [ this.store.getProxy().getModel() ]; 
      success.apply(this, arguments); 
     } 
    } 

}); 

柱:

每列正常熄滅反彈,並說「給我所有的sto有一個領域等於列名的領域「。但是我們將商店傳遞給紙板,所以我們需要重寫_queryForData。另外,當我們這樣做時(我不知道爲什麼),有一些關於定義列高度的事情,所以我不得不在getColumnHeightFromCards()方法中添加一點點catch。

_queryForData: function() { 
     var allRecords = []; 

     var records = this.store.queryBy(function(record) { 
      if (record.data._column === this.getValue()) { allRecords.push(record); } 
     }, this); 

     this.createAndAddCards(allRecords); 
    }, 
    getColumnHeightFromCards: function() { 
     var contentMinHeight = 500, 
      bottomPadding = 30, 
      cards = this.query(this.cardConfig.xtype), 
      height = bottomPadding; 

     for(var i = 0, l = cards.length; i < l; ++i) { 
      if (cards[i].el) { 
       height += cards[i].getHeight(); 
      } else { 
       height += 100; 
      } 

     } 

     height = Math.max(height, contentMinHeight); 
     height += this.down('#columnHeader').getHeight(); 

     return height; 
    } 

完成

所以,如果你添加所有這些拼在一起,你會得到,我們可以推到一個面板(並且你可以繼續工作,以找出如何一個大的HTML文件重寫拖動結果併爲第一個項目添加選擇器面板(並且可以更好地抽象爲它自己的類))。

全部東西:

<!DOCTYPE html> 
<html> 
<head> 
    <title>cardboard</title> 

    <script type="text/javascript" src="/apps/2.0p3/sdk.js"></script> 

    <script type="text/javascript"> 
     Rally.onReady(function() { 
      /*global console, Ext */ 

      Ext.define('DependencyColumn', { 
       extend: 'Rally.ui.cardboard.Column', 
       alias: 'widget.dependencycolumn', 
       constructor: function(config) { 
        this.mergeConfig(config); 
        this.callParent([this.config]); 
       }, 
       initComponent: function() { 
        this.callParent(arguments); 
       }, 
       _queryForData: function() { 
        var allRecords = []; 

        var records = this.store.queryBy(function(record) { 
         if (record.data._column === this.getValue()) { allRecords.push(record); } 
        }, this); 

        this.createAndAddCards(allRecords); 
       }, 
       getColumnHeightFromCards: function() { 
        var contentMinHeight = 500, 
         bottomPadding = 30, 
         cards = this.query(this.cardConfig.xtype), 
         height = bottomPadding; 

        for(var i = 0, l = cards.length; i < l; ++i) { 
         if (cards[i].el) { 
          height += cards[i].getHeight(); 
         } else { 
          height += 100; 
         } 

        } 

        height = Math.max(height, contentMinHeight); 
        height += this.down('#columnHeader').getHeight(); 

        return height; 
       } 

      }); 
      /*global console, Ext */ 

      Ext.define('DependencyCardboard', { 
       extend: 'Rally.ui.cardboard.CardBoard', 
       alias: 'widget.dependencycardboard', 
       constructor: function(config) { 
        this.mergeConfig(config); 
        this.callParent([this.config]); 
       }, 
       initComponent: function() { 
        this.callParent(arguments); 
       }, 
       _retrieveModels: function(success) { 
        if (this.store) { 
         this.models = [ this.store.getProxy().getModel() ]; 
         success.apply(this, arguments); 
        } 
       } 

      }); 
      /*global console, Ext */ 
      Ext.define('CustomApp', { 
       extend: 'Rally.app.App', 
       componentCls: 'app', 
       items: [ { xtype: 'container', itemId: 'outer_box' }], 
       launch: function() { 
        Ext.create('Rally.data.WsapiDataStore', { 
         model: "hierarchicalrequirement", 
         autoLoad: true, 
         fetch: ['Name','Predecessors','Successors','FormattedID','ObjectID','_ref'], 
         filters: [ { 
          property: 'FormattedID', operator: 'contains', value: '37' 
         } ], 
         listeners: { 
          load: function(store,data,success) { 
           if (data.length === 1) { 
            var base_story = data[0].data; 
            var modified_records = []; 

            base_story._column = "base"; 
            modified_records.push(base_story); 

            Ext.Array.each(base_story.Predecessors, function(story) { 
             story._column = "predecessor"; 
             modified_records.push(story); 
            }); 

            Ext.Array.each(base_story.Successors, function(story) { 
             story._column = "successor"; 
             modified_records.push(story); 
            }); 

            Ext.define('CardModel', { 
             extend: 'Ext.data.Model', 
             fields: [ 
              { name: '_ref', type: 'string' }, 
              { name: 'ObjectID', type: 'number'}, 
              { name: 'Name', type: 'string', attributeDefinition: { AttributeType: 'STRING'} }, 
              { name: 'FormattedID', type: 'string'}, 
              { name: '_column', type: 'string' }, 
              { name: 'ScheduleState', type: 'string' } ] , 
             getField: function(name) { 
              if (this.data[name]) { 
               var return_field = null; 
               Ext.Array.each(this.store.model.getFields(), function(field) { 
                if (field.name === name) { 
                 return_field = field; 
                } 
               }); 

               return return_field; 
              } else { 
               return null; 
              } 
             } 
            }); 

            var cardStore = Ext.create('Ext.data.Store',{ 
             model: 'CardModel', 
             data: modified_records 
            }); 

            var cardboard = Ext.create('DependencyCardboard', { 
             attribute: '_column', 
             store: cardStore, 
             height: 500, 
             columns: [{ 
              xtype: 'dependencycolumn', 
              displayValue: 'predecessor', 
              value: 'predecessor', 
              store: cardStore 
             }, 
             { 
              xtype: 'dependencycolumn', 
              displayValue: 'base', 
              value: 'base', 
              store: cardStore 
             }, 
             { 
              xtype: 'dependencycolumn', 
              displayValue: 'successor', 
              value: 'successor', 
              store: cardStore 
             }] 
            }); 

            this.down('#outer_box').add(cardboard); 
           } 
          }, 
          scope: this 
         } 
        }); 
       } 
      }); 

      Rally.launchApp('CustomApp', { 
       name: 'cardboard' 
      }); 
     }); 
    </script> 

    <style type="text/css"> 
     .app { 
      /* Add app styles here */ 
     } 
    </style> 
</head> 
<body></body> 
</html> 
+0

太謝謝你了! – 2012-08-20 15:36:21