Class: AspaceFormHelper::FormContext

Inherits:
Object
  • Object
show all
Defined in:
frontend/app/helpers/aspace_form_helper.rb

Direct Known Subclasses

ReadOnlyContext

Defined Under Namespace

Classes: BaseDefinition, JSONModelDefinition, ReadOnlyContext

Constant Summary collapse

PROPERTIES_TO_EXCLUDE_FROM_READ_ONLY_VIEW =
["jsonmodel_type", "lock_version", "_resolved", "uri", "ref", "create_time", "system_mtime", "user_mtime", "created_by", "last_modified_by", "sort_name_auto_generate", "suppressed", "display_string", "file_uri", "agent_person_id", "agent_software_id", "agent_family_id", "agent_corporate_entity_id", "id"]

Instance Method Summary collapse

Constructor Details

#initialize(name, values_from, parent) ⇒ FormContext

Returns a new instance of FormContext.



16
17
18
19
20
21
22
# File 'frontend/app/helpers/aspace_form_helper.rb', line 16

def initialize(name, values_from, parent)
  values = values_from.is_a?(JSONModelType) ? values_from.to_hash(:raw) : values_from

  @forms = FormHelpers.new
  @parent = parent
  @context = [[name, values]]
end

Instance Method Details

#[](key) ⇒ Object



218
219
220
# File 'frontend/app/helpers/aspace_form_helper.rb', line 218

def [](key)
  obj[key]
end

#add_tooltip_options(tooltip, options) ⇒ Object



543
544
545
546
547
548
549
550
551
552
553
# File 'frontend/app/helpers/aspace_form_helper.rb', line 543

def add_tooltip_options(tooltip, options)
  options[:title] = tooltip
  options['data-placement'] = 'bottom'
  options['data-html'] = true
  options['data-delay'] = 500
  options['data-trigger'] = 'manual'
  options['data-template'] = '<div class="tooltip archivesspace-help"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
  options[:class] ||= ''
  options[:class] += ' has-tooltip'
  options
end

#allowable_types_for(name) ⇒ Object



707
708
709
710
711
712
713
# File 'frontend/app/helpers/aspace_form_helper.rb', line 707

def allowable_types_for(name)
  if @active_template && @parent.templates[@active_template]
    @parent.templates[@active_template][:definition].allowable_types_for(name)
  else
    []
  end
end

#checkbox(name, opts = {}, default = true, force_checked = false) ⇒ Object



559
560
561
562
563
564
# File 'frontend/app/helpers/aspace_form_helper.rb', line 559

def checkbox(name, opts = {}, default = true, force_checked = false)
  options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => 1}
  options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "1") or (obj[name].nil? and default)

  @forms.tag("input", options.merge(opts), false, false)
end

#checkboxes_for_oai_sets(set_json, value_list) ⇒ Object

takes a JSON representation of the current options selected and the list of archival_record_level enums returns HTML for a set of checkboxes representing current selected and deselected sets for OAI export



568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
# File 'frontend/app/helpers/aspace_form_helper.rb', line 568

def checkboxes_for_oai_sets(set_json, value_list)
  return "" if value_list == nil
  # when called by #new, set_json will be nil.
  if set_json
    set_arry = JSON::parse(set_json)
  else
    set_arry = []
  end

  html = ""

  html << "<div class='form-group'>"
  html << label("oai_sets_available", {}, ["control-label", "col-sm-2"])
  html << "<div class='col-sm-9'>"
  html << "<ul class='checkbox-list'>"
  value_list['enumeration_values'].each do |v|
    # if we have an empty list of checkboxes, assume all sets are enabled.
    # otherwise, a checkbox is on if it's the in the list we get from the backend.
    checked = set_arry.include?(v['id'].to_s) || set_arry.length == 0

    html << "<li class='list-group-item'>"
    html << "<div class='checkbox'>"
    html << "<label>"
    html << "<input id=\"#{v['id']}\" name=\"sets[#{v['id']}]\" type=\"checkbox\" "
    if checked
      html << "checked=\"checked\" "
    end

    if readonly?
      html << "disabled />"
    else
      html << "/>"
    end # of checkbox tag

    html << "#{v['value']}"
    html << "</label>"
    html << "</div>"
    html << "</li>"
  end
  html << "</ul>"
  html << "</div>" #col-sm-9
  html << "</div>" #form-group

  return html.html_safe
end

#clean_mixed_content(content, root_url) ⇒ Object



30
31
32
33
34
35
# File 'frontend/app/helpers/aspace_form_helper.rb', line 30

def clean_mixed_content(content, root_url)
  content = content.to_s
  return content if content.blank?

  MixedContentParser::parse(content, root_url, { :wrap_blocks => false } ).to_s.html_safe
end

#combobox(name, options, opts = {}) ⇒ Object



404
405
406
407
# File 'frontend/app/helpers/aspace_form_helper.rb', line 404

def combobox(name, options, opts = {})
  select(name, options, opts.merge({ :"data-combobox" => true,
                                     :id => id_for(name) }))
end

#current_contextObject



208
209
210
# File 'frontend/app/helpers/aspace_form_helper.rb', line 208

def current_context
  @context.last
end

#current_idObject



255
256
257
# File 'frontend/app/helpers/aspace_form_helper.rb', line 255

def current_id
  path(nil).gsub(/[\[\]]/, '_')
end

#custom_report_template_limit_optionsObject



1321
1322
1323
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1321

def custom_report_template_limit_options
  [100, 500, 1000, 5000, 10000, 50000]
end

#default_for(name) ⇒ Object



698
699
700
701
702
703
704
# File 'frontend/app/helpers/aspace_form_helper.rb', line 698

def default_for(name)
  if @active_template && @parent.templates[@active_template]
    @parent.templates[@active_template][:definition].default_for(name)
  else
    nil
  end
end

#define_template(name, definition = nil, &block) ⇒ Object



1149
1150
1151
1152
1153
1154
1155
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1149

def define_template(name, definition = nil, &block)
  @templates ||= {}
  @templates[name] = {
    :block => block,
    :definition => (definition || BaseDefinition.new),
  }
end

#emit_template(name, *args) ⇒ Object



501
502
503
504
505
506
507
508
509
510
# File 'frontend/app/helpers/aspace_form_helper.rb', line 501

def emit_template(name, *args)
  if !@parent.templates[name]
    raise "No such template: #{name.inspect}"
  end

  old = @active_template
  @active_template = name
  @parent.templates[name][:block].call(self, *args)
  @active_template = old
end

#error_params(exceptions) ⇒ Object



1299
1300
1301
1302
1303
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1299

def error_params(exceptions)
  {
    :"data-form-errors" => (exceptions && exceptions.keys[0])
  }
end

#exceptions_for_js(exceptions) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
# File 'frontend/app/helpers/aspace_form_helper.rb', line 236

def exceptions_for_js(exceptions)
  result = {}
  [:errors, :warnings].each do |condition|
    if exceptions[condition]
      result[condition] = exceptions[condition].keys.map {|property|
        id_for_javascript(property)
      }
    end
  end

  result.to_json.html_safe
end

#fields_for(object, context_name, &block) ⇒ Object

renders a single template containing form elements.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'frontend/app/helpers/aspace_form_helper.rb', line 141

def fields_for(object, context_name, &block)
  result = ""

  push(context_name, object) do
    result << hidden_input("lock_version", object["lock_version"]) if object
    result << @parent.capture(object, &block)
  end

  extra_classes = ""

  # ANW-429: Add class to top level div so element can be switched out by JS based on user form input
  # TODO: refactor
  extra_classes += "sdl-subrecord-form" if context_name == "structured_date_range" || context_name == "structured_date_single"


  ("<div data-name-path=\"#{set_index(self.path(context_name), '${index}')}\" " +
    " data-id-path=\"#{id_for(set_index(self.path(context_name), '${index}'), false)}\" " +
    " class=\"subrecord-form-fields-for #{extra_classes}\">#{result}</div>").html_safe
