Skip to content

Commit

Permalink
Merge remote-tracking branch 'scho/0-8' into 0-8
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Gorin committed Sep 6, 2012
2 parents de18f45 + fd37443 commit 644631f
Show file tree
Hide file tree
Showing 20 changed files with 853 additions and 6 deletions.
212 changes: 212 additions & 0 deletions lib/netzke/communitypack/tree_panel.rb
@@ -0,0 +1,212 @@
# Ext.tree.TreePanel-based component
#
# TODO: Add documentation for usage
class Netzke::Communitypack::TreePanel < Netzke::Base


# Include data accessor module
include ::Netzke::Basepack::DataAccessor
# Include columns module
include ::Netzke::Basepack::GridPanel::Columns

extend ActiveSupport::Memoizable

self.default_instance_config = {
:indicate_leafs => true,
:auto_scroll => false,
:root_visible => false,
:load_inline_data => true,
:enable_pagination => true,
:rows_per_page => 30,
:treecolumn => 'tree' # The default name of the column, that will be the treecolumn
}

js_configure do |c|
c.extend = "Ext.tree.TreePanel"
c.mixin :tree_panel
c.include :paging_tree_store
end

# Configure dynamic JS properties for instantiation
def js_config
super.tap do |c|
# Hand over inline data to the js config hash
c[:inline_data] = get_data if config[:load_inline_data]
end
end

def configure(c) #:nodoc:
super
c.title = c.title || self.class.js_config.properties[:title] || data_class.name.pluralize
c.columns = final_columns(with_meta: true)
# Set it to the primary key if not given and camelize it
# Setting it to anything else than the primary key is especially useful when instances of different class are shown in one tree
# because the primary key MUST be unique!
c.pri = (c.pri || data_class.primary_key).to_s.camelize(:lower)
# Add extra fields for a tree: A method ':name(r)' is called for every record to retrieve the value
c.extra_fields ||= []
c.extra_fields << {:name => 'leaf', :type => 'boolean'} # This will call leaf?(r) for every record
c.extra_fields << {:name => 'expanded', :type => 'boolean'} # This will call expanded?(r) for every record
# only if the node id property is different from the data class' primary key, we need to add and extra field
c.extra_fields << {:name => c.pri.to_s.camelize(:lower), :type => 'string'} if c.pri != data_class.primary_key
end

# Sets the xtype to 'treecolumn' for the column with name equal to the :treecolumn value of the config
def set_default_xtype(c)
if c[:name] == config[:treecolumn].to_s
c[:xtype] = 'treecolumn'
else
super
end
end

# Set data_index
# The name of the field configuration of the Ext JS model will be set to this value
# This is neccessary since the data is serialized as a hash (with camelized keys)
# so the data_index must also be camelized
def set_default_data_index(c)
c[:data_index] = c[:name].camelize(:lower)
end

# Call super and then set the data_index
def augment_column_config(c)
super
set_default_data_index(c)
end

# @!method get_data_endpoint
#
# Returns something like:
# [
# { 'id'=> 1, 'text'=> 'A folder Node', 'leaf'=> false },
# { 'id'=> 2, 'text'=> 'A leaf Node', 'leaf'=> true }
# ]
#
# @param [Hash] params
endpoint :get_data do |params, this|
this.merge! get_data(params)
end

# Method that is called by the get_data endpoint
# Calls the get_children method and returns the serialized records
#
# @param [] *args takes any arguments
# @return [Hash] all the serialized data
def get_data(*args)
params = args.first || {} # params are optional!
if !config[:prohibit_read]
{}.tap do |res|
# set children to an instance variable in order to access them later
@records = get_children(params)

# Serialize children
res[:data] = serialize_data(@records)
res[:total] = count_records(params) if config[:enable_pagination] && (params[:id].nil? || params[:id] == 'root')
end
else
flash :error => "You don't have permissions to read data"
{ :netzke_feedback => @flash }
end
end

