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;
 }
Example #5
0
 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;
     }
 }