require 'ransack' require 'widget_list/version' require 'widget_list/hash' require 'widget_list/string' require 'widget_list/utils' require 'widget_list/tpl' require 'widget_list/widgets' require 'widget_list/railtie' require 'csv' require 'json' require 'uri' require 'extensions/action_controller_base' module WidgetList # # WidgetList Administration/Setup # def self.go!() if $_REQUEST.key?('iframe') eval(WidgetList::Administration.new.translate_config_to_code()) return @output else list = WidgetList::List.new() return list.render() end end class Administration def show_interface() config_file = Rails.root.join("config", "widget-list-administration.json") config_file_all = Rails.root.join("config", "widget-list-administration-all.json") if config_file.file? && !$_REQUEST.key?('ajax') && !$_REQUEST.key?('name') File.delete(Rails.root.join("config", "widget-list-administration.json")) end ac = ActionController::Base.new() default_config = WidgetList::List::get_defaults() config_id, page_config = get_configuration() page_json = JSON.parse(ajax_get_field_json(page_config['view'])) #Loop models models = Dir[ Rails.root.join("app", "models").to_s + '**/*'].reject {|fn| File.directory?(fn) } if !models.empty? model_options = '' + models.collect { |model| model_name = model.split('/').last.to_s.camelize.gsub(/.rb/,'') "" }.sort.uniq.join('') else model_options = '' end #Groupings #default_grouping : editing_grouping @fill = {} # # Writing most of this interface while drunk trancing/coding out on ah.fm. # This administration form should help people new to widget_list to easily stub out new implementations # # # INIT PROMPT # if config_file_all.file? && !$_REQUEST.key?('restore') @fill[''] = 'style="display:none"' @fill[''] = 'style="display:none"' options = '' json = JSON.parse(File.new(Rails.root.join("config", "widget-list-administration-all.json")).read) json.keys.each { |val| void, controller_action = val.split('|') controller, action = controller_action.split('-') options += '' } @fill[''] = WidgetList::Utils::fill({ '' => WidgetList::Widgets::widget_button('New', { 'onclick' => "ClickTab('.start','ShowStart',true);jQuery('#sections').fadeIn('slow');" , 'innerClass' => "primary" } ), '' => WidgetList::Widgets::widget_button('Edit', { 'onclick' => "isSubmitting = true; document.location = document.location + '?restore=' + escape(jQuery('#edit_widget_list').val());" , 'innerClass' => "primary" } ), '' => '', } ,'

Start a New Widget List

Edit Existing:

  ') else @fill[''] = '' @fill[''] = '' end # # BASE # @fill[''] = $_SERVER['PATH_INFO'] @fill[''] = WidgetList::Widgets::widget_button('Step One - Start ->', {'id' => 'start' , 'onclick' => "ShowStart();" , 'innerClass' => "primary" } ) + WidgetList::Widgets::widget_button('Step Two - Fields ->', {'id' => 'fields' , 'onclick' => "ShowFields();" , 'innerClass' => "primary disabled" } ) + WidgetList::Widgets::widget_button('Step Three - Rows ->', {'id' => 'rows' , 'onclick' => "ShowRows();" , 'innerClass' => "primary disabled" } ) + WidgetList::Widgets::widget_button('Step Four - Search ->', {'id' => 'search' , 'onclick' => "ShowSearch();" , 'innerClass' => "primary disabled" } ) + WidgetList::Widgets::widget_button('Step Four - Footer Actions ->', {'id' => 'footer' , 'onclick' => "ShowFooter();" , 'innerClass' => "primary disabled" } ) + WidgetList::Widgets::widget_button('Step Five - Misc & Submit ->', {'id' => 'misc_submit', 'onclick' => "ShowSubmit();" , 'innerClass' => "success disabled" } ) # # START # @fill[''] = 'Stub Out A New WidgetList Implementation' @fill[''] = (!@isEditing) ? $_REQUEST['controller'] : page_config['desiredController'] @fill[''] = (!@isEditing) ? $_REQUEST['action'] : page_config['desiredAction'] @fill[''] = (!@isEditing) ? config_id : page_config['name'] @fill[''] = model_options @fill[''] = (!@isEditing) ? '' : page_config['title'] @fill[''] = (!@isEditing) ? '' : page_config['listDescription'] @fill[''] = (!@isEditing) ? 'checked' : (page_config['primaryDatabase'] == "1") ? 'checked' : '' # # FIELD LEVEL # @fill[''] = (!@isEditing) ? '' : page_config['noDataMessage'] @fill[''] = (!@isEditing) ? 'checked' : (page_config['useSort'] == "1") ? 'checked' : '' @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = '' @fieldFill[''] = '' @fieldFill[''] = 'fields' @fieldFill[''] = 'Field' @fieldFill[''] = 'Desc' @fieldFill[''] = '' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add Field', {'onclick' => "AddField();", 'innerClass' => "success" } ) @fill[''] = (!@isEditing) ? '' : page_json['fields'] @fill[''] = (!@isEditing) ? '' : (page_config['showHidden'] == "1") ? 'checked' : '' @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = '' @fieldFill[''] = '' @fieldFill[''] = 'fields_hidden' @fieldFill[''] = 'Field' @fieldFill[''] = 'Desc' @fieldFill[''] = 'disabled' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add Hidden Field', {'onclick' => "AddHiddenField();", 'innerClass' => "success" } ) @fill[''] = (!@isEditing) ? '' : page_json['fields_hidden'] @fill[''] = (!@isEditing) ? '' : (page_config['fieldFunctionOn'] == "1") ? 'checked' : '' @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = '' @fieldFill[''] = '' @fieldFill[''] = 'fields_function' @fieldFill[''] = 'Field' @fieldFill[''] = 'Database Function' @fieldFill[''] = '' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add Function', {'onclick' => "AddFieldFunction();", 'innerClass' => "success" } ) @fill[''] = (!@isEditing) ? '' : page_json['fields_function'] # # ROW LEVEL # @fill[''] = (!@isEditing) ? default_config['rowLimit'] : page_config['rowLimit'] @fill[''] = (!@isEditing) ? 'Actions' : page_config['rowButtonsName'] @fill[''] = (!@isEditing) ? '' : (page_config['rowButtonsOn'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? '' : (page_config['drillDownsOn'] == "1") ? 'checked' : '' @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = 'Button Text' @fieldFill[''] = (!@isEditing) ? '/' : '/' + page_config['desiredController'] + '/' @fieldFill[''] = 'info' @fieldFill[''] = 'GoodClass(this)' @fieldFill[''] = 'Text' @fieldFill[''] = 'text' @fieldFill[''] = 'The Button Text' @fieldFill[''] = 'URL' @fieldFill[''] = 'url' @fieldFill[''] = 'Color' @fieldFill[''] = 'class' @fieldFill[''] = 'primary=(blue) info=(light-blue) success=(green) danger=(red) disabled=(light grey) default=(grey)' @fieldFill[''] = 'buttons' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add Button To Each Row', {'onclick' => "AddButton();", 'innerClass' => "info" } ) @fill[''] = page_json['buttons'] @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = 'filter_col_name' @fieldFill[''] = 'col_name' @fieldFill[''] = 'col_name' @fieldFill[''] = 'ReplaceColumnsToLinked(this)' @fieldFill[''] = 'ReplaceColumnsToLinked(this)' @fieldFill[''] = 'Internal Filter Name (:drill_down_name)
' @fieldFill[''] = 'drill_down_name' @fieldFill[''] = ':drill_down_name is a parameter of build_drill_down that is what is passed and returned from get_filter_and_drilldown when you handle the request after clicked' @fieldFill[''] = 'Data To Pass From View (:data_to_pass_from_view)
' @fieldFill[''] = 'data_to_pass_from_view' @fieldFill[''] = 'Column to Show (:column_to_show)
' @fieldFill[''] = 'column_to_show' @fieldFill[''] = ':column_to_show should either be the column or possibly a formatted column like CONCAT or COUNT' @fieldFill[''] = 'drill_downs' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add New Drill Down', {'onclick' => "AddDrillDown();", 'innerClass' => "success" } ) @fill[''] = page_json['drill_downs'] # # SEARCH # @fill[''] = (!@isEditing) ? 'checked' : (page_config['showSearch'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? 'checked' : (page_config['showExport'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? default_config['exportButtonTitle'] : page_config['exportButtonTitle'] @fill[''] = (!@isEditing) ? 'checked' : (page_config['useRansack'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? '' : (page_config['ransackAdvancedForm'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? '' : (page_config['useGrouping'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? default_config['searchTitle'] : page_config['searchTitle'] @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = 'column_name' @fieldFill[''] = 'User Desc' @fieldFill[''] = 'group_by' @fieldFill[''] = 'Field' @fieldFill[''] = 'Desc' @fieldFill[''] = '' @fieldFill[''] = 'InvalidField(this)' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add New Group By', {'onclick' => "AddGroupBy();", 'innerClass' => "success" } ) @fill[''] = (!@isEditing) ? '' : page_json['group_by'] # # FOOTER # @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = 'Button Text' @fieldFill[''] = (!@isEditing) ? '/' : '/' + page_config['desiredController'] + '/your_action' @fieldFill[''] = 'info' @fieldFill[''] = 'Text' @fieldFill[''] = 'text' @fieldFill[''] = 'The Button Text' @fieldFill[''] = 'URL' @fieldFill[''] = 'url' @fieldFill[''] = 'Color' @fieldFill[''] = 'class' @fieldFill[''] = 'primary=(blue) info=(light-blue) success=(green) danger=(red) disabled=(light grey) default=(grey)' @fieldFill[''] = 'footer_buttons' @fieldFill[''] = 'GoodClass(this)' @fill[''] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) @fill[''] = WidgetList::Widgets::widget_button('Add Footer Button', {'onclick' => "AddFooterButton();", 'innerClass' => "success" } ) @fill[''] = page_json['footer_buttons'] @fill[''] = (!@isEditing) ? '' : (page_config['footerOn'] == "1") ? 'checked' : '' # # MISC & SUBMIT # @fill[''] = (!@isEditing) ? '' : (page_config['checkboxEnabled'] == "1") ? 'checked' : '' @fill[''] = (!@isEditing) ? '' : build_field_options(page_json['all_fields'], page_config['checkboxField']) @fill[''] = WidgetList::Widgets::widget_button('Submit', {'onclick' => "Submit();" , 'innerClass' => "success" } ) # # HELP BUTTONS # @help = {} @help[''] = "The title list_params will show above the list similar to the title of this page to stub out an implementation of the list." @help[''] = "Ransack gem will provide multiple column filtering abilities in the advanced drop down arrow form" @help[''] = "This is the grey description of the wild card search" @help[''] = "Hidden fields are not shown, but you can use the record values inside of important tags passed from buttons and drill downs" @help[''] = "This value is supposed to be the primary key to identify the row" @help[''] = "Internal use only reserved for future use. Not really important as of yet" @help[''] = "The name of the controller drives most session level storage and javascript pointers and IDs of a list" @help[''] = "10,20,50,100,500,1000 are supported" @help[''] = "Controller is used to generate button URLs internally in this utility and as a way to restore configurations for future editing and code re-generation" @help[''] = "Link drill downs allow you to build a link around a field value, in which allows you to select which column value to pass to a drill down. It allows you to CONCAT or run a query for the display of the column and it then handles the filtering of the data" @help[''] = "A fieldFunction is a wrapper to call functions around columns that exist or possibly adding new fields that dont exist. It is good for formatting data after the where clause." @help[''] = "Enter a field name to group by and a description to show to the user. If you leave the field name blank it will NOT group by the field, but will show all records" @help[''] = "For each record. Add several buttons which will pass tags which are the record values to another page or javascript function" @help[''] = "By default, widget_list will build the advanced form for you when this option is unchecked. By checking, the code builder will place the advanced form inside your controller so you can add additional filtering options you will have to handle on your own" @help.each { |k,v| @fill[k] = WidgetList::Widgets::widget_button('?', {'onclick' => "alert('" + v + "')", 'innerClass' => "default" }, true ) } return WidgetList::Utils::fill(@fill , ac.render_to_string(:partial => 'widget_list/administration/output') ) end def add_pointer(key,subtract=0) whitespace = 31 - subtract "['#{key}'] " + "".ljust(whitespace - key.length) + " = " end def add_conditional(key,conditional) whitespace = 19 "'#{escape_code key}' " + "".ljust(whitespace - key.length) + " #{conditional}" end def escape_code(code) if $_REQUEST.key?('iframe') #It is so weird, during output return, you need an extra slash to populate the code properly, but during rendering this is needed code.gsub(/'/,"\\\\'") else code.gsub(/'/,"\\\\\\\\'") end end def translate_config_to_code() config_id, page_config = get_configuration() fields,fields_hidden,fields_function,buttons,footer_buttons,group_by,drill_downs = normalize_configs(page_config) drill_down_code = '' case_statements = '' case_statements2 = '' view_code = '' export_code = '' visible_field_code = '' hidden_field_code = '' variable_code = '' checkbox_code = '' button_code = '' grouping_code = '' grouping_code2 = '' search_out = '' field_function_code = '' database_type = WidgetList::List.get_db_type(page_config['primaryDatabase'] == '1' ? true : false) using_grouping = (page_config['useGrouping'] == '1' && page_config['showSearch'] == '1' && !group_by.empty?) #------------ DRILL DOWNS ------------ if page_config['drillDownsOn'] == "1" && !drill_downs.empty? search_out += " list_parms['searchFieldsOut'] = {}" drill_downs.each { |field| search_out += " list_parms['searchFieldsOut']#{add_pointer(field[1]['column_to_show'],9)} true" column_to_show = "'#{field[1]['column_to_show'].gsub(/_linked/,'')}'" if using_grouping if database_type == 'oracle' column_to_show = "groupByFilter == 'none' ? '#{escape_code field[1]['column_to_show'].gsub(/_linked/,'')}' : 'MAX(#{escape_code field[1]['column_to_show'].gsub(/_linked/,'')})'" end end field_function_code += " list_parms['fieldFunction']#{add_pointer(field[1]['column_to_show'],7)} WidgetList::List::build_drill_down( :list_id => list_parms['name'], :drill_down_name => '#{escape_code field[0]}', :data_to_pass_from_view => #{column_to_show}, :column_to_show => #{column_to_show}, :column_alias => '#{escape_code field[1]['column_to_show']}', :primary_database => #{page_config['primaryDatabase'] == '1' ? 'true' : 'false'} )" case_statements += <<-EOD when '#{field[0]}' list_parms['filter'] << " #{field[1]['column_to_show'].gsub(/_linked/,'')} = ? " list_parms['bindVars'] << #{page_config['view']}.sanitize(filterValue) list_parms['listDescription'] = drillDownBackLink + ' Filtered by #{escape_code field[1]['column_to_show'].gsub(/_linked/,'').camelize} (' + filterValue + ')' EOD } drill_down_code = <<-EOD # # Handle Dynamic Filters # drillDown, filterValue = WidgetList::List::get_filter_and_drilldown(list_parms['name']) drillDownBackLink = WidgetList::List::drill_down_back(list_parms['name']) case drillDown#{case_statements} else list_parms['listDescription'] = '#{escape_code page_config['listDescription']}' end EOD else drill_down_code = " list_parms['listDescription'] = '#{escape_code page_config['listDescription']}' " end if page_config['rowButtonsOn'] == '1' variable_code += " button_column_name = '#{escape_code page_config['rowButtonsName']}'" end #------------ VIEW ------------ if page_config['useRansack'] == '1' && page_config['showSearch'] == '1' view_code = " list_parms#{add_pointer('ransackSearch',-10)} #{page_config['view']}.search(#{($_REQUEST.key?('iframe')) ? '$_REQUEST' : 'params'}[:q]) list_parms#{add_pointer('view',-10)} list_parms['ransackSearch'].result " if page_config['ransackAdvancedForm'] == '1' view_code += " list_parms['listSearchForm'] = WidgetList::Utils::fill( { '' => WidgetList::Widgets::widget_button('Search', WidgetList::List::build_search_button_click(list_parms)), '' => \"HideAdvancedSearch(this)\" } , '
\">X

