public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); $book_name = $request->getURIData('book'); $atom_type = $request->getURIData('type'); $atom_name = $request->getURIData('name'); $atom_context = nonempty($request->getURIData('context'), null); $atom_index = nonempty($request->getURIData('index'), null); require_celerity_resource('diviner-shared-css'); $book = id(new DivinerBookQuery())->setViewer($viewer)->withNames(array($book_name))->executeOne(); if (!$book) { return new Aphront404Response(); } $symbol = id(new DivinerAtomQuery())->setViewer($viewer)->withBookPHIDs(array($book->getPHID()))->withTypes(array($atom_type))->withNames(array($atom_name))->withContexts(array($atom_context))->withIndexes(array($atom_index))->withIsDocumentable(true)->needAtoms(true)->needExtends(true)->needChildren(true)->executeOne(); if (!$symbol) { return new Aphront404Response(); } $atom = $symbol->getAtom(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumbs->addTextCrumb($book->getShortTitle(), '/book/' . $book->getName() . '/'); $atom_short_title = $atom ? $atom->getDocblockMetaValue('short', $symbol->getTitle()) : $symbol->getTitle(); $crumbs->addTextCrumb($atom_short_title); $header = id(new PHUIHeaderView())->setHeader($this->renderFullSignature($symbol)); $properties = new PHUIPropertyListView(); $group = $atom ? $atom->getProperty('group') : $symbol->getGroupName(); if ($group) { $group_name = $book->getGroupName($group); } else { $group_name = null; } $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); $document = id(new PHUIDocumentViewPro())->setBook($book->getTitle(), $group_name)->setHeader($header)->addClass('diviner-view'); if ($atom) { $this->buildDefined($properties, $symbol); $this->buildExtendsAndImplements($properties, $symbol); $this->buildRepository($properties, $symbol); $warnings = $atom->getWarnings(); if ($warnings) { $warnings = id(new PHUIInfoView())->setErrors($warnings)->setTitle(pht('Documentation Warnings'))->setSeverity(PHUIInfoView::SEVERITY_WARNING); } $document->appendChild($warnings); } $methods = $this->composeMethods($symbol); $field = 'default'; $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer)->addObject($symbol, $field); foreach ($methods as $method) { foreach ($method['atoms'] as $matom) { $engine->addObject($matom, $field); } } $engine->process(); if ($atom) { $content = $this->renderDocumentationText($symbol, $engine); $document->appendChild($content); } $toc = $engine->getEngineMetadata($symbol, $field, PhutilRemarkupHeaderBlockRule::KEY_HEADER_TOC, array()); if (!$atom) { $document->appendChild(id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->appendChild(pht('This atom no longer exists.'))); } if ($atom) { $document->appendChild($this->buildParametersAndReturn(array($symbol))); } if ($methods) { $tasks = $this->composeTasks($symbol); if ($tasks) { $methods_by_task = igroup($methods, 'task'); // Add phantom tasks for methods which have a "@task" name that isn't // documented anywhere, or methods that have no "@task" name. foreach ($methods_by_task as $task => $ignored) { if (empty($tasks[$task])) { $tasks[$task] = array('name' => $task, 'title' => $task ? $task : pht('Other Methods'), 'defined' => $symbol); } } $section = id(new DivinerSectionView())->setHeader(pht('Tasks')); foreach ($tasks as $spec) { $section->addContent(id(new PHUIHeaderView())->setNoBackground(true)->setHeader($spec['title'])); $task_methods = idx($methods_by_task, $spec['name'], array()); $box_content = array(); if ($task_methods) { $list_items = array(); foreach ($task_methods as $task_method) { $atom = last($task_method['atoms']); $item = $this->renderFullSignature($atom, true); if (strlen($atom->getSummary())) { $item = array($item, " — ", $atom->getSummary()); } $list_items[] = phutil_tag('li', array(), $item); } $box_content[] = phutil_tag('ul', array('class' => 'diviner-list'), $list_items); } else { $no_methods = pht('No methods for this task.'); $box_content = phutil_tag('em', array(), $no_methods); } $inner_box = phutil_tag_div('diviner-task-items', $box_content); $section->addContent($inner_box); } $document->appendChild($section); } $section = id(new DivinerSectionView())->setHeader(pht('Methods')); foreach ($methods as $spec) { $matom = last($spec['atoms']); $method_header = id(new PHUIHeaderView())->setNoBackground(true); $inherited = $spec['inherited']; if ($inherited) { $method_header->addTag(id(new PHUITagView())->setType(PHUITagView::TYPE_STATE)->setBackgroundColor(PHUITagView::COLOR_GREY)->setName(pht('Inherited'))); } $method_header->setHeader($this->renderFullSignature($matom)); $section->addContent(array($method_header, $this->renderMethodDocumentationText($symbol, $spec, $engine), $this->buildParametersAndReturn($spec['atoms']))); } $document->appendChild($section); } if ($toc) { $side = new PHUIListView(); $side->addMenuItem(id(new PHUIListItemView())->setName(pht('Contents'))->setType(PHUIListItemView::TYPE_LABEL)); foreach ($toc as $key => $entry) { $side->addMenuItem(id(new PHUIListItemView())->setName($entry[1])->setHref('#' . $key)); } $document->setToc($side); } $prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list); return $this->newPage()->setTitle($symbol->getTitle())->setCrumbs($crumbs)->appendChild(array($document, $prop_list)); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); $document = id(new LegalpadDocumentQuery())->setViewer($viewer)->withIDs(array($request->getURIData('id')))->needDocumentBodies(true)->executeOne(); if (!$document) { return new Aphront404Response(); } $information = $this->readSignerInformation($document, $request); if ($information instanceof AphrontResponse) { return $information; } list($signer_phid, $signature_data) = $information; $signature = null; $type_individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL; $is_individual = $document->getSignatureType() == $type_individual; switch ($document->getSignatureType()) { case LegalpadDocument::SIGNATURE_TYPE_NONE: // nothing to sign means this should be true $has_signed = true; // this is a status UI element $signed_status = null; break; case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL: if ($signer_phid) { // TODO: This is odd and should probably be adjusted after // grey/external accounts work better, but use the omnipotent // viewer to check for a signature so we can pick up // anonymous/grey signatures. $signature = id(new LegalpadDocumentSignatureQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withDocumentPHIDs(array($document->getPHID()))->withSignerPHIDs(array($signer_phid))->executeOne(); if ($signature && !$viewer->isLoggedIn()) { return $this->newDialog()->setTitle(pht('Already Signed'))->appendParagraph(pht('You have already signed this document!'))->addCancelButton('/' . $document->getMonogram(), pht('Okay')); } } $signed_status = null; if (!$signature) { $has_signed = false; $signature = id(new LegalpadDocumentSignature())->setSignerPHID($signer_phid)->setDocumentPHID($document->getPHID())->setDocumentVersion($document->getVersions()); // If the user is logged in, show a notice that they haven't signed. // If they aren't logged in, we can't be as sure, so don't show // anything. if ($viewer->isLoggedIn()) { $signed_status = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors(array(pht('You have not signed this document yet.'))); } } else { $has_signed = true; $signature_data = $signature->getSignatureData(); // In this case, we know they've signed. $signed_at = $signature->getDateCreated(); if ($signature->getIsExemption()) { $exemption_phid = $signature->getExemptionPHID(); $handles = $this->loadViewerHandles(array($exemption_phid)); $exemption_handle = $handles[$exemption_phid]; $signed_text = pht('You do not need to sign this document. ' . '%s added a signature exemption for you on %s.', $exemption_handle->renderLink(), phabricator_datetime($signed_at, $viewer)); } else { $signed_text = pht('You signed this document on %s.', phabricator_datetime($signed_at, $viewer)); } $signed_status = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->setErrors(array($signed_text)); } $field_errors = array('name' => true, 'email' => true, 'agree' => true); $signature->setSignatureData($signature_data); break; case LegalpadDocument::SIGNATURE_TYPE_CORPORATION: $signature = id(new LegalpadDocumentSignature())->setDocumentPHID($document->getPHID())->setDocumentVersion($document->getVersions()); if ($viewer->isLoggedIn()) { $has_signed = false; $signed_status = null; } else { // This just hides the form. $has_signed = true; $login_text = pht('This document requires a corporate signatory. You must log in to ' . 'accept this document on behalf of a company you represent.'); $signed_status = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors(array($login_text)); } $field_errors = array('name' => true, 'address' => true, 'contact.name' => true, 'email' => true); $signature->setSignatureData($signature_data); break; } $errors = array(); if ($request->isFormOrHisecPost() && !$has_signed) { // Require two-factor auth to sign legal documents. if ($viewer->isLoggedIn()) { $engine = new PhabricatorAuthSessionEngine(); $engine->requireHighSecuritySession($viewer, $request, '/' . $document->getMonogram()); } list($form_data, $errors, $field_errors) = $this->readSignatureForm($document, $request); $signature_data = $form_data + $signature_data; $signature->setSignatureData($signature_data); $signature->setSignatureType($document->getSignatureType()); $signature->setSignerName((string) idx($signature_data, 'name')); $signature->setSignerEmail((string) idx($signature_data, 'email')); $agree = $request->getExists('agree'); if (!$agree) { $errors[] = pht('You must check "I agree to the terms laid forth above."'); $field_errors['agree'] = pht('Required'); } if ($viewer->isLoggedIn() && $is_individual) { $verified = LegalpadDocumentSignature::VERIFIED; } else { $verified = LegalpadDocumentSignature::UNVERIFIED; } $signature->setVerified($verified); if (!$errors) { $signature->save(); // If the viewer is logged in, signing for themselves, send them to // the document page, which will show that they have signed the // document. Unless of course they were required to sign the // document to use Phabricator; in that case try really hard to // re-direct them to where they wanted to go. // // Otherwise, send them to a completion page. if ($viewer->isLoggedIn() && $is_individual) { $next_uri = '/' . $document->getMonogram(); if ($document->getRequireSignature()) { $request_uri = $request->getRequestURI(); $next_uri = (string) $request_uri; } } else { $this->sendVerifySignatureEmail($document, $signature); $next_uri = $this->getApplicationURI('done/'); } return id(new AphrontRedirectResponse())->setURI($next_uri); } } $document_body = $document->getDocumentBody(); $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer); $engine->addObject($document_body, LegalpadDocumentBody::MARKUP_FIELD_TEXT); $engine->process(); $document_markup = $engine->getOutput($document_body, LegalpadDocumentBody::MARKUP_FIELD_TEXT); $title = $document_body->getTitle(); $manage_uri = $this->getApplicationURI('view/' . $document->getID() . '/'); $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $document, PhabricatorPolicyCapability::CAN_EDIT); // Use the last content update as the modified date. We don't want to // show that a document like a TOS was "updated" by an incidental change // to a field like the preamble or privacy settings which does not acutally // affect the content of the agreement. $content_updated = $document_body->getDateCreated(); // NOTE: We're avoiding `setPolicyObject()` here so we don't pick up // extra UI elements that are unnecessary and clutter the signature page. // These details are available on the "Manage" page. $header = id(new PHUIHeaderView())->setHeader($title)->setUser($viewer)->setEpoch($content_updated)->addActionLink(id(new PHUIButtonView())->setTag('a')->setIcon(id(new PHUIIconView())->setIconFont('fa-pencil'))->setText(pht('Manage'))->setHref($manage_uri)->setDisabled(!$can_edit)->setWorkflow(!$can_edit)); $preamble_box = null; if (strlen($document->getPreamble())) { $preamble_text = PhabricatorMarkupEngine::renderOneObject(id(new PhabricatorMarkupOneOff())->setContent($document->getPreamble()), 'default', $viewer); // NOTE: We're avoiding `setObject()` here so we don't pick up extra UI // elements like "Subscribers". This information is available on the // "Manage" page, but just clutters up the "Signature" page. $preamble = id(new PHUIPropertyListView())->setUser($viewer)->addSectionHeader(pht('Preamble'))->addTextContent($preamble_text); $preamble_box = new PHUIPropertyGroupView(); $preamble_box->addPropertyList($preamble); } $content = id(new PHUIDocumentViewPro())->addClass('legalpad')->setHeader($header)->appendChild(array($signed_status, $preamble_box, $document_markup)); $signature_box = null; if (!$has_signed) { $error_view = null; if ($errors) { $error_view = id(new PHUIInfoView())->setErrors($errors); } $signature_form = $this->buildSignatureForm($document, $signature, $field_errors); switch ($document->getSignatureType()) { default: break; case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL: case LegalpadDocument::SIGNATURE_TYPE_CORPORATION: $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Agree and Sign Document'))->setForm($signature_form); if ($error_view) { $box->setInfoView($error_view); } $signature_box = phutil_tag_div('phui-document-view-pro-box', $box); break; } } $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumbs->addTextCrumb($document->getMonogram()); return $this->buildApplicationPage(array($crumbs, $content, $signature_box), array('title' => $title, 'pageObjects' => array($document->getPHID()))); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. return id(new AphrontRedirectResponse())->setURI($uri); } require_celerity_resource('phriction-document-css'); $document = id(new PhrictionDocumentQuery())->setViewer($user)->withSlugs(array($slug))->executeOne(); $version_note = null; $core_content = ''; $move_notice = ''; $properties = null; if (!$document) { $document = new PhrictionDocument(); if (PhrictionDocument::isProjectSlug($slug)) { $project = id(new PhabricatorProjectQuery())->setViewer($user)->withPhrictionSlugs(array(PhrictionDocument::getProjectSlugIdentifier($slug)))->executeOne(); if (!$project) { return new Aphront404Response(); } } $create_uri = '/phriction/edit/?slug=' . $slug; $notice = new AphrontErrorView(); $notice->setSeverity(AphrontErrorView::SEVERITY_NODATA); $notice->setTitle(pht('No content here!')); $notice->appendChild(pht('No document found at %s. You can <strong>' . '<a href="%s">create a new document here</a></strong>.', phutil_tag('tt', array(), $slug), $create_uri)); $core_content = $notice; $page_title = pht('Page Not Found'); } else { $version = $request->getInt('v'); if ($version) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $version); if (!$content) { return new Aphront404Response(); } if ($content->getID() != $document->getContentID()) { $vdate = phabricator_datetime($content->getDateCreated(), $user); $version_note = new AphrontErrorView(); $version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $version_note->appendChild(pht('You are viewing an older version of this document, as it ' . 'appeared on %s.', $vdate)); } } else { $content = id(new PhrictionContent())->load($document->getContentID()); } $page_title = $content->getTitle(); $properties = $this->buildPropertyListView($document, $content, $slug); $doc_status = $document->getStatus(); $current_status = $content->getChangeType(); if ($current_status == PhrictionChangeType::CHANGE_EDIT || $current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $core_content = $content->renderContent($user); } else { if ($current_status == PhrictionChangeType::CHANGE_DELETE) { $notice = new AphrontErrorView(); $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $notice->setTitle(pht('Document Deleted')); $notice->appendChild(pht('This document has been deleted. You can edit it to put new ' . 'content here, or use history to revert to an earlier version.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_STUB) { $notice = new AphrontErrorView(); $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $notice->setTitle(pht('Empty Document')); $notice->appendChild(pht('This document is empty. You can edit it to put some proper ' . 'content here.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) { $new_doc_id = $content->getChangeRef(); $slug_uri = null; // If the new document exists and the viewer can see it, provide a link // to it. Otherwise, render a generic message. $new_docs = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($new_doc_id))->execute(); if ($new_docs) { $new_doc = head($new_docs); $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); } $notice = id(new AphrontErrorView())->setSeverity(AphrontErrorView::SEVERITY_NOTICE); if ($slug_uri) { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved to %s. You can edit it to put ' . 'new content here, or use history to revert to an earlier ' . 'version.', phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); } else { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved. You can edit it to put new ' . 'contne here, or use history to revert to an earlier ' . 'version.'))); } $core_content = $notice->render(); } else { throw new Exception("Unknown document status '{$doc_status}'!"); } } } } $move_notice = null; if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $from_doc_id = $content->getChangeRef(); $slug_uri = null; // If the old document exists and is visible, provide a link to it. $from_docs = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($from_doc_id))->execute(); if ($from_docs) { $from_doc = head($from_docs); $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); } $move_notice = id(new AphrontErrorView())->setSeverity(AphrontErrorView::SEVERITY_NOTICE); if ($slug_uri) { $move_notice->appendChild(pht('This document was moved from %s.', phutil_tag('a', array('href' => $slug_uri), $slug_uri))); } else { // Render this for consistency, even though it's a bit silly. $move_notice->appendChild(pht('This document was moved from elsewhere.')); } } } $children = $this->renderDocumentChildren($slug); $actions = $this->buildActionView($user, $document); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setActionList($actions); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } $header = id(new PHUIHeaderView())->setHeader($page_title); $prop_list = null; if ($properties) { $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); } $page_content = id(new PHUIDocumentView())->setOffset(true)->setFontKit(PHUIDocumentView::FONT_SOURCE_SANS)->setHeader($header)->appendChild(array($actions, $prop_list, $version_note, $move_notice, $core_content)); $core_page = phutil_tag('div', array('class' => 'phriction-offset'), array($page_content, $children)); return $this->buildApplicationPage(array($crumbs->render(), $core_page), array('pageObjects' => array($document->getPHID()), 'title' => $page_title)); }
public function render() { require_celerity_resource('phui-object-box-css', 'sprint'); $header = $this->header; if ($this->headerText) { $header = id(new PHUIHeaderView())->setHeader($this->headerText); } $showhide = null; if ($this->showAction !== null) { if (!$header) { $header = id(new PHUIHeaderView()); } Javelin::initBehavior('phabricator-reveal-content'); $hide_action_id = celerity_generate_unique_node_id(); $show_action_id = celerity_generate_unique_node_id(); $content_id = celerity_generate_unique_node_id(); $hide_style = $this->showHideOpen ? 'display: none;' : null; $show_style = $this->showHideOpen ? null : 'display: none;'; $hide_action = id(new PHUIButtonView())->setTag('a')->addSigil('reveal-content')->setID($hide_action_id)->setStyle($hide_style)->setHref($this->showHideHref)->setMetaData(array('hideIDs' => array($hide_action_id), 'showIDs' => array($content_id, $show_action_id)))->setText($this->showAction); $show_action = id(new PHUIButtonView())->setTag('a')->addSigil('reveal-content')->setStyle($show_style)->setHref('#')->setID($show_action_id)->setMetaData(array('hideIDs' => array($content_id, $show_action_id), 'showIDs' => array($hide_action_id)))->setText($this->hideAction); $header->addActionLink($hide_action); $header->addActionLink($show_action); $showhide = array(phutil_tag('div', array('class' => 'phui-object-box-hidden-content', 'id' => $content_id, 'style' => $show_style), $this->showHideContent)); } if ($this->actionListID) { $icon_id = celerity_generate_unique_node_id(); $icon = id(new PHUIIconView())->setIcon('fa-bars'); $meta = array('map' => array($this->actionListID => 'phabricator-action-list-toggle', $icon_id => 'phuix-dropdown-open')); $mobile_menu = id(new PHUIButtonView())->setTag('a')->setText(pht('Actions'))->setHref('#')->setIcon($icon)->addClass('phui-mobile-menu')->setID($icon_id)->addSigil('jx-toggle-class')->setMetadata($meta); $header->addActionLink($mobile_menu); } $ex = $this->validationException; $exception_errors = null; if ($ex) { $messages = array(); foreach ($ex->getErrors() as $error) { $messages[] = $error->getMessage(); } if ($messages) { $exception_errors = id(new PHUIInfoView())->setErrors($messages); } } $tab_lists = array(); $property_lists = array(); $tab_map = array(); $default_key = 'tab.default'; // Find the selected tab, or select the first tab if none are selected. if ($this->tabs) { $selected_tab = null; foreach ($this->tabs as $key => $tab) { if ($tab->getSelected()) { $selected_tab = $key; break; } } if ($selected_tab === null) { head($this->tabs)->setSelected(true); $selected_tab = head_key($this->tabs); } } foreach ($this->propertyLists as $key => $list) { $group = new PHUIPropertyGroupView(); $i = 0; foreach ($list as $item) { $group->addPropertyList($item); if ($i > 0) { $item->addClass('phui-property-list-section-noninitial'); } $i++; } if ($this->tabs && $key != $default_key) { $tab_id = celerity_generate_unique_node_id(); $tab_map[$key] = $tab_id; if ($key === $selected_tab) { $style = null; } else { $style = 'display: none'; } $tab_lists[] = phutil_tag('div', array('style' => $style, 'id' => $tab_id), $group); } else { if ($this->tabs) { $group->addClass('phui-property-group-noninitial'); } $property_lists[] = $group; } } $tabs = null; if ($this->tabs) { $tabs = id(new PHUIListView())->setType(PHUIListView::NAVBAR_LIST); foreach ($this->tabs as $tab) { $tabs->addMenuItem($tab); } Javelin::initBehavior('phui-object-box-tabs'); } $content = id(new PHUIBoxView())->appendChild(array($this->showHideOpen == false ? $this->anchor : null, $header, $this->infoView, $this->formErrors, $this->formSaved, $exception_errors, $this->form, $tabs, $tab_lists, $showhide, $this->showHideOpen == true ? $this->anchor : null, $property_lists, $this->table, $this->renderChildren()))->setBorder(true)->setID($this->id)->addMargin(PHUI::MARGIN_LARGE_TOP)->addMargin(PHUI::MARGIN_LARGE_LEFT)->addMargin(PHUI::MARGIN_LARGE_RIGHT)->addClass('sprintui-object-box'); if ($this->color) { $content->addClass('phui-object-box-' . $this->color); } if ($this->collapsed) { $content->addClass('phui-object-box-collapsed'); } if ($this->tabs) { $content->addSigil('phui-object-box'); $content->setMetadata(array('tabMap' => $tab_map)); } if ($this->flush) { $content->addClass('phui-object-box-flush'); } foreach ($this->sigils as $sigil) { $content->addSigil($sigil); } if ($this->metadata !== null) { $content->setMetadata($this->metadata); } if ($this->objectList) { $content->appendChild($this->objectList); } return $content; }
public function render() { require_celerity_resource('phui-object-box-css'); if ($this->headerColor) { $header_color = $this->headerColor; } else { $header_color = PHUIActionHeaderView::HEADER_LIGHTBLUE; } if ($this->header) { $header = $this->header; $header->setHeaderColor($header_color); } else { $header = id(new PHUIHeaderView())->setHeader($this->headerText)->setHeaderColor($header_color); } $ex = $this->validationException; $exception_errors = null; if ($ex) { $messages = array(); foreach ($ex->getErrors() as $error) { $messages[] = $error->getMessage(); } if ($messages) { $exception_errors = id(new AphrontErrorView())->setErrors($messages); } } $tab_lists = array(); $property_lists = array(); $tab_map = array(); $default_key = 'tab.default'; // Find the selected tab, or select the first tab if none are selected. if ($this->tabs) { $selected_tab = null; foreach ($this->tabs as $key => $tab) { if ($tab->getSelected()) { $selected_tab = $key; break; } } if ($selected_tab === null) { head($this->tabs)->setSelected(true); $selected_tab = head_key($this->tabs); } } foreach ($this->propertyLists as $key => $list) { $group = new PHUIPropertyGroupView(); $i = 0; foreach ($list as $item) { $group->addPropertyList($item); if ($i > 0) { $item->addClass('phui-property-list-section-noninitial'); } $i++; } if ($this->tabs && $key != $default_key) { $tab_id = celerity_generate_unique_node_id(); $tab_map[$key] = $tab_id; if ($key === $selected_tab) { $style = null; } else { $style = 'display: none'; } $tab_lists[] = phutil_tag('div', array('style' => $style, 'id' => $tab_id), $group); } else { if ($this->tabs) { $group->addClass('phui-property-group-noninitial'); } $property_lists[] = $group; } } $tabs = null; if ($this->tabs) { $tabs = id(new PHUIListView())->setType(PHUIListView::NAVBAR_LIST); foreach ($this->tabs as $tab) { $tabs->addMenuItem($tab); } Javelin::initBehavior('phui-object-box-tabs'); } $content = id(new PHUIBoxView())->appendChild(array($header, $this->errorView, $this->formErrors, $this->formSaved, $exception_errors, $this->form, $tabs, $tab_lists, $property_lists, $this->renderChildren()))->setBorder(true)->setID($this->id)->addMargin(PHUI::MARGIN_LARGE_TOP)->addMargin(PHUI::MARGIN_LARGE_LEFT)->addMargin(PHUI::MARGIN_LARGE_RIGHT)->addClass('phui-object-box'); if ($this->tabs) { $content->addSigil('phui-object-box'); $content->setMetadata(array('tabMap' => $tab_map)); } if ($this->flush) { $content->addClass('phui-object-box-flush'); } $content->addClass('phui-object-box-' . $header_color); foreach ($this->sigils as $sigil) { $content->addSigil($sigil); } if ($this->metadata !== null) { $content->setMetadata($this->metadata); } return $content; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $this->slug = $request->getURIData('slug'); $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. return id(new AphrontRedirectResponse())->setURI($uri); } require_celerity_resource('phriction-document-css'); $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withSlugs(array($slug))->executeOne(); $version_note = null; $core_content = ''; $move_notice = ''; $properties = null; $content = null; $toc = null; if (!$document) { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); if ($slug == '/') { $title = pht('Welcome to Phriction'); $subtitle = pht('Phriction is a simple and easy to use wiki for ' . 'keeping track of documents and their changes.'); $page_title = pht('Welcome'); $create_text = pht('Edit this Document'); } else { $title = pht('No Document Here'); $subtitle = pht('There is no document here, but you may create it.'); $page_title = pht('Page Not Found'); $create_text = pht('Create this Document'); } $create_uri = '/phriction/edit/?slug=' . $slug; $create_button = id(new PHUIButtonView())->setTag('a')->setText($create_text)->setHref($create_uri)->setColor(PHUIButtonView::GREEN); $core_content = id(new PHUIBigInfoView())->setIcon('fa-book')->setTitle($title)->setDescription($subtitle)->addAction($create_button); } else { $version = $request->getInt('v'); if ($version) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $version); if (!$content) { return new Aphront404Response(); } if ($content->getID() != $document->getContentID()) { $vdate = phabricator_datetime($content->getDateCreated(), $viewer); $version_note = new PHUIInfoView(); $version_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $version_note->appendChild(pht('You are viewing an older version of this document, as it ' . 'appeared on %s.', $vdate)); } } else { $content = id(new PhrictionContent())->load($document->getContentID()); } $page_title = $content->getTitle(); $properties = $this->buildPropertyListView($document, $content, $slug); $doc_status = $document->getStatus(); $current_status = $content->getChangeType(); if ($current_status == PhrictionChangeType::CHANGE_EDIT || $current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $core_content = $content->renderContent($viewer); $toc = $this->getToc($content); } else { if ($current_status == PhrictionChangeType::CHANGE_DELETE) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Document Deleted')); $notice->appendChild(pht('This document has been deleted. You can edit it to put new ' . 'content here, or use history to revert to an earlier version.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_STUB) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Empty Document')); $notice->appendChild(pht('This document is empty. You can edit it to put some proper ' . 'content here.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) { $new_doc_id = $content->getChangeRef(); $slug_uri = null; // If the new document exists and the viewer can see it, provide a link // to it. Otherwise, render a generic message. $new_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($new_doc_id))->execute(); if ($new_docs) { $new_doc = head($new_docs); $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); } $notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved to %s. You can edit it to put ' . 'new content here, or use history to revert to an earlier ' . 'version.', phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); } else { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved. You can edit it to put new ' . 'content here, or use history to revert to an earlier ' . 'version.'))); } $core_content = $notice->render(); } else { throw new Exception(pht("Unknown document status '%s'!", $doc_status)); } } } } $move_notice = null; if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $from_doc_id = $content->getChangeRef(); $slug_uri = null; // If the old document exists and is visible, provide a link to it. $from_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($from_doc_id))->execute(); if ($from_docs) { $from_doc = head($from_docs); $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); } $move_notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $move_notice->appendChild(pht('This document was moved from %s.', phutil_tag('a', array('href' => $slug_uri), $slug_uri))); } else { // Render this for consistency, even though it's a bit silly. $move_notice->appendChild(pht('This document was moved from elsewhere.')); } } } $children = $this->renderDocumentChildren($slug); $actions = $this->buildActionView($viewer, $document); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } $header = id(new PHUIHeaderView())->setUser($viewer)->setPolicyObject($document)->setHeader($page_title)->setActionList($actions); if ($content) { $header->setEpoch($content->getDateCreated()); } $prop_list = null; if ($properties) { $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); } $prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list); $page_content = id(new PHUIDocumentViewPro())->setHeader($header)->setToc($toc)->appendChild(array($version_note, $move_notice, $core_content)); return $this->newPage()->setTitle($page_title)->setCrumbs($crumbs)->setPageObjectPHIDs(array($document->getPHID()))->appendChild(array($page_content, $prop_list, $children)); }
protected function getTagContent() { require_celerity_resource('phui-box-css'); require_celerity_resource('phui-object-box-css'); $header = $this->header; if ($this->headerText) { $header = id(new PHUIHeaderView())->setHeader($this->headerText); } $showhide = null; if ($this->showAction !== null) { if (!$header) { $header = id(new PHUIHeaderView()); } Javelin::initBehavior('phabricator-reveal-content'); $hide_action_id = celerity_generate_unique_node_id(); $show_action_id = celerity_generate_unique_node_id(); $content_id = celerity_generate_unique_node_id(); $hide_style = $this->showHideOpen ? 'display: none;' : null; $show_style = $this->showHideOpen ? null : 'display: none;'; $hide_action = id(new PHUIButtonView())->setTag('a')->addSigil('reveal-content')->setID($hide_action_id)->setStyle($hide_style)->setIcon('fa-search')->setHref($this->showHideHref)->setMetaData(array('hideIDs' => array($hide_action_id), 'showIDs' => array($content_id, $show_action_id)))->setText($this->showAction); $show_action = id(new PHUIButtonView())->setTag('a')->addSigil('reveal-content')->setStyle($show_style)->setIcon('fa-search')->setHref('#')->setID($show_action_id)->setMetaData(array('hideIDs' => array($content_id, $show_action_id), 'showIDs' => array($hide_action_id)))->setText($this->hideAction); $header->addActionLink($hide_action); $header->addActionLink($show_action); $showhide = array(phutil_tag('div', array('class' => 'phui-object-box-hidden-content', 'id' => $content_id, 'style' => $show_style), $this->showHideContent)); } if ($this->actionListID) { $icon_id = celerity_generate_unique_node_id(); $icon = id(new PHUIIconView())->setIcon('fa-bars'); $meta = array('map' => array($this->actionListID => 'phabricator-action-list-toggle', $icon_id => 'phuix-dropdown-open')); $mobile_menu = id(new PHUIButtonView())->setTag('a')->setText(pht('Actions'))->setHref('#')->setIcon($icon)->addClass('phui-mobile-menu')->setID($icon_id)->addSigil('jx-toggle-class')->setMetadata($meta); $header->addActionLink($mobile_menu); } $ex = $this->validationException; $exception_errors = null; if ($ex) { $messages = array(); foreach ($ex->getErrors() as $error) { $messages[] = $error->getMessage(); } if ($messages) { $exception_errors = id(new PHUIInfoView())->setErrors($messages); } } if ($this->propertyLists) { $lists = new PHUIPropertyGroupView(); $ii = 0; foreach ($this->propertyLists as $list) { if ($ii > 0 || $this->tabGroups) { $list->addClass('phui-property-list-section-noninitial'); } $lists->addPropertyList($list); $ii++; } } else { $lists = null; } $content = array($this->showHideOpen == false ? $this->anchor : null, $header, $this->infoView, $this->formErrors, $this->formSaved, $exception_errors, $this->form, $this->tabGroups, $showhide, $this->showHideOpen == true ? $this->anchor : null, $lists, $this->table, $this->renderChildren()); if ($this->objectList) { $content[] = $this->objectList; } return $content; }
public function willRender() { $tab_lists = array(); $property_lists = array(); $tab_map = array(); $default_key = 'tab.default'; // Find the selected tab, or select the first tab if none are selected. if ($this->tabs) { $selected_tab = null; foreach ($this->tabs as $key => $tab) { if ($tab->getSelected()) { $selected_tab = $key; break; } } if ($selected_tab === null) { head($this->tabs)->setSelected(true); $selected_tab = head_key($this->tabs); } } foreach ($this->propertyLists as $key => $list) { $group = new PHUIPropertyGroupView(); $i = 0; foreach ($list as $item) { $group->addPropertyList($item); if ($i > 0) { $item->addClass('phui-property-list-section-noninitial'); } $i++; } if ($this->tabs && $key != $default_key) { $tab_id = celerity_generate_unique_node_id(); $tab_map[$key] = $tab_id; if ($key === $selected_tab) { $style = null; } else { $style = 'display: none'; } $tab_lists[] = phutil_tag('div', array('style' => $style, 'id' => $tab_id), $group); } else { if ($this->tabs) { $group->addClass('phui-property-group-noninitial'); } $property_lists[] = $group; } $this->propertyList = $property_lists; $this->tabMap = $tab_map; $this->tabLists = $tab_lists; } }