[git] web/qa.git branch master updated. afcb958
| From: | johannes@php.net | Date: | Sun, 04 Mar 2012 22:46:39 +0000 |
| Subject: | [git] web/qa.git branch master updated. afcb958 | ||
| Groups: | php.qa | ||
| Request: | Send a blank email to php-qa+get-66124@lists.php.net to get a copy of this message | ||
The branch, master on web/qa.git has been updated
via afcb95867b06d3926a2e43cd1fd7f583b0191455 (commit)
via 7070ea56fd28e97946f5e601cb4ca8c9d20c2426 (commit)
via 1dcf2d86aa02cafdbd449ecb30575ac0a0962f08 (commit)
via 5fa7cddbadb43eb32844048f0ab43c4c1bac9223 (commit)
via d76a8d18ad1e457bed8c51c0e3f50fd7dfff4cda (commit)
via f7f02b3e7ff2ab3fa03af8870ea995132a8b5704 (commit)
via e5249845ad55e5971a91e933469ae6f70547d2cb (commit)
via 5769df1c481662dd4a584e107e622425798d67a3 (commit)
via a84c7d8ff5c7c90b849466563ce9990ebbd7a0ae (commit)
via a480e07e46ab2d69061c95bb758c662304a0e8b1 (commit)
via 9dbb4d0319d9eda5577b87e1f97283bdbf2f5d3d (commit)
via 0c1c3e6112cc401b92e74d0cd5d0022842f2a1d3 (commit)
via b267f73d34af9025f1c1d0356625c79f7c7b05da (commit)
via fb803e22619dcf65330f0902b6a8050441184f49 (commit)
via 4ecd34f5bd3cbc617662e6cb2be91a3a6441ccef (commit)
via 90fd22d1730b42065af9aebec4e4bff39980a1ef (commit)
via 380e82d0e854d4ba244d09977f75c98241a9fd83 (commit)
via 9aecf5bb00644717e28fdee3d32476b366f36506 (commit)
via 68039495c021b84bd3934b53fa8531e4501c36cd (commit)
via 122550c83b0c28e0b1e735b624e68a5f97a7dce1 (commit)
via 5b3af0fc444e5681a1a024d1991c53453fa4a89f (commit)
via 03ed80422340d5ae56e27773392ecb6717e3684f (commit)
via 74fca45cbcdf576e57e4e09af394efcae1e760d5 (commit)
from f86cd454b3a03c71fe95bb5aa4dcaff785b3ff1e (commit)
http://git.php.net/?p=web/qa.git;a=log;h=afcb95867b06d3926a2e43cd1fd7f583b0191455;hp=f86cd454b3a03c71fe95bb5aa4dcaff785b3ff1e
Summary of changes:
.gitignore | 1 +
gfx/github.ico | Bin 0 -> 1150 bytes
include/functions.php | 3 +-
pulls/api.php | 186 ++++++++++++++
pulls/config.php.in | 5 +
pulls/index.php | 137 +++++++++++
pulls/jquery.ba-bbq.min.js | 18 ++
pulls/jsrender.js | 573 ++++++++++++++++++++++++++++++++++++++++++++
pulls/pullrequests.js | 154 ++++++++++++
9 files changed, 1076 insertions(+), 1 deletions(-)
create mode 100644 gfx/github.ico
create mode 100644 pulls/api.php
create mode 100644 pulls/config.php.in
create mode 100644 pulls/index.php
create mode 100644 pulls/jquery.ba-bbq.min.js
create mode 100644 pulls/jsrender.js
create mode 100644 pulls/pullrequests.js
-- Log ----------------------------------------
commit afcb95867b06d3926a2e43cd1fd7f583b0191455
Merge: f86cd45 7070ea5
Author: Johannes Schlüter <johannes@php.net>
Date: Sun Mar 4 23:35:39 2012 +0100
Add GitHub Pull Request Management stuff.
* pull-request/2: (22 commits)
Fix WS.
Do some nicer error handling.
More cleanup for hide/show logic.
Bind show/hide on hashchange event
Fix event handling.
Refresh correct thing after closing a pull request and fix event handling
Use URL hash for history.
Use config.php here, too.
Move config in a file.
Avoid errors if no action was provided.
Fix HTML.
Fid indention.
Split JavaScript stuff in a extra file
Ask for login when needed.
Use a local icon.
Use correct preposition
Store password a bit safer.
Add Pull Request UI to navigation.
WS.
Add login stuff and update routines.
...
diff --cc .gitignore
index 8322433,28a1930..0c0821b
--- a/.gitignore
+++ b/.gitignore
@@@ -1,2 -1,2 +1,3 @@@
reports/db/*.sqlite
+reports/db/*.cache
+ pulls/config.php
commit 7070ea56fd28e97946f5e601cb4ca8c9d20c2426
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 23:31:41 2012 +0100
Fix WS.
diff --git a/include/functions.php b/include/functions.php
index b0eeb33..e231193 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -34,8 +34,8 @@ function common_header() {
| <a href="/rc.php" class="head_links">Release
Candidates</a>
| <a href="/howtohelp.php" class="head_links">How to
Help</a>
| <a href="/handling-bugs.php" class="head_links">Handling
Bug Reports</a>
- | <a href="/reports/" class="head_links">Test Reports</a>
- | <a href="/pulls/" class="head_links">Manage Pull
Requests</a>
+ | <a href="/reports/" class="head_links">Test
Reports</a>
+ | <a href="/pulls/" class="head_links">Manage Pull
Requests</a>
</td>
<td valign="bottom" align="right"
class="head_links"> </td>
</tr>
commit 1dcf2d86aa02cafdbd449ecb30575ac0a0962f08
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 23:14:56 2012 +0100
Do some nicer error handling.
diff --git a/pulls/index.php b/pulls/index.php
index 2d88047..f70e8a8 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -2,7 +2,7 @@
include("../include/functions.php");
include("../include/release-qa.php");
-require("./config.php");
+@include("./config.php");
$TITLE = "PHP-QA: GitHub Pull Requests";
$SITE_UPDATE = date("D M d H:i:s Y T", filectime(__FILE__));
@@ -105,6 +105,18 @@ $ git push origin master # everything okay? good, let's push it
<span id="notloggedin"><a href="#">Login</a></span>
</div>
<h1>Github Pull Requests</h1>
+<?php
+if (empty($_ENV['AUTH_TOKEN'])) {
+ echo '<div style="width: 100%; border: 2px solid red;
padding:10px;"><b>Error:</b> AUTH_TOKEN not set</div><br>';
+}
+
+if (!constant('GITHUB_PASS')) {
+ echo '<div style="width: 100%; border: 2px solid red;
padding:10px;"><b>Error:</b> config.php not configured
correctly.</div><br>';
+ common_footer();
+ exit;
+}
+
+?>
<div id="backToRepolist"><a href="#"><<<--
Repos</a></div>
<div id="mainContent"><ul id="repolist"></ul>The PHP
project is using github to mirror its git repostories from <a href="http://git.php.net">git.php.net</a>.</div>
<div id="repoContent"></div>
commit 5fa7cddbadb43eb32844048f0ab43c4c1bac9223
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 23:07:05 2012 +0100
More cleanup for hide/show logic.
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index d9cd2dc..f1cbbd8 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -9,6 +9,7 @@ repoList.prototype.showList = function() {
$("#repolist").fadeIn();
$("#backToRepolist").hide();
$("#repoContent").fadeOut();
+ $("#mainContent").show();
this.refreshView();
}
@@ -20,7 +21,6 @@ repoList.prototype.hideList = function() {
repoList.prototype.refreshView = function() {
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
- $("#mainContent").show();
$("li", $("#repolist")).click(function(ev) { var reponame =
loadRepo($(this).attr("repo")); $.bbq.pushState({ repo: reponame }); ev.preventDefault();
});
}
repoList.prototype.update = function() {
@@ -115,7 +115,6 @@ function loadRepo(repo) {
url: GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
success: function (data) {
$("#loading").hide();
- $("#mainContent").hide();
$("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
$(".pullinstructions").click(function(ev) {
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
commit d76a8d18ad1e457bed8c51c0e3f50fd7dfff4cda
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 23:04:32 2012 +0100
Bind show/hide on hashchange event
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index 22a5e00..d9cd2dc 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -95,11 +95,11 @@ $(document).ready(function() {
login = new loginHandler();
repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
repos.update();
- repos.showList();
$(window).bind( "hashchange", function(e) {
if ($.bbq.getState( "repo" )) {
loadRepo($.bbq.getState("repo"));
+ repos.hideList();
} else {
repos.showList();
}
@@ -114,7 +114,6 @@ function loadRepo(repo) {
dataType: 'jsonp',
url: GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
success: function (data) {
- repos.hideList();
$("#loading").hide();
$("#mainContent").hide();
$("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
commit f7f02b3e7ff2ab3fa03af8870ea995132a8b5704
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 02:25:52 2012 +0100
Fix event handling.
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index 05db0b6..22a5e00 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -118,9 +118,10 @@ function loadRepo(repo) {
$("#loading").hide();
$("#mainContent").hide();
$("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
- $(".pullinstructions").click(function() {
+ $(".pullinstructions").click(function(ev) {
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
.dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
+ ev.preventDefault();
});
$(".updatepullrequest").click(function(ev) {
var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
@@ -133,7 +134,7 @@ function loadRepo(repo) {
$.bbq.pushState({ repo: repo });
}
});
-
+
}
function updateRepo(reponame, num, dia) {
commit e5249845ad55e5971a91e933469ae6f70547d2cb
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sun Mar 4 01:33:59 2012 +0100
Refresh correct thing after closing a pull request and fix event handling
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index 59d9e2d..05db0b6 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -2,14 +2,14 @@ function repoList(baseurl, org) {
this.url = baseurl+'orgs/'+org+'/repos';
this.data = {data:[]};
var t = this;
- $("#backToRepolist").click(function () { $.bbq.removeState('repo'); });
+ $("#backToRepolist").click(function (ev) { $.bbq.removeState('repo');
ev.preventDefault();});
}
repoList.prototype.showList = function() {
$("#repolist").fadeIn();
$("#backToRepolist").hide();
$("#repoContent").fadeOut();
- repos.refreshView();
+ this.refreshView();
}
repoList.prototype.hideList = function() {
@@ -21,7 +21,7 @@ repoList.prototype.hideList = function() {
repoList.prototype.refreshView = function() {
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
$("#mainContent").show();
- $("li", $("#repolist")).click(function() { var reponame =
loadRepo($(this).attr("repo")); $.bbq.pushState({ repo: reponame }); });
+ $("li", $("#repolist")).click(function(ev) { var reponame =
loadRepo($(this).attr("repo")); $.bbq.pushState({ repo: reponame }); ev.preventDefault();
});
}
repoList.prototype.update = function() {
var t = this;
@@ -38,12 +38,14 @@ function loginHandler() {
this.user = false;
this.logindialog = $("#loginDialog").dialog({autoOpen: false});
this.checkLoggedIn();
- $("#notloggedin").click(function() {
+ $("#notloggedin").click(function(ev) {
t.showLoginForm();
+ ev.preventDefault();
} );
- $("#loginBtn").click(function() {
+ $("#loginBtn").click(function(ev) {
t.logindialog.dialog("close");
t.login();
+ ev.preventDefault();
} );
}
@@ -73,8 +75,9 @@ loginHandler.prototype.updateLoginState = function(d) {
$("#checkinglogin").hide();
$("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
$("#notloggedin").hide();
- $("#loggedin a").click(function() {
+ $("#loggedin a").click(function(ev) {
$.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
+ ev.preventDefault();
});
this.user = d.user;
} else {
@@ -119,10 +122,11 @@ function loadRepo(repo) {
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
.dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
});
- $(".updatepullrequest").click(function() {
+ $(".updatepullrequest").click(function(ev) {
var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
.dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')'
});
- $("button", dia).click(function(r, n, dia) { return function() {
updateRepo(r, n, dia); }}(repo, $(this).attr("number"), dia) );
+ $("button", dia).click(function(r, n, dia) { return function(ev) {
updateRepo(r, n, dia); ev.preventDefault();}}(repo, $(this).attr("number"), dia) );
+ ev.preventDefault();
});
$("#repoPullList").accordion({ autoHeight: false });
$("#repoContent").show();
@@ -145,7 +149,7 @@ function updateRepo(reponame, num, dia) {
id: num,
state: $("select", dia).attr("value"),
comment: $("textarea", dia).attr("value")
- }, success: function(d) { repos.update(); } });
+ }, success: function(d) { loadRepo(reponame); } });
dia.dialog("destroy");
}
commit 5769df1c481662dd4a584e107e622425798d67a3
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 23:55:36 2012 +0100
Use URL hash for history.
diff --git a/pulls/index.php b/pulls/index.php
index c113a3b..2d88047 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -51,6 +51,7 @@ common_header();
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
<script type="text/javascript" src="jsrender.js"></script>
+ <script type="text/javascript"
src="jquery.ba-bbq.min.js"></script>
<script id="repoListItemTemplate" type="text/x-jquery-tmpl">
<li repo="{{=name}}"><b><a
href="#">{{=name}}:</a></b> {{=description}} ({{=open_issues}})</li>
</script>
diff --git a/pulls/jquery.ba-bbq.min.js b/pulls/jquery.ba-bbq.min.js
new file mode 100644
index 0000000..80de36f
--- /dev/null
+++ b/pulls/jquery.ba-bbq.min.js
@@ -0,0 +1,18 @@
+/*
+ * jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
+ * http://benalman.com/projects/jquery-bbq-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function($,r){var
h,n=Array.prototype.slice,t=decodeURIComponent,a=$.param,j,c,m,y,b=$.bbq=$.bbq||{},s,x,k,e=$.event.special,d="hashchange",B="querystring",F="fragment",z="elemUrlAttr",l="href",w="src",p=/^.*\?|#.*$/g,u,H,g,i,C,E={};function
G(I){return typeof I==="string"}function D(J){var I=n.call(arguments,1);return
function(){return J.apply(this,I.concat(n.call(arguments)))}}function o(I){return
I.replace(H,"$2")}function q(I){return
I.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(K,P,I,L,J){var
R,O,N,Q,M;if(L!==h){N=I.match(K?H:/^([^#?]*)\??([^#]*)(#?.*)/);M=N[3]||"";if(J===2&&G(L)){O=L.replace(K?u:p,"")}else{Q=m(N[2]);L=G(L)?m[K?F:B](L):L;O=J===2?L:J===1?$.extend({},L,Q):$.extend({},Q,L);O=j(O);if(K){O=O.replace(g,t)}}R=N[1]+(K?C:O||!N[1]?"?":"")+O+M}else{R=P(I!==h?I:location.href)}return
R}a[B]=D(f,0,q);a[F]=c=D(f,1,o);a.sorted=j=function(J,K){var
I=[],L={};$.each(a(J,K).split("&"),function(P,M){var
O=M.replace(/(?:%5B|=).*$/,""),N=L[O];if(!N){N=L[O]=[];I.pu!
sh(O)}N.push(M)});return $.map(I.sort(),function(M){return
L[M]}).join("&")};c.noEscape=function(J){J=J||"";var
I=$.map(J.split(""),encodeURIComponent);g=new
RegExp(I.join("|"),"g")};c.noEscape(",/");c.ajaxCrawlable=function(I){if(I!==h){if(I){u=/^.*(?:#!|#)/;H=/^([^#]*)(?:#!|#)?(.*)$/;C="#!"}else{u=/^.*#/;H=/^([^#]*)#?(.*)$/;C="#"}i=!!I}return
i};c.ajaxCrawlable(0);$.deparam=m=function(L,I){var
K={},J={"true":!0,"false":!1,"null":null};$.each(L.replace(/\+/g,"
").split("&"),function(O,T){var
N=T.split("="),S=t(N[0]),M,R=K,P=0,U=S.split("]["),Q=U.length-1;if(/\[/.test(U[0])&&/\]$/.test(U[Q])){U[Q]=U[Q].replace(/\]$/,"");U=U.shift().split("[").concat(U);Q=U.length-1}else{Q=0}if(N.length===2){M=t(N[1]);if(I){M=M&&!isNaN(M)?+M:M==="undefined"?h:J[M]!==h?J[M]:M}if(Q){for(;P<=Q;P++){S=U[P]===""?R.length:U[P];R=R[S]=P<Q?R[S]||(U[P+1]&&isNaN(U[P+1])?{}:[]):M}}else{if($.isArray(K[S])){K[S].push(M)}else{if(K[S]!==h){K[S]=[K[S],M]}else{K[S]=M}}}}else{if(S){K[S]=I?h:""}}});return
K};f!
unction A(K,I,J){if(I===h||typeof I==="boolean"){J=I;I=a[K?F:B!
]()}else{I=G(I)?I.replace(K?u:p,""):I}return
m(I,J)}m[B]=D(A,0);m[F]=y=D(A,1);$[z]||($[z]=function(I){return
$.extend(E,I)})({a:l,base:l,iframe:w,img:w,input:w,form:"action",link:l,script:w});k=$[z];function
v(L,J,K,I){if(!G(K)&&typeof K!=="object"){I=K;K=J;J=h}return
this.each(function(){var
O=$(this),M=J||k()[(this.nodeName||"").toLowerCase()]||"",N=M&&O.attr(M)||"";O.attr(M,a[L](N,K,I))})}$.fn[B]=D(v,B);$.fn[F]=D(v,F);b.pushState=s=function(L,I){if(G(L)&&/^#/.test(L)&&I===h){I=2}var
K=L!==h,J=c(location.href,K?L:{},K?I:2);location.href=J};b.getState=x=function(I,J){return
I===h||typeof I==="boolean"?y(I):y(J)[I]};b.removeState=function(I){var
J={};if(I!==h){J=x();$.each($.isArray(I)?I:arguments,function(L,K){delete
J[K]})}s(J,2)};e[d]=$.extend(e[d],{add:function(I){var K;function J(M){var
L=M[F]=c();M.getState=function(N,O){return N===h||typeof
N==="boolean"?m(L,N):m(L,O)[N]};K.apply(this,arguments)}if($.isFunction(I)){K=I;return
J}else{K=I.handler;I.handler=J}}})})(jQue!
ry,this);
+/*
+ * jQuery hashchange event - v1.3 - 7/21/2010
+ * http://benalman.com/projects/jquery-hashchange-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function($,e,b){var
c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in
e&&(i===b||i>7);function
a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return
j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return
false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var
j={},p,m=a(),k=function(q){return
q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function
n(){var
r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var
q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe
tabindex="-1"
title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title!
"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return
a(q.location.href)};l=function(v,s){var
u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return
j})()})(jQuery,this);
\ No newline at end of file
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index 3e0de6e..59d9e2d 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -2,7 +2,7 @@ function repoList(baseurl, org) {
this.url = baseurl+'orgs/'+org+'/repos';
this.data = {data:[]};
var t = this;
- $("#backToRepolist").click(function () { t.showList(); });
+ $("#backToRepolist").click(function () { $.bbq.removeState('repo'); });
}
repoList.prototype.showList = function() {
@@ -14,13 +14,14 @@ repoList.prototype.showList = function() {
repoList.prototype.hideList = function() {
$("#repolist").fadeOut();
+ $("#mainContent").hide();
$("#backToRepolist").fadeIn();
}
repoList.prototype.refreshView = function() {
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
$("#mainContent").show();
- $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
+ $("li", $("#repolist")).click(function() { var reponame =
loadRepo($(this).attr("repo")); $.bbq.pushState({ repo: reponame }); });
}
repoList.prototype.update = function() {
var t = this;
@@ -92,6 +93,16 @@ $(document).ready(function() {
repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
repos.update();
repos.showList();
+
+ $(window).bind( "hashchange", function(e) {
+ if ($.bbq.getState( "repo" )) {
+ loadRepo($.bbq.getState("repo"));
+ } else {
+ repos.showList();
+ }
+ });
+
+ $(window).trigger( "hashchange" );
});
function loadRepo(repo) {
@@ -115,6 +126,7 @@ function loadRepo(repo) {
});
$("#repoPullList").accordion({ autoHeight: false });
$("#repoContent").show();
+ $.bbq.pushState({ repo: repo });
}
});
commit a84c7d8ff5c7c90b849466563ce9990ebbd7a0ae
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 22:27:05 2012 +0100
Use config.php here, too.
diff --git a/pulls/api.php b/pulls/api.php
index 06694f3..c6f747c 100644
--- a/pulls/api.php
+++ b/pulls/api.php
@@ -1,9 +1,5 @@
<?php
-
-const GITHUB_BASEURL = 'https://api.github.com/';
-const GITHUB_ORG = 'php';
-const GITHUB_USER = 'johannes';
-define('GITHUB_PASS', include('passwd.php')); // FETCH FROM ENVIRONMENT
+require('./config.php');
if ($_SERVER['SERVER_NAME'] === 'schlueters.de') {
define('DEV', true);
commit a480e07e46ab2d69061c95bb758c662304a0e8b1
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 22:23:30 2012 +0100
Move config in a file.
diff --git a/.gitignore b/.gitignore
index f981b00..28a1930 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
reports/db/*.sqlite
+pulls/config.php
diff --git a/pulls/config.php.in b/pulls/config.php.in
new file mode 100644
index 0000000..ec65f53
--- /dev/null
+++ b/pulls/config.php.in
@@ -0,0 +1,5 @@
+<?php
+const GITHUB_BASEURL = 'https://api.github.com/';
+const GITHUB_ORG = 'php';
+const GITHUB_USER = '....';
+const GITHUB_PASS = '....';
diff --git a/pulls/index.php b/pulls/index.php
index 4e08625..c113a3b 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -2,6 +2,8 @@
include("../include/functions.php");
include("../include/release-qa.php");
+require("./config.php");
+
$TITLE = "PHP-QA: GitHub Pull Requests";
$SITE_UPDATE = date("D M d H:i:s Y T", filectime(__FILE__));
@@ -91,8 +93,8 @@ $ git push origin master # everything okay? good, let's push it
<button>Go</button>
</script>
<script type="text/javascript">
- var GITHUB_BASEURL = "https://api.github.com/";
- var GITHUB_ORG = "php";
+ var GITHUB_BASEURL = <?php echo json_encode(GITHUB_BASEURL); ?>;
+ var GITHUB_ORG = <?php echo json_encode(GITHUB_ORG); ?>;
var API_URL = "api.php";
</script>
<script src="pullrequests.js"></script>
commit 9dbb4d0319d9eda5577b87e1f97283bdbf2f5d3d
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 15:54:40 2012 +0100
Avoid errors if no action was provided.
diff --git a/pulls/api.php b/pulls/api.php
index 5035a02..06694f3 100644
--- a/pulls/api.php
+++ b/pulls/api.php
@@ -180,11 +180,11 @@ $accepted_actions = array(
'loggedin',
'ghupdate'
);
-if (in_array($_REQUEST['action'], $accepted_actions)) {
+if (isset($_REQUEST['action']) && in_array($_REQUEST['action'],
$accepted_actions)) {
$action = $_REQUEST['action'];
$action();
} else {
header('HTTP/1.0 400 Bad Request');
- die(json_encode(array('success' => false, 'errors' =>
array("Unknown method $_REQUEST[action]"))));
+ die(json_encode(array('success' => false, 'errors' =>
array("Unknown method"))));
}
commit 0c1c3e6112cc401b92e74d0cd5d0022842f2a1d3
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 15:27:09 2012 +0100
Fix HTML.
diff --git a/pulls/index.php b/pulls/index.php
index c5209b3..4e08625 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -99,7 +99,7 @@ $ git push origin master # everything okay? good, let's push it
<div id="loginstatus">
<span id="checkinglogin">(checking login state ...)</span>
<span id="loggedin"></span>
- <span id="notloggedin"><a href="#">Login</span>
+ <span id="notloggedin"><a href="#">Login</a></span>
</div>
<h1>Github Pull Requests</h1>
<div id="backToRepolist"><a href="#"><<<--
Repos</a></div>
commit b267f73d34af9025f1c1d0356625c79f7c7b05da
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 15:14:54 2012 +0100
Fid indention.
diff --git a/pulls/pullrequests.js b/pulls/pullrequests.js
index 71334b4..3e0de6e 100644
--- a/pulls/pullrequests.js
+++ b/pulls/pullrequests.js
@@ -1,138 +1,139 @@
- function repoList(baseurl, org) {
- this.url = baseurl+'orgs/'+org+'/repos';
- this.data = {data:[]};
- var t = this;
- $("#backToRepolist").click(function () { t.showList(); });
- }
+function repoList(baseurl, org) {
+ this.url = baseurl+'orgs/'+org+'/repos';
+ this.data = {data:[]};
+ var t = this;
+ $("#backToRepolist").click(function () { t.showList(); });
+}
- repoList.prototype.showList = function() {
- $("#repolist").fadeIn();
- $("#backToRepolist").hide();
- $("#repoContent").fadeOut();
- repos.refreshView();
- }
+repoList.prototype.showList = function() {
+ $("#repolist").fadeIn();
+ $("#backToRepolist").hide();
+ $("#repoContent").fadeOut();
+ repos.refreshView();
+}
- repoList.prototype.hideList = function() {
- $("#repolist").fadeOut();
- $("#backToRepolist").fadeIn();
- }
+repoList.prototype.hideList = function() {
+ $("#repolist").fadeOut();
+ $("#backToRepolist").fadeIn();
+}
- repoList.prototype.refreshView = function() {
-
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
- $("#mainContent").show();
- $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
- }
- repoList.prototype.update = function() {
- var t = this;
- $("#loading").show();
- $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
- }
- repoList.prototype.setData = function(data) {
- this.data = data;
- this.refreshView();
- }
+repoList.prototype.refreshView = function() {
+ $("#repolist").html($("#repoListItemTemplate").render(this.data.data));
+ $("#mainContent").show();
+ $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
+}
+repoList.prototype.update = function() {
+ var t = this;
+ $("#loading").show();
+ $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
+}
+repoList.prototype.setData = function(data) {
+ this.data = data;
+ this.refreshView();
+}
- function loginHandler() {
- var t = this;
- this.user = false;
- this.logindialog = $("#loginDialog").dialog({autoOpen: false});
- this.checkLoggedIn();
- $("#notloggedin").click(function() {
- t.showLoginForm();
- } );
- $("#loginBtn").click(function() {
- t.logindialog.dialog("close");
- t.login();
- } );
- }
+function loginHandler() {
+ var t = this;
+ this.user = false;
+ this.logindialog = $("#loginDialog").dialog({autoOpen: false});
+ this.checkLoggedIn();
+ $("#notloggedin").click(function() {
+ t.showLoginForm();
+ } );
+ $("#loginBtn").click(function() {
+ t.logindialog.dialog("close");
+ t.login();
+ } );
+}
- loginHandler.prototype.showLoginForm = function() {
- this.logindialog.dialog("open");
- }
+loginHandler.prototype.showLoginForm = function() {
+ this.logindialog.dialog("open");
+}
- loginHandler.prototype.login = function() {
- var user = $("#userField").attr("value");
- var pass = $("#passField").attr("value");
- var t = this;
+loginHandler.prototype.login = function() {
+ var user = $("#userField").attr("value");
+ var pass = $("#passField").attr("value");
+ var t = this;
- $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user:
user, pass: pass }, success: function(d) { t.updateLoginState(d); } });
- }
+ $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user: user,
pass: pass }, success: function(d) { t.updateLoginState(d); } });
+}
- loginHandler.prototype.checkLoggedIn = function() {
- var t = this;
- $("#checkinglogin").show();
- $("#loggedin").hide();
- $("#notloggedin").hide();
- $.ajax({ url: API_URL+'?action=loggedin', success: function(d) {
t.updateLoginState(d); } });
- }
+loginHandler.prototype.checkLoggedIn = function() {
+ var t = this;
+ $("#checkinglogin").show();
+ $("#loggedin").hide();
+ $("#notloggedin").hide();
+ $.ajax({ url: API_URL+'?action=loggedin', success: function(d) {
t.updateLoginState(d); } });
+}
- loginHandler.prototype.updateLoginState = function(d) {
- var t = this;
- if (d.success && d.user) {
- $("#checkinglogin").hide();
- $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
- $("#notloggedin").hide();
- $("#loggedin a").click(function() {
- $.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
- });
- this.user = d.user;
- } else {
- $("#checkinglogin").hide();
- $("#loggedin").hide();
- $("#notloggedin").fadeIn();
- this.user = false;
- }
- }
+loginHandler.prototype.updateLoginState = function(d) {
+ var t = this;
+ if (d.success && d.user) {
+ $("#checkinglogin").hide();
+ $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
+ $("#notloggedin").hide();
+ $("#loggedin a").click(function() {
+ $.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
+ });
+ this.user = d.user;
+ } else {
+ $("#checkinglogin").hide();
+ $("#loggedin").hide();
+ $("#notloggedin").fadeIn();
+ this.user = false;
+ }
+}
- var repos;
- var login;
+var repos;
+var login;
- $(document).ready(function() {
- login = new loginHandler();
- repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
- repos.update();
- repos.showList();
- });
+$(document).ready(function() {
+ login = new loginHandler();
+ repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
+ repos.update();
+ repos.showList();
+});
- function loadRepo(repo) {
- $("#loading").show();
- $.ajax({
- dataType: 'jsonp',
- url:
GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
- success: function (data) {
- repos.hideList();
- $("#loading").hide();
- $("#mainContent").hide();
- $("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
- $(".pullinstructions").click(function() {
-
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
- .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
- });
- $(".updatepullrequest").click(function() {
- var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
- .dialog({title:
$(this).attr("number")+': '+$(this).attr("title")+'
('+$(this).attr("state")+')' });
- $("button", dia).click(function(r, n, dia) { return function() {
updateRepo(r, n, dia); }}(repo, $(this).attr("number"), dia) );
- });
- $("#repoPullList").accordion({ autoHeight: false });
- $("#repoContent").show();
- }
- });
+function loadRepo(repo) {
+ $("#loading").show();
+ $.ajax({
+ dataType: 'jsonp',
+ url: GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
+ success: function (data) {
+ repos.hideList();
+ $("#loading").hide();
+ $("#mainContent").hide();
+ $("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
+ $(".pullinstructions").click(function() {
+
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
+ .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
+ });
+ $(".updatepullrequest").click(function() {
+ var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
+ .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')'
});
+ $("button", dia).click(function(r, n, dia) { return function() {
updateRepo(r, n, dia); }}(repo, $(this).attr("number"), dia) );
+ });
+ $("#repoPullList").accordion({ autoHeight: false });
+ $("#repoContent").show();
+ }
+ });
- }
+}
+
+function updateRepo(reponame, num, dia) {
+ var t = this;
+ if (!login.user) {
+ login.showLoginForm();
+ return;
+ }
+ $("#loading").show();
+ $.ajax({ url: API_URL, type: "POST", data: {
+ action: 'ghupdate',
+ repo: reponame,
+ id: num,
+ state: $("select", dia).attr("value"),
+ comment: $("textarea", dia).attr("value")
+ }, success: function(d) { repos.update(); } });
+ dia.dialog("destroy");
+}
- function updateRepo(reponame, num, dia) {
- var t = this;
- if (!login.user) {
- login.showLoginForm();
- return;
- }
- $("#loading").show();
- $.ajax({ url: API_URL, type: "POST", data: {
- action: 'ghupdate',
- repo: reponame,
- id: num,
- state: $("select", dia).attr("value"),
- comment: $("textarea", dia).attr("value")
- }, success: function(d) { repos.update(); } });
- dia.dialog("destroy");
- }
commit fb803e22619dcf65330f0902b6a8050441184f49
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 15:08:31 2012 +0100
Split JavaScript stuff in a extra file
diff --git a/pulls/index.php b/pulls/index.php
index 39128e5..c5209b3 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -94,146 +94,8 @@ $ git push origin master # everything okay? good, let's push it
var GITHUB_BASEURL = "https://api.github.com/";
var GITHUB_ORG = "php";
var API_URL = "api.php";
-
- function repoList(baseurl, org) {
- this.url = baseurl+'orgs/'+org+'/repos';
- this.data = {data:[]};
- var t = this;
- $("#backToRepolist").click(function () { t.showList(); });
- }
-
- repoList.prototype.showList = function() {
- $("#repolist").fadeIn();
- $("#backToRepolist").hide();
- $("#repoContent").fadeOut();
- repos.refreshView();
- }
-
- repoList.prototype.hideList = function() {
- $("#repolist").fadeOut();
- $("#backToRepolist").fadeIn();
- }
-
- repoList.prototype.refreshView = function() {
-
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
- $("#mainContent").show();
- $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
- }
- repoList.prototype.update = function() {
- var t = this;
- $("#loading").show();
- $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
- }
- repoList.prototype.setData = function(data) {
- this.data = data;
- this.refreshView();
- }
-
- function loginHandler() {
- var t = this;
- this.user = false;
- this.logindialog = $("#loginDialog").dialog({autoOpen: false});
- this.checkLoggedIn();
- $("#notloggedin").click(function() {
- t.showLoginForm();
- } );
- $("#loginBtn").click(function() {
- t.logindialog.dialog("close");
- t.login();
- } );
- }
-
- loginHandler.prototype.showLoginForm = function() {
- this.logindialog.dialog("open");
- }
-
- loginHandler.prototype.login = function() {
- var user = $("#userField").attr("value");
- var pass = $("#passField").attr("value");
- var t = this;
-
- $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user:
user, pass: pass }, success: function(d) { t.updateLoginState(d); } });
- }
-
- loginHandler.prototype.checkLoggedIn = function() {
- var t = this;
- $("#checkinglogin").show();
- $("#loggedin").hide();
- $("#notloggedin").hide();
- $.ajax({ url: API_URL+'?action=loggedin', success: function(d) {
t.updateLoginState(d); } });
- }
-
- loginHandler.prototype.updateLoginState = function(d) {
- var t = this;
- if (d.success && d.user) {
- $("#checkinglogin").hide();
- $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
- $("#notloggedin").hide();
- $("#loggedin a").click(function() {
- $.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
- });
- this.user = d.user;
- } else {
- $("#checkinglogin").hide();
- $("#loggedin").hide();
- $("#notloggedin").fadeIn();
- this.user = false;
- }
- }
-
- var repos;
- var login;
-
- $(document).ready(function() {
- login = new loginHandler();
- repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
- repos.update();
- repos.showList();
- });
-
- function loadRepo(repo) {
- $("#loading").show();
- $.ajax({
- dataType: 'jsonp',
- url:
GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
- success: function (data) {
- repos.hideList();
- $("#loading").hide();
- $("#mainContent").hide();
- $("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
- $(".pullinstructions").click(function() {
-
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
- .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
- });
- $(".updatepullrequest").click(function() {
- var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
- .dialog({title:
$(this).attr("number")+': '+$(this).attr("title")+'
('+$(this).attr("state")+')' });
- $("button", dia).click(function(r, n, dia) { return function() {
updateRepo(r, n, dia); }}(repo, $(this).attr("number"), dia) );
- });
- $("#repoPullList").accordion({ autoHeight: false });
- $("#repoContent").show();
- }
- });
-
- }
-
- function updateRepo(reponame, num, dia) {
- var t = this;
- if (!login.user) {
- login.showLoginForm();
- return;
- }
- $("#loading").show();
- $.ajax({ url: API_URL, type: "POST", data: {
- action: 'ghupdate',
- repo: reponame,
- id: num,
- state: $("select", dia).attr("value"),
- comment: $("textarea", dia).attr("value")
- }, success: function(d) { repos.update(); } });
- dia.dialog("destroy");
- }
</script>
+ <script src="pullrequests.js"></script>
<div id="loginstatus">
<span id="checkinglogin">(checking login state ...)</span>
<span id="loggedin"></span>
diff --git a/pulls/index.php b/pulls/pullrequests.js
similarity index 54%
copy from pulls/index.php
copy to pulls/pullrequests.js
index 39128e5..71334b4 100644
--- a/pulls/index.php
+++ b/pulls/pullrequests.js
@@ -1,100 +1,3 @@
-<?php
-include("../include/functions.php");
-include("../include/release-qa.php");
-
-$TITLE = "PHP-QA: GitHub Pull Requests";
-$SITE_UPDATE = date("D M d H:i:s Y T", filectime(__FILE__));
-
-common_header();
-
-?>
-<table width="70%" border="0" cellspacing="0"
cellpadding="0">
- <tr>
- <td width="10"><img src="../gfx/spacer.gif" width="10"
height="1"></td>
- <td width="100%">
- <style>
- #loading {
- position:fixed;
- top:50%;
- padding-top:-20px;
- height:40px;
- left:50%;
- padding-left:-50px;
- width:100px;
- border:1px solid black;
- background-color: black;
- color: white;
- text-align: center;
- vertical-align: center;
- }
-
- .ghuser {
- border: 1px solid #ffcc66;
- float: right;
- margin-left: 5px;
- margin-bottom: 5px;
- }
-
- .ghuser a {
- color: #ffcc66;
- text-decoration: none;
- }
-
- #loginstatus {
- width: 100%;
- text-align: right;
- }
- </style>
- <link href="http://code.jquery.com/ui/1.8.18/themes/ui-lightness/jquery-ui.css"
rel="stylesheet" type="text/css"/>
- <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
- <script type="text/javascript" src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
- <script type="text/javascript" src="jsrender.js"></script>
- <script id="repoListItemTemplate" type="text/x-jquery-tmpl">
- <li repo="{{=name}}"><b><a
href="#">{{=name}}:</a></b> {{=description}} ({{=open_issues}})</li>
- </script>
- <script id="repoOverviewTemplate" type="text/x-jquery-tmpl">
- <h2>{{=repoName}}</h2>
- <div id="repoPullList">
- {{=pullList!}}
- </div>
- <!-- iframe style='width:100%; height:300px;border-width:1px;' src=''
id='ghframe' name='ghframe'></iframe -->
- </script>
- <script id="pullRequestListItem" type="text/x-jquery-tmpl">
- <h3><a href='#'>{{=number}}: {{=title}} ({{=state}})</a></h3>
- <div class="pullrequest">
- <div class="ghuser"><a href="{{=user.url}}"><img
src="{{=user.avatar_url}}"><br>{{=user.login}}</a></div>
- <div>Created: {{=created_at}}, LastUpdated: {{=updated_at}}</div>
- <div>{{=body}}</div>
- <div><a href="{{=html_url}}"><img
src="../gfx/github.ico"> On GitHub</a> |
- <a href="{{=diff_url}}">Diff</a> |
- <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="pullinstructions">Show Pull Instructions</a>
|
- <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="updatepullrequest">Update</a>
- </div>
- </div>
- </script>
- <script id="pullInstructionTemplate" type="text/x-jquery-tmpl">
- <pre>
-$ git fetch git://github.com/php/{{=repo}} pull/{{=number}}/head:pull-request/{{=number}}
-$ git log -p pull-request/{{=number}} # REVIEW IT
-$ git merge pull-request/{{=number}} # Merge it, add a GOOD commit message
-$ make test # you better don't forget that
-$ git push origin master # everything okay? good, let's push it
- </pre>
- </script>
- <script id="updatePullRequestTemplate" type="text/x-jquery-tmpl">
- State: <select id="newState">
- <option>open</option>
- <option>closed</option>
- </select><br>
- Please provide a comment for your change:<br>
- <textarea id="comment"></textarea><br>
- <button>Go</button>
- </script>
- <script type="text/javascript">
- var GITHUB_BASEURL = "https://api.github.com/";
- var GITHUB_ORG = "php";
- var API_URL = "api.php";
-
function repoList(baseurl, org) {
this.url = baseurl+'orgs/'+org+'/repos';
this.data = {data:[]};
@@ -233,28 +136,3 @@ $ git push origin master # everything okay? good, let's push it
}, success: function(d) { repos.update(); } });
dia.dialog("destroy");
}
- </script>
- <div id="loginstatus">
- <span id="checkinglogin">(checking login state ...)</span>
- <span id="loggedin"></span>
- <span id="notloggedin"><a href="#">Login</span>
- </div>
- <h1>Github Pull Requests</h1>
- <div id="backToRepolist"><a href="#"><<<--
Repos</a></div>
- <div id="mainContent"><ul id="repolist"></ul>The PHP
project is using github to mirror its git repostories from <a href="http://git.php.net">git.php.net</a>.</div>
- <div id="repoContent"></div>
- <div id="loginDialog" title="Login">
- Username: <br><input id="userField"><br>
- Password: <br><input id="passField" type="password"><br>
- <button id="loginBtn">Login</button>
- </div>
- <div id="loading">Loading</div>
-
- </td>
- <td width="10"><img src="http://qa.php.net/gfx/spacer.gif"
width="10" height="1"></td>
- </tr>
- </table>
-<?php
-
-common_footer();
-
commit 4ecd34f5bd3cbc617662e6cb2be91a3a6441ccef
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 15:04:54 2012 +0100
Ask for login when needed.
diff --git a/pulls/index.php b/pulls/index.php
index 5150a43..39128e5 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -135,7 +135,7 @@ $ git push origin master # everything okay? good, let's push it
this.logindialog = $("#loginDialog").dialog({autoOpen: false});
this.checkLoggedIn();
$("#notloggedin").click(function() {
- t.logindialog.dialog("open");
+ t.showLoginForm();
} );
$("#loginBtn").click(function() {
t.logindialog.dialog("close");
@@ -143,6 +143,10 @@ $ git push origin master # everything okay? good, let's push it
} );
}
+ loginHandler.prototype.showLoginForm = function() {
+ this.logindialog.dialog("open");
+ }
+
loginHandler.prototype.login = function() {
var user = $("#userField").attr("value");
var pass = $("#passField").attr("value");
@@ -216,7 +220,7 @@ $ git push origin master # everything okay? good, let's push it
function updateRepo(reponame, num, dia) {
var t = this;
if (!login.user) {
- window.alert("Login First!");
+ login.showLoginForm();
return;
}
$("#loading").show();
commit 90fd22d1730b42065af9aebec4e4bff39980a1ef
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 04:40:36 2012 +0100
Use a local icon.
diff --git a/gfx/github.ico b/gfx/github.ico
new file mode 100644
index 0000000..9db08f2
Binary files /dev/null and b/gfx/github.ico differ
diff --git a/pulls/index.php b/pulls/index.php
index d0498f4..5150a43 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -65,7 +65,7 @@ common_header();
<div class="ghuser"><a href="{{=user.url}}"><img
src="{{=user.avatar_url}}"><br>{{=user.login}}</a></div>
<div>Created: {{=created_at}}, LastUpdated: {{=updated_at}}</div>
<div>{{=body}}</div>
- <div><a href="{{=html_url}}"><img src="https://github.com/favicon.ico"> On
GitHub</a> |
+ <div><a href="{{=html_url}}"><img
src="../gfx/github.ico"> On GitHub</a> |
<a href="{{=diff_url}}">Diff</a> |
<a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="pullinstructions">Show Pull Instructions</a>
|
<a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="updatepullrequest">Update</a>
commit 380e82d0e854d4ba244d09977f75c98241a9fd83
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 04:37:14 2012 +0100
Use correct preposition
diff --git a/pulls/api.php b/pulls/api.php
index abc15dc..5035a02 100644
--- a/pulls/api.php
+++ b/pulls/api.php
@@ -57,7 +57,7 @@ function verify_password_DEV($user, $pass)
function ghpostcomment($pull, $comment)
{
- $post = json_encode(array("body" => "**Comment in behalf of $_SESSION[user] at
php.net:**\n\n$comment"));
+ $post = json_encode(array("body" => "**Comment on behalf of $_SESSION[user] at
php.net:**\n\n$comment"));
$opts = array(
commit 9aecf5bb00644717e28fdee3d32476b366f36506
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 01:51:56 2012 +0100
Store password a bit safer.
diff --git a/pulls/api.php b/pulls/api.php
index bd6c99c..abc15dc 100644
--- a/pulls/api.php
+++ b/pulls/api.php
@@ -3,7 +3,7 @@
const GITHUB_BASEURL = 'https://api.github.com/';
const GITHUB_ORG = 'php';
const GITHUB_USER = 'johannes';
-define('GITHUB_PASS', trim(file_get_contents('passwd'))); // FETCH FROM
ENVIRONMENT
+define('GITHUB_PASS', include('passwd.php')); // FETCH FROM ENVIRONMENT
if ($_SERVER['SERVER_NAME'] === 'schlueters.de') {
define('DEV', true);
commit 68039495c021b84bd3934b53fa8531e4501c36cd
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 01:47:37 2012 +0100
Add Pull Request UI to navigation.
diff --git a/include/functions.php b/include/functions.php
index ad0f819..b0eeb33 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -34,7 +34,8 @@ function common_header() {
| <a href="/rc.php" class="head_links">Release
Candidates</a>
| <a href="/howtohelp.php" class="head_links">How to
Help</a>
| <a href="/handling-bugs.php" class="head_links">Handling
Bug Reports</a>
- | <a href="/reports/" class="head_links">Test
reports</a>
+ | <a href="/reports/" class="head_links">Test Reports</a>
+ | <a href="/pulls/" class="head_links">Manage Pull
Requests</a>
</td>
<td valign="bottom" align="right"
class="head_links"> </td>
</tr>
commit 122550c83b0c28e0b1e735b624e68a5f97a7dce1
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 01:41:14 2012 +0100
WS.
diff --git a/pulls/index.php b/pulls/index.php
index eed9c01..d0498f4 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -97,15 +97,15 @@ $ git push origin master # everything okay? good, let's push it
function repoList(baseurl, org) {
this.url = baseurl+'orgs/'+org+'/repos';
- this.data = {data:[]};
- var t = this;
- $("#backToRepolist").click(function () { t.showList(); });
+ this.data = {data:[]};
+ var t = this;
+ $("#backToRepolist").click(function () { t.showList(); });
}
repoList.prototype.showList = function() {
$("#repolist").fadeIn();
- $("#backToRepolist").hide();
- $("#repoContent").fadeOut();
+ $("#backToRepolist").hide();
+ $("#repoContent").fadeOut();
repos.refreshView();
}
@@ -117,12 +117,12 @@ $ git push origin master # everything okay? good, let's push it
repoList.prototype.refreshView = function() {
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
$("#mainContent").show();
- $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
+ $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
}
repoList.prototype.update = function() {
var t = this;
$("#loading").show();
- $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
+ $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
}
repoList.prototype.setData = function(data) {
this.data = data;
@@ -133,11 +133,11 @@ $ git push origin master # everything okay? good, let's push it
var t = this;
this.user = false;
this.logindialog = $("#loginDialog").dialog({autoOpen: false});
- this.checkLoggedIn();
- $("#notloggedin").click(function() {
+ this.checkLoggedIn();
+ $("#notloggedin").click(function() {
t.logindialog.dialog("open");
- } );
- $("#loginBtn").click(function() {
+ } );
+ $("#loginBtn").click(function() {
t.logindialog.dialog("close");
t.login();
} );
@@ -145,35 +145,35 @@ $ git push origin master # everything okay? good, let's push it
loginHandler.prototype.login = function() {
var user = $("#userField").attr("value");
- var pass = $("#passField").attr("value");
- var t = this;
+ var pass = $("#passField").attr("value");
+ var t = this;
- $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user: user,
pass: pass }, success: function(d) { t.updateLoginState(d); } });
+ $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user:
user, pass: pass }, success: function(d) { t.updateLoginState(d); } });
}
loginHandler.prototype.checkLoggedIn = function() {
var t = this;
$("#checkinglogin").show();
- $("#loggedin").hide();
- $("#notloggedin").hide();
- $.ajax({ url: API_URL+'?action=loggedin', success: function(d) { t.updateLoginState(d);
} });
+ $("#loggedin").hide();
+ $("#notloggedin").hide();
+ $.ajax({ url: API_URL+'?action=loggedin', success: function(d) {
t.updateLoginState(d); } });
}
loginHandler.prototype.updateLoginState = function(d) {
var t = this;
if (d.success && d.user) {
$("#checkinglogin").hide();
- $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
- $("#notloggedin").hide();
- $("#loggedin a").click(function() {
+ $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
+ $("#notloggedin").hide();
+ $("#loggedin a").click(function() {
$.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
- });
- this.user = d.user;
- } else {
+ });
+ this.user = d.user;
+ } else {
$("#checkinglogin").hide();
$("#loggedin").hide();
- $("#notloggedin").fadeIn();
- this.user = false;
+ $("#notloggedin").fadeIn();
+ this.user = false;
}
}
@@ -192,23 +192,23 @@ $ git push origin master # everything okay? good, let's push it
$.ajax({
dataType: 'jsonp',
url:
GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
- success: function (data) {
- repos.hideList();
- $("#loading").hide();
- $("#mainContent").hide();
- $("#repoContent").html( $("#repoOverviewTemplate").render([{repoName:
repo, pullList: $("#pullRequestListItem").render(data.data)}]));
- $(".pullinstructions").click(function() {
- $('<div></div>').html($("#pullInstructionTemplate").render({
repo: repo, number: $(this).attr("number")}))
- .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
- });
- $(".updatepullrequest").click(function() {
- var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
- .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')'
});
- $("button", dia).click(function(r, n, dia) { return function() { updateRepo(r, n,
dia); }}(repo, $(this).attr("number"), dia) );
- });
- $("#repoPullList").accordion({ autoHeight: false });
- $("#repoContent").show();
- }
+ success: function (data) {
+ repos.hideList();
+ $("#loading").hide();
+ $("#mainContent").hide();
+ $("#repoContent").html(
$("#repoOverviewTemplate").render([{repoName: repo, pullList:
$("#pullRequestListItem").render(data.data)}]));
+ $(".pullinstructions").click(function() {
+
$('<div></div>').html($("#pullInstructionTemplate").render({ repo:
repo, number: $(this).attr("number")}))
+ .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
+ });
+ $(".updatepullrequest").click(function() {
+ var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
+ .dialog({title:
$(this).attr("number")+': '+$(this).attr("title")+'
('+$(this).attr("state")+')' });
+ $("button", dia).click(function(r, n, dia) { return function() {
updateRepo(r, n, dia); }}(repo, $(this).attr("number"), dia) );
+ });
+ $("#repoPullList").accordion({ autoHeight: false });
+ $("#repoContent").show();
+ }
});
}
commit 5b3af0fc444e5681a1a024d1991c53453fa4a89f
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Sat Mar 3 01:28:49 2012 +0100
Add login stuff and update routines.
diff --git a/pulls/index.php b/pulls/index.php
index fe9f836..eed9c01 100644
--- a/pulls/index.php
+++ b/pulls/index.php
@@ -39,6 +39,11 @@ common_header();
color: #ffcc66;
text-decoration: none;
}
+
+ #loginstatus {
+ width: 100%;
+ text-align: right;
+ }
</style>
<link href="http://code.jquery.com/ui/1.8.18/themes/ui-lightness/jquery-ui.css"
rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
@@ -62,7 +67,8 @@ common_header();
<div>{{=body}}</div>
<div><a href="{{=html_url}}"><img src="https://github.com/favicon.ico"> On
GitHub</a> |
<a href="{{=diff_url}}">Diff</a> |
- <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="pullinstructions">Show Pull Instructions</a>
+ <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="pullinstructions">Show Pull Instructions</a>
|
+ <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="updatepullrequest">Update</a>
</div>
</div>
</script>
@@ -75,9 +81,19 @@ $ make test # you better don't forget that
$ git push origin master # everything okay? good, let's push it
</pre>
</script>
+ <script id="updatePullRequestTemplate" type="text/x-jquery-tmpl">
+ State: <select id="newState">
+ <option>open</option>
+ <option>closed</option>
+ </select><br>
+ Please provide a comment for your change:<br>
+ <textarea id="comment"></textarea><br>
+ <button>Go</button>
+ </script>
<script type="text/javascript">
var GITHUB_BASEURL = "https://api.github.com/";
var GITHUB_ORG = "php";
+ var API_URL = "api.php";
function repoList(baseurl, org) {
this.url = baseurl+'orgs/'+org+'/repos';
@@ -113,8 +129,59 @@ $ git push origin master # everything okay? good, let's push it
this.refreshView();
}
+ function loginHandler() {
+ var t = this;
+ this.user = false;
+ this.logindialog = $("#loginDialog").dialog({autoOpen: false});
+ this.checkLoggedIn();
+ $("#notloggedin").click(function() {
+ t.logindialog.dialog("open");
+ } );
+ $("#loginBtn").click(function() {
+ t.logindialog.dialog("close");
+ t.login();
+ } );
+ }
+
+ loginHandler.prototype.login = function() {
+ var user = $("#userField").attr("value");
+ var pass = $("#passField").attr("value");
+ var t = this;
+
+ $.ajax({ url: API_URL, type: "POST", data: { action: 'login', user: user,
pass: pass }, success: function(d) { t.updateLoginState(d); } });
+ }
+
+ loginHandler.prototype.checkLoggedIn = function() {
+ var t = this;
+ $("#checkinglogin").show();
+ $("#loggedin").hide();
+ $("#notloggedin").hide();
+ $.ajax({ url: API_URL+'?action=loggedin', success: function(d) { t.updateLoginState(d);
} });
+ }
+
+ loginHandler.prototype.updateLoginState = function(d) {
+ var t = this;
+ if (d.success && d.user) {
+ $("#checkinglogin").hide();
+ $("#loggedin").html("Welcome "+d.user+" (<a
href='#'>Logout</a>)").fadeIn();
+ $("#notloggedin").hide();
+ $("#loggedin a").click(function() {
+ $.ajax({ url: API_URL+'?action=logout', success: function(d) {
t.updateLoginState(d); } });
+ });
+ this.user = d.user;
+ } else {
+ $("#checkinglogin").hide();
+ $("#loggedin").hide();
+ $("#notloggedin").fadeIn();
+ this.user = false;
+ }
+ }
+
var repos;
+ var login;
+
$(document).ready(function() {
+ login = new loginHandler();
repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
repos.update();
repos.showList();
@@ -133,18 +200,50 @@ $ git push origin master # everything okay? good, let's push it
$(".pullinstructions").click(function() {
$('<div></div>').html($("#pullInstructionTemplate").render({
repo: repo, number: $(this).attr("number")}))
.dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
- });
+ });
+ $(".updatepullrequest").click(function() {
+ var dia =
$('<div></div>').html($("#updatePullRequestTemplate").render({}))
+ .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')'
});
+ $("button", dia).click(function(r, n, dia) { return function() { updateRepo(r, n,
dia); }}(repo, $(this).attr("number"), dia) );
+ });
$("#repoPullList").accordion({ autoHeight: false });
$("#repoContent").show();
}
});
- }
+ }
+
+ function updateRepo(reponame, num, dia) {
+ var t = this;
+ if (!login.user) {
+ window.alert("Login First!");
+ return;
+ }
+ $("#loading").show();
+ $.ajax({ url: API_URL, type: "POST", data: {
+ action: 'ghupdate',
+ repo: reponame,
+ id: num,
+ state: $("select", dia).attr("value"),
+ comment: $("textarea", dia).attr("value")
+ }, success: function(d) { repos.update(); } });
+ dia.dialog("destroy");
+ }
</script>
+ <div id="loginstatus">
+ <span id="checkinglogin">(checking login state ...)</span>
+ <span id="loggedin"></span>
+ <span id="notloggedin"><a href="#">Login</span>
+ </div>
<h1>Github Pull Requests</h1>
<div id="backToRepolist"><a href="#"><<<--
Repos</a></div>
<div id="mainContent"><ul id="repolist"></ul>The PHP
project is using github to mirror its git repostories from <a href="http://git.php.net">git.php.net</a>.</div>
<div id="repoContent"></div>
+ <div id="loginDialog" title="Login">
+ Username: <br><input id="userField"><br>
+ Password: <br><input id="passField" type="password"><br>
+ <button id="loginBtn">Login</button>
+ </div>
<div id="loading">Loading</div>
</td>
commit 03ed80422340d5ae56e27773392ecb6717e3684f
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Fri Mar 2 23:49:37 2012 +0100
Add local API endpoint.
This will be used by the JS frontend for doing user authentication
and doing write operations on GitHub.
diff --git a/pulls/api.php b/pulls/api.php
new file mode 100644
index 0000000..bd6c99c
--- /dev/null
+++ b/pulls/api.php
@@ -0,0 +1,190 @@
+<?php
+
+const GITHUB_BASEURL = 'https://api.github.com/';
+const GITHUB_ORG = 'php';
+const GITHUB_USER = 'johannes';
+define('GITHUB_PASS', trim(file_get_contents('passwd'))); // FETCH FROM
ENVIRONMENT
+
+if ($_SERVER['SERVER_NAME'] === 'schlueters.de') {
+ define('DEV', true);
+ error_reporting(-1);
+ ini_set('display_errors', 1);
+} else {
+ define('DEV', false);
+}
+
+function verify_password($user, $pass)
+{
+ global $errors;
+
+ $post = http_build_query(
+ array(
+ 'token' => getenv('AUTH_TOKEN'),
+ 'username' => $user,
+ 'password' => $pass,
+ )
+ );
+
+ $opts = array(
+ 'method' => 'POST',
+ 'header' => 'Content-type:
application/x-www-form-urlencoded',
+ 'content' => $post,
+ );
+
+ $ctx = stream_context_create(array('http' => $opts));
+
+ $s = @file_get_contents('https://master.php.net/fetch/cvsauth.php',
false, $ctx);
+
+ $a = @unserialize($s);
+ if (!is_array($a)) {
+ $errors[] = "Failed to get authentication information.\nMaybe master is
down?\n";
+ return false;
+ }
+ if (isset($a['errno'])) {
+ $errors[] = "Authentication failed: {$a['errstr']}\n";
+ return false;
+ }
+
+ return true;
+}
+
+function verify_password_DEV($user, $pass)
+{
+ global $errors;
+ $errors[] = "Unknown user $user (DEV)";
+ return $user === 'johannes';
+}
+
+function ghpostcomment($pull, $comment)
+{
+ $post = json_encode(array("body" => "**Comment in behalf of $_SESSION[user] at
php.net:**\n\n$comment"));
+
+
+ $opts = array(
+ 'method' => 'POST',
+ 'content' => $post,
+ );
+
+ $ctx = stream_context_create(array('http' => $opts));
+
+ $url = str_replace('https://', 'https://'.GITHUB_USER.':'.GITHUB_PASS.'@',
$pull->_links->comments->href);
+ $s = @file_get_contents($url, false, $ctx);
+ return (bool)$s;
+}
+
+function ghchangestate($pull, $state)
+{
+ $content = json_encode(array("state" => $state));
+
+ $opts = array(
+ 'method' => 'PATCH',
+ 'content' => $content
+ );
+
+ $ctx = stream_context_create(array('http' => $opts));
+
+ $url = str_replace('https://', 'https://'.GITHUB_USER.':'.GITHUB_PASS.'@',
$pull->_links->self->href);
+ $s = @file_get_contents($url, false, $ctx);
+ return (bool)$s;
+}
+
+function login()
+{
+ global $errors;
+
+ $func = DEV ? 'verify_password_DEV' : 'verify_password';
+ if ($func($_POST['user'], $_POST['pass'])) {
+ $_SESSION['user'] = $_POST['user'];
+ die(json_encode(array('success' => true, 'user' =>
$_POST['user'])));
+ } else {
+ header('HTTP/1.0 401 Unauthorized');
+ $_SESSION['user'] = false;
+ die(json_encode(array('success' => false, 'errors' => $errors)));
+ }
+}
+
+function logout()
+{
+ session_destroy();
+ die(json_encode(array('success' => true)));
+}
+
+function loggedin()
+{
+ $result = array(
+ 'success' => !empty($_SESSION['user'])
+ );
+ if (!empty($_SESSION['user'])) {
+ $result['user'] = $_SESSION['user'];
+ }
+ die(json_encode($result));
+}
+
+function ghupdate()
+{
+ if (empty($_SESSION['user'])) {
+ header('HTTP/1.0 401 Unauthorized');
+ die(json_encode(array('success' => false, 'errors' =>
array('Unauthorized'))));
+ }
+
+ if (empty($_POST['repo'])) {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' => array("No
repo provided"))));
+ }
+
+ if (empty($_POST['id']) || !is_numeric($_POST['id'])) {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' => array("No or
inalid id provided"))));
+ }
+
+ if (empty($_POST['comment']) || !($comment = trim($_POST['comment']))) {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' => array("No
comment provided"))));
+ }
+
+ if (!empty($_POST['state']) && !in_array($_POST['state'],
array('open', 'closed'))) {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' =>
array("Invalid state"))));
+ }
+
+ $pull_raw =
@file_get_contents(GITHUB_BASEURL.'repos/'.GITHUB_ORG.'/'.urlencode($_POST['repo']).'/pulls/'.$_POST['id']);
+ $pull = $pull_raw ? json_decode($pull_raw) : false;
+ if (!$pull) {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' =>
array("Failed to get data from GitHub"))));
+ }
+
+ $comment = @get_magic_quotes_gpc() ? stripslashes($_POST['comment']) :
$_POST['comment'];
+
+ if (!ghpostcomment($pull, $comment)) {
+ header('500 Internal Server Error');
+ die(json_encode(array('success' => false, 'errors' =>
array("Failed to add comment on GitHub"))));
+ }
+
+ if (!empty($_POST['state'])) {
+ if (!ghchangestate($pull, $_POST['state'])) {
+ header('500 Internal Server Error');
+ die(json_encode(array('success' => false, 'errors' =>
array("Failed to set new state"))));
+ }
+ }
+
+ die(json_encode(array('success' => true)));
+}
+
+header('Content-Type: application/json');
+session_start();
+
+$accepted_actions = array(
+ 'login',
+ 'logout',
+ 'loggedin',
+ 'ghupdate'
+);
+if (in_array($_REQUEST['action'], $accepted_actions)) {
+ $action = $_REQUEST['action'];
+ $action();
+} else {
+ header('HTTP/1.0 400 Bad Request');
+ die(json_encode(array('success' => false, 'errors' =>
array("Unknown method $_REQUEST[action]"))));
+}
+
commit 74fca45cbcdf576e57e4e09af394efcae1e760d5
Author: Johannes Schlueter <johannes@schlueters.de>
Date: Fri Mar 2 22:06:21 2012 +0100
Add initial version of the GitHub Pull Request management stuff
diff --git a/pulls/index.php b/pulls/index.php
new file mode 100644
index 0000000..fe9f836
--- /dev/null
+++ b/pulls/index.php
@@ -0,0 +1,157 @@
+<?php
+include("../include/functions.php");
+include("../include/release-qa.php");
+
+$TITLE = "PHP-QA: GitHub Pull Requests";
+$SITE_UPDATE = date("D M d H:i:s Y T", filectime(__FILE__));
+
+common_header();
+
+?>
+<table width="70%" border="0" cellspacing="0"
cellpadding="0">
+ <tr>
+ <td width="10"><img src="../gfx/spacer.gif" width="10"
height="1"></td>
+ <td width="100%">
+ <style>
+ #loading {
+ position:fixed;
+ top:50%;
+ padding-top:-20px;
+ height:40px;
+ left:50%;
+ padding-left:-50px;
+ width:100px;
+ border:1px solid black;
+ background-color: black;
+ color: white;
+ text-align: center;
+ vertical-align: center;
+ }
+
+ .ghuser {
+ border: 1px solid #ffcc66;
+ float: right;
+ margin-left: 5px;
+ margin-bottom: 5px;
+ }
+
+ .ghuser a {
+ color: #ffcc66;
+ text-decoration: none;
+ }
+ </style>
+ <link href="http://code.jquery.com/ui/1.8.18/themes/ui-lightness/jquery-ui.css"
rel="stylesheet" type="text/css"/>
+ <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
+ <script type="text/javascript" src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
+ <script type="text/javascript" src="jsrender.js"></script>
+ <script id="repoListItemTemplate" type="text/x-jquery-tmpl">
+ <li repo="{{=name}}"><b><a
href="#">{{=name}}:</a></b> {{=description}} ({{=open_issues}})</li>
+ </script>
+ <script id="repoOverviewTemplate" type="text/x-jquery-tmpl">
+ <h2>{{=repoName}}</h2>
+ <div id="repoPullList">
+ {{=pullList!}}
+ </div>
+ <!-- iframe style='width:100%; height:300px;border-width:1px;' src=''
id='ghframe' name='ghframe'></iframe -->
+ </script>
+ <script id="pullRequestListItem" type="text/x-jquery-tmpl">
+ <h3><a href='#'>{{=number}}: {{=title}} ({{=state}})</a></h3>
+ <div class="pullrequest">
+ <div class="ghuser"><a href="{{=user.url}}"><img
src="{{=user.avatar_url}}"><br>{{=user.login}}</a></div>
+ <div>Created: {{=created_at}}, LastUpdated: {{=updated_at}}</div>
+ <div>{{=body}}</div>
+ <div><a href="{{=html_url}}"><img src="https://github.com/favicon.ico"> On
GitHub</a> |
+ <a href="{{=diff_url}}">Diff</a> |
+ <a href="#" number="{{=number}}" state="{{=state}}"
title="{{=title}}" class="pullinstructions">Show Pull Instructions</a>
+ </div>
+ </div>
+ </script>
+ <script id="pullInstructionTemplate" type="text/x-jquery-tmpl">
+ <pre>
+$ git fetch git://github.com/php/{{=repo}} pull/{{=number}}/head:pull-request/{{=number}}
+$ git log -p pull-request/{{=number}} # REVIEW IT
+$ git merge pull-request/{{=number}} # Merge it, add a GOOD commit message
+$ make test # you better don't forget that
+$ git push origin master # everything okay? good, let's push it
+ </pre>
+ </script>
+ <script type="text/javascript">
+ var GITHUB_BASEURL = "https://api.github.com/";
+ var GITHUB_ORG = "php";
+
+ function repoList(baseurl, org) {
+ this.url = baseurl+'orgs/'+org+'/repos';
+ this.data = {data:[]};
+ var t = this;
+ $("#backToRepolist").click(function () { t.showList(); });
+ }
+
+ repoList.prototype.showList = function() {
+ $("#repolist").fadeIn();
+ $("#backToRepolist").hide();
+ $("#repoContent").fadeOut();
+ repos.refreshView();
+ }
+
+ repoList.prototype.hideList = function() {
+ $("#repolist").fadeOut();
+ $("#backToRepolist").fadeIn();
+ }
+
+ repoList.prototype.refreshView = function() {
+
$("#repolist").html($("#repoListItemTemplate").render(this.data.data));
+ $("#mainContent").show();
+ $("li", $("#repolist")).click(function() {
loadRepo($(this).attr("repo")); });
+ }
+ repoList.prototype.update = function() {
+ var t = this;
+ $("#loading").show();
+ $.ajax({ dataType: 'jsonp', url: this.url, success: function(d) { t.setData(d);
$("#loading").hide(); } });
+ }
+ repoList.prototype.setData = function(data) {
+ this.data = data;
+ this.refreshView();
+ }
+
+ var repos;
+ $(document).ready(function() {
+ repos = new repoList(GITHUB_BASEURL, GITHUB_ORG);
+ repos.update();
+ repos.showList();
+ });
+
+ function loadRepo(repo) {
+ $("#loading").show();
+ $.ajax({
+ dataType: 'jsonp',
+ url:
GITHUB_BASEURL+'repos/'+GITHUB_ORG+"/"+repo+"/pulls",
+ success: function (data) {
+ repos.hideList();
+ $("#loading").hide();
+ $("#mainContent").hide();
+ $("#repoContent").html( $("#repoOverviewTemplate").render([{repoName:
repo, pullList: $("#pullRequestListItem").render(data.data)}]));
+ $(".pullinstructions").click(function() {
+ $('<div></div>').html($("#pullInstructionTemplate").render({
repo: repo, number: $(this).attr("number")}))
+ .dialog({title: $(this).attr("number")+':
'+$(this).attr("title")+' ('+$(this).attr("state")+')',
width: 800 });
+ });
+ $("#repoPullList").accordion({ autoHeight: false });
+ $("#repoContent").show();
+ }
+ });
+
+ }
+ </script>
+ <h1>Github Pull Requests</h1>
+ <div id="backToRepolist"><a href="#"><<<--
Repos</a></div>
+ <div id="mainContent"><ul id="repolist"></ul>The PHP
project is using github to mirror its git repostories from <a href="http://git.php.net">git.php.net</a>.</div>
+ <div id="repoContent"></div>
+ <div id="loading">Loading</div>
+
+ </td>
+ <td width="10"><img src="http://qa.php.net/gfx/spacer.gif"
width="10" height="1"></td>
+ </tr>
+ </table>
+<?php
+
+common_footer();
+
diff --git a/pulls/jsrender.js b/pulls/jsrender.js
new file mode 100644
index 0000000..5998650
--- /dev/null
+++ b/pulls/jsrender.js
@@ -0,0 +1,573 @@
+/*! JsRender v1.0pre - (jsrender.js version: does not require jQuery): http://github.com/BorisMoore/jsrender */
+/*
+ * Optimized version of jQuery Templates, fosr rendering to string, using 'codeless'
markup.
+ *
+ * Copyright 2011, Boris Moore
+ * Released under the MIT License.
+ */
+window.JsViews || window.jQuery && jQuery.views || (function( window, undefined ) {
+
+var $, _$, JsViews, viewsNs, tmplEncode, render, rTag, registerTags, registerHelpers, extend,
+ FALSE = false, TRUE = true,
+ jQuery = window.jQuery, document = window.document,
+ htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
+ rPath =
/^(true|false|null|[\d\.]+)|(\w+|\$(view|data|ctx|(\w+)))([\w\.]*)|((['"])(?:\\\1|.)*\7)$/g,
+ rParams =
/(\$?[\w\.\[\]]+)(?:(\()|\s*(===|!==|==|!=|<|>|<=|>=)\s*|\s*(\=)\s*)?|(\,\s*)|\\?(\')|\\?(\")|(\))|(\s+)/g,
+ rNewLine = /\r?\n/g,
+ rUnescapeQuotes = /\\(['"])/g,
+ rEscapeQuotes = /\\?(['"])/g,
+ rBuildHash = /\x08([^\x08]+)\x08/g,
+ autoName = 0,
+ escapeMapForHtml = {
+ "&": "&",
+ "<": "<",
+ ">": ">"
+ },
+ htmlSpecialChar = /[\x00"&'<>]/g,
+ slice = Array.prototype.slice;
+
+if ( jQuery ) {
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // jQuery is loaded, so make $ the jQuery object
+ $ = jQuery;
+
+ $.fn.extend({
+ // Use first wrapped element as template markup.
+ // Return string obtained by rendering the template against data.
+ render: function( data, context, parentView, path ) {
+ return render( data, this[0], context, parentView, path );
+ },
+
+ // Consider the first wrapped element as a template declaration, and get the compiled template or
store it as a named template.
+ template: function( name, context ) {
+ return $.template( name, this[0], context );
+ }
+ });
+
+} else {
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // jQuery is not loaded. Make $ the JsViews object
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+ window.JsViews = JsViews = window.$ = $ = {
+ extend: function( target, source ) {
+ var name;
+ for ( name in source ) {
+ target[ name ] = source[ name ];
+ }
+ return target;
+ },
+ isArray: Array.isArray || function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Array]";
+ },
+ noConflict: function() {
+ if ( window.$ === JsViews ) {
+ window.$ = _$;
+ }
+ return JsViews;
+ }
+ };
+}
+
+extend = $.extend;
+
+//=================
+// View constructor
+//=================
+
+function View( context, path, parentView, data, template ) {
+ // Returns a view data structure for a new rendered instance of a template.
+ // The content field is a hierarchical array of strings and nested views.
+
+ parentView = parentView || { viewsCount:0, ctx: viewsNs.helpers };
+
+ var parentContext = parentView && parentView.ctx;
+
+ return {
+ jsViews: "v1.0pre",
+ path: path || "",
+ // inherit context from parentView, merged with new context.
+ itemNumber: ++parentView.viewsCount || 1,
+ viewsCount: 0,
+ tmpl: template,
+ data: data || parentView.data || {},
+ // Set additional context on this view (which will modify the context inherited from the parent,
and be inherited by child views)
+ ctx : context && context === parentContext
+ ? parentContext
+ : (parentContext ? extend( extend( {}, parentContext ), context ) : context||{}),
+ // If no jQuery, extend does not support chained copies - so limit to two parameters
+ parent: parentView
+ };
+}
+extend( $, {
+ views: viewsNs = {
+ templates: {},
+ tags: {
+ "if": function() {
+ var ifTag = this,
+ view = ifTag._view;
+ view.onElse = function( presenter, args ) {
+ var i = 0,
+ l = args.length;
+ while ( l && !args[ i++ ]) {
+ // Only render content if args.length === 0 (i.e. this is an else with no condition) or if a
condition argument is truey
+ if ( i === l ) {
+ return "";
+ }
+ }
+ view.onElse = undefined; // If condition satisfied, so won't run 'else'.
+ return render( view.data, presenter.tmpl, view.ctx, view);
+ };
+ return view.onElse( this, arguments );
+ },
+ "else": function() {
+ var view = this._view;
+ return view.onElse ? view.onElse( this, arguments ) : "";
+ },
+ each: function() {
+ var i,
+ self = this,
+ result = "",
+ args = arguments,
+ l = args.length,
+ content = self.tmpl,
+ view = self._view;
+ for ( i = 0; i < l; i++ ) {
+ result += args[ i ] ? render( args[ i ], content, self.ctx || view.ctx, view, self._path,
self._ctor ) : "";
+ }
+ return l ? result
+ // If no data parameter, use the current $data from view, and render once
+ : result + render( view.data, content, view.ctx, view, self._path, self.tag );
+ },
+ "=": function( value ) {
+ return value;
+ },
+ "*": function( value ) {
+ return value;
+ }
+ },
+ helpers: {
+ not: function( value ) {
+ return !value;
+ }
+ },
+ allowCode: FALSE,
+ debugMode: TRUE,
+ err: function( e ) {
+ return viewsNs.debugMode ? ("<br/><b>Error:</b> <em> " +
(e.message || e) + ". </em>"): '""';
+ },
+
+//===============
+// setDelimiters
+//===============
+
+ setDelimiters: function( openTag, closeTag ) {
+ // Set or modify the delimiter characters for tags: "{{" and "}}"
+ var firstCloseChar = closeTag.charAt( 0 ),
+ secondCloseChar = closeTag.charAt( 1 );
+ openTag = "\\" + openTag.charAt( 0 ) + "\\" + openTag.charAt( 1 );
+ closeTag = "\\" + firstCloseChar + "\\" + secondCloseChar;
+
+ // Build regex with new delimiters
+ // {{
+ rTag = openTag
+ // # tag (followed by space,! or }) or equals or code
+ + "(?:(?:(\\#)?(\\w+(?=[!\\s\\" + firstCloseChar + "]))" +
"|(?:(\\=)|(\\*)))"
+ // params
+ + "\\s*((?:[^\\" + firstCloseChar + "]|\\" + firstCloseChar +
"(?!\\" + secondCloseChar + "))*?)"
+ // encoding
+ + "(!(\\w*))?"
+ // closeBlock
+ + "|(?:\\/([\\w\\$\\.\\[\\]]+)))"
+ // }}
+ + closeTag;
+
+ // Default rTag: # tag equals code params encoding
closeBlock
+ //
/\{\{(?:(?:(\#)?(\w+(?=[\s\}!]))|(?:(\=)|(\*)))((?:[^\}]|\}(?!\}))*?)(!(\w*))?|(?:\/([\w\$\.\[\]]+)))\}\}/g;
+
+ rTag = new RegExp( rTag, "g" );
+ },
+
+
+//===============
+// registerTags
+//===============
+
+ // Register declarative tag.
+ registerTags: registerTags = function( name, tagFn ) {
+ var key;
+ if ( typeof name === "object" ) {
+ for ( key in name ) {
+ registerTags( key, name[ key ]);
+ }
+ } else {
+ // Simple single property case.
+ viewsNs.tags[ name ] = tagFn;
+ }
+ return this;
+ },
+
+//===============
+// registerHelpers
+//===============
+
+ // Register helper function for use in markup.
+ registerHelpers: registerHelpers = function( name, helper ) {
+ if ( typeof name === "object" ) {
+ // Object representation where property name is path and property value is value.
+ // TODO: We've discussed an "objectchange" event to capture all N property
updates here. See TODO note above about propertyChanges.
+ var key;
+ for ( key in name ) {
+ registerHelpers( key, name[ key ]);
+ }
+ } else {
+ // Simple single property case.
+ viewsNs.helpers[ name ] = helper;
+ }
+ return this;
+ },
+
+//===============
+// tmpl.encode
+//===============
+
+ encode: function( encoding, text ) {
+ return text
+ ? ( tmplEncode[ encoding || "html" ] || tmplEncode.html)( text ) // HTML encoding is
the default
+ : "";
+ },
+
+ encoders: tmplEncode = {
+ "none": function( text ) {
+ return text;
+ },
+ "html": function( text ) {
+ // HTML encoding helper: Replace < > & and ' and " by corresponding
entities.
+ // Implementation, from Mike Samuel <msamuel@google.com>
+ return String( text ).replace( htmlSpecialChar, replacerForHtml );
+ }
+ //TODO add URL encoding, and perhaps other encoding helpers...
+ },
+
+//===============
+// renderTag
+//===============
+
+ renderTag: function( tag, view, encode, content, tagProperties ) {
+ // This is a tag call, with arguments: "tag", view, encode, content, presenter [,
params...]
+ var ret, ctx, name,
+ args = arguments,
+ presenters = viewsNs.presenters;
+ hash = tagProperties._hash,
+ tagFn = viewsNs.tags[ tag ];
+
+ if ( !tagFn ) {
+ return "";
+ }
+
+ content = content && view.tmpl.nested[ content - 1 ];
+ tagProperties.tmpl = tagProperties.tmpl || content || undefined;
+ // Set the tmpl property to the content of the block tag, unless set as an override property on
the tag
+
+ if ( presenters && presenters[ tag ]) {
+ ctx = extend( extend( {}, tagProperties.ctx ), tagProperties );
+ delete ctx.ctx;
+ delete ctx._path;
+ delete ctx.tmpl;
+ tagProperties.ctx = ctx;
+ tagProperties._ctor = tag + (hash ? "=" + hash.slice( 0, -1 ) : "");
+
+ tagProperties = extend( extend( {}, tagFn ), tagProperties );
+ tagFn = viewsNs.tags.each; // Use each to render the layout template against the data
+ }
+
+ tagProperties._encode = encode;
+ tagProperties._view = view;
+ ret = tagFn.apply( tagProperties, args.length > 5 ? slice.call( args, 5 ) : [view.data] );
+ return ret || (ret === undefined ? "" : ret.toString()); // (If ret is the value 0 or
false or null, will render to string)
+ }
+ },
+
+//===============
+// render
+//===============
+
+ render: render = function( data, tmpl, context, parentView, path, tagName ) {
+ // Render template against data as a tree of subviews (nested template), or as a string
(top-level template).
+ // tagName parameter for internal use only. Used for rendering templates registered as tags
(which may have associated presenter objects)
+ var i, l, dataItem, arrayView, content, result = "";
+
+ if ( arguments.length === 2 && data.jsViews ) {
+ parentView = data;
+ context = parentView.ctx;
+ data = parentView.data;
+ }
+ tmpl = $.template( tmpl );
+ if ( !tmpl ) {
+ return ""; // Could throw...
+ }
+
+ if ( $.isArray( data )) {
+ // Create a view item for the array, whose child views correspond to each data item.
+ arrayView = new View( context, path, parentView, data);
+ l = data.length;
+ for ( i = 0, l = data.length; i < l; i++ ) {
+ dataItem = data[ i ];
+ content = dataItem ? tmpl( dataItem, new View( context, path, arrayView, dataItem, tmpl, this
)) : "";
+ result += viewsNs.activeViews ? "<!--item-->" + content +
"<!--/item-->" : content;
+ }
+ } else {
+ result += tmpl( data, new View( context, path, parentView, data, tmpl ));
+ }
+
+ return viewsNs.activeViews
+ // If in activeView mode, include annotations
+ ? "<!--tmpl(" + (path || "") + ") " + (tagName ?
"tag=" + tagName : tmpl._name) + "-->" + result +
"<!--/tmpl-->"
+ // else return just the string result
+ : result;
+ },
+
+//===============
+// template
+//===============
+
+ template: function( name, tmpl ) {
+ // Set:
+ // Use $.template( name, tmpl ) to cache a named template,
+ // where tmpl is a template string, a script element or a jQuery instance wrapping a script
element, etc.
+ // Use $( "selector" ).template( name ) to provide access by name to a script block
template declaration.
+
+ // Get:
+ // Use $.template( name ) to access a cached template.
+ // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
+ // will return the compiled template, without adding a name reference.
+ // If templateString is not a selector, $.template( templateString ) is equivalent
+ // to $.template( null, templateString ). To ensure a string is treated as a template,
+ // include an HTML element, an HTML comment, or a template comment tag.
+
+ if (tmpl) {
+ // Compile template and associate with name
+ if ( "" + tmpl === tmpl ) { // type string
+ // This is an HTML string being passed directly in.
+ tmpl = compile( tmpl );
+ } else if ( jQuery && tmpl instanceof $ ) {
+ tmpl = tmpl[0];
+ }
+ if ( tmpl ) {
+ if ( jQuery && tmpl.nodeType ) {
+ // If this is a template block, use cached copy, or generate tmpl function and cache.
+ tmpl = $.data( tmpl, "tmpl" ) || $.data( tmpl, "tmpl", compile(
tmpl.innerHTML ));
+ }
+ viewsNs.templates[ tmpl._name = tmpl._name || name || "_" + autoName++ ] = tmpl;
+ }
+ return tmpl;
+ }
+ // Return named compiled template
+ return name
+ ? "" + name !== name // not type string
+ ? (name._name
+ ? name // already compiled
+ : $.template( null, name ))
+ : viewsNs.templates[ name ] ||
+ // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec)
+ $.template( null, htmlExpr.test( name ) ? name : try$( name ))
+ : null;
+ }
+});
+
+viewsNs.setDelimiters( "{{", "}}" );
+
+//=================
+// compile template
+//=================
+
+// Generate a reusable function that will serve to render a template against data
+// (Compile AST then build template function)
+
+function parsePath( all, comp, object, viewDataCtx, viewProperty, path, string, quot ) {
+ return object
+ ? ((viewDataCtx
+ ? viewProperty
+ ? ("$view." + viewProperty)
+ : object
+ :("$data." + object)
+ ) + ( path || "" ))
+ : string || (comp || "");
+}
+
+function compile( markup ) {
+ var newNode,
+ loc = 0,
+ stack = [],
+ topNode = [],
+ content = topNode,
+ current = [,,topNode];
+
+ function pushPreceedingContent( shift ) {
+ shift -= loc;
+ if ( shift ) {
+ content.push( markup.substr( loc, shift ).replace( rNewLine,"\\n"));
+ }
+ }
+
+ function parseTag( all, isBlock, tagName, equals, code, params, useEncode, encode, closeBlock,
index ) {
+ // rTag : # tagName equals code params encode closeBlock
+ //
/\{\{(?:(?:(\#)?(\w+(?=[\s\}!]))|(?:(\=)|(\*)))((?:[^\}]|\}(?!\}))*?)(!(\w*))?|(?:\/([\w\$\.\[\]]+)))\}\}/g;
+
+ // Build abstract syntax tree: [ tagName, params, content, encode ]
+ var named,
+ hash = "",
+ parenDepth = 0,
+ quoted = FALSE, // boolean for string content in double qoutes
+ aposed = FALSE; // or in single qoutes
+
+ function parseParams( all, path, paren, comp, eq, comma, apos, quot, rightParen, space, index ) {
+ // path paren eq comma apos quot rtPrn space
+ // /(\$?[\w\.\[\]]+)(?:(\()|(===)|(\=))?|(\,\s*)|\\?(\')|\\?(\")|(\))|(\s+)/g
+
+ return aposed
+ // within single-quoted string
+ ? ( aposed = !apos, (aposed ? all : '"'))
+ : quoted
+ // within double-quoted string
+ ? ( quoted = !quot, (quoted ? all : '"'))
+ : comp
+ // comparison
+ ? ( path.replace( rPath, parsePath ) + comp)
+ : eq
+ // named param
+ ? parenDepth ? "" :( named = TRUE, '\b' + path + ':')
+ : paren
+ // function
+ ? (parenDepth++, path.replace( rPath, parsePath ) + '(')
+ : rightParen
+ // function
+ ? (parenDepth--, ")")
+ : path
+ // path
+ ? path.replace( rPath, parsePath )
+ : comma
+ ? ","
+ : space
+ ? (parenDepth
+ ? ""
+ : named
+ ? ( named = FALSE, "\b")
+ : ","
+ )
+ : (aposed = apos, quoted = quot, '"');
+ }
+
+ tagName = tagName || equals;
+ pushPreceedingContent( index );
+ if ( code ) {
+ if ( viewsNs.allowCode ) {
+ content.push([ "*", params.replace( rUnescapeQuotes, "$1" )]);
+ }
+ } else if ( tagName ) {
+ if ( tagName === "else" ) {
+ current = stack.pop();
+ content = current[ 2 ];
+ isBlock = TRUE;
+ }
+ params = (params
+ ? (params + " ")
+ .replace( rParams, parseParams )
+ .replace( rBuildHash, function( all, keyValue, index ) {
+ hash += keyValue + ",";
+ return "";
+ })
+ : "");
+ params = params.slice( 0, -1 );
+ newNode = [
+ tagName,
+ useEncode ? encode || "none" : "",
+ isBlock && [],
+ "{" + hash + "_hash:'" + hash + "',_path:'" +
params + "'}",
+ params
+ ];
+
+ if ( isBlock ) {
+ stack.push( current );
+ current = newNode;
+ }
+ content.push( newNode );
+ } else if ( closeBlock ) {
+ current = stack.pop();
+ }
+ loc = index + all.length; // location marker - parsed up to here
+ if ( !current ) {
+ throw "Expected block tag";
+ }
+ content = current[ 2 ];
+ }
+ markup = markup.replace( rEscapeQuotes, "\\$1" );
+ markup.replace( rTag, parseTag );
+ pushPreceedingContent( markup.length );
+ return buildTmplFunction( topNode );
+}
+
+// Build javascript compiled template function, from AST
+function buildTmplFunction( nodes ) {
+ var ret, node, i,
+ nested = [],
+ l = nodes.length,
+ code = "try{var views="
+ + (jQuery ? "jQuery" : "JsViews")
+ + '.views,tag=views.renderTag,enc=views.encode,html=views.encoders.html,$ctx=$view
&& $view.ctx,result=""+\n\n';
+
+ for ( i = 0; i < l; i++ ) {
+ node = nodes[ i ];
+ if ( node[ 0 ] === "*" ) {
+ code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + ( i + 1 < l ?
"result+=" : "" );
+ } else if ( "" + node === node ) { // type string
+ code += '"' + node + '"+';
+ } else {
+ var tag = node[ 0 ],
+ encode = node[ 1 ],
+ content = node[ 2 ],
+ obj = node[ 3 ],
+ params = node[ 4 ],
+ paramsOrEmptyString = params + '||"")+';
+
+ if( content ) {
+ nested.push( buildTmplFunction( content ));
+ }
+ code += tag === "="
+ ? (!encode || encode === "html"
+ ? "html(" + paramsOrEmptyString
+ : encode === "none"
+ ? ("(" + paramsOrEmptyString)
+ : ('enc("' + encode + '",' + paramsOrEmptyString)
+ )
+ : 'tag("' + tag + '",$view,"' + ( encode || "" ) +
'",'
+ + (content ? nested.length : '""') // For block tags, pass in the key
(nested.length) to the nested content template
+ + "," + obj + (params ? "," : "") + params + ")+";
+ }
+ }
+ ret = new Function( "$data, $view", code.slice( 0, -1) + ";return
result;\n\n}catch(e){return views.err(e);}" );
+ ret.nested = nested;
+ return ret;
+}
+
+//========================== Private helper functions, used by code above
==========================
+
+function replacerForHtml( ch ) {
+ // Original code from Mike Samuel <msamuel@google.com>
+ return escapeMapForHtml[ ch ]
+ // Intentional assignment that caches the result of encoding ch.
+ || ( escapeMapForHtml[ ch ] = "&#" + ch.charCodeAt( 0 ) + ";" );
+}
+
+function try$( selector ) {
+ // If selector is valid, return jQuery object, otherwise return (invalid) selector string
+ try {
+ return $( selector );
+ } catch( e) {}
+ return selector;
+}
+})( window );
Thank you for your contribution.