From 1febdc5f07e0458d18cdb51ebab348416056340d Mon Sep 17 00:00:00 2001
From: UndefinedOffset
Date: Tue, 17 Dec 2013 12:23:54 -0400
Subject: [PATCH] Initial Commit
---
.gitignore | 3 +
LICENSE | 27 +++++++
README.md | 43 ++++++++++
_config.php | 6 ++
_config/config.yml | 6 ++
code/PackagistShortCode.php | 109 ++++++++++++++++++++++++++
composer.json | 23 ++++++
css/PackagistButton.css | 98 +++++++++++++++++++++++
images/packagist-button.png | Bin 0 -> 5845 bytes
templates/Includes/PackagistButton.ss | 14 ++++
10 files changed, 329 insertions(+)
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 _config.php
create mode 100644 _config/config.yml
create mode 100644 code/PackagistShortCode.php
create mode 100644 composer.json
create mode 100644 css/PackagistButton.css
create mode 100644 images/packagist-button.png
create mode 100644 templates/Includes/PackagistButton.ss
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5aa30a2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/.buildpath
+/.project
+/.settings
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..26dcd2a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013, The Web Builders Group Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ Neither the name of The Web Builders Group Inc nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d727778
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+Packagist Short Code
+=================
+Add a short code for adding a Packagist installs button with a count to a HTMLText field.
+
+## Maintainer Contact
+* Ed Chipman ([UndefinedOffset](https://github.com/UndefinedOffset))
+
+## Requirements
+* SilverStripe CMS 3.x
+
+
+## Installation
+* Download the module from here https://github.com/webbuilders-group/silverstripe-packagistshortcode/archive/master.zip
+* Extract the downloaded archive into your site root so that the destination folder is called githubshortcode, opening the extracted folder should contain _config.php in the root along with other files/folders
+* Run dev/build?flush=all to regenerate the manifest
+
+
+## Usage
+Usage is pretty straight forward to add a packagist downloads button you simply add the following:
+```
+[packagist package="package owner/package name"]
+```
+
+Optionally you may add mode="monthly" or button="daily" (defaults to total) to show the download count for the given period.
+```
+[packagist package="package owner/package name" mode="monthly"]
+
+```
+
+In 3.1 the short codes above will work as included however the updated syntax for the short code would be (of course layout and button are not required):
+```
+[packagist,package="package owner/package name",mode="monthly"]
+```
+
+
+#### Configuration Options
+There are a few configuration options available to you:
+
+```yml
+PackagistShortCode:
+ CacheTime: 86400 #Cache time in seconds (default is 1 day, remember the GitHub api is rate limited)
+ UseShortHandNumbers: true #Use short hand numbers i.e 5.6K or not
+```
diff --git a/_config.php b/_config.php
new file mode 100644
index 0000000..3f9c716
--- /dev/null
+++ b/_config.php
@@ -0,0 +1,6 @@
+register('packagist', array('PackagistShortCode', 'parse'));
+?>
\ No newline at end of file
diff --git a/_config/config.yml b/_config/config.yml
new file mode 100644
index 0000000..46f53c4
--- /dev/null
+++ b/_config/config.yml
@@ -0,0 +1,6 @@
+---
+Name: packagistbutton
+---
+PackagistShortCode:
+ CacheTime: 86400 #Cache time in seconds
+ UseShortHandNumbers: true #Use short hand numbers i.e 5.6K or not
\ No newline at end of file
diff --git a/code/PackagistShortCode.php b/code/PackagistShortCode.php
new file mode 100644
index 0000000..def229e
--- /dev/null
+++ b/code/PackagistShortCode.php
@@ -0,0 +1,109 @@
+Packagist package undefined
';
+ }
+
+ //Get Config
+ $config=Config::inst()->forClass('PackagistShortCode');
+
+
+ $obj=new ViewableData();
+
+ //Add the Respository Setting
+ $obj->Package=$arguments['package'];
+
+ //Add the button config
+ if(array_key_exists('mode', $arguments) && ($arguments['mode']=='total' || $arguments['mode']=='monthly' || $arguments['mode']=='daily')) {
+ $obj->DisplayMode=$arguments['mode'];
+ }else {
+ $obj->DisplayMode='total';
+ }
+
+ //Retrieve Stats
+ SS_Cache::set_cache_lifetime('PackagistShortCode', $config->CacheTime);
+
+ $cacheKey=md5('packagistshortcode_'.$arguments['package']);
+ $cache=SS_Cache::factory('PackagistShortCode');
+ $cachedData=$cache->load($cacheKey);
+ if($cachedData==null) {
+ $response=self::getFromAPI($arguments['package']);
+
+ //Verify a 200, if not say the repo errored out and cache false
+ if(empty($response) || $response===false || !property_exists($response, 'package')) {
+ $cachedData=array('total'=>'N/A', 'monthly'=>'N/A', 'daily'=>'N/A');
+ }else {
+ if($config->UseShortHandNumbers==true) {
+ $totalDownloads=self::shortHandNumber($response->package->downloads->total);
+ $monthlyDownloads=self::shortHandNumber($response->package->downloads->monthly);
+ $dailyDownloads=self::shortHandNumber($response->package->downloads->daily);
+ }else {
+ $totalDownloads=number_format($response->package->downloads->total);
+ $monthlyDownloads=number_format($response->package->downloads->monthly);
+ $dailyDownloads=number_format($response->package->downloads->daily);
+ }
+
+ $cachedData=array('total'=>$totalDownloads, 'monthly'=>$monthlyDownloads, 'daily'=>$dailyDownloads);
+ }
+
+ //Cache response to file system
+ $cache->save(serialize($cachedData), $cacheKey);
+ }else {
+ $cachedData=unserialize($cachedData);
+ }
+
+
+ $obj->TotalDownloads=$cachedData['total'];
+ $obj->MonthlyDownloads=$cachedData['monthly'];
+ $obj->DailyDownloads=$cachedData['daily'];
+
+
+ //Init ss viewer and render
+ Requirements::css(PACKAGISTSHORTCODE_BASE.'/css/PackagistButton.css');
+
+ $ssViewer=new SSViewer('PackagistButton');
+ return $ssViewer->process($obj);
+ }
+
+ /**
+ * Loads the data from the github api
+ * @param {string} $url URL to load
+ * @return {stdObject} Returns the JSON Response from the GitHub API
+ *
+ * @see http://developer.github.com/v3/repos/#get
+ */
+ final protected static function getFromAPI($repo) {
+ if(function_exists('curl_init') && $ch=curl_init()) {
+ curl_setopt($ch, CURLOPT_URL, 'https://packagist.org/packages/'.$repo.'.json');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+
+
+ $contents=json_decode(curl_exec($ch));
+ curl_close($ch);
+
+ return $contents;
+ }else {
+ user_error('CURL is not available', E_USER_ERROR);
+ }
+ }
+
+ /**
+ * Gets the short hand of the given number so 1000 becomes 1k, 2000 becomes 2k, and 1000000 becomes 1m etc
+ * @param {int} $number Number to convert
+ * @return {string} Short hand of the given number
+ */
+ protected static function shortHandNumber($number) {
+ if($number>=1000000000) {
+ return round($number/1000000000, 1).'B';
+ }else if($number>=1000000) {
+ return round($number/1000000, 1).'M';
+ }else if($number>=1000) {
+ return round($number/1000, 1).'K';
+ }
+
+ return $number;
+ }
+}
+?>
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..367a3ef
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,23 @@
+{
+ "name": "webbuilders-group/silverstripe-packagistshortcode",
+ "description": "Add a short code for adding a Packagist installs button with a count to a HTMLText field.",
+ "type": "silverstripe-module",
+ "keywords": ["silverstripe", "packagist", "shortcode"],
+ "license": "BSD-3-Clause",
+ "authors": [
+ {
+ "name": "Ed Chipman",
+ "homepage": "http://webbuildersgroup.com",
+ "role": "Developer"
+ }
+ ],
+
+ "require":
+ {
+ "silverstripe/framework": "3.*",
+ "composer/installers": "*"
+ },
+ "support": {
+ "issues": "https://github.com/webbuilders-group/silverstripe-packagistshortcode/issues"
+ }
+}
diff --git a/css/PackagistButton.css b/css/PackagistButton.css
new file mode 100644
index 0000000..08536d4
--- /dev/null
+++ b/css/PackagistButton.css
@@ -0,0 +1,98 @@
+.packagistButtonGroup .packagistButton {
+ clear: both;
+
+ margin: 10px 0 20px 0;
+}
+
+.packagistButtonGroup.stacked .packagistButton {
+ display: block;
+}
+
+.packagistButtonGroup.stacked .packagistButton + .packagistButton {
+ margin-top: -10px;
+}
+
+.packagistButtonGroup.inline .packagistButton + .packagistButton {
+ margin-left: 4ex;
+}
+
+.packagistButtonGroup .packagistButton a {
+ background: url(./../images/packagist-button.png) no-repeat;
+
+ display: inline-block;
+
+ width: 170px;
+ height: 26px;
+
+ vertical-align: middle;
+}
+
+.packagistButtonGroup a.packagistDownloadsButton:hover, .packagistButtonGroup a.packagistDownloadsButton:active {
+ background-position: 0 -26px;
+}
+
+.packagistButtonGroup .packagistButton span.count {
+ background-color: #FAFAFA;
+
+ position: relative;
+
+ font-family: Arial, sans-serif;
+ font-size: 11px;
+ color: #666666;
+
+ text-decoration: none;
+ text-shadow: 0 1px 0 #FFFFFF;
+
+ line-height: 15px;
+
+ white-space: nowrap;
+
+ border: 1px solid #DDDDDD;
+
+ margin-left: 8px;
+ padding: 6px 7px 5px;
+
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.packagistButtonGroup .packagistButton span.count:after {
+ display: block;
+
+ position: absolute;
+ top: 50%;
+ right: 100%;
+
+ content: "";
+
+ border-width: 6px;
+ border-style: solid;
+ border-color: transparent #FAFAFA transparent transparent;
+
+ width: 0;
+ height: 0;
+
+ margin-right: -1px;
+ margin-top: -6px;
+}
+
+.packagistButtonGroup .packagistButton span.count:before {
+ display: block;
+
+ position: absolute;
+ top: 50%;
+ right: 100%;
+
+ content: "";
+
+ border-width: 6px;
+ border-style: solid;
+ border-color: transparent #D4D4D4 transparent transparent;
+
+ width: 0;
+ height: 0;
+
+ margin-right: 0;
+ margin-top: -6px;
+}
\ No newline at end of file
diff --git a/images/packagist-button.png b/images/packagist-button.png
new file mode 100644
index 0000000000000000000000000000000000000000..b6cc080a4ea1da1a1baa6f3adf4333cdacd3f956
GIT binary patch
literal 5845
zcmaJ_byQUAyGB4Hr5j`jQF?}EXlLl|7GY+9L75?jZls0|0hN+gq`MSp0i|0SX%4M4
zUOc~Z&hP$l&)sY7{l$8o=Z)`Od%b&Ob+uKnFN#ub612uIr@0BTM)_6U814cyzM7a@a#g9ktwnqo|~G{G>mlc3FS
zjG&j3^9>sZM@HVu*#`C$fdSYe?2#y0j=knq4geA^%V8p>1=MneARLgYKCTD@A8kXJ
z&r_HboI_p?AmatT5pY6aYye(P&roh)FIkR1b-_3D-`heQfIlIar?MRXamrLn7XU%K
zA^>87Kmiy~90(8x34%mKB_t&H0m48KPzWe21QHeiNq|L!!9XD3uZ!cxnk(E6tPfTG
z%ht_Gmcs#qaRv(sd3t&ZdWs05UG0THQc_aCHH3u)ZV&=)-YATXmjKF*^KS(x!VTt%
zbjBdjD8O$;8(XwHMwa8o)Bl9vT1yM8hH}H$pkN3!s4T|~Ul56egB8UIY?`hBeb>zM!Ex~ZMt(|?NgX7NwiBTzTB?s`+yHUx=z
zI5^ZAYEVT(ubCYyB8;I@({+=ynmv0o1(*m9BLi>%Y}A0asJ%so*EbmLmD}ZTpMP8=
zZSTm7u&Q#0_Kz+KFG_u#-oaJrBYECa>*6B75^eNb$PbYZO7BgOR_tL@wuG;IpJ&C
z{3EQR@T(TN#3Z+`uf^V$mb&xg!L6#`SOrr>u$Etxp8Um*NXzMRbWFbg#m}x1v+9Jj
zw1}cCA7V;M%9zfhwXd*=38SdQ?8M+0dlEfwod|PmyS-X7<5~Wl-4Uzd@Os_se+FJ?6`&3
z>2iVDmtVifU2;6VBBmK|8Z7$3>oBh_Y#MdYrNJf7rc{GcVqdeH8ULCQ-A>FG=U=@$
zvOD84u1L9^S0HYnzknNA;>F218oQV0VPztPwye{HSlk;qj#cZI2zzzTbYxuid^QzaBipsIM?!7ECIF
zZMCCQ7#J~Tks_X-MRH~o7!?J$wa(SA6hDvQpODU|N~O)_;BkFyOrRD`@nrAX>$rE-
zd4#iT>SJ*CdAyB2m`$_jur|LnBF$!gfLP@+Ds#%`r81*$B}WH|B~$9q;h8N<>bLlD
zmz~S?ST?;6Gg(#U+CFBI1Qn9KbX&pajEr+U(Y
zsTb*eFFK(EOJ2l(bh6gMoJ;IqCa7`mv$EK+^xSfx&E9ZV8%Fk_M9Pg1!L4Atp
zW!_17-twW`HbfEfdOyhfoF;DQ9wP3xe>fh@8W9TIRAb1g-5r|!6erIH&zDK(<2>UY
z^sikkgcm`SosCv{alxyAi8P;gI%(e9xRYorn(?u*isJ^C6$Z6;!sxNm=ati-PcdZ=S?X!j&!-ikTv{JWp2H?q>a
z4#r&AH}hsa*i6qobF@$oy@_T{&o+*&WNkeL*prd_VTH`(0%vbw{hz=ad>H(Pi~3vK
zgSXjaeQE@DpP^9QLAUVsuP^qh1$cPJ##>M3eF=$(Y*JIHUUyd?=g^zvdeHEJyY&dP
zNDEPXNKY6vj)t~5%fzzNjB44jZv7|s)o8F)GtX7Rkm6-eIjg9zE8ZtQnfbBJ
z+C3`wHC+O_$_E00zL<~jVQ$`6J7?paozOZ~C6lx5iBi}gh5qV@E3b~+S-y@0O^K_|
z53c-pjjk#Pyxlg*)Gv9YmF+;OmtnDDn7gXsHAI(^Pp{FJBHV_&@qluO%FotafUzm9)i~^?IDb1>H*-L^1`ReV?j%|B_9xRM+^^5*^v1rSxS+
zJ#he?5oUAbzKHwaJpbE=Qk!zcV&beaUO)@U@$vD>=fwAU$nZ9_a8!t(4p2f|Rp6X@
z2r^H@JY?~n4IveCh^wObzncIFHP$A0mmx@%xw6fgNHpQ4(>N65NaY^I26a5w6B7r`gJilVMs0E9=yH
zrS%${x!8GZE-I_L;6*-7^ls(IBq9D8BbEz4_F`?>^X`S7l&L`r4X3%g)l5z7Ta3}}
zBtv9a0sF03n=3O(qLHtSOiWn9cUR{YYguTE_vEZZ9
zSmo1CaQw#n=3Fwg64AI=W4iBp4xtuPI7O=jg8$Si*LR_37yGs*JGW>eLwvjI(n_p0
zKmMl#Yc`ZRFR2}4^OXGvDG4!ZpTVq=uQjpIEwe3+MerzR5wX!?g
z$yP71)Fj_DJPDa*2vIfTitoGiQWho|!0JzeZZ(L232qKh1cD%uD1G1nS(``sHEy~R
zGgmCdo&KQ8V^{TrGt*yN4^|J2~R8qu~i#ICNx##PO8
z0PeD2L>S)rK(qfnx*l!2R7XIP=ws8h%q4TAf0rx0ztU*aM085(cl(4|D;=db;4USO
zwsT!*JKcwq{S2@g3@Fd~^-!67_jxPp$C!8_$BJFm+wGBm1bV5824ss7GJhOtFk(6}
zW4v$PUk>u5;Vlhsdc~L0EgM>)J5blVX#7oRXjsv)`#Ay
zg@>PbORdi0fA+>|vtS^rck5_RppHIVRB*0x?43e4scnmVl8thj6uMr
zny*GU?tYh=5bOyBips})1@=eI`ZTD;dXPre!03Z^<3znhjasAlVY
z`%#f0~t!=IDSXJcS`&FFBL(5D1$;(Xg
zJe^sWvhytS*e3XNrAdInK%qr-$DxY2E?$-=oF#gVmE*2Tc-OBZmO^EVC;`dUii<}f
zwN}kFZ}U7dvPaL#7_C>Koc>;DhH^e2g2C!sl!B_!_Oc)rdWO+6C=MuBK+^hM_ufb{1
z&QUh0n`-?YiQXat5BTo?bX_Q>EyHP9IOl^4gxz~rrdMzGO
z3x76av`?15TG`sp$>(#0P>D3zAki(+*~LRt(X2PZJf6clFed))qbl|Am^+`pXTIyE
zf99v{5A7)FHORJtRJInsqE||^0fNdByt|`H+a60xOk(p?!B^k{(-~stCiS5
z$^yb={qh&XBf4M{mx4#ZUEhS3Ps!^Kmg}M&92>~q>BrsHi9wM0U4M0=XQ{sGn;bTOebr1InmPwnVZN%c;H0pcvZ91FOah~?F4$)fW^Cb^R9*~`X{yaV*9kr^LbiKK^K&8*@
z=VN};XK{Dp78gIYfeMA*e~{1>%P=UL9X$Ke!t}>EEz3rGgg!j6?c>~btA1(cC_20Q
z$beuuaS6nbG<$6oWKPxZ=UPS}t!;ejhc-z-JtU&upSB?4;%*II6_Ia~n~nF{I`3!N
zZ_JLz9-3W=M5{~eUnR2pb5h)6xgl3fN}?e|ht-KWQpl+!RI9b;9kjp&-9>Z5Ttk*k
z=F#FYxslf6aeDqO9fJT#-I#+rV79cAqqisLM1ePb*r|e{2reFUXe$O+@Ajq#l#KXA
zMP^t~{$qCCSyWK31I8O=NTGP02^C8xrO?oP!$Lc(K6v$`=4@w`*r67z_%sB=oT&aB
lXs60Se9dQd{0o;9X9>35wX`K#|NBR?nvyoO?9r2u{{eRy!r}k`
literal 0
HcmV?d00001
diff --git a/templates/Includes/PackagistButton.ss b/templates/Includes/PackagistButton.ss
new file mode 100644
index 0000000..cc5cca4
--- /dev/null
+++ b/templates/Includes/PackagistButton.ss
@@ -0,0 +1,14 @@
+
+
+
+
+ <% if $DisplayMode=='monthly' %>
+ $MonthlyDownloads
+ <% else_if $DisplayMode=='daily' %>
+ $DailyDownloads
+ <% else %>
+ $TotalDownloads
+ <% end_if %>
+
+
+
\ No newline at end of file