end

#form_context(name, values_from = {}, &body) ⇒ Object



984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
# File 'frontend/app/helpers/aspace_form_helper.rb', line 984

def form_context(name, values_from = {}, &body)
  context = FormContext.new(name, values_from, self)

  env = self.request.env
  env['form_context_depth'] ||= 0

  s = "<div class=\"form-context\" id=\"form_#{name}\">".html_safe
  s << context.hidden_input("lock_version", values_from["lock_version"])

  env['form_context_depth'] += 1
  s << capture(context, &body)
  env['form_context_depth'] -= 1

  if env['form_context_depth'] == 0
    # Only emit the JS templates at the top-level
    s << templates_for_js(values_from["jsonmodel_type"])
  end
  s << "</div>".html_safe

  s
rescue
  Rails.logger.error("Failure generating templates for JS: #{$!}")
  Rails.logger.error("Stacktrace:\n%s" % [$@.join("\n")])

  raise $!
end

#form_topObject



162
163
164
# File 'frontend/app/helpers/aspace_form_helper.rb', line 162

def form_top
  @context[0].first
end

#h(str) ⇒ Object



25
26
27
# File 'frontend/app/helpers/aspace_form_helper.rb', line 25

def h(str)
  ERB::Util.html_escape(str)
end

#help_path_for(name) ⇒ Object



196
197
198
199
200
# File 'frontend/app/helpers/aspace_form_helper.rb', line 196

def help_path_for(name)
  names = @context.map(&:first)
  return "#{names[-1].to_s.gsub(/\[.*\]/, "").singularize}_#{name}" if names.length > 0
  name
end

#hidden_input(name, value = nil, field_opts = {}) ⇒ Object



487
488
489
490
491
492
493
494
495
496
497
498
499
# File 'frontend/app/helpers/aspace_form_helper.rb', line 487

def hidden_input(name, value = nil, field_opts = {})
  value = obj[name] if value.nil?

  full_name = path(name)

  if value && value.is_a?(Hash) && value.has_key?('ref')
    full_name += '[ref]'
    value = value['ref']
  end

  @forms.tag("input", {:id => id_for(name), :type => "hidden", :value => h(value), :name => full_name}.merge(field_opts),
             false, false)
end

#i18n_for(name) ⇒ Object



231
232
233
# File 'frontend/app/helpers/aspace_form_helper.rb', line 231

def i18n_for(name)
  "#{@active_template or form_top}.#{name.to_s.gsub(/\[\]$/, "")}"
end

#idObject



167
168
169
# File 'frontend/app/helpers/aspace_form_helper.rb', line 167

def id
  "form_#{form_top}"
end

#id_for(name, qualify = true) ⇒ Object



259
260
261
262
263
# File 'frontend/app/helpers/aspace_form_helper.rb', line 259

def id_for(name, qualify = true)
  name = path(name) if qualify

  name.gsub(/[\[\]]/, '_')
end

#id_for_javascript(name) ⇒ Object



250
251
252
# File 'frontend/app/helpers/aspace_form_helper.rb', line 250

def id_for_javascript(name)
  "#{form_top}#{name.split("/").collect {|a| "[#{a}]"}.join}".gsub(/[\[\]\/]/, "_")
end

#is_required_by_admin?(required_values, record_name, field_name) ⇒ Boolean

ANW-429: returns true if an admin has specified field_name as a custom require in record_name. This code is run inside the templates to ensure that these fields are required no matter how many copies of record_name are added to a form. required_values is generally queried from the DB once in the controller, and then passed in here from the view preventing multiple queries.

Returns:

  • (Boolean)


1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1308

def is_required_by_admin?(required_values, record_name, field_name)
  return false if required_values == [] || required_values.nil? || required_values[record_name].nil?

  # need to call #first because it's possible to specify requires for multiple subrecords, so required_values[record_name] contains an array of hashes.
  required_list_for_record = required_values[record_name].first

  if required_list_for_record
    required_list_for_record[field_name] == "REQ"
  else
    false
  end
end

#jsonmodel_definition(type, root = nil) ⇒ Object



1025
1026
1027
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1025

def jsonmodel_definition(type, root = nil)
  JSONModelDefinition.new(JSONModel(type), root)
end

#label(name, opts = {}, classes = []) ⇒ Object



522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
# File 'frontend/app/helpers/aspace_form_helper.rb', line 522

def label(name, opts = {}, classes = [])
  prefix = ''
  prefix << "#{opts[:contextual]}." if opts[:contextual]
  prefix << 'plugins.' if opts[:plugin]

  classes << 'control-label'

  options = {:class => classes.join(' '), :for => id_for(name)}

  unless (tooltip = tooltip(name, prefix)).empty?
    add_tooltip_options(tooltip, options)
  end

  attr_string = options.merge(opts || {})
                  .map {|k, v| '%s="%s"' % [CGI::escapeHTML(k.to_s),
                                            CGI::escapeHTML(v.to_s)]}
                  .join(' ')
  content = CGI::escapeHTML(I18n.t(prefix + i18n_for(name)))
  "<label #{attr_string}>#{content}</label>".html_safe
end

#label_and_boolean(name, opts = {}, default = false, force_checked = false) ⇒ Object



326
327
328
329
330
# File 'frontend/app/helpers/aspace_form_helper.rb', line 326

def label_and_boolean(name, opts = {}, default = false, force_checked = false)
  opts[:col_size] = 1
  opts[:controls_class] = "checkbox"
  label_with_field(name, checkbox(name, opts, default, force_checked), opts)
end

#label_and_date(name, opts = {}) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'frontend/app/helpers/aspace_form_helper.rb', line 269

def label_and_date(name, opts = {})
  field_opts = (opts[:field_opts] || {}).merge({
      :class => "date-field form-control",
      :"data-format" => "yyyy-mm-dd",
      :"data-date" => Date.today.strftime('%Y-%m-%d'),
      :"data-autoclose" => true,
      :"data-force-parse" => false,
      :"data-label" => I18n.t("actions.date_picker")
  })

  if obj[name].blank? && opts[:default]
    value = opts[:default]
  else
    value = obj[name]
  end

  opts[:col_size] = 4

  date_input = textfield(name, value, field_opts)

  label_with_field(name, date_input, opts)
end

#label_and_disabled_checkbox(name) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'frontend/app/helpers/aspace_form_helper.rb', line 292

def label_and_disabled_checkbox(name)
  html = ""

  html << "<div class='form-group'>"

  html << "<label class='col-sm-2 control-label'>#{name}</label>"
  html << "<div class='col-sm-1'>"
  html << "<input type='checkbox' name='disabled' disabled>"
  html << "</div>"
  html << "</div>"

  return html.html_safe
end

#label_and_fourpartidObject



512
513
514
515
516
517
518
519
# File 'frontend/app/helpers/aspace_form_helper.rb', line 512

def label_and_fourpartid
  field_html =  textfield("id_0", obj["id_0"], :class => "id_0 form-control", :size => 10)
  field_html << textfield("id_1", obj["id_1"], :class => "id_1 form-control", :size => 10, :disabled => obj["id_0"].blank? && obj["id_1"].blank?, :'aria-label' => "id_1")
  field_html << textfield("id_2", obj["id_2"], :class => "id_2 form-control", :size => 10, :disabled => obj["id_1"].blank? && obj["id_2"].blank?, :'aria-label' => "id_2")
  field_html << textfield("id_3", obj["id_3"], :class => "id_3 form-control", :size => 10, :disabled => obj["id_2"].blank? && obj["id_3"].blank?, :'aria-label' => "id_3")
  @forms.(:div, (I18n.t(i18n_for("id_0")) + field_html).html_safe, :class=> "identifier-fields")
  label_with_field("id_0", field_html, :control_class => "identifier-fields")
end

#label_and_merge_select(name, default = "", opts = {}) ⇒ Object



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'frontend/app/helpers/aspace_form_helper.rb', line 364

def label_and_merge_select(name, default = "", opts = {})
  value = obj[name]
  begin
    jsonmodel_type = obj["jsonmodel_type"]
    prefix = opts[:plugin] ? 'plugins.' : ''
    schema = JSONModel(jsonmodel_type).schema
    if (schema["properties"][name].has_key?('dynamic_enum'))
      value = I18n.t({:enumeration => schema["properties"][name]["dynamic_enum"], :value => value}, :default => value)
    elsif schema["properties"][name].has_key?("enum")
      value = I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}_#{value}", :default => value)
    end
  rescue
  end
  if opts.has_key? :controls_class
    opts[:controls_class] << " label-only"
  else
    opts[:controls_class] = " label-only"
  end
  if value.blank?
    label_with_field(name, value.blank? ? default : value , opts)
  else
    label_with_field(name, merge_select(name, value, opts), opts)
  end
