Class ::xowf::WorkflowPage

::xowf::WorkflowPage[i] create ...

Defined in

Class Relations

  • class: ::xotcl::Class[i]
  • superclass: ::xotcl::Object[i]
::xotcl::Class create ::xowf::WorkflowPage \
     -superclass ::xotcl::Object

Methods (to be applied on instances)

  • answer_is_correct (scripted, public)

     <instance of xowf::WorkflowPage[i]> answer_is_correct

    Check, if answer is correct based on "answer" and "correct_when" attributes of form fields and provided user input.

    Testcases:
    No testcase defined.
    set correct 0
    :log "WorkflowPage(${:name}).answer_is_correct autocorrect '[:get_from_template auto_correct]' -- [string is true -strict [:get_from_template auto_correct]]"
    if {[string is true -strict [:get_from_template auto_correct]]} {
      :log "==== answer_is_correct '[:instantiated_form_fields]'"
      foreach f [:instantiated_form_fields] {
        #:log [$f serialize]
        #:log "checking correctness [$f name] [$f info class] answer?[$f exists value] correct_when ?[$f exists correct_when]"
        if {[$f exists value]} {
          set r [$f answer_is_correct]
          #:log [$f serialize]
          if {$r != 1} {
            #:log [$f serialize]
            #:log "checking correctness [$f name] failed ([$f answer_is_correct])"
            set correct -1
            break
          }
          set correct 1
        }
      }
    }
    return $correct
  • call_action (scripted, public)

     <instance of xowf::WorkflowPage[i]> call_action [ -action action ] \
        [ -attributes attributes ]

    Call the specified action in the current workflow instance. The specified attributes are provided like form_parameters to the action of the workflow.

    Switches:
    -action (optional)
    -attributes (optional)

    Testcases:
    No testcase defined.
    if {![:is_wf_instance]} {
      error "Page [self] is not a Workflow Instance"
    }
    
    set actionObj [:get_action_obj -action $action]
    return [$actionObj invoke -attributes $attributes]
  • call_action_foreach (scripted, public)

     <instance of xowf::WorkflowPage[i]> call_action_foreach \
        -action action  [ -attributes attributes ] page_names

    Call the specified action for each of the specified pages denoted by the list of page names

    Switches:
    -action (required)
    -attributes (optional)
    Parameters:
    page_names (required)

    Testcases:
    No testcase defined.
    foreach page_name $page_names {
      set page [${:package_id} get_page_from_name -parent_id [:parent_id] -name $page_name]
      if {$page ne ""} {
        $page call_action -action $action -attributes $attributes
      } else {
        ns_log notice "WF: could not call action $action, since $page_name in [:parent_id] failed"
      }
    }
  • childpage (scripted, public)

     <instance of xowf::WorkflowPage[i]> childpage -name name  \
        [ -form form ]

    Return the child page of the current object with the provided name. In case the child object does not exist, create it as an instance of the provided form.

    Switches:
    -name (required)
    -form (optional)
    Returns:
    page object

    Testcases:
    create_test_items
    if {[info exists form]} {
      set child_page_id [::${:package_id} lookup  -use_package_path false  -default_lang en  -name $name  -parent_id ${:item_id}]
      if {$child_page_id == 0} {
        ns_log notice "child page '$name' does not exist"
        set form_obj [::${:package_id} instantiate_forms  -default_lang "en"  -forms $form]
        if {[llength $form_obj] == 0} {
          error "childpage: cannot instantiate $form"
        }
        set p [$form_obj create_form_page_instance  -name $name  -nls_language en_US  -parent_id ${:item_id}  -package_id ${:package_id}  -instance_attributes {}]
        $p save_new
      } else {
        #ns_log notice "child page '$name' exists already (item_id $child_page_id)"
        set p [::xo::db::CrClass get_instance_from_db -item_id $child_page_id]
      }
      return $p
    } else {
      error "cannot create '$name': API supports so far only form pages"
    }
  • footer (scripted, public)

     <instance of xowf::WorkflowPage[i]> footer

    Provide a tailored footer for workflow definition pages and workflow instance pages containing controls for instantiating forms or providing links to the workflow definition.

    Testcases:
    create_workflow_with_instance
    if {[info exists :__no_form_page_footer]} {
      next
    } else {
      set parent_id [:parent_id]
      set form_item_id ${:page_template}
      #:msg "is wf page [:is_wf], is wf instance page [:is_wf_instance]"
      if {[:is_wf]} {
        #
        # page containing a work flow definition
        #
        #set ctx [::xowf::Context require [self]]
        set work_flow_form [::xo::db::CrClass get_instance_from_db -item_id $form_item_id]
        set work_flow_base [$work_flow_form pretty_link]
    
        set wf [self]
        set wf_base [$wf pretty_link]
        set button_objs [list]
    
        # create new workflow instance button with start form
        #if {[:parent_id] != [::${:package_id} folder_id]} {
        #  set parent_id [:parent_id]
        #}
        set link [::${:package_id} make_link -link $wf_base $wf create-new parent_id return_url]
        lappend button_objs [::xowiki::includelet::form-menu-button-new new -volatile  -parent_id $parent_id  -form $wf -link $link]
    
        # list workflow instances button
        set obj [::xowiki::includelet::form-menu-button-wf-instances new -volatile  -package_id ${:package_id} -parent_id $parent_id  -base $wf_base -form $wf]
        if {[info exists return_url]} {
          $obj return_url $return_url
        }
        lappend button_objs $obj
    
        # work flow definition button
        set obj [::xowiki::includelet::form-menu-button-form new -volatile  -package_id ${:package_id} -parent_id $parent_id  -base $work_flow_base -form $work_flow_form]
        if {[info exists return_url]} {$obj return_url $return_url}
        lappend button_objs $obj
    
        # make menu
        return [:include [list form-menu -form_item_id ${:item_id} -button_objs $button_objs]]
    
      } elseif {[:is_wf_instance]} {
        #
        # work flow instance
        #
        set entry_form_item_id [:wf_property wf_form_id]
        set work_flow_form [::xo::db::CrClass get_instance_from_db -item_id $form_item_id]
        set work_flow_base [$work_flow_form pretty_link]
        set button_objs [list]
    
        #:msg entry_form_item_id=$entry_form_item_id-exists?=[nsf::is object $entry_form_item_id]
    
        # form definition button
        if {![nsf::is object $entry_form_item_id]} {
          # In case, the id is a form object, it is a dynamic form,
          # that we can't edit; therefore, we provide no link.
          #
          # Here, we have an id that we use for fetching...
          #
          set form [::xo::db::CrClass get_instance_from_db -item_id $entry_form_item_id]
          set base [$form pretty_link]
          set obj [::xowiki::includelet::form-menu-button-form new -volatile  -package_id ${:package_id} -parent_id $parent_id  -base $base -form $form]
          if {[info exists return_url]} {
            $obj return_url $return_url
          }
          lappend button_objs $obj
        }
        #
        # work flow definition button
        #
        set obj [::xowiki::includelet::form-menu-button-wf new -volatile  -package_id ${:package_id} -parent_id $parent_id  -base $work_flow_base -form $work_flow_form]
        if {[info exists return_url]} {$obj return_url $return_url}
        lappend button_objs $obj
        # make menu
        return [:include [list form-menu -form_item_id ${:page_template} -button_objs $button_objs]]
      } else {
        next
      }
    }
  • get_action_obj (scripted, public)

     <instance of xowf::WorkflowPage[i]> get_action_obj -action action 

    Check if the action can be executed in the current state, and if so, return the action_obj.

    Switches:
    -action (required)

    Testcases:
    create_workflow_with_instance
    set ctx [::xowf::Context require [self]]
    #
    # First try to call the action in the current state
    #
    foreach a [$ctx get_actions] {
      if {[namespace tail $a] eq "$action"} {
        # In the current state, the specified action is allowed
        :log  "--xowf action $action allowed -- name='${:name}'"
        return $a
      }
    }
    #
    # Some actions are state-safe, these can be called in every state
    #
    set actionObj [$ctx wf_definition_object $action]
    if {[nsf::is object $actionObj] && [$actionObj state_safe]} {
      # The action is defined as state-safe, so if can be called in every state
      :log  "--xowf action $action state_safe -- name='${:name}'"
      return $actionObj
    }
    error "No state-safe action '$action' available in workflow instance [self] of  [${:page_template} name] in state [$ctx get_current_state]\n Available actions: [[$ctx current_state] get_actions]"
  • get_revision_sets (scripted, public)

     <instance of xowf::WorkflowPage[i]> get_revision_sets \
        [ -with_instance_attributes ]

    Return a list of ns_sets containing revision_id, creation_date, creation_user, creation_ip, and state for the current workflow instance.

    Switches:
    -with_instance_attributes (optional)

    Testcases:
    create_test_items
    set item_id ${:item_id}
    if {$with_instance_attributes} {
      set revision_sets [::xo::dc sets -prepare integer wf_revisions {
        SELECT revision_id, creation_date, last_modified, creation_user,
               creation_ip, state, assignee, instance_attributes
        FROM cr_revisions cr, acs_objects o, xowiki_form_page x, xowiki_page_instance pi
        WHERE cr.item_id = :item_id
        AND   o.object_id = cr.revision_id
        AND   x.xowiki_form_page_id = cr.revision_id
        AND   pi.page_instance_id = cr.revision_id
        ORDER BY cr.revision_id ASC
      }]
    } else {
      set revision_sets [::xo::dc sets -prepare integer wf_revisions {
        SELECT revision_id, creation_date, last_modified, creation_user, creation_ip, state, assignee
        FROM cr_revisions cr, acs_objects o, xowiki_form_page x
        WHERE cr.item_id = :item_id
        AND   o.object_id = cr.revision_id
        AND   x.xowiki_form_page_id = cr.revision_id
        ORDER BY cr.revision_id ASC
      }]
    }
    return $revision_sets
  • is_wf (scripted, public)

     <instance of xowf::WorkflowPage[i]> is_wf

    Check, if the current page is a workflow page (page, defining a workflow)

    Testcases:
    create_test_items, create_workflow_with_instance
    if {[info exists :__wf(workflow_definition)]} {
      return 1
    } elseif {[:property workflow_definition] ne ""} {
      array set :__wf ${:instance_attributes}
      return 1
    } else {
      return 0
    }
  • is_wf_instance (scripted, public)

     <instance of xowf::WorkflowPage[i]> is_wf_instance

    Check, if the current page is a workflow instance (page, referring to a workflow)

    Testcases:
    create_test_items, create_workflow_with_instance
    if {[array exists :__wfi]} {
      return 1
    }
    #
    # We cannot call get_template_object here, because this will lead
    # to a recursive loop.
    #
    if {![nsf::is object ::${:page_template}]} {
      ::xo::db::CrClass get_instance_from_db -item_id ${:page_template}
    }
    if {${:state} ne ""
        && [${:page_template} hasclass ::xowf::WorkflowPage]
        && [${:page_template} is_wf]
      } {
      array set :__wfi [${:page_template} instance_attributes]
      return 1
    }
    return 0
  • post_process_dom_tree (scripted, public)

     <instance of xowf::WorkflowPage[i]> post_process_dom_tree dom_doc \
        dom_root form_fields

    post-process form in edit mode to provide feedback in feedback mode

    Parameters:
    dom_doc (required)
    dom_root (required)
    form_fields (required)

    Testcases:
    create_workflow_with_instance
    # In feedback mode, we set the CSS class to correct or incorrect
    
    if {[info exists :__feedback_mode]} {
      unset :__feedback_mode
      ::xo::Page requireCSS /resources/xowf/feedback.css
      set form [lindex [$dom_root selectNodes "//form"] 0]
      $form setAttribute class "[$form getAttribute class] feedback"
    
      #
      # In cases, where the HTML exercise was given, we process the HTML
      # to flag the result.
      #
      # TODO: What should we do with the feedback. "util_user_message" is
      # not optimal...
      #
      foreach f $form_fields {
        if {[$f exists __rendered]} continue
        if {[$f exists evaluated_answer_result]} {
          set result [$f set evaluated_answer_result]
          foreach n [$dom_root selectNodes "//form//*\[@name='[$f name]'\]"] {
            set oldCSSClass [expr {[$n hasAttribute class] ? [$n getAttribute class] : ""}]
            $n setAttribute class [string trim "$oldCSSClass [$f form_widget_CSSclass]"]
            $f form_widget_CSSclass $result
    
            set helpText [$f help_text]
            if {$helpText ne ""} {
              #set divNode [$dom_doc createElement div]
              #$divNode setAttribute class [$f form_widget_CSSclass]
              #$divNode appendChild [$dom_doc createTextNode $helpText]
              #[$n parentNode] insertBefore $divNode [$n nextSibling]
    
              #set spanNode [$dom_doc createElement span]
              #$spanNode setAttribute class "glyphicon glyphicon-ok [$f form_widget_CSSclass]"
              #[$n parentNode] insertBefore $spanNode [$n nextSibling]
    
              set parentNode [$n parentNode]
              set oldClass [$parentNode getAttribute class ""]
              $parentNode setAttribute class "selection [$f form_widget_CSSclass]"
              $parentNode setAttribute title $helpText
    
              #util_user_message -message "field [$f name], value [$f value]: $helpText"
            }
          }
        }
      }
      #
      # Provide feedback for the whole exercise.
      #
      if {[:answer_is_correct]} {
        set feedback [:get_from_template feedback_correct]
      } else {
        set feedback [:get_from_template feedback_incorrect]
      }
      if {$feedback ne ""} {
        $dom_root appendFromScript {
          html::div -class feedback {
            html::t -disableOutputEscaping $feedback
          }
        }
      }
    }
  • post_process_form_fields (scripted, public)

     <instance of xowf::WorkflowPage[i]> post_process_form_fields \
        form_fields

    Propagate the feedback mode setting of this workflow page to the supplied formfields.

    Parameters:
    form_fields (required)

    Testcases:
    create_workflow_with_instance
    #:log ------------------post_process_form_fields-feedback_mode=[info exists :__feedback_mode]
    if {[info exists :__feedback_mode]} {
      #
      # Provide feedback for every alternative
      #
      foreach f $form_fields {
        $f set_feedback ${:__feedback_mode}
      }
    }
    #:log ------------------post_process_form_fields-feedback_mode=[info exists :__feedback_mode]-DONE
  • render_form_action_buttons (scripted, public)

     <instance of xowf::WorkflowPage[i]> render_form_action_buttons \
        [ -formfieldButtonClass formfieldButtonClass ] \
        [ -CSSclass CSSclass ]

    Render the defined actions in the current state with submit buttons

    Switches:
    -formfieldButtonClass (optional, defaults to "::xowiki::formfield::submit_button")
    -CSSclass (optional)

    Testcases:
    create_workflow_with_instance
    if {[:is_wf_instance]} {
    
      set ctx [::xowf::Context require [self]]
      set buttons {}
      foreach action [$ctx get_actions] {
        set success 0
        foreach role [$action roles] {
          set success [:check_role $role]
          if {$successbreak
        }
        if {$success} {
          set f [$formfieldButtonClass new  -name __action_[namespace tail $action]  -form_button_wrapper_CSSclass [$action wrapper_CSSclass]  -label_noquote [$action label_noquote]  -CSSclass $CSSclass  -destroy_on_cleanup  ]
          if {[$action extra_css_class] ne ""} {
            #$f append form_button_CSSclass " " [$action extra_css_class]
            $f form_button_CSSclass ""
            $f CSSclass_list_add form_button_CSSclass [$action extra_css_class]
          }
          $f CSSclass_list_add form_button_CSSclass prevent-double-click
          #ns_log notice "RENDER BUTTON has CSSclass [$f CSSclass] // [$f form_button_CSSclass]"
          if {[$action exists title]} {
            $f title [$action title]
          }
          $f value [$action label]
          lappend buttons $f
        }
      }
      #
      # Render the button widgets.
      #
      :render_form_action_buttons_widgets -CSSclass $CSSclass $buttons
    } else {
      next
    }
  • render_form_action_buttons_widgets (scripted, public)

     <instance of xowf::WorkflowPage[i]> render_form_action_buttons_widgets \
        [ -CSSclass CSSclass ] buttons

    With the given set of buttons, produce the HTML for the button container and the included inputs.

    Switches:
    -CSSclass (optional)
    Parameters:
    buttons (required)

    Testcases:
    create_workflow_with_instance
    if {[llength $buttons] > 0} {
      #
      # Build button groups based on "form_button_wrapper_CSSclass".
      #
      set previous_wrapper_class "NONE"
      set wrapper_groups {}
      set group_num 0
      foreach f $buttons {
        set wrapper_class [$f form_button_wrapper_CSSclass]
        if {$wrapper_class eq $previous_wrapper_class} {
          dict lappend wrapper_groups [list $wrapper_class $group_num$f
          continue
        }
        incr group_num
        dict lappend wrapper_groups [list $wrapper_class $group_num$f
        set previous_wrapper_class $wrapper_class
      }
    
      foreach wrapper_group [dict keys $wrapper_groups] {
        ::html::div -class [lindex $wrapper_group 0] {
          foreach f [dict get $wrapper_groups $wrapper_group] {
            $f render_input
          }
        }
      }
    }
  • render_icon (scripted, public)

     <instance of xowf::WorkflowPage[i]> render_icon

    Provide an icon or text for describing the kind of application.

    Testcases:
    create_workflow_with_instance
    if {[:info procs render_icon] ne ""} {
      #
      # In case, we have a per-object method (i.e., defined via the
      # workflow), use this with highest precedence.
      #
      next
    
    } elseif {[:is_wf_instance]} {
      set page_template ${:page_template}
      set title [::$page_template title]
      regsub {[.]wf$} $title "" title
      return [list text $title is_richtext false]
    } elseif {[:is_wf]} {
      return [list text "Workflow" is_richtext false]
    } else {
      next
    }
  • render_thumbnails (scripted, public)

     <instance of xowf::WorkflowPage[i]> render_thumbnails upload_info

    Renderer of the thumbnail file(s)

    Parameters:
    upload_info (required)
    dict containing the "file_object" and "file_name"
    Returns:
    HTML content

    Testcases:
    No testcase defined.
    dict with upload_info {
      set parent_id ${:item_id}
      set feedbackFiles [xo::dc list_of_lists . {
        select item_id, name from cr_items where parent_id = :parent_id
      }]
      if {[regexp {^([^/]+)/} $file_name . qn]} {
        set HTML [:QM render_feedback_files  -question_name $qn  -feedbackFiles $feedbackFiles]
      } else {
        set HTML "$file_name created"
      }
    }
    return $HTML
  • schedule_action (scripted, public)

     <instance of xowf::WorkflowPage[i]> schedule_action -time time  \
        [ -party_id party_id ] -action action  [ -attributes attributes ]

    Schedule the specified action for the current workflow instance at the given time. The specified attributes are provided like form_parameters to the action of the workflow.

    Switches:
    -time (required)
    time when the atjob should be executed
    -party_id (optional)
    party_id for the user executing the atjob
    -action (required)
    workflow action to be executed
    -attributes (optional)
    arguments provided to the workflow action (attribute value pairs)

    Testcases:
    No testcase defined.
    if {![:is_wf_instance]} {
      error "Page [self] is not a Workflow Instance"
    }
    if {![info exists party_id]} {
      set party_id [::xo::cc user_id]
    }
    :schedule_job -time $time -party_id $party_id  [list call_action -action $action -attributes $attributes]
  • schedule_job (scripted, public)

     <instance of xowf::WorkflowPage[i]> schedule_job -time time  \
        [ -party_id party_id ] cmd

    Schedule the specified Tcl command for the current package instance at the given time.

    Switches:
    -time (required)
    -party_id (optional)
    Parameters:
    cmd (required)

    Testcases:
    No testcase defined.
    :log "-at $time"
    set j [::xowf::atjob new  -time $time  -party_id $party_id  -cmd $cmd  -url [:pretty_link]  -object [self]]
    $j persist
  • solution_set (scripted, public)

     <instance of xowf::WorkflowPage[i]> solution_set

    Compute solution set in form of attribute=value pairs based on "answer" attribute of form fields.

    Testcases:
    No testcase defined.
    set solutions [list]
    foreach f [:instantiated_form_fields] {
      if {![$f exists answer]} continue
      lappend solutions [$f name]=[$f answer]
    }
    return [join [lsort $solutions", "]
  • stats_record_count (scripted, public)

     <instance of xowf::WorkflowPage[i]> stats_record_count name

    Record that the specified question was used.

    Parameters:
    name (required)

    Testcases:
    create_test_items
    dict incr :__stats_count $name
  • stats_record_detail (scripted, public)

     <instance of xowf::WorkflowPage[i]> stats_record_detail \
        [ -label label ] [ -value value ] [ -name name ] \
        [ -correctly_answered on|off ]

    Record the stat detail of the question.

    Switches:
    -label (optional)
    -value (optional)
    -name (optional)
    -correctly_answered (optional, boolean)

    Testcases:
    create_test_items
    dict set :__stats_label $name label $value $label
    if {[info exists :__stats_success] && [dict exists ${:__stats_success} $name $value]} {
      set details [dict get ${:__stats_success} $name $value]
    } else {
      set details ""
    }
    dict incr details $correctly_answered
    dict set :__stats_success $name $value $details
  • wf_context (scripted, public)

     <instance of xowf::WorkflowPage[i]> wf_context [ ctx ]

    Return for a workflow page the workflow context object. The same function can be used as well for setting the workflow context at the first places (e.g. on initialization of the wf-context).

    Parameters:
    ctx (optional)

    Testcases:
    create_workflow_with_instance
    if {$ctx ne ""} {
      set :_wf_context $ctx
    }
    return ${:_wf_context}
  • www-edit (scripted, public)

     <instance of xowf::WorkflowPage[i]> www-edit args [ args... ]

    Hook for editing workflow pages

    Parameters:
    args (required)

    Testcases:
    create_workflow_with_instance
    if {[:is_wf_instance]} {
      set ctx [::xowf::Context require [self]]
      set s [$ctx current_state]
      :include_header_info -css [$s extra_css] -js [$s extra_js]
    }
    next
  • www-view (scripted, public)

     <instance of xowf::WorkflowPage[i]> www-view [ content ]

    Provide additional view modes: - edit: instead of viewing a page, it is opened in edit mode - view_user_input: show user the provided input - view_user_input_with_feedback: show user the provided input with feedback

    Parameters:
    content (optional)

    Testcases:
    create_test_items, create_workflow_with_instance
    # The edit method calls view with an HTML content as argument.
    # To avoid a loop, when "view" is redirected to "edit",
    # we make sure that we only check the redirect on views
    # without content.
    
    #:msg "view [self args] [:is_wf_instance]"
    
    if {[:is_wf_instance] && $content eq ""} {
      set ctx [::xowf::Context require [self]]
      set method [$ctx get_view_method]
      set s [$ctx current_state]
      :include_header_info -css [$s extra_css] -js [$s extra_js]
    
      if {$method ne "" && $method ne "view"} {
        #:msg "view redirects to $method in state [$ctx get_current_state]"
        switch -- $method {
          view_user_input {
            #:msg "calling edit with disable_input_fields=1"
            return [:www-edit -disable_input_fields 1]
          }
          view_user_input_with_feedback {
            set :__feedback_mode 1
            #:msg "calling edit with disable_input_fields=1"
            return [:www-edit -disable_input_fields 1]
          }
          default {
            #:msg "calling $method"
            return [::${:package_id} invoke -method $method]
          }
        }
      }
    }
    next

Variables

::xowf::WorkflowPage set __default_metaclass ::xotcl::Class
::xowf::WorkflowPage set __default_superclass ::xotcl::Object