mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Add an async driver for document rendering and a crude "Hexdump" document engine
Summary: Depends on D19237. Ref T13105. This adds a (very basic) "Hexdump" engine (mostly just to have a second option to switch to) and a selector for choosing view modes. Test Plan: Viewed some files, switched between audio/video/image/hexdump. Maniphest Tasks: T13105 Differential Revision: https://secure.phabricator.com/D19238
This commit is contained in:
parent
01f22a8d06
commit
f646153f4d
14 changed files with 411 additions and 32 deletions
|
@ -9,7 +9,7 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => 'e68cf1fa',
|
||||
'conpherence.pkg.js' => '15191c65',
|
||||
'core.pkg.css' => '6a8ba174',
|
||||
'core.pkg.css' => '97dc0e74',
|
||||
'core.pkg.js' => '8581cd02',
|
||||
'differential.pkg.css' => '113e692c',
|
||||
'differential.pkg.js' => 'f6d809c0',
|
||||
|
@ -168,7 +168,7 @@ return array(
|
|||
'rsrc/css/phui/phui-object-box.css' => '9cff003c',
|
||||
'rsrc/css/phui/phui-pager.css' => 'edcbc226',
|
||||
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => '79fc3a02',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => 'ef864066',
|
||||
'rsrc/css/phui/phui-remarkup-preview.css' => '54a34863',
|
||||
'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892',
|
||||
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
||||
|
@ -392,6 +392,7 @@ return array(
|
|||
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
|
||||
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '1db13e70',
|
||||
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
|
||||
'rsrc/js/application/files/behavior-document-engine.js' => 'f6d6f389',
|
||||
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
|
||||
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
||||
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '191b4909',
|
||||
|
@ -606,6 +607,7 @@ return array(
|
|||
'javelin-behavior-diffusion-jump-to' => '73d09eef',
|
||||
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
|
||||
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
|
||||
'javelin-behavior-document-engine' => 'f6d6f389',
|
||||
'javelin-behavior-doorkeeper-tag' => '1db13e70',
|
||||
'javelin-behavior-drydock-live-operation-status' => '901935ef',
|
||||
'javelin-behavior-durable-column' => '2ae077e1',
|
||||
|
@ -848,7 +850,7 @@ return array(
|
|||
'phui-oi-simple-ui-css' => 'a8beebea',
|
||||
'phui-pager-css' => 'edcbc226',
|
||||
'phui-pinboard-view-css' => '2495140e',
|
||||
'phui-property-list-view-css' => '79fc3a02',
|
||||
'phui-property-list-view-css' => 'ef864066',
|
||||
'phui-remarkup-preview-css' => '54a34863',
|
||||
'phui-segment-bar-view-css' => 'b1d1b892',
|
||||
'phui-spacing-css' => '042804d6',
|
||||
|
@ -2151,6 +2153,11 @@ return array(
|
|||
'javelin-util',
|
||||
'javelin-reactor',
|
||||
),
|
||||
'f6d6f389' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'f829edb3' => array(
|
||||
'javelin-view',
|
||||
'javelin-install',
|
||||
|
|
|
@ -3001,6 +3001,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
|
||||
'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php',
|
||||
'PhabricatorFileDeleteTransaction' => 'applications/files/xaction/PhabricatorFileDeleteTransaction.php',
|
||||
'PhabricatorFileDocumentController' => 'applications/files/controller/PhabricatorFileDocumentController.php',
|
||||
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
|
||||
'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php',
|
||||
'PhabricatorFileEditEngine' => 'applications/files/editor/PhabricatorFileEditEngine.php',
|
||||
|
@ -3140,6 +3141,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php',
|
||||
'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php',
|
||||
'PhabricatorHeraldContentSource' => 'applications/herald/contentsource/PhabricatorHeraldContentSource.php',
|
||||
'PhabricatorHexdumpDocumentEngine' => 'applications/files/document/PhabricatorHexdumpDocumentEngine.php',
|
||||
'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php',
|
||||
'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php',
|
||||
'PhabricatorHomeConstants' => 'applications/home/constants/PhabricatorHomeConstants.php',
|
||||
|
@ -8590,6 +8592,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileDataController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDeleteTransaction' => 'PhabricatorFileTransactionType',
|
||||
'PhabricatorFileDocumentController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileEditController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileEditEngine' => 'PhabricatorEditEngine',
|
||||
|
@ -8747,6 +8750,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
|
||||
'PhabricatorHeraldApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorHeraldContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorHexdumpDocumentEngine' => 'PhabricatorDocumentEngine',
|
||||
'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||
'PhabricatorHomeApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorHomeConstants' => 'PhabricatorHomeController',
|
||||
|
|
|
@ -89,6 +89,8 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
|
|||
'iconset/(?P<key>[^/]+)/' => array(
|
||||
'select/' => 'PhabricatorFileIconSetSelectController',
|
||||
),
|
||||
'document/(?P<engineKey>[^/]+)/(?P<phid>[^/]+)/'
|
||||
=> 'PhabricatorFileDocumentController',
|
||||
) + $this->getResourceSubroutes(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileDocumentController
|
||||
extends PhabricatorFileController {
|
||||
|
||||
private $file;
|
||||
private $engine;
|
||||
private $ref;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$file_phid = $request->getURIData('phid');
|
||||
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($file_phid))
|
||||
->executeOne();
|
||||
if (!$file) {
|
||||
return $this->newErrorResponse(
|
||||
pht(
|
||||
'This file ("%s") does not exist or could not be loaded.',
|
||||
$file_phid));
|
||||
}
|
||||
$this->file = $file;
|
||||
|
||||
$ref = id(new PhabricatorDocumentRef())
|
||||
->setFile($file);
|
||||
$this->ref = $ref;
|
||||
|
||||
$engines = PhabricatorDocumentEngine::getEnginesForRef($viewer, $ref);
|
||||
$engine_key = $request->getURIData('engineKey');
|
||||
if (!isset($engines[$engine_key])) {
|
||||
return $this->newErrorResponse(
|
||||
pht(
|
||||
'The engine ("%s") is unknown, or unable to render this document.',
|
||||
$engine_key));
|
||||
}
|
||||
$engine = $engines[$engine_key];
|
||||
$this->engine = $engine;
|
||||
|
||||
try {
|
||||
$content = $engine->newDocument($ref);
|
||||
} catch (Exception $ex) {
|
||||
return $this->newErrorResponse($ex->getMessage());
|
||||
}
|
||||
|
||||
return $this->newContentResponse($content);
|
||||
}
|
||||
|
||||
private function newErrorResponse($message) {
|
||||
$container = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'document-engine-error',
|
||||
),
|
||||
array(
|
||||
id(new PHUIIconView())
|
||||
->setIcon('fa-exclamation-triangle red'),
|
||||
' ',
|
||||
$message,
|
||||
));
|
||||
|
||||
return $this->newContentResponse($container);
|
||||
}
|
||||
|
||||
|
||||
private function newContentResponse($content) {
|
||||
$viewer = $this->getViewer();
|
||||
$request = $this->getRequest();
|
||||
|
||||
$file = $this->file;
|
||||
$engine = $this->engine;
|
||||
$ref = $this->ref;
|
||||
|
||||
if ($request->isAjax()) {
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent(
|
||||
array(
|
||||
'markup' => hsprintf('%s', $content),
|
||||
));
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
if ($file) {
|
||||
$crumbs->addTextCrumb($file->getMonogram(), $file->getInfoURI());
|
||||
}
|
||||
|
||||
$label = $engine->getViewAsLabel($ref);
|
||||
if ($label) {
|
||||
$crumbs->addTextCrumb($label);
|
||||
}
|
||||
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$content_frame = id(new PHUIObjectBoxView())
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->appendChild($content);
|
||||
|
||||
$page_frame = id(new PHUITwoColumnView())
|
||||
->setFooter($content_frame);
|
||||
|
||||
return $this->newPage()
|
||||
->setCrumbs($crumbs)
|
||||
->setTitle(
|
||||
array(
|
||||
$ref->getName(),
|
||||
pht('Standalone'),
|
||||
))
|
||||
->appendChild($page_frame);
|
||||
}
|
||||
|
||||
}
|
|
@ -404,50 +404,70 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
|
||||
private function newFileContent(PhabricatorFile $file) {
|
||||
$viewer = $this->getViewer();
|
||||
$engines = PhabricatorDocumentEngine::getAllEngines();
|
||||
|
||||
$ref = id(new PhabricatorDocumentRef())
|
||||
->setFile($file);
|
||||
|
||||
foreach ($engines as $key => $engine) {
|
||||
$engine = id(clone $engine)
|
||||
->setViewer($viewer);
|
||||
|
||||
if (!$engine->canRenderDocument($ref)) {
|
||||
unset($engines[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$engines[$key] = $engine;
|
||||
}
|
||||
|
||||
if (!$engines) {
|
||||
throw new Exception(pht('No engine can render this document.'));
|
||||
}
|
||||
|
||||
$vectors = array();
|
||||
foreach ($engines as $key => $usable_engine) {
|
||||
$vectors[$key] = $usable_engine->newSortVector($ref);
|
||||
}
|
||||
$vectors = msortv($vectors, 'getSelf');
|
||||
|
||||
$engine = $engines[head_key($vectors)];
|
||||
$engines = PhabricatorDocumentEngine::getEnginesForRef($viewer, $ref);
|
||||
$engine = head($engines);
|
||||
|
||||
$content = $engine->newDocument($ref);
|
||||
if (!$content) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$icon = $engine->newDocumentIcon($ref);
|
||||
|
||||
$views = array();
|
||||
foreach ($engines as $candidate_engine) {
|
||||
$label = $candidate_engine->getViewAsLabel($ref);
|
||||
if ($label === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$view_icon = $candidate_engine->getViewAsIconIcon($ref);
|
||||
|
||||
$views[] = array(
|
||||
'viewKey' => $candidate_engine->getDocumentEngineKey(),
|
||||
'icon' => $view_icon,
|
||||
'name' => $label,
|
||||
'engineURI' => $candidate_engine->getRenderURI($ref),
|
||||
);
|
||||
}
|
||||
|
||||
Javelin::initBehavior('document-engine');
|
||||
|
||||
$viewport_id = celerity_generate_unique_node_id();
|
||||
|
||||
$viewport = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'id' => $viewport_id,
|
||||
),
|
||||
$content);
|
||||
|
||||
$meta = array(
|
||||
'viewportID' => $viewport_id,
|
||||
'viewKey' => $engine->getDocumentEngineKey(),
|
||||
'views' => $views,
|
||||
'standaloneURI' => $engine->getRenderURI($ref),
|
||||
);
|
||||
|
||||
$view_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('View Options'))
|
||||
->setIcon('fa-file-image-o')
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setMetadata($meta)
|
||||
->setDropdown(true)
|
||||
->addSigil('document-engine-view-dropdown');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeaderIcon($icon)
|
||||
->setHeader($ref->getName());
|
||||
->setHeader($ref->getName())
|
||||
->addActionLink($view_button);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setHeader($header)
|
||||
->appendChild($content);
|
||||
->appendChild($viewport);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ final class PhabricatorAudioDocumentEngine
|
|||
|
||||
const ENGINEKEY = 'audio';
|
||||
|
||||
public function getViewAsLabel(PhabricatorDocumentRef $ref) {
|
||||
return pht('View as Audio');
|
||||
}
|
||||
|
||||
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return 'fa-file-sound-o';
|
||||
}
|
||||
|
|
|
@ -59,4 +59,52 @@ abstract class PhabricatorDocumentEngine
|
|||
return 2000;
|
||||
}
|
||||
|
||||
abstract public function getViewAsLabel(PhabricatorDocumentRef $ref);
|
||||
|
||||
public function getViewAsIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return $this->getDocumentIconIcon($ref);
|
||||
}
|
||||
|
||||
public function getRenderURI(PhabricatorDocumentRef $ref) {
|
||||
$file = $ref->getFile();
|
||||
if (!$file) {
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
$engine_key = $this->getDocumentEngineKey();
|
||||
$file_phid = $file->getPHID();
|
||||
|
||||
return "/file/document/{$engine_key}/{$file_phid}/";
|
||||
}
|
||||
|
||||
final public static function getEnginesForRef(
|
||||
PhabricatorUser $viewer,
|
||||
PhabricatorDocumentRef $ref) {
|
||||
$engines = self::getAllEngines();
|
||||
|
||||
foreach ($engines as $key => $engine) {
|
||||
$engine = id(clone $engine)
|
||||
->setViewer($viewer);
|
||||
|
||||
if (!$engine->canRenderDocument($ref)) {
|
||||
unset($engines[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$engines[$key] = $engine;
|
||||
}
|
||||
|
||||
if (!$engines) {
|
||||
throw new Exception(pht('No content engine can render this document.'));
|
||||
}
|
||||
|
||||
$vectors = array();
|
||||
foreach ($engines as $key => $usable_engine) {
|
||||
$vectors[$key] = $usable_engine->newSortVector($ref);
|
||||
}
|
||||
$vectors = msortv($vectors, 'getSelf');
|
||||
|
||||
return array_select_keys($engines, array_keys($vectors));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,14 @@ final class PhabricatorDocumentRef
|
|||
return null;
|
||||
}
|
||||
|
||||
public function loadData() {
|
||||
if ($this->file) {
|
||||
return $this->file->loadFileData();
|
||||
}
|
||||
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
public function hasAnyMimeType(array $candidate_types) {
|
||||
$mime_full = $this->getMimeType();
|
||||
$mime_parts = explode(';', $mime_full);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHexdumpDocumentEngine
|
||||
extends PhabricatorDocumentEngine {
|
||||
|
||||
const ENGINEKEY = 'hexdump';
|
||||
|
||||
public function getViewAsLabel(PhabricatorDocumentRef $ref) {
|
||||
return pht('View as Hexdump');
|
||||
}
|
||||
|
||||
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return 'fa-microchip';
|
||||
}
|
||||
|
||||
protected function getContentScore() {
|
||||
return 500;
|
||||
}
|
||||
|
||||
protected function canRenderDocumentType(PhabricatorDocumentRef $ref) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function newDocumentContent(PhabricatorDocumentRef $ref) {
|
||||
$content = $ref->loadData();
|
||||
|
||||
$output = array();
|
||||
$offset = 0;
|
||||
|
||||
$lines = str_split($content, 16);
|
||||
foreach ($lines as $line) {
|
||||
$output[] = sprintf(
|
||||
'%08x %- 23s %- 23s %- 16s',
|
||||
$offset,
|
||||
$this->renderHex(substr($line, 0, 8)),
|
||||
$this->renderHex(substr($line, 8)),
|
||||
$this->renderBytes($line));
|
||||
|
||||
$offset += 16;
|
||||
}
|
||||
|
||||
$output = implode("\n", $output);
|
||||
|
||||
$container = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'document-engine-hexdump PhabricatorMonospaced',
|
||||
),
|
||||
$output);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
private function renderHex($bytes) {
|
||||
$length = strlen($bytes);
|
||||
|
||||
$output = array();
|
||||
for ($ii = 0; $ii < $length; $ii++) {
|
||||
$output[] = sprintf('%02x', ord($bytes[$ii]));
|
||||
}
|
||||
|
||||
return implode(' ', $output);
|
||||
}
|
||||
|
||||
private function renderBytes($bytes) {
|
||||
$length = strlen($bytes);
|
||||
|
||||
$output = array();
|
||||
for ($ii = 0; $ii < $length; $ii++) {
|
||||
$chr = $bytes[$ii];
|
||||
$ord = ord($chr);
|
||||
|
||||
if ($ord < 0x20 || $ord >= 0x7F) {
|
||||
$chr = '.';
|
||||
}
|
||||
|
||||
$output[] = $chr;
|
||||
}
|
||||
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,10 @@ final class PhabricatorImageDocumentEngine
|
|||
|
||||
const ENGINEKEY = 'image';
|
||||
|
||||
public function getViewAsLabel(PhabricatorDocumentRef $ref) {
|
||||
return pht('View as Image');
|
||||
}
|
||||
|
||||
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return 'fa-file-image-o';
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ final class PhabricatorVideoDocumentEngine
|
|||
|
||||
const ENGINEKEY = 'video';
|
||||
|
||||
public function getViewAsLabel(PhabricatorDocumentRef $ref) {
|
||||
return pht('View as Video');
|
||||
}
|
||||
|
||||
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return 'fa-film';
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ final class PhabricatorVoidDocumentEngine
|
|||
|
||||
const ENGINEKEY = 'void';
|
||||
|
||||
public function getViewAsLabel(PhabricatorDocumentRef $ref) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
|
||||
return 'fa-file';
|
||||
}
|
||||
|
|
|
@ -231,3 +231,14 @@ div.phui-property-list-stacked .phui-property-list-properties
|
|||
text-align: center;
|
||||
color: {$greytext};
|
||||
}
|
||||
|
||||
.document-engine-error {
|
||||
margin: 20px auto;
|
||||
text-align: center;
|
||||
color: {$redtext};
|
||||
}
|
||||
|
||||
.document-engine-hexdump {
|
||||
margin: 20px;
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @provides javelin-behavior-document-engine
|
||||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
* javelin-stratcom
|
||||
*/
|
||||
|
||||
JX.behavior('document-engine', function() {
|
||||
|
||||
function onmenu(e) {
|
||||
var node = e.getNode('document-engine-view-dropdown');
|
||||
var data = JX.Stratcom.getData(node);
|
||||
|
||||
if (data.menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.prevent();
|
||||
|
||||
var menu = new JX.PHUIXDropdownMenu(node);
|
||||
var list = new JX.PHUIXActionListView();
|
||||
|
||||
var view;
|
||||
for (var ii = 0; ii < data.views.length; ii++) {
|
||||
var spec = data.views[ii];
|
||||
|
||||
view = new JX.PHUIXActionView()
|
||||
.setName(spec.name)
|
||||
.setIcon(spec.icon)
|
||||
.setHref(spec.engineURI);
|
||||
|
||||
view.setHandler(JX.bind(null, function(spec, e) {
|
||||
if (!e.isNormalClick()) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.prevent();
|
||||
menu.close();
|
||||
|
||||
onview(data, spec);
|
||||
}, spec));
|
||||
|
||||
list.addItem(view);
|
||||
}
|
||||
|
||||
menu.setContent(list.getNode());
|
||||
|
||||
data.menu = menu;
|
||||
menu.open();
|
||||
}
|
||||
|
||||
function onview(data, spec) {
|
||||
var handler = JX.bind(null, onrender, data);
|
||||
|
||||
new JX.Request(spec.engineURI, handler)
|
||||
.send();
|
||||
}
|
||||
|
||||
function onrender(data, r) {
|
||||
var viewport = JX.$(data.viewportID);
|
||||
|
||||
JX.DOM.setContent(viewport, JX.$H(r.markup));
|
||||
}
|
||||
|
||||
JX.Stratcom.listen('click', 'document-engine-view-dropdown', onmenu);
|
||||
|
||||
});
|
Loading…
Reference in a new issue