end

#label_and_password(name, opts = {}) ⇒ Object



321
322
323
# File 'frontend/app/helpers/aspace_form_helper.rb', line 321

def label_and_password(name, opts = {})
  label_with_field(name, password(name, obj[name], opts[:field_opts] || {}), opts)
end

#label_and_readonly(name, default = "", opts = {}) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'frontend/app/helpers/aspace_form_helper.rb', line 338

def label_and_readonly(name, default = "", opts = {})
  value = obj[name]
  if !(value.is_a? String)
    value = value.to_s
  end

  begin
    jsonmodel_type = obj["jsonmodel_type"]
    prefix = opts[:plugin] ? 'plugins.' : ''
    schema = JSONModel(jsonmodel_type).schema
    if (schema["properties"][name].has_key?('dynamic_enum'))
      value = I18n.t({:enumeration => schema["properties"][name]["dynamic_enum"], :value => value}, :default => value)
    elsif schema["properties"][name].has_key?("enum")
      value = I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}_#{value}", :default => value)
    end
  rescue
  end
  if opts.has_key? :controls_class
    opts[:controls_class] << " label-only"
  else
    opts[:controls_class] = " label-only"
  end

  label_with_field(name, value.blank? ? default : value , opts)
end

#label_and_req_boolean(name, opts = {}, default = false, force_checked = false) ⇒ Object



332
333
334
335
336
# File 'frontend/app/helpers/aspace_form_helper.rb', line 332

def label_and_req_boolean(name, opts = {}, default = false, force_checked = false)
  opts[:col_size] = 1
  opts[:controls_class] = "req_checkbox"
  label_with_field(name, req_checkbox(name, opts, default, force_checked), opts)
end

#label_and_select(name, options, opts = {}) ⇒ Object



311
312
313
314
315
316
317
318
# File 'frontend/app/helpers/aspace_form_helper.rb', line 311

def label_and_select(name, options, opts = {})
  options = ([""] + options) if opts[:nodefault]
  opts[:field_opts] ||= {}

  opts[:col_size] = 9
  widget = options.length < COMBOBOX_MIN_LIMIT ? select(name, options, opts[:field_opts] || {}) : combobox(name, options, opts[:field_opts] || {})
  label_with_field(name, widget, opts)
end

#label_and_textarea(name, opts = {}) ⇒ Object



306
307
308
# File 'frontend/app/helpers/aspace_form_helper.rb', line 306

def label_and_textarea(name, opts = {})
  label_with_field(name, textarea(name, obj[name] || opts[:default], opts[:field_opts] || {}), opts)
end

#label_and_textfield(name, opts = {}) ⇒ Object



265
266
267
# File 'frontend/app/helpers/aspace_form_helper.rb', line 265

def label_and_textfield(name, opts = {})
  label_with_field(name, textfield(name, obj[name], opts[:field_opts] || {}), opts)
end

#label_with_field(name, field_html, opts = {}) ⇒ Object



725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
# File 'frontend/app/helpers/aspace_form_helper.rb', line 725

def label_with_field(name, field_html, opts = {})
  opts[:label_opts] ||= {}
  opts[:label_opts][:plugin] = opts[:plugin]
  opts[:col_size] ||= 9

  control_group_classes,
  label_classes,
  controls_classes = %w(form-group), [], []

  unless opts[:layout] && opts[:layout] == 'stacked'
    label_classes << "col-sm-#{opts[:label_opts].fetch(:col_size, 2)}"
    controls_classes << "col-sm-#{opts[:col_size]}"
  end
  # There must be a better way to say this...
  # The value of the 'required' option wins out if set to either true or false
  # if not specified, we take the value of required?
  required = [:required, 'required'].map {|r| opts[r]}.compact.first
  if required.nil?
    required = required?(name)
  end

  control_group_classes << "required" if required == true
  control_group_classes << "required" if obj[name].is_a? String and obj[name].end_with?("REQ")
  control_group_classes << "conditionally-required" if required == :conditionally

  control_group_classes << "#{opts[:control_class]}" if opts.has_key? :control_class

  #TODO: refactor this. We don't need a separate method for each extra special class to be added below. Probably the thing to is to use the opts param.
  # ANW-617: add JS classes to slug fields
  control_group_classes << "js-slug_textfield" if name == "slug"
  control_group_classes << "js-slug_auto_checkbox" if name == "is_slug_auto"

  # ANW-429: add JS classes to structured date fields
  control_group_classes << "js-structured_date_select" if name == "date_type_structured"


  controls_classes << "#{opts[:controls_class]}" if opts.has_key? :controls_class

  control_group = "<div class=\"#{control_group_classes.join(' ')}\">"
  control_group << label(name, opts[:label_opts], label_classes)
  control_group << "<div class=\"#{controls_classes.join(' ')}\">"
  control_group << field_html
  control_group << "</div>"
  control_group << "</div>"

  # ANW-429
  # TODO: Refactor to the JS files, ideally so this is run when the "Add Date" button is clicked. This is a tricky one since the select field this JS needs to be run on doesn't exist until the callbacks that run after the button is clicked run. Putting it here means that it runs as part of the html, and is always included in the right context.
  control_group << "<script>selectStructuredDateSubform();</script>" if name == "date_type_structured"

  control_group.html_safe
end

#list_for(objects, context_name, &block) ⇒ Object

renders a list of form element sets from a template. Each item will be re-orderable. Objects should be an array.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'frontend/app/helpers/aspace_form_helper.rb', line 121

def list_for(objects, context_name, &block)
  objects ||= []
  result = ""

  objects.each_with_index do |object, idx|
    push(set_index(context_name, idx), object) do
      result << "<li id=\"#{current_id}\" class=\"subrecord-form-wrapper\" data-index=\"#{idx}\" data-object-name=\"#{context_name.gsub(/\[\]/, "").singularize}\">"
      result << hidden_input("lock_version") if obj.respond_to?(:has_key?) && obj.has_key?("lock_version")
      result << @parent.capture(object, idx, &block)
      result << "</li>"
    end
  end

  ("<ul data-name-path=\"#{set_index(self.path(context_name), '${index}')}\" " +
   " data-id-path=\"#{id_for(set_index(self.path(context_name), '${index}'), false)}\" " +
   " class=\"subrecord-form-list\">#{result}</ul>").html_safe
