module Scrivito # this class is the server-side equivalent of the JavaScript class `cms_field_element` class CmsFieldTag < Struct.new(:view, :tag_name, :obj_or_widget, :field_name) FIELD_TYPES_WITH_ORIGINAL_CONTENT = %w[ binary date enum html multienum reference referencelist string text ] include TagRenderer def content(&block) if field_type == 'widgetlist' raise ArgumentError, 'No block allowed for widgetlist fields' if block_given? modifications = modification_info || [] rendered_widgets = default_content.each_with_index.map do |widget, index| WidgetTag.new(view, widget, modifications[index]).render end view.safe_join(rendered_widgets) else block_given? ? view.capture { yield } : view.scrivito_value(default_content) end end def options return {} unless authenticated_editor? options = { 'private-field-workspace-id' => current_workspace_id, 'field-name' => field_name, 'field-obj-class' => obj_or_widget.obj_class_name, 'field-type' => field_type, } modification = comparison.modification_for_attribute(obj_or_widget, field_name) if modification == Modification::EDITED && field_type != 'widgetlist' options['field-modification'] = modification end if obj_or_widget.kind_of?(BasicWidget) options['private-field-obj-id'] = obj_or_widget.obj.id options['private-field-widget-id'] = obj_or_widget.id else options['private-field-obj-id'] = obj_or_widget.id end if FIELD_TYPES_WITH_ORIGINAL_CONTENT.include?(field_type) original_value = view.scrivito_value(current_value) original_content = original_content(field_type, original_value, current_value) encoded_content = Base64.strict_encode64(MultiJson.encode(original_content)) options['private-field-original-content'] = encoded_content end if field_type == 'widgetlist' options['private-field-widget-allowed-classes'] = build_valid_widget_classes.to_json end options end def modification_info calculate_content_and_modification @content_and_modification.second end private def build_valid_widget_classes obj_or_widget.valid_widget_class_names_for(field_name).map do |widget_class| { name: widget_class, description: description_for_widget_class(widget_class), } end end def field_type @field_type ||= obj_or_widget.type_of_attribute(field_name) end def description_for_widget_class(class_name) class_name.constantize.description_for_editor end def default_content calculate_content_and_modification @content_and_modification.first end def calculate_content_and_modification @content_and_modification ||= comparison.diff_for(obj_or_widget, field_name) || [current_value, nil] end def comparison editing_context.comparison end def current_value obj_or_widget[field_name] end def current_workspace_id Workspace.current.id end def authenticated_editor? editing_context.authenticated_editor? end def editing_context EditingContextMiddleware.from_request(view.request) end def original_content(field_type, field_value, raw_value) case field_type when 'binary' then field_value && {} when 'date' then raw_value.try(:utc).try(:iso8601) when 'reference' then field_value.try(:id) when 'referencelist' then field_value.map(&:id) else field_value end end end end