1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-04-08 10:28:29 +02:00

Add concept of "skins" to phame, and add a phacility skin

Summary:
introduce an abstract "PhameBlogSkin" class and instantiate two versions -- PhabricatorBlogSkin (Default) and PhacilityBlogSkin.

Most notable hack is including the directory /rsrc/images/phacility - this lets things "work" without messing around with the phacility.com CSS and instead just cutting and pasting most of the file.

Test Plan: played around with Phame a bunch. In particular, created a blog with a custom domain and the phacility skin. Verified it looked good and individual posts looked okay.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T1373

Differential Revision: https://secure.phabricator.com/D3687
This commit is contained in:
Bob Trahan 2012-10-12 16:01:33 -07:00
parent 421d2d6a08
commit 8355f3592f
21 changed files with 886 additions and 315 deletions

View file

@ -462,6 +462,27 @@ celerity_register_resource_map(array(
'disk' => '/rsrc/image/nyan.gif', 'disk' => '/rsrc/image/nyan.gif',
'type' => 'gif', 'type' => 'gif',
), ),
'/rsrc/image/phacility/phacility_logo.jpg' =>
array(
'hash' => '88000de28b8741acc584b24560bd3d4f',
'uri' => '/res/88000de2/rsrc/image/phacility/phacility_logo.jpg',
'disk' => '/rsrc/image/phacility/phacility_logo.jpg',
'type' => 'jpg',
),
'/rsrc/image/phacility/sprites.png' =>
array(
'hash' => 'b018a070d120f689a2beb8ece67e1b1e',
'uri' => '/res/b018a070/rsrc/image/phacility/sprites.png',
'disk' => '/rsrc/image/phacility/sprites.png',
'type' => 'png',
),
'/rsrc/image/phacility/tactile_noise.png' =>
array(
'hash' => '7fb4ca90b8b0919153770b6badb982f0',
'uri' => '/res/7fb4ca90/rsrc/image/phacility/tactile_noise.png',
'disk' => '/rsrc/image/phacility/tactile_noise.png',
'type' => 'png',
),
'/rsrc/image/search.png' => '/rsrc/image/search.png' =>
array( array(
'hash' => 'ff7da044e6f923b8f569dec11f97e5e5', 'hash' => 'ff7da044e6f923b8f569dec11f97e5e5',
@ -2182,6 +2203,15 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/javelin/lib/Workflow.js', 'disk' => '/rsrc/js/javelin/lib/Workflow.js',
), ),
'jquery-js' =>
array(
'uri' => '/res/7f0dd213/rsrc/js/application/phame/skins/phacility/jquery/jquery.min.js',
'type' => 'js',
'requires' =>
array(
),
'disk' => '/rsrc/js/application/phame/skins/phacility/jquery/jquery.min.js',
),
'maniphest-batch-editor' => 'maniphest-batch-editor' =>
array( array(
'uri' => '/res/fb15d744/rsrc/css/application/maniphest/batch-editor.css', 'uri' => '/res/fb15d744/rsrc/css/application/maniphest/batch-editor.css',
@ -2888,23 +2918,43 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/uiexample/ReactorSendPropertiesExample.js', 'disk' => '/rsrc/js/application/uiexample/ReactorSendPropertiesExample.js',
), ),
'phame-blog-detail-css' => 'phacility-bootstrap-css' =>
array( array(
'uri' => '/res/5a0e24ab/rsrc/css/application/phame/blog-detail.css', 'uri' => '/res/28f0ad0e/rsrc/css/application/phame/skins/phacility/bootstrap/bootstrap.min.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
), ),
'disk' => '/rsrc/css/application/phame/blog-detail.css', 'disk' => '/rsrc/css/application/phame/skins/phacility/bootstrap/bootstrap.min.css',
), ),
'phame-blog-post-list-css' => 'phacility-css' =>
array( array(
'uri' => '/res/371237fa/rsrc/css/application/phame/blog-post-list.css', 'uri' => '/res/f55275c2/rsrc/css/application/phame/skins/phacility/phacility.css',
'type' => 'css',
'requires' =>
array(
0 => 'phacility-bootstrap-css',
),
'disk' => '/rsrc/css/application/phame/skins/phacility/phacility.css',
),
'phacility-js' =>
array(
'uri' => '/res/f441bc88/rsrc/js/application/phame/skins/phacility/bootstrap/bootstrap.min.js',
'type' => 'js',
'requires' =>
array(
0 => 'jquery-js',
),
'disk' => '/rsrc/js/application/phame/skins/phacility/bootstrap/bootstrap.min.js',
),
'phame-css' =>
array(
'uri' => '/res/2d18adca/rsrc/css/application/phame/phame.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
), ),
'disk' => '/rsrc/css/application/phame/blog-post-list.css', 'disk' => '/rsrc/css/application/phame/phame.css',
), ),
'phriction-document-css' => 'phriction-document-css' =>
array( array(

View file

@ -602,6 +602,7 @@ phutil_register_library_map(array(
'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php',
'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php',
'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php', 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php',
'PhabricatorBlogSkin' => 'applications/phame/view/skins/PhabricatorBlogSkin.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php', 'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php',
@ -1155,6 +1156,7 @@ phutil_register_library_map(array(
'PhameBlogListBaseController' => 'applications/phame/controller/blog/list/PhameBlogListBaseController.php', 'PhameBlogListBaseController' => 'applications/phame/controller/blog/list/PhameBlogListBaseController.php',
'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php', 'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php',
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
'PhameBlogSkin' => 'applications/phame/view/skins/PhameBlogSkin.php',
'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php',
'PhameBloggerPostListController' => 'applications/phame/controller/post/list/PhameBloggerPostListController.php', 'PhameBloggerPostListController' => 'applications/phame/controller/post/list/PhameBloggerPostListController.php',
'PhameController' => 'applications/phame/controller/PhameController.php', 'PhameController' => 'applications/phame/controller/PhameController.php',
@ -1784,6 +1786,7 @@ phutil_register_library_map(array(
'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler',
'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController',
'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation', 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation',
'PhabricatorBlogSkin' => 'PhameBlogSkin',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController', 'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
@ -2280,6 +2283,7 @@ phutil_register_library_map(array(
'PhameBlogListBaseController' => 'PhameController', 'PhameBlogListBaseController' => 'PhameController',
'PhameBlogListView' => 'AphrontView', 'PhameBlogListView' => 'AphrontView',
'PhameBlogQuery' => 'PhabricatorOffsetPagedQuery', 'PhameBlogQuery' => 'PhabricatorOffsetPagedQuery',
'PhameBlogSkin' => 'AphrontView',
'PhameBlogViewController' => 'PhameController', 'PhameBlogViewController' => 'PhameController',
'PhameBloggerPostListController' => 'PhamePostListBaseController', 'PhameBloggerPostListController' => 'PhamePostListBaseController',
'PhameController' => 'PhabricatorController', 'PhameController' => 'PhabricatorController',

View file

@ -153,13 +153,17 @@ abstract class AphrontApplicationConfiguration {
// 2 basic cases // 2 basic cases
// -- looking at a list of blog posts, path is nothing or '/' // -- looking at a list of blog posts, path is nothing or '/'
// -- looking at an actual blog post, path is like /btrahan/post_title // -- we have to fudge the URI in this case
// -- looking at an actual blog post, path is like
// /phame/posts/<author>/post_title
// NOTE: it is possible to get other phame pages, we just do
// not link to them at this time.
if (!$path || $path == '/') { if (!$path || $path == '/') {
$path = $blog->getViewURI(); $path = $blog->getViewURI();
} else {
$path = '/phame/posts/'.trim($path, '/').'/';
} }
PhameBlog::setRequestBlog($blog);
$celerity = CelerityAPI::getStaticResourceResponse(); $celerity = CelerityAPI::getStaticResourceResponse();
$celerity->setUseFullURI(true); $celerity->setUseFullURI(true);
} }

View file

@ -21,6 +21,8 @@
*/ */
abstract class PhameController extends PhabricatorController { abstract class PhameController extends PhabricatorController {
private $showSideNav; private $showSideNav;
private $showChrome = true;
private $deviceReady = false;
protected function setShowSideNav($value) { protected function setShowSideNav($value) {
$this->showSideNav = (bool) $value; $this->showSideNav = (bool) $value;
@ -30,6 +32,22 @@ abstract class PhameController extends PhabricatorController {
return $this->showSideNav; return $this->showSideNav;
} }
protected function setShowChrome($show_chrome) {
$this->showChrome = $show_chrome;
return $this;
}
private function getShowChrome() {
return $this->showChrome;
}
public function setDeviceReady($device_ready) {
$this->deviceReady = $device_ready;
return $this;
}
public function getDeviceReady() {
return $this->deviceReady;
}
public function buildStandardPageResponse($view, array $data) { public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView(); $page = $this->buildStandardPageView();
@ -38,6 +56,8 @@ abstract class PhameController extends PhabricatorController {
$page->setBaseURI('/phame/'); $page->setBaseURI('/phame/');
$page->setTitle(idx($data, 'title')); $page->setTitle(idx($data, 'title'));
$page->setGlyph("\xe2\x9c\xa9"); $page->setGlyph("\xe2\x9c\xa9");
$page->setShowChrome($this->getShowChrome());
$page->setDeviceReady($this->getDeviceReady());
if ($this->showSideNav()) { if ($this->showSideNav()) {
$nav = $this->renderSideNavFilterView($this->getSideNavFilter()); $nav = $this->renderSideNavFilterView($this->getSideNavFilter());

View file

@ -123,6 +123,7 @@ final class PhameBlogEditController
$description = $request->getStr('description'); $description = $request->getStr('description');
$blogger_arr = $request->getArr('bloggers'); $blogger_arr = $request->getArr('bloggers');
$custom_domain = $request->getStr('custom_domain'); $custom_domain = $request->getStr('custom_domain');
$skin = $request->getStr('skin');
if (empty($blogger_arr)) { if (empty($blogger_arr)) {
$error = 'Bloggers must be nonempty.'; $error = 'Bloggers must be nonempty.';
@ -155,6 +156,7 @@ final class PhameBlogEditController
} }
$blog->setDomain($custom_domain); $blog->setDomain($custom_domain);
} }
$blog->setSkin($skin);
if (empty($errors)) { if (empty($errors)) {
$blog->save(); $blog->save();
@ -231,6 +233,13 @@ final class PhameBlogEditController
'blog.example.com') 'blog.example.com')
->setError($e_custom_domain) ->setError($e_custom_domain)
) )
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Skin')
->setName('skin')
->setValue($blog->getSkin())
->setOptions(PhameBlog::getSkinOptionsForSelect())
)
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->addCancelButton('/phame/blog/') ->addCancelButton('/phame/blog/')

View file

@ -99,47 +99,38 @@ final class PhameBlogViewController
$posts = array(); $posts = array();
} }
$actions = array('view'); $notice = array();
$is_admin = false;
// TODO -- make this check use a policy
if (isset($bloggers[$user->getPHID()])) {
$actions[] = 'edit';
$is_admin = true;
}
if ($request->getExists('new')) { if ($request->getExists('new')) {
$notice = $this->buildNoticeView() $notice =
->setTitle('Successfully created your blog.') array(
->appendChild('Time to write some posts.'); 'title' => 'Successfully created your blog.',
'body' => 'Time to write some posts.'
);
} else if ($request->getExists('edit')) { } else if ($request->getExists('edit')) {
$notice = $this->buildNoticeView() $notice =
->setTitle('Successfully edited your blog.') array(
->appendChild('Time to write some posts.'); 'title' => 'Successfully edited your blog.',
} else { 'body' => 'Time to write some posts.'
$notice = null; );
} }
$panel = id(new PhamePostListView()) $skin = $blog->getSkinRenderer();
->setBlogStyle(true) $skin
->setUser($this->getRequest()->getUser()) ->setUser($this->getRequest()->getUser())
->setNotice($notice)
->setBloggers($bloggers) ->setBloggers($bloggers)
->setPosts($posts) ->setPosts($posts)
->setActions($actions)
->setDraftList(false);
$details = id(new PhameBlogDetailView())
->setUser($user)
->setBloggers($bloggers)
->setBlog($blog) ->setBlog($blog)
->setIsAdmin($is_admin); ->setRequestURI($this->getRequest()->getRequestURI());
$this->setShowSideNav(false); $this->setShowSideNav(false);
$this->setShowChrome($skin->getShowChrome());
$this->setDeviceReady($skin->getDeviceReady());
$skin->setIsExternalDomain($blog->getDomain() == $request->getHost());
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
array( array(
$notice, $skin
$details,
$panel,
), ),
array( array(
'title' => $blog->getName(), 'title' => $blog->getName(),

View file

@ -299,6 +299,7 @@ final class PhamePostEditController
</div> </div>
</div>'; </div>';
require_celerity_resource('phame-css');
Javelin::initBehavior( Javelin::initBehavior(
'phame-post-preview', 'phame-post-preview',
array( array(

View file

@ -39,9 +39,11 @@ extends PhameController {
->setPhameTitle($phame_title) ->setPhameTitle($phame_title)
->setDateModified(time()); ->setDateModified(time());
$blogger = PhabricatorObjectHandleData::loadOneHandle($user->getPHID());
$post_html = id(new PhamePostDetailView()) $post_html = id(new PhamePostDetailView())
->setUser($user) ->setUser($user)
->setBlogger($user) ->setBlogger($blogger)
->setPost($post) ->setPost($post)
->setIsPreview(true) ->setIsPreview(true)
->render(); ->render();

View file

@ -90,8 +90,9 @@ extends PhameController {
if ($post) { if ($post) {
$this->setPhameTitle($post->getPhameTitle()); $this->setPhameTitle($post->getPhameTitle());
$blogger = id(new PhabricatorUser())->loadOneWhere( $blogger = PhabricatorObjectHandleData::loadOneHandle(
'phid = %s', $post->getBloggerPHID()); $post->getBloggerPHID(),
$user);
if (!$blogger) { if (!$blogger) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -100,9 +101,15 @@ extends PhameController {
} else if ($this->getBloggerName() && $this->getPhameTitle()) { } else if ($this->getBloggerName() && $this->getPhameTitle()) {
$phame_title = $this->getPhameTitle(); $phame_title = $this->getPhameTitle();
$phame_title = PhabricatorSlug::normalize($phame_title); $phame_title = PhabricatorSlug::normalize($phame_title);
$blogger = id(new PhabricatorUser())->loadOneWhere( $blogger_user = id(new PhabricatorUser())->loadOneWhere(
'username = %s', 'username = %s',
$this->getBloggerName()); $this->getBloggerName());
if (!$blogger_user) {
return new Aphront404Response();
}
$blogger = PhabricatorObjectHandleData::loadOneHandle(
$blogger_user->getPHID(),
$user);
if (!$blogger) { if (!$blogger) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -128,12 +135,12 @@ extends PhameController {
} }
if ($post->isDraft()) { if ($post->isDraft()) {
$notice = $this->buildNoticeView() $notice = array(
->setTitle('You are previewing a draft.') 'title' => 'You are previewing a draft.',
->setErrors(array( 'body' => 'Only you can see this draft until you publish it. '.
'Only you can see this draft until you publish it.', 'If you chose a comment widget it will show up when '.
'If you chose a comment widget it will show up when you publish.', 'you publish.'
)); );
} else if ($request->getExists('saved')) { } else if ($request->getExists('saved')) {
$new_link = phutil_render_tag( $new_link = phutil_render_tag(
'a', 'a',
@ -143,24 +150,43 @@ extends PhameController {
), ),
'write another blog post' 'write another blog post'
); );
$notice = $this->buildNoticeView() $notice = array(
->appendChild('<p>Saved post successfully.</p>') 'title' => 'Saved post successfully.',
->appendChild('Seek even more phame and '.$new_link); 'body' => 'Seek even more phame and '.$new_link.'.'
);
} else { } else {
$notice = null; $notice = array();
} }
$page = id(new PhamePostDetailView()) $actions = array('more');
if ($post->getBloggerPHID() == $user->getPHID()) {
$actions[] = 'edit';
}
$blog = PhameBlog::getRequestBlog();
if ($blog) {
$skin = $blog->getSkinRenderer();
$skin->setBlog($blog);
$skin->setIsExternalDomain(true);
} else {
$skin = new PhabricatorBlogSkin();
}
$skin
->setUser($user) ->setUser($user)
->setRequestURI($request->getRequestURI()) ->setRequestURI($request->getRequestURI())
->setBlogger($blogger) ->setBloggers(array($blogger->getPHID() => $blogger))
->setPost($post); ->setPosts(array($post))
->setNotice($notice)
->setShowPostComments(true)
->setActions($actions);
$this->setShowSideNav(false); $this->setShowSideNav(false);
$this->setShowChrome($skin->getShowChrome());
$this->setDeviceReady($skin->getDeviceReady());
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
array( array(
$notice, $skin
$page,
), ),
array( array(
'title' => $post->getTitle(), 'title' => $post->getTitle(),

View file

@ -80,7 +80,7 @@ final class PhameAllPostListController
$query->withVisibility(PhamePost::VISIBILITY_PUBLISHED); $query->withVisibility(PhamePost::VISIBILITY_PUBLISHED);
$this->setPhamePostQuery($query); $this->setPhamePostQuery($query);
$this->setActions(array('view')); $this->setActions(array());
$page_title = 'All Posts'; $page_title = 'All Posts';
$this->setPageTitle($page_title); $this->setPageTitle($page_title);

View file

@ -71,9 +71,10 @@ abstract class PhamePostListBaseController
} }
protected function buildPostListPageResponse() { protected function buildPostListPageResponse() {
$pager = $this->getPager(); $request = $this->getRequest();
$query = $this->getPhamePostQuery(); $pager = $this->getPager();
$posts = $query->executeWithOffsetPager($pager); $query = $this->getPhamePostQuery();
$posts = $query->executeWithOffsetPager($pager);
$bloggers = $this->loadBloggersFromPosts($posts); $bloggers = $this->loadBloggersFromPosts($posts);
@ -82,6 +83,7 @@ abstract class PhamePostListBaseController
->setBloggers($bloggers) ->setBloggers($bloggers)
->setPosts($posts) ->setPosts($posts)
->setActions($this->getActions()) ->setActions($this->getActions())
->setRequestURI($request->getRequestURI())
->setDraftList($this->isDraft()); ->setDraftList($this->isDraft());
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(

View file

@ -21,6 +21,8 @@
*/ */
final class PhameBlog extends PhameDAO { final class PhameBlog extends PhameDAO {
const SKIN_DEFAULT = 'PhabricatorBlogSkin';
protected $id; protected $id;
protected $phid; protected $phid;
protected $name; protected $name;
@ -29,9 +31,13 @@ final class PhameBlog extends PhameDAO {
protected $configData; protected $configData;
protected $creatorPHID; protected $creatorPHID;
private $skin;
private $bloggerPHIDs; private $bloggerPHIDs;
private $bloggers; private $bloggers;
static private $requestBlog;
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,
@ -46,6 +52,12 @@ final class PhameBlog extends PhameDAO {
PhabricatorPHIDConstants::PHID_TYPE_BLOG); PhabricatorPHIDConstants::PHID_TYPE_BLOG);
} }
public function getSkinRenderer() {
$skin = $this->getSkin();
return new $skin();
}
/** /**
* Makes sure a given custom blog uri is properly configured in DNS * Makes sure a given custom blog uri is properly configured in DNS
* to point at this Phabricator instance. If there is an error in * to point at this Phabricator instance. If there is an error in
@ -142,6 +154,27 @@ final class PhameBlog extends PhameDAO {
return $this->bloggers; return $this->bloggers;
} }
public function getSkin() {
$config = coalesce($this->getConfigData(), array());
return idx($config, 'skin', self::SKIN_DEFAULT);
}
public function setSkin($skin) {
$config = coalesce($this->getConfigData(), array());
$config['skin'] = $skin;
return $this->setConfigData($config);
}
static public function getSkinOptionsForSelect() {
$classes = id(new PhutilSymbolLoader())
->setAncestorClass('PhameBlogSkin')
->setType('class')
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
return ipull($classes, 'name', 'name');
}
public function getPostListURI() { public function getPostListURI() {
return $this->getActionURI('posts'); return $this->getActionURI('posts');
} }
@ -165,4 +198,12 @@ final class PhameBlog extends PhameDAO {
private function getActionURI($action) { private function getActionURI($action) {
return '/phame/blog/'.$action.'/'.$this->getPHID().'/'; return '/phame/blog/'.$action.'/'.$this->getPHID().'/';
} }
public static function setRequestBlog(PhameBlog $blog) {
self::$requestBlog = $blog;
}
public static function getRequestBlog() {
return self::$requestBlog;
}
} }

View file

@ -22,19 +22,9 @@
final class PhameBlogDetailView extends AphrontView { final class PhameBlogDetailView extends AphrontView {
private $user; private $user;
private $isAdmin;
private $blog; private $blog;
private $bloggers; private $bloggers;
public function setIsAdmin($is_admin) {
$this->isAdmin = $is_admin;
return $this;
}
private function getIsAdmin() {
return $this->isAdmin;
}
public function setUser(PhabricatorUser $user) { public function setUser(PhabricatorUser $user) {
$this->user = $user; $this->user = $user;
return $this; return $this;
@ -60,38 +50,58 @@ final class PhameBlogDetailView extends AphrontView {
return $this->blog; return $this->blog;
} }
public function render() { public function render() {
require_celerity_resource('phabricator-remarkup-css'); require_celerity_resource('phabricator-remarkup-css');
require_celerity_resource('phame-blog-detail-css');
$user = $this->getUser(); $user = $this->getUser();
$blog = $this->getBlog(); $blog = $this->getBlog();
$bloggers = $this->getBloggers(); $bloggers = $this->getBloggers();
$name = phutil_escape_html($blog->getName()); $name = phutil_escape_html($blog->getName());
$description = phutil_escape_html($blog->getDescription()); $description = phutil_escape_html($blog->getDescription());
$bloggers_txt = implode(' &middot; ', mpull($bloggers, 'renderLink'));
$panel = id(new AphrontPanelView())
->addClass('blog-detail')
->setHeader($name)
->setCaption($description)
->setWidth(AphrontPanelView::WIDTH_FORM)
->appendChild('Current bloggers: '.$bloggers_txt);
if ($this->getIsAdmin()) { $detail = phutil_render_tag(
$panel->addButton( 'div',
array(
'class' => 'blog-detail'
),
phutil_render_tag(
'div',
array(
'class' => 'header',
),
phutil_render_tag( phutil_render_tag(
'a', 'h1',
array( array(),
'href' => $blog->getEditURI(), $name
'class' => 'button grey', )
), ).
'Edit Blog') phutil_render_tag(
); 'div',
array(
'class' => 'description'
),
$description
).
phutil_render_tag(
'div',
array(
'class' => 'bloggers'
),
'Current bloggers: '.$this->getBloggersHTML($bloggers)
)
);
} return $detail;
return $panel->render();
} }
private function getBloggersHTML(array $bloggers) {
assert_instances_of($bloggers, 'PhabricatorObjectHandle');
$arr = array();
foreach ($bloggers as $blogger) {
$arr[] = '<strong>'.phutil_escape_html($blogger->getName()).'</strong>';
}
return implode(' &middot; ', $arr);
}
} }

View file

@ -64,61 +64,37 @@ final class PhameBlogListView extends AphrontView {
return $panel->render(); return $panel->render();
} }
$table_data = array(); $view = new PhabricatorObjectItemListView();
foreach ($blogs as $blog) { foreach ($blogs as $blog) {
$view_link = phutil_render_tag(
'a',
array(
'href' => $blog->getViewURI(),
),
phutil_escape_html($blog->getName()));
$bloggers = $blog->getBloggers(); $bloggers = $blog->getBloggers();
if (isset($bloggers[$user->getPHID()])) {
$edit = phutil_render_tag(
'a',
array(
'class' => 'button small grey',
'href' => $blog->getEditURI(),
),
'Edit');
} else {
$edit = null;
}
$view = phutil_render_tag(
'a',
array(
'class' => 'button small grey',
'href' => $blog->getViewURI(),
),
'View');
$table_data[] =
array(
$view_link,
implode(', ', mpull($blog->getBloggers(), 'renderLink')),
$view,
$edit,
);
}
$table = new AphrontTableView($table_data); $item = id(new PhabricatorObjectItemView())
$table->setHeaders( ->setHeader($blog->getName())
array( ->setHref($blog->getViewURI())
'Name', ->addDetail(
'Bloggers', 'Bloggers',
'', implode(', ', mpull($bloggers, 'renderLink')))
'', ->addDetail(
)); 'Custom Domain',
$table->setColumnClasses( $blog->getDomain());
array(
null, if (isset($bloggers[$user->getPHID()])) {
null, $item->addAttribute(
'action', phutil_render_tag(
'action', 'a',
)); array(
'class' => 'button small grey',
'href' => $blog->getEditURI(),
),
'Edit'));
}
$view->addItem($item);
}
$panel->setCreateButton('Create a Blog', '/phame/blog/new/'); $panel->setCreateButton('Create a Blog', '/phame/blog/new/');
$panel->setHeader($this->getHeader()); $panel->setHeader($this->getHeader());
$panel->appendChild($table); $panel->appendChild($view);
return $panel->render(); return $panel->render();
} }

View file

@ -20,18 +20,23 @@
* @group phame * @group phame
*/ */
final class PhamePostDetailView extends AphrontView { final class PhamePostDetailView extends AphrontView {
private $post;
private $blogger;
private $requestURI;
private $user;
private $isPreview;
public function setIsPreview($is_preview) { private $user;
$this->isPreview = $is_preview; 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; return $this;
} }
private function isPreview() { public function getShouldShorten() {
return $this->isPreview; return $this->shouldShorten;
} }
public function setUser(PhabricatorUser $user) { public function setUser(PhabricatorUser $user) {
@ -42,6 +47,41 @@ final class PhamePostDetailView extends AphrontView {
return $this->user; 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) { public function setRequestURI(PhutilURI $uri) {
$uri = PhabricatorEnv::getProductionURI($uri->setQueryParams(array())); $uri = PhabricatorEnv::getProductionURI($uri->setQueryParams(array()));
$this->requestURI = $uri; $this->requestURI = $uri;
@ -51,45 +91,75 @@ final class PhamePostDetailView extends AphrontView {
return $this->requestURI; return $this->requestURI;
} }
public function setBlogger(PhabricatorUser $blogger) { public function setIsPreview($is_preview) {
$this->blogger = $blogger; $this->isPreview = $is_preview;
return $this; return $this;
} }
private function getBlogger() { private function isPreview() {
return $this->blogger; return $this->isPreview;
} }
public function setPost(PhamePost $post) { public function setShowComments($show_comments) {
$this->post = $post; $this->showComments = $show_comments;
return $this; return $this;
} }
private function getPost() { private function getShowComments() {
return $this->post; return $this->showComments;
} }
public function render() { public function render() {
require_celerity_resource('phabricator-remarkup-css'); require_celerity_resource('phabricator-remarkup-css');
require_celerity_resource('phame-css');
$user = $this->getUser(); $user = $this->getUser();
$blogger = $this->getBlogger(); $blogger = $this->getBlogger();
$post = $this->getPost(); $post = $this->getPost();
$engine = PhabricatorMarkupEngine::newPhameMarkupEngine(); $actions = $this->getActions();
$body = $engine->markupText($post->getBody()); $noun = $post->isDraft() ? 'Draft' : 'Post';
if ($post->isDraft()) { $buttons = array();
$uri = '/phame/draft/';
$label = 'Back to Your Drafts'; foreach ($actions as $action) {
} else { switch ($action) {
$uri = '/phame/posts/'.$blogger->getUsername().'/'; case 'view':
$label = 'More Posts by '.phutil_escape_html($blogger->getUsername()); $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)
);
} }
$button = phutil_render_tag(
'a',
array(
'href' => $uri,
'class' => 'grey button',
),
$label
);
$publish_date = $post->getDatePublished(); $publish_date = $post->getDatePublished();
if ($publish_date) { if ($publish_date) {
@ -101,55 +171,114 @@ final class PhamePostDetailView extends AphrontView {
phabricator_datetime($post->getDateModified(), phabricator_datetime($post->getDateModified(),
$user); $user);
} }
$caption .= ' by '.phutil_render_tag( $caption .= ' by <b>'.
'a', phutil_escape_html($blogger->getName()).'</b>.';
array(
'href' => new PhutilURI('/p/'.$blogger->getUsername().'/'),
),
phutil_escape_html($blogger->getUsername())
).'.';
if ($this->isPreview()) { $shortened = false;
$width = AphrontPanelView::WIDTH_FULL; $body_text = $post->getBody();
} else { if ($this->getShouldShorten()) {
$width = AphrontPanelView::WIDTH_WIDE; $body_length = phutil_utf8_strlen($body_text);
$body_text = phutil_utf8_shorten($body_text, 5000);
$shortened = $body_length > phutil_utf8_strlen($body_text);
} }
$panel = id(new AphrontPanelView()) $engine = PhabricatorMarkupEngine::newPhameMarkupEngine();
->setHeader(phutil_escape_html($post->getTitle())) $body = $engine->markupText($body_text);
->appendChild('<div class="phabricator-remarkup">'.$body.'</div>')
->setWidth($width) $comments = null;
->addButton($button) if ($this->getShowComments()) {
->setCaption($caption); switch ($post->getCommentsWidget()) {
if ($user->getPHID() == $post->getBloggerPHID()) { case 'facebook':
if ($post->isDraft()) { $comments = $this->renderFacebookComments();
$label = 'Edit Draft'; break;
} else { case 'disqus':
$label = 'Edit Post'; $comments = $this->renderDisqusComments();
break;
case 'none':
default:
$comments = null;
break;
} }
$button = phutil_render_tag(
'a',
array(
'href' => $post->getEditURI(),
'class' => 'grey button',
),
$label);
$panel->addButton($button);
} }
switch ($post->getCommentsWidget()) {
case 'facebook':
$comments = $this->renderFacebookComments();
break;
case 'disqus':
$comments = $this->renderDisqusComments();
break;
case 'none':
default:
$comments = null;
break;
}
$panel->appendChild($comments);
return $panel->render(); $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() { private function renderFacebookComments() {
@ -161,7 +290,8 @@ final class PhamePostDetailView extends AphrontView {
$fb_root = phutil_render_tag('div', $fb_root = phutil_render_tag('div',
array( array(
'id' => 'fb-root', 'id' => 'fb-root',
) ),
''
); );
$c_uri = '//connect.facebook.net/en_US/all.js#xfbml=1&appId='.$fb_id; $c_uri = '//connect.facebook.net/en_US/all.js#xfbml=1&appId='.$fb_id;
@ -181,9 +311,10 @@ final class PhamePostDetailView extends AphrontView {
'class' => 'fb-comments', 'class' => 'fb-comments',
'data-href' => $this->getRequestURI(), 'data-href' => $this->getRequestURI(),
'data-num-posts' => 5, 'data-num-posts' => 5,
'data-width' => 1080, 'data-width' => 1080, // we hack this to fluid in css
'data-colorscheme' => 'dark', 'data-colorscheme' => 'dark',
) ),
''
); );
return '<hr />' . $fb_root . $fb_js . $fb_comments; return '<hr />' . $fb_root . $fb_js . $fb_comments;

View file

@ -24,9 +24,26 @@ final class PhamePostListView extends AphrontView {
private $user; private $user;
private $posts; private $posts;
private $bloggers; private $bloggers;
private $actions; private $actions = array();
private $draftList; private $draftList;
private $blogStyle; 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) { public function setDraftList($draft_list) {
$this->draftList = $draft_list; $this->draftList = $draft_list;
@ -72,28 +89,14 @@ final class PhamePostListView extends AphrontView {
return $this; return $this;
} }
private function getActions() { private function getActions() {
if ($this->actions) { return $this->actions;
return $this->actions;
}
return array();
}
public function setBlogStyle($style) {
$this->blogStyle = $style;
return $this;
}
private function getBlogStyle() {
return $this->blogStyle;
} }
public function render() { public function render() {
$user = $this->getUser(); $user = $this->getUser();
$posts = $this->getPosts(); $posts = $this->getPosts();
$bloggers = $this->getBloggers(); $bloggers = $this->getBloggers();
$noun = $this->getPostNoun(); $noun = $this->getPostNoun();
// TODO -- change this from a boolean to a string
// this string will represent a more specific "style" below
$blog_style = $this->getBlogStyle();
if (empty($posts)) { if (empty($posts)) {
$panel = id(new AphrontPanelView()) $panel = id(new AphrontPanelView())
@ -103,10 +106,9 @@ final class PhamePostListView extends AphrontView {
sprintf('/phame/%s/new', strtolower($noun))); sprintf('/phame/%s/new', strtolower($noun)));
return $panel->render(); return $panel->render();
} }
require_celerity_resource('phabricator-remarkup-css'); require_celerity_resource('phabricator-remarkup-css');
if ($blog_style) { require_celerity_resource('phame-css');
require_celerity_resource('phame-blog-post-list-css');
}
$engine = PhabricatorMarkupEngine::newPhameMarkupEngine(); $engine = PhabricatorMarkupEngine::newPhameMarkupEngine();
$html = array(); $html = array();
@ -114,43 +116,23 @@ final class PhamePostListView extends AphrontView {
foreach ($posts as $post) { foreach ($posts as $post) {
$blogger_phid = $post->getBloggerPHID(); $blogger_phid = $post->getBloggerPHID();
$blogger = $bloggers[$blogger_phid]; $blogger = $bloggers[$blogger_phid];
$blogger_link = $blogger->renderLink(); $detail = id(new PhamePostDetailView())
$updated = phabricator_datetime($post->getDateModified(), ->setUser($user)
$user); ->setPost($post)
$body = $engine->markupText($post->getBody()); ->setBlogger($blogger)
$panel = id(new AphrontPanelView()) ->setActions($actions)
->setHeader(phutil_escape_html($post->getTitle())) ->setRequestURI($this->getRequestURI())
->setCaption('Last updated '.$updated.' by '.$blogger_link.'.') ->setShowComments($this->getShowPostComments());
->appendChild('<div class="phabricator-remarkup">'.$body.'</div>');
if ($blog_style) {
$panel->addClass('blog-post-list');
}
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;
default:
break;
}
$button = phutil_render_tag(
'a',
array(
'href' => $uri,
'class' => 'grey button',
),
$label);
$panel->addButton($button);
}
$html[] = $panel->render(); $html[] = $detail->render();
} }
return implode('', $html); return phutil_render_tag(
'div',
array(
'class' => 'blog-post-list'
),
implode('', $html)
);
} }
} }

View file

@ -0,0 +1,44 @@
<?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 PhabricatorBlogSkin extends PhameBlogSkin {
public function __construct() {
$this->setShowChrome(true);
}
protected function renderHeader() {
return '';
}
protected function renderFooter() {
return '';
}
protected function renderBody() {
require_celerity_resource('phame-css');
return
$this->renderNotice() .
$this->renderPosts() .
$this->renderBlogDetails();
}
}

View file

@ -0,0 +1,200 @@
<?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

@ -1,18 +0,0 @@
/**
* @provides phame-blog-detail-css
*/
.blog-detail {
clear: right;
float: right;
width: 20%;
margin: 16px 16px 16px 0px;
padding: 12px 8px 12px 8px;
}
.device-tablet .blog-detail,
.device-phone .blog-detail {
float: none;
margin: 16px auto;
width: 90%;
}

View file

@ -1,18 +0,0 @@
/**
* @provides phame-blog-post-list-css
*/
.blog-post-list {
clear: left;
float: left;
width: 70%;
margin: 16px 0px 16px 16px;
padding: 12px 8px 12px 8px;
}
.device-tablet .blog-post-list,
.device-phone .blog-post-list {
float: none;
width: 90%;
margin: 16px auto;
}

View file

@ -0,0 +1,114 @@
/**
* @provides phame-css
*/
.notice {
background: #F3F3FF;
border: 1px solid #008;
margin: 16px 16px 4px 26px;
}
.notice h3 {
background: #E3E3FF;
padding: 8px;
}
.notice h4 {
font-weight: normal;
padding: 8px;
}
.phame-post-preview-header {
margin: 0px 0px 16px 0px;
}
.blog-post-list {
clear: left;
float: left;
width: 70%;
margin: 16px 0px 16px 16px;
padding: 0px 8px 12px 8px;
}
.device-tablet .blog-post-list,
.device-phone .blog-post-list {
float: none;
width: 90%;
margin: 16px auto;
}
.blog-post-list-full {
clear: left;
float: left;
margin: 16px 0px 0px 0px;
padding: 0px 16px 0px 16px;
}
.device-tablet .blog-post-list-full,
.device-phone .blog-post-list-full {
float: none;
margin: 16px auto;
}
.blog-detail {
float: right;
clear: right;
width: 20%;
margin: 16px 16px 16px 0px;
}
.device-tablet .blog-detail,
.device-phone .blog-detail {
float: none;
margin: 16px auto;
width: 90%;
}
.blog-detail .description {
margin: 16px 0px 16px 0px;
}
.blog-detail .bloggers {
font-size: 11px;
}
.blog-post,
.blog-detail {
border: 1px solid #DBDBDB;
background: #F9F9F9;
padding: 20px;
}
.blog-post {
margin: 0px 0px 20px 0px;
}
.blog-post .header {
padding: 0px 0px 16px 0px;
}
.blog-post .header h1 {
clear: none;
}
.blog-post .header .last-updated {
color: #666;
clear: none;
font-size: 11px;
}
.blog-post .header .buttons {
float: right;
}
.blog-post .header .buttons a {
margin: 0px 0px 0px 12px;
}
.more-and-comments {
padding: 12px 0px 12px 0px;
}
.fb-comments,
.fb-comments span,
.fb-comments iframe[style] {
width: 100% !important;
}