' " end else view_code = " list_parms#{add_pointer('view',-10)} #{page_config['view']} " end #------------ EXPORT ------------ if page_config['showExport'] == '1' && page_config['showSearch'] == '1' export_code += "list_parms['showExport'] = #{page_config['showExport'] == '1' ? 'true' : 'false'} list_parms['exportButtonTitle'] = '#{escape_code page_config['exportButtonTitle']}'" end if page_config['showSearch'] == '1' export_code += " list_parms['searchTitle'] = '#{escape_code page_config['searchTitle']}'" end #------------ VISIBLE FIELDS ------------ if page_config['checkboxEnabled'] == '1' checkbox_code += " list_parms = WidgetList::List.checkbox_helper(list_parms,'#{page_config['checkboxField']}') " if using_grouping visible_field_code += " list_parms['fields']#{add_pointer('checkbox')} #{add_conditional('checkbox_header',"if groupByFilter == 'none'")}" else visible_field_code += " list_parms['fields']#{add_pointer('checkbox')} 'checkbox_header'" end end fields.each { |field,description| conditional = '' if using_grouping conditional = ' if groupByFilter == \'none\'' if group_by.key?(field) || group_by.key?(field.gsub(/_linked/,'')) conditional = " if groupByFilter == 'none' || groupByFilter == 'group_#{escape_code group_by[field.gsub(/_linked/,'')].gsub(/ /,'_').downcase}'" end end visible_field_code += " list_parms['fields']#{add_pointer(field)} #{add_conditional(description,conditional)}" } #------------ GROUPING ------------ if using_grouping variable_code += " groupByDesc = '' # Initialize a variable you can use in listDescription to show what the current grouping selection is groupByFilter = 'none' # This variable should be used to control business logic based on the grouping and is a short hand key rather than using what is returned from get_group_by_selection " visible_field_code += " list_parms['fields']#{add_pointer('cnt')} #{add_conditional('Count'," if groupByFilter != 'none'")} " if database_type == 'oracle' count = 'TO_CHAR(COUNT(1))' else count = 'COUNT(1)' end field_function_code += " list_parms['fieldFunction']#{add_pointer('cnt',7)} #{add_conditional(count," if groupByFilter != 'none'")}" descriptions = [] group_by.each { |field,description| descriptions << "'" + escape_code(description) + "'" desc = '' filter = '' unless field.empty? desc = " (Grouped By #{escape_code field.camelize})" filter = "group_#{description.gsub(/ /,'_').downcase}" else filter = 'none' end case_statements2 += <<-EOD when '#{escape_code description}' list_parms['groupBy'] = '#{escape_code field}' groupByFilter = '#{escape_code filter}' groupByDesc = '#{escape_code desc}' EOD } grouping_code = <<-EOD # # Group By # groupBy = WidgetList::List::get_group_by_selection(list_parms) case groupBy#{case_statements2} else list_parms['groupBy'] = '' end EOD grouping_code += " list_parms['groupByItems'] = " + '[' + descriptions.join(', ') + ']' grouping_code2 = " # # Prevent Oracle grouping errors # list_parms = WidgetList::List.group_by_max_each_field(list_parms,groupByFilter) " if database_type == 'oracle' end #------------ BUTTONS ------------ if page_config['rowButtonsOn'] == '1' visible_field_code += " list_parms['fields'][button_column_name.downcase] = button_column_name.capitalize" visible_field_code += " if groupByFilter == 'none'" if using_grouping button_code += " # # Buttons # mini_buttons = {} " buttons.each { |field| button_code += " mini_buttons['button_#{escape_code field[0].downcase}'] = {'page' => '#{escape_code field[1]['url']}', 'text' => '#{escape_code field[0]}', 'function' => 'Redirect', 'innerClass' => '#{escape_code field[1]['class']}', 'tags' => {'all'=>'all'} } " } button_code += " list_parms['buttons'] = {button_column_name.downcase => mini_buttons} " end #------------ FOOTER ------------ if page_config['footerOn'] == '1' && !footer_buttons.empty? btns = [] footer_buttons.each {|field| btns << " WidgetList::Widgets::widget_button('#{escape_code field[0]}', {'page' => '#{escape_code field[1]['url']}','innerClass' => '#{escape_code field[1]['class']}'})" } button_code += " list_parms['customFooter'] = " + btns.join(' + ') end #------------ FIELD FUNCTIONS ------------ if page_config['fieldFunctionOn'] == '1' && !fields_function.empty? fields_function.each { |field,command| field_function_code += " list_parms['fieldFunction']#{add_pointer(field,7)} '#{escape_code command}'" } end if page_config['showHidden'] == '1' fields_hidden.each { |field| hidden_field_code += " list_parms['fieldsHidden'] << '#{escape_code field[1]}'" } end if page_config['rowButtonsOn'] == '1' field_function_code += " list_parms['fieldFunction'][button_column_name.downcase] = \"''\"" end if page_config['checkboxEnabled'] == '1' field_function_code += " list_parms['fieldFunction']#{add_pointer('checkbox',7)} \"''\"" end <<-EOD begin #{variable_code} list_parms = WidgetList::List::init_config() list_parms['name'] = '#{escape_code page_config['name']}' list_parms['noDataMessage'] = '#{escape_code page_config['noDataMessage']}' list_parms['rowLimit'] = #{page_config['rowLimit']} list_parms['title'] = '#{escape_code page_config['title']}' list_parms['useSort'] = #{page_config['useSort'] == '1' ? 'true' : 'false'} list_parms['database'] = '#{page_config['primaryDatabase'] == '1' ? 'primary' : 'secondary'}' #{export_code} #{drill_down_code} #{grouping_code} # # Fields # #{visible_field_code} #{hidden_field_code} #{field_function_code} #{search_out} #{grouping_code2} # # Model # #{view_code} #{checkbox_code} #{button_code} # # Render List # output_type, output = WidgetList::List.build_list(list_parms) case output_type when 'html' @output = output when 'json' return render :inline => output when 'export' send_data(output, :filename => list_parms['name'] + '.csv') return end rescue Exception => e # # Rescue Errors # Rails.logger.info e.to_s + "\\n\\n" + $!.backtrace.join("\\n\\n") if Rails.env == 'development' list_parms['errors'] << '

(Ruby Exception - Still attempted to render list with given config ' + list_parms.inspect + ') Exception ==> ' + e.to_s + "

Backtrace:

" + $!.backtrace.join("