end

#merge_checkbox(name, opts = {}, default = false, force_checked = false) ⇒ Object



674
675
676
677
678
679
# File 'frontend/app/helpers/aspace_form_helper.rb', line 674

def merge_checkbox(name, opts = {}, default = false, force_checked = false)
  options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => "REPLACE"}
  options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "REPLACE") or (obj[name].nil? and default)

  @forms.tag("input", options.merge(opts), false, false)
end

#merge_select(name, value, opts) ⇒ Object

ANW-429: Modified this method so that a disable_replace can be passed in, which will skip the creation of the “replace” checkboxes. This can be used to not render them in case a replace in inappropriate, e.g., the target record has nothing to replace with.



391
392
393
394
395
396
397
398
399
400
401
402
# File 'frontend/app/helpers/aspace_form_helper.rb', line 391

def merge_select(name, value, opts)
  unless opts[:disable_replace] == true
    value += "<label class='subreplace-control'>".html_safe
    value += merge_checkbox("#{name}", {
      :class => "merge-toggle"}, false, false)
    value += "&#160;<small>".html_safe
    value += I18n.t("actions.merge_replace")
    value += "</small></label>".html_safe
  else
    value += ""
  end
end

#merge_victim_view(hash, opts = {}) ⇒ Object



883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
# File 'frontend/app/helpers/aspace_form_helper.rb', line 883

def merge_victim_view(hash, opts = {})
  jsonmodel_type = hash["jsonmodel_type"]
  schema = JSONModel(jsonmodel_type).schema
  prefix = opts[:plugin] ? 'plugins.' : ''
  html = "<div class='form-horizontal'>"

  hash.reject {|k, v| PROPERTIES_TO_EXCLUDE_FROM_READ_ONLY_VIEW.include?(k)}.each do |property, value|
    if schema and schema["properties"].has_key?(property)
      if (schema["properties"][property].has_key?('dynamic_enum'))
        value = I18n.t({:enumeration => schema["properties"][property]["dynamic_enum"], :value => value}, :default => value)
      elsif schema["properties"][property].has_key?("enum")
        value = I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}_#{value}", :default => value)
      elsif schema["properties"][property]["type"] === "boolean"
        value = value === true ? "True" : "False"
      elsif schema["properties"][property]["type"] === "date"
        value = value.blank? ? "" : Date.strptime(value, "%Y-%m-%d")
      elsif schema["properties"][property]["type"] === "array"
        # this view doesn't support arrays
        next
      elsif value.is_a? Hash
        # can't display an object either
        next
      end
    end
    html << "<div class='form-group'>"
    html << "<div class='control-label col-sm-2'>#{I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}")}</div>"
    html << "<div class='label-only col-sm-8'>#{value}</div>"
    html << "</div>"
  end
  html << "</div>"
  html.html_safe
end

#name_to_json_path(name) ⇒ Object

Turn a name like my[nested][object][0][title] into the equivalent JSON path (my/nested/object/0/title)



174
175
176
# File 'frontend/app/helpers/aspace_form_helper.rb', line 174

def name_to_json_path(name)
  name.gsub(/[\[\]]+/, "/").gsub(/\/+$/, "").gsub(/^\/+/, "")
end

#notes_preview(notes_index = "notes", content_index = "content") ⇒ Object

ANW-429 Generates HTML for a very stripped down summary of a note for use in the agents merge preview. TODO: Eventually we’ll want to use the notes partials in place of this code. This code was created because the current notes show takes up a lot of space, and work needs to be done to figure out the exact setup/context needed to get those views to render properly. T



781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
# File 'frontend/app/helpers/aspace_form_helper.rb', line 781

def notes_preview(notes_index = "notes", content_index = "content")
   = I18n.t("note._frontend.preview.content")
  html = ""

  if obj[notes_index] && obj[notes_index].length > 0

    html << "<div class='subrecord-form-container'>"
    html << "<h4 class='subrecord-form-heading'>#{I18n.t("subsections.notes")}</h4>"

    obj[notes_index].each_with_index do |o, i|
      notes_heading = I18n.t("note.#{o['jsonmodel_type'].to_s}")

      if o[content_index].is_a?(Array)
        notes_content = o[content_index].join(" : ")
      else
        notes_content = o[content_index]
      end

      html << "<section>"
      html << "<h5>#{notes_heading}</h5>"
      html << "<div class='panel panel-default'>"
      html << "<div class=\"form-group\">"
      html << "<label class='control-label col-sm-2'>#{content_label}</label>"
      html << "<div class='col-sm-9 label-only'>"
      html << "#{notes_content}"
      html << "</div>"
      html << "</div>"
      html << "</div>"
      html << "</section>"
    end

    html << "</div>"

    html.html_safe

  end
end

#notes_preview_single(obj) ⇒ Object

Same as above, but intended for use with an agents top level notes record instead of a subrecord, in the merge selector form. Needed because emitting templates as usual breaks the merge selector interface



821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# File 'frontend/app/helpers/aspace_form_helper.rb', line 821

def notes_preview_single(obj)
   = I18n.t("note._frontend.preview.content")
  html = ""

  notes_content = ""

  obj['subnotes'].each do |subnote|
    if subnote['jsonmodel_type'] == "note_text"
      notes_content << subnote["content"] if subnote["content"]
    end
  end

  html << "<br />"
  html << "<section>"
  html << "<div class='panel panel-default'>"
  html << "<div class=\"form-group\">"
  html << "<label class='control-label col-sm-2'>#{content_label}</label>"
  html << "<div class='col-sm-9 label-only'>"
  html << "#{notes_content}"
  html << "</div>"
  html << "</div>"
  html << "</div>"
  html << "</section>"

  html.html_safe
end

#oai_config_repo_set_codes_field(set_json, repositories) ⇒ Object



614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# File 'frontend/app/helpers/aspace_form_helper.rb', line 614

def oai_config_repo_set_codes_field(set_json, repositories)
  #label_and_textfield(name, opts)
  set_arry = JSON::parse(set_json)

  html = ""

  html << "<div class='form-group'>"
  html << label("repo_set_section", {}, ["control-label", "col-sm-2"])
  html << "<div class='col-sm-9'>"
  html << "<ul class='checkbox-list'>"
  repositories.each do |r|
    # a checkbox is on if it's the in the list we get from the backend.
    checked = set_arry.include?(r['repo_code'].to_s)

    html << "<li class='list-group-item'>"
    html << "<div class='checkbox'>"
    html << "<label>"
    html << "<input id=\"#{r['repo_code']}\" name=\"repo_set_codes[#{r['repo_code']}]\" type=\"checkbox\" "
    if checked
      html << "checked=\"checked\" "
    end

    html << "/>"

    html << "#{r['repo_code']}"
    html << "</label>"
    html << "</div>"
    html << "</li>"
  end
  html << "</ul>"
  html << "</div>" #col-sm-9
  html << "</div>" #form-group

  return html.html_safe
end

#oai_config_sponsor_set_names_field(set_json, opts = {}) ⇒ Object



650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
# File 'frontend/app/helpers/aspace_form_helper.rb', line 650

def oai_config_sponsor_set_names_field(set_json, opts = {})
  # turn array from DB into a comma delimited list for UI
  set_arry = JSON::parse(set_json)
  value = set_arry.join("|")

  html = ""

  html << "<div class='form-group'>"
  html << label("sponsor_set_names", {}, ["control-label", "col-sm-2"])
  html << "<div class='col-sm-9'>"
  html << "<input id='oai_config_sponsor_set_names_' type='text' value='#{value}' name='oai_config[sponsor_set_names]' class='form-control js-taggable' datarole='tagsinput'>"
  html << "</div>"
  html << "</div>"

  return html.html_safe
