diff --git a/conf/default.conf.php b/conf/default.conf.php
index ebcaf8761e..4a4e7c2d37 100644
--- a/conf/default.conf.php
+++ b/conf/default.conf.php
@@ -1086,7 +1086,7 @@ return array(
// Directories to look for Phame skins inside of.
'phame.skins' => array(
- 'externals/skin/',
+ 'externals/skins/',
),
// -- Remarkup -------------------------------------------------------------- //
diff --git a/externals/skins/oblivious/css/oblivious.css b/externals/skins/oblivious/css/oblivious.css
new file mode 100644
index 0000000000..13c71259a9
--- /dev/null
+++ b/externals/skins/oblivious/css/oblivious.css
@@ -0,0 +1,77 @@
+html, body, p, h1, h2, h3 {
+ padding: 0;
+ margin: 0;
+ font-weight: normal;
+}
+
+html {
+ font-family: "Helvetica Neue", "Arial", sans-serif;
+ font-size: 16px;
+ overflow-y: scroll;
+ color: #555555;
+}
+
+.oblivious-info {
+ position: fixed;
+ width: 15%;
+ border-right: 1px solid #dfdfdf;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ padding: 140px 2% 0;
+ overflow: hidden;
+
+ background: url(/image/badge.png);
+ background-repeat: no-repeat;
+ background-position: 20px 20px;
+}
+
+.oblivious-content {
+ padding-top: 3%;
+ margin-left: 22%;
+ max-width: 600px;
+}
+
+a {
+ color: #222222;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #a00000;
+}
+
+
+h1 {
+ font-size: 24px;
+ font-weight: normal;
+}
+
+h2 {
+ font-size: 22px;
+ font-weight: bold;
+}
+
+.phame-post {
+ margin: 0 0 2em;
+}
+
+.phame-post-date {
+ font-size: 12px;
+ margin: .25em 0 1em;
+}
+
+.phame-post {
+ line-height: 1.6em;
+}
+
+.phame-post p {
+ margin: 0 0 1em;
+}
+
+
+.fb-comments,
+.fb-comments span,
+.fb-comments iframe[style] {
+ width: 100% !important;
+}
diff --git a/externals/skins/oblivious/header.php b/externals/skins/oblivious/header.php
index 93945f901c..b7aadc2369 100644
--- a/externals/skins/oblivious/header.php
+++ b/externals/skins/oblivious/header.php
@@ -2,6 +2,9 @@
+
+ getCSSResources(); ?>
+
diff --git a/externals/skins/oblivious/image/badge.png b/externals/skins/oblivious/image/badge.png
new file mode 100644
index 0000000000..15f84b92f5
Binary files /dev/null and b/externals/skins/oblivious/image/badge.png differ
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 3b27e630d5..4f42848ef1 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -91,6 +91,7 @@ phutil_register_library_map(array(
'AphrontView' => 'view/AphrontView.php',
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
+ 'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php',
'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php',
'CelerityResourceGraph' => 'infrastructure/celerity/CelerityResourceGraph.php',
'CelerityResourceMap' => 'infrastructure/celerity/CelerityResourceMap.php',
@@ -1174,6 +1175,7 @@ phutil_register_library_map(array(
'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php',
'PhamePostView' => 'applications/phame/view/PhamePostView.php',
'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php',
+ 'PhameResourceController' => 'applications/phame/controller/PhameResourceController.php',
'PhameSkinSpecification' => 'applications/phame/skins/PhameSkinSpecification.php',
'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php',
'PhortuneStripeBaseController' => 'applications/phortune/stripe/controller/PhortuneStripeBaseController.php',
@@ -1334,6 +1336,7 @@ phutil_register_library_map(array(
'AphrontTypeaheadTemplateView' => 'AphrontView',
'AphrontUsageException' => 'AphrontException',
'AphrontWebpageResponse' => 'AphrontResponse',
+ 'CelerityPhabricatorResourceController' => 'CelerityResourceController',
'CelerityResourceController' => 'PhabricatorController',
'CelerityResourceGraph' => 'AbstractDirectedGraph',
'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase',
@@ -2313,6 +2316,7 @@ phutil_register_library_map(array(
'PhamePostUnpublishController' => 'PhameController',
'PhamePostView' => 'AphrontView',
'PhamePostViewController' => 'PhameController',
+ 'PhameResourceController' => 'CelerityResourceController',
'PhortuneMonthYearExpiryControl' => 'AphrontFormControl',
'PhortuneStripeBaseController' => 'PhabricatorController',
'PhortuneStripePaymentFormView' => 'AphrontView',
diff --git a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php
index ee3153d748..33be0b29f9 100644
--- a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php
@@ -155,7 +155,7 @@ class AphrontDefaultApplicationConfiguration
'(?P
pkg/)?'.
'(?P[a-f0-9]{8})/'.
'(?P.+\.(?:css|js|jpg|png|swf|gif))'
- => 'CelerityResourceController',
+ => 'CelerityPhabricatorResourceController',
),
);
}
diff --git a/src/applications/phame/application/PhabricatorApplicationPhame.php b/src/applications/phame/application/PhabricatorApplicationPhame.php
index 84ca525a9c..cd0a684c7c 100644
--- a/src/applications/phame/application/PhabricatorApplicationPhame.php
+++ b/src/applications/phame/application/PhabricatorApplicationPhame.php
@@ -46,6 +46,9 @@ final class PhabricatorApplicationPhame extends PhabricatorApplication {
return array(
'/phame/' => array(
'' => 'PhamePostListController',
+ 'r/(?P\d+)/(?P[^/]+)/(?P.*)'
+ => 'PhameResourceController',
+
'live/(?P[^/]+)/(?P.*)' => 'PhameBlogLiveController',
'post/' => array(
'(?:(?Pdraft|all)/)?' => 'PhamePostListController',
diff --git a/src/applications/phame/controller/PhameResourceController.php b/src/applications/phame/controller/PhameResourceController.php
new file mode 100644
index 0000000000..f933adf759
--- /dev/null
+++ b/src/applications/phame/controller/PhameResourceController.php
@@ -0,0 +1,81 @@
+root;
+ }
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ $this->hash = $data['hash'];
+ $this->name = $data['name'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ // We require a visible blog associated with a given skin to serve
+ // resources, so you can't go fishing around where you shouldn't be.
+
+ $blog = id(new PhameBlogQuery())
+ ->setViewer($user)
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$blog) {
+ return new Aphront404Response();
+ }
+
+ $skin = $blog->getSkinRenderer($request);
+ $spec = $skin->getSpecification();
+
+ $this->root = $spec->getRootDirectory().DIRECTORY_SEPARATOR;
+ return $this->serveResource($this->name, $package_hash = null);
+ }
+
+ protected function buildResourceTransformer() {
+ $xformer = new CelerityResourceTransformer();
+ $xformer->setMinify(false);
+ $xformer->setTranslateURICallback(array($this, 'translateResourceURI'));
+ return $xformer;
+ }
+
+ public function translateResourceURI(array $matches) {
+ $uri = trim($matches[1], "'\" \r\t\n");
+
+ if (Filesystem::pathExists($this->root.$uri)) {
+ $hash = filemtime($this->root.$uri);
+ } else {
+ $hash = '-';
+ }
+
+ $uri = '/phame/r/'.$this->id.'/'.$hash.'/'.$uri;
+ return 'url('.$uri.')';
+ }
+
+}
diff --git a/src/applications/phame/controller/blog/PhameBlogLiveController.php b/src/applications/phame/controller/blog/PhameBlogLiveController.php
index 8f4e5976f5..02e09b7344 100644
--- a/src/applications/phame/controller/blog/PhameBlogLiveController.php
+++ b/src/applications/phame/controller/blog/PhameBlogLiveController.php
@@ -50,19 +50,20 @@ final class PhameBlogLiveController extends PhameController {
->setURI('http://'.$blog->getDomain().'/'.$this->more);
}
- if ($blog->getDomain()) {
- $base_path = '/';
- } else {
- $base_path = '/phame/live/'.$blog->getID().'/';
- }
-
$phame_request = clone $request;
$phame_request->setPath('/'.ltrim($this->more, '/'));
+ if ($blog->getDomain()) {
+ $uri = new PhutilURI('http://'.$blog->getDomain().'/');
+ } else {
+ $uri = '/phame/live/'.$blog->getID().'/';
+ $uri = PhabricatorEnv::getURI($uri);
+ }
+
$skin = $blog->getSkinRenderer($phame_request);
$skin
->setBlog($blog)
- ->setBaseURI($request->getRequestURI()->setPath($base_path));
+ ->setBaseURI((string)$uri);
$skin->willProcessRequest(array());
return $skin->processRequest();
diff --git a/src/applications/phame/skins/PhameBasicBlogSkin.php b/src/applications/phame/skins/PhameBasicBlogSkin.php
index aa797dc442..fdfeedd35e 100644
--- a/src/applications/phame/skins/PhameBasicBlogSkin.php
+++ b/src/applications/phame/skins/PhameBasicBlogSkin.php
@@ -25,7 +25,7 @@ abstract class PhameBasicBlogSkin extends PhameBlogSkin {
private $pager;
- final public function processRequest() {
+ public function processRequest() {
$request = $this->getRequest();
$content = $this->renderContent($request);
@@ -98,6 +98,21 @@ abstract class PhameBasicBlogSkin extends PhameBlogSkin {
return '404 Not Found
';
}
+ final public function getResourceURI($resource) {
+ $root = $this->getSpecification()->getRootDirectory();
+ $path = $root.DIRECTORY_SEPARATOR.$resource;
+
+ $data = Filesystem::readFile($path);
+ $hash = PhabricatorHash::digest($data);
+ $hash = substr($hash, 0, 6);
+ $id = $this->getBlog()->getID();
+
+ $uri = '/phame/r/'.$id.'/'.$hash.'/'.$resource;
+ $uri = PhabricatorEnv::getCDNURI($uri);
+
+ return $uri;
+ }
+
/* -( Paging )------------------------------------------------------------- */
@@ -179,7 +194,7 @@ abstract class PhameBasicBlogSkin extends PhameBlogSkin {
/**
* @task internal
*/
- private function renderContent(AphrontRequest $request) {
+ protected function renderContent(AphrontRequest $request) {
$user = $request->getUser();
$matches = null;
diff --git a/src/applications/phame/skins/PhameBasicTemplateBlogSkin.php b/src/applications/phame/skins/PhameBasicTemplateBlogSkin.php
index dfee960423..e94b442ac9 100644
--- a/src/applications/phame/skins/PhameBasicTemplateBlogSkin.php
+++ b/src/applications/phame/skins/PhameBasicTemplateBlogSkin.php
@@ -21,11 +21,51 @@
*/
final class PhameBasicTemplateBlogSkin extends PhameBasicBlogSkin {
- public function willProcessRequest(array $data) {
+ private $cssResources;
+
+ public function processRequest() {
$root = dirname(phutil_get_library_root('phabricator'));
require_once $root.'/support/phame/libskin.php';
- parent::willProcessRequest($data);
+ $css = $this->getPath('css/');
+ if (Filesystem::pathExists($css)) {
+ $this->cssResources = array();
+ foreach (Filesystem::listDirectory($css) as $path) {
+ if (!preg_match('/.css$/', $path)) {
+ continue;
+ }
+ $this->cssResources[] = phutil_render_tag(
+ 'link',
+ array(
+ 'rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => $this->getResourceURI('css/'.$path),
+ ));
+ }
+ $this->cssResources = implode("\n", $this->cssResources);
+ }
+
+ $request = $this->getRequest();
+ $content = $this->renderContent($request);
+
+ if (!$content) {
+ $content = $this->render404Page();
+ }
+
+ $content = array(
+ $this->renderHeader(),
+ $content,
+ $this->renderFooter(),
+ );
+
+ $response = new AphrontWebpageResponse();
+ $response->setContent(implode("\n", $content));
+
+ return $response;
+ }
+
+ public function getCSSResources() {
+ return $this->cssResources;
}
public function getName() {
@@ -45,7 +85,9 @@ final class PhameBasicTemplateBlogSkin extends PhameBasicBlogSkin {
ob_start();
if (Filesystem::pathExists($this->getPath($__template__))) {
- extract($__scope__ + $this->getDefaultScope());
+ // Fool lint.
+ $__evil__ = 'extract';
+ $__evil__($__scope__ + $this->getDefaultScope());
require $this->getPath($__template__);
}
diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php
index 1d3c4d7693..b006d67206 100644
--- a/src/applications/phame/storage/PhameBlog.php
+++ b/src/applications/phame/storage/PhameBlog.php
@@ -65,6 +65,12 @@ final class PhameBlog extends PhameDAO
self::SKIN_DEFAULT);
}
+ if (!$spec) {
+ throw new Exception(
+ "This blog has an invalid skin, and the default skin failed to ".
+ "load.");
+ }
+
$skin = newv($spec->getSkinClass(), array($request));
$skin->setSpecification($spec);
diff --git a/src/applications/phame/view/PhamePostView.php b/src/applications/phame/view/PhamePostView.php
index b39af0d038..ae26615d48 100644
--- a/src/applications/phame/view/PhamePostView.php
+++ b/src/applications/phame/view/PhamePostView.php
@@ -169,8 +169,7 @@ final class PhamePostView extends AphrontView {
),
$this->renderTitle().
$this->renderDatePublished().
- $this->renderSummary().
- $this->renderComments());
+ $this->renderSummary());
}
private function renderFacebookComments() {
@@ -198,13 +197,14 @@ final class PhamePostView extends AphrontView {
$c_uri
);
+
+ $uri = $this->getSkin()->getURI('post/'.$this->getPost()->getPhameTitle());
+
$fb_comments = phutil_render_tag('div',
array(
'class' => 'fb-comments',
- 'data-href' => $this->getRequestURI(),
+ 'data-href' => $uri,
'data-num-posts' => 5,
- 'data-width' => 1080, // we hack this to fluid in css
- 'data-colorscheme' => 'dark',
),
''
);
@@ -249,7 +249,7 @@ final class PhamePostView extends AphrontView {
' document.getElementsByTagName("body")[0]).appendChild(dsq);'.
'})(); ',
$post->getPHID(),
- $this->getRequestURI(),
+ $this->getSkin()->getURI('post/'.$this->getPost()->getPhameTitle()),
$post->getTitle()
);
diff --git a/src/infrastructure/celerity/CelerityPhabricatorResourceController.php b/src/infrastructure/celerity/CelerityPhabricatorResourceController.php
new file mode 100644
index 0000000000..4eff40b2de
--- /dev/null
+++ b/src/infrastructure/celerity/CelerityPhabricatorResourceController.php
@@ -0,0 +1,59 @@
+path = $data['path'];
+ $this->hash = $data['hash'];
+ $this->package = !empty($data['package']);
+ }
+
+ public function processRequest() {
+ $package_hash = null;
+ if ($this->package) {
+ $package_hash = $this->hash;
+ }
+ return $this->serveResource($this->path, $package_hash);
+ }
+
+ protected function buildResourceTransformer() {
+ $xformer = new CelerityResourceTransformer();
+ $xformer->setMinify(PhabricatorEnv::getEnvConfig('celerity.minify'));
+ $xformer->setCelerityMap(CelerityResourceMap::getInstance());
+ return $xformer;
+ }
+
+}
diff --git a/src/infrastructure/celerity/CelerityResourceController.php b/src/infrastructure/celerity/CelerityResourceController.php
index e29fb4519f..ab00881b1e 100644
--- a/src/infrastructure/celerity/CelerityResourceController.php
+++ b/src/infrastructure/celerity/CelerityResourceController.php
@@ -16,18 +16,13 @@
* limitations under the License.
*/
-/**
- * Delivers CSS and JS resources to the browser. This controller handles all
- * ##/res/## requests, and manages caching, package construction, and resource
- * preprocessing.
- *
- * @group celerity
- */
-final class CelerityResourceController extends PhabricatorController {
+abstract class CelerityResourceController extends PhabricatorController {
- private $path;
- private $hash;
- private $package;
+ abstract protected function getRootDirectory();
+
+ protected function buildResourceTransformer() {
+ return null;
+ }
public function shouldRequireLogin() {
return false;
@@ -37,15 +32,11 @@ final class CelerityResourceController extends PhabricatorController {
return false;
}
- public function willProcessRequest(array $data) {
- $this->path = $data['path'];
- $this->hash = $data['hash'];
- $this->package = !empty($data['package']);
+ private function getDiskPath($to_resource = null) {
+ return $this->getRootDirectory().$to_resource;
}
- public function processRequest() {
- $path = $this->path;
-
+ protected function serveResource($path, $package_hash = null) {
// Sanity checking to keep this from exposing anything sensitive, since it
// ultimately boils down to disk reads.
if (preg_match('@(//|\.\.)@', $path)) {
@@ -66,11 +57,9 @@ final class CelerityResourceController extends PhabricatorController {
return $this->makeResponseCacheable(new Aphront304Response());
}
- $root = dirname(phutil_get_library_root('phabricator'));
-
- if ($this->package) {
+ if ($package_hash) {
$map = CelerityResourceMap::getInstance();
- $paths = $map->resolvePackage($this->hash);
+ $paths = $map->resolvePackage($package_hash);
if (!$paths) {
return new Aphront404Response();
}
@@ -78,7 +67,8 @@ final class CelerityResourceController extends PhabricatorController {
try {
$data = array();
foreach ($paths as $package_path) {
- $data[] = Filesystem::readFile($root.'/webroot/'.$package_path);
+ $disk_path = $this->getDiskPath($package_path);
+ $data[] = Filesystem::readFile($disk_path);
}
$data = implode("\n\n", $data);
} catch (Exception $ex) {
@@ -86,17 +76,17 @@ final class CelerityResourceController extends PhabricatorController {
}
} else {
try {
- $data = Filesystem::readFile($root.'/webroot/'.$path);
+ $disk_path = $this->getDiskPath($path);
+ $data = Filesystem::readFile($disk_path);
} catch (Exception $ex) {
return new Aphront404Response();
}
}
- $xformer = new CelerityResourceTransformer();
- $xformer->setMinify(PhabricatorEnv::getEnvConfig('celerity.minify'));
- $xformer->setCelerityMap(CelerityResourceMap::getInstance());
-
- $data = $xformer->transformResource($path, $data);
+ $xformer = $this->buildResourceTransformer();
+ if ($xformer) {
+ $data = $xformer->transformResource($path, $data);
+ }
$response = new AphrontFileResponse();
$response->setContent($data);
@@ -104,7 +94,7 @@ final class CelerityResourceController extends PhabricatorController {
return $this->makeResponseCacheable($response);
}
- private function getSupportedResourceTypes() {
+ protected function getSupportedResourceTypes() {
return array(
'css' => 'text/css; charset=utf-8',
'js' => 'text/javascript; charset=utf-8',
diff --git a/src/infrastructure/celerity/CelerityResourceTransformer.php b/src/infrastructure/celerity/CelerityResourceTransformer.php
index 7ecada2cd9..f681a08abf 100644
--- a/src/infrastructure/celerity/CelerityResourceTransformer.php
+++ b/src/infrastructure/celerity/CelerityResourceTransformer.php
@@ -24,6 +24,12 @@ final class CelerityResourceTransformer {
private $minify;
private $rawResourceMap;
private $celerityMap;
+ private $translateURICallback;
+
+ public function setTranslateURICallback($translate_uricallback) {
+ $this->translateURICallback = $translate_uricallback;
+ return $this;
+ }
public function setMinify($minify) {
$this->minify = $minify;
@@ -46,8 +52,10 @@ final class CelerityResourceTransformer {
switch ($type) {
case 'css':
$data = preg_replace_callback(
- '@url\s*\((\s*[\'"]?/rsrc/.*?)\)@s',
- array($this, 'translateResourceURI'),
+ '@url\s*\((\s*[\'"]?.*?)\)@s',
+ nonempty(
+ $this->translateURICallback,
+ array($this, 'translateResourceURI')),
$data);
break;
}