le * Show/hide attributes based on the values of other attributes. * * Some attributes may not be applicable depending upon the value of another * attribute. It may be desireable to hide the attribute unless an appropriate * value is selected for the other attribute to avoid confusing users. This * module has an administrative interface for specifying the dependencies * and Javascript code for hiding and showing the attributes. */ /** * Implements hook_menu(). */ function uc_dropdown_attributes_menu() { $items = array(); $items['node/%node/edit/dependencies'] = array( 'title' => 'Dependencies', 'description' => 'Product attribute dependency administration.', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_dropdown_attributes_product', 1), 'access callback' => 'uc_attribute_product_access', 'access arguments' => array(1), 'theme callback' => 'uc_dropdown_attributes_admin_theme', 'type' => MENU_LOCAL_TASK, 'weight' => 1, 'file' => 'dependent_dropdown.inc', ); $items['node/%/dependencies/%/dependency/%'] = array( 'type' => MENU_CALLBACK, 'page callback' => 'uc_dropdown_attributes_dependency', 'page arguments' => array(1, 3, 5), 'access callback' => TRUE, ); $items['admin/store/products/classes/%/dependencies'] = array( 'title' => 'Dependencies', 'description' => 'Product class attribute dependency administration.', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_dropdown_attributes_class', 4), 'access arguments' => array('administer product classes'), 'file' => 'dependent_dropdown.inc', ); return $items; } /** * Implements hook_form_alter(). */ function uc_dropdown_attributes_form_alter(array &$form, array &$form_state, string $form_id): void { if (preg_match('/^uc_product_kit_add_to_cart_form.*/', $form_id)) { foreach ($form['products'] as $key => $value) { if (is_numeric($key)) { $type = uc_dropdown_attributes_dependency_type((int) $key); if (!is_null($type)) { $values = $form_state['values'] ?? []; uc_dropdown_attributes_product_alter((int) $key, $form['products'][$key], $values, $type, $form_state['rebuild']); if (!isset($form['#after_build']) || !in_array('_uc_dropdown_attributes_kit_build', $form['#after_build'])) { $form['#after_build'][] = '_uc_dropdown_attributes_kit_build'; } } } } } if (preg_match('/^uc_product_add_to_cart_form.*/', $form_id)) { $nid = $form['nid']['#value']; $type = uc_dropdown_attributes_dependency_type((int) $nid); if (!is_null($type)) { $values = $form_state['values'] ?? []; uc_dropdown_attributes_product_alter((int) $nid, $form, $values, $type, $form_state['rebuild']); $form['node_id'] = array( '#type' => 'hidden', '#value' => $nid, ); switch ($type) { case 'node': $form['#after_build'][] = '_uc_dropdown_attributes_product_build'; break; case 'class': $form['#after_build'][] = '_uc_dropdown_attributes_class_build'; break; } } } } /** * Alter products in preparation for drop down attributes. * * Adds the 'Please select' and removes the default value. Ubercart does this * for required attributes but since these attributes can no longer be required * if the attributes are dependent then this reproduces the same thing. * * @param int $nid * Node ID. * @param array $form * Product form. * @param array $form_values * Values from $form_state. * @param string $type * 'node' for dependencies defined on the node level; * 'class' for dependencies defined on the product class. * @param bool $rebuild * Whether the form is being rebuilt. */ function uc_dropdown_attributes_product_alter(int $nid, array &$form, array $form_values, string $type, bool $rebuild): void { switch ($type) { case 'node': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $attributes = db_query($sql, array(':nid' => $nid)); break; case 'class': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type($nid); $attributes = db_query($sql, array(':pcid' => $pcid)); break; default: $attributes = new stdClass(); break; } $parent_aids = array(); if (!$rebuild) { $data = $form['node']['#value']->data; } $load = FALSE; foreach ($attributes as $attribute) { $parent_aids[$attribute->parent_aid] = $attribute->parent_aid; if (isset($form['attributes'][$attribute->aid]['#options']) && count($form['attributes'][$attribute->aid]['#options']) && $attribute->required) { switch ($form['attributes'][$attribute->aid]['#type']) { case 'select': $form['attributes'][$attribute->aid]['#options'] = array('' => t('Please select')) + $form['attributes'][$attribute->aid]['#options']; $form['attributes'][$attribute->aid]['#default_value'] = ''; if (!$rebuild && isset($data['attributes'][$attribute->aid])) { $data['attributes'][$attribute->aid] = ''; $load = TRUE; } break; case 'radios': $form['attributes'][$attribute->aid]['#default_value'] = NULL; if (!$rebuild && isset($data['attributes'][$attribute->aid])) { $data['attributes'][$attribute->aid] = ''; $load = TRUE; } // Validation does not work if required set later. if (isset($form_values['attributes'][$attribute->parent_aid])) { $parent_value = $form_values['attributes'][$attribute->parent_aid]; $values = unserialize($attribute->parent_values); $parent_aid = $attribute->parent_aid; if (is_array($values) && in_array($parent_value, $values)) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } break; case 'checkboxes': $form['attributes'][$attribute->aid]['#default_value'] = array(); if (!$rebuild && isset($data['attributes'][$attribute->aid])) { $data['attributes'][$attribute->aid] = array(); $load = TRUE; } break; } } } if ($load) { $form['node']['#value'] = uc_product_load_variant($nid, $data); } $update_node = variable_get('uc_product_update_node_view', 0); if (!$update_node) { // If Ubercart update is not enabled then ajax needs to be attached to // parent attributes. foreach ($parent_aids as $aid) { $form['attributes'][$aid]['#ajax'] = array( 'callback' => 'uc_dropdown_attributes_ajax_callback', 'wrapper' => $form['attributes']['#id'], ); } } } /** * Ajax callback for attribute selection form elements. */ function uc_dropdown_attributes_ajax_callback(array $form, array $form_state) { if (count($form_state['triggering_element']['#parents']) == 4) { // This is a product kit. $key = $form_state['triggering_element']['#parents'][1]; return $form['products'][$key]['attributes']; } return $form['attributes']; } /** * Form build for products. * * Callback for $form['#after_build'] for products. Adds the CSS to hide * the dependent attributes. */ function _uc_dropdown_attributes_product_build(array $form, array &$form_state) { $nid = $form['nid']['#value']; $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $attributes = db_query($sql, array(':nid' => $nid)); if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents) - 1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, (int) $nid, 'node', $form_state['values']); } foreach ($attributes as $attribute) { if (!isset($form_state['values']['attributes'][$attribute->parent_aid])) { continue; } $parent_value = $form_state['values']['attributes'][$attribute->parent_aid]; if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') { $parent_values = array_diff((array) $parent_value, array(0)); $values = unserialize($attribute->parent_values); if (is_array($values) && count(array_intersect($parent_values, $values))) { // Show dependent attribute. if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { // Hide dependent attribute. $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $attribute->aid); } } else { if ($parent_value) { // A value has been entered in parent attribute. $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { // Show dependent attribute. if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { // Hide dependent attribute. $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $attribute->aid); } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $attribute->aid); } } } return $form; } /** * Clear inputs for attribute. * * @param array $form * Form array. * @param array $form_state * Form state array. * @param int $aid * Attribute ID. */ function uc_dropdown_attributes_clear_input(array &$form, array &$form_state, int $aid): void { // Use nullsafe operator and null coalescing for PHP 8.0 compatibility $attributes_input = $form_state['input']['attributes'] ?? null; if ($attributes_input === null || !isset($form['attributes'][$aid])) { return; } $type = $form['attributes'][$aid]['#type'] ?? null; if ($type === null) { return; } switch ($type) { case 'checkboxes': if (isset($attributes_input[$aid])) { foreach ($attributes_input[$aid] as $oid => $value) { $form_state['input']['attributes'][$aid][$oid] = NULL; } } break; case 'radios': case 'select': $form_state['input']['attributes'][$aid] = ''; break; case 'textfield': $form_state['input']['attributes'][$aid] = ''; break; default: break; } } /** * Form build for classes. * * Callback for $form['#after_build'] for product classes. Adds * the CSS to hide the dependent attributes. */ function _uc_dropdown_attributes_class_build(array $form, array &$form_state) { $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type($form['nid']['#value']); $attributes = db_query($sql, array(':pcid' => $pcid)); if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents) - 1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['values']); } $parent_value = null; // Initialize parent_value before the loop foreach ($attributes as $attribute) { if (isset($form_state['values']['attributes'])) { $parent_value = $form_state['values']['attributes'][$attribute->parent_aid]; } if ($parent_value) { $values = unserialize($attribute->parent_values); if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') { $parent_values = array_diff((array) $parent_value, array(0)); if (is_array($values) && count(array_intersect($parent_values, $values))) { if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (count($form['attributes'][$attribute->aid]['#value']) > 0) { $form['attributes'][$attribute->aid]['#value'] = array(); } } } else { if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if ($form['attributes'][$attribute->aid]['#value'] != '') { $form['attributes'][$attribute->aid]['#value'] = ''; } } } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form['attributes'][$attribute->aid]['#value']) && $form['attributes'][$attribute->aid]['#value'] != '') { $form['attributes'][$attribute->aid]['#value'] = ''; } } } return $form; } /** * Form build for product kits. * * Callback for $form['#after_build'] for product kits. Renders the dependent * attributes and stores the html as a Javascript array. */ function _uc_dropdown_attributes_kit_build(array $form, array &$form_state) { foreach ($form['products'] as $key => $value) { if (is_numeric($key)) { $type = uc_dropdown_attributes_dependency_type((int) $key); switch ($type) { case 'node': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $id = $key; $attributes = db_query($sql, array(':nid' => $key)); break; case 'class': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type((int) $key); $id = $pcid; $attributes = db_query($sql, array(':pcid' => $pcid)); break; default: $attributes = array(); break; } if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents) - 1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, $id, $type, $form_state['values']['products'][$key]); } foreach ($attributes as $attribute) { $aid = $attribute->aid; $parent_aid = $attribute->parent_aid; $parent_value = $form_state['values']['products'][$key]['attributes'][$parent_aid]; if ($parent_value) { $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['products'][$key]['attributes'][$aid]['#required'] = TRUE; } } else { $form['products'][$key]['attributes'][$aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if ($form['products'][$key]['attributes'][$aid]['#value'] != '') { $form['products'][$key]['attributes'][$aid]['#value'] = ''; } } } else { $form['products'][$key]['attributes'][$aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if ($form['products'][$key]['attributes'][$aid]['#value'] != '') { $form['products'][$key]['attributes'][$aid]['#value'] = ''; } } } } } return $form; } /** * Unset values of orphaned children. * * Called recursively to remove orphaned values from form_state. * * @param int $parent_aid * Attribute ID of the triggering element. * @param mixed $parent_value * Option ID of the value of the triggering element. * @param mixed $id * Node ID or product class ID. * @param string $type * 'node' or 'class'. * @param array $form_values * Part of the form_state array containing the attributes. */ function uc_dropdown_attributes_remove_values(int $parent_aid, $parent_value, $id, string $type, array &$form_values): void { switch ($type) { case 'node': $sql = 'SELECT aid, required, parent_values FROM {uc_dropdown_attributes} WHERE nid=:nid AND parent_aid=:parent_aid'; $children = db_query($sql, array( ':nid' => $id, ':parent_aid' => $parent_aid) ); break; case 'class': $sql = 'SELECT aid, required, parent_values FROM {uc_dropdown_classes} WHERE pcid=:pcid AND parent_aid=:parent_aid'; $children = db_query($sql, array( ':pcid' => $id, ':parent_aid' => $parent_aid) ); break; default: $children = array(); break; } foreach ($children as $child) { if ($child->required) { if (isset($form_values['attributes'][$child->aid])) { $value = $form_values['attributes'][$child->aid]; $form_values['attributes'][$child->aid] = ''; if ($value) { $values = unserialize($child->parent_values); if (is_array($values) && !in_array($parent_value, $values)) { uc_dropdown_attributes_remove_values((int) $child->aid, $value, $id, $type, $form_values); } } } } } } /** * Add the style to hide the attribute. * * @param string $html * HTML for the element. * * @return string * Modified element HTML. */ function uc_dropdown_attributes_post_render(string $html): string { $pos = strpos($html, '>'); if ($pos !== false) { $html = substr_replace($html, ' style="display:none;">', $pos, 1); } return $html; } /** * Retrieves the attribute dependencies. * * Callback to supply attribute dependencies to Javascript. * * @param int $nid * Node ID. * @param string $id * String containing attribute ID. * * @return object * JSON structure. */ function uc_dropdown_attributes_dependency(int $nid, string $id, string $parent_id) { $temp = explode('-', $id); if ($temp[1] == 'attributes') { $aid = $temp[2]; } else { $aid = $temp[4]; } $result = new stdClass(); $query = 'SELECT parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid && aid=:aid'; $db_result = db_query($query, array(':nid' => $nid, ':aid' => $aid)); foreach ($db_result as $item) { $result->status = TRUE; $result->nid = $nid; $result->id = $id; $result->parent_id = $parent_id; $result->parent_values = unserialize($item->parent_values); $result->required = $item->required; drupal_json_output($result); return; } $pcid = uc_dropdown_attributes_get_type($nid); $query = 'SELECT parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid && aid=:aid'; $db_result = db_query($query, array(':pcid' => $pcid, ':aid' => $aid)); foreach ($db_result as $item) { $result->status = TRUE; $result->nid = $nid; $result->id = $id; $result->parent_id = $parent_id; $result->parent_values = unserialize($item->parent_values); $result->required = $item->required; drupal_json_output($result); return; } $result->status = FALSE; drupal_json_output($result); } /** * Create an attribute dependency. * * A public function that creates and stores an attribute dependency for a * product. * * @param int $nid * Node ID. * @param int $aid * Attribute ID of the dependent (child) attribute. * @param int $parent_aid * Attribute ID of the parent attribute. * @param array $options * Array of the Option IDs that trigger the dependent attribute. * @param bool $required * TRUE if the dependent (child) attribute is required when it appears and * FALSE if it is not required. */ function uc_dropdown_attributes_product_create_dependency(int $nid, int $aid, int $parent_aid, array $options, bool $required): void { $attribute = uc_attribute_load($aid); $dep = db_insert('uc_dropdown_attributes') ->fields(array( 'nid' => $nid, 'aid' => $aid, 'parent_aid' => $parent_aid, 'parent_values' => serialize($options), 'required' => $required, )) ->execute(); // Need to check to make sure attribute is not required all the time. $sql = 'SELECT nid, aid, required FROM {uc_product_attributes} WHERE nid=:nid && aid=:aid'; $result = db_query($sql, array(':nid' => $nid, ':aid' => $aid)); foreach ($result as $item) { if ($item->required == 1) { $dep = db_update('uc_product_attributes') ->fields(array( 'required' => 0, )) ->condition('nid', $item->nid) ->condition('aid', $item->aid) ->execute(); } } } /** * Create an attribute dependency for product classes. * * A public function that creates and stores an attribute dependency for * product classes. * * @param int $pcid * Product class ID. * @param int $aid * Attribute ID of the dependent (child) attribute. * @param int $parent_aid * Attribute ID of the parent attribute. * @param array $options * Array of the Option IDs that trigger the dependent attribute. * @param bool $required * TRUE if the dependent (child) attribute is required when it appears and * FALSE if it is not required. */ function uc_dropdown_attributes_class_create_dependency(int $pcid, int $aid, int $parent_aid, array $options, bool $required): void { $attribute = uc_attribute_load($aid); $dep = db_insert('uc_dropdown_classes') ->fields(array( 'pcid' => $pcid, 'aid' => $aid, 'parent_aid' => $parent_aid, 'parent_values' => serialize($options), 'required' => $required, )) ->execute(); // Need to check to make sure attribute is not required all the time. $sql = 'SELECT pcid, aid, required FROM {uc_class_attributes} WHERE pcid=:pcid && aid=:aid'; $result = db_query($sql, array(':pcid' => $pcid, ':aid' => $aid)); foreach ($result as $item) { if ($item->required == 1) { $dep = db_update('uc_class_attributes') ->fields(array( 'required' => 0, )) ->condition('pcid', $item->pcid) ->condition('aid', $item->aid) ->execute(); } } } /** * Implements hook_theme(). */ function uc_dropdown_attributes_theme(): array { return array( 'uc_dropdown_attributes_product' => array( 'render element' => 'form', ), 'uc_dropdown_attributes_class' => array( 'render element' => 'form', ), ); } /** * Retrieve product class from the node ID. * * @param int $nid * Node id. * * @return string * The type field from the node object. */ function uc_dropdown_attributes_get_type(int $nid): string { $sql = 'SELECT type FROM {node} WHERE nid=:nid'; $type = db_query($sql, array(':nid' => $nid))->fetchField(); return $type; } /** * Retrieve whether dependencies are defined by node or class. * * @param int $nid * Node id. * * @return string|null * 'node' for dependencies defined on the node level; * 'class' for dependencies defined on the product class; otherwise, NULL. */ function uc_dropdown_attributes_dependency_type(int $nid): ?string { $sql = 'SELECT COUNT(*) FROM {uc_dropdown_attributes} WHERE nid=:nid'; $count = db_query($sql, array(':nid' => $nid))->fetchField(); if ($count > 0) { return 'node'; } $pcid = uc_dropdown_attributes_get_type($nid); $sql = 'SELECT COUNT(*) FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $count = db_query($sql, array(':pcid' => $pcid))->fetchField(); if ($count > 0) { return 'class'; } return NULL; } /** * Determine the correct theme to use for dependencies admin page. * * @return string * theme to use or empty string if default theme. */ function uc_dropdown_attributes_admin_theme(): string { if (variable_get('node_admin_theme', 0) == 1) { return (string)variable_get('admin_theme', ''); } return ''; } /** * Implements hook_form_FORM_ID_alter() for uc_order_edit_form(). */ function uc_dropdown_attributes_form_uc_order_edit_form_alter(array &$form, array &$form_state): void { if (isset($form_state['products_action']) && $form_state['products_action'] == 'add_product') { $product_type = $form['product_controls']['node']['#value']->type; if ($product_type == 'product_kit') { foreach ($form['product_controls']['sub_products'] as $nid => $product) { if (is_numeric($nid)) { $type = uc_dropdown_attributes_dependency_type((int) $nid); if (!is_null($type)) { uc_dropdown_attributes_order_product_alter((int) $nid, $form['product_controls']['sub_products'][$nid]['attributes'], $type); if (!in_array('_uc_dropdown_attributes_order_product_kit_build', $form['#after_build'])) { $form['#after_build'][] = '_uc_dropdown_attributes_order_product_kit_build'; } } } } } else{ $nid = $form['product_controls']['node']['#value']->nid; $type = uc_dropdown_attributes_dependency_type((int) $nid); if (!is_null($type)) { uc_dropdown_attributes_order_product_alter((int) $nid, $form['product_controls']['attributes'], $type); $form['nid'] = array( '#type' => 'hidden', '#value' => $nid, ); switch ($type) { case 'node': $form['#after_build'][] = '_uc_dropdown_attributes_order_product_build'; break; case 'class': $form['#after_build'][] = '_uc_dropdown_attributes_order_class_build'; break; } } } } } /** * Alter products on oder page in preparation for drop down attributes. * * Adds the 'Please select' and removes the default value. Ubercart does this * for required attributes but since these attributes can no longer be required * if the attributes are dependent then this reproduces the same thing. * * @param int $nid * Node ID. * @param array $form_attributes * Attributes part of the product form. * @param string $type * 'node' for dependencies defined on the node level; * 'class' for dependencies defined on the product class. */ function uc_dropdown_attributes_order_product_alter(int $nid, array &$form_attributes, string $type): void { switch ($type) { case 'node': $sql = 'SELECT aid, parent_aid, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $attributes = db_query($sql, array(':nid' => $nid)); break; case 'class': $sql = 'SELECT aid, parent_aid, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type($nid); $attributes = db_query($sql, array(':pcid' => $pcid)); break; } $parent_aids = array(); foreach ($attributes as $attribute) { $parent_aids[$attribute->parent_aid] = $attribute->parent_aid; if (isset($form_attributes[$attribute->aid]['#options']) && count($form_attributes[$attribute->aid]['#options']) && $attribute->required) { switch ($form_attributes[$attribute->aid]['#type']) { case 'select': $form_attributes[$attribute->aid]['#options'] = array('' => t('Please select')) + $form_attributes[$attribute->aid]['#options']; $form_attributes[$attribute->aid]['#default_value'] = ''; break; case 'radios': $form_attributes[$attribute->aid]['#default_value'] = ''; break; case 'checkboxes': $form_attributes[$attribute->aid]['#default_value'] = array(); break; } } } foreach ($parent_aids as $aid) { $form_attributes[$aid]['#ajax'] = array( 'callback' => 'uc_dropdown_attributes_order_ajax_callback', 'wrapper' => $form_attributes['#id'], ); } } /** * Ajax callback for order attribute selection form elements. */ function uc_dropdown_attributes_order_ajax_callback(array $form, array $form_state) { if (in_array('sub_products', $form_state['triggering_element']['#parents'])) { // This is a product kit. $nid = $form_state['triggering_element']['#parents'][2]; return $form['product_controls']['sub_products'][$nid]['attributes']; } return $form['product_controls']['attributes']; } /** * Form build for products for the order page. * * Callback for $form['#after_build'] for products. Adds the CSS to hide * the dependent attributes. */ function _uc_dropdown_attributes_order_product_build(array $form, array &$form_state) { $nid = $form['nid']['#value']; $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $attributes = db_query($sql, array(':nid' => $nid)); if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents)-1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, (int) $nid, 'node', $form_state['values']['product_controls']); } uc_dropdown_attributes_order_attribute_display( $attributes, $form['product_controls']['attributes'], $form_state['values']['product_controls']['attributes'] ); return $form; } /** * Form build for classes for the order page. * * Callback for $form['#after_build'] for product classes. * Adds the CSS to hide the dependent attributes. */ function _uc_dropdown_attributes_order_class_build(array $form, array &$form_state) { $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type($form['nid']['#value']); $attributes = db_query($sql, array(':pcid' => $pcid)); if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents)-1]; $parent_value = $form_state['triggering_element']['#value']; // Note that values are stored in input, not values. uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['input']['product_controls']); } uc_dropdown_attributes_order_attribute_display( $attributes, $form['product_controls']['attributes'], $form_state['values']['product_controls']['attributes'] ); return $form; } /** * Form build for product kits for the order page. * * Callback for $form['#after_build'] for products. Adds the CSS to hide * the dependent attributes. */ function _uc_dropdown_attributes_order_product_kit_build(array $form, array &$form_state) { foreach ($form['product_controls']['sub_products'] as $nid => $product) { if (is_numeric($nid)) { $type = uc_dropdown_attributes_dependency_type((int) $nid); switch ($type) { case 'node': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_attributes} WHERE nid=:nid'; $attributes = db_query($sql, array(':nid' => $nid)); if (isset($form_state['triggering_element']) && $nid == $form_state['triggering_element']['#parents'][2]) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents)-1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, (int) $nid, 'node', $form_state['values']['product_controls']['sub_products'][$nid]); } uc_dropdown_attributes_order_attribute_display( $attributes, $form['product_controls']['sub_products'][$nid]['attributes'], $form_state['values']['product_controls']['sub_products'][$nid]['attributes'] ); break; case 'class': $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type((int) $nid); $attributes = db_query($sql, array(':pcid' => $pcid)); if (isset($form_state['triggering_element']) && $nid == $form_state['triggering_element']['#parents'][2]) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents)-1]; $parent_value = $form_state['triggering_element']['#value']; // Note that values are stored in input, not values. uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['input']['product_controls']['sub_products'][$nid]); } uc_dropdown_attributes_order_attribute_display( $attributes, $form['product_controls']['sub_products'][$nid]['attributes'], $form_state['values']['product_controls']['sub_products'][$nid]['attributes'] ); break; } } } return $form; } /** * Alter display of attributes on the oder page. * * @param array $attributes * Array of attribute dependency objects. * @param array &$form_attributes * Attributes part of the product form. * @param array $form_state_attributes * Attributes part of the product form_state. */ function uc_dropdown_attributes_order_attribute_display(array $attributes, array &$form_attributes, array $form_state_attributes): void { foreach ($attributes as $attribute) { if (!isset($form_state_attributes[$attribute->parent_aid])) { continue; } $parent_value = $form_state_attributes[$attribute->parent_aid]; if ($parent_value) { // A value has been entered in parent attribute. $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { // Show dependent attribute. if ($attribute->required) { $form_attributes[$attribute->aid]['#required'] = TRUE; } } else { // Hide dependent attribute. $form_attributes[$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form_attributes[$attribute->aid]['#value']) && $form_attributes[$attribute->aid]['#value'] != '') { $form_attributes[$attribute->aid]['#value'] = ''; } } } else { $form_attributes[$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form_attributes[$attribute->aid]['#value']) && $form_attributes[$attribute->aid]['#value'] != '') { $form_attributes[$attribute->aid]['#value'] = ''; } } } } /** * Form build for classes in product kits for the order page. * * Callback for $form['#after_build'] for product classes. Adds * the CSS to hide the dependent attributes. */ function _uc_dropdown_attributes_order_class_kit_build(array $form, array &$form_state) { $sql = 'SELECT aid, parent_aid, parent_values, required FROM {uc_dropdown_classes} WHERE pcid=:pcid'; $pcid = uc_dropdown_attributes_get_type($form['nid']['#value']); $attributes = db_query($sql, array(':pcid' => $pcid)); if (isset($form_state['triggering_element'])) { $parents = $form_state['triggering_element']['#parents']; $parent_aid = $parents[count($parents)-1]; $parent_value = $form_state['triggering_element']['#value']; uc_dropdown_attributes_remove_values((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['values']['product_controls']); } $parent_value = null; foreach ($attributes as $attribute) { if (isset($form_state['values']['product_controls']['attributes'][$attribute->parent_aid])) { $parent_value = $form_state['values']['product_controls']['attributes'][$attribute->parent_aid]; } if ($parent_value) { $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['product_controls']['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['product_controls']['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form['product_controls']['attributes'][$attribute->aid]['#value']) && $form['product_controls']['attributes'][$attribute->aid]['#value'] != '') { $form['product_controls']['attributes'][$attribute->aid]['#value'] = ''; } } } else { $form['product_controls']['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form['product_controls']['attributes'][$attribute->aid]['#value']) && $form['product_controls']['attributes'][$attribute->aid]['#value'] != '') { $form['product_controls']['attributes'][$attribute->aid]['#value'] = ''; } } } return $form; } /** * Implements hook_node_load(). * * Ubercart fails to load attributes for product classes. */ function uc_dropdown_attributes_node_load(array $nodes): void { foreach ($nodes as $node) { if (uc_product_is_product($node)) { if (empty($node->attributes)) { $node->attributes = uc_class_get_attributes($node->type); } } } }Sealcoating, Line Striping and Asphalt Contractors in New York | Asphalt Sealcoating Direct

You are here

Sealcoating, Line Striping and Asphalt Contractors in New York

Asphalt Driveway Contractor Directory:

We know that you may have landed at this website looking for information on maintaining your own Asphalt Driveway, and if you are like most, you're probably feeling a little overwhelmed because of all of the information.

If you have decided to hire a contractor, we invite you to use our free on-line Contractor Directory by choosing your state below. If your state is not available, we do not currently have any contractors listed in your area but we are working to update the list to provide you with the best choice of asphalt related contractors.

This is a list of Asphalt Driveway Contractors who claim to have the skill and experience to handle your Asphalt maintenance and repair needs. Please note, these companies are not endorsed or screened by us, so make sure you do your part to check on them before committing to do business. We provide the contractor directory as an easy way to find sealcoaters and asphalt pavement contractors in your area.

Note: Starting 2024, we are no longer accepting new business registrations for the contractor directory, and will sunset this feature completely, sometime in the future.

Accra

Albany

Amherst

Auburn

Averill Park

Binghamton

Bouckville

Brooklyn

Buffalo

Cameron Mills

Cazenovia

Centreach

Charlotte

Cheektowaga

Chittenango

Cicero

Clarence

Clifton Park

Cold Spring Harbor

Cuba

East Aurora

East Northport

Elwood

Fort Edward

Ft. Edward

Fulton

Gansevoort

Geneva

Ghana

Glens Falls

Gowanda

Greenlawn

Grove

Halfmoon

Hamburg

Hamilton

Hilton

Hudson Falls

Huntington

Huntington Station

Jamaica

Lake Grove

Lancaster

mahopac falls

Malta

Mechanicville

Melose

Montrose

Morrisville

Mount Sinai

Munnsville

New Hartford

New York

New York City

Niagara Falls

Northport

Oneida

Orange County

Orchard Park

Oswego

Plainfield

Poughkeepsie

Pulaski

putnam county

Queens

Queensbury

Ramsey

Rifton

Rochester

Rockland County

Rome

Saratoga Springs

Saugerties

Scarsdale

Schagticoke

Schenectady

Selkirk

somers

Staten Island

Stillwater

Syosset

Syracuse

Taberg

Tonawanda

Troy

Utica

Valhalla

Wading River

Walden

Wantagh

Waterford

Waterloo

Watertown

west Harrison

West Seneca

Westchester county

white plains

Williamson

yorktown heights