end

#objObject



213
214
215
# File 'frontend/app/helpers/aspace_form_helper.rb', line 213

def obj
  @context.last.second
end

#parent_contextObject



203
204
205
# File 'frontend/app/helpers/aspace_form_helper.rb', line 203

def parent_context
  form_top
end

#password(name = nil, value = "", opts = {}) ⇒ Object



482
483
484
485
# File 'frontend/app/helpers/aspace_form_helper.rb', line 482

def password(name = nil, value = "", opts = {})
  @forms.tag("input", {:id => id_for(name), :type => "password", :value => h(value), :name => path(name)}.merge(opts),
             false, false)
end

#path(name = nil) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'frontend/app/helpers/aspace_form_helper.rb', line 179

def path(name = nil)
  names = @context.map(&:first)
  tail = names.drop(1)
  tail += [name] if name

  path = tail.map {|e|
    if e =~ /(.*?)\[([0-9]+)?\]$/
      "[#{$1}][#{$2}]"
    else
      "[#{e}]"
    end
  }.join("")

  "#{names.first}#{path}"
end

#possible_options_for(name, add_empty_options = false, opts = {}) ⇒ Object



716
717
718
719
720
721
722
# File 'frontend/app/helpers/aspace_form_helper.rb', line 716

def possible_options_for(name, add_empty_options = false, opts = {})
  if @active_template && @parent.templates[@active_template]
    @parent.templates[@active_template][:definition].options_for(self, name, add_empty_options, opts)
  else
    []
  end
end

#preserve_newlines(string) ⇒ Object



1283
1284
1285
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1283

def preserve_newlines(string)
  string.gsub(/\n/, '<br>')
end

#push(name, values_from = {}) {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



223
224
225
226
227
228
# File 'frontend/app/helpers/aspace_form_helper.rb', line 223

def push(name, values_from = {})
  path(name) # populate the i18n mapping
  @context.push([name, values_from])
  yield(self)
  @context.pop
end

#radio(name, value, opts = {}) ⇒ Object



681
682
683
684
685
686
# File 'frontend/app/helpers/aspace_form_helper.rb', line 681

def radio(name, value, opts = {})
  options = {:id => "#{id_for(name)}", :type => "radio", :name => path(name), :value => value}
  options[:checked] = "checked" if obj[name] == value

  @forms.tag("input", options.merge(opts), false, false)
end

#read_only_view(hash, opts = {}) ⇒ Object



1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1234

def read_only_view(hash, opts = {})
  jsonmodel_type = hash["jsonmodel_type"]
  schema = JSONModel(jsonmodel_type).schema
  prefix = opts[:plugin] ? 'plugins.' : ''
  html = "<div class='form-horizontal'>"

  # in some cases, we want to not display certain fields for some records, but not for others.
  # e.g., we don't want to display published for subjects (they are always published), but we do for other records types.
  if opts[:exclude]
    props_to_exclude = PROPERTIES_TO_EXCLUDE_FROM_READ_ONLY_VIEW + opts[:exclude]
  else
    props_to_exclude = PROPERTIES_TO_EXCLUDE_FROM_READ_ONLY_VIEW

  end

  hash.reject {|k, v| props_to_exclude.include?(k)}.each do |property, value|

    if schema and schema["properties"].has_key?(property)
      if (schema["properties"][property].has_key?('dynamic_enum'))
        value = I18n.t({:enumeration => schema["properties"][property]["dynamic_enum"], :value => value}, :default => value)
      elsif schema["properties"][property].has_key?("enum")
        value = I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}_#{value}", :default => value)
      elsif schema["properties"][property]["type"] === "boolean"
        value = value === true ? "True" : "False"
      elsif schema["properties"][property]["type"] === "date"
        value = value.blank? ? "" : Date.strptime(value, "%Y-%m-%d")
      elsif schema["properties"][property]["type"] === "integer"
        value = value.blank? ? "" : value.to_s
      elsif schema["properties"][property]["type"] === "array"
        # this view doesn't support arrays
        next
      elsif value.is_a? Hash
        # can't display an object either
        next
      end
    end

    html << "<div class='form-group'>"
    html << "<div class='control-label col-sm-2'>#{I18n.t("#{prefix}#{jsonmodel_type.to_s}.#{property}")}</div>"
    html << "<div class='label-only col-sm-8'>#{value}</div>"
    html << "</div>"

  end

  html << "</div>"

  html.html_safe
end

#readonly?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'frontend/app/helpers/aspace_form_helper.rb', line 38

def readonly?
  false
end

#readonly_context(name, values_from = {}, &body) ⇒ Object



1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1217

def readonly_context(name, values_from = {}, &body)
  context = ReadOnlyContext.new(name, values_from, self)

  # Not feeling great about this, but we render the form twice: the first pass
  # sets up the mapping from form input names to i18n keys, while the second
  # actually uses that map to set the labels correctly.
  capture(context, &body)

  s = "<div class=\"readonly-context form-horizontal\">".html_safe
  s << capture(context, &body)
  s << "</div>".html_safe

  s
end

#record_level_merge_controls(form, name = "undefined", controls = true, replace = true, append = true) ⇒ Object

ANW-429 outputs HTML for checkboxes for record-level add and replace for agents merge



850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
# File 'frontend/app/helpers/aspace_form_helper.rb', line 850

def record_level_merge_controls(form, name = "undefined", controls = true, replace = true, append = true)
  html = ""

  html << '<h4 class="subrecord-form-heading">'
  html << I18n.t("#{name}._singular").to_s

  if controls
    if replace
      html << '<label class="replace-control">'
      html << form.merge_checkbox('replace')
      html << '<small>'
      html << I18n.t("actions.merge_replace").to_s
      html << '</small>'
      html << '</label>'
    end

    if append
      html << '<label class="append-control">'
      html << form.merge_checkbox('append')
      html << '<small>'
      html << I18n.t("actions.merge_add").to_s
      html << '</small>'
      html << '</label>'
    end
  end

  html << '</h4>'

  return html.html_safe
end

#req_checkbox(name, opts = {}, default = true, force_checked = false) ⇒ Object



667
668
669
670
671
672
# File 'frontend/app/helpers/aspace_form_helper.rb', line 667

def req_checkbox(name, opts = {}, default = true, force_checked = false)
  options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => "REQ"}
  options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "REQ") or (obj[name].nil? and default)

  @forms.tag("input", options.merge(opts), false, false)
end

#required?(name) ⇒ Boolean

Returns:

  • (Boolean)


689
690
691
692
693
694
695
# File 'frontend/app/helpers/aspace_form_helper.rb', line 689

def required?(name)
  if @active_template && @parent.templates[@active_template]
    @parent.templates[@active_template][:definition].required?(name)
  else
    false
  end
end

#select(name, options, opts = {}) ⇒ Object



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
# File 'frontend/app/helpers/aspace_form_helper.rb', line 410

