1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 08:52:39 +01:00

Move skins toward modularization

Summary:
Two high-level things happening here:

  - We no longer ever need to put meta-UI (content creation, editing, notices, etc.) on live blog views, since this is all in Phame now. I pulled this out.
  - On the other hand, I pushed more routing/control logic into Skins and made the root skin a Controller instead of a View. This simplifies some of the code above skins, and the theory behind this is that it gives us greater flexibility to, e.g., put a glue layer between Phame and Wordpress templates or whatever else, and allows skins to handle routing and thus add pages like "About" or "Bio".
  - I added a basic skin below the root skin which is more like the old root skin and has standard rendering hooks.
  - "Ten Eleven" is a play on the popular (default?) Wordpress themes called "Twenty Ten", "Twenty Eleven" and "Twenty Twelve".

Test Plan: Viewed live blog and live posts. They aren't pretty, but they don't have extraneous resources.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1373

Differential Revision: https://secure.phabricator.com/D3714
This commit is contained in:
epriestley 2012-10-17 08:36:25 -07:00
parent 1105cfc3a8
commit 83bbad8ba0
14 changed files with 611 additions and 788 deletions

View file

@ -604,7 +604,6 @@ phutil_register_library_map(array(
'PhabricatorBarePageExample' => 'applications/uiexample/examples/PhabricatorBarePageExample.php',
'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php',
'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php',
'PhabricatorBlogSkin' => 'applications/phame/view/skins/PhabricatorBlogSkin.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php',
@ -1150,6 +1149,7 @@ phutil_register_library_map(array(
'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php',
'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php',
'PhabricatorXHProfSampleListView' => 'applications/xhprof/view/PhabricatorXHProfSampleListView.php',
'PhameBasicBlogSkin' => 'applications/phame/skins/PhameBasicBlogSkin.php',
'PhameBlog' => 'applications/phame/storage/PhameBlog.php',
'PhameBlogDeleteController' => 'applications/phame/controller/blog/PhameBlogDeleteController.php',
'PhameBlogDetailView' => 'applications/phame/view/PhameBlogDetailView.php',
@ -1157,23 +1157,23 @@ phutil_register_library_map(array(
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
'PhameBlogSkin' => 'applications/phame/view/skins/PhameBlogSkin.php',
'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php',
'PhameBlogSkinTenEleven' => 'applications/phame/skins/PhameBlogSkinTenEleven.php',
'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php',
'PhameController' => 'applications/phame/controller/PhameController.php',
'PhameDAO' => 'applications/phame/storage/PhameDAO.php',
'PhamePost' => 'applications/phame/storage/PhamePost.php',
'PhamePostDeleteController' => 'applications/phame/controller/post/PhamePostDeleteController.php',
'PhamePostDetailView' => 'applications/phame/view/PhamePostDetailView.php',
'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php',
'PhamePostFramedController' => 'applications/phame/controller/post/PhamePostFramedController.php',
'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php',
'PhamePostListView' => 'applications/phame/view/PhamePostListView.php',
'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php',
'PhamePostNotLiveController' => 'applications/phame/controller/post/PhamePostNotLiveController.php',
'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php',
'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php',
'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php',
'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php',
'PhamePostView' => 'applications/phame/view/PhamePostView.php',
'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php',
'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php',
'PhortuneStripeBaseController' => 'applications/phortune/stripe/controller/PhortuneStripeBaseController.php',
@ -1790,7 +1790,6 @@ phutil_register_library_map(array(
'PhabricatorBarePageExample' => 'PhabricatorUIExample',
'PhabricatorBarePageView' => 'AphrontPageView',
'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation',
'PhabricatorBlogSkin' => 'PhameBlogSkin',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
@ -2279,6 +2278,7 @@ phutil_register_library_map(array(
'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO',
'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController',
'PhabricatorXHProfSampleListView' => 'AphrontView',
'PhameBasicBlogSkin' => 'PhameBlogSkin',
'PhameBlog' =>
array(
0 => 'PhameDAO',
@ -2291,7 +2291,8 @@ phutil_register_library_map(array(
'PhameBlogListController' => 'PhameController',
'PhameBlogLiveController' => 'PhameController',
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhameBlogSkin' => 'AphrontView',
'PhameBlogSkin' => 'PhabricatorController',
'PhameBlogSkinTenEleven' => 'PhameBasicBlogSkin',
'PhameBlogViewController' => 'PhameController',
'PhameController' => 'PhabricatorController',
'PhameDAO' => 'PhabricatorLiskDAO',
@ -2302,17 +2303,16 @@ phutil_register_library_map(array(
2 => 'PhabricatorMarkupInterface',
),
'PhamePostDeleteController' => 'PhameController',
'PhamePostDetailView' => 'AphrontView',
'PhamePostEditController' => 'PhameController',
'PhamePostFramedController' => 'PhameController',
'PhamePostListController' => 'PhameController',
'PhamePostListView' => 'AphrontView',
'PhamePostNewController' => 'PhameController',
'PhamePostNotLiveController' => 'PhameController',
'PhamePostPreviewController' => 'PhameController',
'PhamePostPublishController' => 'PhameController',
'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhamePostUnpublishController' => 'PhameController',
'PhamePostView' => 'AphrontView',
'PhamePostViewController' => 'PhameController',
'PhortuneMonthYearExpiryControl' => 'AphrontFormControl',
'PhortuneStripeBaseController' => 'PhabricatorController',

View file

@ -55,6 +55,11 @@ final class AphrontRequest {
return $this->applicationConfiguration;
}
final public function setPath($path) {
$this->path = $path;
return $this;
}
final public function getPath() {
return $this->path;
}

View file

@ -50,46 +50,21 @@ final class PhameBlogLiveController extends PhameController {
->setURI('http://'.$blog->getDomain().'/'.$this->more);
}
$pager = id(new AphrontCursorPagerView())
->readFromRequest($request);
$query = id(new PhamePostQuery())
->setViewer($user)
->withBlogPHIDs(array($blog->getPHID()));
$matches = null;
$path = $this->more;
if (preg_match('@^/(?P<view>[^/]+)/(?P<name>.*)$@', $path, $matches)) {
$view = $matches['view'];
$name = $matches['name'];
if ($blog->getDomain()) {
$base_path = '/';
} else {
$view = '';
$name = '';
$base_path = '/phame/live/'.$blog->getID().'/';
}
switch ($view) {
case 'post':
$query->withPhameTitles(array($name));
break;
}
$phame_request = clone $request;
$phame_request->setPath('/'.ltrim($this->more, '/'));
$posts = $query->executeWithCursorPager($pager);
$skin = $blog->getSkinRenderer();
$skin = $blog->getSkinRenderer($phame_request);
$skin
->setUser($user)
->setPosts($posts)
->setBloggers($this->loadViewerHandles(mpull($posts, 'getBloggerPHID')))
->setBlog($blog)
->setRequestURI($this->getRequest()->getRequestURI());
->setBaseURI($request->getRequestURI()->setPath($base_path));
$page = $this->buildStandardPageView();
$page->appendChild($skin);
$page->setShowChrome(false);
$response = new AphrontWebpageResponse();
$response->setContent($page->render());
return $response;
return $skin->processRequest();
}
}

View file

@ -43,29 +43,21 @@ final class PhamePostFramedController extends PhameController {
return new Aphront404Response();
}
$skin = $post->getBlog()->getSkinRenderer();
$blog = $post->getBlog();
$handles = $this->loadViewerHandles(
array(
$post->getBloggerPHID(),
));
$phame_request = $request->setPath('/post/'.$post->getPhameTitle());
$skin = $post->getBlog()->getSkinRenderer($phame_request);
$uri = clone $request->getRequestURI();
$uri->setPath('/phame/live/'.$blog->getID().'/');
$skin
->setUser($user)
->setPreview(true)
->setBlog($post->getBlog())
->setPosts(array($post))
->setBloggers($handles)
->setRequestURI($this->getRequest()->getRequestURI());
->setBaseURI((string)$uri);
$page = $this->buildStandardPageView();
$page->setFrameable(true);
$page->setShowChrome(false);
$page->appendChild($skin);
$response = new AphrontWebpageResponse();
$response = $skin->processRequest();
$response->setFrameable(true);
$response->setContent($page->render());
return $response;
}
}

View file

@ -30,24 +30,15 @@ extends PhameController {
$request = $this->getRequest();
$user = $request->getUser();
$body = $request->getStr('body');
$title = $request->getStr('title');
$phame_title = $request->getStr('phame_title');
$post = id(new PhamePost())
->setBody($body)
->setTitle($title)
->setPhameTitle($phame_title)
->setDateModified(time());
->setBody($body);
$blogger = PhabricatorObjectHandleData::loadOneHandle($user->getPHID());
$content = PhabricatorMarkupEngine::renderOneObject(
$post,
PhamePost::MARKUP_FIELD_BODY,
$user);
$post_html = id(new PhamePostDetailView())
->setUser($user)
->setBlogger($blogger)
->setPost($post)
->setIsPreview(true)
->render();
return id(new AphrontAjaxResponse())->setContent($post_html);
return id(new AphrontAjaxResponse())->setContent($content);
}
}

View file

@ -0,0 +1,256 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @task paging Paging
* @task internal Internals
* @group phame
*/
abstract class PhameBasicBlogSkin extends PhameBlogSkin {
private $pager;
final public function processRequest() {
$request = $this->getRequest();
$content = $this->renderContent($request);
if (!$content) {
$content = $this->render404Page();
}
$content = array(
$this->renderHeader(),
$content,
$this->renderFooter(),
);
$view = id(new PhabricatorBarePageView())
->setRequest($request)
->setController($this)
->setDeviceReady(true)
->setTitle($this->getBlog()->getName());
if ($this->getPreview()) {
$view->setFrameable(true);
}
$view->appendChild($content);
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
public function getSkinName() {
return get_class($this);
}
abstract protected function renderHeader();
abstract protected function renderFooter();
protected function renderPostDetail(PhamePostView $post) {
return $post;
}
protected function renderPostList(array $posts) {
$list = phutil_render_tag(
'div',
array(
'class' => 'phame-post-list',
),
id(new AphrontNullView())->appendChild($posts)->render());
$pager = $this->renderOlderPageLink().$this->renderNewerPageLink();
if ($pager) {
$pager = phutil_render_tag(
'div',
array(
'class' => 'phame-pager',
));
}
return $list.$pager;
}
protected function render404Page() {
return '<h2>404 Not Found</h2>';
}
/* -( Paging )------------------------------------------------------------- */
/**
* @task paging
*/
public function getPageSize() {
return 100;
}
/**
* @task paging
*/
protected function getOlderPageURI() {
if ($this->pager) {
$next = $this->pager->getNextPageID();
if ($next) {
return $this->getURI('older/'.$next.'/');
}
}
return null;
}
/**
* @task paging
*/
protected function renderOlderPageLink() {
$uri = $this->getOlderPageURI();
return phutil_render_tag(
'a',
array(
'class' => 'phame-page-link phame-page-older',
'href' => $uri,
),
pht("\xE2\x80\xB9 Older"));
}
/**
* @task paging
*/
protected function getNewerPageURI() {
if ($this->pager) {
$next = $this->pager->getNextPageID();
if ($next) {
return $this->getURI('newer/'.$next.'/');
}
}
return null;
}
/**
* @task paging
*/
protected function renderNewerPageLink() {
$uri = $this->getNewerPageURI();
return phutil_render_tag(
'a',
array(
'class' => 'phame-page-link phame-page-newer',
'href' => $uri,
),
pht("Newer \xE2\x80\xBA"));
}
/* -( Internals )---------------------------------------------------------- */
/**
* @task internal
*/
private function renderContent(AphrontRequest $request) {
$user = $request->getUser();
$matches = null;
$path = $request->getPath();
if (preg_match('@^/post/(?P<name>.*)$@', $path, $matches)) {
$post = id(new PhamePostQuery())
->setViewer($user)
->withBlogPHIDs(array($this->getBlog()->getPHID()))
->withPhameTitles(array($matches['name']))
->executeOne();
if ($post) {
$view = head($this->buildPostViews(array($post)));
return $this->renderPostDetail($view);
}
} else {
$pager = new AphrontCursorPagerView();
if (preg_match('@^/older/(?P<before>\d+)/$@', $path, $matches)) {
$pager->setBeforeID($matches['before']);
} else if (preg_match('@^/newer/(?P<after>\d)/$@', $path, $matches)) {
$pager->setAfterID($matches['after']);
} else if (preg_match('@^/$@', $path, $matches)) {
// Just show the first page.
} else {
return null;
}
$pager->setPageSize($this->getPageSize());
$posts = id(new PhamePostQuery())
->setViewer($user)
->withBlogPHIDs(array($this->getBlog()->getPHID()))
->executeWithCursorPager($pager);
$this->pager = $pager;
if ($posts) {
$views = $this->buildPostViews($posts);
return $this->renderPostList($views);
}
}
return null;
}
private function buildPostViews(array $posts) {
assert_instances_of($posts, 'PhamePost');
$user = $this->getRequest()->getUser();
$engine = id(new PhabricatorMarkupEngine())
->setViewer($user);
$phids = array();
foreach ($posts as $post) {
$engine->addObject($post, PhamePost::MARKUP_FIELD_BODY);
$phids[] = $post->getBloggerPHID();
}
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$engine->process();
$views = array();
foreach ($posts as $post) {
$view = id(new PhamePostView())
->setViewer($user)
->setSkin($this)
->setPost($post)
->setBody($engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY))
->setAuthor($handles[$post->getBloggerPHID()]);
$post->makeEphemeral();
if (!$post->getDatePublished()) {
$post->setDatePublished(time());
}
$views[] = $view;
}
return $views;
}
}

View file

@ -0,0 +1,55 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group phame
*/
abstract class PhameBlogSkin extends PhabricatorController {
private $blog;
private $baseURI;
private $preview;
public function setPreview($preview) {
$this->preview = $preview;
return $this;
}
public function getPreview() {
return $this->preview;
}
final public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
final public function getURI($path) {
return $this->baseURI.$path;
}
final public function setBlog(PhameBlog $blog) {
$this->blog = $blog;
return $this;
}
final public function getBlog() {
return $this->blog;
}
}

View file

@ -19,26 +19,36 @@
/**
* @group phame
*/
final class PhabricatorBlogSkin extends PhameBlogSkin {
final class PhameBlogSkinTenEleven extends PhameBasicBlogSkin {
public function __construct() {
$this->setShowChrome(true);
public function getName() {
return 'Ten Eleven (Default)';
}
protected function renderHeader() {
return '';
$blog_name = $this->getBlog()->getName();
$about = $this->getBlog()->getDescription();
$about = phutil_escape_html($about);
return <<<EOHTML
<div class="main-panel">
<div class="header">
<h1>{$blog_name}</h1>
<div class="about">{$about}</div>
</div>
<div class="splash">
</div>
<div class="content">
EOHTML;
}
protected function renderFooter() {
return '';
return <<<EOHTML
</div>
</div>
EOHTML;
}
protected function renderBody() {
require_celerity_resource('phame-css');
return
$this->renderNotice() .
$this->renderPosts() .
$this->renderBlogDetails();
}
}

View file

@ -24,7 +24,7 @@ final class PhameBlog extends PhameDAO
const MARKUP_FIELD_DESCRIPTION = 'markup:description';
const SKIN_DEFAULT = 'PhabricatorBlogSkin';
const SKIN_DEFAULT = 'PhameBlogSkinTenEleven';
protected $id;
protected $phid;
@ -56,13 +56,13 @@ final class PhameBlog extends PhameDAO
PhabricatorPHIDConstants::PHID_TYPE_BLOG);
}
public function getSkinRenderer() {
public function getSkinRenderer(AphrontRequest $request) {
try {
$skin = newv($this->getSkin(), array());
$skin = newv($this->getSkin(), array($request));
} catch (PhutilMissingSymbolException $ex) {
// If this blog has a skin but it's no longer available (for example,
// it was uninstalled) just return the default skin.
$skin = newv(self::SKIN_DEFAULT, array());
$skin = newv(self::SKIN_DEFAULT, array($request));
}
return $skin;

View file

@ -1,360 +0,0 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group phame
*/
final class PhamePostDetailView extends AphrontView {
private $user;
private $post;
private $blog;
private $blogger;
private $actions = array();
private $requestURI;
private $isPreview;
private $showComments;
private $shouldShorten;
public function setShouldShorten($should_shorten) {
$this->shouldShorten = $should_shorten;
return $this;
}
public function getShouldShorten() {
return $this->shouldShorten;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function getUser() {
return $this->user;
}
public function setPost(PhamePost $post) {
$this->post = $post;
return $this;
}
private function getPost() {
return $this->post;
}
public function setBlog(PhameBlog $blog) {
$this->blog = $blog;
return $this;
}
private function getBlog() {
return $this->blog;
}
public function setBlogger(PhabricatorObjectHandle $blogger) {
$this->blogger = $blogger;
return $this;
}
private function getBlogger() {
return $this->blogger;
}
public function setActions(array $actions) {
$this->actions = $actions;
return $this;
}
private function getActions() {
if ($this->actions) {
return $this->actions;
}
return array();
}
public function setRequestURI(PhutilURI $uri) {
$uri = PhabricatorEnv::getProductionURI($uri->setQueryParams(array()));
$this->requestURI = $uri;
return $this;
}
private function getRequestURI() {
return $this->requestURI;
}
public function setIsPreview($is_preview) {
$this->isPreview = $is_preview;
return $this;
}
private function isPreview() {
return $this->isPreview;
}
public function setShowComments($show_comments) {
$this->showComments = $show_comments;
return $this;
}
private function getShowComments() {
return $this->showComments;
}
public function render() {
require_celerity_resource('phabricator-remarkup-css');
require_celerity_resource('phame-css');
$user = $this->getUser();
$blogger = $this->getBlogger();
$post = $this->getPost();
$actions = $this->getActions();
$noun = $post->isDraft() ? 'Draft' : 'Post';
$buttons = array();
foreach ($actions as $action) {
switch ($action) {
case 'view':
$uri = $post->getViewURI($blogger->getName());
$label = 'View '.$noun;
break;
case 'edit':
$uri = $post->getEditURI();
$label = 'Edit '.$noun;
break;
case 'more':
if ($post->isDraft()) {
$uri = '/phame/draft/';
$label = 'Back to Your Drafts';
} else {
$uri = '/phame/posts/'.$blogger->getName().'/';
$label = 'More Posts by '.phutil_escape_html($blogger->getName());
}
break;
default:
break;
}
$button = phutil_render_tag(
'a',
array(
'href' => $uri,
'class' => 'grey button',
),
$label);
$buttons[] = $button;
}
$button_html = '';
if ($buttons) {
$button_html = phutil_render_tag(
'div',
array(
'class' => 'buttons'
),
implode('', $buttons)
);
}
$publish_date = $post->getDatePublished();
if ($publish_date) {
$caption = 'Published '.
phabricator_datetime($publish_date,
$user);
} else {
$caption = 'Last edited '.
phabricator_datetime($post->getDateModified(),
$user);
}
$caption .= ' by <b>'.
phutil_escape_html($blogger->getName()).'</b>.';
$shortened = false;
$body_text = $post->getBody();
if ($this->getShouldShorten()) {
$body_length = phutil_utf8_strlen($body_text);
$body_text = phutil_utf8_shorten($body_text, 5000);
$shortened = $body_length > phutil_utf8_strlen($body_text);
}
$engine = PhabricatorMarkupEngine::newPhameMarkupEngine();
$body = $engine->markupText($body_text);
$comments = null;
if ($this->getShowComments()) {
switch ($post->getCommentsWidget()) {
case 'facebook':
$comments = $this->renderFacebookComments();
break;
case 'disqus':
$comments = $this->renderDisqusComments();
break;
case 'none':
default:
$comments = null;
break;
}
}
$more_to_do = null;
if (!$comments) {
if ($shortened) {
$more_to_do =
phutil_render_tag(
'div',
array(
'class' => 'more-and-comments'
),
phutil_render_tag(
'a',
array(
'href' => $post->getViewURI()
),
'&#8594; Read More'
)
);
} else if ($post->getCommentsWidget() &&
$post->getCommentsWidget() != 'none') {
$more_to_do =
phutil_render_tag(
'div',
array(
'class' => 'more-and-comments'
),
phutil_render_tag(
'a',
array(
'href' => $post->getViewURI()
),
'&#8594; Comment'
)
);
}
}
$post_html =
phutil_render_tag(
'div',
array(
'class' => 'blog-post'
),
phutil_render_tag(
'div',
array(
'class' => 'header',
),
$button_html .
phutil_render_tag(
'h1',
array(),
phutil_render_tag('a',
array(
'href' => $post->getViewURI($blogger->getName())
),
phutil_escape_html($post->getTitle())
)
).
phutil_render_tag(
'div',
array(
'class' => 'last-updated'
),
$caption
)
).
phutil_render_tag(
'div',
array(
'class' => 'phabricator-remarkup'
),
$body
).
$comments.$more_to_do
);
return $post_html;
}
private function renderFacebookComments() {
$fb_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
if (!$fb_id) {
return null;
}
$fb_root = phutil_render_tag('div',
array(
'id' => 'fb-root',
),
''
);
$c_uri = '//connect.facebook.net/en_US/all.js#xfbml=1&appId='.$fb_id;
$fb_js = jsprintf(
'<script>(function(d, s, id) {'.
' var js, fjs = d.getElementsByTagName(s)[0];'.
' if (d.getElementById(id)) return;'.
' js = d.createElement(s); js.id = id;'.
' js.src = %s;'.
' fjs.parentNode.insertBefore(js, fjs);'.
'}(document, \'script\', \'facebook-jssdk\'));</script>',
$c_uri
);
$fb_comments = phutil_render_tag('div',
array(
'class' => 'fb-comments',
'data-href' => $this->getRequestURI(),
'data-num-posts' => 5,
'data-width' => 1080, // we hack this to fluid in css
'data-colorscheme' => 'dark',
),
''
);
return '<hr />' . $fb_root . $fb_js . $fb_comments;
}
private function renderDisqusComments() {
$disqus_shortname = PhabricatorEnv::getEnvConfig('disqus.shortname');
if (!$disqus_shortname) {
return null;
}
$post = $this->getPost();
$disqus_thread = phutil_render_tag('div',
array(
'id' => 'disqus_thread'
)
);
// protip - try some var disqus_developer = 1; action to test locally
$disqus_js = jsprintf(
'<script>'.
' var disqus_shortname = "phabricator";'.
' var disqus_identifier = %s;'.
' var disqus_url = %s;'.
' var disqus_title = %s;'.
'(function() {'.
' var dsq = document.createElement("script");'.
' dsq.type = "text/javascript";'.
' dsq.async = true;'.
' dsq.src = "http://" + disqus_shortname + ".disqus.com/embed.js";'.
'(document.getElementsByTagName("head")[0] ||'.
' document.getElementsByTagName("body")[0]).appendChild(dsq);'.
'})(); </script>',
$post->getPHID(),
$this->getRequestURI(),
$post->getTitle()
);
return '<hr />' . $disqus_thread . $disqus_js;
}
}

View file

@ -1,138 +0,0 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group phame
*/
final class PhamePostListView extends AphrontView {
private $user;
private $posts;
private $bloggers;
private $actions = array();
private $draftList;
private $requestURI;
private $showPostComments;
public function setShowPostComments($show_post_comments) {
$this->showPostComments = $show_post_comments;
return $this;
}
private function getShowPostComments() {
return $this->showPostComments;
}
public function setRequestURI($request_uri) {
$this->requestURI = $request_uri;
return $this;
}
public function getRequestURI() {
return $this->requestURI;
}
public function setDraftList($draft_list) {
$this->draftList = $draft_list;
return $this;
}
public function isDraftList() {
return (bool) $this->draftList;
}
private function getPostNoun() {
if ($this->isDraftList()) {
$noun = 'Draft';
} else {
$noun = 'Post';
}
return $noun;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
private function getUser() {
return $this->user;
}
public function setPosts(array $posts) {
assert_instances_of($posts, 'PhamePost');
$this->posts = $posts;
return $this;
}
private function getPosts() {
return $this->posts;
}
public function setBloggers(array $bloggers) {
assert_instances_of($bloggers, 'PhabricatorObjectHandle');
$this->bloggers = $bloggers;
return $this;
}
private function getBloggers() {
return $this->bloggers;
}
public function setActions(array $actions) {
$this->actions = $actions;
return $this;
}
private function getActions() {
return $this->actions;
}
public function render() {
$user = $this->getUser();
$posts = $this->getPosts();
$bloggers = $this->getBloggers();
$noun = $this->getPostNoun();
if (empty($posts)) {
$panel = id(new AphrontPanelView())
->setHeader(sprintf('No %ss... Yet!', $noun))
->setCaption('Will you answer the call to phame?')
->setCreateButton(sprintf('New %s', $noun),
sprintf('/phame/%s/new', strtolower($noun)));
return $panel->render();
}
require_celerity_resource('phabricator-remarkup-css');
require_celerity_resource('phame-css');
$engine = PhabricatorMarkupEngine::newPhameMarkupEngine();
$html = array();
$actions = $this->getActions();
foreach ($posts as $post) {
$blogger_phid = $post->getBloggerPHID();
$blogger = $bloggers[$blogger_phid];
$detail = id(new PhamePostDetailView())
->setUser($user)
->setPost($post)
->setBlogger($blogger)
->setActions($actions)
->setRequestURI($this->getRequestURI())
->setShowComments($this->getShowPostComments());
$html[] = $detail->render();
}
return phutil_render_tag(
'div',
array(
'class' => 'blog-post-list'
),
implode('', $html)
);
}
}

View file

@ -0,0 +1,233 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group phame
*/
final class PhamePostView extends AphrontView {
private $post;
private $author;
private $viewer;
private $body;
private $skin;
public function setSkin(PhameBlogSkin $skin) {
$this->skin = $skin;
return $this;
}
public function getSkin() {
return $this->skin;
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
public function setAuthor(PhabricatorObjectHandle $author) {
$this->author = $author;
return $this;
}
public function getAuthor() {
return $this->author;
}
public function setPost(PhamePost $post) {
$this->post = $post;
return $this;
}
public function getPost() {
return $this->post;
}
public function setBody($body) {
$this->body = $body;
return $this;
}
public function getBody() {
return $this->body;
}
public function renderTitle() {
$href = $this->getSkin()->getURI('post/'.$this->getPost()->getPhameTitle());
return phutil_render_tag(
'h2',
array(
'class' => 'phame-post-title',
),
phutil_render_tag(
'a',
array(
'href' => $href,
),
phutil_escape_html($this->getPost()->getTitle())));
}
public function renderDatePublished() {
return phutil_render_tag(
'div',
array(
'class' => 'phame-post-date',
),
phutil_escape_html(
pht(
'Published on %s by %s',
phabricator_datetime(
$this->getPost()->getDatePublished(),
$this->getViewer()),
$this->getAuthor()->getName())));
}
public function renderBody() {
return phutil_render_tag(
'div',
array(
'class' => 'phame-post-body',
),
$this->getBody());
}
public function renderComments() {
$post = $this->getPost();
switch ($post->getCommentsWidget()) {
case 'facebook':
$comments = $this->renderFacebookComments();
break;
case 'disqus':
$comments = $this->renderDisqusComments();
break;
case 'none':
default:
$comments = null;
break;
}
return $comments;
}
public function render() {
return phutil_render_tag(
'div',
array(
'class' => 'phame-post',
),
$this->renderTitle().
$this->renderDatePublished().
$this->renderBody().
$this->renderComments());
}
private function renderFacebookComments() {
$fb_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
if (!$fb_id) {
return null;
}
$fb_root = phutil_render_tag('div',
array(
'id' => 'fb-root',
),
''
);
$c_uri = '//connect.facebook.net/en_US/all.js#xfbml=1&appId='.$fb_id;
$fb_js = jsprintf(
'<script>(function(d, s, id) {'.
' var js, fjs = d.getElementsByTagName(s)[0];'.
' if (d.getElementById(id)) return;'.
' js = d.createElement(s); js.id = id;'.
' js.src = %s;'.
' fjs.parentNode.insertBefore(js, fjs);'.
'}(document, \'script\', \'facebook-jssdk\'));</script>',
$c_uri
);
$fb_comments = phutil_render_tag('div',
array(
'class' => 'fb-comments',
'data-href' => $this->getRequestURI(),
'data-num-posts' => 5,
'data-width' => 1080, // we hack this to fluid in css
'data-colorscheme' => 'dark',
),
''
);
return phutil_render_tag(
'div',
array(
'class' => 'phame-comments-facebook',
),
$fb_root.
$fb_js.
$fb_comments);
}
private function renderDisqusComments() {
$disqus_shortname = PhabricatorEnv::getEnvConfig('disqus.shortname');
if (!$disqus_shortname) {
return null;
}
$post = $this->getPost();
$disqus_thread = phutil_render_tag('div',
array(
'id' => 'disqus_thread'
)
);
// protip - try some var disqus_developer = 1; action to test locally
$disqus_js = jsprintf(
'<script>'.
' var disqus_shortname = "phabricator";'.
' var disqus_identifier = %s;'.
' var disqus_url = %s;'.
' var disqus_title = %s;'.
'(function() {'.
' var dsq = document.createElement("script");'.
' dsq.type = "text/javascript";'.
' dsq.async = true;'.
' dsq.src = "http://" + disqus_shortname + ".disqus.com/embed.js";'.
'(document.getElementsByTagName("head")[0] ||'.
' document.getElementsByTagName("body")[0]).appendChild(dsq);'.
'})(); </script>',
$post->getPHID(),
$this->getRequestURI(),
$post->getTitle()
);
return phutil_render_tag(
'div',
array(
'class' => 'phame-comments-disqus',
),
$disqus_thread.
$disqus_js);
}
}

View file

@ -1,200 +0,0 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group phame
*/
abstract class PhameBlogSkin extends AphrontView {
private $user;
private $blog;
private $bloggers;
private $posts;
private $actions;
private $notice;
private $showChrome;
private $deviceReady;
private $isExternalDomain;
private $requestURI;
private $showPostComments;
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function getUser() {
return $this->user;
}
public function setBlog(PhameBlog $blog) {
$this->blog = $blog;
return $this;
}
public function getBlog() {
return $this->blog;
}
public function setBloggers(array $bloggers) {
assert_instances_of($bloggers, 'PhabricatorObjectHandle');
$this->bloggers = $bloggers;
return $this;
}
public function getBloggers() {
return $this->bloggers;
}
public function setPosts(array $posts) {
assert_instances_of($posts, 'PhamePost');
$this->posts = $posts;
return $this;
}
protected function getPosts() {
return $this->posts;
}
public function setActions($actions) {
$this->actions = $actions;
return $this;
}
public function getActions() {
return $this->actions;
}
public function setNotice(array $notice) {
$this->notice = $notice;
return $this;
}
protected function getNotice() {
return $this->notice;
}
public function setIsExternalDomain($is_external_domain) {
$this->isExternalDomain = $is_external_domain;
return $this;
}
protected function getIsExternalDomain() {
return $this->isExternalDomain;
}
public function setRequestURI($request_uri) {
$this->requestURI = $request_uri;
return $this;
}
private function getRequestURI() {
return $this->requestURI;
}
protected function setShowChrome($show_chrome) {
$this->showChrome = $show_chrome;
return $this;
}
public function getShowChrome() {
return $this->showChrome;
}
protected function setDeviceReady($device_ready) {
$this->deviceReady = $device_ready;
return $this;
}
public function getDeviceReady() {
return $this->deviceReady;
}
public function setShowPostComments($show_post_comments) {
$this->showPostComments = $show_post_comments;
return $this;
}
public function getShowPostComments() {
return $this->showPostComments;
}
public function __construct() {
// set any options here
}
public function render() {
return
$this->renderHeader().
$this->renderBody().
$this->renderFooter();
}
abstract protected function renderHeader();
abstract protected function renderBody();
abstract protected function renderFooter();
final public function renderPosts() {
$list = id(new PhamePostListView())
->setUser($this->getUser())
->setPosts($this->getPosts())
->setBloggers($this->getBloggers())
->setRequestURI($this->getRequestURI())
->setShowPostComments($this->getShowPostComments())
->setDraftList(false);
return $list->render();
}
final protected function renderBlogDetails() {
$details = array();
$blog = $this->getBlog();
if ($blog) {
$detail = id(new PhameBlogDetailView())
->setUser($this->getUser())
->setBlog($this->getBlog())
->setBloggers($this->getBloggers());
$details[] = $detail->render();
}
// TODO - more cool boxes for the right hand column...!
return implode('', $details);
}
final protected function renderNotice() {
$notice_html = '';
if ($this->getIsExternalDomain()) {
return $notice_html;
}
$notice = $this->getNotice();
if ($notice) {
$header = $notice['title'];
$details = $notice['body'];
$notice_html = phutil_render_tag(
'div',
array(
'class' => 'notice'
),
phutil_render_tag(
'h3',
array(),
$header
).phutil_render_tag(
'h4',
array(),
$details
)
);
}
return $notice_html;
}
}

View file

@ -54,6 +54,10 @@ final class PhabricatorRemarkupRuleCountdown extends PhutilRemarkupRule {
$metadata_key = self::KEY_RULE_COUNTDOWN;
$metadata = $engine->getTextMetadata($metadata_key, array());
if (!$metadata) {
return;
}
require_celerity_resource('javelin-behavior-countdown-timer');
foreach ($metadata as $id => $info) {