") + "
" end output_type, output = WidgetList::List.build_list(list_parms) case output_type when 'html' @output = output when 'json' return render :inline => output when 'export' send_data(output, :filename => list_parms['name'] + '.csv') return end end EOD end def get_configuration() config_id = config_id() config_file = Rails.root.join("config", "widget-list-administration.json") if config_file.file? && ($_REQUEST.key?('iframe') || $_REQUEST.key?('name')) configuration = JSON.parse(File.new(Rails.root.join("config", "widget-list-administration.json")).read) elsif $_REQUEST.key?('restore') configuration = JSON.parse(File.new(Rails.root.join("config", "widget-list-administration-all.json")).read) else configuration = {} end if configuration.key?(config_id) @isEditing = true page_config = configuration[config_id] ['useSort','showHidden','fieldFunctionOn','rowButtonsOn','drillDownsOn','showSearch','showExport','useRansack','ransackAdvancedForm','useGrouping','footerOn','checkboxEnabled'].each { |item| unless page_config.key?(item) page_config[item] = "0" end } else @isEditing = false page_config = {} end return [config_id,page_config] end def build_field_options(fields,selected='') options = '' fields.each { |field,description| options += "" } return options end def normalize_configs(page_config) fields = {} fields_hidden = {} fields_function = {} buttons = {} footer_buttons = {} group_by = {} drill_downs = {} if page_config.key?('fields') page_config['fields']['key'].each_with_index { |v,k| fields[v] = page_config['fields']['description'][k.to_i] } end if page_config.key?('fields_hidden') page_config['fields_hidden']['key'].each { |v| fields_hidden[v] = v } end if page_config.key?('fields_function') page_config['fields_function']['key'].each_with_index { |v,k| fields_function[v] = page_config['fields_function']['description'][k.to_i] } end if page_config.key?('group_by') page_config['group_by']['key'].each_with_index { |v,k| group_by[v] = page_config['group_by']['description'][k.to_i] } end if page_config.key?('buttons') page_config['buttons']['text'].each_with_index { |v,k| buttons[v] = {} buttons[v]['url'] = page_config['buttons']['url'][k.to_i] buttons[v]['class'] = page_config['buttons']['class'][k.to_i] } end if page_config.key?('footer_buttons') page_config['footer_buttons']['text'].each_with_index { |v,k| footer_buttons[v] = {} footer_buttons[v]['url'] = page_config['footer_buttons']['url'][k.to_i] footer_buttons[v]['class'] = page_config['footer_buttons']['class'][k.to_i] } end if page_config.key?('drill_downs') page_config['drill_downs']['drill_down_name'].each_with_index { |v,k| drill_downs[v] = {} drill_downs[v]['data_to_pass_from_view'] = page_config['drill_downs']['data_to_pass_from_view'][k.to_i] drill_downs[v]['column_to_show'] = page_config['drill_downs']['column_to_show'][k.to_i] } end return [fields,fields_hidden,fields_function,buttons,footer_buttons,group_by,drill_downs] end def ajax_get_field_json(model_name) config_id, page_config = get_configuration() ac = ActionController::Base.new() @response = {} fields = {} fields_hidden = {} all_fields = {} fields_function = {} buttons = {} footer_buttons = {} group_by = {} drill_downs = {} if @isEditing model = page_config['view'].constantize.new model.attributes.keys.each { |field| all_fields[field] = field.gsub(/_/,' _').camelize } fields,fields_hidden,fields_function,buttons,footer_buttons,group_by,drill_downs = normalize_configs(page_config) else controller = ($_REQUEST.key?('desiredController') ? $_REQUEST['desiredController'] : $_REQUEST['controller'] ) if $_REQUEST.key?('ajax') model = model_name.constantize.new model.attributes.keys.each { |field| fields[field] = field.gsub(/_/,' _').camelize all_fields[field] = field.gsub(/_/,' _').camelize fields_function[field] = 'CNT(' + field + ') or NVL(' + field + ') or TO_DATE(' + field + ') etc...' } footer_buttons['Add New ' + model_name] = {} footer_buttons['Add New ' + model_name]['url'] = '/' + controller + '/add/' footer_buttons['Add New ' + model_name]['class'] = 'info' end buttons['Edit'] = {} buttons['Delete'] = {} buttons['Delete']['class'] = 'danger' buttons['Delete']['url'] = '/' + controller + '/delete/id/' buttons['Edit']['url'] = '/' + controller + '/edit/id/' buttons['Edit']['class'] = 'info' if $_REQUEST.key?('ajax') group_by[''] = 'All ' + model_name + 's' group_by['field_name'] = 'This will group by field_name and show Count' buttons['Delete']['url'] = '/' + controller + '/delete/' + fields.keys.first + '/' buttons['Edit']['url'] = '/' + controller + '/edit/' + fields.keys.first + '/' end end @response['fields'] = '' @response['fields_hidden'] = '' @response['fields_function'] = '' @response['buttons'] = '' @response['group_by'] = '' @response['footer_buttons'] = '' @response['drill_downs'] = '' fields.each { |field,description| @fieldFill = {} @fieldFill[''] = 'fields' @fieldFill[''] = field @fieldFill[''] = description @fieldFill[''] = remove_field_button() @fieldFill[''] = 'Field' @fieldFill[''] = 'Desc' @fieldFill[''] = '' @response['fields'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) } fields_hidden.each { |field| @fieldFill = {} @fieldFill[''] = 'fields_hidden' @fieldFill[''] = field[1] @fieldFill[''] = '' @fieldFill[''] = remove_field_button() @fieldFill[''] = 'Desc' @fieldFill[''] = 'Field' @fieldFill[''] = 'disabled' @response['fields_hidden'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) } group_by.each { |field,description| @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = field @fieldFill[''] = description @fieldFill[''] = 'group_by' @fieldFill[''] = 'Field' @fieldFill[''] = 'Desc' @fieldFill[''] = '' @fieldFill[''] = 'InvalidField(this)' @response['group_by'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) } fields_function.each { |field,description| @fieldFill = {} @fieldFill[''] = 'fields_function' @fieldFill[''] = field @fieldFill[''] = description @fieldFill[''] = remove_field_button() @fieldFill[''] = 'Database Function' @fieldFill[''] = 'Field' @fieldFill[''] = '' @response['fields_function'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') ) } buttons.each { |field| @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = field[0] @fieldFill[''] = field[1]['url'] @fieldFill[''] = field[1]['class'] @fieldFill[''] = 'GoodClass(this)' @fieldFill[''] = 'Text' @fieldFill[''] = 'text' @fieldFill[''] = 'The Button Text' @fieldFill[''] = 'URL' @fieldFill[''] = 'url' @fieldFill[''] = 'Color' @fieldFill[''] = 'class' @fieldFill[''] = 'primary=(blue) info=(light-blue) success=(green) danger=(red) disabled=(light grey) default=(grey)' @fieldFill[''] = 'buttons' @response['buttons'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) } drill_downs.each { |field| @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = field[0] @fieldFill[''] = field[1]['data_to_pass_from_view'] @fieldFill[''] = field[1]['column_to_show'] @fieldFill[''] = 'ReplaceColumnsToLinked(this)' @fieldFill[''] = 'ReplaceColumnsToLinked(this)' @fieldFill[''] = 'Internal Filter Name (:drill_down_name)
' @fieldFill[''] = 'drill_down_name' @fieldFill[''] = ':drill_down_name is a parameter of build_drill_down that is what is passed and returned from get_filter_and_drilldown when you handle the request after clicked' @fieldFill[''] = 'Data To Pass From View (:data_to_pass_from_view)
' @fieldFill[''] = 'data_to_pass_from_view' @fieldFill[''] = 'Column to Show (:column_to_show)
' @fieldFill[''] = 'column_to_show' @fieldFill[''] = ':column_to_show should either be the column or possibly a formatted column like CONCAT or COUNT' @fieldFill[''] = 'drill_downs' @response['drill_downs'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) } footer_buttons.each { |field| @fieldFill = {} @fieldFill[''] = remove_field_button() @fieldFill[''] = field[0] @fieldFill[''] = field[1]['url'] @fieldFill[''] = field[1]['class'] @fieldFill[''] = 'GoodClass(this)' @fieldFill[''] = 'Text' @fieldFill[''] = 'text' @fieldFill[''] = 'The Button Text' @fieldFill[''] = 'URL' @fieldFill[''] = 'url' @fieldFill[''] = 'Color' @fieldFill[''] = 'class' @fieldFill[''] = 'primary=(blue) info=(light-blue) success=(green) danger=(red) disabled=(light grey) default=(grey)' @fieldFill[''] = 'footer_buttons' @response['footer_buttons'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') ) } if $_REQUEST.key?('ajax') || @isEditing @response['all_fields'] = all_fields @response['checked_fields'] = build_field_options(all_fields, page_config.key?('checkboxField') ? page_config['checkboxField'] : '') end return @response.to_json end def remove_field_button() WidgetList::Widgets::widget_button('Remove', {'onclick' => "RemoveField(this)", 'innerClass' => "danger" }, true ) end def config_id() config_id = '' if $_REQUEST.key?('restore') config_id = $_REQUEST['restore'] else config_id += $_REQUEST['controller'] if $_REQUEST.key?('controller') config_id += $_REQUEST['action'] if $_REQUEST.key?('action') config_id += '|' + $_REQUEST['desiredController'] if $_REQUEST.key?('desiredController') config_id += '-' + $_REQUEST['desiredAction'] if $_REQUEST.key?('desiredAction') end return config_id end def save_and_show_code() ac = ActionController::Base.new() config_id = config_id() config_file = Rails.root.join("config", "widget-list-administration.json") if config_file.file? configuration = JSON.parse(File.new(Rails.root.join("config", "widget-list-administration.json")).read) else configuration = {} end configuration[config_id] = $_REQUEST time = Time.new configuration[config_id]['savedOn'] = time.year.to_s + '-' + time.month.to_s.rjust(2, "0") + '-' + time.day.to_s.rjust(2, "0") config_file_all = Rails.root.join("config", "widget-list-administration-all.json") if config_file_all.file? configuration_all = JSON.parse(File.new(Rails.root.join("config", "widget-list-administration-all.json")).read) else configuration_all = {} end configuration_all[config_id] = $_REQUEST File.open(Rails.root.join("config", "widget-list-administration.json"), "w") do |file| file.puts configuration.to_json end File.open(Rails.root.join("config", "widget-list-administration-all.json"), "w") do |file| file.puts configuration_all.to_json end @fill = {} unless $_REQUEST.key?('ajax') @fill[''] = translate_config_to_code() end return WidgetList::Utils::fill(@fill ,ac.render_to_string(:partial => 'widget_list/administration/output_save') ) unless $_REQUEST.key?('ajax') return @fill.to_json end end # # WidgetList Core Logic # if defined?(Rails) && defined?(Rails::Engine) class Engine < ::Rails::Engine require 'widget_list/engine' end end class List @debug = true attr_accessor :isAdministrating include ActionView::Helpers::SanitizeHelper # @param [Hash] list def initialize(list={}) # Defaults for all configs # See https://github.com/davidrenne/widget_list/blob/master/README.md#feature-configurations @items = WidgetList::List::get_defaults() if list.empty? || list == @items @isAdministrating = true return else @isAdministrating = false end @csv = [] @csv << [] @totalRowCount= 0 @totalPages = 0 @fixHtmlLinksReplace = {} @sequence = 1 @totalRows = 0 @totalPage = 0 @listSortNext = 'ASC' @filter = '' @listFilter = '' @fieldList = [] @templateFill = {} @results = {} @headerPieces = {} ac = ActionController::Base.new() #the main template and outer shell @items.deep_merge!({ 'template' => ac.render_to_string(:partial => 'widget_list/list_partials/outer_shell') }) @items.deep_merge!({ 'row' => ac.render_to_string(:partial => 'widget_list/list_partials/row') }) @items.deep_merge!({ 'list_description' => ac.render_to_string(:partial => 'widget_list/list_partials/list_description') }) @items.deep_merge!({ 'col' => ac.render_to_string(:partial => 'widget_list/list_partials/col') }) @items.deep_merge!({ 'templateSequence' => ac.render_to_string(:partial => 'widget_list/list_partials/sequence') }) #Sorting # @items.deep_merge!({ 'templateSortColumn' => ac.render_to_string(:partial => 'widget_list/list_partials/sort_column') }) @items.deep_merge!({ 'templateNoSortColumn' => ac.render_to_string(:partial => 'widget_list/list_partials/no_sort_column') }) #Pagintion # @items.deep_merge!({ 'template_pagination_wrapper' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_wrapper') }) @items.deep_merge!({ 'template_pagination_next_active' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_next_active') }) @items.deep_merge!({ 'template_pagination_next_disabled' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_next_disabled') }) @items.deep_merge!({ 'template_pagination_previous_active' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_previous_active') }) @items.deep_merge!({ 'template_pagination_previous_disabled' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_previous_disabled') }) @items.deep_merge!({ 'template_pagination_jump_active' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_jump_active') }) @items.deep_merge!({ 'template_pagination_jump_unactive' => ac.render_to_string(:partial => 'widget_list/list_partials/pagination_jump_unactive') }) @items.deep_merge!({ 'statement' => {'select'=> {'view' => ' SELECT FROM ' } } }) @items.deep_merge!({ 'statement' => {'count'=> {'view' => ' SELECT count(1) total FROM ' } } }) #inject site wide configs before list specific configs if a helper exists if defined?(WidgetListHelper) == 'constant' && WidgetListHelper::SiteDefaults.class == Class && WidgetListHelper::SiteDefaults.respond_to?('get_site_widget_list_defaults') @items = WidgetList::Widgets::populate_items(WidgetListHelper::SiteDefaults::get_site_widget_list_defaults() ,@items) end if defined?(WidgetListThemeHelper) == 'constant' && WidgetListThemeHelper::ThemeDefaults.class == Class && WidgetListThemeHelper::ThemeDefaults.respond_to?('get_theme_widget_list_defaults') @items = WidgetList::Widgets::populate_items(WidgetListThemeHelper::ThemeDefaults::get_theme_widget_list_defaults() ,@items) end @items = WidgetList::Widgets::populate_items(list,@items) # If ransack is used if @items['view'].class.name == 'ActiveRecord::Relation' && @items['ransackSearch'].class.name == 'Ransack::Search' @items['ransackSearch'].build_condition if @items['ransackSearch'].conditions.empty? if @items['listSearchForm'].empty? # # if no one passed a listSearchForm inject a default one to show the ransack form # fill = { '' => WidgetList::Widgets::widget_button('Search', {'onclick' => WidgetList::List::build_search_button_click(@items), 'innerClass' => @items['defaultButtonClass'] }), '' => "HideAdvancedSearch(this)" } @items['listSearchForm'] = WidgetList::Utils::fill( fill , ac.render_to_string(:partial => 'widget_list/ransack_widget_list_advanced_search') ) end end # I have several different styles for borders, but using borders Everywhere will setup everything with one call if @items['bordersEverywhere?'] @items['borderedColumns'] = @items['borderHeadFoot'] = @items['borderedRows'] = true @items['borderColumnStyle'] = @items['borderRowStyle'] = @items['headFootBorderStyle'] = @items['tableBorder'] = @items['borderEverywhere'] end # current_db is a flag of the last known primary or secondary YML used or defaulted when running a list @current_db_selection = @items['database'] if get_database.db_type == 'oracle' @items.deep_merge!({'statement' => {'count'=> {'view' => ' SELECT count(1) total FROM ' + ((@items['groupBy'].empty? && !@active_record_model) ? ' ' : '' ) } } }) @items.deep_merge!({'statement' => {'select'=> {'view' => 'SELECT FROM ( SELECT a.*, DENSE_RANK() over () rn FROM ( SELECT ' + ( (!get_view().include?('(')) ? '' : get_view().strip.split(" ").last ) + '.* FROM ) a ' + ((@items['groupBy'].empty?) ? '' : '') + ' ) ' + ((!@active_record_model) ? '' : '') } } }) end if $_REQUEST.key?('searchClear') clear_search_session() end begin @isJumpingList = false #Ajax ListJump if ! $_REQUEST.empty? if $_REQUEST.key?('LIST_FILTER_ALL') && !$_REQUEST['LIST_FILTER_ALL'].empty? @items['LIST_FILTER_ALL'] = $_REQUEST['LIST_FILTER_ALL'] @isJumpingList = true end if $_REQUEST.key?('LIST_COL_SORT') && !$_REQUEST['LIST_COL_SORT'].empty? @items['LIST_COL_SORT'] = $_REQUEST['LIST_COL_SORT'] @isJumpingList = true end if $_REQUEST.key?('LIST_COL_SORT_ORDER') && !$_REQUEST['LIST_COL_SORT_ORDER'].empty? @items['LIST_COL_SORT_ORDER'] = $_REQUEST['LIST_COL_SORT_ORDER'] @isJumpingList = true end if $_REQUEST.key?('LIST_SEQUENCE') && !$_REQUEST['LIST_SEQUENCE'].empty? @items['LIST_SEQUENCE'] = $_REQUEST['LIST_SEQUENCE'].to_i @isJumpingList = true end if $_REQUEST.key?('ROW_LIMIT') && !$_REQUEST['ROW_LIMIT'].empty? @items['ROW_LIMIT'] = $_REQUEST['ROW_LIMIT'] @isJumpingList = true if @items['showPagination'] $_SESSION['pageDisplayLimit'] = $_REQUEST['ROW_LIMIT'] $_SESSION.deep_merge!({'ROW_LIMIT' => { @items['name'] => $_REQUEST['ROW_LIMIT']} }) end end clear_sort_get_vars() if $_REQUEST.key?('list_action') && $_REQUEST['list_action'] == 'ajax_widgetlist_checks' && @items['storeSessionChecks'] ajax_maintain_checks() end end @items['groupByClick'] = WidgetList::Utils::fill({'' => @items['name']}, @items['groupByClickDefault'] + @items['groupByClick']) if @items['searchClear'] || @items['searchClearAll'] clear_search_session(@items.key?('searchClearAll')) end matchesCurrentList = $_REQUEST.key?('BUTTON_VALUE') && $_REQUEST['BUTTON_VALUE'] == @items['buttonVal'] isSearchRequest = $_REQUEST.key?('search_filter') && $_REQUEST['search_filter'] != 'undefined' templateCustomSearch = !@items['templateFilter'].empty? # if you define templateFilter WidgetList will not attempt to build a where clause with search # # Search restore # if !isSearchRequest && $_SESSION.class.name == 'Hash' && !$_SESSION.empty? && $_SESSION.key?('SEARCH_FILTER') && $_SESSION['SEARCH_FILTER'].key?(@items['name']) && @items['searchSession'] isSearchRestore = true end if (isSearchRequest && matchesCurrentList && !templateCustomSearch && @items['showSearch']) || isSearchRestore if !isSearchRestore $_SESSION.deep_merge!({'SEARCH_FILTER' => { @items['name'] => $_REQUEST['search_filter']} }) searchFilter = $_REQUEST['search_filter'].strip_or_self() else searchFilter = $_SESSION['SEARCH_FILTER'][@items['name']] end if ! searchFilter.empty? if ! @items['filter'].empty? && @items['filter'].class.name != 'Array' # convert string to array filter filterString = @items['filter'] @items['filter'] = [] @items['filter'] << filterString end fieldsToSearch = @items['fields'].dup if @items['fieldsHidden'].class.name == 'Array' @items['fieldsHidden'].each { |columnPivot| fieldsToSearch[columnPivot] = strip_aliases(columnPivot) } elsif @items['fieldsHidden'].class.name == 'Hash' @items['fieldsHidden'].each { |columnPivot| fieldsToSearch[columnPivot[0]] = strip_aliases(columnPivot[0]) } end fieldsToSearch.delete('cnt') if fieldsToSearch.key?('cnt') searchCriteria = searchFilter.strip_or_self() searchSQL = [] numericSearch = false # # Comma delimited search # if searchFilter.include?(',') #It is either a CSV or a comma inside the search string # criteriaTmp = searchFilter.split_it(',') #Assumed a CSV of numeric ids # isNumeric = true criteriaTmp.each_with_index { |value, key| if !value.empty? criteriaTmp[key] = value.strip_or_self() if !criteriaTmp[key].nil? && ! criteriaTmp[key].empty? if ! WidgetList::Utils::numeric?(criteriaTmp[key]) isNumeric = false end else criteriaTmp.delete(key) end end } if isNumeric numericSearch = true if @items['searchIdCol'].class.name == 'Array' @items['searchIdCol'].each { |searchIdCol| if(fieldsToSearch.key?(searchIdCol)) searchSQL << tick_field() + searchIdCol + tick_field() + " IN(" + searchFilter + ")" end } if !searchSQL.empty? # # Assemble Numeric Filter # @items['filter'] << "(" + searchSQL.join(' OR ') + ")" end elsif @items['fields'].key?(@items['searchIdCol']) numericSearch = true @items['filter'] << tick_field() + "#{@items['searchIdCol']}" + tick_field() + " IN(" + criteriaTmp.join(',') + ")" end end elsif @items['searchIdCol'].class.name == 'Array' if WidgetList::Utils::numeric?(searchFilter) && ! searchFilter.include?('.') numericSearch = true @items['searchIdCol'].each { |searchIdCol| if fieldsToSearch.key?(searchIdCol) searchSQL << tick_field() + "#{searchIdCol}" + tick_field() + " IN(#{searchFilter})" end } if !searchSQL.empty? # # Assemble Numeric Filter # @items['filter'] << "(" + searchSQL.join(' OR ') + ")" end end elsif WidgetList::Utils::numeric?(searchFilter) && ! searchFilter.include?('.') && @items['fields'].key?(@items['searchIdCol']) numericSearch = true @items['filter'] << tick_field() + "#{@items['searchIdCol']}" + tick_field() + " IN(" + searchFilter + ")" end # If it is not an id or a list of ids then it is assumed a string search if !numericSearch fieldsToSearch.each { |fieldName,fieldTitle| fieldName = strip_aliases(fieldName) # new lodgette. if fieldFunction exists, find all matches and skip them if @items['fieldFunction'].key?(fieldName) if get_database.db_type == 'oracle' theField = fieldName else theField = @items['fieldFunction'][fieldName] + cast_col() end else theField = tick_field() + "#{fieldName}" + cast_col() + tick_field() end skip = false skip = skip_column(fieldName) #buttons must ALWAYS BE ON THE RIGHT SIDE IN ORDER FOR THIS NOT TO SEARCH A NON-EXISTENT COLUMN (used to be hard coded to 'features' as a column to remove) if skip next end #Search only specified fields. This can involve a dynamic field list from an advanced search form # if ! @items['searchFieldsIn'].empty? # # If it exists in either key or value # if ! @items['searchFieldsIn'].key?(fieldName) && ! @items['searchFieldsIn'].include?(fieldName) next end elsif ! @items['searchFieldsOut'].empty? if @items['searchFieldsOut'].key?(fieldName) || @items['searchFieldsOut'].include?(fieldName) next end end #todo - escape bind variables using Sequel searchSQL << theField + " LIKE '%" + searchCriteria + "%'" } # # Assemble String Filter # if(! searchSQL.empty?) @items['filter'] << "(" + searchSQL.join(' OR ') + ")" end end end end if !$_REQUEST.key?('BUTTON_VALUE') #Initialize page load/Session stuff whe list first loads # WidgetList::List::clear_check_box_session(@items['name']) end if ! @items.key?('templateHeader') @items['templateHeader'] = '' end #Set a list title if it exists # if ! $_REQUEST.key?('BUTTON_VALUE') && !@items['title'].empty? @items['templateHeader'] = '