def select(name, options, opts = {})
    if opts.has_key? :class
      opts[:class] << " form-control"
    else
      opts[:class] = "form-control"
    end
    if opts.has_key? :"data-combobox"
      opts[:role] = "listbox"
      opts[:"aria-label"] = I18n.t(i18n_for(name))
    end
    selection = obj[name]
    selection = selection[0...-4] if selection.is_a? String and selection.end_with?("_REQ")
    @forms.select_tag(path(name), @forms.options_for_select(options, selection || default_for(name) || opts[:default]), {:id => id_for(name)}.merge!(opts))
  end

  def textarea(name = nil, value = "", opts = {})
    value = value[0...-4] if value.is_a? String and value.end_with?("_REQ")
    value = nil if value === "REQ"
    options = {:id => id_for(name), :rows => 3}

    placeholder = I18n.t("#{i18n_for(name)}_placeholder", :default => '')
    options[:placeholder] = placeholder if not placeholder.empty?
    options[:class] = "form-control"

    @forms.text_area_tag(path(name), h(value), options.merge(opts))
  end

  def textarea_ro(name = nil, value = "", opts = {})
    return "" if value.blank?
    opts[:escape] = true unless opts[:escape] == false
    opts[:base_url] ||= "/"
    value = clean_mixed_content(value, opts[:base_url]) if opts[:clean] == true
    value = @parent.preserve_newlines(value) if opts[:clean] == true
    value = CGI::escapeHTML(value) if opts[:escape]
    value.html_safe
  end

  def textfield(name = nil, value = nil, opts = {})
    value ||= obj[name] if !name.nil?

    value = value[0...-4] if value.is_a? String and value.end_with?("_REQ")
    value = nil if value === "REQ"

    options = {:id => id_for(name), :type => "text", :value => h(value), :name => path(name)}

    placeholder = I18n.t("#{i18n_for(name)}_placeholder", :default => '')
    options[:placeholder] = placeholder if not placeholder.empty?
    options[:class] = "form-control"

    value = @forms.tag("input", options.merge(opts),
               false, false)

    if opts[:automatable]
      by_default = default_for("#{name}_auto_generate") || false
      value << "<label>".html_safe
      value << checkbox("#{name}_auto_generate", {
        :class => "automate-field-toggle", :display_text_when_checked => I18n.t("states.auto_generated")
        }, by_default, false)
      value << "&#160;<small>".html_safe
      value << I18n.t("actions.automate")
      value << "</small></label>".html_safe
    end

    inline_help = I18n.t("#{i18n_for(name)}_inline_help", :default => '')
    if !inline_help.empty?
      value << "<span class=\"help-inline\">#{inline_help}</span>".html_safe
    end

    value
  end


  def password(name = nil, value = "", opts = {})
    @forms.tag("input", {:id => id_for(name), :type => "password", :value => h(value), :name => path(name)}.merge(opts),
               false, false)
  end

  def hidden_input(name, value = nil, field_opts = {})
    value = obj[name] if value.nil?

    full_name = path(name)

    if value && value.is_a?(Hash) && value.has_key?('ref')
      full_name += '[ref]'
      value = value['ref']
    end

    @forms.tag("input", {:id => id_for(name), :type => "hidden", :value => h(value), :name => full_name}.merge(field_opts),
               false, false)
  end

  def emit_template(name, *args)
    if !@parent.templates[name]
      raise "No such template: #{name.inspect}"
    end

    old = @active_template
    @active_template = name
    @parent.templates[name][:block].call(self, *args)
    @active_template = old
  end

  def label_and_fourpartid
    field_html =  textfield("id_0", obj["id_0"], :class => "id_0 form-control", :size => 10)
    field_html << textfield("id_1", obj["id_1"], :class => "id_1 form-control", :size => 10, :disabled => obj["id_0"].blank? && obj["id_1"].blank?, :'aria-label' => "id_1")
    field_html << textfield("id_2", obj["id_2"], :class => "id_2 form-control", :size => 10, :disabled => obj["id_1"].blank? && obj["id_2"].blank?, :'aria-label' => "id_2")
    field_html << textfield("id_3", obj["id_3"], :class => "id_3 form-control", :size => 10, :disabled => obj["id_2"].blank? && obj["id_3"].blank?, :'aria-label' => "id_3")
    @forms.(:div, (I18n.t(i18n_for("id_0")) + field_html).html_safe, :class=> "identifier-fields")
    label_with_field("id_0", field_html, :control_class => "identifier-fields")
  end


  def label(name, opts = {}, classes = [])
    prefix = ''
    prefix << "#{opts[:contextual]}." if opts[:contextual]
    prefix << 'plugins.' if opts[:plugin]

    classes << 'control-label'

    options = {:class => classes.join(' '), :for => id_for(name)}

    unless (tooltip = tooltip(name, prefix)).empty?
      add_tooltip_options(tooltip, options)
    end

    attr_string = options.merge(opts || {})
                    .map {|k, v| '%s="%s"' % [CGI::escapeHTML(k.to_s),
                                              CGI::escapeHTML(v.to_s)]}
                    .join(' ')
    content = CGI::escapeHTML(I18n.t(prefix + i18n_for(name)))
    "<label #{attr_string}>#{content}</label>".html_safe
  end

  def add_tooltip_options(tooltip, options)
    options[:title] = tooltip
    options['data-placement'] = 'bottom'
    options['data-html'] = true
    options['data-delay'] = 500
    options['data-trigger'] = 'manual'
    options['data-template'] = '<div class="tooltip archivesspace-help"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
    options[:class] ||= ''
    options[:class] += ' has-tooltip'
    options
  end

  def tooltip(name, prefix = '')
    I18n.t_raw("#{prefix}#{i18n_for(name)}_tooltip", :default => '')
  end

  def checkbox(name, opts = {}, default = true, force_checked = false)
    options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => 1}
    options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "1") or (obj[name].nil? and default)

    @forms.tag("input", options.merge(opts), false, false)
  end

  # takes a JSON representation of the current options selected and the list of archival_record_level enums
  # returns HTML for a set of checkboxes representing current selected and deselected sets for OAI export
  def checkboxes_for_oai_sets(set_json, value_list)
    return "" if value_list == nil
    # when called by #new, set_json will be nil.
    if set_json
      set_arry = JSON::parse(set_json)
    else
      set_arry = []
    end

    html = ""

    html << "<div class='form-group'>"
    html << label("oai_sets_available", {}, ["control-label", "col-sm-2"])
    html << "<div class='col-sm-9'>"
    html << "<ul class='checkbox-list'>"
    value_list['enumeration_values'].each do |v|
      # if we have an empty list of checkboxes, assume all sets are enabled.
      # otherwise, a checkbox is on if it's the in the list we get from the backend.
      checked = set_arry.include?(v['id'].to_s) || set_arry.length == 0

      html << "<li class='list-group-item'>"
      html << "<div class='checkbox'>"
      html << "<label>"
      html << "<input id=\"#{v['id']}\" name=\"sets[#{v['id']}]\" type=\"checkbox\" "
      if checked
        html << "checked=\"checked\" "
      end

      if readonly?
        html << "disabled />"
      else
        html << "/>"
      end # of checkbox tag

      html << "#{v['value']}"
      html << "</label>"
      html << "</div>"
      html << "</li>"
    end
    html << "</ul>"
    html << "</div>" #col-sm-9
    html << "</div>" #form-group

    return html.html_safe
  end

  def oai_config_repo_set_codes_field(set_json, repositories)
    #label_and_textfield(name, opts)
    set_arry = JSON::parse(set_json)

    html = ""

    html << "<div class='form-group'>"
    html << label("repo_set_section", {}, ["control-label", "col-sm-2"])
    html << "<div class='col-sm-9'>"
    html << "<ul class='checkbox-list'>"
    repositories.each do |r|
      # a checkbox is on if it's the in the list we get from the backend.
      checked = set_arry.include?(r['repo_code'].to_s)

      html << "<li class='list-group-item'>"
      html << "<div class='checkbox'>"
      html << "<label>"
      html << "<input id=\"#{r['repo_code']}\" name=\"repo_set_codes[#{r['repo_code']}]\" type=\"checkbox\" "
      if checked
        html << "checked=\"checked\" "
      end

      html << "/>"

      html << "#{r['repo_code']}"
      html << "</label>"
      html << "</div>"
      html << "</li>"
    end
    html << "</ul>"
    html << "</div>" #col-sm-9
    html << "</div>" #form-group

    return html.html_safe
  end

  def oai_config_sponsor_set_names_field(set_json, opts = {})
    # turn array from DB into a comma delimited list for UI
    set_arry = JSON::parse(set_json)
    value = set_arry.join("|")

    html = ""

    html << "<div class='form-group'>"
    html << label("sponsor_set_names", {}, ["control-label", "col-sm-2"])
    html << "<div class='col-sm-9'>"
    html << "<input id='oai_config_sponsor_set_names_' type='text' value='#{value}' name='oai_config[sponsor_set_names]' class='form-control js-taggable' datarole='tagsinput'>"
    html << "</div>"
    html << "</div>"

    return html.html_safe
  end

  def req_checkbox(name, opts = {}, default = true, force_checked = false)
    options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => "REQ"}
    options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "REQ") or (obj[name].nil? and default)

    @forms.tag("input", options.merge(opts), false, false)
  end

  def merge_checkbox(name, opts = {}, default = false, force_checked = false)
    options = {:id => "#{id_for(name)}", :type => "checkbox", :name => path(name), :value => "REPLACE"}
    options[:checked] = "checked" if force_checked or (obj[name] === true) or (obj[name].is_a? String and obj[name].start_with?("true")) or (obj[name] === "REPLACE") or (obj[name].nil? and default)

    @forms.tag("input", options.merge(opts), false, false)
  end

  def radio(name, value, opts = {})
    options = {:id => "#{id_for(name)}", :type => "radio", :name => path(name), :value => value}
    options[:checked] = "checked" if obj[name] == value

    @forms.tag("input", options.merge(opts), false, false)
  end


  def required?(name)
    if @active_template && @parent.templates[@active_template]
      @parent.templates[@active_template][:definition].required?(name)
    else
      false
    end
  end


  def default_for(name)
    if @active_template && @parent.templates[@active_template]
      @parent.templates[@active_template][:definition].default_for(name)
    else
      nil
    end
  end


  def allowable_types_for(name)
    if @active_template && @parent.templates[@active_template]
      @parent.templates[@active_template][:definition].allowable_types_for(name)
    else
      []
    end
  end


  def possible_options_for(name, add_empty_options = false, opts = {})
    if @active_template && @parent.templates[@active_template]
      @parent.templates[@active_template][:definition].options_for(self, name, add_empty_options, opts)
    else
      []
    end
  end


  def label_with_field(name, field_html, opts = {})
    opts[:label_opts] ||= {}
    opts[:label_opts][:plugin] = opts[:plugin]
    opts[:col_size] ||= 9

    control_group_classes,
    label_classes,
    controls_classes = %w(form-group), [], []

    unless opts[:layout] && opts[:layout] == 'stacked'
      label_classes << "col-sm-#{opts[:label_opts].fetch(:col_size, 2)}"
      controls_classes << "col-sm-#{opts[:col_size]}"
    end
    # There must be a better way to say this...
    # The value of the 'required' option wins out if set to either true or false
    # if not specified, we take the value of required?
    required = [:required, 'required'].map {|r| opts[r]}.compact.first
    if required.nil?
      required = required?(name)
    end

    control_group_classes << "required" if required == true
    control_group_classes << "required" if obj[name].is_a? String and obj[name].end_with?("REQ")
    control_group_classes << "conditionally-required" if required == :conditionally

    control_group_classes << "#{opts[:control_class]}" if opts.has_key? :control_class

    #TODO: refactor this. We don't need a separate method for each extra special class to be added below. Probably the thing to is to use the opts param.
    # ANW-617: add JS classes to slug fields
    control_group_classes << "js-slug_textfield" if name == "slug"
    control_group_classes << "js-slug_auto_checkbox" if name == "is_slug_auto"

    # ANW-429: add JS classes to structured date fields
    control_group_classes << "js-structured_date_select" if name == "date_type_structured"


    controls_classes << "#{opts[:controls_class]}" if opts.has_key? :controls_class

    control_group = "<div class=\"#{control_group_classes.join(' ')}\">"
    control_group << label(name, opts[:label_opts], label_classes)
    control_group << "<div class=\"#{controls_classes.join(' ')}\">"
    control_group << field_html
    control_group << "</div>"
    control_group << "</div>"

    # ANW-429
    # TODO: Refactor to the JS files, ideally so this is run when the "Add Date" button is clicked. This is a tricky one since the select field this JS needs to be run on doesn't exist until the callbacks that run after the button is clicked run. Putting it here means that it runs as part of the html, and is always included in the right context.
    control_group << "<script>selectStructuredDateSubform();</script>" if name == "date_type_structured"

    control_group.html_safe
  end

  # ANW-429
  # Generates HTML for a very stripped down summary of a note for use in the agents merge preview.
  # TODO: Eventually we'll want to use the notes partials in place of this code. This code was created because the current notes show takes up a lot of space, and work needs to be done to figure out the exact setup/context needed to get those views to render properly.
  # T
  def notes_preview(notes_index = "notes", content_index = "content")
     = I18n.t("note._frontend.preview.content")
    html = ""

    if obj[notes_index] && obj[notes_index].length > 0

      html << "<div class='subrecord-form-container'>"
      html << "<h4 class='subrecord-form-heading'>#{I18n.t("subsections.notes")}</h4>"

      obj[notes_index].each_with_index do |o, i|
        notes_heading = I18n.t("note.#{o['jsonmodel_type'].to_s}")

        if o[content_index].is_a?(Array)
          notes_content = o[content_index].join(" : ")
        else
          notes_content = o[content_index]
        end

        html << "<section>"
        html << "<h5>#{notes_heading}</h5>"
        html << "<div class='panel panel-default'>"
        html << "<div class=\"form-group\">"
        html << "<label class='control-label col-sm-2'>#{content_label}</label>"
        html << "<div class='col-sm-9 label-only'>"
        html << "#{notes_content}"
        html << "</div>"
        html << "</div>"
        html << "</div>"
        html << "</section>"
      end

      html << "</div>"

      html.html_safe

    end
  end

  # Same as above, but intended for use with an agents top level notes record instead of a subrecord, in the merge selector form.
  # Needed because emitting templates as usual breaks the merge selector interface
  def notes_preview_single(obj)
     = I18n.t("note._frontend.preview.content")
    html = ""

    notes_content = ""

    obj['subnotes'].each do |subnote|
      if subnote['jsonmodel_type'] == "note_text"
        notes_content << subnote["content"] if subnote["content"]
      end
    end

    html << "<br />"
    html << "<section>"
    html << "<div class='panel panel-default'>"
    html << "<div class=\"form-group\">"
    html << "<label class='control-label col-sm-2'>#{content_label}</label>"
    html << "<div class='col-sm-9 label-only'>"
    html << "#{notes_content}"
    html << "</div>"
    html << "</div>"
    html << "</div>"
    html << "</section>"

    html.html_safe
  end

  # ANW-429
  # outputs HTML for checkboxes for record-level add and replace for agents merge
  def record_level_merge_controls(form, name = "undefined", controls = true, replace = true, append = true)
    html = ""

    html << '<h4 class="subrecord-form-heading">'
    html << I18n.t("#{name}._singular").to_s

    if controls
      if replace
        html << '<label class="replace-control">'
        html << form.merge_checkbox('replace')
        html << '<small>'
        html << I18n.t("actions.merge_replace").to_s
        html << '</small>'
        html << '</label>'
      end

      if append
        html << '<label class="append-control">'
        html << form.merge_checkbox('append')
        html << '<small>'
        html << I18n.t("actions.merge_add").to_s
        html << '</small>'
        html << '</label>'
      end
    end

    html << '</h4>'

    return html.html_safe
  end

