Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/infrastructure/celerity/CelerityResourceMap.php b/src/infrastructure/celerity/CelerityResourceMap.php
index c9beffc2d3..030fd3233d 100644
--- a/src/infrastructure/celerity/CelerityResourceMap.php
+++ b/src/infrastructure/celerity/CelerityResourceMap.php
@@ -1,243 +1,243 @@
<?php
/**
* Interface to the static resource map, which is a graph of available
* resources, resource dependencies, and packaging information. You generally do
* not need to invoke it directly; instead, you call higher-level Celerity APIs
* and it uses the resource map to satisfy your requests.
*/
final class CelerityResourceMap {
private static $instances = array();
private $resources;
private $symbolMap;
private $requiresMap;
private $packageMap;
private $nameMap;
private $hashMap;
public function __construct(CelerityResources $resources) {
$this->resources = $resources;
$map = $resources->loadMap();
$this->symbolMap = idx($map, 'symbols', array());
$this->requiresMap = idx($map, 'requires', array());
$this->packageMap = idx($map, 'packages', array());
$this->nameMap = idx($map, 'names', array());
// We derive these reverse maps at runtime.
$this->hashMap = array_flip($this->nameMap);
$this->componentMap = array();
foreach ($this->packageMap as $package_name => $symbols) {
foreach ($symbols as $symbol) {
$this->componentMap[$symbol] = $package_name;
}
}
}
public static function getNamedInstance($name) {
if (empty(self::$instances[$name])) {
$resources_list = CelerityPhysicalResources::getAll();
if (empty($resources_list[$name])) {
throw new Exception(
pht(
'No resource source exists with name "%s"!', $name));
}
$instance = new CelerityResourceMap($resources_list[$name]);
self::$instances[$name] = $instance;
}
return self::$instances[$name];
}
public function getPackagedNamesForSymbols(array $symbols) {
$resolved = $this->resolveResources($symbols);
return $this->packageResources($resolved);
}
private function resolveResources(array $symbols) {
$map = array();
foreach ($symbols as $symbol) {
if (!empty($map[$symbol])) {
continue;
}
$this->resolveResource($map, $symbol);
}
return $map;
}
private function resolveResource(array &$map, $symbol) {
if (empty($this->symbolMap[$symbol])) {
throw new Exception(
pht(
'Attempting to resolve unknown resource, "%s".',
$symbol));
}
$hash = $this->symbolMap[$symbol];
$map[$symbol] = $hash;
if (isset($this->requiresMap[$hash])) {
$requires = $this->requiresMap[$hash];
} else {
$requires = array();
}
foreach ($requires as $required_symbol) {
if (!empty($map[$required_symbol])) {
continue;
}
$this->resolveResource($map, $required_symbol);
}
}
private function packageResources(array $resolved_map) {
$packaged = array();
$handled = array();
foreach ($resolved_map as $symbol => $hash) {
if (isset($handled[$symbol])) {
continue;
}
if (empty($this->componentMap[$symbol])) {
$packaged[] = $this->hashMap[$hash];
} else {
$package_name = $this->componentMap[$symbol];
$packaged[] = $package_name;
$package_symbols = $this->packageMap[$package_name];
foreach ($package_symbols as $package_symbol) {
$handled[$package_symbol] = true;
}
}
}
return $packaged;
}
public function getResourceDataForName($resource_name) {
return $this->resources->getResourceData($resource_name);
}
public function getResourceNamesForPackageName($package_name) {
$package_symbols = idx($this->packageMap, $package_name);
if (!$package_symbols) {
return null;
}
$resource_names = array();
foreach ($package_symbols as $symbol) {
$resource_names[] = $this->hashMap[$this->symbolMap[$symbol]];
}
return $resource_names;
}
/**
* Get the epoch timestamp of the last modification time of a symbol.
*
* @param string Resource symbol to lookup.
* @return int Epoch timestamp of last resource modification.
*/
public function getModifiedTimeForName($name) {
if ($this->isPackageResource($name)) {
$names = array();
foreach ($this->packageMap[$name] as $symbol) {
$names[] = $this->getResourceNameForSymbol($symbol);
}
} else {
$names = array($name);
}
$mtime = 0;
foreach ($names as $name) {
$mtime = max($mtime, $this->resources->getResourceModifiedTime($name));
}
return $mtime;
}
/**
* Return the absolute URI for the resource associated with a symbol. This
* method is fairly low-level and ignores packaging.
*
* @param string Resource symbol to lookup.
* @return string|null Resource URI, or null if the symbol is unknown.
*/
public function getURIForSymbol($symbol) {
$hash = idx($this->symbolMap, $symbol);
return $this->getURIForHash($hash);
}
/**
* Return the absolute URI for the resource associated with a resource name.
* This method is fairly low-level and ignores packaging.
*
* @param string Resource name to lookup.
* @return string|null Resource URI, or null if the name is unknown.
*/
public function getURIForName($name) {
$hash = idx($this->nameMap, $name);
return $this->getURIForHash($hash);
}
/**
* Return the absolute URI for a resource, identified by hash.
* This method is fairly low-level and ignores packaging.
*
* @param string Resource hash to lookup.
* @return string|null Resource URI, or null if the hash is unknown.
*/
private function getURIForHash($hash) {
if ($hash === null) {
return null;
}
return $this->resources->getResourceURI($hash, $this->hashMap[$hash]);
}
/**
* Return the resource symbols required by a named resource.
*
* @param string Resource name to lookup.
* @return list<string>|null List of required symbols, or null if the name
* is unknown.
*/
public function getRequiredSymbolsForName($name) {
- $hash = idx($this->symbolMap, $name);
+ $hash = idx($this->nameMap, $name);
if ($hash === null) {
return null;
}
return idx($this->requiresMap, $hash, array());
}
/**
* Return the resource name for a given symbol.
*
* @param string Resource symbol to lookup.
* @return string|null Resource name, or null if the symbol is unknown.
*/
public function getResourceNameForSymbol($symbol) {
$hash = idx($this->symbolMap, $symbol);
return idx($this->hashMap, $hash);
}
public function isPackageResource($name) {
return isset($this->packageMap[$name]);
}
public function getResourceTypeForName($name) {
return $this->resources->getResourceType($name);
}
}
diff --git a/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php b/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php
index b979c9e87b..4c73e10d8e 100644
--- a/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php
+++ b/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php
@@ -1,265 +1,265 @@
<?php
final class PhabricatorJavelinLinter extends ArcanistLinter {
private $symbols = array();
private $symbolsBinary;
private $haveWarnedAboutBinary;
const LINT_PRIVATE_ACCESS = 1;
const LINT_MISSING_DEPENDENCY = 2;
const LINT_UNNECESSARY_DEPENDENCY = 3;
const LINT_UNKNOWN_DEPENDENCY = 4;
const LINT_MISSING_BINARY = 5;
private function getBinaryPath() {
if ($this->symbolsBinary === null) {
list($err, $stdout) = exec_manual('which javelinsymbols');
$this->symbolsBinary = ($err ? false : rtrim($stdout));
}
return $this->symbolsBinary;
}
public function willLintPaths(array $paths) {
if (!$this->getBinaryPath()) {
return;
}
$root = dirname(phutil_get_library_root('phabricator'));
require_once $root.'/scripts/__init_script__.php';
$futures = array();
foreach ($paths as $path) {
if ($this->shouldIgnorePath($path)) {
continue;
}
$future = $this->newSymbolsFuture($path);
$futures[$path] = $future;
}
foreach (Futures($futures)->limit(8) as $path => $future) {
$this->symbols[$path] = $future->resolvex();
}
}
public function getLinterName() {
return 'JAVELIN';
}
public function getLintSeverityMap() {
return array(
self::LINT_MISSING_BINARY => ArcanistLintSeverity::SEVERITY_WARNING,
);
}
public function getLintNameMap() {
return array(
self::LINT_PRIVATE_ACCESS => 'Private Method/Member Access',
self::LINT_MISSING_DEPENDENCY => 'Missing Javelin Dependency',
self::LINT_UNNECESSARY_DEPENDENCY => 'Unnecessary Javelin Dependency',
self::LINT_UNKNOWN_DEPENDENCY => 'Unknown Javelin Dependency',
self::LINT_MISSING_BINARY => '`javelinsymbols` Not In Path',
);
}
public function getCacheGranularity() {
return ArcanistLinter::GRANULARITY_REPOSITORY;
}
public function getCacheVersion() {
$version = '0';
$binary_path = $this->getBinaryPath();
if ($binary_path) {
$version .= '-'.md5_file($binary_path);
}
return $version;
}
private function shouldIgnorePath($path) {
return preg_match('@/__tests__/|externals/javelin/docs/@', $path);
}
public function lintPath($path) {
if ($this->shouldIgnorePath($path)) {
return;
}
if (!$this->symbolsBinary) {
if (!$this->haveWarnedAboutBinary) {
$this->haveWarnedAboutBinary = true;
// TODO: Write build documentation for the Javelin binaries and point
// the user at it.
$this->raiseLintAtLine(
1,
0,
self::LINT_MISSING_BINARY,
"The 'javelinsymbols' binary in the Javelin project is not ".
"available in \$PATH, so the Javelin linter can't run. This ".
"isn't a big concern, but means some Javelin problems can't be ".
"automatically detected.");
}
return;
}
list($uses, $installs) = $this->getUsedAndInstalledSymbolsForPath($path);
foreach ($uses as $symbol => $line) {
$parts = explode('.', $symbol);
foreach ($parts as $part) {
if ($part[0] == '_' && $part[1] != '_') {
$base = implode('.', array_slice($parts, 0, 2));
if (!array_key_exists($base, $installs)) {
$this->raiseLintAtLine(
$line,
0,
self::LINT_PRIVATE_ACCESS,
"This file accesses private symbol '{$symbol}' across file ".
"boundaries. You may only access private members and methods ".
"from the file where they are defined.");
}
break;
}
}
}
if ($this->getEngine()->getCommitHookMode()) {
// Don't do the dependency checks in commit-hook mode because we won't
// have an available working copy.
return;
}
$external_classes = array();
foreach ($uses as $symbol => $line) {
$parts = explode('.', $symbol);
$class = implode('.', array_slice($parts, 0, 2));
if (!array_key_exists($class, $external_classes) &&
!array_key_exists($class, $installs)) {
$external_classes[$class] = $line;
}
}
$celerity = CelerityResourceMap::getNamedInstance('phabricator');
$path = preg_replace(
'@^externals/javelinjs/src/@',
'webroot/rsrc/js/javelin/',
$path);
$need = $external_classes;
- $resource_name = substr($path, strlen('webroot'));
+ $resource_name = substr($path, strlen('webroot/'));
$requires = $celerity->getRequiredSymbolsForName($resource_name);
if (!$requires) {
$requires = array();
}
foreach ($requires as $key => $requires_symbol) {
$requires_name = $celerity->getResourceNameForSymbol($requires_symbol);
if ($requires_name === null) {
$this->raiseLintAtLine(
0,
0,
self::LINT_UNKNOWN_DEPENDENCY,
"This file @requires component '{$requires_symbol}', but it does ".
"not exist. You may need to rebuild the Celerity map.");
unset($requires[$key]);
continue;
}
if (preg_match('/\\.css$/', $requires_name)) {
// If JS requires CSS, just assume everything is fine.
unset($requires[$key]);
} else {
- $symbol_path = 'webroot'.$requires_name;
+ $symbol_path = 'webroot/'.$requires_name;
list($ignored, $req_install) = $this->getUsedAndInstalledSymbolsForPath(
$symbol_path);
if (array_intersect_key($req_install, $external_classes)) {
$need = array_diff_key($need, $req_install);
unset($requires[$key]);
}
}
}
foreach ($need as $class => $line) {
$this->raiseLintAtLine(
$line,
0,
self::LINT_MISSING_DEPENDENCY,
"This file uses '{$class}' but does not @requires the component ".
"which installs it. You may need to rebuild the Celerity map.");
}
foreach ($requires as $component) {
$this->raiseLintAtLine(
0,
0,
self::LINT_UNNECESSARY_DEPENDENCY,
"This file @requires component '{$component}' but does not use ".
"anything it provides.");
}
}
private function loadSymbols($path) {
if (empty($this->symbols[$path])) {
$this->symbols[$path] = $this->newSymbolsFuture($path)->resolvex();
}
return $this->symbols[$path];
}
private function newSymbolsFuture($path) {
$future = new ExecFuture('javelinsymbols # %s', $path);
$future->write($this->getData($path));
return $future;
}
private function getUsedAndInstalledSymbolsForPath($path) {
list($symbols) = $this->loadSymbols($path);
$symbols = trim($symbols);
$uses = array();
$installs = array();
if (empty($symbols)) {
// This file has no symbols.
return array($uses, $installs);
}
$symbols = explode("\n", trim($symbols));
foreach ($symbols as $line) {
$matches = null;
if (!preg_match('/^([?+\*])([^:]*):(\d+)$/', $line, $matches)) {
throw new Exception(
"Received malformed output from `javelinsymbols`.");
}
$type = $matches[1];
$symbol = $matches[2];
$line = $matches[3];
switch ($type) {
case '?':
$uses[$symbol] = $line;
break;
case '+':
$installs['JX.'.$symbol] = $line;
break;
}
}
$contents = $this->getData($path);
$matches = null;
$count = preg_match_all(
'/@javelin-installs\W+(\S+)/',
$contents,
$matches,
PREG_PATTERN_ORDER);
if ($count) {
foreach ($matches[1] as $symbol) {
$installs[$symbol] = 0;
}
}
return array($uses, $installs);
}
}
diff --git a/webroot/rsrc/js/core/DraggableList.js b/webroot/rsrc/js/core/DraggableList.js
index 87037f1df7..56be0790ce 100644
--- a/webroot/rsrc/js/core/DraggableList.js
+++ b/webroot/rsrc/js/core/DraggableList.js
@@ -1,299 +1,308 @@
/**
* @provides phabricator-draggable-list
* @requires javelin-install
* javelin-dom
* javelin-stratcom
* javelin-util
* javelin-vector
* javelin-magical-init
* @javelin
*/
JX.install('DraggableList', {
construct : function(sigil, root) {
this._sigil = sigil;
this._root = root || document.body;
// NOTE: Javelin does not dispatch mousemove by default.
JX.enableDispatch(document.body, 'mousemove');
JX.DOM.listen(this._root, 'mousedown', sigil, JX.bind(this, this._ondrag));
JX.Stratcom.listen('mousemove', null, JX.bind(this, this._onmove));
JX.Stratcom.listen('mouseup', null, JX.bind(this, this._ondrop));
},
events : [
'didLock',
'didUnlock',
'shouldBeginDrag',
'didBeginDrag',
'didCancelDrag',
'didEndDrag',
'didDrop'],
properties : {
findItemsHandler : null
},
members : {
_root : null,
_dragging : null,
_locked : 0,
_origin : null,
_target : null,
_targets : null,
_dimensions : null,
_ghostHandler : null,
_ghostNode : null,
setGhostHandler : function(handler) {
this._ghostHandler = handler;
return this;
},
getGhostHandler : function() {
return this._ghostHandler || JX.bind(this, this._defaultGhostHandler);
},
getGhostNode : function() {
if (!this._ghostNode) {
this._ghostNode = JX.$N('li', {className: 'drag-ghost'});
}
return this._ghostNode;
},
setGhostNode : function(node) {
this._ghostNode = node;
return this;
},
_defaultGhostHandler : function(ghost, target) {
var parent = this._dragging.parentNode;
if (target && target.nextSibling) {
parent.insertBefore(ghost, target.nextSibling);
} else if (!target && parent.firstChild) {
parent.insertBefore(ghost, parent.firstChild);
} else {
parent.appendChild(ghost);
}
},
findItems : function() {
var handler = this.getFindItemsHandler();
if (__DEV__) {
if (!handler) {
JX.$E('JX.Draggable.findItems(): No findItemsHandler set!');
}
}
return handler();
},
_ondrag : function(e) {
if (this._dragging) {
// Don't start dragging if we're already dragging something.
return;
}
if (this._locked) {
// Don't start drag operations while locked.
return;
}
if (!e.isNormalMouseEvent()) {
// Don't start dragging for shift click, right click, etc.
return;
}
if (this.invoke('shouldBeginDrag', e).getPrevented()) {
return;
}
e.kill();
this._dragging = e.getNode(this._sigil);
this._origin = JX.$V(e);
this._dimensions = JX.$V(this._dragging);
var targets = [];
var items = this.findItems();
for (var ii = 0; ii < items.length; ii++) {
targets.push({
item: items[ii],
y: JX.$V(items[ii]).y + (JX.Vector.getDim(items[ii]).y / 2)
});
}
targets.sort(function(u, v) { return v.y - u.y; });
this._targets = targets;
this._target = false;
if (!this.invoke('didBeginDrag', this._dragging).getPrevented()) {
var ghost = this.getGhostNode();
ghost.style.height = JX.Vector.getDim(this._dragging).y + 'px';
JX.DOM.alterClass(this._dragging, 'drag-dragging', true);
}
},
_onmove : function(e) {
if (!this._dragging) {
return;
}
var ghost = this.getGhostNode();
var target = this._target;
var targets = this._targets;
var dragging = this._dragging;
var origin = this._origin;
var p = JX.$V(e);
// Compute the size and position of the drop target indicator, because we
// need to update our static position computations to account for it.
var adjust_h = JX.Vector.getDim(ghost).y;
var adjust_y = JX.$V(ghost).y;
// Find the node we're dragging the object underneath. This is the first
// node in the list that's above the cursor. If that node is the node
// we're dragging or its predecessor, don't select a target, because the
// operation would be a no-op.
// NOTE: When we're dragging into the first position in the list, we
// use the target `null`. When we don't have a valid target, we use
// the target `false`. Spooky! Magic! Anyway, `null` and `false` mean
// completely different things.
var cur_target = null;
var trigger;
for (var ii = 0; ii < targets.length; ii++) {
// If the drop target indicator is above the target, we need to adjust
// the target's trigger height down accordingly. This makes dragging
// items down the list smoother, because the target doesn't jump to the
// next item while the cursor is over it.
trigger = targets[ii].y;
if (adjust_y <= trigger) {
trigger += adjust_h;
}
// If the cursor is above this target, we aren't dropping underneath it.
if (trigger >= p.y) {
continue;
}
// Don't choose the dragged row or its predecessor as targets.
cur_target = targets[ii].item;
if (cur_target == dragging) {
cur_target = false;
}
if (targets[ii - 1] && targets[ii - 1].item == dragging) {
cur_target = false;
}
break;
}
+ // If the dragged row is the first row, don't allow it to be dragged
+ // into the first position, since this operation doesn't make sense.
+ if (cur_target === null) {
+ var first_item = targets[targets.length - 1].item;
+ if (dragging === first_item) {
+ cur_target = false;
+ }
+ }
+
// If we've selected a new target, update the UI to show where we're
// going to drop the row.
- if (cur_target != target) {
+ if (cur_target !== target) {
- if (target) {
+ if (target !== false) {
JX.DOM.remove(ghost);
}
if (cur_target !== false) {
var ok = this.getGhostHandler()(ghost, cur_target);
// If the handler returns explicit `false`, prevent the drag.
if (ok === false) {
cur_target = false;
}
}
target = cur_target;
if (target !== false) {
// If we've changed where the ghost node is, update the adjustments
// so we accurately reflect document state when we tweak things below.
// This avoids a flash of bad state as the mouse is dragged upward
// across the document.
adjust_h = JX.Vector.getDim(ghost).y;
adjust_y = JX.$V(ghost).y;
}
}
// If the drop target indicator is above the cursor in the document,
// adjust the cursor position for the change in node document position.
// Do this before choosing a new target to avoid a flash of nonsense.
if (target !== false) {
if (adjust_y <= origin.y) {
p.y -= adjust_h;
}
}
p.x = 0;
p.y -= origin.y;
p.setPos(dragging);
this._target = target;
e.kill();
},
_ondrop : function(e) {
if (!this._dragging) {
return;
}
var target = this._target;
var dragging = this._dragging;
var ghost = this.getGhostNode();
this._dragging = null;
JX.$V(0, 0).setPos(dragging);
if (target !== false) {
JX.DOM.remove(dragging);
JX.DOM.replace(ghost, dragging);
this.invoke('didDrop', dragging, target);
} else {
this.invoke('didCancelDrag', dragging);
}
if (!this.invoke('didEndDrag', dragging).getPrevented()) {
JX.DOM.alterClass(dragging, 'drag-dragging', false);
}
e.kill();
},
lock : function() {
this._locked++;
if (this._locked === 1) {
this.invoke('didLock');
}
return this;
},
unlock : function() {
if (__DEV__) {
if (!this._locked) {
JX.$E("JX.Draggable.unlock(): Draggable is not locked!");
}
}
this._locked--;
if (!this._locked) {
this.invoke('didUnlock');
}
return this;
}
}
});

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 1, 9:21 PM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
431185
Default Alt Text
(23 KB)

Event Timeline