#-- # Copyright (c) 2012+ Damjan Rems # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ module DrgcmsFormFields ########################################################################### # Implementation of select DRG CMS form field. # # ===Form options: # * +name:+ field name (required) # * +type:+ select (required) # * +choices:+ Values for choices separated by comma. Values can also be specified like description:value. # In the example description will be shown to user, but value will be saved to document. # choices: 'OK:0,Ready:1,Error:2' # choices: Ruby,Pyton,PHP # * +eval:+ Choices will be provided by evaluating expression # * eval: dc_choices4('model_name','description_field_name','_id'); dc_choices4 helper will provide data for select field. # * eval: ModelName.choices4_field; ModelName class will define method choices4_field which # will provide data for select field. # * collection_name.search_field_name.method_name; When searching is more complex custom search # method may be defined in CollectionName model which will provide result set for search. # * If choices or eval is not defined choices will be provided from translation helpers. For example: # Collection has field status choices for field may be provided by en.helpers.model_name.choices4_status # entry of english translation. English is of course default translation. If you provide translations in # your local language then select choices will be localized. # en.helpers.model_name.choices4_status: 'OK:0,Ready:1,Error:2' # sl.helpers.model_name.choices4_status: 'V redu:0,Pripravljen:1,Napaka:2' # * +depend:+ Select options may depend on a value in some other field. If depend option is specified # then chices must be provided by class method and defined in eval option. # * +html:+ html options which apply to select field (optional) # # Form example: # 30: # name: type # type: select # 40: # name: parent # type: select # eval: DcCategory.values_for_parent # html: # include_blank: true # 50: # name: company # type: select # choices: Audi,BMW,Mercedes # or # choices: helpers.label.model.choices4_field # 60: # name: type # type: select # eval: Cars.choices4_type # depend: company ########################################################################### class Select < DrgcmsField ########################################################################### # Choices are defined in helper as: # helper.label.table_name.choices_for_fieldname or # choices4_tablename_fieldname ########################################################################### def choices_in_helper(helper = nil) helper ||= "helpers.label.#{@form['table']}.choices4_#{@yaml['name']}" c = t(helper) if c.match( 'translation missing' ) helper = "choices_for_#{@form['table']}_#{@yaml['name']}" return "Error. #{helper} not defined" if c.match( 'translation missing' ) end c end ########################################################################### # Choices are defined by evaluating an expression. This is most common class # method defined in a class. eg. SomeClass.get_choices4 ########################################################################### def choices_in_eval(e) e.strip! if @yaml['depend'].nil? method = e.split(/\ |\(/).first return eval(e) if respond_to?(method) # id method defined here return eval('@parent.'+e) if @parent.respond_to?(method) # is method defined in helpers # eval whatever it is there eval e else # add event listener to depend field @js << %( $(document).ready(function() { $('#record_#{@yaml['depend']}').change( function(e) { update_select_depend('record_#{@yaml['name']}', 'record_#{@yaml['depend']}','#{e}');}); $('#_record_#{@yaml['depend']}').change( function(e) { update_select_depend('record_#{@yaml['name']}', '_record_#{@yaml['depend']}','#{e}');}); }); ) # depend field might be virtual field. It's value should be set in params depend_value = @yaml['depend'][0] == '_' ? @parent.params["p_#{@yaml['depend']}"] : @record[@yaml['depend']] e << " '#{depend_value}'" eval e end end ########################################################################### # Create choices array for select field. ########################################################################### def get_choices begin choices = case when @yaml['choices'] then @yaml['choices'].match('helpers.') ? choices_in_helper(@yaml['choices']) : @yaml['choices'] when @yaml['eval'] then choices_in_eval(@yaml['eval']) else choices_in_helper() end # Convert string to Array choices.class == String ? choices.chomp.split(',').inject([]) { |r,v| r << (v.match(':') ? v.split(':') : v ) } : choices rescue Exception => e Rails.logger.debug "\nError in select eval. #{e.message}\n" Rails.logger.debug(e.backtrace.join($/)) if Rails.env.development? ['error'] # return empty array when error occures end end ########################################################################### # Will add code to view more data about selected option in a window ########################################################################### def add_view_code return '' if (data = @record.send(@yaml['name'])).blank? ar = @yaml['view'].split(/\ |\,/).delete_if {|e| e.blank?} table, form_name = *ar url = @parent.url_for(controller: :cmsedit, id: data, action: :edit, table: table, form_name: form_name, readonly: true, window_close: 1 ) icon = @parent.fa_icon('eye') %(#{icon}) end ########################################################################### # Return value when readonly is required ########################################################################### def ro_standard value = @record.respond_to?(@yaml['name']) ? @record.send(@yaml['name']) : nil return self if value.blank? choices = get_choices() if value.class == Array # multiple choices html = '' value.each do |element| choices.each do |choice| if choice.to_s == element.to_s html << '
' if html.size > 0 html << "#{element.to_s}" end end end return super(html) else choices.each do |choice| if choice.class == Array return super(choice.first) if choice.last.to_s == value.to_s else return super(choice) if choice.to_s == value.to_s end end end super('') end ########################################################################### # Render select field html code ########################################################################### def render return ro_standard if @readonly set_initial_value('html','selected') # separate options and html part html_part = {} @yaml['html'].symbolize_keys! %i(class id style required).each { |sym| html_part[sym] = @yaml['html'].delete(sym) if html_part[sym]} html_part[:multiple] = true if @yaml['multiple'] record = record_text_for(@yaml['name']) if html_part[:multiple] @html << @parent.select(record, @yaml['name'], get_choices, @yaml['html'], html_part) @js << "$('##{record}_#{@yaml['name']}').selectMultiple();" else @html << @parent.select(record, @yaml['name'], get_choices, @yaml['html'], html_part) # add code for view more data @html << add_view_code() if @yaml['view'] end self end ########################################################################### # Return value. ########################################################################### def self.get_data(params, name) if params['record'][name].class == Array params['record'][name].delete_if {|e| e.blank? } return if params['record'][name].size == 0 # convert to BSON objects is_id = BSON::ObjectId.legal?(params['record'][name].first) return params['record'][name].map{ |e| BSON::ObjectId.from_string(e) } if is_id end params['record'][name] end end end