end

#set_index(template, idx) ⇒ Object



43
44
45
# File 'frontend/app/helpers/aspace_form_helper.rb', line 43

def set_index(template, idx)
  template.gsub(/\[\]$/, "[#{idx}]")
end

#slug_url_field(name, repo_slug = nil, generate_url_with_repo_slug = nil) ⇒ Object

ANW-617: TODO: Ideally, this method should generate a full URL, with the value from AppConfig[:public_url], so the link is fully actionable. Ran into a a bug (with AS? or deeper?) where the value of AppConfig[:public_url] was being changed at runtime simply by getting it’s value, with code like base_url = AppConfig[:public_url]. For now, this method generates a relative URL, like ‘\resources\Resource A’ to avoid this.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'frontend/app/helpers/aspace_form_helper.rb', line 51

def slug_url_field(name, repo_slug = nil, generate_url_with_repo_slug = nil)
  url = ""
  html = ""

  case obj['jsonmodel_type']
  when 'resource'
    scope = :repo
    route = "resources"
  when 'accession'
    scope = :repo
    route = "accessions"
  when 'classification'
    scope = :repo
    route = "classifications"
  when 'classification_term'
    scope = :repo
    route = "classification_terms"
  when 'digital_object'
    scope = :repo
    route = "digital_objects"
  when 'repository'
    scope = :global
    route = "repositories"
  when 'agent_person'
    scope = :global
    route = "agents"
  when 'agent_family'
    scope = :global
    route = "agents"
  when 'agent_software'
    scope = :global
    route = "agents"
  when 'agent_corporate_entity'
    scope = :global
    route = "agents"
  when 'subject'
    scope = :global
    route = "subjects"
  when 'archival_object'
    scope = :repo
    route = "archival_objects"
  when 'digital_object_component'
    scope = :repo
    route = "digital_object_components"
  end

  # For repo scoped objects,
  # if we have access to the repo slug in the session and the repo scoped URLs are enabled
  # generate link with repo slug
  if !obj['slug'].nil? &&
     !obj['slug'].empty? &&
     AppConfig[:use_human_readable_urls]

    if scope == :repo
      if generate_url_with_repo_slug && repo_slug
        url << "/" + "repositories" + "/"
        url << repo_slug
      end
    end

    url << "/" + route + "/" + obj['slug']
  else
    url = obj['uri']
  end

  url.to_s
