diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5b99c31..9c4f271 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -3,11 +3,11 @@
-
-
-
+
+
+
@@ -62,37 +62,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -105,18 +75,12 @@
@@ -169,7 +139,7 @@
-
+
@@ -252,20 +222,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -364,32 +320,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -434,7 +364,7 @@
-
+
@@ -460,28 +390,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -526,37 +434,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -580,6 +458,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -593,7 +485,7 @@
-
+
@@ -609,7 +501,7 @@
-
+
@@ -620,6 +512,11 @@
+
+
+
+
+
@@ -659,16 +556,18 @@
-
+
+
-
-
-
+
+
+
+
@@ -720,29 +619,29 @@
-
-
+
+
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
-
+
@@ -766,45 +665,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -892,195 +756,199 @@
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/www/css/styles.css b/www/css/styles.css
index 9ee7da9..b5077bb 100644
--- a/www/css/styles.css
+++ b/www/css/styles.css
@@ -351,4 +351,93 @@ ul.nav li.dropdown-append:hover > ul.dropdown-menu {
.expCollContent > div {
padding: 15px 60px;
+}
+
+/* ExtendedGitGraph
+-------------------------------------------------- */
+
+.git_list {
+ display: inline-block;
+ width: 715px;
+ height: 115px;
+ overflow: visible;
+}
+
+.git_list text.caption {
+ font-size: 10px;
+ fill: #666;
+}
+
+.git_list text.caption_month {
+ font-size: 8px;
+ fill: #BBB;
+}
+
+.git_list text.caption_day {
+ font-size: 8px;
+ fill: #BBB;
+}
+
+.svg-tip:after {
+ box-sizing: border-box;
+ position: absolute;
+ left: 50%;
+ height: 5px;
+ width: 5px;
+ bottom: -10px;
+ margin: 0px 0px 0px -5px;
+ content: " ";
+ border: 5px solid transparent;
+ border-top-color: rgba(0, 0, 0, 0.8);
+ -moz-border-top-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-bottom-colors: none;
+ -moz-border-left-colors: none;
+ border-image: none;
+}
+
+.svg-tip {
+ padding: 5px;
+ background: none repeat scroll 0% 0% rgba(0, 0, 0, 0.8);
+ color: #BBB;
+ font-size: 12px;
+ position: absolute;
+ z-index: 99999;
+ text-align: center;
+ border-radius: 3px;
+ box-sizing: border-box;
+ opacity: 0;
+}
+
+.extGitGraphContainer {
+ background-color: #ECF0F1;
+ margin: 10px;
+ display: inline-block;
+
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ box-shadow: 0px 0 1px rgba(0, 0, 0, 0.25) inset;
+}
+
+.egg_footer {
+ margin-top: 5px;
+
+ text-align: right;
+ margin-right: 5px;
+ margin-bottom: 5px;
+
+ color: #FFF;
+ text-shadow: 0px 0px 8px #2C3E50, 0px 0px 8px #2C3E50;
+}
+
+.egg_footer > a {
+
+ text-decoration: none;
+ color: inherit;
+}
+
+.egg_footer > a:hover {
+ text-decoration: none;
+ color: #2C3E50;
+ text-shadow: 0px 0px 8px #00F;
}
\ No newline at end of file
diff --git a/www/protected/components/MSController.php b/www/protected/components/MSController.php
index f6d029d..7dd71a6 100644
--- a/www/protected/components/MSController.php
+++ b/www/protected/components/MSController.php
@@ -22,4 +22,9 @@ class MSController extends CController
* @var string the currently active Element in the Navbar
*/
public $selectedNav = '';
+
+ /**
+ * @var string[] additional js scripts
+ */
+ public $js_scripts = array();
}
\ No newline at end of file
diff --git a/www/protected/components/extendedGitGraph/demo.php b/www/protected/components/extendedGitGraph/demo.php
new file mode 100644
index 0000000..fe6ca57
--- /dev/null
+++ b/www/protected/components/extendedGitGraph/demo.php
@@ -0,0 +1,34 @@
+authenticate('7e26c5f1621349c14a7d');
+
+//$v->setToken('7b3f6443cdd4b2f92d75c4c8aa83cfda6c7ca3ce');
+//$v->collect();
+
+$v->loadData();
+
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+ generateAndSave();
+ echo $v->loadFinished();
+ ?>
+
+
\ No newline at end of file
diff --git a/www/protected/components/extendedGitGraph/extendedGitGraph.php b/www/protected/components/extendedGitGraph/extendedGitGraph.php
new file mode 100644
index 0000000..99b8bf9
--- /dev/null
+++ b/www/protected/components/extendedGitGraph/extendedGitGraph.php
@@ -0,0 +1,277 @@
+username = $usr_name;
+
+ set_time_limit(300); // 5min
+ }
+
+ public function authenticate($auth_key) {
+ $url = sprintf(self::API_TOKEN, $auth_key);
+ $result = file_get_contents($url);
+
+ $result = str_replace('access_token=', '', $result);
+ $result = str_replace('&scope=&token_type=bearer', '', $result);
+
+ setToken($result);
+ }
+
+ public function setToken($token) {
+ $this->token = $token;
+ $this->tokenHeader = 'access_token=' . $token . '&token_type=bearer';
+ }
+
+ public function collect() {
+ ob_implicit_flush(true);
+ ob_end_flush();
+
+ //--------------------------------
+
+ $this->listRepositories();
+
+ $this->listAllCommits();
+
+ $this->save();
+
+ //--------------------------------
+
+ $this->output_flushed($this->getRemainingRequests() . ' Requests remaining');
+ }
+
+ private function listRepositories() {
+ $page = 1;
+ $url = sprintf(self::API_REPOSITORIESLIST . '&' . $this->tokenHeader, $this->username, $page);
+
+ $result = $this->getJSON($url);
+
+ $repo_list = array();
+
+ while (! empty($result)) {
+ foreach ($result as $result_repo) {
+ $repo_list[] = $this->parseRepoJSON($result_repo);
+
+ $this->output_flushed("Found Repo: " . $result_repo->{'full_name'});
+ }
+
+ //##########
+
+ $url = sprintf(self::API_REPOSITORIESLIST . '&' . $this->tokenHeader, $this->username, ++$page);
+
+ $result = $this->getJSON($url);
+ }
+
+ $this->repositories = $repo_list;
+ }
+
+ private function getJSON($url) {
+ $options = array('http' => array('user_agent'=> $_SERVER['HTTP_USER_AGENT']));
+// $options = array('http' => array('user_agent'=> 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36'));
+ $context = stream_context_create($options);
+ $response = file_get_contents($url, false, $context);
+
+ return json_decode($response);
+ }
+
+ private function getRemainingRequests() {
+ $json = $this->getJSON(self::API_RATELIMIT . '?' . $this->tokenHeader);
+
+ return $json->{'resources'}->{'core'}->{'remaining'};
+ }
+
+ private function listAllCommits() {
+ $this->commits = array();
+
+ foreach($this->repositories as $repo) {
+ $this->listCommits($repo);
+ }
+ }
+
+ private function listCommits($repo) {
+ $page = 1;
+ $url = $repo['commits_url'] . '?per_page=100&page=' . $page . '&author=' .$this->username . '&' .$this->tokenHeader;
+
+ $result = $this->getJSON($url);
+
+ $commit_list = array();
+
+ while (! empty($result)) {
+ foreach ($result as $result_commit) {
+ $commit_list[] = $this->parseCommitJSON($repo, $result_commit);
+ }
+
+ $this->output_flushed("Found 100 Commits from " . $repo['full_name']);
+
+ //##########
+
+ $url = $repo['commits_url'] . '?per_page=100&page=' . ++$page . '&author=' .$this->username . '&' .$this->tokenHeader;
+
+ $result = $this->getJSON($url);
+ }
+
+ $this->commits = array_merge($this->commits, $commit_list);
+ }
+
+ private function parseRepoJSON($json) {
+ return
+ [
+ 'id' => $json->{'id'},
+ 'name' => $json->{'name'},
+ 'full_name' => $json->{'full_name'},
+ 'owner' => $json->{'owner'}->{'login'},
+ 'owner_id' => $json->{'owner'}->{'id'},
+ 'owner_avatar-url' => $json->{'owner'}->{'avatar_url'},
+ 'owner_gravatar-id' => $json->{'owner'}->{'gravatar_id'},
+ 'url' => $json->{'html_url'},
+ 'language' => $json->{'language'},
+ 'url' => $json->{'html_url'},
+ 'creation' => DateTime::createFromFormat(DateTime::ISO8601, $json->{'created_at'}),
+ 'size' => $json->{'size'},
+ 'default_branch' => $json->{'default_branch'},
+ 'commits_url' => str_replace('{/sha}', '', $json->{'commits_url'}),
+ ];
+ }
+
+ private function parseCommitJSON($repo, $json) {
+ return
+ [
+ 'sha' => $json->{'sha'},
+ 'author_name' => $json->{'commit'}->{'author'}->{'name'},
+ 'author_mail' => $json->{'commit'}->{'author'}->{'email'},
+ 'author_login' => $json->{'author'}->{'login'},
+ 'author_id' => $json->{'author'}->{'id'},
+ 'sha' => $json->{'sha'},
+ 'message' => $json->{'commit'}->{'message'},
+ 'repository' => $repo,
+ 'date' => DateTime::createFromFormat(DateTime::ISO8601, $json->{'commit'}->{'author'}->{'date'}),
+ ];
+ }
+
+ private function save() {
+ $this->output_flushed("Start saving data");
+
+ $save = serialize(
+ [
+ 'repositories' => $this->repositories,
+ 'commits' => $this->commits,
+ ]);
+
+ file_put_contents('protected/data/ext_git_graph_apidata.dat', $save);
+
+ $this->output_flushed('Finished saving data');
+ }
+
+ public function output_flushed($txt)
+ {
+ echo '[' . date('H:i.s') . '] ' . $txt . "
";
+ }
+
+ public function loadData() {
+ $data = unserialize(file_get_contents('protected/data/ext_git_graph_apidata.dat'));
+
+ $this->repositories = $data['repositories'];
+ $this->commits = $data['commits'];
+ }
+
+ public function generate($year) {
+ $ymap = $this->generateYearMap($year); // unused on purpose (template.php needs it)
+
+ $ymapmax = $this->getMaxCommitCount(); // unused on purpose (template.php needs it)
+
+ ob_start();
+ include('template.php');
+ $returned = ob_get_contents();
+ ob_end_clean();
+
+ return $returned;
+ }
+
+ public function generateAndSave() {
+ $result = '';
+
+ foreach($this->getYears() as $year) {
+ $result.= $this->generate($year);
+ $result.= '
';
+ }
+
+ file_put_contents('protected/data/gitgraph.dat',
+ serialize(
+ [
+ 'creation' => new DateTime(),
+ 'content' => $result,
+ ]));
+
+ return $result;
+ }
+
+ public function loadFinished() {
+ $data = unserialize(file_get_contents('protected/data/gitgraph.dat'));
+ return $data['content'];
+ }
+
+ public function getFinishedDate() {
+ $data = unserialize(file_get_contents('protected/data/gitgraph.dat'));
+ return $data['creation'];
+ }
+
+ private function getMaxCommitCount() {
+ $max = 0;
+
+ foreach($this->getYears() as $year) {
+ $max = max($max, max($this->generateYearMap($year)));
+ }
+
+ return $max;
+ }
+
+ private function generateYearMap($year) {
+ $ymap = array();
+
+ $date = new DateTime($year . '-01-01');
+ while($date->format('Y') == $year) {
+ $ymap[$date->format('Y-m-d')] = 0;
+
+ $date = $date->modify("+1 day");
+ }
+
+ foreach ($this->commits as $commit) {
+ if(array_key_exists($commit['date']->format('Y-m-d'), $ymap))
+ $ymap[$commit['date']->format('Y-m-d')]++;
+ }
+
+ return $ymap;
+ }
+
+ public function getYears() {
+ $years = array();
+
+ foreach ($this->commits as $commit) {
+ if(! in_array($commit['date']->format('Y'), $years))
+ $years[] = $commit['date']->format('Y');
+ }
+
+ asort($years);
+
+ return $years;
+ }
+}
\ No newline at end of file
diff --git a/www/protected/components/extendedGitGraph/script.js b/www/protected/components/extendedGitGraph/script.js
new file mode 100644
index 0000000..6b5e670
--- /dev/null
+++ b/www/protected/components/extendedGitGraph/script.js
@@ -0,0 +1,25 @@
+jQuery(document).ready(function ($) {
+ $('.svg-tip').fadeOut(0);
+ $('.svg-tip').css({opacity: 1});
+
+ $("rect").mouseenter(
+ function (event) {
+ $('.svg-tip').stop(true, true);
+
+ $('.svg-tip').fadeIn(400);
+
+ $('.svg-tip strong').html($(event.target).attr('hvr_header'));
+ $('.svg-tip span').html($(event.target).attr('hvr_content'));
+
+ $('.svg-tip').css({left: $(event.target).position().left - $('.svg-tip').outerWidth() /2 - 2.5 + 9});
+ $('.svg-tip').css({top: $(event.target).position().top - $('.svg-tip').outerHeight() - 10});
+
+ }
+ );
+ $("rect").mouseleave(
+ function () {
+ $('.svg-tip').stop(true, true);
+ $('.svg-tip').fadeOut(400);
+ }
+ );
+});
\ No newline at end of file
diff --git a/www/protected/components/extendedGitGraph/style.css b/www/protected/components/extendedGitGraph/style.css
new file mode 100644
index 0000000..4d59c15
--- /dev/null
+++ b/www/protected/components/extendedGitGraph/style.css
@@ -0,0 +1,90 @@
+.git_list {
+ display: inline-block;
+ width: 715px;
+ height: 115px;
+ overflow: visible;
+}
+
+.git_list text.caption {
+ font-size: 10px;
+ fill: #666;
+}
+
+.git_list text.caption_month {
+ font-size: 8px;
+ fill: #BBB;
+}
+
+.git_list text.caption_day {
+ font-size: 8px;
+ fill: #BBB;
+}
+
+.svg-tip:after {
+ box-sizing: border-box;
+ position: absolute;
+ left: 50%;
+ height: 5px;
+ width: 5px;
+ bottom: -10px;
+ margin: 0px 0px 0px -5px;
+ content: " ";
+ border: 5px solid transparent;
+ border-top-color: rgba(0, 0, 0, 0.8);
+ -moz-border-top-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-bottom-colors: none;
+ -moz-border-left-colors: none;
+ border-image: none;
+}
+
+.svg-tip {
+ padding: 5px;
+ background: none repeat scroll 0% 0% rgba(0, 0, 0, 0.8);
+ color: #BBB;
+ font-size: 12px;
+ position: absolute;
+ z-index: 99999;
+ text-align: center;
+ border-radius: 3px;
+ box-sizing: border-box;
+ opacity: 0;
+}
+
+body {
+ background-color: white;
+ margin: 40px 0 0;
+}
+
+.extGitGraphContainer {
+ background-color: #ECF0F1;
+ margin: 10px;
+ display: inline-block;
+
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ box-shadow: 0px 0 1px rgba(0, 0, 0, 0.25) inset;
+}
+
+.egg_footer {
+ margin-top: 5px;
+
+ text-align: right;
+ margin-right: 5px;
+ margin-bottom: 5px;
+
+ color: #FFF;
+ text-shadow: 0px 0px 8px #2C3E50, 0px 0px 8px #2C3E50;
+}
+
+.egg_footer > a {
+
+ text-decoration: none;
+ color: inherit;
+}
+
+.egg_footer > a:hover {
+ text-decoration: none;
+ color: #2C3E50;
+ text-shadow: 0px 0px 8px #00F;
+}
\ No newline at end of file
diff --git a/www/protected/components/extendedGitGraph/template.php b/www/protected/components/extendedGitGraph/template.php
new file mode 100644
index 0000000..f1c29ce
--- /dev/null
+++ b/www/protected/components/extendedGitGraph/template.php
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/www/protected/config/main.php b/www/protected/config/main.php
index 910b9d5..88d8f26 100644
--- a/www/protected/config/main.php
+++ b/www/protected/config/main.php
@@ -32,6 +32,7 @@ return ArrayX::merge(
'application.models.*',
'application.components.*',
'application.components.widgets.*',
+ 'application.components.extendedGitGraph.*',
'bootstrap.components.*',
'bootstrap.behaviors.*',
'bootstrap.helpers.*',
diff --git a/www/protected/controllers/MSMainController.php b/www/protected/controllers/MSMainController.php
index 9f16edd..15d4124 100644
--- a/www/protected/controllers/MSMainController.php
+++ b/www/protected/controllers/MSMainController.php
@@ -75,6 +75,8 @@ class MSMainController extends MSController
{
$data = array();
+ $this->js_scripts[] = file_get_contents('protected/components/extendedGitGraph/script.js');
+
if(isset($_POST['SendMailForm']))
{
$model = new SendMailForm();
@@ -132,6 +134,12 @@ class MSMainController extends MSController
public function actionAdmin()
{
+ if (isset($_GET['do_egh_update']) && $_GET['do_egh_update'] == '1') {
+ $this->layout = null;
+ $this->render('admin_updateEGH', array());
+ return;
+ }
+
$this->render('admin', array());
}
diff --git a/www/protected/data/.gitignore b/www/protected/data/.gitignore
new file mode 100644
index 0000000..9dff48e
--- /dev/null
+++ b/www/protected/data/.gitignore
@@ -0,0 +1,2 @@
+ext_git_graph_apidata.dat
+gitgraph.dat
\ No newline at end of file
diff --git a/www/protected/views/layouts/main.php b/www/protected/views/layouts/main.php
index cf639d2..0a6942f 100644
--- a/www/protected/views/layouts/main.php
+++ b/www/protected/views/layouts/main.php
@@ -90,5 +90,14 @@
+
+js_scripts as $script ) {
+ echo '', PHP_EOL;
+ }
+?>
+