'; $html = [ // Simple HTML. 0 => ['prefix' => '

', 'suffix' => '

'], // Tricky HTML5 example that's unsupported by PHP <=5.4's DOMDocument: // https://www.drupal.org/comment/7938201#comment-7938201. 1 => ['prefix' => '

', 'suffix' => '

' . $edge_case_html5 . '
'], // Multi-byte content *before* the HTML that needs the "is-active" class. 2 => ['prefix' => '

αβγδεζηθικλμνξοσὠ

', 'suffix' => '

'], ]; $tags = [ // Of course, it must work on anchors. 'a', // Unfortunately, it must also work on list items. 'li', // … and therefore, on *any* tag, really. 'foo', ]; $contents = [ // Regular content. 'test', // Mix of UTF-8 and HTML entities, both must be retained. '☆ 3 × 4 = €12 and 4 × 3 = €12 ☆', // Multi-byte content. 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ', // Text that closely approximates an important attribute, but should be // ignored. 'data-drupal-link-system-path="<front>"', ]; // Define all variations that *do* affect whether or not an "is-active" // class is set: all possible situations that can be encountered. $situations = []; // Situations with context: front page, English, no query. $context = [ 'path' => 'myfrontpage', 'front' => TRUE, 'language' => 'en', 'query' => [], ]; // Nothing to do. $markup = 'bar'; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => []]; // Matching path, plus all matching variations. $attributes = [ 'data-drupal-link-system-path' => 'myfrontpage', ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'en']]; // Matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => TRUE]]; // Special matching path, plus all variations. $attributes = [ 'data-drupal-link-system-path' => '', ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'en']]; // Special matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => TRUE]]; // Situations with context: non-front page, Dutch, no query. $context = [ 'path' => 'llama', 'front' => FALSE, 'language' => 'nl', 'query' => [], ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => []]; // Matching path, plus all matching variations. $attributes = [ 'data-drupal-link-system-path' => 'llama', ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'nl']]; // Matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Special non-matching path, plus all variations. $attributes = [ 'data-drupal-link-system-path' => '', ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => '{"foo":"bar"}']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Situations with context: non-front page, Dutch, with query. $context = [ 'path' => 'llama', 'front' => FALSE, 'language' => 'nl', 'query' => ['foo' => 'bar'], ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => []]; // Matching path, plus all matching variations. $attributes = [ 'data-drupal-link-system-path' => 'llama', 'data-drupal-link-query' => Json::encode(['foo' => 'bar']), ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'nl']]; // Matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Special non-matching path, plus all variations. $attributes = [ 'data-drupal-link-system-path' => '', ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Situations with context: non-front page, Dutch, with query. $context = [ 'path' => 'llama', 'front' => FALSE, 'language' => 'nl', 'query' => ['foo' => 'bar'], ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => []]; // Matching path, plus all matching variations. $attributes = [ 'data-drupal-link-system-path' => 'llama', 'data-drupal-link-query' => Json::encode(['foo' => 'bar']), ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'nl']]; // Matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Special non-matching path, plus all variations. $attributes = [ 'data-drupal-link-system-path' => '', ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl', 'data-drupal-link-query' => TRUE]]; // Situations with context: front page, English, query. $context = [ 'path' => 'myfrontpage', 'front' => TRUE, 'language' => 'en', 'query' => ['foo' => 'bar'], ]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => []]; // Matching path, plus all matching variations. $attributes = [ 'data-drupal-link-system-path' => 'myfrontpage', 'data-drupal-link-query' => Json::encode(['foo' => 'bar']), ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'en']]; // Matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => TRUE]]; // Special matching path, plus all variations. $attributes = [ 'data-drupal-link-system-path' => '', 'data-drupal-link-query' => Json::encode(['foo' => 'bar']), ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes + ['hreflang' => 'en']]; // Special matching path, plus all non-matching variations. $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'nl']]; unset($attributes['data-drupal-link-query']); $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['data-drupal-link-query' => TRUE]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => ""]]; $situations[] = ['context' => $context, 'is active' => FALSE, 'attributes' => $attributes + ['hreflang' => 'en', 'data-drupal-link-query' => TRUE]]; // Query with unsorted keys must match when the attribute is in sorted form. $context = [ 'path' => 'myfrontpage', 'front' => TRUE, 'language' => 'en', 'query' => ['foo' => 'bar', 'baz' => 'qux'], ]; $attributes = [ 'data-drupal-link-system-path' => 'myfrontpage', 'data-drupal-link-query' => Json::encode(['baz' => 'qux', 'foo' => 'bar']), ]; $situations[] = ['context' => $context, 'is active' => TRUE, 'attributes' => $attributes]; // Loop over the surrounding HTML variations. $data = []; for ($h = 0; $h < count($html); $h++) { $html_prefix = $html[$h]['prefix']; $html_suffix = $html[$h]['suffix']; // Loop over the tag variations. for ($t = 0; $t < count($tags); $t++) { $tag = $tags[$t]; // Loop over the tag contents variations. for ($c = 0; $c < count($contents); $c++) { $tag_content = $contents[$c]; $create_markup = function (Attribute $attributes) use ($html_prefix, $html_suffix, $tag, $tag_content) { return $html_prefix . '<' . $tag . $attributes . '>' . $tag_content . '' . $html_suffix; }; // Loop over the situations. for ($s = 0; $s < count($situations); $s++) { $situation = $situations[$s]; // Build the source markup. $source_markup = $create_markup(new Attribute($situation['attributes'])); // Build the target markup. If no "is-active" class should be set, // the resulting HTML should be identical. Otherwise, it should get // an "is-active" class, either by extending an existing "class" // attribute or by adding a "class" attribute. $target_markup = NULL; if (!$situation['is active']) { $target_markup = $source_markup; } else { $active_attributes = $situation['attributes']; if (!isset($active_attributes['class'])) { $active_attributes['class'] = []; } $active_attributes['class'][] = 'is-active'; $target_markup = $create_markup(new Attribute($active_attributes)); } $data[] = [$source_markup, $situation['context']['path'], $situation['context']['front'], $situation['context']['language'], $situation['context']['query'], $target_markup]; } } } } // Test case to verify that the 'is-active' class is not added multiple // times. $data[] = [ 0 => 'Once Twice', 1 => '', 2 => TRUE, 3 => 'en', 4 => [], 5 => 'Once Twice', ]; // Test cases to verify that the 'is-active' class is added when on the // front page, and there are two different kinds of matching links on the // page: // - the matching path (the resolved front page path) // - the special matching path ('') $front_special_link = 'Front'; $front_special_link_active = 'Front'; $front_path_link = 'Front Path'; $front_path_link_active = 'Front Path'; $data[] = [ 0 => $front_path_link . ' ' . $front_special_link, 1 => 'myfrontpage', 2 => TRUE, 3 => 'en', 4 => [], 5 => $front_path_link_active . ' ' . $front_special_link_active, ]; $data[] = [ 0 => $front_special_link . ' ' . $front_path_link, 1 => 'myfrontpage', 2 => TRUE, 3 => 'en', 4 => [], 5 => $front_special_link_active . ' ' . $front_path_link_active, ]; // Test cases to verify that links to the front page do not get the // 'is-active' class when not on the front page. $other_link = 'Other page'; $other_link_active = 'Other page'; $data['-and-other-link-on-other-path'] = [ 0 => $front_special_link . ' ' . $other_link, 1 => 'otherpage', 2 => FALSE, 3 => 'en', 4 => [], 5 => $front_special_link . ' ' . $other_link_active, ]; $data['front-and-other-link-on-other-path'] = [ 0 => $front_path_link . ' ' . $other_link, 1 => 'otherpage', 2 => FALSE, 3 => 'en', 4 => [], 5 => $front_path_link . ' ' . $other_link_active, ]; $data['other-and--link-on-other-path'] = [ 0 => $other_link . ' ' . $front_special_link, 1 => 'otherpage', 2 => FALSE, 3 => 'en', 4 => [], 5 => $other_link_active . ' ' . $front_special_link, ]; $data['other-and-front-link-on-other-path'] = [ 0 => $other_link . ' ' . $front_path_link, 1 => 'otherpage', 2 => FALSE, 3 => 'en', 4 => [], 5 => $other_link_active . ' ' . $front_path_link, ]; return $data; } /** * Tests setLinkActiveClass(). * * @param string $html_markup * The original HTML markup. * @param string $current_path * The system path of the currently active page. * @param bool $is_front * Whether the current page is the front page (which implies the current * path might also be ). * @param string $url_language * The language code of the current URL. * @param array $query * The query string for the current URL. * @param string $expected_html_markup * The expected updated HTML markup. * * @dataProvider providerTestSetLinkActiveClass * @covers ::setLinkActiveClass */ public function testSetLinkActiveClass($html_markup, $current_path, $is_front, $url_language, array $query, $expected_html_markup) { $this->assertSame($expected_html_markup, ActiveLinkResponseFilter::setLinkActiveClass($html_markup, $current_path, $is_front, $url_language, $query)); } }