mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Bring in JX.Workflow and the inline commenting behavior, plus sync Javelin.
This commit is contained in:
parent
4faad5b3f1
commit
9dac0ed9f1
26 changed files with 934 additions and 246 deletions
|
@ -31,10 +31,10 @@ return array(
|
||||||
|
|
||||||
// The username to use when connecting to MySQL.
|
// The username to use when connecting to MySQL.
|
||||||
'mysql.user' => 'root',
|
'mysql.user' => 'root',
|
||||||
|
|
||||||
// The password to use when connecting to MySQL.
|
// The password to use when connecting to MySQL.
|
||||||
'mysql.pass' => '',
|
'mysql.pass' => '',
|
||||||
|
|
||||||
// The MySQL server to connect to.
|
// The MySQL server to connect to.
|
||||||
'mysql.host' => 'localhost',
|
'mysql.host' => 'localhost',
|
||||||
|
|
||||||
|
@ -56,22 +56,22 @@ return array(
|
||||||
|
|
||||||
// Is Recaptcha enabled? If disabled, captchas will not appear.
|
// Is Recaptcha enabled? If disabled, captchas will not appear.
|
||||||
'recaptcha.enabled' => false,
|
'recaptcha.enabled' => false,
|
||||||
|
|
||||||
// Your Recaptcha public key, obtained from Recaptcha.
|
// Your Recaptcha public key, obtained from Recaptcha.
|
||||||
'recaptcha.public-key' => null,
|
'recaptcha.public-key' => null,
|
||||||
|
|
||||||
// Your Recaptcha private key, obtained from Recaptcha.
|
// Your Recaptcha private key, obtained from Recaptcha.
|
||||||
'recaptcha.private-key' => null,
|
'recaptcha.private-key' => null,
|
||||||
|
|
||||||
|
|
||||||
'user.default-profile-image-phid' => 'PHID-FILE-f57aaefce707fc4060ef',
|
'user.default-profile-image-phid' => 'PHID-FILE-f57aaefce707fc4060ef',
|
||||||
|
|
||||||
// When email is sent, try to hand it off to the MTA immediately. The only
|
// When email is sent, try to hand it off to the MTA immediately. The only
|
||||||
// reason to disable this is if your MTA infrastructure is completely
|
// reason to disable this is if your MTA infrastructure is completely
|
||||||
// terrible. If you disable this option, you must run the 'metamta_mta.php'
|
// terrible. If you disable this option, you must run the 'metamta_mta.php'
|
||||||
// daemon or mail won't be handed off to the MTA.
|
// daemon or mail won't be handed off to the MTA.
|
||||||
'metamta.send-immediately' => true,
|
'metamta.send-immediately' => true,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Placeholder so I don't forget about this, hopefully.
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Placeholder so I don't forget about this, hopefully.
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
celerity_register_resource_map(array(
|
celerity_register_resource_map(array(
|
||||||
'aphront-dialog-view-css' =>
|
'aphront-dialog-view-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/771b987d/rsrc/css/aphront/dialog-view.css',
|
'uri' => '/res/d98e6292/rsrc/css/aphront/dialog-view.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -188,6 +188,15 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/css/core/core.css',
|
'disk' => '/rsrc/css/core/core.css',
|
||||||
),
|
),
|
||||||
|
'phabricator-core-dialog-css' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/d9580553/rsrc/css/core/dialog.css',
|
||||||
|
'type' => 'css',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/css/core/dialog.css',
|
||||||
|
),
|
||||||
'phabricator-remarkup-css' =>
|
'phabricator-remarkup-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/786989c3/rsrc/css/core/remarkup.css',
|
'uri' => '/res/786989c3/rsrc/css/core/remarkup.css',
|
||||||
|
@ -226,6 +235,16 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js',
|
'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js',
|
||||||
),
|
),
|
||||||
|
'javelin-behavior-differential-edit-inline-comments' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/51d7da98/rsrc/js/application/differential/behavior-edit-inline-comments.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-lib-dev',
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/application/differential/behavior-edit-inline-comments.js',
|
||||||
|
),
|
||||||
'javelin-behavior-differential-populate' =>
|
'javelin-behavior-differential-populate' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/f7efbf62/rsrc/js/application/differential/behavior-populate.js',
|
'uri' => '/res/f7efbf62/rsrc/js/application/differential/behavior-populate.js',
|
||||||
|
@ -246,9 +265,9 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/differential/behavior-show-more.js',
|
'disk' => '/rsrc/js/application/differential/behavior-show-more.js',
|
||||||
),
|
),
|
||||||
'javelin-init-dev' =>
|
'javelin-magical-init' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/c57a9e89/rsrc/js/javelin/init.dev.js',
|
'uri' => '/res/76614f84/rsrc/js/javelin/init.dev.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -257,7 +276,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-init-prod' =>
|
'javelin-init-prod' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/f0172c54/rsrc/js/javelin/init.min.js',
|
'uri' => '/res/ce6bff38/rsrc/js/javelin/init.min.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -266,7 +285,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-lib-dev' =>
|
'javelin-lib-dev' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/3e747182/rsrc/js/javelin/javelin.dev.js',
|
'uri' => '/res/29c9b6b4/rsrc/js/javelin/javelin.dev.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -275,7 +294,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-lib-prod' =>
|
'javelin-lib-prod' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/9438670e/rsrc/js/javelin/javelin.min.js',
|
'uri' => '/res/ef13c830/rsrc/js/javelin/javelin.min.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -284,7 +303,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-typeahead-dev' =>
|
'javelin-typeahead-dev' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/c81c0f01/rsrc/js/javelin/typeahead.dev.js',
|
'uri' => '/res/6de6ae59/rsrc/js/javelin/typeahead.dev.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -293,17 +312,35 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-typeahead-prod' =>
|
'javelin-typeahead-prod' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/1da2d984/rsrc/js/javelin/typeahead.min.js',
|
'uri' => '/res/593d9bb8/rsrc/js/javelin/typeahead.min.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/javelin/typeahead.min.js',
|
'disk' => '/rsrc/js/javelin/typeahead.min.js',
|
||||||
),
|
),
|
||||||
|
'javelin-workflow-dev' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/2d740661/rsrc/js/javelin/workflow.dev.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/javelin/workflow.dev.js',
|
||||||
|
),
|
||||||
|
'javelin-workflow-prod' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/b758e0a0/rsrc/js/javelin/workflow.min.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/javelin/workflow.min.js',
|
||||||
|
),
|
||||||
), array (
|
), array (
|
||||||
'packages' =>
|
'packages' =>
|
||||||
array (
|
array (
|
||||||
'd348c79d' =>
|
'dc2390af' =>
|
||||||
array (
|
array (
|
||||||
'name' => 'core.pkg.css',
|
'name' => 'core.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -320,7 +357,7 @@ celerity_register_resource_map(array(
|
||||||
9 => 'aphront-typeahead-control-css',
|
9 => 'aphront-typeahead-control-css',
|
||||||
10 => 'phabricator-directory-css',
|
10 => 'phabricator-directory-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/d348c79d/core.pkg.css',
|
'uri' => '/res/pkg/dc2390af/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'69b11588' =>
|
'69b11588' =>
|
||||||
|
@ -340,17 +377,17 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'reverse' =>
|
'reverse' =>
|
||||||
array (
|
array (
|
||||||
'phabricator-core-css' => 'd348c79d',
|
'phabricator-core-css' => 'dc2390af',
|
||||||
'phabricator-core-buttons-css' => 'd348c79d',
|
'phabricator-core-buttons-css' => 'dc2390af',
|
||||||
'phabricator-standard-page-view' => 'd348c79d',
|
'phabricator-standard-page-view' => 'dc2390af',
|
||||||
'aphront-dialog-view-css' => 'd348c79d',
|
'aphront-dialog-view-css' => 'dc2390af',
|
||||||
'aphront-form-view-css' => 'd348c79d',
|
'aphront-form-view-css' => 'dc2390af',
|
||||||
'aphront-panel-view-css' => 'd348c79d',
|
'aphront-panel-view-css' => 'dc2390af',
|
||||||
'aphront-side-nav-view-css' => 'd348c79d',
|
'aphront-side-nav-view-css' => 'dc2390af',
|
||||||
'aphront-table-view-css' => 'd348c79d',
|
'aphront-table-view-css' => 'dc2390af',
|
||||||
'aphront-tokenizer-control-css' => 'd348c79d',
|
'aphront-tokenizer-control-css' => 'dc2390af',
|
||||||
'aphront-typeahead-control-css' => 'd348c79d',
|
'aphront-typeahead-control-css' => 'dc2390af',
|
||||||
'phabricator-directory-css' => 'd348c79d',
|
'phabricator-directory-css' => 'dc2390af',
|
||||||
'differential-core-view-css' => '69b11588',
|
'differential-core-view-css' => '69b11588',
|
||||||
'differential-changeset-view-css' => '69b11588',
|
'differential-changeset-view-css' => '69b11588',
|
||||||
'differential-revision-detail-css' => '69b11588',
|
'differential-revision-detail-css' => '69b11588',
|
||||||
|
|
|
@ -90,6 +90,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
|
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
|
||||||
'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
|
'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
|
||||||
'DifferentialHunk' => 'applications/differential/storage/hunk',
|
'DifferentialHunk' => 'applications/differential/storage/hunk',
|
||||||
|
'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
|
||||||
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
|
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
|
||||||
'DifferentialMail' => 'applications/differential/mail/base',
|
'DifferentialMail' => 'applications/differential/mail/base',
|
||||||
'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
|
'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
|
||||||
|
@ -264,6 +265,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialDiffTableOfContentsView' => 'AphrontView',
|
'DifferentialDiffTableOfContentsView' => 'AphrontView',
|
||||||
'DifferentialDiffViewController' => 'DifferentialController',
|
'DifferentialDiffViewController' => 'DifferentialController',
|
||||||
'DifferentialHunk' => 'DifferentialDAO',
|
'DifferentialHunk' => 'DifferentialDAO',
|
||||||
|
'DifferentialInlineComment' => 'DifferentialDAO',
|
||||||
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
|
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
|
||||||
'DifferentialReviewRequestMail' => 'DifferentialMail',
|
'DifferentialReviewRequestMail' => 'DifferentialMail',
|
||||||
'DifferentialRevision' => 'DifferentialDAO',
|
'DifferentialRevision' => 'DifferentialDAO',
|
||||||
|
|
|
@ -79,6 +79,8 @@ class DifferentialRevisionViewController extends DifferentialController {
|
||||||
|
|
||||||
$changeset_view = new DifferentialChangesetListView();
|
$changeset_view = new DifferentialChangesetListView();
|
||||||
$changeset_view->setChangesets($changesets);
|
$changeset_view->setChangesets($changesets);
|
||||||
|
$changeset_view->setEditable(true);
|
||||||
|
$changeset_view->setRevision($revision);
|
||||||
|
|
||||||
$comment_form = new DifferentialAddCommentView();
|
$comment_form = new DifferentialAddCommentView();
|
||||||
$comment_form->setRevision($revision);
|
$comment_form->setRevision($revision);
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DifferentialInlineComment extends DifferentialDAO {
|
||||||
|
|
||||||
|
protected $revisionID;
|
||||||
|
protected $commentID;
|
||||||
|
protected $authorPHID;
|
||||||
|
|
||||||
|
protected $changesetID;
|
||||||
|
protected $isNewFile;
|
||||||
|
|
||||||
|
protected $lineNumber;
|
||||||
|
protected $lineLength;
|
||||||
|
|
||||||
|
protected $content;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/differential/storage/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('DifferentialInlineComment.php');
|
|
@ -19,12 +19,24 @@
|
||||||
class DifferentialChangesetListView extends AphrontView {
|
class DifferentialChangesetListView extends AphrontView {
|
||||||
|
|
||||||
private $changesets = array();
|
private $changesets = array();
|
||||||
|
private $editable;
|
||||||
|
private $revision;
|
||||||
|
|
||||||
public function setChangesets($changesets) {
|
public function setChangesets($changesets) {
|
||||||
$this->changesets = $changesets;
|
$this->changesets = $changesets;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setEditable($editable) {
|
||||||
|
$this->editable = $editable;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRevision(DifferentialRevision $revision) {
|
||||||
|
$this->revision = $revision;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
require_celerity_resource('differential-changeset-view-css');
|
require_celerity_resource('differential-changeset-view-css');
|
||||||
|
|
||||||
|
@ -105,20 +117,14 @@ class DifferentialChangesetListView extends AphrontView {
|
||||||
Javelin::initBehavior('differential-show-more', array(
|
Javelin::initBehavior('differential-show-more', array(
|
||||||
'uri' => '/differential/changeset/',
|
'uri' => '/differential/changeset/',
|
||||||
));
|
));
|
||||||
/*
|
|
||||||
|
|
||||||
|
if ($this->editable) {
|
||||||
Javelin::initBehavior('differential-context', array(
|
$revision = $this->revision;
|
||||||
'uri' => $render_uri,
|
Javelin::initBehavior('differential-edit-inline-comments', array(
|
||||||
));
|
'uri' => '/differential/inline/edit/'.$revision->getID().'/',
|
||||||
|
|
||||||
if ($edit) {
|
|
||||||
require_static('remarkup-css');
|
|
||||||
Javelin::initBehavior('differential-inline', array(
|
|
||||||
'uri' => '/differential/feedback/'.$revision->getID().'/',
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return
|
return
|
||||||
'<div class="differential-review-stage">'.
|
'<div class="differential-review-stage">'.
|
||||||
implode("\n", $output).
|
implode("\n", $output).
|
||||||
|
|
|
@ -114,21 +114,21 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
|
||||||
$this->setParam('simulated-failures', $count);
|
$this->setParam('simulated-failures', $count);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save() {
|
public function save() {
|
||||||
$try_send = (PhabricatorEnv::getEnvConfig('metamta.send-immediately')) &&
|
$try_send = (PhabricatorEnv::getEnvConfig('metamta.send-immediately')) &&
|
||||||
(!$this->getID());
|
(!$this->getID());
|
||||||
|
|
||||||
$ret = parent::save();
|
$ret = parent::save();
|
||||||
|
|
||||||
if ($try_send) {
|
if ($try_send) {
|
||||||
$mailer = new PhabricatorMailImplementationPHPMailerLiteAdapter();
|
$mailer = new PhabricatorMailImplementationPHPMailerLiteAdapter();
|
||||||
$this->sendNow($force_send = false, $mailer);
|
$this->sendNow($force_send = false, $mailer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function sendNow(
|
public function sendNow(
|
||||||
$force_send = false,
|
$force_send = false,
|
||||||
|
@ -143,7 +143,7 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
|
||||||
throw new Exception("Trying to send an email before next retry!");
|
throw new Exception("Trying to send an email before next retry!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$parameters = $this->parameters;
|
$parameters = $this->parameters;
|
||||||
$phids = array();
|
$phids = array();
|
||||||
|
@ -161,10 +161,10 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||||
->loadHandles();
|
->loadHandles();
|
||||||
|
|
||||||
foreach ($this->parameters as $key => $value) {
|
foreach ($this->parameters as $key => $value) {
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'from':
|
case 'from':
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/metamta/adapter/phpmailerlite');
|
||||||
phutil_require_module('phabricator', 'applications/metamta/storage/base');
|
phutil_require_module('phabricator', 'applications/metamta/storage/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
|
@ -24,31 +24,24 @@ function javelin_render_tag(
|
||||||
if (isset($attributes['sigil']) ||
|
if (isset($attributes['sigil']) ||
|
||||||
isset($attributes['meta']) ||
|
isset($attributes['meta']) ||
|
||||||
isset($attributes['mustcapture'])) {
|
isset($attributes['mustcapture'])) {
|
||||||
$classes = array();
|
|
||||||
foreach ($attributes as $k => $v) {
|
foreach ($attributes as $k => $v) {
|
||||||
switch ($k) {
|
switch ($k) {
|
||||||
case 'sigil':
|
case 'sigil':
|
||||||
$classes[] = 'FN_'.$v;
|
$attributes['data-sigil'] = $v;
|
||||||
unset($attributes[$k]);
|
unset($attributes[$k]);
|
||||||
break;
|
break;
|
||||||
case 'meta':
|
case 'meta':
|
||||||
$response = CelerityAPI::getStaticResourceResponse();
|
$response = CelerityAPI::getStaticResourceResponse();
|
||||||
$id = $response->addMetadata($v);
|
$id = $response->addMetadata($v);
|
||||||
$classes[] = 'FD_'.$id;
|
$attributes['data-meta'] = $id;
|
||||||
unset($attributes[$k]);
|
unset($attributes[$k]);
|
||||||
break;
|
break;
|
||||||
case 'mustcapture':
|
case 'mustcapture':
|
||||||
$classes[] = 'FI_CAPTURE';
|
$attributes['data-mustcapture'] = '1';
|
||||||
unset($attributes[$k]);
|
unset($attributes[$k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($attributes['class'])) {
|
|
||||||
$classes[] = $attributes['class'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributes['class'] = implode(' ', $classes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return phutil_render_tag($tag, $attributes, $content);
|
return phutil_render_tag($tag, $attributes, $content);
|
||||||
|
|
|
@ -68,12 +68,13 @@ class AphrontDialogView extends AphrontView {
|
||||||
'Cancel');
|
'Cancel');
|
||||||
}
|
}
|
||||||
|
|
||||||
return phutil_render_tag(
|
return javelin_render_tag(
|
||||||
'form',
|
'form',
|
||||||
array(
|
array(
|
||||||
'class' => 'aphront-dialog-view',
|
'class' => 'aphront-dialog-view',
|
||||||
'action' => $this->submitURI,
|
'action' => $this->submitURI,
|
||||||
'method' => 'post',
|
'method' => 'post',
|
||||||
|
'sigil' => 'jx-dialog',
|
||||||
),
|
),
|
||||||
'<input type="hidden" name="__form__" value="1" />'.
|
'<input type="hidden" name="__form__" value="1" />'.
|
||||||
'<div class="aphront-dialog-head">'.
|
'<div class="aphront-dialog-head">'.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||||
phutil_require_module('phabricator', 'view/base');
|
phutil_require_module('phabricator', 'view/base');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'markup');
|
phutil_require_module('phutil', 'markup');
|
||||||
|
|
|
@ -70,6 +70,7 @@ class PhabricatorStandardPageView extends AphrontPageView {
|
||||||
require_celerity_resource('phabricator-standard-page-view');
|
require_celerity_resource('phabricator-standard-page-view');
|
||||||
|
|
||||||
require_celerity_resource('javelin-lib-dev');
|
require_celerity_resource('javelin-lib-dev');
|
||||||
|
require_celerity_resource('javelin-workflow-dev');
|
||||||
|
|
||||||
$this->bodyContent = $this->renderChildren();
|
$this->bodyContent = $this->renderChildren();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
* @provides aphront-dialog-view-css
|
* @provides aphront-dialog-view-css
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.aphront-dialog-view {
|
.aphront-dialog-view {
|
||||||
width: 480px;
|
width: 480px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -40,3 +38,23 @@
|
||||||
margin-left: .5em;
|
margin-left: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jx-client-dialog {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-mask {
|
||||||
|
opacity: .5;
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=75)";
|
||||||
|
filter: alpha(opacity=75);
|
||||||
|
background: #999;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 5;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -119,3 +119,14 @@
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
padding: 10px 0px 20px;
|
padding: 10px 0px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.differential-reticle {
|
||||||
|
background: #ffeeaa;
|
||||||
|
border: 1px solid #ffcc00;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
opacity: 0.5;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
55
webroot/rsrc/css/core/dialog.css
Normal file
55
webroot/rsrc/css/core/dialog.css
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* @provides phabricator-core-dialog-css
|
||||||
|
*/
|
||||||
|
|
||||||
|
.jx-dialog {
|
||||||
|
display: block;
|
||||||
|
width: 480px;
|
||||||
|
padding: 8px;
|
||||||
|
background: #666;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-client-dialog {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog .dialog-title {
|
||||||
|
background: #6d84b4;
|
||||||
|
border: none;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 12px 6px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.jx-dialog .dialog-body {
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 16px 12px;
|
||||||
|
border: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog .dialog-foot {
|
||||||
|
border: none;
|
||||||
|
background: #ededed;
|
||||||
|
padding: .5em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog button {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog input {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog .fields {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jx-dialog input.block {
|
||||||
|
display: block;
|
||||||
|
margin: 3px 0 0 0;
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
/**
|
||||||
|
* @provides javelin-behavior-differential-edit-inline-comments
|
||||||
|
* @requires javelin-lib-dev
|
||||||
|
*/
|
||||||
|
|
||||||
|
JX.behavior('differential-edit-inline-comments', function(config) {
|
||||||
|
|
||||||
|
var selecting = false;
|
||||||
|
var reticle = JX.$N('div', {className: 'differential-reticle'});
|
||||||
|
JX.DOM.hide(reticle);
|
||||||
|
document.body.appendChild(reticle);
|
||||||
|
|
||||||
|
var origin = null;
|
||||||
|
var target = null;
|
||||||
|
var root = null;
|
||||||
|
var changeset = null;
|
||||||
|
var workflow = false;
|
||||||
|
var is_new = false;
|
||||||
|
|
||||||
|
function updateReticle() {
|
||||||
|
var top = origin;
|
||||||
|
var bot = target;
|
||||||
|
if (JX.$V(top).y > JX.$V(bot).y) {
|
||||||
|
var tmp = top;
|
||||||
|
top = bot;
|
||||||
|
bot = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
var code = target.nextSibling;
|
||||||
|
|
||||||
|
var pos = JX.$V(top).add(1 + JX.$V.getDim(target).x, 0);
|
||||||
|
var dim = JX.$V.getDim(code).add(-4, 0);
|
||||||
|
dim.y = (JX.$V(bot).y - pos.y) + JX.$V.getDim(bot).y;
|
||||||
|
|
||||||
|
pos.setPos(reticle);
|
||||||
|
dim.setDim(reticle);
|
||||||
|
|
||||||
|
JX.DOM.show(reticle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideReticle() {
|
||||||
|
JX.DOM.hide(reticle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishSelect() {
|
||||||
|
selecting = false;
|
||||||
|
workflow = false;
|
||||||
|
hideReticle();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawInlineComment(table, anchor, r) {
|
||||||
|
copyRows(table, JX.$N('div', JX.HTML(r.markup)), anchor);
|
||||||
|
finishSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNewFile(node) {
|
||||||
|
return node.parentNode.firstChild != node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRowNumber(th_node) {
|
||||||
|
try {
|
||||||
|
return parseInt(th_node.id.match(/^C\d+[ON]L(\d+)$/)[1], 10);
|
||||||
|
} catch (x) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JX.Stratcom.listen(
|
||||||
|
'mousedown',
|
||||||
|
['differential-changeset', 'tag:th'],
|
||||||
|
function(e) {
|
||||||
|
if (workflow ||
|
||||||
|
selecting ||
|
||||||
|
getRowNumber(e.getTarget()) === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selecting = true;
|
||||||
|
root = e.getNode('differential-changeset');
|
||||||
|
|
||||||
|
origin = target = e.getTarget();
|
||||||
|
|
||||||
|
var data = e.getNodeData('differential-changeset');
|
||||||
|
if (isNewFile(target)) {
|
||||||
|
changeset = data.oid;
|
||||||
|
} else {
|
||||||
|
changeset = data.nid;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateReticle();
|
||||||
|
|
||||||
|
e.kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
JX.Stratcom.listen(
|
||||||
|
'mouseover',
|
||||||
|
['differential-changeset', 'tag:th'],
|
||||||
|
function(e) {
|
||||||
|
if (!selecting ||
|
||||||
|
workflow ||
|
||||||
|
(getRowNumber(e.getTarget()) === undefined) ||
|
||||||
|
(isNewFile(e.getTarget()) != isNewFile(origin)) ||
|
||||||
|
(e.getNode('differential-changeset') !== root)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = e.getTarget();
|
||||||
|
|
||||||
|
updateReticle();
|
||||||
|
});
|
||||||
|
|
||||||
|
JX.Stratcom.listen(
|
||||||
|
'mouseup',
|
||||||
|
null,
|
||||||
|
function(e) {
|
||||||
|
if (workflow || !selecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var o = getRowNumber(origin);
|
||||||
|
var t = getRowNumber(target);
|
||||||
|
|
||||||
|
var insert;
|
||||||
|
var len;
|
||||||
|
if (t < o) {
|
||||||
|
len = (o - t);
|
||||||
|
o = t;
|
||||||
|
insert = origin.parentNode;
|
||||||
|
} else {
|
||||||
|
len = (t - o);
|
||||||
|
insert = target.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
op: 'new',
|
||||||
|
changeset: changeset,
|
||||||
|
number: o,
|
||||||
|
length: len,
|
||||||
|
is_new: isNewFile(target) ? 1 : 0
|
||||||
|
};
|
||||||
|
|
||||||
|
workflow = true;
|
||||||
|
|
||||||
|
var w = new JX.Workflow(config.uri, data)
|
||||||
|
.setHandler(function(r) {
|
||||||
|
// Skip over any rows which contain inline feedback. Don't mimic this!
|
||||||
|
// We're shipping around raw HTML here for performance reasons, but
|
||||||
|
// normally you should use sigils to encode this kind of data on
|
||||||
|
// the document.
|
||||||
|
var target = insert.nextSibling;
|
||||||
|
while (target &&
|
||||||
|
(!JX.DOM.isType(target, 'tr')
|
||||||
|
|| target.className.indexOf('inline') !== -1)) {
|
||||||
|
target = target.nextSibling;
|
||||||
|
}
|
||||||
|
drawInlineComment(insert.parentNode, target, r);
|
||||||
|
finishSelect();
|
||||||
|
JX.Stratcom.invoke('inline-comment-update',
|
||||||
|
null,
|
||||||
|
{id : r.inlineCommentID});
|
||||||
|
})
|
||||||
|
.setCloseHandler(finishSelect);
|
||||||
|
|
||||||
|
|
||||||
|
w.listen('error', function(e) {
|
||||||
|
// TODO: uh, tell the user I guess
|
||||||
|
finishSelect();
|
||||||
|
JX.Stratcom.context().stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
w.start();
|
||||||
|
|
||||||
|
e.kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
JX.Stratcom.listen(
|
||||||
|
['mouseover', 'mouseout'],
|
||||||
|
'inline-comment',
|
||||||
|
function(e) {
|
||||||
|
if (selecting || workflow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getType() == 'mouseout') {
|
||||||
|
hideReticle();
|
||||||
|
} else {
|
||||||
|
var data = e.getNodeData('inline-comment');
|
||||||
|
var change = e.getNodeData('differential-changeset');
|
||||||
|
|
||||||
|
root = e.getNode('differential-changeset');
|
||||||
|
|
||||||
|
var prefix = 'C' + change;
|
||||||
|
|
||||||
|
if (data.is_new) {
|
||||||
|
prefix += 'NL';
|
||||||
|
} else {
|
||||||
|
prefix += 'OL';
|
||||||
|
}
|
||||||
|
|
||||||
|
origin = JX.$(prefix + data.number);
|
||||||
|
target = JX.$(prefix + (data.number + data.length));
|
||||||
|
|
||||||
|
updateReticle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JX.Stratcom.listen(
|
||||||
|
'click',
|
||||||
|
[['inline-comment', 'delete'],
|
||||||
|
['inline-comment', 'edit']],
|
||||||
|
function(e) {
|
||||||
|
var data = {
|
||||||
|
op: e.getNode('edit') ? 'edit' : 'delete',
|
||||||
|
id: e.getNodeData('inline-comment').id
|
||||||
|
};
|
||||||
|
new JX.Workflow(config.uri, data)
|
||||||
|
.setHandler(function(r) {
|
||||||
|
var base_row = e.getNode('inline-comment').parentNode.parentNode;
|
||||||
|
if (data.op == 'edit' && r.markup) {
|
||||||
|
drawInlineComment(base_row.parentNode, base_row, r);
|
||||||
|
}
|
||||||
|
JX.DOM.remove(base_row);
|
||||||
|
JX.Stratcom.invoke('differential-inline-comment-update');
|
||||||
|
})
|
||||||
|
.start();
|
||||||
|
e.kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,4 +1,3 @@
|
||||||
/** @provides javelin-init-dev */
|
|
||||||
/**
|
/**
|
||||||
* Javelin core; installs Javelin and Stratcom event delegation.
|
* Javelin core; installs Javelin and Stratcom event delegation.
|
||||||
*
|
*
|
||||||
|
@ -31,7 +30,6 @@
|
||||||
JX.__rawEventQueue = function(what) {
|
JX.__rawEventQueue = function(what) {
|
||||||
master_event_queue.push(what);
|
master_event_queue.push(what);
|
||||||
|
|
||||||
|
|
||||||
// Evade static analysis - JX.Stratcom
|
// Evade static analysis - JX.Stratcom
|
||||||
var Stratcom = JX['Stratcom'];
|
var Stratcom = JX['Stratcom'];
|
||||||
if (Stratcom && Stratcom.ready) {
|
if (Stratcom && Stratcom.ready) {
|
||||||
|
@ -63,7 +61,8 @@
|
||||||
var target = what.srcElement || what.target;
|
var target = what.srcElement || what.target;
|
||||||
if (target &&
|
if (target &&
|
||||||
(what.type in {click: 1, submit: 1}) &&
|
(what.type in {click: 1, submit: 1}) &&
|
||||||
(/ FI_CAPTURE /).test(' ' + target.className + ' ')) {
|
target.getAttribute &&
|
||||||
|
target.getAttribute('data-mustcapture') === '1') {
|
||||||
what.returnValue = false;
|
what.returnValue = false;
|
||||||
what.preventDefault && what.preventDefault();
|
what.preventDefault && what.preventDefault();
|
||||||
document.body.id = 'event_capture';
|
document.body.id = 'event_capture';
|
||||||
|
|
2
webroot/rsrc/js/javelin/init.min.js
vendored
2
webroot/rsrc/js/javelin/init.min.js
vendored
|
@ -1,2 +1,2 @@
|
||||||
/** @provides javelin-init-prod */
|
/** @provides javelin-init-prod */
|
||||||
(function(){if(window.JX)return;window.JX={};window.__DEV__=window.__DEV__||0;var d=false;var f=[];var e=[];var h=document.documentElement;var b=!!h.addEventListener;JX.__rawEventQueue=function(o){e.push(o);var j=JX.Stratcom;if(j&&j.ready){var m=e;e=[];for(var l=0;l<m.length;++l){var k=m[l];try{var test=k.type;}catch(p){continue;}if(!d&&k.type=='domready'){document.body&&(document.body.id=null);d=true;for(var l=0;l<f.length;l++)f[l]();}j.dispatch(k);}}else{var n=o.srcElement||o.target;if(n&&(o.type in {click:1,submit:1})&&(/ FI_CAPTURE /).test(' '+n.className+' ')){o.returnValue=false;o.preventDefault&&o.preventDefault();document.body.id='event_capture';if(!add_event_listener&&document.createEventObject){e.pop();e.push(document.createEventObject(o));}return false;}}};JX.enableDispatch=function(j,k){if(j.addEventListener){j.addEventListener(k,JX.__rawEventQueue,true);}else if(j.attachEvent)j.attachEvent('on'+k,JX.__rawEventQueue);};var a=['click','change','keypress','mousedown','mouseover','mouseout','mouseup','keydown','drop','dragenter','dragleave','dragover'];if(!b)a.push('focusin','focusout');if(window.opera){a.push('focus','blur');}else a.push('submit');for(var c=0;c<a.length;++c)JX.enableDispatch(h,a[c]);var i=[('onpagehide' in window)?'pagehide':'unload','resize','focus','blur'];for(var c=0;c<i.length;++c)JX.enableDispatch(window,i[c]);JX.__simulate=function(k,event){if(!b){var j={target:k,type:event};JX.__rawEventQueue(j);if(j.returnValue===false)return false;}};if(b){document.addEventListener('DOMContentLoaded',function(){JX.__rawEventQueue({type:'domready'});},true);}else{var g="if (this.readyState == 'complete') {"+"JX.__rawEventQueue({type: 'domready'});"+"}";document.write('<script'+' defer="defer"'+' src="javascript:void(0)"'+' onreadystatechange="'+g+'"'+'><\/sc'+'ript\>');}JX.onload=function(j){if(d){j();}else f.push(j);};})();
|
(function(){if(window.JX)return;window.JX={};window.__DEV__=window.__DEV__||0;var d=false;var f=[];var e=[];var h=document.documentElement;var b=!!h.addEventListener;JX.__rawEventQueue=function(o){e.push(o);var j=JX.Stratcom;if(j&&j.ready){var m=e;e=[];for(var l=0;l<m.length;++l){var k=m[l];try{var test=k.type;}catch(p){continue;}if(!d&&k.type=='domready'){document.body&&(document.body.id=null);d=true;for(var l=0;l<f.length;l++)f[l]();}j.dispatch(k);}}else{var n=o.srcElement||o.target;if(n&&(o.type in {click:1,submit:1})&&n.getAttribute&&n.getAttribute('data-mustcapture')==='1'){o.returnValue=false;o.preventDefault&&o.preventDefault();document.body.id='event_capture';if(!add_event_listener&&document.createEventObject){e.pop();e.push(document.createEventObject(o));}return false;}}};JX.enableDispatch=function(j,k){if(j.addEventListener){j.addEventListener(k,JX.__rawEventQueue,true);}else if(j.attachEvent)j.attachEvent('on'+k,JX.__rawEventQueue);};var a=['click','change','keypress','mousedown','mouseover','mouseout','mouseup','keydown','drop','dragenter','dragleave','dragover'];if(!b)a.push('focusin','focusout');if(window.opera){a.push('focus','blur');}else a.push('submit');for(var c=0;c<a.length;++c)JX.enableDispatch(h,a[c]);var i=[('onpagehide' in window)?'pagehide':'unload','resize','focus','blur'];for(var c=0;c<i.length;++c)JX.enableDispatch(window,i[c]);JX.__simulate=function(k,event){if(!b){var j={target:k,type:event};JX.__rawEventQueue(j);if(j.returnValue===false)return false;}};if(b){document.addEventListener('DOMContentLoaded',function(){JX.__rawEventQueue({type:'domready'});},true);}else{var g="if (this.readyState == 'complete') {"+"JX.__rawEventQueue({type: 'domready'});"+"}";document.write('<script'+' defer="defer"'+' src="javascript:void(0)"'+' onreadystatechange="'+g+'"'+'><\/sc'+'ript\>');}JX.onload=function(j){if(d){j();}else f.push(j);};})();
|
||||||
|
|
|
@ -824,7 +824,6 @@ JX.install('Event', {
|
||||||
* }
|
* }
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @return string|null ##null## if there is no associated special key,
|
* @return string|null ##null## if there is no associated special key,
|
||||||
* or one of the strings 'delete', 'tab', 'return',
|
* or one of the strings 'delete', 'tab', 'return',
|
||||||
* 'esc', 'left', 'up', 'right', or 'down'.
|
* 'esc', 'left', 'up', 'right', or 'down'.
|
||||||
|
@ -836,21 +835,17 @@ JX.install('Event', {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = r.keyCode;
|
return JX.Event._keymap[r.keyCode] || null;
|
||||||
do {
|
|
||||||
c = JX.Event._keymap[c] || null;
|
|
||||||
} while (c && JX.Event._keymap[c])
|
|
||||||
|
|
||||||
return c;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the node corresponding to the specified key in this event's node map.
|
* Get the node corresponding to the specified key in this event's node map.
|
||||||
* This is a simple helper method that makes the API for accessing nodes
|
* This is a simple helper method that makes the API for accessing nodes
|
||||||
* less ugly.
|
* less ugly.
|
||||||
*
|
*
|
||||||
* JX.Stratcom.listen('click', 'tag:a', function(e) {
|
* JX.Stratcom.listen('click', 'tag:a', function(e) {
|
||||||
* var a = e.getNode('nearest:a');
|
* var a = e.getNode('tag:a');
|
||||||
* // do something with the link that was clicked
|
* // do something with the link that was clicked
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
|
@ -862,10 +857,29 @@ JX.install('Event', {
|
||||||
* - sigil - first node of each sigil
|
* - sigil - first node of each sigil
|
||||||
* @task info
|
* @task info
|
||||||
*/
|
*/
|
||||||
getNode: function(key) {
|
getNode : function(key) {
|
||||||
return this.getNodes()[key] || null;
|
return this.getNodes()[key] || null;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the metadata associated with the node that corresponds to the key
|
||||||
|
* in this event's node map. This is a simple helper method that makes
|
||||||
|
* the API for accessing metadata associated with specific nodes less ugly.
|
||||||
|
*
|
||||||
|
* JX.Stratcom.listen('click', 'tag:a', function(event) {
|
||||||
|
* var anchorData = event.getNodeData('tag:a');
|
||||||
|
* // do something with the metadata of the link that was clicked
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param string sigil or stratcom node key
|
||||||
|
* @return dict dictionary of the node's metadata
|
||||||
|
* @task info
|
||||||
|
*/
|
||||||
|
getNodeData : function(key) {
|
||||||
|
// Evade static analysis - JX.Stratcom
|
||||||
|
return JX['Stratcom'].getData(this.getNode(key));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
statics : {
|
statics : {
|
||||||
|
@ -878,10 +892,10 @@ JX.install('Event', {
|
||||||
38 : 'up',
|
38 : 'up',
|
||||||
39 : 'right',
|
39 : 'right',
|
||||||
40 : 'down',
|
40 : 'down',
|
||||||
63232 : 38,
|
63232 : 'up',
|
||||||
63233 : 40,
|
63233 : 'down',
|
||||||
62234 : 37,
|
62234 : 'left',
|
||||||
62235 : 39
|
62235 : 'right'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1008,6 +1022,7 @@ JX.install('Event', {
|
||||||
* @task listen Listening to Events
|
* @task listen Listening to Events
|
||||||
* @task handle Responding to Events
|
* @task handle Responding to Events
|
||||||
* @task sigil Managing Sigils
|
* @task sigil Managing Sigils
|
||||||
|
* @task meta Managing Metadata
|
||||||
* @task internal Internals
|
* @task internal Internals
|
||||||
*/
|
*/
|
||||||
JX.install('Stratcom', {
|
JX.install('Stratcom', {
|
||||||
|
@ -1016,8 +1031,6 @@ JX.install('Stratcom', {
|
||||||
_targets : {},
|
_targets : {},
|
||||||
_handlers : [],
|
_handlers : [],
|
||||||
_need : {},
|
_need : {},
|
||||||
_matchName : /\bFN_([^ ]+)/,
|
|
||||||
_matchData : /\bFD_([^ ]+)_([^ ]+)/,
|
|
||||||
_auto : '*',
|
_auto : '*',
|
||||||
_data : {},
|
_data : {},
|
||||||
_execContext : [],
|
_execContext : [],
|
||||||
|
@ -1039,13 +1052,13 @@ JX.install('Stratcom', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Within each datablock, data is identified by a unique index. The data
|
* Within each datablock, data is identified by a unique index. The data
|
||||||
* pointer on a node looks like this:
|
* pointer (data-meta attribute) on a node looks like this:
|
||||||
*
|
*
|
||||||
* FD_1_2
|
* 1_2
|
||||||
*
|
*
|
||||||
* ...where 1 is the block, and 2 is the index within that block. Normally,
|
* ...where 1 is the block, and 2 is the index within that block. Normally,
|
||||||
* blocks are filled on the server side, so index allocation takes place
|
* blocks are filled on the server side, so index allocation takes place
|
||||||
* there. However, when data is provided with JX.Stratcom.sigilize(), we
|
* there. However, when data is provided with JX.Stratcom.addData(), we
|
||||||
* need to allocate indexes on the client.
|
* need to allocate indexes on the client.
|
||||||
*/
|
*/
|
||||||
_dataIndex : 0,
|
_dataIndex : 0,
|
||||||
|
@ -1185,9 +1198,12 @@ JX.install('Stratcom', {
|
||||||
if (path[kk] == 'tag:#document') {
|
if (path[kk] == 'tag:#document') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'JX.Stratcom.listen(..., "tag:#document", ...): ' +
|
'JX.Stratcom.listen(..., "tag:#document", ...): ' +
|
||||||
'listen for document events as "tag:window", not ' +
|
'listen for all events using null, not "tag:#document"');
|
||||||
'"tag:#document", in order to get consistent behavior ' +
|
}
|
||||||
'across browsers.');
|
if (path[kk] == 'tag:window') {
|
||||||
|
throw new Error(
|
||||||
|
'JX.Stratcom.listen(..., "tag:window", ...): ' +
|
||||||
|
'listen for window events using null, not "tag:window"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!type_target[path[kk]]) {
|
if (!type_target[path[kk]]) {
|
||||||
|
@ -1219,29 +1235,27 @@ JX.install('Stratcom', {
|
||||||
* @task internal
|
* @task internal
|
||||||
*/
|
*/
|
||||||
dispatch : function(event) {
|
dispatch : function(event) {
|
||||||
// TODO: simplify this :P
|
|
||||||
var target;
|
|
||||||
try {
|
|
||||||
target = event.srcElement || event.target;
|
|
||||||
if (target === window || (!target || target.nodeName == '#document')) {
|
|
||||||
target = {nodeName: 'window'};
|
|
||||||
}
|
|
||||||
} catch (x) {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = [];
|
var path = [];
|
||||||
var nodes = {};
|
var nodes = {};
|
||||||
var push = function(key, node) {
|
var push = function(key, node) {
|
||||||
// we explicitly only store the first occurrence of each key
|
// we explicitly only store the first occurrence of each key
|
||||||
if (!(key in nodes)) {
|
if (!nodes.hasOwnProperty(key)) {
|
||||||
nodes[key] = node;
|
nodes[key] = node;
|
||||||
path.push(key);
|
path.push(key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var target = event.srcElement || event.target;
|
||||||
|
|
||||||
|
// Since you can only listen by tag, id or sigil, which are all
|
||||||
|
// attributes of an Element (the DOM interface), we unset the target
|
||||||
|
// if it isn't an Element (window and Document are Nodes but not Elements)
|
||||||
|
if (!target || !target.getAttribute) {
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
var cursor = target;
|
var cursor = target;
|
||||||
while (cursor) {
|
while (cursor && cursor.getAttribute) {
|
||||||
push('tag:' + cursor.nodeName.toLowerCase(), cursor);
|
push('tag:' + cursor.nodeName.toLowerCase(), cursor);
|
||||||
|
|
||||||
var id = cursor.id;
|
var id = cursor.id;
|
||||||
|
@ -1249,11 +1263,12 @@ JX.install('Stratcom', {
|
||||||
push('id:' + id, cursor);
|
push('id:' + id, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
var source = cursor.className || '';
|
var sigils = cursor.getAttribute('data-sigil');
|
||||||
// className is an SVGAnimatedString for SVG elements, use baseVal
|
if (sigils) {
|
||||||
var token = ((source.baseVal || source).match(this._matchName) || [])[1];
|
sigils = sigils.split(' ');
|
||||||
if (token) {
|
for (var ii = 0; ii < sigils.length; ii++) {
|
||||||
push(token, cursor);
|
push(sigils[ii], cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = cursor.parentNode;
|
cursor = cursor.parentNode;
|
||||||
|
@ -1264,16 +1279,10 @@ JX.install('Stratcom', {
|
||||||
etype = this._typeMap[etype];
|
etype = this._typeMap[etype];
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = {};
|
|
||||||
for (var key in nodes) {
|
|
||||||
data[key] = this.getData(nodes[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var proxy = new JX.Event()
|
var proxy = new JX.Event()
|
||||||
.setRawEvent(event)
|
.setRawEvent(event)
|
||||||
.setType(etype)
|
.setType(etype)
|
||||||
.setTarget(target)
|
.setTarget(target)
|
||||||
.setData(data)
|
|
||||||
.setNodes(nodes)
|
.setNodes(nodes)
|
||||||
.setPath(path.reverse());
|
.setPath(path.reverse());
|
||||||
|
|
||||||
|
@ -1408,40 +1417,6 @@ JX.install('Stratcom', {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach a sigil (and, optionally, metadata) to a node. Note that you can
|
|
||||||
* not overwrite, remove or replace a sigil.
|
|
||||||
*
|
|
||||||
* @param Node Node without any sigil.
|
|
||||||
* @param string Sigil to name the node with.
|
|
||||||
* @param object? Optional metadata object to attach to the node.
|
|
||||||
* @return void
|
|
||||||
* @task sigil
|
|
||||||
*/
|
|
||||||
sigilize : function(node, sigil, data) {
|
|
||||||
if (__DEV__) {
|
|
||||||
if (node.className.match(this._matchName)) {
|
|
||||||
throw new Error(
|
|
||||||
'JX.Stratcom.sigilize(<node>, ' + sigil + ', ...): ' +
|
|
||||||
'node already has a sigil, sigils may not be overwritten.');
|
|
||||||
}
|
|
||||||
if (typeof data != 'undefined' &&
|
|
||||||
(data === null || typeof data != 'object')) {
|
|
||||||
throw new Error(
|
|
||||||
'JX.Stratcom.sigilize(..., ..., <nonobject>): ' +
|
|
||||||
'data to attach to node is not an object. You must use ' +
|
|
||||||
'objects, not primitives, for metadata.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
JX.Stratcom._setData(node, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.className = 'FN_' + sigil + ' ' + node.className;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a node has a specific sigil.
|
* Determine if a node has a specific sigil.
|
||||||
*
|
*
|
||||||
|
@ -1452,75 +1427,120 @@ JX.install('Stratcom', {
|
||||||
* @task sigil
|
* @task sigil
|
||||||
*/
|
*/
|
||||||
hasSigil : function(node, sigil) {
|
hasSigil : function(node, sigil) {
|
||||||
if (!node.className) {
|
if (__DEV__) {
|
||||||
// Some nodes don't have a className, notably 'document'. We hit
|
if (!node || !node.getAttribute) {
|
||||||
// 'document' when following .parentNode chains, e.g. in
|
throw new Error(
|
||||||
// JX.DOM.nearest(), so exit early if we don't have a className to avoid
|
'JX.Stratcom.hasSigil(<non-element>, ...): ' +
|
||||||
// fataling on 'node.className.match' being undefined.
|
'node is not an element. Most likely, you\'re passing window or ' +
|
||||||
return false;
|
'document, which are not elements and can\'t have sigils.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (node.className.match(this._matchName) || [])[1] == sigil;
|
|
||||||
|
var sigils = node.getAttribute('data-sigil');
|
||||||
|
return sigils && (' ' + sigils + ' ').indexOf(' ' + sigil + ' ') > -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a sigil to a node.
|
||||||
|
*
|
||||||
|
* @param Node Node to add the sigil to.
|
||||||
|
* @param string Sigil to name the node with.
|
||||||
|
* @return void
|
||||||
|
* @task sigil
|
||||||
|
*/
|
||||||
|
addSigil: function(node, sigil) {
|
||||||
|
if (__DEV__) {
|
||||||
|
if (!node || !node.getAttribute) {
|
||||||
|
throw new Error(
|
||||||
|
'JX.Stratcom.addSigil(<non-element>, ...): ' +
|
||||||
|
'node is not an element. Most likely, you\'re passing window or ' +
|
||||||
|
'document, which are not elements and can\'t have sigils.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sigils = node.getAttribute('data-sigil');
|
||||||
|
if (sigils && !JX.Stratcom.hasSigil(node, sigil)) {
|
||||||
|
sigil = sigils + ' ' + sigil;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setAttribute('data-sigil', sigil);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a node's metadata.
|
* Retrieve a node's metadata.
|
||||||
*
|
*
|
||||||
* @param Node Node from which to retrieve data.
|
* @param Node Node from which to retrieve data.
|
||||||
* @return object Data attached to the node, or an empty dictionary if
|
* @return object Data attached to the node. If no data has been attached
|
||||||
* the node has no data attached. In this case, the empty
|
* to the node yet, an empty object will be returned, but
|
||||||
* dictionary is set as the node's metadata -- i.e.,
|
* subsequent calls to this method will always retrieve the
|
||||||
* subsequent calls to getData() will retrieve the same
|
* same object.
|
||||||
* object.
|
* @task meta
|
||||||
*
|
|
||||||
* @task sigil
|
|
||||||
*/
|
*/
|
||||||
getData : function(node) {
|
getData : function(node) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
if (!node) {
|
if (!node || !node.getAttribute) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'JX.Stratcom.getData(<empty>): ' +
|
'JX.Stratcom.getData(<non-element>): ' +
|
||||||
'you must provide a node to get associated data from.');
|
'node is not an element. Most likely, you\'re passing window or ' +
|
||||||
|
'document, which are not elements and can\'t have data.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var matches = (node.className || '').match(this._matchData);
|
var meta_id = (node.getAttribute('data-meta') || '').split('_');
|
||||||
if (matches) {
|
if (meta_id[0] && meta_id[1]) {
|
||||||
var block = this._data[matches[1]];
|
var block = this._data[meta_id[0]];
|
||||||
var index = matches[2];
|
var index = meta_id[1];
|
||||||
if (block && (index in block)) {
|
if (block && (index in block)) {
|
||||||
return block[index];
|
return block[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return JX.Stratcom._setData(node, {});
|
var data = {};
|
||||||
},
|
if (!this._data[1]) { // data block 1 is reserved for JavaScript
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
* @task internal
|
|
||||||
*/
|
|
||||||
allocateMetadataBlock : function() {
|
|
||||||
return this._dataBlock++;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach metadata to a node. This data can later be retrieved through
|
|
||||||
* @{JX.Stratcom.getData()}, or @{JX.Event.getData()}.
|
|
||||||
*
|
|
||||||
* @param Node Node which data should be attached to.
|
|
||||||
* @param object Data to attach.
|
|
||||||
* @return object Attached data.
|
|
||||||
*
|
|
||||||
* @task internal
|
|
||||||
*/
|
|
||||||
_setData : function(node, data) {
|
|
||||||
if (!this._data[1]) { // data block 1 is reserved for javascript
|
|
||||||
this._data[1] = {};
|
this._data[1] = {};
|
||||||
}
|
}
|
||||||
this._data[1][this._dataIndex] = data;
|
this._data[1][this._dataIndex] = data;
|
||||||
node.className = 'FD_1_' + (this._dataIndex++) + ' ' + node.className;
|
node.setAttribute('data-meta', '1_' + (this._dataIndex++));
|
||||||
return data;
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add data to a node's metadata.
|
||||||
|
*
|
||||||
|
* @param Node Node which data should be attached to.
|
||||||
|
* @param object Data to add to the node's metadata.
|
||||||
|
* @return object Data attached to the node that is returned by
|
||||||
|
* JX.Stratcom.getData().
|
||||||
|
* @task meta
|
||||||
|
*/
|
||||||
|
addData : function(node, data) {
|
||||||
|
if (__DEV__) {
|
||||||
|
if (!node || !node.getAttribute) {
|
||||||
|
throw new Error(
|
||||||
|
'JX.Stratcom.addData(<non-element>, ...): ' +
|
||||||
|
'node is not an element. Most likely, you\'re passing window or ' +
|
||||||
|
'document, which are not elements and can\'t have sigils.');
|
||||||
|
}
|
||||||
|
if (!data || typeof data != 'object') {
|
||||||
|
throw new Error(
|
||||||
|
'JX.Stratcom.addData(..., <nonobject>): ' +
|
||||||
|
'data to attach to node is not an object. You must use ' +
|
||||||
|
'objects, not primitives, for metadata.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JX.copy(JX.Stratcom.getData(node), data);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task internal
|
||||||
|
*/
|
||||||
|
allocateMetadataBlock : function() {
|
||||||
|
return this._dataBlock++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1535,7 +1555,7 @@ JX.install('Stratcom', {
|
||||||
|
|
||||||
JX.behavior = function(name, control_function) {
|
JX.behavior = function(name, control_function) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
if (name in JX.behavior._behaviors) {
|
if (JX.behavior._behaviors.hasOwnProperty(name)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'JX.behavior("'+name+'", ...): '+
|
'JX.behavior("'+name+'", ...): '+
|
||||||
'behavior is already registered.');
|
'behavior is already registered.');
|
||||||
|
@ -1566,7 +1586,7 @@ JX.initBehaviors = function(map) {
|
||||||
}
|
}
|
||||||
var configs = map[name];
|
var configs = map[name];
|
||||||
if (!configs.length) {
|
if (!configs.length) {
|
||||||
if (name in JX.behavior._initialized) {
|
if (JX.behavior._initialized.hasOwnProperty(name)) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
configs = [null];
|
configs = [null];
|
||||||
|
@ -1827,7 +1847,7 @@ JX.install('Request', {
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
JX.Stratcom.listen('unload', 'tag:window', JX.Request.shutdown);
|
JX.Stratcom.listen('unload', null, JX.Request.shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -2410,8 +2430,12 @@ JX.$N = function(tag, attr, content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr.sigil) {
|
if (attr.sigil) {
|
||||||
JX.Stratcom.sigilize(node, attr.sigil, attr.meta);
|
JX.Stratcom.addSigil(node, attr.sigil);
|
||||||
delete attr.sigil;
|
delete attr.sigil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr.meta) {
|
||||||
|
JX.Stratcom.addData(node, attr.meta);
|
||||||
delete attr.meta;
|
delete attr.meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2421,17 +2445,6 @@ JX.$N = function(tag, attr, content) {
|
||||||
'$N(' + tag + ', ...): ' +
|
'$N(' + tag + ', ...): ' +
|
||||||
'use the key "meta" to specify metadata, not "data" or "metadata".');
|
'use the key "meta" to specify metadata, not "data" or "metadata".');
|
||||||
}
|
}
|
||||||
if (attr.meta) {
|
|
||||||
throw new Error(
|
|
||||||
'$N(' + tag + ', ...): ' +
|
|
||||||
'if you specify "meta" metadata, you must also specify a "sigil".');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent sigil from being wiped by blind copying the className
|
|
||||||
if (attr.className) {
|
|
||||||
JX.DOM.alterClass(node, attr.className, true);
|
|
||||||
delete attr.className;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JX.copy(node, attr);
|
JX.copy(node, attr);
|
||||||
|
@ -2595,7 +2608,7 @@ JX.install('DOM', {
|
||||||
* @author jgabbard
|
* @author jgabbard
|
||||||
*/
|
*/
|
||||||
nearest : function(node, sigil) {
|
nearest : function(node, sigil) {
|
||||||
while (node && !JX.Stratcom.hasSigil(node, sigil)) {
|
while (node && node.getAttribute && !JX.Stratcom.hasSigil(node, sigil)) {
|
||||||
node = node.parentNode;
|
node = node.parentNode;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
|
|
3
webroot/rsrc/js/javelin/javelin.min.js
vendored
3
webroot/rsrc/js/javelin/javelin.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -86,7 +86,7 @@ JX.install('Typeahead', {
|
||||||
'mousedown',
|
'mousedown',
|
||||||
'tag:a',
|
'tag:a',
|
||||||
JX.bind(this, function(e) {
|
JX.bind(this, function(e) {
|
||||||
this._choose(e.getTarget());
|
this._choose(e.getNode('tag:a'));
|
||||||
e.prevent();
|
e.prevent();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -601,20 +601,25 @@ JX.install('TypeaheadSource', {
|
||||||
var n = Math.min(this.getMaximumResultCount(), hits.length);
|
var n = Math.min(this.getMaximumResultCount(), hits.length);
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
for (var kk = 0; kk < n; kk++) {
|
for (var kk = 0; kk < n; kk++) {
|
||||||
var data = this._raw[hits[kk]];
|
nodes.push(this.createNode(this._raw[hits[kk]]));
|
||||||
nodes.push(JX.$N(
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
href: data.uri,
|
|
||||||
name: data.name,
|
|
||||||
rel: data.id,
|
|
||||||
className: 'jx-result'
|
|
||||||
},
|
|
||||||
data.display));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._typeahead.showResults(nodes);
|
this._typeahead.showResults(nodes);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
createNode : function(data) {
|
||||||
|
return JX.$N(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
href: data.uri,
|
||||||
|
name: data.name,
|
||||||
|
rel: data.id,
|
||||||
|
className: 'jx-result'
|
||||||
|
},
|
||||||
|
data.display
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
normalize : function(str) {
|
normalize : function(str) {
|
||||||
return (this.getNormalizer() || JX.bag())(str);
|
return (this.getNormalizer() || JX.bag())(str);
|
||||||
},
|
},
|
||||||
|
@ -850,11 +855,7 @@ JX.install('Tokenizer', {
|
||||||
this._tokens = [];
|
this._tokens = [];
|
||||||
this._tokenMap = {};
|
this._tokenMap = {};
|
||||||
|
|
||||||
var focus = JX.$N('input', {
|
var focus = this.buildInput(this._orig.value);
|
||||||
className: 'jx-tokenizer-input',
|
|
||||||
type: 'text',
|
|
||||||
value: this._orig.value
|
|
||||||
});
|
|
||||||
this._focus = focus;
|
this._focus = focus;
|
||||||
|
|
||||||
JX.DOM.listen(
|
JX.DOM.listen(
|
||||||
|
@ -870,8 +871,8 @@ JX.install('Tokenizer', {
|
||||||
JX.bind(
|
JX.bind(
|
||||||
this,
|
this,
|
||||||
function(e) {
|
function(e) {
|
||||||
if (e.getNodes().remove) {
|
if (e.getNode('remove')) {
|
||||||
this._remove(e.getData().token.key);
|
this._remove(e.getNodeData('token').key);
|
||||||
} else if (e.getTarget() == this._root) {
|
} else if (e.getTarget() == this._root) {
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
@ -1011,20 +1012,7 @@ JX.install('Tokenizer', {
|
||||||
|
|
||||||
var focus = this._focus;
|
var focus = this._focus;
|
||||||
var root = this._root;
|
var root = this._root;
|
||||||
|
var token = this.buildToken(key, value);
|
||||||
var token = JX.$N('a', {
|
|
||||||
className: 'jx-tokenizer-token'
|
|
||||||
}, value);
|
|
||||||
|
|
||||||
var input = JX.$N('input', {
|
|
||||||
type: 'hidden',
|
|
||||||
value: key,
|
|
||||||
name: this._orig.name+'['+(this._seq++)+']'
|
|
||||||
});
|
|
||||||
|
|
||||||
var remove = JX.$N('a', {
|
|
||||||
className: 'jx-tokenizer-x'
|
|
||||||
}, JX.HTML('×'));
|
|
||||||
|
|
||||||
this._tokenMap[key] = {
|
this._tokenMap[key] = {
|
||||||
value : value,
|
value : value,
|
||||||
|
@ -1033,17 +1021,42 @@ JX.install('Tokenizer', {
|
||||||
};
|
};
|
||||||
this._tokens.push(key);
|
this._tokens.push(key);
|
||||||
|
|
||||||
JX.Stratcom.sigilize(token, 'token', {key : key});
|
|
||||||
JX.Stratcom.sigilize(remove, 'remove');
|
|
||||||
|
|
||||||
token.appendChild(input);
|
|
||||||
token.appendChild(remove);
|
|
||||||
|
|
||||||
root.insertBefore(token, focus);
|
root.insertBefore(token, focus);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
buildInput: function(value) {
|
||||||
|
return JX.$N('input', {
|
||||||
|
className: 'jx-tokenizer-input',
|
||||||
|
type: 'text',
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a token based on a key and value. The "token" and "remove"
|
||||||
|
* sigils are observed by a listener in start().
|
||||||
|
*/
|
||||||
|
buildToken: function(key, value) {
|
||||||
|
var input = JX.$N('input', {
|
||||||
|
type: 'hidden',
|
||||||
|
value: key,
|
||||||
|
name: this._orig.name + '[' + (this._seq++) + ']'
|
||||||
|
});
|
||||||
|
|
||||||
|
var remove = JX.$N('a', {
|
||||||
|
className: 'jx-tokenizer-x',
|
||||||
|
sigil: 'remove'
|
||||||
|
}, JX.HTML('×'));
|
||||||
|
|
||||||
|
return JX.$N('a', {
|
||||||
|
className: 'jx-tokenizer-token',
|
||||||
|
sigil: 'token',
|
||||||
|
meta: {key: key}
|
||||||
|
}, [value, input, remove]);
|
||||||
|
},
|
||||||
|
|
||||||
getTokens : function() {
|
getTokens : function() {
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var key in this._tokenMap) {
|
for (var key in this._tokenMap) {
|
||||||
|
|
2
webroot/rsrc/js/javelin/typeahead.min.js
vendored
2
webroot/rsrc/js/javelin/typeahead.min.js
vendored
File diff suppressed because one or more lines are too long
239
webroot/rsrc/js/javelin/workflow.dev.js
Normal file
239
webroot/rsrc/js/javelin/workflow.dev.js
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
/** @provides javelin-workflow-dev */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires javelin-install javelin-vector javelin-dom
|
||||||
|
* @provides javelin-mask
|
||||||
|
* @javelin
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a transparent "mask" over the page; used by Workflow to draw visual
|
||||||
|
* attention to modal dialogs.
|
||||||
|
*/
|
||||||
|
JX.install('Mask', {
|
||||||
|
statics : {
|
||||||
|
_depth : 0,
|
||||||
|
_mask : null,
|
||||||
|
show : function() {
|
||||||
|
if (!JX.Mask._depth) {
|
||||||
|
JX.Mask._mask = JX.$N('div', {className: 'jx-mask'});
|
||||||
|
document.body.appendChild(JX.Mask._mask);
|
||||||
|
JX.$V.getDocument().setDim(JX.Mask._mask);
|
||||||
|
}
|
||||||
|
++JX.Mask._depth;
|
||||||
|
},
|
||||||
|
hide : function() {
|
||||||
|
--JX.Mask._depth;
|
||||||
|
if (!JX.Mask._depth) {
|
||||||
|
JX.DOM.remove(JX.Mask._mask);
|
||||||
|
JX.Mask._mask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* @requires javelin-stratcom
|
||||||
|
* javelin-request
|
||||||
|
* javelin-dom
|
||||||
|
* javelin-vector
|
||||||
|
* javelin-install
|
||||||
|
* javelin-util
|
||||||
|
* javelin-mask
|
||||||
|
* @provides javelin-workflow
|
||||||
|
* @javelin
|
||||||
|
*/
|
||||||
|
|
||||||
|
JX.install('Workflow', {
|
||||||
|
construct : function(uri, data) {
|
||||||
|
if (__DEV__) {
|
||||||
|
if (!uri || uri == '#') {
|
||||||
|
throw new Error(
|
||||||
|
'new JX.Workflow(<?>, ...): '+
|
||||||
|
'bogus URI provided when creating workflow.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setURI(uri);
|
||||||
|
this.setData(data || {});
|
||||||
|
},
|
||||||
|
|
||||||
|
events : ['error', 'finally', 'submit'],
|
||||||
|
|
||||||
|
statics : {
|
||||||
|
_stack : [],
|
||||||
|
newFromForm : function(form, data) {
|
||||||
|
var inputs = [].concat(
|
||||||
|
JX.DOM.scry(form, 'input'),
|
||||||
|
JX.DOM.scry(form, 'button'),
|
||||||
|
JX.DOM.scry(form, 'textarea'));
|
||||||
|
|
||||||
|
for (var ii = 0; ii < inputs.length; ii++) {
|
||||||
|
if (inputs[ii].disabled) {
|
||||||
|
delete inputs[ii];
|
||||||
|
} else {
|
||||||
|
inputs[ii].disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var workflow = new JX.Workflow(
|
||||||
|
form.getAttribute('action'),
|
||||||
|
JX.copy(data || {}, JX.DOM.serialize(form)));
|
||||||
|
workflow.setMethod(form.getAttribute('method'));
|
||||||
|
workflow.listen('finally', function() {
|
||||||
|
for (var ii = 0; ii < inputs.length; ii++) {
|
||||||
|
inputs[ii] && (inputs[ii].disabled = false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return workflow;
|
||||||
|
},
|
||||||
|
newFromLink : function(link) {
|
||||||
|
var workflow = new JX.Workflow(link.href);
|
||||||
|
return workflow;
|
||||||
|
},
|
||||||
|
_push : function(workflow) {
|
||||||
|
JX.Mask.show();
|
||||||
|
JX.Workflow._stack.push(workflow);
|
||||||
|
},
|
||||||
|
_pop : function() {
|
||||||
|
var dialog = JX.Workflow._stack.pop();
|
||||||
|
(dialog.getCloseHandler() || JX.bag)();
|
||||||
|
dialog._destroy();
|
||||||
|
JX.Mask.hide();
|
||||||
|
},
|
||||||
|
disable : function() {
|
||||||
|
JX.Workflow._disabled = true;
|
||||||
|
},
|
||||||
|
_onbutton : function(event) {
|
||||||
|
|
||||||
|
if (JX.Stratcom.pass()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JX.Workflow._disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var t = event.getTarget();
|
||||||
|
if (t.name == '__cancel__' || t.name == '__close__') {
|
||||||
|
JX.Workflow._pop();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var form = event.getNode('jx-dialog');
|
||||||
|
var data = JX.DOM.serialize(form);
|
||||||
|
data[t.name] = true;
|
||||||
|
data.__wflow__ = true;
|
||||||
|
|
||||||
|
var active = JX.Workflow._stack[JX.Workflow._stack.length - 1];
|
||||||
|
var e = active.invoke('submit', {form: form, data: data});
|
||||||
|
if (!e.getStopped()) {
|
||||||
|
active._destroy();
|
||||||
|
active
|
||||||
|
.setURI(form.getAttribute('action') || active.getURI())
|
||||||
|
.setData(data)
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.prevent();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
members : {
|
||||||
|
_root : null,
|
||||||
|
_pushed : false,
|
||||||
|
_onload : function(r) {
|
||||||
|
// It is permissible to send back a falsey redirect to force a page
|
||||||
|
// reload, so we need to take this branch if the key is present.
|
||||||
|
if (r && (typeof r.redirect != 'undefined')) {
|
||||||
|
JX.go(r.redirect, true);
|
||||||
|
} else if (r && r.dialog) {
|
||||||
|
this._push();
|
||||||
|
this._root = JX.$N(
|
||||||
|
'div',
|
||||||
|
{className: 'jx-client-dialog'},
|
||||||
|
JX.HTML(r.dialog));
|
||||||
|
JX.DOM.listen(
|
||||||
|
this._root,
|
||||||
|
'click',
|
||||||
|
'tag:button',
|
||||||
|
JX.Workflow._onbutton);
|
||||||
|
document.body.appendChild(this._root);
|
||||||
|
var d = JX.$V.getDim(this._root);
|
||||||
|
var v = JX.$V.getViewport();
|
||||||
|
var s = JX.$V.getScroll();
|
||||||
|
JX.$V((v.x - d.x) / 2, s.y + 100).setPos(this._root);
|
||||||
|
try {
|
||||||
|
JX.DOM.focus(JX.DOM.find(this._root, 'button', '__default__'));
|
||||||
|
var inputs = JX.DOM.scry(this._root, 'input')
|
||||||
|
.concat(JX.DOM.scry(this._root, 'textarea'));
|
||||||
|
var miny = Number.POSITIVE_INFINITY;
|
||||||
|
var target = null;
|
||||||
|
for (var ii = 0; ii < inputs.length; ++ii) {
|
||||||
|
if (inputs[ii].type != 'hidden') {
|
||||||
|
// Find the topleft-most displayed element.
|
||||||
|
var p = JX.$V(inputs[ii]);
|
||||||
|
if (p.y < miny) {
|
||||||
|
miny = p.y;
|
||||||
|
target = inputs[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target && JX.DOM.focus(target);
|
||||||
|
} catch (_ignored) {}
|
||||||
|
} else if (this.getHandler()) {
|
||||||
|
this.getHandler()(r);
|
||||||
|
this._pop();
|
||||||
|
} else if (r) {
|
||||||
|
if (__DEV__) {
|
||||||
|
throw new Error('Response to workflow request went unhandled.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_push : function() {
|
||||||
|
if (!this._pushed) {
|
||||||
|
this._pushed = true;
|
||||||
|
JX.Workflow._push(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_pop : function() {
|
||||||
|
if (this._pushed) {
|
||||||
|
this._pushed = false;
|
||||||
|
JX.Workflow._pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_destroy : function() {
|
||||||
|
if (this._root) {
|
||||||
|
JX.DOM.remove(this._root);
|
||||||
|
this._root = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
start : function() {
|
||||||
|
var uri = this.getURI();
|
||||||
|
var method = this.getMethod();
|
||||||
|
var r = new JX.Request(uri, JX.bind(this, this._onload));
|
||||||
|
r.setData(this.getData());
|
||||||
|
r.setDataSerializer(this.getDataSerializer());
|
||||||
|
if (method) {
|
||||||
|
r.setMethod(method);
|
||||||
|
}
|
||||||
|
r.listen('finally', JX.bind(this, this.invoke, 'finally'));
|
||||||
|
r.listen('error', JX.bind(this, function(error) {
|
||||||
|
var e = this.invoke('error', error);
|
||||||
|
if (e.getStopped()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: Default error behavior? On Facebook Lite, we just shipped the
|
||||||
|
// user to "/error/". We could emit a blanket 'workflow-failed' type
|
||||||
|
// event instead.
|
||||||
|
}));
|
||||||
|
r.send();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
properties : {
|
||||||
|
handler : null,
|
||||||
|
closeHandler : null,
|
||||||
|
data : null,
|
||||||
|
dataSerializer : null,
|
||||||
|
method : null,
|
||||||
|
URI : null
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
3
webroot/rsrc/js/javelin/workflow.min.js
vendored
Normal file
3
webroot/rsrc/js/javelin/workflow.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/** @provides javelin-workflow-prod */
|
||||||
|
|
||||||
|
JX.install('Mask',{statics:{_a:0,_b:null,show:function(){if(!JX.Mask._a){JX.Mask._b=JX.$N('div',{className:'jx-mask'});document.body.appendChild(JX.Mask._b);JX.$V.getDocument().setDim(JX.Mask._b);}++JX.Mask._a;},hide:function(){--JX.Mask._a;if(!JX.Mask._a){JX.DOM.remove(JX.Mask._b);JX.Mask._b=null;}}}});JX.install('Workflow',{construct:function(b,a){this.setURI(b);this.setData(a||{});},events:['error','finally','submit'],statics:{_c:[],newFromForm:function(b,a){var d=[].concat(JX.DOM.scry(b,'input'),JX.DOM.scry(b,'button'),JX.DOM.scry(b,'textarea'));for(var c=0;c<d.length;c++)if(d[c].disabled){delete d[c];}else d[c].disabled=true;var e=new JX.Workflow(b.getAttribute('action'),JX.copy(a||{},JX.DOM.serialize(b)));e.setMethod(b.getAttribute('method'));e.listen('finally',function(){for(var f=0;f<d.length;f++)d[f]&&(d[f].disabled=false);});return e;},newFromLink:function(a){var b=new JX.Workflow(a.href);return b;},_d:function(a){JX.Mask.show();JX.Workflow._c.push(a);},_e:function(){var a=JX.Workflow._c.pop();(a.getCloseHandler()||JX.bag)();a._f();JX.Mask.hide();},disable:function(){JX.Workflow._g=true;},_h:function(event){if(JX.Stratcom.pass())return;if(JX.Workflow._g)return;var e=event.getTarget();if(e.name=='__cancel__'||e.name=='__close__'){JX.Workflow._e();}else{var d=event.getNode('jx-dialog');var b=JX.DOM.serialize(d);b[e.name]=true;b.__wflow__=true;var a=JX.Workflow._c[JX.Workflow._c.length-1];var c=a.invoke('submit',{form:d,data:b});if(!c.getStopped()){a._f();a.setURI(d.getAttribute('action')||a.getURI()).setData(b).start();}}event.prevent();}},members:{_i:null,_j:false,_k:function(c){if(c&&(typeof c.redirect!='undefined')){JX.go(c.redirect,true);}else if(c&&c.dialog){this._d();this._i=JX.$N('div',{className:'jx-client-dialog'},JX.HTML(c.dialog));JX.DOM.listen(this._i,'click','tag:button',JX.Workflow._h);document.body.appendChild(this._i);var b=JX.$V.getDim(this._i);var e=JX.$V.getViewport();var d=JX.$V.getScroll();JX.$V((e.x-b.x)/2,d.y+100).setPos(this._i);try{JX.DOM.focus(JX.DOM.find(this._i,'button','__default__'));var inputs=JX.DOM.scry(this._i,'input').concat(JX.DOM.scry(this._i,'textarea'));var miny=Number.POSITIVE_INFINITY;var target=null;for(var ii=0;ii<inputs.length;++ii)if(inputs[ii].type!='hidden'){var p=JX.$V(inputs[ii]);if(p.y<miny){miny=p.y;target=inputs[ii];}}target&&JX.DOM.focus(target);}catch(a){}}else if(this.getHandler()){this.getHandler()(c);this._e();}},_d:function(){if(!this._j){this._j=true;JX.Workflow._d(this);}},_e:function(){if(this._j){this._j=false;JX.Workflow._e();}},_f:function(){if(this._i){JX.DOM.remove(this._i);this._i=null;}},start:function(){var c=this.getURI();var a=this.getMethod();var b=new JX.Request(c,JX.bind(this,this._k));b.setData(this.getData());b.setDataSerializer(this.getDataSerializer());if(a)b.setMethod(a);b.listen('finally',JX.bind(this,this.invoke,'finally'));b.listen('error',JX.bind(this,function(e){var d=this.invoke('error',e);if(d.getStopped())return;}));b.send();}},properties:{handler:null,closeHandler:null,data:null,dataSerializer:null,method:null,URI:null}});
|
Loading…
Reference in a new issue