lib/scrivito/basic_widget.rb in scrivito_sdk-0.50.1 vs lib/scrivito/basic_widget.rb in scrivito_sdk-0.60.0.rc1

- old
+ new

@@ -1,26 +1,60 @@ module Scrivito # The CMS widget class # @api public class BasicWidget + # @!parse extend Scrivito::AttributeContent::ClassMethods + include AttributeContent def self.type_computer @_type_computer ||= TypeComputer.new(Scrivito::BasicWidget, ::Widget) end def self.reset_type_computer! @_type_computer = nil end - def self.hide_from_widget_class_selection? - false + # + # @api public + # This method can be overridden in subclasses to control to which pages or + # widgets the given widget class can be added. This method can be used + # to ensure that only a special type of widget can be added to a specific + # container. An example for this is a +TabGroupWidget+ that should + # contain widgets of the +TabWidget+ type only, and, vice versa, a +TabWidget+ + # should only be contained in a +TabGroupWidget+. A value of +nil+ means that + # no additional restrictions are applied. + # + # This method only further restricts the list of valid classes defined + # by means of {AttributeContent#valid_widget_classes_for}. + # + # @return [Array<String, Symbol, Class>, nil] + # + # @example + # class TabGroupWidget < Widget + # def valid_widget_classes_for(field_name) + # [TabWidget] + # end + # end + # + # class TabWidget < Widget + # def self.valid_container_classes + # [TabGroupWidget] + # end + # end + # + def self.valid_container_classes end - attr_accessor :container, :container_field_name + def self.valid_inside_container?(container_class) + valid_container_classes.nil? || + valid_container_classes.map(&:to_s).include?(container_class.name) + end + attr_accessor :container, :container_attribute_name + attr_writer :obj, :id attr_reader :attributes_to_be_saved delegate :widget_from_pool, to: :obj @@ -44,13 +78,22 @@ # new_widget = Widget.new(_obj_class: "MyWidget") # # store it inside an obj # my_obj(my_widget_field: [new_widget]) # def initialize(attributes = {}) - @attributes_to_be_saved = self.class.with_default_obj_class(attributes) + @attributes_to_be_saved = self.class.prepare_attributes_for_instantiation(attributes) + @attribute_cache = {} end + def self.new(attributes = {}) + if obj_class = extract_obj_class_from_attributes(attributes) + obj_class.new(attributes) + else + super + end + end + def revision obj.revision end # Update the attributes of this Widget @@ -64,12 +107,12 @@ end # Destroys the {Scrivito::BasicWidget Widget} in the current {Workspace} # @api public def destroy - new_widget_list = container[container_field_name] - [self] - container.update(container_field_name => new_widget_list) + new_widget_list = container[container_attribute_name] - [self] + container.update(container_attribute_name => new_widget_list) end # # Create a copy of a {Scrivito::BasicWidget Widget}. # @@ -81,29 +124,34 @@ # # @example Duplicate the first widget in field +my_widget+ # obj.update(my_widgets: obj.my_widgets.push(obj.my_widgets.first.copy)) # def copy - attrs = {} - each_custom_attribute do |attr_name, attr_value, attr_type| - attrs[attr_name] = attr_type == 'widget' ? attr_value.map(&:copy) : attr_value + attributes = {} + attribute_definitions.each do |attribute_definition| + attribute_name = attribute_definition.name + attribute_value = read_attribute(attribute_name) + attribute_value = attribute_value.map(&:copy) if attribute_definition.widgetlist? + attributes[attribute_name] = attribute_value end - self.class.new(attrs) + self.class.new(attributes) end def copy_for_restore(referenced_ids) - attrs = {} - each_custom_attribute do |attr_name, attr_value, attr_type| - attrs[attr_name] = if attr_type == 'widget' - attr_value.reject { |widget| referenced_ids.include?(widget.id) } + attributes = {} + attribute_definitions.each do |attribute_definition| + attribute_name = attribute_definition.name + attribute_value = read_attribute(attribute_name) + if attribute_definition.widgetlist? + attribute_value = attribute_value + .reject { |widget| referenced_ids.include?(widget.id) } .map { |widget| widget.copy_for_restore(referenced_ids) } - else - attr_value end + attributes[attribute_name] = attribute_value end - attrs['_id'] = id - self.class.new(attrs) + attributes['_id'] = id + self.class.new(attributes) end def clone raise "The method `clone' was removed. Please use `copy' instead" end @@ -152,11 +200,11 @@ when Modification::EDITED previous_obj_content = CmsRestApi.get("revisions/#{workspace.base_revision_id}/objs/#{obj.id}") previous_widget_content = previous_obj_content["_widget_pool"]["#{id}"] previous_widget_content.delete_if do |attribute_name, _| - type_of_attribute(attribute_name) == "widget" + type_of_attribute(attribute_name) == 'widgetlist' end CmsRestApi.put("workspaces/#{workspace.id}/objs/#{obj.id}", { obj: {_widget_pool: {id => previous_widget_content}} }) else raise ScrivitoError, "cannot revert changes, since widget is #{modification}." @@ -203,21 +251,31 @@ end # returns the entity ({Scrivito::BasicObj} or {Scrivito::BasicWidget}) that references this widget # @api public def container - @container || cache_container_and_field_name_for_widget.first + @container || container_and_attribute_name.first end + # returns the name of the widget attribute that references this widget + # @api public + def container_attribute_name + @container_attribute_name || container_and_attribute_name.second + end + # returns the name of the widget field that references this widget # @api public + # @deprecated def container_field_name - @container_field_name || cache_container_and_field_name_for_widget.second + Scrivito::Deprecation.warn('Scrivito::BasicWidget#container_field_name is deprecated'\ + ' and will be removed in a future version.'\ + ' Please use Scrivito::BasicWidget#container_attribute_name instead.') + container_attribute_name end - def container_field_index - container[container_field_name].index(self) + def container_attribute_index + container[container_attribute_name].index(self) end def has_attribute?(key) key.to_s == '_obj_class' || super end @@ -259,43 +317,51 @@ # @api public def description_for_editor obj_class_name end + def data_from_cms + if persisted? + super + else + raise_not_persisted_error + end + end + private def workspace if revision.workspace revision.workspace else raise ScrivitoError, "No workspace set for the obj of this widget" end end - def data_from_cms - if persisted? - super - else - raise_not_persisted_error - end - end - def raise_not_persisted_error raise ScrivitoError.new('Can not access a new widget before it has been saved') end def cms_data_for_revision(revision) obj.widget_data_for_revision(id, revision) end - def cache_container_and_field_name_for_widget - @cache_container_and_field_name_for_widget ||= obj.container_and_field_name_for_widget(id) + def container_and_attribute_name + @container_and_attribute_name ||= obj.find_container_and_attribute_name_for_widget(id) end - def each_custom_attribute - data_from_cms.all_custom_attributes.each do |attr_name| - yield attr_name, read_attribute(attr_name), type_of_attribute(attr_name) - end + def has_system_attribute?(attribute_name) + attribute_name == '_obj_class' + end + + alias_method :has_public_system_attribute?, :has_system_attribute? + + def type_of_system_attribute(attribute_name) + 'string' if attribute_name == 'obj_class' + end + + def value_of_system_attribute(attribute_name) + data_from_cms.value_of(attribute_name) end end end