# frozen_string_literal: trueifGem::Version.new(RUBY_VERSION)<Gem::Version.new("3.0")usingPhlex::Overrides::Symbol::NameendmodulePhlexclassSGMLclass<<self# Render the view to a String. Arguments are delegated to <code>new</code>.defcall(...)new(...).callendalias_method:render,:call# Create a new instance of the component.# @note The block will not be delegated to the initializer. Instead, it will be provided to `template` when rendering.defnew(*args,**kwargs,&block)ifblockobject=super(*args,**kwargs,&nil)object.instance_variable_set(:@_content_block,block)objectelsesuperendend# @api privatedefrendered_at_least_once!alias_method:__attributes__,:__final_attributes__alias_method:call,:__final_call__endend# Renders the view and returns the buffer. The default buffer is a mutable String.defcall(buffer=nil,target: +"",view_context: nil,parent: nil,&block)__final_call__(buffer,target: target,view_context: view_context,parent: parent,&block).tapdoself.class.rendered_at_least_once!endend# @api privatedef__final_call__(buffer=nil,target: +"",view_context: nil,parent: nil,&block)@_target=target@_view_context=view_context@_parent=parentblock||=@_content_blockreturnbuffer||targetunlessrender?around_templatedoifblockifDeferredRender===self__vanish__(self,&block)templateelsetemplatedo|*args|ifargs.length>0yield_content_with_args(*args,&block)elseyield_content(&block)endendendelsetemplateendendbuffer?(buffer<<target):targetend# Render another view# @param renderable [Phlex::SGML]# @return [nil]defrender(renderable,&block)caserenderablewhenPhlex::SGMLrenderable.call(target: @_target,view_context: @_view_context,parent: self,&block)whenClassifrenderable<Phlex::SGMLrenderable.new.call(target: @_target,view_context: @_view_context,parent: self,&block)endelseraiseArgumentError,"You can't render a #{renderable}."endnilend# Output text content. The text will be HTML-escaped.# @return [nil]defplain(content)casecontentwhenString@_target<<ERB::Escape.html_escape(content)whenSymbol@_target<<ERB::Escape.html_escape(content.name)whenInteger@_target<<ERB::Escape.html_escape(content.to_s)whennilnilelseif(formatted_object=format_object(content))@_target<<ERB::Escape.html_escape(formatted_object)endendnilend# Output a whitespace character. This is useful for getting inline elements to wrap. If you pass a block, a whitespace will be output before and after yielding the block.# @return [nil]defwhitespace@_target<<" "ifblock_given?yield@_target<<" "endnilend# Output an HTML comment.# @return [nil]defcomment(&block)@_target<<"<!-- "yield_content(&block)@_target<<" -->"nilend# This method is very dangerous and should usually be avoided. It will output the given String without any HTML safety. You should never use this method to output unsafe user input.# @param content [String|nil]# @return [nil]defunsafe_raw(content=nil)returnnilunlesscontent@_target<<contentnilend# Capture a block of output as a String.# @return [String]defcapture(&block)return""unlessblock_given?original_buffer_content=@_target.dup@_target.clearbeginyield_content(&block)new_buffer_content=@_target.dupensure@_target.clear@_target<<original_buffer_contentendnew_buffer_content.is_a?(String)?new_buffer_content:""end# Like `capture` but the output is vanished into a BlackHole buffer.# Because the BlackHole does nothing with the output, this should be faster.# @return [nil]privatedef__vanish__(*args)returnunlessblock_given?original_buffer=@_targetbegin@_target=BlackHoleyield(*args)ensure@_target=original_bufferendnilend# Default render predicate can be overridden to prevent rendering# @return [bool]privatedefrender?trueend# Format the object for output# @return [String]privatedefformat_object(object)caseobjectwhenFloatobject.to_sendend# Override this method to hook in around a template render. You can do things before and after calling <code>super</code> to render the template. You should always call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.# @return [nil]privatedefaround_templatebefore_templateyieldafter_templatenilend# Override this method to hook in right before a template is rendered. Please remember to call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.# @return [nil]privatedefbefore_templatenilend# Override this method to hook in right after a template is rendered. Please remember to call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.# @return [nil]privatedefafter_templatenilend# Yields the block and checks if it buffered anything. If nothing was buffered, the return value is treated as text.# @return [nil]privatedefyield_contentreturnunlessblock_given?original_length=@_target.lengthcontent=yield(self)plain(content)iforiginal_length==@_target.lengthnilend# Same as <code>yield_content</code> but accepts a splat of arguments to yield. This is slightly slower than <code>yield_content</code>, which is why it's defined as a different method because we don't always need arguments so we can usually use <code>yield_content</code> instead.# @return [nil]privatedefyield_content_with_args(*args)returnunlessblock_given?original_length=@_target.lengthcontent=yield(*args)plain(content)iforiginal_length==@_target.lengthnilend# @api privateprivatedef__attributes__(**attributes)__final_attributes__(**attributes).tapdo|buffer|Phlex::ATTRIBUTE_CACHE[respond_to?(:process_attributes)?(attributes.hash+self.class.hash):attributes.hash]=buffer.freezeendend# @api privateprivatedef__final_attributes__(**attributes)ifrespond_to?(:process_attributes)attributes=process_attributes(**attributes)endifattributes[:href]&.start_with?(/\s*javascript:/)attributes.delete(:href)endifattributes["href"]&.start_with?(/\s*javascript:/)attributes.delete("href")endbuffer=+""__build_attributes__(attributes,buffer: buffer)bufferend# @api privateprivatedef__build_attributes__(attributes,buffer:)attributes.eachdo|k,v|nextunlessvname=casekwhenStringthenkwhenSymbolthenk.name.tr("_","-")elsek.to_send# Detect unsafe attribute names. Attribute names are considered unsafe if they match an event attribute or include unsafe characters.ifHTML::EVENT_ATTRIBUTES[name]||name.match?(/[<>&"']/)raiseArgumentError,"Unsafe attribute name detected: #{k}."endcasevwhentruebuffer<<" "<<namewhenStringbuffer<<" "<<name<<'="'<<ERB::Escape.html_escape(v)<<'"'whenSymbolbuffer<<" "<<name<<'="'<<ERB::Escape.html_escape(v.name)<<'"'whenHash__build_attributes__(v.transform_keys{|subkey|casesubkeywhenSymbolthen"#{k}-#{subkey.name.tr('_','-')}"else"#{k}-#{subkey}"end},buffer: buffer)elsebuffer<<" "<<name<<'="'<<ERB::Escape.html_escape(v.to_s)<<'"'endendbufferendendend