' elsif !$_REQUEST.key?('BUTTON_VALUE') # Only if not in ajax would we want to output the filter header # @items['templateHeader'] = '' end # Build the filter (If any) # # todo - unit test filter if !@items['filter'].empty? && @items['filter'].class.name == 'Array' @filter = @items['filter'].join(' AND ') elsif !@items['filter'].empty? && @items['filter'].class.name == 'String' @filter = @items['filter'] end #Sorting # if !@items['LIST_COL_SORT'].empty? @items['LIST_SEQUENCE'] = 1 end if @items['LIST_SEQUENCE'].class.name == 'Fixnum' && @items['LIST_SEQUENCE'] > 0 @sequence = @items['LIST_SEQUENCE'].to_i end if ! @items['ROW_LIMIT'].empty? @items['rowLimit'] = @items['ROW_LIMIT'].to_i end if $_SESSION.key?('ROW_LIMIT') && !$_SESSION['ROW_LIMIT'].nil? && $_SESSION['ROW_LIMIT'].key?(@items['name']) && !$_SESSION['ROW_LIMIT'][@items['name']].empty? @items['rowLimit'] = $_SESSION['ROW_LIMIT'][@items['name']].to_i end if ! @items['LIST_COL_SORT'].empty? case @items['LIST_COL_SORT_ORDER'] when 'ASC' @listSortNext = 'DESC' else @listSortNext = 'ASC' end end generate_limits() rescue Exception => e @templateFill[''] = '
' + generate_error_output(e) + @items['noDataMessage'] + '
' end end def get_grouping_functions() #http://docs.oracle.com/cd/E11882_01/server.112/e10592/functions003.htm [ 'AVG(', 'COLLECT(', 'CORR(', 'COUNT(', 'COVAR_POP(', 'COVAR_SAMP(', 'CUME_DIST(', 'DENSE_RANK(', 'FIRST(', 'GROUP_ID(', 'GROUPING_ID(', 'LAST(', 'LISTAGG(', 'MAX(', 'MEDIAN(', 'MIN(', 'PERCENT_RANK(', 'PERCENTILE_CONT(', 'PERCENTILE_DISC(', 'RANK(', 'REGR_SLOPE(', 'REGR_INTERCEPT(', 'REGR_COUNT(', 'REGR_R2(', 'REGR_AVGX(', 'REGR_AVGY(', 'REGR_SXX(', 'REGR_SYY(', 'REGR_SXY(', 'STATS_MINOMIAL_TEST(', 'STATS_CROSSTAB(', 'STATS_F_TEST(', 'STATS_KS_TEST(', 'STATS_MODE(', 'STATS_MW_TEST(', 'STDDEV(', 'STDDEV_POP(', 'STDDEV_SAMP(', 'SUM(', 'SYS_XMLAGG(', 'VAR_POP(', 'VAR_SAMP(', 'VARIANCE(', 'XMLAGG(', ] end def self.get_defaults() { 'errors' => [], 'name' => ([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(16).join, 'database' => 'primary', # 'title' => '', 'listDescription' => '', 'pageId' => $_SERVER['PATH_INFO'], 'view' => '', 'data' => {}, 'collClass' => '', 'collAlign' => '', 'fields' => {}, 'fieldsHidden' => [], 'bindVars' => [], 'bindVarsLegacy' => {}, 'links' => {}, 'buttons' => {}, 'inputs' => {}, 'filter' => [], 'groupBy' => '', 'rowStart' => 0, 'rowLimit' => 10, 'orderBy' => '', 'allowHTML' => true, 'searchClear' => false, 'searchClearAll' => false, 'showPagination' => true, 'searchSession' => true, # # carryOverRequests will allow you to post custom things from request to all sort/paging URLS for each ajax # 'carryOverRequsts' => ['switch_grouping','group_row_id','q'], # # Head/Foot # 'customFooter' => '', 'customHeader' => '', # # Ajax # 'ajaxFunctionAll' => '', 'ajaxFunction' => 'ListJumpMin', # # Search # 'showSearch' => true, 'searchOnkeyup' => "SearchWidgetList('', '', this);", 'searchIdCol' => 'id', 'searchTitle' => 'Search by Id or CSV of Ids and more', 'searchFieldsIn' => {}, 'searchFieldsOut' => {'id'=>true}, 'templateFilter' => '', # # Export # 'showExport' => true, 'exportButtonTitle' => 'Export CSV', # # Group By Box # 'groupByItems' => [], 'groupBySelected' => false, 'groupByLabel' => 'Group By', 'groupByClick' => '', 'groupByClickDefault' => "ListChangeGrouping('', this);", # # Advanced searching # 'listSearchForm' => '', 'ransackSearch' => false, # # Column Specific # 'columnStyle' => {}, 'columnClass' => {}, 'columnPopupTitle' => {}, 'columnSort' => {}, 'columnWidth' => {}, 'columnNoSort' => {}, # # Column Border (on right of each column) # 'borderedColumns' => false, 'borderColumnStyle' => '1px solid #CCCCCC', # # Row Border (on top of each row) # 'borderedRows' => true, 'borderRowStyle' => '1px solid #CCCCCC', # # Head/Foot border # 'borderHeadFoot' => false, 'headFootBorderStyle' => '1px solid #CCCCCC', 'bordersEverywhere?' => false, 'borderEverywhere' => '1px solid #CCCCCC', # # Buttons # 'defaultButtonClass' => 'info', # # Font # 'fontFamily' => '"Times New Roman", Times, serif', 'headerFooterFontSize' => '14px', 'dataFontSize' => '14px', 'titleFontSize' => '24px', # # Table Colors # 'footerBGColor' => '#ECECEC', 'headerBGColor' => '#ECECEC', 'footerFontColor' => '#494949', 'headerFontColor' => '#494949', 'tableBorder' => '1', 'cornerRadius' => 15, 'useBoxShadow' => true, 'shadowInset' => 10, 'shadowSpread' => 20, 'shadowColor' => '#888888', # # Row specifics # 'rowClass' => '', 'rowFontColor' => 'black', 'rowColorByStatus' => {}, 'rowStylesByStatus' => {}, 'rowOffsets' => ['#FFFFFF','#FFFFFF'], 'class' => 'listContainerPassive', 'tableclass' => 'tableBlowOutPreventer', 'noDataMessage' => 'Currently no data.', 'useSort' => true, 'headerClass' => {}, 'fieldFunction' => {}, 'buttonVal' => 'templateListJump', 'linkFunction' => 'ButtonLinkPost', 'template' => '', 'LIST_COL_SORT_ORDER' => 'ASC', 'LIST_COL_SORT' => '', 'LIST_FILTER_ALL' => '', 'ROW_LIMIT' => '', 'LIST_SEQUENCE' => 1, 'NEW_SEARCH' => false, # # Checkbox # 'checkedClass' => 'widgetlist-checkbox', 'checkedFlag' => {}, 'storeSessionChecks' => false, # # Hooks # 'columnHooks' => {}, 'rowHooks' => {} } end def self.init_config() list_parms = {} WidgetList::List::get_defaults.each { |k,v| if (v.is_a?(Array) || v.is_a?(Hash)) && v.empty? list_parms[k] = v end } return list_parms end def skip_column(fieldName) skip = false (@items['inputs']||{}).each { |k,v| if fieldName == k skip = true end } if @items['buttons'].key?(fieldName) skip = true end return skip end def tick_field() case get_database.db_type when 'postgres','oracle' '' else '`' end end def cast_col() case get_database.db_type when 'postgres' '::char(1000)' else '' end end def ajax_maintain_checks() if !$_SESSION.key?('list_checks') $_SESSION['list_checks'] = {} end # # A list must be provided # if $_REQUEST.key?('LIST_NAME') listName = $_REQUEST['LIST_NAME'] sqlHash = $_REQUEST['SQL_HASH'] sequence = $_REQUEST['LIST_SEQUENCE'].to_s # # The placeholder is created when the list initially forms. This validates it and makes it so # not just anything can be injected into the session via this method. # # # For each posted check box # $_REQUEST.each { |value, checked| if checked.to_s == '1' # # Set it as checked # $_SESSION.deep_merge!({'list_checks' => { listName + sqlHash + value => true } }) else # # Unset if it exists and is unchecked # if $_SESSION['list_checks'].key?(listName + sqlHash + value) $_SESSION['list_checks'].delete(listName + sqlHash + value) end end } # # Check All # if $_REQUEST.key?('checked_all') && $_REQUEST['checked_all'] == '1' if $_SESSION.key?('list_checks') if $_SESSION['list_checks'].key?('check_all_' + sqlHash + listName + sequence) if $_REQUEST['checked_all'].empty? $_SESSION['list_checks'].delete('check_all_' + sqlHash + listName + sequence) else $_SESSION.deep_merge!({'list_checks' => { 'check_all_' + sqlHash + listName + sequence => true } }) end else if ! $_REQUEST['checked_all'].empty? $_SESSION.deep_merge!({'list_checks' => { 'check_all_' + sqlHash + listName + $_REQUEST['LIST_SEQUENCE'] => true } }) end end end end end end def self.clear_check_box_session(name='') if $_SESSION.key?('DRILL_DOWN_FILTERS') $_SESSION.delete('DRILL_DOWN_FILTERS') end if $_SESSION.key?('DRILL_DOWNS') $_SESSION.delete('DRILL_DOWNS') end $_SESSION['list_checks'].keys.each { |key| if key.include?(name) $_SESSION['list_checks'].delete(key) end } if $_SESSION.key?('list_checks') && !$_SESSION['list_checks'].nil? && !$_SESSION['list_checks'].empty? end def clear_search_session(all=false) if $_SESSION.key?('SEARCH_FILTER') && $_SESSION['SEARCH_FILTER'].key?(@items['name']) $_SESSION['SEARCH_FILTER'].delete(@items['name']) end if $_SESSION.key?('ROW_LIMIT') && $_SESSION['ROW_LIMIT'].key?(@items['name']) $_SESSION['ROW_LIMIT'].delete(@items['name']) end if $_SESSION.key?('DRILL_DOWNS') && $_SESSION['DRILL_DOWNS'].key?(@items['name']) $_SESSION['DRILL_DOWNS'].delete(@items['name']) end if $_SESSION.key?('DRILL_DOWN_FILTERS') && $_SESSION['DRILL_DOWN_FILTERS'].key?(@items['name']) $_SESSION['DRILL_DOWN_FILTERS'].delete(@items['name']) end if all && $_SESSION.key?('SEARCH_FILTER') $_SESSION.delete('SEARCH_FILTER') end if all && $_SESSION.key?('ROW_LIMIT') $_SESSION.delete('ROW_LIMIT') end if $_REQUEST.key?('LIST_FILTER_ALL') $_REQUEST.delete('LIST_FILTER_ALL') end if $_REQUEST.key?('LIST_COL_SORT') $_REQUEST.delete('LIST_COL_SORT') end if $_REQUEST.key?('LIST_COL_SORT_ORDER') $_REQUEST.delete('LIST_COL_SORT_ORDER') end if $_REQUEST.key?('LIST_SEQUENCE') $_REQUEST.delete('LIST_SEQUENCE') end end def clear_sql_session(all=false) if $_SESSION.key?('LIST_SEQUENCE') && $_SESSION['LIST_SEQUENCE'].key?(@sqlHash) $_SESSION['LIST_SEQUENCE'].delete(@sqlHash) end if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) $_SESSION['LIST_COL_SORT'].delete(@sqlHash) end if all && $_SESSION.key?('LIST_COL_SORT') $_SESSION.delete('LIST_COL_SORT') end if all && $_SESSION.key?('LIST_SEQUENCE') $_SESSION.delete('LIST_SEQUENCE') end end def self.get_filter_and_drilldown(listId) filter = '' drillDown = '' if !$_REQUEST.key?('BUTTON_VALUE') # Initialize page load/Session stuff whe list first loads # WidgetList::List::clear_check_box_session(listId) end if $_REQUEST.key?('drill_down') && !$_REQUEST.key?('searchClear') drillDown = $_REQUEST['drill_down'] $_SESSION.deep_merge!({'DRILL_DOWNS' => { listId => drillDown} }) elsif $_SESSION.key?('DRILL_DOWNS') && $_SESSION['DRILL_DOWNS'].key?(listId) && !$_REQUEST.key?('searchClear') drillDown = $_SESSION['DRILL_DOWNS'][listId] else drillDown = 'default' end if $_REQUEST.key?('filter') && !$_REQUEST.key?('searchClear') filter = $_REQUEST['filter'] $_SESSION.deep_merge!({'DRILL_DOWN_FILTERS' => { listId => filter} }) elsif $_SESSION.key?('DRILL_DOWN_FILTERS') && $_SESSION['DRILL_DOWN_FILTERS'].key?(listId) && !$_REQUEST.key?('searchClear') filter = $_SESSION['DRILL_DOWN_FILTERS'][listId] end return drillDown, filter end def self.get_group_by_selection(list_parms) groupBy = '' if $_REQUEST.key?('switch_grouping') groupBy = $_REQUEST['switch_grouping'] $_SESSION.deep_merge!({'CURRENT_GROUPING' => { list_parms['name'] => groupBy} }) elsif $_SESSION.key?('CURRENT_GROUPING') && !$_SESSION['CURRENT_GROUPING'].nil? && $_SESSION['CURRENT_GROUPING'].key?(list_parms['name']) groupBy = $_SESSION['CURRENT_GROUPING'][list_parms['name']] list_parms['groupBySelected'] = groupBy else groupBy = '' end return groupBy end def clear_sort_get_vars() $_REQUEST.delete('LIST_FILTER_ALL') $_REQUEST.delete('ROW_LIMIT') $_REQUEST.delete('LIST_SEQUENCE') $_REQUEST.delete('LIST_COL_SORT_ORDER') $_REQUEST.delete('LIST_COL_SORT') $_REQUEST.delete('LIST_FILTER_ALL') end def generate_limits() #Pagination # @items['bindVarsLegacy']['LOW'] = @items['rowStart'] @items['bindVarsLegacy']['HIGH'] = @items['rowLimit'] if @sequence.to_i > 1 && ! @items['NEW_SEARCH'] subtractLimit = 0 if get_database.db_type != 'oracle' subtractLimit = @items['rowLimit'] end @items['bindVarsLegacy']['LOW'] = (((@sequence * @items['rowLimit']) - subtractLimit)) if get_database.db_type == 'oracle' @items['bindVarsLegacy']['HIGH'] = ((((@sequence + 1) * @items['rowLimit']))) @items['bindVarsLegacy']['LOW'] = @items['bindVarsLegacy']['LOW'] - @items['rowLimit'] @items['bindVarsLegacy']['HIGH'] = @items['bindVarsLegacy']['HIGH'] - @items['rowLimit'] end end end # @param [Hash] results # pass results of $DATABASE.final_results after running a _select query def render(results={}) if @isAdministrating if $_REQUEST.key?('name') return WidgetList::Administration.new.save_and_show_code() elsif $_REQUEST.key?('ajax') && $_REQUEST.key?('model') return WidgetList::Administration.new.ajax_get_field_json($_REQUEST['model']) elsif $_REQUEST.key?('ajax') && $_REQUEST.key?('save') return WidgetList::Administration.new.save_and_show_code() else return WidgetList::Administration.new.show_interface() end end begin if !results.empty? @items['data'] = results end #Get total records for statement validation and pagination # @items['data'].keys.each { |column| @items['fields'][column.downcase] = auto_column_name(column) } if !@items['data'].empty? && @items['fields'].empty? if @items['data'].empty? # Generate count() from database # @totalResultCount = get_total_records() else # Count the items in the passed data # @items['data'].keys.each { |column| @totalResultCount = @items['data'][column].count @totalRowCount = @totalResultCount @totalRows = @totalResultCount break } end build_rows() build_headers() listJumpUrl = {} listJumpUrl['PAGE_ID'] = @items['pageId'] listJumpUrl['ACTION'] = 'AJAX' listJumpUrl['BUTTON_VALUE'] = @items['buttonVal'] listJumpUrl['LIST_COL_SORT'] = @items['LIST_COL_SORT'] listJumpUrl['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER'] listJumpUrl['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL'] listJumpUrl['ROW_LIMIT'] = @items['ROW_LIMIT'] listJumpUrl['LIST_SEQUENCE'] = @sequence listJumpUrl['LIST_NAME'] = @items['name'] listJumpUrl['SQL_HASH'] = @sqlHash if $_REQUEST.key?('switch_grouping') listJumpUrl['switch_grouping'] = $_REQUEST['switch_grouping'] end @templateFill[''] = get_radius_value() @templateFill[''] = @items['useBoxShadow'] ? 'box-shadow: ;' : '' @templateFill[''] = get_shadow_inset_value() @templateFill[''] = get_shadow_spread_value() @templateFill[''] = @items['shadowColor'] @templateFill[''] = @items['borderHeadFoot'] ? 'border-top:' + @items['headFootBorderStyle'] + ';' : '' @templateFill[''] = @items['fontFamily'] @templateFill[''] = @items['headerFooterFontSize'] @templateFill['']= @items['customFooter'] @templateFill[''] = @items['customHeader'] @templateFill[''] = '' @templateFill[''] = '' if !$_REQUEST.key?('BUTTON_VALUE') @templateFill[''] = '
' @templateFill[''] = '
' end @templateFill[''] = @items['templateHeader'] @templateFill[''] = @items['tableBorder'] @templateFill[''] = @items['headerBGColor'] @templateFill[''] = @items['footerBGColor'] @templateFill[''] = @items['headerFontColor'] @templateFill[''] = @items['footerFontColor'] @templateFill[''] = @items['title'] @templateFill[''] = @items['class'] if @totalRowCount > 0 @templateFill[''] = '' @templateFill[''] = @items['tableclass'] else @templateFill[''] = 'table-layout:auto;' end #Filter form # if @items['showSearch'] === true if ! @items['templateFilter'].empty? @templateFill[''] = @items['templateFilter'] else @templateFill[''] = '' if !$_REQUEST.key?('search_filter') && !@isJumpingList #Search page url # searchUrl = '' searchVal = '' if ! @items['buttonVal'].empty? searchVal = @items['buttonVal'] else searchVal = @items['name'] end filterParameters = {} filterParameters['BUTTON_VALUE'] = searchVal filterParameters['PAGE_ID'] = @items['pageId'] filterParameters['LIST_NAME'] = @items['name'] filterParameters['SQL_HASH'] = @sqlHash @items['carryOverRequsts'].each { |value| if $_REQUEST.key?(value) filterParameters[value] = $_REQUEST[value] end } searchUrl = WidgetList::Utils::build_url(@items['pageId'], filterParameters, (!$_REQUEST.key?('BUTTON_VALUE'))) list_search = {} # # Search value # list_search['value'] = '' if @items['searchSession'] if $_SESSION.key?('SEARCH_FILTER') && !$_SESSION['SEARCH_FILTER'].nil? && $_SESSION['SEARCH_FILTER'].key?(@items['name']) list_search['value'] = $_SESSION['SEARCH_FILTER'][@items['name']] end end # # Search Input Field # list_search['list-search'] = true list_search['width'] = '500' list_search['input_class'] = 'info-input' list_search['title'] = @items['searchTitle'] list_search['id'] = 'list_search_id_' + @items['name'] list_search['name'] = 'list_search_name_' + @items['name'] list_search['class'] = 'inputOuter widget-search-outer ' + @items['name'].downcase + '-search' list_search['search_ahead'] = { 'url' => searchUrl, 'skip_queue' => false, 'target' => @items['name'], 'search_form' => @items['listSearchForm'], 'onkeyup' => (! @items['searchOnkeyup'].empty?) ? WidgetList::Utils::fill({''=>searchUrl, '' => @items['name'], '' => @items['ajaxFunctionAll']}, @items['searchOnkeyup'] + '') : '' } fillRansack = {} if @items['ransackSearch'] != false fillRansack[''] = ActionController::Base.new.render_to_string(:partial => 'widget_list/ransack_fields', :locals => { 'search_object' => @items['ransackSearch'], 'url' => '--JUMP_URL--'}) end @headerPieces['searchBar'] = WidgetList::Utils::fill(fillRansack,WidgetList::Widgets::widget_input(list_search)) @templateFill[''] = @headerPieces['searchBar'] end # # Grouping box # if ! @items['groupByItems'].empty? list_group = {} list_group['arrow_action'] = 'var stub;' list_group['readonly'] = true if @items['groupBySelected'] list_group['value'] = @items['groupBySelected'] elsif $_REQUEST.key?('group_row_id') tmp = $_REQUEST['group_row_id'].gsub(@items['name'] + '_row_','') if Float(tmp.to_i) != nil list_group['value'] = @items['groupByItems'][tmp.to_i - 1] end else list_group['value'] = @items['groupByItems'][0] end list_group['style'] = 'cursor:pointer;margin-left:5px;' list_group['input_style'] = 'cursor:pointer;' list_group['outer_onclick'] = 'ToggleAdvancedSearch(this);SelectBoxResetSelectedRow(\'' + @items['name'] + '\');' list_group['list-search'] = false list_group['width'] = '200' #hard code for now. needs to be dynamic based on max str length if this caller is made into a "WidgetFakeSelect" list_group['id'] = 'list_group_id_' + @items['name'] list_group['name'] = 'list_group_name_' + @items['name'] list_group['class'] = 'inputOuter widget-search-outer ' + @items['name'].downcase + '-group' className = '' groupRows = [] if !@items['groupBySelected'] className = 'widget-search-results-row-selected' end num = 1 @items['groupByItems'].each { |grouping| if @items['groupBySelected'] && @items['groupBySelected'] === grouping className = 'widget-search-results-row-selected' end groupRows << '
' + grouping + '
' className = '' num = num + 1 } list_group['search_ahead'] = { 'skip_queue' => false, 'search_form'=> '
' + groupRows.join("\n") + '
' } if !@templateFill.key?('') @templateFill[''] = '' end @headerPieces['groupByItems'] = '
' + @items['groupByLabel'] + ':
' + WidgetList::Widgets::widget_input(list_group) + '
' @templateFill[''] += @headerPieces['groupByItems'] end if @items['showExport'] @headerPieces['exportButton'] = '' + WidgetList::Widgets::widget_button(@items['exportButtonTitle'], { 'onclick' => 'ListExport(\'' + @items['name'] + '\');' , 'innerClass' => @items['defaultButtonClass'] }, true) + '' @templateFill[''] += @headerPieces['exportButton'] end end end @templateFill[''] = @items['name'] @templateFill[''] = WidgetList::Utils::build_url(@items['pageId'],listJumpUrl,(!$_REQUEST.key?('BUTTON_VALUE'))) @templateFill['--JUMP_URL--'] = @templateFill[''] @templateFill[''] = @items['name'] + '_jump_url' rescue Exception => e out = '
' + generate_error_output(e) + @items['noDataMessage'] + '
' if !@templateFill.key?('') @templateFill[''] = out else @templateFill[''] += out end end if $_REQUEST.key?('export_widget_list') csv = '' @csv.each{ |v| csv += v.to_csv } return csv else return WidgetList::Utils::fill(@templateFill, @items['template']) end end def get_radius_value() @items['cornerRadius'].to_s.include?('px') ? @items['cornerRadius'].to_s : @items['cornerRadius'].to_s + 'px' end def get_shadow_inset_value() @items['shadowInset'].to_s.include?('px') ? @items['shadowInset'].to_s : @items['shadowInset'].to_s + 'px' end def get_shadow_spread_value() @items['shadowSpread'].to_s.include?('px') ? @items['shadowSpread'].to_s : @items['shadowSpread'].to_s + 'px' end def get_header_px_value() @items['titleFontSize'].to_s.include?('px') ? @items['titleFontSize'].to_s : @items['titleFontSize'].to_s + 'px' end def get_header_pieces() @headerPieces end def build_pagination() pageRange = 3 pageNext = 1 pagePrev = 1 showPrev = false showNext = true prevUrl = '' nextUrl = '' tags = '' urlTags = {} templates = {} urlTags['SQL_HASH'] = @sqlHash urlTags['PAGE_ID'] = @items['pageId'] urlTags['LIST_NAME'] = @items['name'] urlTags['BUTTON_VALUE'] = @items['buttonVal'] urlTags['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL'] templates['btn_previous'] = @items['template_pagination_previous_disabled'] templates['btn_next'] = @items['template_pagination_next_active'] if $_REQUEST.key?('search_filter') && ! $_REQUEST['search_filter'].empty? urlTags['search_filter'] = $_REQUEST['search_filter'] end if @items['LIST_COL_SORT'].empty? urlTags['LIST_COL_SORT'] = @items['LIST_COL_SORT'] urlTags['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER'] urlTags['ROW_LIMIT'] = @items['ROW_LIMIT'] end if @items['links'].key?('paginate') && @items['links']['paginate'].class.name == 'Hash' @items['links']['paginate'].each { |tagName, tag| urlTags[tagName] = tag } end @items['carryOverRequsts'].each { |value| if $_REQUEST.key?(value) urlTags[value] = $_REQUEST[value] end } if (@sequence == @totalPages || ! (@totalPages > 0)) showNext = false else urlTags['LIST_SEQUENCE'] = @sequence + 1 nextUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE'))) end if @sequence > 1 pagePrev = @sequence - 1 urlTags['LIST_SEQUENCE'] = pagePrev prevUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE'))) showPrev = true end if !showNext templates['btn_next'] = @items['template_pagination_next_disabled'] end if showPrev templates['btn_previous'] = @items['template_pagination_previous_active'] end #Assemble navigation buttons # pieces = { '' => nextUrl, '' => @items['name'], '' => prevUrl, '' => @items['ajaxFunction'], '' => @items['ajaxFunctionAll'], } templates['btn_next'] = WidgetList::Utils::fill(pieces,templates['btn_next']) templates['btn_previous'] = WidgetList::Utils::fill(pieces,templates['btn_previous']) # # Sequence Range Drop Down # # Show x per page # urlTags['LIST_SEQUENCE'] = @sequence urlTags['ROW_LIMIT'] = 10 @items['carryOverRequsts'].each { |value| if $_REQUEST.key?(value) urlTags[value] = $_REQUEST[value] end } # Automate select box and rules # rowLimitSelect = [10,20,50,100,500,1000] rowLimitSelectData = {} rowLimitSelectConfigs = {} #Set a default of 10 # urlTags['ROW_LIMIT'] = 10 options = '' rowLimitSelect.each_with_index { |jumpCount, key| if (@totalRows >= jumpCount || @totalRows > rowLimitSelect[key-1]) urlTags['ROW_LIMIT'] = jumpCount rowLimitUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE'))) selected = '' if (@items['rowLimit'] == jumpCount) selected = 'selected' end options += " " end } # WidgetSelect( todo) pageSelect = <<-EOD EOD #Ensure the range does not exceed the actual number of pages # if @totalPages < pageRange pageRange = @totalPages end ### # Create a range of x or less numbers. # # Take 2 off and add 2 or as much as possible either way ### startingPoint = @sequence vkill = pageRange while vkill > 0 do vkill = vkill - 1 if startingPoint <= 1 break else startingPoint = startingPoint-1 end end endPoint = @sequence vkill = pageRange while vkill > 0 do vkill = vkill - 1 if endPoint <= 1 endPoint = endPoint+1 else break end end jumpSection = [] #Builds jump section previous 4 5 6 7 next # for page in startingPoint..endPoint urlTags['LIST_SEQUENCE'] = page urlTags['SQL_HASH'] = @sqlHash jumpTemplate = '' jumpUrl = '' jumpUrl = WidgetList::Utils::build_url(@items['pageId'], urlTags, (!$_REQUEST.key?('BUTTON_VALUE'))) if page == @sequence jumpTemplate = @items['template_pagination_jump_active'] else jumpTemplate = @items['template_pagination_jump_unactive'] end jumpSection << WidgetList::Utils::fill({ '' => page, '' => jumpUrl, '' => @items['name'], '' => @items['ajaxFunction'], '' => @items['ajaxFunctionAll'], }, jumpTemplate) end pieces = { '' => templates['btn_previous'], '' => @sequence, '' => templates['btn_next'], '' => @totalPages, '' => @totalRows, '' => pageSelect, '' => jumpSection.join(''), '' => @items['name'], } paginationOutput = WidgetList::Utils::fill(pieces,@items['template_pagination_wrapper']) if (@items['showPagination']) return paginationOutput else return '' end end def self.build_search_button_click(list_parms) extra_get_vars = '' extra_func = '' filterParameters = {} if list_parms.key?('ajaxFunctionAll') extra_func = list_parms['ajaxFunctionAll'] end if list_parms.key?('carryOverRequsts') list_parms['carryOverRequsts'].each { |value| if $_REQUEST.key?(value) filterParameters[value] = $_REQUEST[value] end } extra_get_vars = WidgetList::Utils::build_query_string(filterParameters) end "ListJumpMin(jQuery('##{list_parms['name']}_jump_url').val() + '&advanced_search=1&' + jQuery('#list_search_id_#{list_parms['name']}_results *').serialize() + '&#{extra_get_vars}', '#{list_parms['name']}');HideAdvancedSearch(this);" + extra_func end def build_headers() headers = [] ii = 0 @items['fields'].each { |field, fieldTitle| colWidthStyle = ''; colClass = ''; popupTitle = ''; templateIdx = 'templateNoSortColumn' #Column class # if ! @items['headerClass'].empty? if @items['headerClass'].key?(field.downcase) colClass = @items['headerClass'][field.downcase] end end #Column width # if ! @items['columnWidth'].empty? if @items['columnWidth'].key?(field.downcase) colWidthStyle = "width:" + @items['columnWidth'][field.downcase] + ";" end end if @items['borderedColumns'] colWidthStyle += 'border-right: ' + @items['borderColumnStyle'] + ';' end colWidthStyle += @items['borderHeadFoot'] ? 'border-bottom:' + @items['headFootBorderStyle'] + ';' : '' $_SESSION.deep_merge!({'LIST_SEQUENCE' => { @sqlHash => @sequence} }) #Hover Title # if @items['columnPopupTitle'].key?(field.downcase) popupTitle = @items['columnPopupTitle'][field.downcase] end # # Column is an input # if @items['inputs'].key?(fieldTitle) && @items['inputs'][fieldTitle].class.name == 'Hash' # # Default checkbox hover to "Select All" # # Do specific input type functions # case @items['inputs'][fieldTitle]['type'] when 'checkbox' if popupTitle.empty? && @items['inputs'][fieldTitle]['items']['check_all'] popupTitle = 'Select All' end # # No sort on this column # if ! @items['columnNoSort'].key?(fieldTitle) @items['columnNoSort'][field] = field end if colClass.empty? @items['headerClass'] = { fieldTitle => 'widgetlist-checkbox-header'} colClass = @items['headerClass'][fieldTitle] end end # # Build the input # fieldTitle = build_column_input(fieldTitle) else if $_REQUEST.key?('export_widget_list') && !skip_column(field) @csv[0] << fieldTitle end end #Add in radius if ii == @items['fields'].length - 1 && @items['listDescription'] == '' colWidthStyle += '-moz-border-radius-topright:' + get_radius_value() + ';-webkit-border-top-right-radius:' + get_radius_value() + ';border-top-right-radius:' + get_radius_value() + ';' end if ii == 0 && @items['listDescription'] == '' colWidthStyle += '-moz-border-radius-topleft:' + get_radius_value() + ';-webkit-border-top-left-radius:' + get_radius_value() + ';border-top-left-radius:' + get_radius_value() + ';' end if (@items['useSort'] && (@items['columnSort'].include?(field) || (@items['columnSort'].key?(field)) && !@items['columnNoSort'].include?(field)) || (@items['columnSort'].empty? && !@items['columnNoSort'].include?(field))) templateIdx = 'templateSortColumn' colSort = {} #Assign the column to be sorted # if !@items['columnSort'].empty? && @items['columnSort'].key?(field) colSort['LIST_COL_SORT'] = @items['columnSort'][field] elsif (!@items['columnSort'].empty? && @items['columnSort'].include?(field)) || @items['columnSort'].empty? colSort['LIST_COL_SORT'] = field end colSort['PAGE_ID'] = @items['pageId'] colSort['LIST_NAME'] = @items['name'] colSort['BUTTON_VALUE'] = @items['buttonVal'] colSort['LIST_COL_SORT_ORDER'] = @listSortNext colSort['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL'] colSort['ROW_LIMIT'] = @items['ROW_LIMIT'] colSort['LIST_SEQUENCE'] = @sequence icon = "" if ( ( (@items.key?('LIST_COL_SORT') && !@items['LIST_COL_SORT'].empty?) && @items['LIST_COL_SORT'] == colSort['LIST_COL_SORT']) || ( $_SESSION.key?('LIST_COL_SORT') && !$_SESSION['LIST_COL_SORT'].nil? && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) && $_SESSION['LIST_COL_SORT'][@sqlHash].key?(field)) ) changedSession = false if @items.key?('LIST_COL_SORT') && !@items['LIST_COL_SORT'].empty? changedSession = ( $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) && ! $_SESSION['LIST_COL_SORT'][@sqlHash].key?(@items['LIST_COL_SORT']) ) if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) $_SESSION['LIST_COL_SORT'].delete(@sqlHash) end $_SESSION.deep_merge!({'LIST_COL_SORT' => { @sqlHash => {@items['LIST_COL_SORT']=> @items['LIST_COL_SORT_ORDER'] } } }) end if !changedSession && @items.key?('LIST_COL_SORT') && ! @items['LIST_COL_SORT'].empty? if @items['LIST_COL_SORT_ORDER'] == 'DESC' icon = "↑" else icon = "↓" end elsif !changedSession && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) #load sort from session $_SESSION['LIST_COL_SORT'][@sqlHash].each_with_index { |order,void| if order[1] == 'DESC' colSort['LIST_COL_SORT_ORDER'] = "ASC" icon = "↑" else colSort['LIST_COL_SORT_ORDER'] = "DESC" icon = "↓" end } end end #Carry over any search criteria on a sort to SORT URL # if $_REQUEST.key?('search_filter') && ! $_REQUEST['search_filter'].empty? if $_REQUEST['search_filter'].empty? colSort['search_filter'] = $_REQUEST['search_filter'] end end @items['carryOverRequsts'].each { |value| if $_REQUEST.key?(value) colSort[value] = $_REQUEST[value] end } colSort['SQL_HASH'] = @sqlHash pieces = { '' => WidgetList::Utils::build_url(@items['pageId'],colSort,(!$_REQUEST.key?('BUTTON_VALUE'))), '' => @items['name'], '' => strip_tags(field).gsub(/\s/,'_'), '' => colWidthStyle, '' => popupTitle, '' => colClass, '' => fieldTitle, '' => @items['ajaxFunction'], '' => @items['ajaxFunctionAll'], } headers << WidgetList::Utils::fill(pieces, @items[templateIdx]) else pieces = { '' => fieldTitle, '' => colWidthStyle, '' => popupTitle, '' => colClass, '' => strip_tags(field).gsub(/\s/,'_') } headers << WidgetList::Utils::fill(pieces, @items[templateIdx]) end ii = ii + 1 } @templateFill[''] = headers.count() @templateFill[''] = build_pagination() @templateFill[''] = headers.join('') if ! @items['listDescription'].empty? fillDesc = {} fillDesc[''] = headers.count() fillDesc[''] = @items['listDescription'] fillDesc[''] = @items['name'] @templateFill[''] = WidgetList::Utils::fill(fillDesc,@items['list_description']) else @templateFill[''] = '' end end # @param [String] column (the name) # @param [Fixnum] row (the id or pointer in the loop to fetch the data) def build_column_input(column, row='') content = '' inputManager = @items['inputs'][column] case inputManager['type'] when "checkbox" input = {} input['name'] = 'widget_check_name' input['id'] = 'widget_check_id' input['check_all'] = false input['value'] = '' input['checked'] = '' input['onclick'] = '' input['input_class'] = 'widgetlist-checkbox-input' input['class_handle'] = '' input = WidgetList::Widgets::populate_items(inputManager['items'],input) onClick = [] checkAllId = '' # # Get a value. Assumes it is a column initially. # # @note headers are ignored and would fail as row would be null # if @results.key?(input['value'].upcase) && !@results[input['value'].upcase][row].to_s.empty? input['value'] = @results[ input['value'].upcase ][row] end if input.key?('disabled_if') && input['disabled_if'].class.name == 'Proc' row_tmp = {} @results.map { |column| column }.each { |col| row_tmp[ col[0] ] = col[1][row] } if input['disabled_if'].call(row_tmp) input['disabled'] = true end end # # Append class handle # input['input_class'] = "#{input['input_class']} #{input['class_handle']}" if input['check_all'] checkAllId = input['id'] if $_SESSION.key?('list_checks') && !$_SESSION['list_checks'].nil? && $_SESSION['list_checks'].key?('check_all_' + @sqlHash.to_s + @items['name'].to_s + @sequence.to_s) input['checked'] = true end # # Set header class # if @items['headerClass'].class.name == 'Array' && @items['headerClass'].key?('checkbox') if $_SESSION['list_checks'].key?('check_all_' + @sqlHash.to_s + @items['name'].to_s + @sequence.to_s) input['checked'] = true end end else input['input_class'] = "#{input['input_class']} #{input['class_handle']} #{input['class_handle']}_list" end # # Setup onclick action # if input['onclick'].empty? listJumpUrl = {} listJumpUrl['BUTTON_VALUE'] = @items['buttonVal'] listJumpUrl['LIST_COL_SORT'] = @items['LIST_COL_SORT'] listJumpUrl['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER'] listJumpUrl['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL'] listJumpUrl['ROW_LIMIT'] = @items['ROW_LIMIT'] listJumpUrl['LIST_SEQUENCE'] = @sequence listJumpUrl['LIST_NAME'] = @items['name'] listJumpUrl['SQL_HASH'] = @sqlHash listJumpUrl['list_action'] = 'ajax_widgetlist_checks' onClick << "AjaxMaintainChecks(this, '#{input['class_handle']}', '#{@items['name']}', '" + WidgetList::Utils::build_url(@items['pageId'],listJumpUrl,(!$_REQUEST.key?('BUTTON_VALUE'))) + "', '#{checkAllId}');" end input['onclick'] = onClick.join(' ') # # Checkbox is checked or not per query value # if ! @items['checkedFlag'].empty? if @items['checkedFlag'].key?(column) input['checked'] = !!@results[ @items['checkedFlag'][column].upcase ][row] end end # # Checkbox is checked or not per session (overwrites query) # if $_SESSION.key?('list_checks') && !$_SESSION['list_checks'].nil? && $_SESSION['list_checks'].key?(@items['name'] + @sqlHash + input['value'].to_s) input['checked'] = true end content = WidgetList::Widgets::widget_check(input) #todo never implemented when "text" a=1 #content = WidgetInput() when "select" a=1 #content = WidgetSelect() end return content end # build_list controls a default AJAX/Export and full HTML return output # in some cases you should copy and paste this logic for custom scenarios in your controller, but in most cases, this is okay def self.build_list(list_parms) list = WidgetList::List.new(list_parms) # # If AJAX, send back JSON # if $_REQUEST.key?('BUTTON_VALUE') && $_REQUEST['LIST_NAME'] == list_parms['name'] if $_REQUEST.key?('export_widget_list') return ['export',list.render()] end ret = {} if $_REQUEST['list_action'] != 'ajax_widgetlist_checks' ret['list'] = list.render() ret['search_bar'] = list.get_header_pieces['searchBar'] ret['group_by_items'] = list.get_header_pieces['groupByItems'] ret['export_button'] = list.get_header_pieces['exportButton'] ret['list_id'] = list_parms['name'] ret['callback'] = 'ListSearchAheadResponse' end return ['json',WidgetList::Utils::json_encode(ret)] else # # Else assign to variable for view # if list.isAdministrating return list.render() else return ['html', list.render() ] end end end # checkbox_helper just builds the proper Hashes to setup a checkbox widget row # it assumes you have a fake column called '' AS checkbox to fill in with the widget_check def self.checkbox_helper(list_parms,primary_key) list_parms.deep_merge!({'inputs' => {'checkbox'=> {'type' => 'checkbox' } } }) list_parms.deep_merge!({'inputs' => {'checkbox'=> {'items' => { 'name' => list_parms['name'] + '_visible_checks[]', 'value' => primary_key, #the value should be a column name mapping 'class_handle' => list_parms['name'] + '_info_tables', } } } }) list_parms.deep_merge!({'inputs' => {'checkbox_header'=> {'type' => 'checkbox' } } }) list_parms.deep_merge!({'inputs' => {'checkbox_header'=> {'items' => { 'check_all' => true, 'id' => list_parms['name'] + '_info_tables_check_all', 'class_handle' => list_parms['name'] + '_info_tables', } } } }) return list_parms end def self.group_by_max_each_field(list_parms,group_by_filter) # # Oracle needs MAX on most fields when grouping in order to shy away from 'not a GROUP BY expression' errors # if group_by_filter != 'none' if list_parms.key?('fieldFunction') && !list_parms['fieldFunction'].empty? list_parms['fieldFunction'].each { |k, v| if !k.include?('_linked') && k != 'cnt' list_parms['fieldFunction'][k] = "MAX(#{v})" end } end if list_parms.key?('fieldsHidden') && !list_parms['fieldsHidden'].empty? list_parms['fieldsHidden'].each { |k| if (list_parms.key?('fieldFunction') && !list_parms['fieldFunction'].empty? && !list_parms['fieldFunction'].key?(k)) || list_parms['fieldFunction'].empty? list_parms['fieldFunction'][k] = "MAX(#{k})" end } end list_parms['fields'].each { |k| if !k.include?('_linked') && k != 'cnt' if (list_parms.key?('fieldFunction') && !list_parms['fieldFunction'].empty? && !list_parms['fieldFunction'].key?(k)) || list_parms['fieldFunction'].empty? list_parms['fieldFunction'][k] = "MAX(#{k})" end end } end return list_parms end def self.drill_down_back(list_name='') '
' end def self.build_drill_down(*params) required_params = { :list_id => true, # -- your widget_list name (used for JS) :drill_down_name => true, # -- an identifier that is pass for the "column" or "type of drill down" which is passed as $_REQUEST['drill_down'] when the user clicks and returned from get_filter_and_drilldown based on session or request :data_to_pass_from_view => true, # -- Any SQL function or column name/value in the resultset in which would be the value passed when the user clicks the drill down :column_to_show => true, # -- The visible column or SQL functions to display to user for the link } optional_params = { :column_alias => '', # -- AS XXXX :extra_function => '', # -- Onclick of link, call another JS function after the drill down function is called :js_function_name => 'ListDrillDown', # -- name of JS Function :column_class => '', # -- custom class on the tag :link_color => 'blue', # -- whatever color you want the link to be :extra_js_func_params => '', # -- Add extra params to ListDrillDown outside of the default :primary_database => true, # -- Since this function builds a column before widget_list is instantiated, tell which connection you are using } valid = WidgetList::Widgets::validate_items(params[0],required_params) items = WidgetList::Widgets::populate_items(params[0],optional_params) if items[:column_alias].empty? items[:column_alias] = items[:column_to_show] end if !items[:column_class].empty? items[:column_class] = ' "' + WidgetList::List::concat_string(items[:primary_database]) + items[:column_class] + WidgetList::List::concat_string(items[:primary_database]) + '"' end if WidgetList::List.get_db_type(items[:primary_database]) == 'oracle' link = %[q'[]' #{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}q'[]' #{WidgetList::List::concat_outer(items[:primary_database])} #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}] else if WidgetList::List.get_db_type(items[:primary_database]) == 'postgres' link = %['"' #{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}'' #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}] else link = %[#{WidgetList::List::concat_inner(items[:primary_database])}""#{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}""#{WidgetList::List::concat_outer(items[:primary_database])} #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}] end end if $_REQUEST.key?('export_widget_list') link = "#{items[:column_to_show]} #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}" end return link end def self.concat_string(primary) case WidgetList::List.get_db_type(primary) when 'mysql' ' , ' when 'oracle','sqlite','postgres' ' || ' else ',' end end def self.double_quote(primary) case WidgetList::List.get_db_type(primary) when 'mysql' '\\"' when 'oracle','sqlite' '""' else '"' end end def self.concat_outer(primary) case WidgetList::List.get_db_type(primary) when 'mysql' ')' else '' end end def self.concat_inner(primary) case WidgetList::List.get_db_type(primary) when 'mysql' 'CONCAT(' else '' end end def build_column_button(column,j) buttons = @items['buttons'][column] columnValue = @results[column.upcase][j] btnOut = [] strCnt = 0 nameId = '' buttons.each { |buttonId,buttonAttribs| function = @items['linkFunction'] parameters = '' renderButton = true page = buttonAttribs['page'].dup if buttonAttribs.key?('tags') tags = buttonAttribs['tags'].dup all_wildcard = false if buttonAttribs['tags'].first[0] == 'all' all_wildcard = true tags = {} @results.keys.each { |tag| tags[tag.downcase] = tag.downcase } end tags.each { | tagName , tag | if @results.key?(tag.upcase) && @results[tag.upcase][j] # # Data exists, lets check to see if page has any lowercase tags for restful URLs # if buttonAttribs.key?('page') && buttonAttribs['page'].include?(tag.downcase) page.gsub!(tag.downcase,@results[tag.upcase][j]) else # # Will build ?tagname=XXXX based on your hash passed to your page # buttonAttribs.deep_merge!({ 'args' => { tagName => @results[tag.upcase][j] } }) unless all_wildcard end else # # User is passing hard coded tags such as 'tags' => {'my_static_var' => '1234'} # Just fill in normally wherever anything is matched # if buttonAttribs.key?('page') && buttonAttribs['page'].include?(tag.downcase) page.gsub!(tagName,tag) else buttonAttribs.deep_merge!({ 'args' => { tagName => tag } }) end end } end nameId = buttonId.to_s + '_' + j.to_s buttonAttribs['name'] = nameId buttonAttribs['id'] = nameId if buttonAttribs.key?('hide_if') && input['hide_if'].class.name == 'Proc' row_tmp = {} @results.map { |column| column }.each { |col| row_tmp[ col[0] ] = col[1][row] } if buttonAttribs['hide_if'].call(row_tmp) renderButton = false end end if (renderButton) strCnt += (buttonAttribs['text'].length * 15) attributes = buttonAttribs.dup attributes['page'] = page attributes['innerClass'] = @items['defaultButtonClass'] if !attributes.key?('innerClass') btnOut << WidgetList::Widgets::widget_button(buttonAttribs['text'], attributes , true) end } #BS width algorithm. HACK/TWEAK/OMG Get it working. # colWidth = ((strCnt + (btnOut.count * 35)) / 2) + 10 return '
' + btnOut.join('') + '
' end # @param [String] column def build_column_link(column,j) links = @items['links'][column] url = {'PAGE_ID' => @items['pageId']} function = @items['linkFunction'] parameters = '' #todo unit test this and all of column links if links.key?('tags') links['tags'].each { | tagName, tag | if @results[tag][j] url[tagName] = @results[tag][j] else url[tagName] = tag end } end if links.key?('onclick') && links['onclick'].class.name == 'Hash' if links['onclick'].key?('function') && !links['onclick']['function'].empty? function = links['onclick']['function'] end if links['onclick'].key?('tags') && !links['onclick']['tags'].empty? links['onclick']['tags'].each { | tagName , tag| if @results.key?(tag.upcase) parameters = ", '" + @results[tag.upcase][j] + "'" end } end end url['SQL_HASH'] = @sqlHash linkUrl = WidgetList::Utils::build_url(@items['pageId'], url, (!$_REQUEST.key?('BUTTON_VALUE'))) "#{function}('#{linkUrl}'#{parameters})" end def build_rows() sql = build_statement() if @totalResultCount > 0 if @items['data'].empty? #Run the actual statement # @totalRowCount = get_database._select(sql , @items['bindVars'], @items['bindVarsLegacy'], @active_record_model) end if @totalRowCount > 0 if @items['data'].empty? @results = get_database.final_results else @results = @items['data'] end #Build each row # max = @totalRowCount-1 rows = [] j = 0 for j in j..max columns = [] row_values = [] customRowColor = '' customRowStyle = '' # # For each column (field) in this row # changedFontColor = false @items['fields'].each { |column , fieldTitle| column = strip_aliases(column) colPieces = {} colClasses = [] theStyle = '' colData = '' colClass = '' onClick = '' colWidthStyle = '' content = '' contentTitle = '' #todo unit test build_column_link # # Column is a Link # if @items['links'].key?(column) && @items['links'][column].class.name == 'Hash' onClick = build_column_link(column,j) end # # Column is a Button # if @items['buttons'].key?(column) && @items['buttons'][column].class.name == 'Hash' content = build_column_button(column, j) # # Column is an input # elsif @items['inputs'].key?(column) && @items['inputs'][column].class.name == 'Hash' colClasses << @items['checkedClass'] content = build_column_input(column, j) # # Column is text # else cleanData = strip_tags(@results[column.upcase][j].to_s) row_values << cleanData # # For now disable length parser # if false && cleanData.length > @items['strlength'] content = @results[column.upcase][j].to_s[ 0, @items['strlength'] ] + '...' else content = @results[column.upcase][j].to_s end # #Strip HTML # if !@items['allowHTML'] content = strip_tags(content) end content = get_database._bind(content, @items['bindVarsLegacy']) # Column color # if ! @items['columnStyle'].empty? if @items['columnStyle'].key?(column.downcase) colHeader = @items['columnStyle'][column.downcase] if @results.key?(colHeader.upcase) theStyle = @results[colHeader.upcase][j] else theStyle = colHeader end end end # Column width # if ! @items['columnWidth'].empty? if @items['columnWidth'].key?(column.downcase) colWidthStyle = "width:" + @items['columnWidth'][column.downcase] + ";" end end # Column Class # if !@items['columnClass'].empty? if @items['columnClass'].key?(column.downcase) colClasses << @items['columnClass'][column.downcase] end end end # # Setup any column classes # colClasses << @items['collClass'] colClass = colClasses.join(' ') # # Row Color # if !@items['rowColorByStatus'].empty? && @items['rowColorByStatus'].key?(column) && !@items['rowColorByStatus'][column].empty? @items['rowColorByStatus'][column].each { |status,color| if status === content customRowColor = color end } end # # Row Style # if !@items['rowStylesByStatus'].empty? && @items['rowStylesByStatus'].key?(column) && !@items['rowStylesByStatus'][column].empty? @items['rowStylesByStatus'][column].each { |status,inlineStyle| if status === content customRowStyle = inlineStyle if inlineStyle.include?('color:') || inlineStyle.include?('color :') changedFontColor = true end end } end # # Set up Column Pieces # colPieces[''] = colClass colPieces[''] = @items['collAlign'] colPieces[''] = theStyle + colWidthStyle if @items['borderedColumns'] colPieces[''] += 'border-right: ' + @items['borderColumnStyle'] + ';' end if @items['borderedRows'] colPieces[''] += 'border-top: ' + @items['borderRowStyle'] + ';' end colPieces[''] = onClick colPieces[''] = contentTitle #todo htmlentities needed ? colPieces[''] = content # # Assemble the Column # columns << WidgetList::Utils::fill(colPieces, @items['col']) } if $_REQUEST.key?('export_widget_list') @csv << row_values end #Draw the row # pieces = {'' => columns.join('') } if @items['rowColorByStatus'].empty? && @items['rowStylesByStatus'].empty? #Set the row color # if( j % 2 ==0) rowColor = @items['rowOffsets'][1] else rowColor = @items['rowOffsets'][0] end #Draw default color # pieces[''] = rowColor pieces[''] = '' pieces[''] = @items['rowClass'] else pieces[''] = !customRowColor.empty? ? customRowColor : @items['rowColor'] pieces[''] = !customRowStyle.empty? ? customRowStyle : '' pieces[''] = @items['rowClass'] end pieces[''] += 'font-size:' + @items['dataFontSize'] + ';' if !changedFontColor pieces[''] += 'color:' + @items['rowFontColor'] + ';' end rows << WidgetList::Utils::fill(pieces, @items['row']) end @templateFill[''] = rows.join('') else err_message = (get_database.errors) ? @items['noDataMessage'] + ' (An error occurred)' : @items['noDataMessage'] @templateFill[''] = '
' + generate_error_output() + err_message + '
' end else err_message = (get_database.errors) ? @items['noDataMessage'] + ' (An error occurred)' : @items['noDataMessage'] @templateFill[''] = '
' + generate_error_output() + err_message + '
' end end def generate_error_output(ex='') sqlDebug = "" if !@items['errors'].empty? sqlDebug += "

(" + @items['errors'].join(', ') + ")" end if Rails.env == 'development' sqlDebug += "

" end if Rails.env == 'development' && get_database.errors sqlDebug += "

(" + get_database.last_error.to_s + ")" end if Rails.env == 'development' && ex != '' sqlDebug += "

(" + ex.to_s + ")
"  + $!.backtrace.join("\n\n") +  "
" end if Rails.env != 'development' if get_database.errors Rails.logger.info get_database.last_error.to_s end if ex != '' Rails.logger.info $!.backtrace.join("\n\n") end end Rails.logger.info sqlDebug sqlDebug end def build_statement() statement = '' @fieldList = [] @fieldListPlain = [] pieces = { '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => ''} #Build out a list of columns to select from # @items['fields'].each { |column, fieldTitle| @fieldListPlain << strip_aliases(column) if @items['fieldFunction'].key?(column) && !@items['fieldFunction'][column].empty? # fieldFunction's should not have an alias, just the database functions column = @items['fieldFunction'][column] + " " + column end @fieldList << column } if get_database.db_type == 'oracle' if !@items['groupBy'].empty? @fieldList << 'MAX(rn) as rn' else @fieldList << 'rn' end @fieldListPlain << 'rn' end if @items['fieldsHidden'].class.name == 'Array' @items['fieldsHidden'].each { |column| if !@items['fields'].key?(column) @fieldListPlain << strip_aliases(column) if @items['fieldFunction'].key?(column) && !@items['fieldFunction'][column].empty? # fieldFunction's should not have an alias, just the database functions column = @items['fieldFunction'][column] + " " + column end @fieldList << column end } elsif @items['fieldsHidden'].class.name == 'Hash' @items['fieldsHidden'].each { |column| col = column[0] if !@items['fields'].key?(col) @fieldListPlain << strip_aliases(col) if @items['fieldFunction'].key?(column[0]) && !@items['fieldFunction'][column[0]].empty? # fieldFunction's should not have an alias, just the database functions col = @items['fieldFunction'][column[0]] + " " + column[0] end @fieldList << col end } end viewPieces = {} viewPieces[''] = @fieldListPlain.join(',') viewPieces[''] = @fieldList.join(',') viewPieces[''] = get_view() statement = WidgetList::Utils::fill(viewPieces, @items['statement']['select']['view']) @sqlHash = Digest::SHA2.hexdigest( WidgetList::Utils::fill(pieces, statement) ) if @items['searchClear'] || @items['searchClearAll'] clear_sql_session(@items.key?('searchClearAll')) end if !$_REQUEST.key?('BUTTON_VALUE') && !$_SESSION['LIST_SEQUENCE'].nil? && $_SESSION.key?('LIST_SEQUENCE') && $_SESSION['LIST_SEQUENCE'].key?(@sqlHash) && $_SESSION['LIST_SEQUENCE'][@sqlHash] > 0 @sequence = $_SESSION['LIST_SEQUENCE'][@sqlHash] generate_limits end if !@filter.empty? pieces[''] = ' WHERE ' + @filter end if !@items['groupBy'].empty? pieces[''] = ' GROUP BY ' + @items['groupBy'] else pieces[''] = '' end if !@items['LIST_COL_SORT'].empty? || ($_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)) pieces[''] += ' ORDER BY ' foundColumn = false if ! @items['LIST_COL_SORT'].empty? foundColumn = true pieces[''] += tick_field() + strip_aliases(@items['LIST_COL_SORT']) + tick_field() + " " + @items['LIST_COL_SORT_ORDER'] else $_SESSION['LIST_COL_SORT'][@sqlHash].each_with_index { |order,void| if @items['fields'].key?(order[0]) foundColumn = true pieces[''] += tick_field() + strip_aliases(order[0]) + tick_field() + " " + order[1] end } if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) end # Add base order by if ! @items['orderBy'].empty? pieces[''] += ',' if foundColumn == true pieces[''] += @items['orderBy'] end elsif !@items['orderBy'].empty? pieces[''] += ' ORDER BY ' + @items['orderBy'] end if get_database.db_type == 'oracle' && pieces[''].empty? #oracle needs a field to perform the rank() over #if field is not an "inputs" or a "buttons" #if field is all NULL, then you better watch out as paging will NOT work tmp = @items['fields'].dup.reject { |val| if (!@items['inputs'].key?(val) && !@items['buttons'].key?(val)) false else true end } keys = tmp.keys pieces[''] += ' ORDER BY ' + strip_aliases(keys[0]) + ' ASC' unless keys[0].nil? end case get_database.db_type when 'postgres' pieces[''] = ' LIMIT :HIGH OFFSET :LOW' when 'oracle' pieces[''] = ' WHERE ( rn >' + (@sequence > 1 ? '' : '=') + ' :LOW AND rn <= :HIGH ) ' else pieces[''] = ' LIMIT :LOW, :HIGH' end statement = WidgetList::Utils::fill(pieces, statement) if @items['rowLimit'].to_i >= @totalRows @items['bindVarsLegacy']['LOW'] = 0 @sequence = 1 end statement end def strip_aliases(name='') name = (name.include?(' ') ? name.split(' ').last : name) ((name.include?('.')) ? name.split('.').last.gsub(/'||"/,'') : name.gsub(/'||"/,'')) end def auto_column_name(name='') name.gsub(/\_/,' ').gsub(/\-/,' ').capitalize end def get_total_records() filter = '' fields = {} sql = '' hashed = false if !get_view().empty? sql = WidgetList::Utils::fill({'' => get_view(),'' => !@items['groupBy'].empty? ? ' GROUP BY ' + @items['groupBy'] : '' }, @items['statement']['count']['view']) end if ! @filter.empty? filter = ' WHERE ' + @filter end sql = WidgetList::Utils::fill({'' => filter}, sql) if ! sql.empty? if @items['showPagination'] cnt = get_database._select(sql, @items['bindVars'], @items['bindVarsLegacy'], @active_record_model) if cnt > 0 if cnt > get_database.final_results['TOTAL'][0].to_i #sometimes databases and queries run do not count(1) and group properly and instead rows = cnt else rows = get_database.final_results['TOTAL'][0].to_i end else rows = 0 end if rows > 0 @totalRows = rows.to_i end else rows = 1 end else rows = 0 end if @totalRows > 0 @totalPages = (@totalRows.to_f / @items['rowLimit'].to_f).ceil() end rows end def self.determine_db_type(db_type) if db_type.include?('://') the_type, void = db_type.split("://") if the_type == 'sqlite:/' the_type = 'sqlite' end return the_type.downcase else begin WidgetList::List::load_widget_list_database_yml() if $widget_list_db_conf.key?(db_type) if $widget_list_db_conf[db_type]['adapter'].include?('mysql') return 'mysql' elsif $widget_list_db_conf[db_type]['adapter'].include?('postgres') return 'postgres' elsif $widget_list_db_conf[db_type]['adapter'].include?('oracle') return 'oracle' elsif $widget_list_db_conf[db_type]['adapter'].include?('sqlite') return 'sqlite' elsif $widget_list_db_conf[db_type]['adapter'].include?('sqlserver') return 'sqlserver' elsif $widget_list_db_conf[db_type]['adapter'].include?('ibm') return 'db2' end end rescue return '' end end end def self.load_widget_list_yml if $widget_list_conf.nil? $widget_list_conf = YAML.load(ERB.new(File.new(Rails.root.join("config", "widget-list.yml")).read).result)[Rails.env] end end def self.load_widget_list_database_yml if $widget_list_db_conf.nil? $widget_list_db_conf = YAML.load(ERB.new(File.new(Rails.root.join("config", "database.yml")).read).result) end end def self.get_db_type(primary=true) WidgetList::List::load_widget_list_yml() if primary database_conn = $widget_list_conf[:primary] else database_conn = $widget_list_conf[:secondary] end WidgetList::List::determine_db_type(database_conn) end def get_db_type(primary=true) WidgetList::List::get_db_type(primary) end def get_view @active_record_model = false if (@is_primary_sequel && @items['database'] == 'primary') || (@is_secondary_sequel && @items['database'] == 'secondary') return @items['view'] elsif @items['view'].respond_to?('scoped') && @items['view'].scoped.respond_to?('to_sql') @active_record_model = @items['view'].name.constantize new_columns = [] @items['fields'].each { |column, fieldTitle| if @items['fieldFunction'].key?(column) && !@items['fieldFunction'][column].empty? # fieldFunction's should not have an alias, just the database functions column = @items['fieldFunction'][column] + " " + column end new_columns << column } if @items['fieldsHidden'].class.name == 'Array' && !@items['fieldsHidden'].empty? @items['fieldsHidden'].each { |columnPivot| if !@items['fields'].key?(columnPivot) if @items['fieldFunction'].key?(columnPivot) && !@items['fieldFunction'][columnPivot].empty? # fieldFunction's should not have an alias, just the database functions columnPivot = @items['fieldFunction'][columnPivot] + " " + columnPivot end new_columns << columnPivot end } elsif @items['fieldsHidden'].class.name == 'Hash' && !@items['fieldsHidden'].empty? @items['fieldsHidden'].each { |columnPivot| if !@items['fields'].key?(columnPivot[0]) if @items['fieldFunction'].key?(columnPivot[0]) && !@items['fieldFunction'][columnPivot[0]].empty? # fieldFunction's should not have an alias, just the database functions columnPivot[0] = @items['fieldFunction'][columnPivot[0]] + " " + columnPivot[0] end new_columns << columnPivot[0] end } end view = @items['view'].scoped.to_sql sql_from = view[view.index(/FROM/),view.length] view = "SELECT #{new_columns.join(',')} " + sql_from where = '' if !@items['groupBy'].empty? where = '' end return "( #{view} #{where} ) a" else return "" end end def connect @has_connected = true begin if Rails.root.join("config", "widget-list.yml").file? WidgetList::List::load_widget_list_yml() if $widget_list_conf.nil? throw 'Configuration file widget-list.yml has no data. Check that (' + Rails.env + ') Rails.env matches the pointers in the file' end @primary_conn = $widget_list_conf[:primary] @secondary_conn = $widget_list_conf[:secondary] else throw 'widget-list.yml not found' end @is_primary_sequel = true @is_secondary_sequel = true if @primary_conn != false && ! @primary_conn.include?(':/') @is_primary_sequel = false end if @secondary_conn != false && !@secondary_conn.include?(':/') @is_secondary_sequel = false end if @primary_conn != false if @primary_conn.include?(':/') @widget_list_sequel_conn = Sequel.connect(@primary_conn) @widget_list_sequel_conn.db_type = WidgetList::List::determine_db_type(@primary_conn) else @widget_list_ar_conn = WidgetListActiveRecord.new @widget_list_ar_conn.db_type = WidgetList::List::determine_db_type(@primary_conn) end end if @secondary_conn != false if @secondary_conn.include?(':/') @widget_list_sequel_conn2 = Sequel.connect(@secondary_conn) @widget_list_sequel_conn2.db_type = WidgetList::List::determine_db_type(@secondary_conn) else @widget_list_ar_conn2 = WidgetListActiveRecord.new @widget_list_ar_conn2.db_type = WidgetList::List::determine_db_type(@secondary_conn) end end rescue Exception => e Rails.logger.info "widget-list.yml and connection to @widget_list_sequel_conn or @widget_list_sequel_conn2 failed. Please fix and try again (" + e.to_s + ")" end end def self.is_sequel(primary) WidgetList::List::load_widget_list_yml() if primary database_conn = $widget_list_conf[:primary] else database_conn = $widget_list_conf[:secondary] end is_sequel = true if database_conn != false && ! database_conn.include?('://') is_sequel = false end return is_sequel end def self.get_sequel(primary=true) WidgetList::List::load_widget_list_yml() if primary Sequel.connect($widget_list_conf[:primary]) else Sequel.connect($widget_list_conf[:secondary]) end end def get_database if @has_connected.nil? connect end if @is_primary_sequel && @widget_list_sequel_conn.class.name.to_s.split('::').first == 'Sequel' && @current_db_selection == 'primary' || @current_db_selection.nil? @widget_list_sequel_conn.test_connection end if @is_secondary_sequel && @widget_list_sequel_conn2.class.name.to_s.split('::').first == 'Sequel' && @current_db_selection == 'secondary' @widget_list_sequel_conn2.test_connection end case @current_db_selection when 'primary' return (@is_primary_sequel) ? @widget_list_sequel_conn : @widget_list_ar_conn when 'secondary' return (@is_secondary_sequel) ? @widget_list_sequel_conn2 : @widget_list_ar_conn2 else return (@is_primary_sequel) ? @widget_list_sequel_conn : @widget_list_ar_conn end end end end