From 15b197c28406e4621fc5bd80bdab3bb49ddc8c96 Mon Sep 17 00:00:00 2001 From: Gordon Anderson Date: Tue, 19 May 2015 07:35:35 +0700 Subject: [PATCH] ENHANCEMENT: Addition of tag cloud widget complete with tests --- .travis.yml | 2 +- code/widgets/BlogTagsCloudWidget.php | 108 +++++++++++++++++++++++ css/blog.css | 44 +++++++++ scss/blog.scss | 90 +++++++++++++++---- templates/widgets/BlogTagsCloudWidget.ss | 12 +++ tests/BlogCategoryTest.php | 2 +- tests/BlogTagsCloudWidgetTest.php | 60 +++++++++++++ tests/blog.yml | 48 ++++++++++ 8 files changed, 349 insertions(+), 17 deletions(-) create mode 100644 code/widgets/BlogTagsCloudWidget.php create mode 100644 templates/widgets/BlogTagsCloudWidget.ss create mode 100644 tests/BlogTagsCloudWidgetTest.php diff --git a/.travis.yml b/.travis.yml index bb726e5..a44118b 100755 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ before_script: - phpenv rehash - composer self-update || true - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss + - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require "silverstripe/comments" --require "silverstripe/widgets" - cd ~/builds/ss #Execute tests with or without coverage diff --git a/code/widgets/BlogTagsCloudWidget.php b/code/widgets/BlogTagsCloudWidget.php new file mode 100644 index 0000000..550e9f3 --- /dev/null +++ b/code/widgets/BlogTagsCloudWidget.php @@ -0,0 +1,108 @@ + 'Blog', + ); + + /** + * {@inheritdoc} + */ + public function getCMSFields() + { + $this->beforeUpdateCMSFields(function ($fields) { + /* + * @var FieldList $fields + */ + $fields->push( + DropdownField::create('BlogID', _t('BlogTagsCloudWidget.Blog', + 'Blog'), Blog::get()->map()) + ); + }); + + return parent::getCMSFields(); + } + + /** + * @return array + */ + public function getTags() + { + if ($blog = $this->Blog()) { + $escapedID = Convert::raw2sql($blog->ID); + $sql = 'SELECT DISTINCT "BlogTag"."URLSegment","BlogTag"."Title",Count("BlogTagID") AS "TagCount" + from "BlogPost_Tags" + INNER JOIN "BlogPost" + ON "BlogPost"."ID" = "BlogPost_Tags"."BlogPostID" + INNER JOIN "BlogTag" + ON "BlogTag"."ID" = "BlogPost_Tags"."BlogTagID" + WHERE "BlogID" = ' . $escapedID + . ' GROUP By "BlogTag"."URLSegment","BlogTag"."Title" + ORDER BY "Title"'; + + $records = DB::query($sql); + $bloglink = $blog->Link(); + $maxTagCount = 0; + + // create DataObjects that can be used to render the tag cloud + $tags = new ArrayList(); + foreach ($records as $record) { + $tag = new DataObject(); + $tag->TagName = $record['Title']; + $link = $bloglink.'tag/'.$record['URLSegment']; + $tag->Link = $link; + if ($record['TagCount'] > $maxTagCount) { + $maxTagCount = $record['TagCount']; + } + $tag->TagCount = $record['TagCount']; + $tags->push($tag); + } + + // normalize the tag counts from 1 to 10 + $tagfactor = 10 / $maxTagCount; + foreach ($tags->getIterator() as $tag) { + $normalized = round($tagfactor * ($tag->TagCount)); + $tag->NormalizedTag = $normalized; + } + + return $tags; + } + + return array(); + } +} + +class BlogTagsCloudWidget_Controller extends Widget_Controller +{ +} diff --git a/css/blog.css b/css/blog.css index fee7da5..fe370bc 100644 --- a/css/blog.css +++ b/css/blog.css @@ -12,3 +12,47 @@ .blog-sidebar .WidgetHolder ul li { list-style-type: none; } +ul.blogTagCloud { + list-style-type: none; + clear: both; +} +ul.blogTagCloud li { + float: left; + display: inline; + padding-right: 8px; +} +ul.blogTagCloud li a span { + float: left; + line-height: 30px; text-align: center; + padding: 0px; +} +ul.blogTagCloud .tagCount10 { + font-size: 26pt; +} +ul.blogTagCloud .tagCount9 { + font-size: 24pt; +} +ul.blogTagCloud .tagCount8 { + font-size: 22pt; +} +ul.blogTagCloud .tagCount7 { + font-size: 20pt; +} +ul.blogTagCloud .tagCount6 { + font-size: 18pt; +} +ul.blogTagCloud .tagCount5 { + font-size: 16pt; +} +ul.blogTagCloud .tagCount4 { + font-size: 14pt; +} +ul.blogTagCloud .tagCount3 { + font-size: 12pt; +} +ul.blogTagCloud .tagCount2 { + font-size: 10pt; +} +ul.blogTagCloud .tagCount1 { + font-size: 8pt; +} diff --git a/scss/blog.scss b/scss/blog.scss index 0be33cf..2f022cf 100644 --- a/scss/blog.scss +++ b/scss/blog.scss @@ -1,15 +1,75 @@ -.no-sidebar .content-container.size3of4 { - width: 75%; -} - -.blog-entry .post-image img { - width: 98.75%; -} - -.blog-sidebar .WidgetHolder ul { - margin-left: 0; - - li { - list-style-type: none; - } -} +.no-sidebar .content-container.size3of4 { + width: 75%; +} + +.blog-entry .post-image img { + width: 98.75%; +} + +.blog-sidebar .WidgetHolder ul { + margin-left: 0; + + li { + list-style-type: none; + } +} + +// tag cloud related +$baseTagFontSize:4pt; + +ul.blogTagCloud { + list-style-type: none; + clear: both; + + li { + float: left; + display: inline; + padding-right: 8px; + + a span { + float: left; + line-height: 30px; text-align: center; + padding: 0px; + } + } + + .tagCount10 { + font-size: $baseTagFontSize+22pt; + } + + .tagCount9 { + font-size: $baseTagFontSize+20pt; + } + + .tagCount8 { + font-size: $baseTagFontSize+18pt; + } + + .tagCount7 { + font-size: $baseTagFontSize+16pt; + } + + .tagCount6 { + font-size: $baseTagFontSize+14pt; + } + + .tagCount5 { + font-size: $baseTagFontSize+12pt; + } + + .tagCount4 { + font-size: $baseTagFontSize+10pt; + } + + .tagCount3 { + font-size: $baseTagFontSize+8pt; + } + + .tagCount2 { + font-size: $baseTagFontSize+6pt; + } + + .tagCount1 { + font-size: $baseTagFontSize+4pt; + } +} diff --git a/templates/widgets/BlogTagsCloudWidget.ss b/templates/widgets/BlogTagsCloudWidget.ss new file mode 100644 index 0000000..f327e36 --- /dev/null +++ b/templates/widgets/BlogTagsCloudWidget.ss @@ -0,0 +1,12 @@ +<% if $Tags %> + +
+<% end_if %> diff --git a/tests/BlogCategoryTest.php b/tests/BlogCategoryTest.php index db0564f..c6aef8b 100755 --- a/tests/BlogCategoryTest.php +++ b/tests/BlogCategoryTest.php @@ -49,7 +49,7 @@ class BlogCategoryTest extends FunctionalTest */ $category = $this->objFromFixture('BlogCategory', 'FirstCategory'); - $this->assertEquals(1, $category->BlogPosts()->count(), 'Category blog post count'); + $this->assertEquals(5, $category->BlogPosts()->count(), 'Category blog post count'); } public function testCanView() diff --git a/tests/BlogTagsCloudWidgetTest.php b/tests/BlogTagsCloudWidgetTest.php new file mode 100644 index 0000000..43d1a67 --- /dev/null +++ b/tests/BlogTagsCloudWidgetTest.php @@ -0,0 +1,60 @@ +markTestSkipped('Widgets module not installed'); + } + + $widget = new BlogTagsCloudWidget(); + $fields = $widget->getCMSFields(); + $names = array(); + foreach ($fields as $field) { + array_push($names, $field->getName()); + } + + $expected = array('Title', 'Enabled', 'BlogID'); + $this->assertEquals($expected, $names); + } + + public function testGetTags() { + if (!class_exists('Widget')) { + $this->markTestSkipped('Widgets module not installed'); + } + $widget = new BlogTagsCloudWidget(); + $blog = $this->objFromFixture('Blog', 'FourthBlog'); + $widget->BlogID = $blog->ID; + $widget->write(); + $tags = $widget->getTags()->toArray(); + + $tag = $tags[0]; + $this->assertEquals('Cat', $tag->TagName); + $this->assertEquals('/fourth-blog/tag/cat', $tag->Link); + $this->assertEquals(2, $tag->TagCount); + $this->assertEquals(5, $tag->NormalizedTag); + + $tag = $tags[1]; + $this->assertEquals('Cool', $tag->TagName); + $this->assertEquals('/fourth-blog/tag/cool', $tag->Link); + $this->assertEquals(3, $tag->TagCount); + $this->assertEquals(8, $tag->NormalizedTag); + + $tag = $tags[2]; + $this->assertEquals('Kiwi', $tag->TagName); + $this->assertEquals('/fourth-blog/tag/kiwi', $tag->Link); + $this->assertEquals(1, $tag->TagCount); + $this->assertEquals(3, $tag->NormalizedTag); + + $tag = $tags[3]; + $this->assertEquals('Popular', $tag->TagName); + $this->assertEquals('/fourth-blog/tag/popular', $tag->Link); + $this->assertEquals(4, $tag->TagCount); + $this->assertEquals(10, $tag->NormalizedTag); + } +} diff --git a/tests/blog.yml b/tests/blog.yml index b4be745..e9f6690 100755 --- a/tests/blog.yml +++ b/tests/blog.yml @@ -85,6 +85,24 @@ BlogTag: URLSegment: 'third-tag' Blog: =>Blog.ThirdBlog + #Tags for Tag Cloud widget + PopularTag: + Title: 'Popular' + URLSegment: 'popular-tag' + Blog: =>Blog.FourthBlog + CoolTag: + Title: 'Cool' + URLSegment: 'cool-tag' + Blog: =>Blog.FourthBlog + CatTag: + Title: 'Cat' + URLSegment: 'cat-tag' + Blog: =>Blog.FourthBlog + KiwiTag: + Title: 'Kiwi' + URLSegment: 'kiwi-tag' + Blog: =>Blog.FourthBlog + BlogCategory: FirstCategory: Title: 'First Category' @@ -146,3 +164,33 @@ BlogPost: PublishDate: '2012-01-09 15:00:00' Parent: =>Blog.FourthBlog Authors: =>Member.BlogEditor,=>Member.Writer,=>Member.Contributor + + #Posts for the tag cloud widget test + TaggedPost1: + Title: 'Tagged Post 1' + URLSegment: tagged-post-1 + PublishDate: '2012-01-09 15:00:00' + Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag + Categories: =>BlogCategory.FirstCategory + Parent: =>Blog.FourthBlog + TaggedPost2: + Title: 'Tagged Post 2' + URLSegment: tagged-post-2 + PublishDate: '2012-01-09 15:00:00' + Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag,=>BlogTag.CatTag + Categories: =>BlogCategory.FirstCategory + Parent: =>Blog.FourthBlog + TaggedPost3: + Title: 'Tagged Post 3' + URLSegment: tagged-post-3 + PublishDate: '2012-01-09 17:20:00' + Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag,=>BlogTag.CatTag,=>BlogTag.KiwiTag + Categories: =>BlogCategory.FirstCategory + Parent: =>Blog.FourthBlog + TaggedPost4: + Title: 'Tagged Post 4' + URLSegment: tagged-post-4 + PublishDate: '2012-04-09 15:00:00' + Tags: =>BlogTag.PopularTag + Categories: =>BlogCategory.FirstCategory + Parent: =>Blog.FourthBlog