"; $function_has_category_tree_check=false; ?>
" id="question_" data-has_display_condition="" data-question_field_ref=""=1) { echo "title=\"" . escape(lang_or_i18n_get_translated($field["tooltip_text"], "fieldtooltip-")) . "\""; } ?>>
" style="display:none;"= 1){ echo "title=\"" . escape(lang_or_i18n_get_translated($field["tooltip_text"], "fieldtooltip-")) . "\"";} ?> >
onChange="UpdateResultCount();" onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"onKeyUp="if('' != jQuery(this).val()){FilterBasicSearchOptions('',[]);}">
$node) { // Special case for vertically ordered checkboxes. // Order by needs to be reset as per the new order so that we can reshuffle them using the order by as a reference if($checkbox_ordered_vertically) { $field['node_options'][$node_index]['order_by'] = $order_by_resetter++; } } if ($field["display_as_dropdown"] || $forsearchbar) { # Show as a dropdown box $name = "nodes_searched[{$field['ref']}]"; ?> 40: $cols = 1; break; case $l > 25: $cols = 2; break; case $l > 15: $cols = 3; break; case $l > 10: $cols = 4; break; case $l > 5: $cols = 5; break; default: $cols = 10; } $height = ceil(count($field['node_options']) / $cols); global $checkbox_ordered_vertically, $checkbox_vertical_columns; if($checkbox_ordered_vertically) { if(!hook('rendersearchchkboxes')) { # ---------------- Vertical Ordering (only if configured) ----------- ?>
checked onClick="UpdateResultCount();">
$cols) { $wrap = 1; ?>
checked onClick="UpdateResultCount();">

{$n_details['name']}
"; } ?>
  "> $data_attr_value) { $data_attr_key = str_replace(' ', '_', $data_attr_key); $result .= ' data-' . $data_attr_key . '="' . $data_attr_value . '"'; } $result .= '>' . escape($label) . ''; return $result; } /** * Renders search actions functionality as a dropdown box * * @param array $collection_data Collection data * @param boolean $top_actions Set to true if actions are to be rendered in the search filter bar (above results) * @param boolean $two_line Display on two lines * @param string $id Selector HTML ID * @param array $resource_data Resource data * @param boolean $optionsonly Render only options * @param string $forpage Specifically target for which page actions apply * * @return void */ function render_actions(array $collection_data, $top_actions = true, $two_line = true, $id = '',$resource_data=array(),$optionsonly=false, $forpage="") { if(hook('prevent_running_render_actions')) { return; } global $baseurl, $lang, $k, $pagename, $order_by, $sort, $USER_SELECTION_COLLECTION; $is_selection_collection = isset($collection_data['ref']) && $collection_data['ref'] == $USER_SELECTION_COLLECTION; // globals that could also be passed as a reference global $result /*search result*/; $action_selection_id = ($forpage!=""?$forpage:$pagename) . '_action_selection' . $id; if(!$top_actions) { $action_selection_id .= '_bottom'; } if(isset($collection_data['ref'])) { $action_selection_id .= '_' . str_replace("-","_",$collection_data['ref']); } if(!$optionsonly) {?>

style="">
checked />
" > ', escape($input), escape($input), $numeric ? "number" : "text", escape((string) $current), $extra ); echo $additionaltext; ?>
'From','pixelwidthmin'=>'To') * @param string $additionaltext (optional) Text to to display after input * @param boolean $numeric Set to true to force numeric input */ function render_split_text_question($label, $inputs = array(), $additionaltext="", $numeric=false, $extra="", $currentvals=array()) { ?>
$inputtext) { echo "
" . $inputtext . "
\n"; echo "\n"; } echo $additionaltext; ?>
'From','pixelwidthmin'=>'To') * @param string $current The current selected value * @param string $extra Extra attributes used on the selector element * @param array $ctx Rendering context. Should be used to inject different elements (e.g set the div class, add onchange for select) * * @return void */ function render_dropdown_question($label, $inputname, $options = array(), $current="", $extra="", array $ctx = array()) { $div_class = array("Question"); if(isset($ctx["div_class"]) && is_array($ctx["div_class"]) && !empty($ctx["div_class"])) { $div_class = array_merge($div_class, $ctx["div_class"]); } $input_class = isset($ctx["input_class"]) ? $ctx["input_class"] : "stdwidth"; $onchange = (isset($ctx["onchange"]) && trim($ctx["onchange"]) != "" ? trim($ctx["onchange"]) : ""); $onchange = ($onchange != "" ? sprintf("onchange=\"%s\"", $onchange) : ""); $extra .= " {$onchange}"; ?>
">
$field)) || hook('edithidefield2', '', array('field' => $field))); } /** * Displays a field in the resource edit interface. * * This function handles the rendering of various types of fields based on their configurations and context. * It supports multiple modes, such as batch editing, and adjusts the display based on user permissions, * errors from previous saves, and whether the field is being copied from another resource. * * @param int $n The index of the field in the form. * @param array $field The field configuration array containing settings and metadata for the field. * @param bool $newtab Indicates if the field should be displayed in a new tab. * @param bool $modal Indicates if the field is part of a modal dialog. */ function display_field($n, $field, $newtab=false,$modal=false) { debug_function_call(__FUNCTION__, [$n, $field['ref'], $newtab, $modal]); global $use, $ref, $original_fields, $multiple, $lastglobal,$is_template, $language, $lang, $blank_edit_template, $edit_autosave, $errors, $tabs_on_edit, $collapsible_sections, $ctrls_to_save, $embedded_data_user_select, $embedded_data_user_select_fields, $show_error, $save_errors, $baseurl, $is_search, $all_selected_nodes,$original_nodes, $FIXED_LIST_FIELD_TYPES, $TEXT_FIELD_TYPES, $DATE_FIELD_TYPES, $upload_review_mode, $check_edit_checksums, $locked_fields, $lastedited, $copyfrom, $fields; // Set $is_search to false in case page request is not an ajax load and $is_search hs been set from the searchbar $is_search=false; if(!isset($locked_fields)) { $locked_fields = explode(",",getval("lockedfields","")); } if(!isset($copyfrom)) { $copyfrom = getval('copyfrom', ''); } $name="field_" . $field["ref"]; $value=$field["value"]; $value=trim((string) $value); $use_copyfrom=true; $omit_when_copying_enacted=false; if ($use != $ref && ($field["omit_when_copying"])) { debug("display_field: reverting copied value for field " . $field["ref"] . " as omit_when_copying is enabled"); # Return this field value back to the original value, instead of using the value from the copied resource/metadata template # This is triggered if field has the 'omit_when_copying' flag set reset($original_fields); $use_copyfrom=false; foreach ($original_fields as $original_field) { if ($original_field["ref"]==$field["ref"]) { $value=$original_field["value"]; } } $selected_nodes = $original_nodes; $omit_when_copying_enacted=true; } elseif(($ref<0 || $upload_review_mode) && isset($locked_fields) && in_array($field["ref"], $locked_fields) && $lastedited > 0) { // Get value from last edited resource debug("display_field: locked field " . $field['ref'] . ". Using nodes from last resource edited - " . $lastedited); $selected_nodes = get_resource_nodes($lastedited,$field["ref"]); } else { $selected_nodes = $all_selected_nodes; if (in_array($field["type"], $DATE_FIELD_TYPES) && !$GLOBALS['use_native_input_for_date_field']) { $submitted_val = sanitize_date_field_input($field["ref"], false); } else { $submitted_val = getval("field_" . $field['ref'], ""); } if(!empty($save_errors) && $submitted_val != "") { // Set to the value that was submitted $value = $submitted_val; } } $displaycondition=true; if ($field["display_condition"] != "") { // Check if field has a display condition set and render the client side check display condition functions $displaycondition = check_display_condition($n, $field, $fields, true, $use); debug(sprintf('$displaycondition = %s', json_encode($displaycondition))); } if ($multiple && ( (getval("copyfrom","") == "" && getval('metadatatemplate', '') == "") || str_replace(array(" ",","),"",(string)$value)=="") ) { debug('Blank the value for multi-edits unless copying data from resource'); $value=""; } if ($field["global"] == 0 && $lastglobal && $collapsible_sections) { ?>

TypeSpecificSection">
checked onClick="batch_edit_toggle_edit_multi_checkbox_question();"
padding-bottom:0;margin-bottom:0;">
" id="question_"style="border-top:none; display:none; ">

" style="display:none;">
"; if(!hook('replacefield', '', array($field['type'], $field['ref'], $n))) { global $auto_order_checkbox, $auto_order_checkbox_case_insensitive, $FIXED_LIST_FIELD_TYPES, $is_search; // Establish the full set of selected nodes to be rendered for this field // Do this only if the field's selected nodes haven't previously been adjusted to take account of omit_when_copying if (!$omit_when_copying_enacted && isset($field['nodes'])) { $selected_nodes = array_unique(array_merge($selected_nodes, explode(",", $field['nodes']))); } debug(sprintf('$selected_nodes = %s', json_encode($selected_nodes))); if(in_array($field['type'], $FIXED_LIST_FIELD_TYPES)) { $name = "nodes[{$field['ref']}]"; // Sometimes we need to pass multiple options if(in_array($field['type'], array(FIELD_TYPE_CHECK_BOX_LIST, FIELD_TYPE_CATEGORY_TREE))) { $name = "nodes[{$field['ref']}][]"; } elseif(FIELD_TYPE_DYNAMIC_KEYWORDS_LIST == $field['type']) { $name = "field_{$field['ref']}"; } $field_nodes = []; foreach ($selected_nodes as $selected_node) { // Check node is valid if (!isset($field['node_options'][$selected_node])) { continue; } $field_nodes[] = $selected_node; } sort($field_nodes); debug(sprintf('$field_nodes = %s', json_encode($field_nodes))); if(!$multiple && getval("copyfrom","") == "" && getval('metadatatemplate', '') == "" && $check_edit_checksums) { echo ""; echo ""; } } elseif($field['type']==FIELD_TYPE_DATE_RANGE && !$blank_edit_template && getval("copyfrom","") == "" && getval('metadatatemplate', '') == "" && $check_edit_checksums) { $field['node_options'] = get_nodes($field['ref'], null, false); $field_nodes = array(); foreach($selected_nodes as $selected_node) { if(in_array($selected_node,array_column($field['node_options'],"ref"))) { $field_nodes[] = $selected_node; } } sort($field_nodes); debug(sprintf('$field_nodes = %s', json_encode($field_nodes))); echo ""; } elseif(!$multiple && !$blank_edit_template && getval("copyfrom","")=="" && getval('metadatatemplate', '') == "" && $check_edit_checksums) { echo ""; } elseif ($field['type'] === FIELD_TYPE_DATE && $GLOBALS['use_native_input_for_date_field']) { if ($GLOBALS['blank_date_upload_template'] && $value !== '' && $ref <= 0) { $value = ''; } } $is_search = false; include "edit_fields/{$type}.php"; $lastglobal = $field['global']==1; } # ---------------------------------------------------------------------------- # Display any error messages from previous save if (array_key_exists($field["ref"],$errors)) { ?>
!! !!
clear:left; display:none;" id="help_">
" class="ExifOptions" cellpadding="3" cellspacing="3" style="display: none;" >
" name="exif_option_" value="yes" checked> " name="exif_option_" value="no"> " name="exif_option_" value="append"> " name="exif_option_" value="prepend">
=1) { $found_start_year = $ss[0] ?? ""; $found_start_month = $ss[1] ?? ""; $found_start_day = $ss[2] ?? ""; } $se=explode("-",$endvalue); if (count($se)>=1) { $found_end_year = $se[0] ?? ""; $found_end_month = $se[1] ?? ""; $found_end_day = $se[2] ?? ""; } // If the form has been submitted (but not reset) but data was not saved get the submitted values if($reset == "") { foreach(array("start_y", "start-m","start-d","end-y","end-m","end-d") as $subpart) { if(getval($name . "_" . $subpart,"") != "") { ${"found_" . $subpart} = escape(getval($name . "_" . $subpart,"")); } } } if($daterange_edtf_support) { // Use EDTF format for date input ?> " name="_edtf" id="_edtf" type="text" value="" style="display:none;" disabled onChange="UpdateResultCount();" onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"onChange="AutoSave('');">
onChange="UpdateResultCount();" onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"onChange="if(sufficientDateParts('_start')){AutoSave('');}">
onChange="UpdateResultCount();" onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"onChange="if(sufficientDateParts('_end')){AutoSave('');}">
">