end

#templatesObject



1012
1013
1014
1015
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1012

def templates
  @templates ||= {}
  @templates
end

#templates_for_js(jsonmodel_type = nil) ⇒ Object



1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1158

def templates_for_js(jsonmodel_type = nil)
  @delivering_js_templates = true

  result = ""
  return result if @templates.blank?

  obj = {}
  obj['jsonmodel_type'] = jsonmodel_type if jsonmodel_type

  templates_to_process = @templates.clone
  templates_processed = []

  # As processing a template may register further templates that hadn't been
  # registered previously, keep looping until we have no more templates to
  # process.
  #
  # Because infinite loops are terrifying and a pain to debug, let us reign
  # in the fear with a 100-loop-count-get-out-of-here-alive limit.
  i = 0
  while (true)
    templates_to_process.each do |name, template|
      context = FormContext.new("${path}", obj, self)

      def context.id_for(name, qualify = true)
        name = path(name) if qualify

        name.gsub(/[\[\]]/, '_').gsub('${path}', '${id_path}')
      end

      context.instance_eval do
        @active_template = name
      end

      result << "<div id=\"template_#{name}\"><!--"
      result << capture(context, &template[:block])
      result << "--></div>"

      templates_processed << name
    end

    if templates_processed.length < @templates.length
      # some new templates were defined while outputing the js templates
      templates_to_process = @templates.reject {|name, _| templates_processed.include?(name)}
    else
      # we've got them all
      break
    end

    i += 1

    if i > 100
      Rails.logger.error("templates_for_js has looped out more that 100 times")
      break
    end
  end

  result.html_safe
end

#textarea(name = nil, value = "", opts = {}) ⇒ Object



425
426
427
428
429
430
431
432
433
434
435
# File 'frontend/app/helpers/aspace_form_helper.rb', line 425

def textarea(name = nil, value = "", opts = {})
  value = value[0...-4] if value.is_a? String and value.end_with?("_REQ")
  value = nil if value === "REQ"
  options = {:id => id_for(name), :rows => 3}

  placeholder = I18n.t("#{i18n_for(name)}_placeholder", :default => '')
  options[:placeholder] = placeholder if not placeholder.empty?
  options[:class] = "form-control"

  @forms.text_area_tag(path(name), h(value), options.merge(opts))
end

#textarea_ro(name = nil, value = "", opts = {}) ⇒ Object



437
438
439
440
441
442
443
444
445
# File 'frontend/app/helpers/aspace_form_helper.rb', line 437

def textarea_ro(name = nil, value = "", opts = {})
  return "" if value.blank?
  opts[:escape] = true unless opts[:escape] == false
  opts[:base_url] ||= "/"
  value = clean_mixed_content(value, opts[:base_url]) if opts[:clean] == true
  value = @parent.preserve_newlines(value) if opts[:clean] == true
  value = CGI::escapeHTML(value) if opts[:escape]
  value.html_safe
end

#textfield(name = nil, value = nil, opts = {}) ⇒ Object



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'frontend/app/helpers/aspace_form_helper.rb', line 447

def textfield(name = nil, value = nil, opts = {})
  value ||= obj[name] if !name.nil?

  value = value[0...-4] if value.is_a? String and value.end_with?("_REQ")
  value = nil if value === "REQ"

  options = {:id => id_for(name), :type => "text", :value => h(value), :name => path(name)}

  placeholder = I18n.t("#{i18n_for(name)}_placeholder", :default => '')
  options[:placeholder] = placeholder if not placeholder.empty?
  options[:class] = "form-control"

  value = @forms.tag("input", options.merge(opts),
             false, false)

  if opts[:automatable]
    by_default = default_for("#{name}_auto_generate") || false
    value << "<label>".html_safe
    value << checkbox("#{name}_auto_generate", {
      :class => "automate-field-toggle", :display_text_when_checked => I18n.t("states.auto_generated")
      }, by_default, false)
    value << "&#160;<small>".html_safe
    value << I18n.t("actions.automate")
    value << "</small></label>".html_safe
  end

  inline_help = I18n.t("#{i18n_for(name)}_inline_help", :default => '')
  if !inline_help.empty?
    value << "<span class=\"help-inline\">#{inline_help}</span>".html_safe
  end

  value
end

#tooltip(name, prefix = '') ⇒ Object



555
556
557
# File 'frontend/app/helpers/aspace_form_helper.rb', line 555

def tooltip(name, prefix = '')
  I18n.t_raw("#{prefix}#{i18n_for(name)}_tooltip", :default => '')
end

#update_monitor_params(record) ⇒ Object



1288
1289
1290
1291
1292
1293
1294
1295
1296
# File 'frontend/app/helpers/aspace_form_helper.rb', line 1288

def update_monitor_params(record)
  {
    :"data-update-monitor" => true,
    :"data-update-monitor-url" => url_for(:controller => :update_monitor, :action => :poll),
    :"data-update-monitor-record-uri" => record.uri,
    :"data-update-monitor-record-is-stale" => !!@record_is_stale,
    :"data-update-monitor-lock_version" => record.lock_version
  }
end