├── tagadelic.install
├── templates
└── tagadelic_taxonomy_cloud.tpl.php
├── tagadelic.info
├── lib
└── Drupal
│ └── tagadelic
│ └── Tests
│ ├── TagadelicTaxonomyTestBase.php
│ ├── TagadelicTestBase.php
│ ├── TagadelicTestCase.php
│ ├── TagadelicTaxonomyAdminWebTestCase.php
│ └── TagadelicTaxonomyTestCase.php
├── tagadelic_taxonomy.info
├── .travis.yml
├── tagadelic.css
├── tests
├── support
│ └── FakeDrupal.php
├── TagadelicTagTest.php
├── TagadelicTagToStringTest.php
├── TagadelicDrupalWrapperTest.php
├── TagadelicTagMethodsTest.php
└── TagadelicCloudTest.php
├── tagadelic.module
├── TagadelicDrupalWrapper.php
├── TagadelicCloud.php
├── tagadelic_taxonomy.module
├── TagadelicTag.php
└── README.md
/tagadelic.install:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/tagadelic_taxonomy_cloud.tpl.php:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/tagadelic.info:
--------------------------------------------------------------------------------
1 | name = Tagadelic
2 | description = "Tagadelic makes weighted tag clouds from any-ol' weighted list."
3 | core = 7.x
4 | dependencies[] = taxonomy
5 | package = "Taxonomy"
6 |
7 | ;files[] = tests/tagadelic_test_base.test
8 | ;files[] = tests/tagadelic.test
9 | files[] = tagadelic.module
10 | files[] = tagadelic.install
11 |
12 | files[] = TagadelicCloud.php
13 | files[] = TagadelicTag.php
14 | files[] = TagadelicDrupalWrapper.php
15 |
--------------------------------------------------------------------------------
/lib/Drupal/tagadelic/Tests/TagadelicTaxonomyTestBase.php:
--------------------------------------------------------------------------------
1 | $arg) {
26 | if (is_array($arg) && !empty($arg)) {
27 | $args[$id] = serialize($arg);
28 | }
29 | elseif (is_array($arg) && empty($arg)) {
30 | $args[$id] = "Array";
31 | }
32 | }
33 | $arglist = join(',', $args);
34 | return "{$func}({$arglist})";
35 | }
36 | //@codeCoverageIgnoreEnd
37 |
--------------------------------------------------------------------------------
/tests/TagadelicTagTest.php:
--------------------------------------------------------------------------------
1 | drupal = $this->getMock("TagadelicDrupalWrapper", array("check_plain", "l"));
21 | $this->drupal->expects($this->any())
22 | ->method('check_plain')
23 | ->will($this->returnArgument(0));
24 | $this->object = new TagadelicTag(42, "blackbeard", 2);
25 | $this->object->set_drupal($this->drupal);
26 | }
27 |
28 | /**
29 | * Tears down the fixture, for example, closes a network connection.
30 | * This method is called after a test is executed.
31 | */
32 | protected function tearDown() {
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/Drupal/tagadelic/Tests/TagadelicTestCase.php:
--------------------------------------------------------------------------------
1 | "Tagadelic Test",
14 | "description" => "Tests if Tagadelic correctly adds the libraries",
15 | "group" => "Tagadelic",
16 | );
17 | }
18 |
19 | /**
20 | * testAutoloader Tests if classes are autoloaded.
21 | * @covers TagadelicCloud, TagadelicTag, TagaDelicDrupalWrapper.
22 | * @scope public
23 | */
24 | public function testAutoloader() {
25 | $tag = new \TagadelicTag(12, "jane", 2);
26 | $cloud = new \TagadelicCloud(1337);
27 | $drupal = new \TagaDelicDrupalWrapper();
28 |
29 | $this->assertEqual("TagadelicTag" , get_class($tag));
30 | $this->assertEqual("TagadelicCloud" , get_class($cloud));
31 | $this->assertEqual("TagadelicDrupalWrapper" , get_class($drupal));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tagadelic.module:
--------------------------------------------------------------------------------
1 |
6 | * @link http://berk.es
7 | */
8 |
9 | /**
10 | ____________________________________
11 | / This is an empty-ish file. Because \
12 | \ Drupal needs a .module /
13 | ------------------------------------
14 | \ / \ //\
15 | \ |\___/| / \// \\
16 | /0 0 \__ / // | \ \
17 | / / \/_/ // | \ \
18 | @_^_@'/ \/_ // | \ \
19 | //_^_/ \/_ // | \ \
20 | ( //) | \/// | \ \
21 | ( / /) _|_ / ) // | \ _\
22 | ( // /) '/,_ _ _/ ( ; -. | _ _\.-~ .-~~~^-.
23 | (( / / )) ,-{ _ `-.|.-~-. .~ `.
24 | (( // / )) '/\ / ~-. _ .-~ .-~^-. \
25 | (( /// )) `. { } / \ \
26 | (( / )) .----~-.\ \-' .~ \ `. \^-.
27 | ///.----..> \ _ -~ `. ^-` ^-_
28 | ///-._ _ _ _ _ _ _}^ - - - - ~ ~-- ,.-~
29 | /.-~
30 | */
31 |
--------------------------------------------------------------------------------
/TagadelicDrupalWrapper.php:
--------------------------------------------------------------------------------
1 | drupal->expects($this->once())
19 | ->method('l')
20 | ->will($this->returnValue("blackbeard"));
21 | }
22 | /**
23 | * @covers TagadelicTag::__ToString
24 | */
25 | public function test__ToString() {
26 | $this->assertTag(array("tag" => "a", "content" => "blackbeard"), $this->object->__ToString());
27 | }
28 |
29 | /**
30 | * @covers tagadelictag::__tostring
31 | */
32 | public function test__ToStringHasLink() {
33 | $link = '/foo/bar';
34 | $this->object->set_link($link);
35 |
36 | $this->drupal->expects($this->any())
37 | ->method('l')
38 | ->with(
39 | $this->anything(),
40 | $this->equalto($link),
41 | $this->anything());
42 |
43 | $this->object->__tostring();
44 | }
45 |
46 | /**
47 | * @covers tagadelictag::__tostring
48 | */
49 | public function test__ToStringHasTitle() {
50 | $this->object->set_description("Foo Bar");
51 | $expected_attrs = array("title" => "Foo Bar");
52 |
53 | $this->drupal->expects($this->any())
54 | ->method('l')
55 | ->with(
56 | $this->anything(),
57 | $this->anything(),
58 | $this->equalto(array("attributes" => $expected_attrs)))
59 | ->will($this->returnvalue(""));
60 |
61 | $this->object->__tostring();
62 | }
63 |
64 | /**
65 | * @covers tagadelictag::__tostring
66 | */
67 | public function test__ToStringHasNoTitle() {
68 | $this->object->set_description("");
69 |
70 | $this->drupal->expects($this->any())
71 | ->method('l')
72 | ->with(
73 | $this->anything(),
74 | $this->anything(),
75 | $this->equalto(array()))
76 | ->will($this->returnvalue(""));
77 |
78 | $this->object->__tostring();
79 | }
80 |
81 | /**
82 | * @covers tagadelictag::__tostring
83 | */
84 | public function test__ToStringHasWeight() {
85 | $this->object->set_weight(3);
86 | $expected_attrs = array("class" => array("level3"));
87 |
88 | $this->drupal->expects($this->any())
89 | ->method('l')
90 | ->with(
91 | $this->anything(),
92 | $this->anything(),
93 | $this->equalto(array("attributes" => $expected_attrs)))
94 | ->will($this->returnvalue(""));
95 |
96 | $this->object->__tostring();
97 | }
98 |
99 | /**
100 | * @covers tagadelictag::__tostring
101 | */
102 | public function test__ToStringHasNoWeight() {
103 | $this->object->set_weight(0);
104 |
105 | $this->drupal->expects($this->any())
106 | ->method('l')
107 | ->with(
108 | $this->anything(),
109 | $this->anything(),
110 | $this->equalto(array()))
111 | ->will($this->returnvalue(""));
112 |
113 | $this->object->__tostring();
114 | }
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/tests/TagadelicDrupalWrapperTest.php:
--------------------------------------------------------------------------------
1 | object = new TagadelicDrupalWrapper();
17 | }
18 |
19 | /**
20 | * Tears down the fixture, for example, closes a network connection.
21 | * This method is called after a test is executed.
22 | */
23 | protected function tearDown() {
24 | }
25 |
26 | /**
27 | * @covers TagadelicDrupalWrapper::cache_get
28 | */
29 | public function testCache_get() {
30 | $this->assertTrue(method_exists($this->object, "cache_get"));
31 | $this->assertSame($this->object->cache_get(1337), "cache_get(1337,cache)");
32 | $this->assertSame($this->object->cache_get(1337,"custom"), "cache_get(1337,custom)");
33 | }
34 |
35 | /**
36 | * @expectedException PHPUnit_Framework_Error
37 | */
38 | public function testCache_get_requires_cid() {
39 | $this->object->cache_get();
40 | }
41 |
42 | /**
43 | * @covers TagadelicDrupalWrapper::cache_set
44 | */
45 | public function testCache_set() {
46 | $this->assertTrue(method_exists($this->object, "cache_set"));
47 | $this->assertSame($this->object->cache_set(1337, "hello"), "cache_set(1337,hello,cache)");
48 | $this->assertSame($this->object->cache_set(1337, "hello","custom"), "cache_set(1337,hello,custom)");
49 | $this->assertSame($this->object->cache_set(1337, "hello","custom", 280602000), "cache_set(1337,hello,custom,280602000)");
50 | }
51 |
52 | /**
53 | * @expectedException PHPUnit_Framework_Error
54 | */
55 | public function testCache_set_requires_cid() {
56 | $this->object->cache_set();
57 | }
58 | /**
59 | * @expectedException PHPUnit_Framework_Error
60 | */
61 | public function testCache_set_requires_data() {
62 | $this->object->cache_set(1337);
63 | }
64 |
65 | /**
66 | * @covers TagadelicDrupalWrapper::check_plain
67 | */
68 | public function testCheck_plain() {
69 | $this->assertTrue(method_exists($this->object, "check_plain"));
70 | $this->assertSame($this->object->check_plain("hello"), "check_plain(hello)");
71 | }
72 |
73 | /**
74 | * @expectedException PHPUnit_Framework_Error
75 | */
76 | public function testCheck_plain_requires_text() {
77 | $this->object->check_plain();
78 | }
79 |
80 | public function testL() {
81 | $this->assertTrue(method_exists($this->object, "l"));
82 | $this->assertSame($this->object->l("text", "path"), "l(text,path,Array)");
83 |
84 | $options = array("attributes"=>array("title"=>"foo"));
85 | $serialized = serialize($options);
86 | $this->assertSame($this->object->l("text", "path", $options),"l(text,path,{$serialized})");
87 | }
88 |
89 | /**
90 | * @expectedException PHPUnit_Framework_Error
91 | */
92 | public function testL_requires_text() {
93 | $this->object->l();
94 | }
95 | /**
96 | * @expectedException PHPUnit_Framework_Error
97 | */
98 | public function testL_requires_path() {
99 | $this->object->l("text");
100 | }
101 |
102 | /**
103 | * @covers TagadelicDrupalWrapper::shuffle
104 | */
105 | public function testShuffle() {
106 | $array_to_shuffle = array("a", "b");
107 | $this->assertTrue(method_exists($this->object, "shuffle"));
108 | //Cannot test the method signature, because we cannot redeclare global "shuffle()"
109 | }
110 |
111 | /**
112 | * @expectedException PHPUnit_Framework_Error
113 | */
114 | public function testShuffle_requires_array() {
115 | $this->object->shuffle();
116 | }
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/tests/TagadelicTagMethodsTest.php:
--------------------------------------------------------------------------------
1 |
2 | assertSame(42, $this->object->get_id());
19 | }
20 |
21 | /**
22 | * @covers TagadelicTag::get_name
23 | */
24 | public function testGet_name() {
25 | $this->assertSame("blackbeard", $this->object->get_name());
26 | }
27 |
28 | /**
29 | * @covers TagadelicTag::get_description
30 | */
31 | public function testGet_description() {
32 | $this->object->set_description("Foo Bar");
33 | $this->assertSame("Foo Bar", $this->object->get_description());
34 | }
35 |
36 | /**
37 | * @covers TagadelicTag::get_weight
38 | */
39 | public function testGet_weight() {
40 | $this->object->set_weight(123);
41 | $this->assertSame(123, $this->object->get_weight());
42 | }
43 |
44 | /**
45 | * @covers TagadelicTag::get_weight
46 | */
47 | public function testGet_count() {
48 | $this->assertSame(2, $this->object->get_count());
49 | }
50 |
51 | /**
52 | * @covers TagadelicTag::set_weight
53 | */
54 | public function testSet_weight() {
55 | $this->object->set_weight(123);
56 | $this->assertAttributeSame(123, "weight", $this->object);
57 | }
58 |
59 | /**
60 | * @covers TagadelicTag::set_drupal
61 | */
62 | public function testSet_drupal() {
63 | $drupal = $this->getMock("TagaDelicDrupalWrapper");
64 | $this->object->set_drupal($drupal);
65 | $this->assertAttributeSame($drupal, "drupal", $this->object);
66 | }
67 |
68 | /**
69 | * @covers TagadelicTag::drupal
70 | */
71 | public function testDrupal() {
72 | $drupal = $this->getMock("TagaDelicDrupalWrapper");
73 | $this->object->set_drupal($drupal);
74 | $this->assertSame($this->object->drupal(), $drupal);
75 | }
76 |
77 | /**
78 | * @covers TagadelicTag::drupal
79 | */
80 | public function testDrupalInstatiatesNewWrapper() {
81 | $this->object->set_drupal(NULL);
82 | $this->assertInstanceOf("TagaDelicDrupalWrapper", $this->object->drupal());
83 | }
84 |
85 | /**
86 | * @covers TagadelicTag::set_description
87 | */
88 | public function testSet_description() {
89 | $this->object->set_description("Foo Bar");
90 | $this->assertAttributeSame("Foo Bar", "description", $this->object);
91 | }
92 |
93 | /**
94 | * @covers TagadelicTag::set_link
95 | */
96 | public function testSet_link() {
97 | $this->object->set_link("tag/blackbeard");
98 | $this->assertAttributeSame("tag/blackbeard", "link", $this->object);
99 | }
100 |
101 | /**
102 | * @covers TagadelicTag::force_dirty
103 | */
104 | public function testForce_dirty() {
105 | $this->object->force_dirty();
106 | $this->assertAttributeSame(TRUE, "dirty", $this->object);
107 | }
108 |
109 | /**
110 | * @covers TagadelicTag::force_clean
111 | */
112 | public function testForce_clean() {
113 | $this->object->force_clean();
114 | $this->assertAttributeSame(FALSE, "dirty", $this->object);
115 | }
116 |
117 | /**
118 | * @covers TagadelicTag::clean()
119 | */
120 | public function testCleansWhenDirty() {
121 | $drupal = $this->getMock("TagaDelicDrupalWrapper");
122 | $drupal->expects($this->exactly(2))->method("check_plain");
123 |
124 | $this->object->set_drupal($drupal);
125 | $this->object->force_dirty();
126 |
127 | $this->object->get_name();
128 | $this->object->get_description();
129 | }
130 |
131 | /**
132 | * @covers TagadelicTag::clean()
133 | */
134 | public function testSkipsCleanWhenClean() {
135 | $drupal = $this->getMock("TagaDelicDrupalWrapper");
136 | $drupal->expects($this->never())->method("check_plain");
137 |
138 | $this->object->set_drupal($drupal);
139 | $this->object->force_clean();
140 |
141 | $this->object->get_name();
142 | $this->object->get_description();
143 | }
144 | /**
145 | * @covers TagadelicTag::distributed
146 | */
147 | public function testDistributed() {
148 | $this->assertSame(log(2), $this->object->distributed());
149 | }
150 |
151 | /**
152 | * @covers TagadelicTag::distributed
153 | */
154 | public function testDistributed_NotInfinite() {
155 |
156 | $this->object = new TagadelicTag(24, "redhair", 0);
157 |
158 | $this->assertFalse((is_infinite($this->object->distributed())));
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/TagadelicCloud.php:
--------------------------------------------------------------------------------
1 | id = $id;
27 | $this->tags = $tags;
28 | }
29 |
30 | /**
31 | * Getter for id
32 | * @ingroup getters
33 | * @returns Integer id of this cloud
34 | */
35 | public function get_id() {
36 | return $this->id;
37 | }
38 |
39 | /**
40 | * Getter for tags
41 | * @ingroup getters
42 | * @returns Array list of tags
43 | */
44 | public function get_tags() {
45 | $this->recalculate();
46 | return $this->tags;
47 | }
48 |
49 | /**
50 | * Add a new tag to the cloud
51 | * @param $tag TagadelicTag
52 | * instance of TagadelicTag.
53 | *
54 | * return $this, for chaining.
55 | */
56 | public function add_tag($tag) {
57 | $this->tags[] = $tag;
58 | return $this;
59 | }
60 |
61 | /**
62 | * setter for drupal(wrapper). Mostly for testability
63 | * Operates on $this
64 | * Returns $this
65 | */
66 | public function set_drupal($drupal) {
67 | $this->drupal = $drupal;
68 | return $this;
69 | }
70 |
71 | /**
72 | * Getter for drupal
73 | * @return DrupalWrapper value in $this::$drupal.
74 | */
75 | public function drupal() {
76 | if (empty($this->drupal)) {
77 | $this->drupal = new TagadelicDrupalWrapper();
78 | }
79 | return $this->drupal;
80 | }
81 |
82 | /**
83 | * Instantiate $this from cache
84 | * Optionally pass $drupal, a Drupalwrapper along, mostly for testing.
85 | * Returns this
86 | */
87 | public static function from_cache($id, $drupal) {
88 | $cache_id = "tagadelic_cloud_{$id}";
89 | return $drupal->cache_get($cache_id);
90 | }
91 |
92 | /**
93 | * Writes the cloud to cache. Will recalculate if needed.
94 | * @return $this; for chaining.
95 | */
96 | public function to_cache() {
97 | $cache_id = "tagadelic_cloud_{$this->id}";
98 | $this->drupal()->cache_set($cache_id, $this);
99 | return $this;
100 | }
101 |
102 | /**
103 | * Sorts the tags by given property.
104 | * @return $this; for chaining.
105 | */
106 | public function sort($by_property) {
107 | if ($by_property == "random") {
108 | $this->drupal()->shuffle($this->tags);
109 | }
110 | else {
111 | //Bug in PHP https://bugs.php.net/bug.php?id=50688, lets supress the error.
112 | @usort($this->tags, array($this, "cb_sort_by_{$by_property}"));
113 | }
114 | return $this;
115 | }
116 |
117 | /**
118 | * (Re)calculates the weights on the tags.
119 | * @param $recalculate. Optional flag to enfore recalculation of the weights for the tags in this cloud.
120 | * defaults to FALSE, meaning the value will be calculated once per cloud.
121 | * @return $this; for chaining
122 | */
123 | private function recalculate() {
124 | $tags = array();
125 | // Find minimum and maximum log-count.
126 | $min = 1e9;
127 | $max = -1e9;
128 | foreach ($this->tags as $id => $tag) {
129 | $min = min($min, $tag->distributed());
130 | $max = max($max, $tag->distributed());
131 | $tags[$id] = $tag;
132 | }
133 | // Note: we need to ensure the range is slightly too large to make sure even
134 | // the largest element is rounded down.
135 | $range = max(.01, $max - $min) * 1.0001;
136 | foreach ($tags as $id => $tag) {
137 | $this->tags[$id]->set_weight(1 + floor($this->steps * ($tag->distributed() - $min) / $range));
138 | }
139 | return $this;
140 | }
141 |
142 | private function cb_sort_by_name($a, $b) {
143 | return strcoll($a->get_name(), $b->get_name());
144 | }
145 |
146 | private function cb_sort_by_count($a, $b) {
147 | $ac = $a->get_count();
148 | $bc = $b->get_count();
149 | if ($ac == $bc) {
150 | return 0;
151 | }
152 | //Highest first, High to low
153 | return ($ac < $bc) ? +1 : -1;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/lib/Drupal/tagadelic/Tests/TagadelicTaxonomyAdminWebTestCase.php:
--------------------------------------------------------------------------------
1 | "Tagadelic Taxonomy Admin Test",
18 | "description" => "Tests admin area in Tagadelic Taxonomy",
19 | "group" => "Tagadelic",
20 | );
21 | }
22 |
23 | /**
24 | * @scope public
25 | * @returns Type Description of return value
26 | */
27 | public function setUp(array $modules = array()) {
28 | parent::setUp($modules);
29 | $this->deleteVocabularies();
30 |
31 | $this->web_user = $this->drupalCreateUser(array("administer site configuration", "administer users"));
32 | $this->drupalLogin($this->web_user);
33 | }
34 |
35 | public function testHasTagaDelicPage() {
36 | $this->drupalGet($this->admin_url);
37 | $this->assertResponse(200, "Can Access Page");
38 | $this->assertText(t("Tag Cloud"), "Title of page is Tag Cloud");
39 | }
40 |
41 | public function testIsOnlyAccessibleForAdmin() {
42 | $web_user = $this->drupalCreateUser(array('access content'));
43 | $this->drupalLogin($web_user);
44 |
45 | $this->drupalGet($this->admin_url);
46 | $this->assertResponse(403);
47 | }
48 |
49 | public function testHasCheckboxesForAllVocabularies() {
50 | $this->createVocabularies(5);
51 | $this->drupalGet($this->admin_url);
52 | foreach($this->vocabularies as $vocabulary) {
53 | $id = "edit-tagadelic-taxonomy-vocabularies-{$vocabulary->vid}";
54 | $this->assertHasCheckbox($id);
55 | }
56 | }
57 |
58 | public function testCheckboxesGetDefaults() {
59 | $this->createVocabularies(5);
60 |
61 | foreach($this->vocabularies as $vocabulary) {
62 | $values[$vocabulary->vid] = $vocabulary->vid;
63 | }
64 | variable_set("tagadelic_taxonomy_vocabularies", $values);
65 |
66 | $this->drupalGet($this->admin_url);
67 | foreach($this->vocabularies as $vocabulary) {
68 | $id = "edit-tagadelic-taxonomy-vocabularies-{$vocabulary->vid}";
69 | $this->assertFieldChecked($id);
70 | }
71 | }
72 |
73 | public function testSelectedVocabulariesAreSaved() {
74 | $values = $edit = array();
75 | $this->createVocabularies(5);
76 | $this->drupalGet($this->admin_url); //Create the form item
77 |
78 | foreach($this->vocabularies as $vocabulary) {
79 | $values[$vocabulary->vid] = $vocabulary->vid;
80 |
81 | $key = "tagadelic_taxonomy_vocabularies[{$vocabulary->vid}]";
82 | $edit[$key] = TRUE;
83 | }
84 | $this->drupalPost(NULL, $edit, "Save configuration");
85 |
86 | $this->assertVariableIs("tagadelic_taxonomy_vocabularies", $values);
87 | }
88 |
89 |
90 | protected function assertHasCheckbox($id, $message = '', $group = 'Other') {
91 | if (empty($message)) {
92 | $message = "checkbox '{$id}' not found";
93 | }
94 |
95 | $this->assertHasXpath(".//input[@id='{$id}'][@type='checkbox']");
96 | }
97 |
98 | protected function assertHasXpath($xpath, $message = '', $group = 'Other') {
99 | if (empty($message)) {
100 | $message = "xpath '{$xpath}' not found.";
101 | }
102 | $xpath = $this->xpath($xpath);
103 | $truthiness = count($xpath) > 0;
104 | return $this->assertTrue($truthiness, $message, $group);
105 | }
106 |
107 | protected function assertVariableIs($name, $expected_value, $refresh = FALSE, $message = '', $group = 'Other') {
108 | if ($refresh) {
109 | $this->refreshVariables();
110 | }
111 | $real_value = variable_get($name, NULL);
112 |
113 | // We want identical-ish arrays.
114 | if (is_array($expected_value)) {
115 | ksort($expected_value);
116 | }
117 | if (is_array($real_value)) {
118 | ksort($real_value);
119 | }
120 |
121 | if (empty($message)) {
122 | $expected = var_export($expected_value, TRUE);
123 | $real = var_export($real_value, TRUE);
124 | $message = "variable {$name} with {$expected} not found. Was {$real}.";
125 | }
126 | return $this->assertIdentical($expected_value, $real_value, $message);
127 | }
128 |
129 | /*
130 | * Builder functions
131 | */
132 | private function createVocabularies($amount) {
133 | $tx_test = new \TaxonomyWebTestCase();
134 | for ($i = 0; $i < $amount; $i++) {
135 | $this->vocabularies[] = $tx_test->createVocabulary();
136 | }
137 |
138 | return $this;
139 | }
140 |
141 | private function deleteVocabularies() {
142 | foreach(taxonomy_vocabulary_load_multiple(FALSE) as $vocabulary) {
143 | taxonomy_vocabulary_delete($vocabulary->vid);
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/tagadelic_taxonomy.module:
--------------------------------------------------------------------------------
1 |
6 | * @link http://berk.es
7 | */
8 |
9 | /**
10 | * Implements hook_menu().
11 | * @see hook_menu()
12 | */
13 | function tagadelic_taxonomy_menu() {
14 | $items['tagadelic_taxonomy'] = array(
15 | 'title' => 'Tag Cloud',
16 | 'page callback' => 'tagadelic_taxonomy_cloud',
17 | 'page arguments' => array('60'),
18 | 'access arguments' => array("access content"),
19 | 'expanded' => TRUE,
20 | );
21 | # Admin pages
22 | $items['admin/structure/tagadelic_taxonomy'] = array(
23 | 'title' => 'Tag Cloud',
24 | 'page callback' => 'tagadelic_taxonomy_admin',
25 | 'access arguments' => array("administer site configuration"),
26 | );
27 | return $items;
28 | }
29 |
30 | /**
31 | * Constructs a simple page.
32 | * Callback from the menu.
33 | */
34 | function tagadelic_taxonomy_cloud() {
35 | return theme("tagadelic_taxonomy_cloud", array("tags" => tagadelic_taxonomy_get_cloud(60)));
36 | }
37 |
38 | function tagadelic_taxonomy_get_cloud($max_amount) {
39 | drupal_add_css(drupal_get_path('module', 'tagadelic') . '/tagadelic.css');
40 |
41 | $cloud = new TagadelicCloud("tagadalic_taxonomy");
42 |
43 | foreach (tagadelic_taxonomy_tags_from_db($max_amount) as $term) {
44 | $tag = new TagadelicTag($term->tid, $term->name, $term->count);
45 | $tag->set_link("taxonomy/term/{$term->tid}");
46 |
47 | $cloud->add_tag($tag);
48 | }
49 |
50 | # Because now here wer're returning an array, not HTML.
51 | return $cloud->get_tags();
52 | }
53 |
54 | function tagadelic_taxonomy_theme($existing, $type, $theme, $path) {
55 | return array(
56 | "tagadelic_taxonomy_cloud" => array(
57 | "variables" => array(
58 | "tags" => array(),
59 | "name" => "",
60 | ),
61 | "path" => "{$path}/templates",
62 | "template" => "tagadelic_taxonomy_cloud"
63 | ), // tagadelic_taxonomy_cloud
64 |
65 | );
66 | }
67 |
68 | function tagadelic_taxonomy_tags_from_db($max_amount) {
69 | $tags = array();
70 |
71 | $query = db_select('taxonomy_index', 'i');
72 |
73 | $alias = $query->leftjoin('taxonomy_term_data', 't', '%alias.tid = i.tid');
74 |
75 | $query->addExpression('COUNT(i.nid)', 'count');
76 | $query->addField($alias, 'tid');
77 | $query->addField($alias, 'name');
78 | $query->addField($alias, 'description');
79 | $query->orderBy('count', 'DESC');
80 |
81 | foreach(variable_get("tagadelic_taxonomy_vocabularies", array()) as $vid => $state) {
82 | if ($state != $vid) { //Disabled
83 | $query->condition('t.vid', $vid, '<>');
84 | }
85 | }
86 |
87 | $query->range(0, $max_amount)
88 | ->groupBy("i.tid");
89 |
90 | return $query->execute();
91 | }
92 |
93 | /********************************************************************
94 | * Admin pages methods *
95 | *******************************************************************/
96 |
97 | /**
98 | * tagadelic_taxonomy_admin Renders admin page
99 | *
100 | * @returns String $html The Contents of the page, as HTML
101 | */
102 | function tagadelic_taxonomy_admin() {
103 | $html = "";
104 |
105 | $form = drupal_get_form("tagadelic_taxonomy_admin_form");
106 | $html .= drupal_render($form);
107 |
108 | return $html;
109 | }
110 |
111 | function tagadelic_taxonomy_admin_form($form, &$form_state) {
112 | $form = array();
113 | $options = array();
114 |
115 | foreach(taxonomy_get_vocabularies() as $vocabulary) {
116 | $options[$vocabulary->vid] = $vocabulary->name;
117 | }
118 |
119 | $form["tagadelic_taxonomy_vocabularies"] = array(
120 | "#type" => "checkboxes",
121 | "#title" => "Vocabularies used in Tag Cloud",
122 | "#options" => $options,
123 | "#default_value" => variable_get('tagadelic_taxonomy_vocabularies', array()),
124 | );
125 |
126 | return system_settings_form($form);
127 | }
128 |
129 | /**
130 | * Implementation of hook_block_info
131 | *
132 | * @returns array $blocks
133 | */
134 | function tagadelic_taxonomy_block_info() {
135 | return array(
136 | 'tagadelic_taxonomy' => array(
137 | 'info' => t('Tagadelic Tag cloud'),
138 | 'cache' => DRUPAL_NO_CACHE,
139 | )
140 | );
141 | }
142 |
143 | /**
144 | * Implementation of hook_block_view
145 | *
146 | * @param String $delta name key for the block
147 | *
148 | * @return array $block renderable array of terms cloud
149 | */
150 | function tagadelic_taxonomy_block_view($delta = '') {
151 | $body = theme("tagadelic_taxonomy_cloud", array("tags" => tagadelic_taxonomy_get_cloud(12)));
152 | $body .= l(t("More tags"), "tagadelic_taxonomy", array("attributes" => array("class" => array("more"))));
153 | return array(
154 | 'subject' => t('Tag cloud'),
155 | 'content' => array(
156 | '#type' => 'markup',
157 | '#markup' => $body,
158 | )
159 | );
160 | }
161 |
--------------------------------------------------------------------------------
/TagadelicTag.php:
--------------------------------------------------------------------------------
1 | id = $id;
26 | $this->name = $name;
27 | if($count != 0) {
28 | $this->count = $count;
29 | }
30 | }
31 |
32 | /**
33 | * Magic method to render the Tag.
34 | * turns the tag into an HTML link to its source.
35 | */
36 | public function __ToString() {
37 | $this->clean();
38 |
39 | $attributes = $options = array();
40 |
41 | if (!empty($this->description)) $attributes["title"] = $this->description;
42 | if ($this->weight > 0) $attributes["class"][] = "level{$this->weight}";
43 |
44 | if (!empty($attributes)) $options["attributes"] = $attributes;
45 |
46 | return $this->drupal()->l($this->name, $this->link, $options);
47 | }
48 |
49 | /**
50 | * Getter for the ID
51 | * @ingroup getters
52 | * return Integer Identifier
53 | **/
54 | public function get_id() {
55 | return $this->id;
56 | }
57 |
58 | /**
59 | * Getter for the name
60 | * @ingroup getters
61 | * return String the human readable name
62 | **/
63 | public function get_name() {
64 | $this->clean();
65 | return $this->name;
66 | }
67 |
68 | /**
69 | * Getter for the description
70 | * @ingroup getters
71 | * return String the human readable description
72 | **/
73 | public function get_description() {
74 | $this->clean();
75 | return $this->description;
76 | }
77 |
78 | /**
79 | * Returns the weight, getter only.
80 | * Will call recalculate to calculate the weight.
81 | * @ingroup getters
82 | * return Float the weight of this tag.
83 | **/
84 | public function get_weight() {
85 | return $this->weight;
86 | }
87 |
88 | /**
89 | * Returns the count, getter only.
90 | * @ingroup getters
91 | * return Int the count as provided when Initializing the Object.
92 | **/
93 | public function get_count() {
94 | return $this->count;
95 | }
96 |
97 | /**
98 | * Sets the optional description.
99 | * A tag may have a description
100 | * @param $description String a description
101 | */
102 | public function set_description($description) {
103 | $this->description = $description;
104 | }
105 |
106 | /**
107 | * Link to a resource.
108 | * @param link String Optional a link to a resource that represents
109 | * the tag. e.g. a listing with all things tagged with Tag, or
110 | * the article that represents the tag.
111 | */
112 | public function set_link($link) {
113 | $this->link = $link;
114 | }
115 |
116 | /**
117 | * setter for weight
118 | * Operates on $this
119 | * Returns $this
120 | */
121 | public function set_weight($weight) {
122 | $this->weight = $weight;
123 | return $this;
124 | }
125 |
126 | /**
127 | * setter for drupal(Wrapper)
128 | * Operates on $this
129 | * Returns $this
130 | */
131 | public function set_drupal($drupal) {
132 | $this->drupal = $drupal;
133 | return $this;
134 | }
135 | /**
136 | * Getter for drupal, if not found, will instantiate a default TagaDelicDrupalWrapper
137 | * @return type value in $this::$drupal.
138 | */
139 | public function drupal() {
140 | if (empty($this->drupal)) {
141 | $this->drupal = new TagaDelicDrupalWrapper();
142 | }
143 | return $this->drupal;
144 | }
145 |
146 | /**
147 | * Flag $name and $description as dirty; none-cleaned.
148 | * BEWARE! This will probably lead to double escaping, unless you know what you are doing.
149 | */
150 | public function force_dirty() {
151 | $this->dirty = true;
152 | }
153 |
154 | /**
155 | * Flag $name and $description as safe.
156 | * XSS-escaping and sanitizing is left to implementer.
157 | * BEWARE! Only enforce when you know what you are doing. Seriously!
158 | */
159 | public function force_clean() {
160 | $this->dirty = false;
161 | }
162 |
163 | /**
164 | * Calculates a more evenly distributed value.
165 | */
166 | public function distributed() {
167 | return log($this->count);
168 | }
169 |
170 | /**
171 | * Utility, to enforce XSS filtering on strings before they are
172 | * printed or returned.
173 | **/
174 | private function clean() {
175 | if ($this->dirty) {
176 | $this->name = $this->drupal()->check_plain($this->name);
177 | $this->description = $this->drupal()->check_plain($this->description);
178 | $this->force_clean();
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tagadelic #
2 | Tagadelic provides an API and a few simple turnkey modules, which allows you to easily create tagclouds, weighted lists, search-clouds and such.
3 |
4 | With the API you can build a module with a few lines of PHP, to turn anything that can be counted into a weighted cloud. Which can be presented to your users anyway and anywhere on your site.
5 |
6 | With the turnkey modules, you can add a page that shows taxonomy-terms in a weighted cloud: terms that are used more often are bigger. Another module provides a page that shows article-titles in a cloud: titles from articles that are read more often appear bigger.
7 |
8 | [](https://travis-ci.org/berkes/tagadelic)
9 |
10 | ## End-users ##
11 | Install and enable _"tagadelic taxonomy"_ for a tagcloud from your
12 | taxonomy-terms, and _"tagadelic titles"_ for a tagcloud from
13 | article-titles. The required libaries and such will be installed
14 | automatically.
15 |
16 | ### Documentation for end-users ###
17 |
18 | * [Tagadelic Taxonomy](https://github.com/berkes/tagadelic/wiki/Tagadelic-Taxonomy)
19 | * [Tagadelic Titles](https://github.com/berkes/tagadelic/wiki/Tagadelic-Titles)
20 |
21 | ## Developers ##
22 |
23 | Tagadelic is essentially a set of classes with APIs that allow you to
24 | build word-clouds from anything that can be counted. The end-user
25 | modules described above, should be considered example- and
26 | convenience-modules. Examples for you, when you want to develop your own
27 | clouds. And convenience for the poor souls who cannot develop such
28 | module :).
29 |
30 | An example:
31 |
32 | get_tags() as $tag) {
40 | print $tag;
41 | }
42 | ?>
43 |
44 | This will output:
45 |
46 | Anne Bonney
47 | Sadie the Goat
48 | Mary Read.
115 |
--------------------------------------------------------------------------------
/tests/TagadelicCloudTest.php:
--------------------------------------------------------------------------------
1 | object = new TagadelicCloud(1337);
21 |
22 | $this->addTagStub("jane", "Jane", 200);
23 | $this->addTagStub("blackbeard", "Blackbeard", 100);
24 | }
25 |
26 | /**
27 | * Tears down the fixture, for example, closes a network connection.
28 | * This method is called after a test is executed.
29 | */
30 | protected function tearDown() {
31 | }
32 |
33 | /**
34 | * constructor should set the ID to the variable passed.
35 | */
36 | public function test__construct() {
37 | // First param should be assigned to the id.
38 | $this->assertAttributeSame(1337, "id", $this->object);
39 |
40 | // Optional second argument pre-sets the tags.
41 | $this->object = new TagadelicCloud(1337, $this->mock_tags);
42 | $this->assertAttributeSame($this->mock_tags, "tags", $this->object);
43 | }
44 |
45 | /**
46 | * @covers TagadelicCloud::get_id
47 | */
48 | public function testGet_id() {
49 | $this->assertEquals(1337, $this->object->get_id());
50 | }
51 |
52 | /**
53 | * @covers TagadelicCloud::get_tags
54 | * Tests if get_Tags returns an array only.
55 | */
56 | public function testGet_tags() {
57 | $this->object = new TagadelicCloud(1337, $this->mock_tags);
58 | $this->assertSame($this->mock_tags, $this->object->get_tags());
59 | }
60 |
61 | /**
62 | * @covers TagadelicCloud::add_tag
63 | */
64 | public function testAdd_tag() {
65 | $this->object->add_tag($this->mock_tags["blackbeard"]);
66 | $this->assertAttributeContains($this->mock_tags["blackbeard"], "tags", $this->object);
67 | }
68 |
69 | /**
70 | * @covers TagadelicCloud::add_tag()
71 | */
72 | public function testAdd_tagIsChainable() {
73 | $this->assertEquals($this->object->add_tag($this->mock_tags["blackbeard"]), $this->object);
74 | }
75 |
76 | /**
77 | * @covers TagadelicCloud::set_drupal()
78 | */
79 | public function testSet_drupal() {
80 | $drupal = new StdClass();
81 | $this->object->set_drupal($drupal);
82 | $this->assertAttributeSame($drupal, "drupal", $this->object);
83 | }
84 |
85 | /**
86 | * @covers TagadelicCloud::drupal()
87 | */
88 | public function testDrupalReturnsSetValue() {
89 | $drupal = "ThisIsDrupal";
90 | $this->object->set_drupal($drupal);
91 | $this->assertSame($this->object->drupal(), $drupal);
92 | }
93 |
94 | /**
95 | * @covers TagadelicCloud::drupal()
96 | */
97 | public function testDrupalInstantiatesNewWrapper() {
98 | $this->object->set_drupal(NULL);
99 | $drupal = $this->getMock("TagadelicDrupalWrapper");
100 | $this->assertInstanceOf("TagadelicDrupalWrapper", $this->object->drupal());
101 | }
102 |
103 | /**
104 | * @covers tagadeliccloud::from_cache
105 | */
106 | public function testfrom_cache() {
107 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("cache_get"));
108 | $drupal->expects($this->once())
109 | ->method("cache_get")
110 | ->with("tagadelic_cloud_1337")
111 | ->will($this->returnvalue($this->object));
112 | $cloud = TagadelicCloud::from_cache(1337, $drupal);
113 | $this->assertinstanceof("TagadelicCloud", $cloud);
114 | }
115 |
116 | /**
117 | * @covers tagadeliccloud::to_cache
118 | */
119 | public function testTo_cache() {
120 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("cache_set"));
121 | $drupal->expects($this->once())
122 | ->method("cache_set")
123 | ->with("tagadelic_cloud_1337", $this->object);
124 | $this->object->set_drupal($drupal);
125 |
126 | $this->object->to_cache();
127 | }
128 |
129 | /**
130 | * Get Tags should calculate the weights
131 | */
132 | public function testGetCalculatedTags() {
133 | foreach ($this->mock_tags as $mock_tag) {
134 | $mock_tag->expects($this->once())
135 | ->method('set_weight')
136 | ->with($this->greaterThan(0))
137 | ->will($this->returnSelf());
138 | $mocks[] = $mock_tag;
139 | }
140 | $this->object = new TagadelicCloud(1337, $mocks);
141 | $this->object->get_tags();
142 | }
143 |
144 | /**
145 | * Get Tags should calculate the weights
146 | */
147 | public function testGetCalculatedWeights() {
148 | $mocks = array();
149 | $assert_table = array(
150 | // name , count , weight
151 | array("Mary Read" , 1 , 1),
152 | array("Jean Fleury" , 1 , 1),
153 | array("François Le Clerc" , 1 , 1),
154 | array("Blackbeard" , 2 , 1),
155 | array("Henry Morgan" , 3 , 2),
156 | array("Bartolomew Roberts" , 10 , 3),
157 | array("Stede Bonnet" , 20 , 4),
158 | array("Edward Low" , 40 , 5),
159 | array("Anne Bonny" , 100 , 6),
160 | );
161 | $i = 1;
162 |
163 | foreach($assert_table as $assertion) {
164 | $mock = $this->getMock("TagadelicTag", array("set_weight"), array($i++, $assertion[0], $assertion[1]));
165 | $mock->expects($this->once())
166 | ->method("set_weight")
167 | ->with($assertion[2])
168 | ->will($this->returnSelf());
169 |
170 | $mocks[] = $mock;
171 | }
172 | $this->object = new TagadelicCloud(1337, $mocks);
173 | $this->object->get_tags();
174 | }
175 |
176 | /**
177 | * Default is not sorted
178 | **/
179 | public function testNotSorted() {
180 | $this->object->add_tag($this->addTagStub("bill", "William Kidd", 100));
181 | $this->object->add_tag($this->addTagStub("cheung", "Cheung Po Tsai", 20));
182 |
183 | $expected_order = array("William Kidd", "Cheung Po Tsai");
184 | $given_order = array();
185 |
186 | foreach($this->object->get_tags() as $tag) {
187 | $given_order[] = $tag->get_name();
188 | }
189 |
190 | $this->assertSame($given_order, $expected_order);
191 | }
192 |
193 | /**
194 | * Sort By name
195 | **/
196 | public function testSortByName() {
197 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("check_plain"));
198 | $drupal->expects($this->any())->method("check_plain")->will($this->returnArgument(0));
199 | $this->object->set_drupal($drupal);
200 |
201 | $this->object->add_tag($this->addTagStub("bill", "William Kidd", 100));
202 | $this->object->add_tag($this->addTagStub("cheung", "Cheung Po Tsai", 20));
203 |
204 | $expected_order = array("Cheung Po Tsai", "William Kidd");
205 | $given_order = array();
206 |
207 | $this->object->sort("name");
208 |
209 | foreach($this->object->get_tags() as $tag) {
210 | $given_order[] = $tag->get_name();
211 | }
212 |
213 | $this->assertSame($given_order, $expected_order);
214 | }
215 |
216 | /**
217 | * Sort By name should sort International characters like ÅÄÖABO
218 | *
219 | * Uses Locale de_DE, which must be available on your system.
220 | * Debian/Ubuntu users:
221 | * $ locale -a
222 | * $ #lists all locales available. Find if de_DE is there, if not, install it.
223 | * $ sudo apt-get install language-pack-de-base
224 | **/
225 | public function testSortByNameWithInternationalCharacters() {
226 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("check_plain"));
227 | $drupal->expects($this->any())->method("check_plain")->will($this->returnArgument(0));
228 | $this->object->set_drupal($drupal);
229 |
230 | $this->object->add_tag($this->addTagStub("ae", "Ä", 10));
231 | $this->object->add_tag($this->addTagStub("oe", "Ö", 20));
232 | $this->object->add_tag($this->addTagStub("ue", "Ü", 30));
233 | $this->object->add_tag($this->addTagStub("u", "U", 40));
234 | $this->object->add_tag($this->addTagStub("o", "O", 50));
235 | $this->object->add_tag($this->addTagStub("a", "A", 60));
236 |
237 | $expected_order = array("A", "Ä", "O", "Ö", "U", "Ü");
238 | $given_order = array();
239 |
240 | setlocale(LC_COLLATE, 'fr_FR.utf8');
241 | $this->object->sort("name");
242 |
243 | foreach($this->object->get_tags() as $tag) {
244 | $given_order[] = $tag->get_name();
245 | }
246 |
247 | $this->assertSame($given_order, $expected_order);
248 | }
249 |
250 | /**
251 | * Sort by count. Highest count first.
252 | */
253 | public function testSortByCount() {
254 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("check_plain"));
255 | $drupal->expects($this->any())->method("check_plain")->will($this->returnArgument(0));
256 | $this->object->set_drupal($drupal);
257 |
258 | $this->object->add_tag($this->addTagStub("bill", "William Kidd", 100));
259 | $this->object->add_tag($this->addTagStub("cheung", "Cheung Po Tsai", 200));
260 |
261 | $expected_order = array("Cheung Po Tsai", "William Kidd");
262 | $given_order = array();
263 |
264 | $this->object->sort("count");
265 |
266 | foreach($this->object->get_tags() as $tag) {
267 | $given_order[] = $tag->get_name();
268 | }
269 |
270 | $this->assertSame($given_order, $expected_order);
271 | }
272 |
273 | /**
274 | * Sort random.
275 | */
276 | public function testSortRandom() {
277 | $drupal = $this->getMock("TagadelicDrupalWrapper", array("shuffle"));
278 | $drupal->expects($this->once())
279 | ->method("shuffle");
280 | $this->object->set_drupal($drupal);
281 |
282 | $this->object->sort("random");
283 | }
284 |
285 | /**
286 | * Creates a stub for a tag
287 | */
288 | private function addTagStub($id, $name, $count) {
289 | $stub = $this->getMock("TagadelicTag", array("get_name", "get_count", "set_weight"), array($id, $name, $count));
290 |
291 | $stub->expects($this->any())
292 | ->method("get_name")
293 | ->will($this->returnValue($name));
294 | $stub->expects($this->any())
295 | ->method("get_count")
296 | ->will($this->returnValue($count));
297 |
298 | $this->mock_tags[$id] = $stub;
299 | return $stub;
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/lib/Drupal/tagadelic/Tests/TagadelicTaxonomyTestCase.php:
--------------------------------------------------------------------------------
1 | "Tagadelic Taxonomy Test",
20 | "description" => "Tests tagclouds from Tagadelic Taxonomy",
21 | "group" => "Tagadelic",
22 | );
23 | }
24 |
25 | /**
26 | * @scope public
27 | * @returns Type Description of return value
28 | */
29 | public function setUp(array $modules = array()) {
30 | parent::setUp(array('block'));
31 |
32 | // Create an admin user allowed to edit block settings
33 | $this->admin_user = $this->drupalCreateUser(array(
34 | 'administer blocks',
35 | 'access administration pages',
36 | ));
37 |
38 | }
39 |
40 | public function testHasTagcloudPage() {
41 | $this->drupalGet("tagadelic_taxonomy");
42 | $this->assertResponse(200, "Can Access Page");
43 | $this->assertText(t("Tag Cloud"), "Title of page is Tag Cloud");
44 | }
45 |
46 | public function testOnlyAccessContentAccessible() {
47 | # Remove access content permission from anonymous user.
48 | # As per http://drupal.stackexchange.com/a/70478/787
49 | user_role_revoke_permissions(1, array('access content'));
50 | $this->drupalGet("tagadelic_taxonomy");
51 | $this->assertResponse(403);
52 | }
53 |
54 | public function testTagsWithoutNodesNotOnPage() {
55 | $this->createVocAndTags(3, FALSE);
56 | $this->drupalGet("tagadelic_taxonomy");
57 | foreach($this->tags as $tag) {
58 | $this->assertNoText($tag->name);
59 | }
60 | }
61 |
62 | public function testHasTagsOnPage() {
63 | $this->createVocAndTags(1);
64 | $this->drupalGet("tagadelic_taxonomy");
65 | $tag = $this->tags[0];
66 | $this->assertText($tag->name);
67 | }
68 |
69 | public function testHasClickableLink() {
70 | $this->createVocAndTags(1);
71 | $this->drupalGet("tagadelic_taxonomy");
72 |
73 | $link = "/taxonomy/term/{$this->tags[0]->tid}";
74 | $this->assertHasXpath("//*/ul[@class='tag-cloud']/li/a[@href='{$link}']");
75 | }
76 |
77 | public function testHasFiveTags() {
78 | $this->createVocAndTags(5);
79 | $this->drupalGet("tagadelic_taxonomy");
80 | $amount = count($this->xpath("//*/ul[@class='tag-cloud']/li"));
81 | $this->assertEqual(5, $amount);
82 | }
83 |
84 | public function testHasMaxsixtyTags() {
85 | $this->createVocAndTags(61);
86 | $this->drupalGet("tagadelic_taxonomy");
87 | $this->assertAmountTagsOnPage(60);
88 | }
89 |
90 | public function testOrdersTagsByUsage() {
91 | $this->createVocAndTags(3, FALSE);
92 | $this->createNodesWithTags(3);
93 |
94 | $this->drupalGet("tagadelic_taxonomy");
95 | $tags = $this->xpath("//*/ul[@class='tag-cloud']/li/a");
96 |
97 | $found = array();
98 | foreach ($tags as $tag) {
99 | $attributes = $tag->attributes();
100 | $found[] = (string) $attributes["href"];
101 | }
102 | $this->assertEqual($found, array("/taxonomy/term/3", "/taxonomy/term/2", "/taxonomy/term/1"));
103 | }
104 |
105 | public function testOnlyHasTagsFromSelectedVocabularies() {
106 | $this->createVocsAndTags(3, 3);
107 | $this->createNodesWithTags(100);
108 |
109 | $disabled_voc = $this->vocabularies[0];
110 | foreach($this->vocabularies as $vocabulary) {
111 | if ($disabled_voc->vid == $vocabulary->vid) {
112 | $setting[$vocabulary->vid] = 0;
113 | }
114 | else {
115 | $setting[$vocabulary->vid] = $vocabulary->vid;
116 | }
117 | }
118 | variable_set("tagadelic_taxonomy_vocabularies", $setting);
119 | $this->refreshVariables();
120 |
121 | $this->drupalGet("tagadelic_taxonomy");
122 | foreach($this->tags_by_voc[$disabled_voc->vid] as $term) {
123 | $this->assertNoText($term->name);
124 | }
125 | }
126 |
127 | public function testHasWeightedTags() {
128 | $this->createVocAndTags(10);
129 | $this->createNodesWithTags(100);
130 | $this->drupalGet("tagadelic_taxonomy");
131 |
132 | $weights = array(1,2,3,4,4,5,5,6,6,6);
133 | $i = 0;
134 | foreach($this->tags as $tag) {
135 | $weight = $weights[$i++];
136 | $this->assertTagHasWeight($tag->name, $weight);
137 | }
138 | }
139 |
140 | public function testAttachesCssToPage() {
141 | $this->createVocAndTags(1);
142 | $this->drupalGet("tagadelic_taxonomy");
143 | $this->assertRaw('/tagadelic.css', "Tagadelic CSS added to styles");
144 | }
145 |
146 | public function testAttachesCssOnlyToCloudPages() {
147 | $this->createVocAndTags(1);
148 | $this->drupalGet("node");
149 | $this->assertNotRaw('/tagadelic.css', "Tagadelic CSS added to styles");
150 | }
151 |
152 | public function testBlockRendering() {
153 | $this->enableBlock();
154 | $this->createNodesWithTags(10);
155 |
156 | $this->drupalGet('node');
157 | $this->assertText(t("Tag cloud"), "Title of block is Tag Cloud");
158 | }
159 |
160 | public function testBlockHasMoreLinkToPage() {
161 | $this->enableBlock();
162 | $this->createVocAndTags(11);
163 |
164 | $this->drupalGet('node');
165 |
166 | $this->assertHasXpath('//*/a[@class="more"]');
167 | $this->assertLink("More tags");
168 |
169 | # This will cause a false-positive, as we have a link to tagadelic_taxonomy in the main-menu too!
170 | $this->assertLinkByHref("tagadelic_taxonomy");
171 | }
172 |
173 | public function testBlockHasMaxTwelveTags() {
174 | $this->enableBlock();
175 | $this->createVocAndTags(13);
176 |
177 | $this->drupalGet('node');
178 | $this->assertAmountTagsOnPage(12);
179 | }
180 |
181 | /*************************************************************************
182 | * Test Helpers
183 | *************************************************************************/
184 | private function createVocAndTags($amount_of_tags, $create_node = TRUE) {
185 | $tx_test = new \TaxonomyWebTestCase();
186 |
187 | $this->tags = array();
188 | $this->vocabulary = $tx_test->createVocabulary();
189 | for ($i = 0; $i < $amount_of_tags; $i++) {
190 | $this->tags[] = $tx_test->createTerm($this->vocabulary);
191 | }
192 |
193 | if ($create_node) $this->createNodesWithTags(1);
194 | return $this;
195 | }
196 |
197 | private function createVocsAndTags($amount_of_vocs, $amount_of_tags_per_voc) {
198 | $tx_test = new \TaxonomyWebTestCase();
199 |
200 | $this->tags = array();
201 | $this->tags_by_voc = array();
202 |
203 | for ($v = 0; $v < $amount_of_vocs; $v++) {
204 | $voc = $tx_test->createVocabulary();
205 | $this->vocabularies[] = $voc;
206 | $this->tags_by_voc[$voc->vid] = array();
207 |
208 | for ($t = 0; $t < $amount_of_tags_per_voc; $t++) {
209 | $tag = $tx_test->createTerm($voc);
210 | $this->tags[] = $tag;
211 | $this->tags_by_voc[$voc->vid][] = $tag;
212 | }
213 |
214 | }
215 | return $this;
216 | }
217 |
218 | /**
219 | * Creates $amount nodes with terms attached.
220 | *
221 | *
222 | * Fuck it, I am poking around in the database directly instead of testing
223 | * and preparing all this field, entity, admin-user and whatnot. I am not
224 | * interested in whether or not we can store nodes with tags, only that they
225 | * are there. By adding them to the database, we achieve that.
226 | */
227 | private function createNodesWithTags($amount) {
228 | $this->nodes = array();
229 | $attachable = $this->tags;
230 |
231 | for ($i = 0; $i < $amount; $i++) {
232 | // Post an article.
233 | $node = new \StdClass();
234 | $node->title = $this->randomName();
235 | $node->type = "story";
236 | node_save($node);
237 | $this->nodes[] = $node;
238 |
239 | // Attach the terms
240 | $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
241 | foreach($attachable as $tag) {
242 | $query->values(array(
243 | 'nid' => $node->nid,
244 | 'tid' => $tag->tid,
245 | 'sticky' => TRUE,
246 | 'created' => $node->created,
247 | ));
248 | }
249 | $query->execute();
250 |
251 | //remove one tag, so the next node gets one less tag attached.
252 | array_shift($attachable);
253 | }
254 | return $this;
255 | }
256 |
257 | private function enableBlock() {
258 | theme_enable(array('seven'));
259 | $region = 'content';
260 | $module = 'tagadelic_taxonomy';
261 | // set the block to a theme region, taken from block.test
262 | $delta = db_query("SELECT delta FROM {block} WHERE module = :module AND theme = :theme", array(':module' => $module, ':theme' => 'seven'))->fetchField();
263 | $edit = array();
264 | $edit['blocks[' . $module . '_' . $delta . '][region]'] = $region;
265 |
266 | $this->drupalLogin($this->admin_user);
267 | $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
268 | $this->drupalLogout();
269 | }
270 |
271 | /**
272 | * assertHasXpath Asserts the existence of an xpath
273 | *
274 | * @scope private
275 | * @returns Boolean Boolean Assertion-result
276 | */
277 | private function assertHasXpath($xpath, $message = '', $group = 'Other') {
278 | if (empty($message)) {
279 | $message = "xpath '{$xpath}' not found.";
280 | }
281 | $xpath = $this->xpath($xpath);
282 | $truthiness = count($xpath) > 0;
283 | return $this->assertTrue($truthiness, $message, $group);
284 | }
285 |
286 | private function assertHasTag($name, $message = '', $group = 'Other') {
287 | $xpath = "//ul[@class='tag-cloud']/li/a";
288 | return $this->assertHasXpath($xpath, $message, $group);
289 | }
290 |
291 | private function assertAmountTagsOnPage($expected_amount, $message = '', $group = 'Other') {
292 | $amount = count($this->xpath("//*/ul[@class='tag-cloud']/li"));
293 | if (!$message) {
294 | $message = t("Expected $expected_amount Tags, found $amount");
295 | }
296 | $this->assertEqual($expected_amount, $amount, $message);
297 | }
298 |
299 | private function assertTagHasWeight($name, $weight, $message = '', $group = 'Other') {
300 | $truthiness = FALSE;
301 | $class ='';
302 | $xpath = $this->xpath("//*/ul[@class='tag-cloud']/li/a[contains(text(),'{$name}')]");
303 |
304 | if (!empty($xpath)) {
305 | $attributes = $xpath[0]->attributes();
306 | $class = $attributes["class"];
307 | if ($class == "level{$weight}") $truthiness = TRUE;
308 | }
309 |
310 | if (empty($message)) {
311 | $message = "No tag with name '{$name}' and class 'level{$weight}' found. Tag with '{$name}' has class '{$class}'";
312 | }
313 |
314 | return $this->assertTrue($truthiness, $message, $group = 'Other');
315 | }
316 |
317 | // Inverse of http://api.drupal.org/api/drupal/modules!simpletest!drupal_web_test_case.php/function/DrupalWebTestCase%3A%3AassertRaw/7
318 | private function assertNotRaw($raw, $message = '', $group = 'Other') {
319 | if (!$message) {
320 | $message = t('Raw "@raw" not found', array('@raw' => $raw));
321 | }
322 | return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
323 | }
324 | }
325 |
--------------------------------------------------------------------------------