">

"> <?php echo str_replace(array(" />
0 && $imagedata['thumb_height'] > 0 ) { $ratio = $imagedata["thumb_width"] / $imagedata["thumb_height"]; } else { $size = $img_url != "" ? getimagesize($img_url) : []; $ratio = isset($size[0]) ? $size[0] / $size[1] : 1; } switch($display) { case "xlthumbs": $defaultwidth = 320; $defaultheight = 320; break; case "thumbs": $defaultwidth = 200; $defaultheight = 200; break; case "list": $defaultwidth = 40; $defaultheight = 40; break; case "col": $defaultwidth = $imagedata['thumb_width']; $defaultheight = $imagedata['thumb_height']; break; default: $defaultwidth = 75; $defaultheight = 75; break; } if ($ratio > 1) { $width = $defaultwidth; $height = round($defaultwidth / $ratio); $margin = floor(($defaultheight - $height ) / 2); } elseif ($ratio < 1) { # portrait image dimensions $height = $defaultheight; $width = round($defaultheight * $ratio); $margin = floor(($defaultheight - $height ) / 2); } else { # square image or no image dimensions $height = $defaultheight; $width = $defaultwidth; $margin = "auto"; } return array($width, $height, $margin); } /** * Render the share options (used on collection_share.php and resource_share.php) * * @param array $shareopts Array of share options. If not set will use the old getval() methods * "password" bool Has a password been set for this share? (password will not actually be displayed) * "editaccesslevel" int Current access level of share * "editexpiration" string Current expiration date * "editgroup" int ID of existing share group * @return void */ function render_share_options($shareopts=array()) { global $lang, $usergroup,$minaccess,$allowed_external_share_groups,$resource_share_expire_never; global $resource_share_expire_days,$resource_share_expire_days_default; $password = $shareopts['password'] ?? getval('password', ''); $editaccesslevel = $shareopts['editaccesslevel'] ?? getval('editaccesslevel', ''); $editexpiration = $shareopts['editexpiration'] ?? getval('editexpiration', null); $editgroup = $shareopts['editgroup'] ?? getval('editgroup', ''); if ( $editexpiration === "" && $resource_share_expire_days_default > 0 || $editexpiration != "" && date('Y-m-d', strtotime($editexpiration)) < date('Y-m-d',time()) ) { $editexpiration = date('Y-m-d',time() + (60*60*24*$resource_share_expire_days_default)); } if(!hook('replaceemailaccessselector')) {?>
0) { $fieldtypefilter = " WHERE type IN (" . ps_param_insert(count($ftypes)) . ")"; $parameters = ps_param_fill($ftypes, "i"); } $fields = ps_query("SELECT " . columns_in("resource_type_field") . " from resource_type_field " . (($fieldtypefilter=="")?"":$fieldtypefilter) . " ORDER BY title, name", $parameters, "schema"); echo ""; } /** * Render a filter bar button * * @param string $text Button text * @param string $attr Button attributes * @param string $icon HTML for icon element (e.g "") * * @return void */ function render_filter_bar_button($text, $attr, $icon) { ?>
'; if($forjs) { return str_replace(array("\r","\n"),"",$trash_html); } else { echo $trash_html; } } /** * Renders the browse bar * * @return void */ function render_browse_bar() { global $lang, $browse_bar_workflow, $enable_themes; $bb_html = ''; echo $bb_html; echo ''; } /** * Generates a root row item for the browse bar * * @return string $html */ function generate_browse_bar_item($id, $text) { $html = '
'; $html .= '
'; $html .= '
'; $html .= ''; $html .= ''; $html .= "
"; return $html; } /** * Generates a help icon that opens the relevant Knowledge Base article in a modal * * @param string $page Knowledge Base article to display, leave blank to show the Knowledge Base homepage * @param boolean $return_string Set to true to return the html as a single line string, False will cause the function to echo the html * * @return mixed if $return_string=true return is string, else void */ function render_help_link($page='',$return_string=false) { global $lang,$help_modal,$baseurl; // Build html for link into a string $help_link_html = '
class="Question">
*" : ""); ?>
>
$USER_SELECTION_COLLECTION)); $x_selected = '' . number_format($i) . " {$lang["selected"]}"; return "
{$x_selected}"; } /** * Renders the "Edit selected" button. This is using the special 'COLLECTION_TYPE_SELECTION' collection * * @return void */ function render_edit_selected_btn() { global $baseurl_short, $lang, $USER_SELECTION_COLLECTION, $restypes, $archive; $search = "!collection{$USER_SELECTION_COLLECTION}"; # Editable_only=true (so returns editable resources only) $editable_resources = do_search($search, $restypes, "resourceid", $archive, -1, "desc", false, 0, false, false, "", false, false, true, true); # Editable_only=false (so returns resources whether editable or not) $all_resources = do_search($search, $restypes, "resourceid", $archive, -1, "desc", false, 0, false, false, "", false, false, true, false); # If there are no editable resources then don't render the edit selected button # Setup count of editable resources $editable_resources_count = 0; $editable_resource_refs=array(); if(is_array($editable_resources)) { $editable_resources_count = count($editable_resources); $editable_resource_refs=array_column($editable_resources,"ref"); } # Setup count of editable and non-editable resources $all_resources_count = 0; $all_resource_refs=array(); if(is_array($all_resources)) { $all_resources_count = count($all_resources); $all_resource_refs=array_column($all_resources,"ref"); } # If both counts are zero then there cannot be any editable resources, so no edit selected button if($editable_resources_count == 0 && $all_resources_count == 0) { return; } # If not all selected resources are editable then the edit selected button may be inappropriate if($editable_resources_count != $all_resources_count) { # Counts differ meaning there are non-editable resources $non_editable_resource_refs=array_diff($all_resource_refs,$editable_resource_refs); # Is grant edit present for all non-editables? foreach($non_editable_resource_refs as $non_editable_ref) { if ( !hook('customediteaccess','',array($non_editable_ref)) ) { return; } } # All non_editables have grant edit # Don't return as edit button can be rendered } $batch_edit_url = generateURL( "{$baseurl_short}pages/edit.php", array( "search" => $search, "collection" => $USER_SELECTION_COLLECTION, "restypes" => $restypes, "order_by" => "resourceid", "archive" => $archive, "sort" => "desc", "daylimit" => "", "editsearchresults" => "true", "modal" => "true", )); $attributes = " id=\"EditSelectedResourcesBtn\""; $attributes .= " onclick=\"ModalLoad('{$batch_edit_url}', true);\""; render_filter_bar_button($lang["edit_selected"], $attributes, ICON_EDIT); } /** * Renders the "Clear selected" button. This is using the special 'COLLECTION_TYPE_SELECTION' collection * * @return void */ function render_clear_selected_btn() { global $lang, $USER_SELECTION_COLLECTION, $CSRF_token_identifier, $usersession; $attributes = " id=\"ClearSelectedResourcesBtn\" class=\"ClearSelectedButton\""; $attributes .= " onclick=\"ClearSelectionCollection(this);\""; $attributes .= " data-csrf-token-identifier=\"{$CSRF_token_identifier}\""; $attributes .= " data-csrf-token=\"" . generateCSRFToken($usersession, "clear_selected_btn_{$USER_SELECTION_COLLECTION}") . "\""; render_filter_bar_button($lang["clear_selected"], $attributes, ICON_REMOVE); } /** * Render the actions specific to when a user selected resources (using the special "COLLECTION_TYPE_SELECTION" collection) * * @return void */ function render_selected_collection_actions() { global $USER_SELECTION_COLLECTION, $usercollection, $usersession, $lang, $CSRF_token_identifier, $search, $render_actions_extra_options, $render_actions_filter, $resources_count, $result; $orig_resources_count = $resources_count; $orig_search = $search; $search = "!collection{$USER_SELECTION_COLLECTION}"; $orig_result = $result; $result = get_collection_resources_with_data($USER_SELECTION_COLLECTION); $selected_resources = array_column($result, "ref"); $resources_count = count($selected_resources); $usercollection_resources = get_collection_resources($usercollection); $refs_to_remove = count(array_intersect($selected_resources, $usercollection_resources)); $collection_data = get_collection($USER_SELECTION_COLLECTION); $valid_selection_collection_actions = array( "relate_all", "save_search_items_to_collection", "remove_selected_from_collection", "search_items_disk_usage", "csv_export_results_metadata", "share_collection", "download_collection", "license_batch", "consent_batch", 'delete_all_in_collection', ); if($refs_to_remove > 0) { $callback_csrf_token = generateCSRFToken($usersession, "collection_remove_resources"); $render_actions_extra_options = array( array( "value" => "remove_selected_from_collection", "label" => $lang["remove_selected_from_collection"], "data_attr" => array( "callback" => "RemoveSelectedFromCollection('{$CSRF_token_identifier}', '{$callback_csrf_token}');", ), "category" => ACTIONGROUP_COLLECTION, ), ); } $render_actions_filter = function($action) use ($valid_selection_collection_actions) { return in_array($action["value"], $valid_selection_collection_actions); }; // override the language for actions as it's now specific to a selection of resources $lang["relateallresources"] = $lang["relate_selected_resources"]; $lang["savesearchitemstocollection"] = $lang["add_selected_to_collection"]; $lang["searchitemsdiskusage"] = $lang["selected_items_disk_usage"]; $lang["share"] = $lang["share_selected"]; $lang['deleteallresourcesfromcollection'] = $lang['deleteselectedfromcollection']; $lang["deleteallsure"] = $lang['deleteallselectedsure']; render_actions($collection_data, true, false); $search = $orig_search; $result = $orig_result; $resources_count = $orig_resources_count; } // Render a select input for a user's collections function render_user_collection_select($name = "collection", $collections=array(), $selected=0, $classes = "", $onchangejs = "") { global $userref,$hidden_collections,$active_collections,$lang; if(count($collections) == 0) { $collections = get_user_collections($userref); } echo ""; } /** * Render CSRF information as data attributes. Useful to allow JS to run state changing operations */ function render_csrf_data_attributes($ident) { global $CSRF_token_identifier, $usersession; $token = generateCSRFToken($usersession, $ident); return "data-csrf-token-identifier=\"{$CSRF_token_identifier}\" data-csrf-token=\"{$token}\""; } /** * Check display condition for a field. * * @uses get_nodes() * @uses extract_node_options() * @uses get_resource_nodes() * @uses get_node_by_name() * * @param integer $n Question sequence number on the rendered form * @param array $field Field on which we check display conditions * @param array $fields Resource field data and properties as returned by get_resource_field_data() * @param boolean $render_js Set to TRUE to render the client side code for checking display conditions or FALSE otherwise * @param integer $resource_ref Resource reference for which the display condition applies * * @return boolean Returns TRUE if no display condition or if field should be displayed or FALSE if field should not be displayed. */ function check_display_condition($n, array $field, array $fields, $render_js, int $resource_ref) { debug_function_call(__FUNCTION__, [$n, $field['ref'], ['ignored on purpose - too verbose'], $render_js]); global $required_fields_exempt, $blank_edit_template, $ref, $use, $FIXED_LIST_FIELD_TYPES; if(trim((string) $field['display_condition']) == "") { return true; # This field does not have a display condition, so it should be displayed } debug(sprintf('$use = %s', json_encode($use))); // Assume the candidate field is to be displayed $displaycondition = true; // Break down into array of conditions $conditions = explode(';', $field['display_condition']); $condref = 0; $scriptconditions = array(); // Need all field data to check display conditions global $display_check_data; if(!is_array($display_check_data)) { $display_check_data = get_resource_field_data($use,false,false); debug('Loaded $display_check_data'); } // On upload, check against the posted nodes as save_resource_data() saves nodes after going through all the fields $user_set_values = getval('nodes', [], false, 'is_array'); debug(sprintf('$user_set_values = %s', json_encode($user_set_values))); foreach ($conditions as $condition) # Check each condition { debug(sprintf('field #%s - checking condition "%s"', $field['ref'], $condition)); $displayconditioncheck = false; // Break this condition down into fieldname $s[0] and value(s) $s[1] $s = explode('=', $condition); // Process all fields which are referenced by display condition(s) on the candidate field // For each referenced field, render javascript to trigger when the referenced field changes for ($cf=0;$cf