# Serializes an array of objects
#
# @param [Array] records
# @return [Array] the serialized data
def serialize_data(records)
records.map { |r|
r.netzke_hash(final_columns(:with_meta => true)).tap { |h|

config[:extra_fields].each do |f|
name = f[:name].underscore.to_sym
h[name] = send("#{name}#{f[:type] == 'boolean' ? '?' : ''}", r)
end

inline_children = get_inline_children(r)
h[:data] = serialize_data(inline_children) unless inline_children.nil?
h
}
}
end

# Retrieves all children for a node
# Note: It's recommended to override this method
#
# @param [Hash] params
# @return [Array] array of records
def get_children(params)
scope_data_class(params) do
params[:limit] = config[:rows_per_page] if config[:enable_pagination] && (params[:id].nil? || params[:id] == 'root')
params[:scope] = config[:scope]
data_adapter.get_records(params, final_columns)
end
end

# Scopes the data class depending on the config of the parent_key and the node
#
# @param [Hash] params
def scope_data_class(params, &block)
if config[:parent_key]
# The value of the pri property of the expanded node is passed as params[:id] ('root' for the root collection)
if params[:id].nil? || params[:id] == 'root'
data_class.where(config[:parent_key] => nil).scoping do
yield
end
else
data_class.where(config[:parent_key] => params[:id]).scoping do
yield
end
end
else
yield
end
end

# Counts the total records
#
# @param [Hash] params
# @return [Fixnum] The number of records
def count_records(params)
scope_data_class(params) do
params[:scope] = config[:scope]
data_adapter.count_records(params, final_columns)
end
end

# Should return all children of the record that should also be serialized in the current request
# Note: It's recommended to override this method
#
# @param [Object] r The record for which the inline children should be loaded
# @return [NilClass, Array] If nil is returned, the tree doesn't know anything about any children, so opening the node will cause another request.
# If an empty array is returned, the tree assumes that there are no children available for this node (and thus you can't open it!)
def get_inline_children(r)
nil
end

# Is the record a leaf or not?
# Note: It's recommended to override this method
#
# @param [Object] r
# @return [Boolean] Whether the node is a leaf or not
def leaf?(r)
r.children.empty?
end

# Is the record a expanded or not?
# Note: It's recommended to override this method
#
# @param [Object] r
# @return [Boolean] Whether the node is expanded or not
def expanded?(r)
false
end

# Is the record a leaf or not?
# Note: It's recommended to override this method
#
# @param [Object] r
# @return [Boolean] Whether the node is a leaf or not
def node_id(r)
r.send(data_class.primary_key)
end
end
@@ -0,0 +1,67 @@
// Extends Ext.data.TreeStore and adds paging to it
Ext.define('Ext.netzke.PagingTreeStore', {
extend: 'Ext.data.TreeStore',
alias: 'pagingtreestore',
currentPage: 1,
config:{
totalCount: null,
pageSize: null
},
// Load a specific Page
loadPage: function(page){
var me = this;
me.currentPage = page;
me.read({
page: page,
start: (page - 1) * me.pageSize,
limit: me.pageSize
});
},
// Load next Page
nextPage: function(){
this.loadPage(this.currentPage + 1);
},
// Load previous Page
previousPage: function(){
this.loadPage(this.currentPage - 1);
},
// Overwrite function in order to set totalCount
onProxyLoad: function(operation) {
// This method must be overwritten in order to set totalCount
var me = this,
resultSet = operation.getResultSet(),
node = operation.node;
// If the node doesn't have a parent node, set totalCount
if (resultSet && node.parentNode == null) {
me.setTotalCount(resultSet.total);
}
// We're done here, call parent
this.callParent(arguments);
},
getCount : function(){
return this.getRootNode().childNodes.length;
},
getRange : function(start, end){
var me = this,
items = this.getRootNode().childNodes,
range = [],
i;
if (items.length < 1) {
return range;
}
start = start || 0;
end = Math.min(typeof end == 'undefined' ? items.length - 1 : end, items.length - 1);
if (start <= end) {
for (i = start; i <= end; i++) {
range[range.length] = items[i];
}
} else {
for (i = start; i >= end; i--) {
range[range.length] = items[i];
}
}
return range;
}


});

0 comments on commit 644631f

Please sign in to comment.