diff --git a/externals/cowsay/INSTALL b/externals/cowsay/INSTALL deleted file mode 100644 index d3844ca565..0000000000 --- a/externals/cowsay/INSTALL +++ /dev/null @@ -1,15 +0,0 @@ -================= -Installing cowsay -================= - -If you really want to get things installed a nice and pretty way, - - sh install.sh - -It will ask approximately one question. If you can't answer it, -you need serious help. - -If the install goes well, you can start cowing immediately! Just -be sure to read the manual page first... - -$Id: INSTALL,v 1.1 1999/08/14 08:03:17 tony Exp $ diff --git a/externals/cowsay/MANIFEST b/externals/cowsay/MANIFEST deleted file mode 100644 index a3ff805fed..0000000000 --- a/externals/cowsay/MANIFEST +++ /dev/null @@ -1,11 +0,0 @@ -ChangeLog Changes to recent versions. -INSTALL Instructions for installing cowsay. -LICENSE The license for use and redistribution of cowsay. -MANIFEST This file. -README Read this first. Really. -Wrap.pm.diff Diff for Text/Wrap.pm. -cows/* Support files used by cowsay. -cowsay Main cowsay executable. -cowsay.1 Main cowsay manual page. -install.sh cowsay installation script. -pgp_public_key.txt Verify the signature file with this key. diff --git a/externals/cowsay/README b/externals/cowsay/README index b5de08c405..50b746c1ec 100644 --- a/externals/cowsay/README +++ b/externals/cowsay/README @@ -36,3 +36,11 @@ this directory. -- Tony Monroe (tony@nog.net) $Id: README,v 1.3 2000/05/28 06:24:46 tony Exp $ + +---- + +In September 2015, Phabricator imported the Perl version of cowsay +in the core, to use its nice template files. Anyway, the logic now +is not in Perl. It was re-implemented in PHP, here: + +src/infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php diff --git a/externals/cowsay/Wrap.pm.diff b/externals/cowsay/Wrap.pm.diff deleted file mode 100644 index 1da064079e..0000000000 --- a/externals/cowsay/Wrap.pm.diff +++ /dev/null @@ -1,47 +0,0 @@ -*** Wrap.pm.in Thu May 22 00:21:42 1997 ---- Wrap.pm Fri Nov 12 10:00:15 1999 -*************** -*** 3,9 **** - require Exporter; - - @ISA = (Exporter); -! @EXPORT = qw(wrap); - @EXPORT_OK = qw($columns); - - $VERSION = 97.011701; ---- 3,9 ---- - require Exporter; - - @ISA = (Exporter); -! @EXPORT = qw(wrap fill); - @EXPORT_OK = qw($columns); - - $VERSION = 97.011701; -*************** -*** 66,71 **** ---- 66,90 ---- - - print "-----------$r---------\n" if $debug;; - return $r; -+ } -+ -+ ## Copied up from below. -+ sub fill -+ { -+ my ($ip, $xp, @raw) = @_; -+ my @para; -+ my $pp; -+ -+ for $pp (split(/\n\s+/, join("\n",@raw))) { -+ $pp =~ s/\s+/ /g; -+ my $x = wrap($ip, $xp, $pp); -+ push(@para, $x); -+ } -+ -+ # if paragraph_indent is the same as line_indent, -+ # separate paragraphs with blank lines -+ -+ return join ($ip eq $xp ? "\n\n" : "\n", @para); - } - - 1; diff --git a/externals/cowsay/cowsay b/externals/cowsay/cowsay deleted file mode 100755 index 900ca46014..0000000000 --- a/externals/cowsay/cowsay +++ /dev/null @@ -1,187 +0,0 @@ -#%BANGPERL% - -## -## Cowsay 3.03 -## -## This file is part of cowsay. (c) 1999-2000 Tony Monroe. -## - -use Text::Tabs qw(expand); -use Text::Wrap qw(wrap fill $columns); -use File::Basename; -use Getopt::Std; -use Cwd; - -$version = "3.03"; -$progname = basename($0); -$eyes = "oo"; -$tongue = " "; -$cowpath = $ENV{'COWPATH'} || '%PREFIX%/share/cows'; -@message = (); -$thoughts = ""; - -## Yeah, this is rude, I know. But hopefully it gets around a nasty -## little version dependency. - -$Text::Wrap::initial_tab = 8; -$Text::Wrap::subsequent_tab = 8; -$Text::Wrap::tabstop = 8; - -## One of these days, we'll get it ported to Windows. Yeah, right. - -if (($^O eq "MSWin32") or ($^O eq "Windows_NT")) { ## Many perls, eek! - $pathsep = ';'; -} else { - $pathsep = ':'; -} - -%opts = ( - 'e' => 'oo', - 'f' => 'default.cow', - 'n' => 0, - 'T' => ' ', - 'W' => 40, -); - -getopts('bde:f:ghlLnNpstT:wW:y', \%opts); - -&display_usage if $opts{'h'}; -&list_cowfiles if $opts{'l'}; - -$borg = $opts{'b'}; -$dead = $opts{'d'}; -$greedy = $opts{'g'}; -$paranoid = $opts{'p'}; -$stoned = $opts{'s'}; -$tired = $opts{'t'}; -$wired = $opts{'w'}; -$young = $opts{'y'}; -$eyes = substr($opts{'e'}, 0, 2); -$tongue = substr($opts{'T'}, 0, 2); -$the_cow = ""; - -&slurp_input; -$Text::Wrap::columns = $opts{'W'}; -@message = ($opts{'n'} ? expand(@message) : - split("\n", fill("", "", @message))); -&construct_balloon; -&construct_face; -&get_cow; -print @balloon_lines; -print $the_cow; - -sub list_cowfiles { - my $basedir; - my @dirfiles; - chop($basedir = cwd); - for my $d (split(/$pathsep/, $cowpath)) { - print "Cow files in $d:\n"; - opendir(COWDIR, $d) || die "$0: Cannot open $d\n"; - for my $file (readdir COWDIR) { - if ($file =~ s/\.cow$//) { - push(@dirfiles, $file); - } - } - closedir(COWDIR); - print wrap("", "", sort @dirfiles), "\n"; - @dirfiles = (); - chdir($basedir); - } - exit(0); -} - -sub slurp_input { - unless ($ARGV[0]) { - chomp(@message = ); - } else { - &display_usage if $opts{'n'}; - @message = join(' ', @ARGV); - } -} - -sub maxlength { - my ($l, $m); - $m = -1; - for my $i (@_) { - $l = length $i; - $m = $l if ($l > $m); - } - return $m; -} - -sub construct_balloon { - my $max = &maxlength(@message); - my $max2 = $max + 2; ## border space fudge. - my $format = "%s %-${max}s %s\n"; - my @border; ## up-left, up-right, down-left, down-right, left, right - if ($0 =~ /think/i) { - $thoughts = 'o'; - @border = qw[ ( ) ( ) ( ) ]; - } elsif (@message < 2) { - $thoughts = '\\'; - @border = qw[ < > ]; - } else { - $thoughts = '\\'; - if ($V and $V gt v5.6.0) { # Thanks, perldelta. - @border = qw[ / \\ \\ / | | ]; - } else { - @border = qw[ / \ \ / | | ]; - } - } - push(@balloon_lines, - " " . ("_" x $max2) . " \n" , - sprintf($format, $border[0], $message[0], $border[1]), - (@message < 2 ? "" : - map { sprintf($format, $border[4], $_, $border[5]) } - @message[1 .. $#message - 1]), - (@message < 2 ? "" : - sprintf($format, $border[2], $message[$#message], $border[3])), - " " . ("-" x $max2) . " \n" - ); -} - -sub construct_face { - if ($borg) { $eyes = "=="; } - if ($dead) { $eyes = "xx"; $tongue = "U "; } - if ($greedy) { $eyes = "\$\$"; } - if ($paranoid) { $eyes = "@@"; } - if ($stoned) { $eyes = "**"; $tongue = "U "; } - if ($tired) { $eyes = "--"; } - if ($wired) { $eyes = "OO"; } - if ($young) { $eyes = ".."; } -} - -sub get_cow { -## -## Get a cow from the specified cowfile; otherwise use the default cow -## which was defined above in $the_cow. -## - my $f = $opts{'f'}; - my $full = ""; - if ($opts{'f'} =~ m,/,) { - $full = $opts{'f'}; - } else { - for my $d (split(/:/, $cowpath)) { - if (-f "$d/$f") { - $full = "$d/$f"; - last; - } elsif (-f "$d/$f.cow") { - $full = "$d/$f.cow"; - last; - } - } - if ($full eq "") { - die "$progname: Could not find $f cowfile!\n"; - } - } - do $full; - die "$progname: $@\n" if $@; -} - -sub display_usage { - die </dev/null 2>&1; then - echo Found a good perl in $perl - goodperls="$goodperls $perl" - fi -done -echo The following perl executables will run cowsay: -echo $goodperls -echo I recommend the latest stable perl you can find. -set $goodperls -if [ -z "$1" ]; then - echo Ack! You do not have Perl 5 installed correctly! - echo Get thee to CPAN! - exit 1 -fi -usethisperl=$1 -echo I will be using $1 because I know it will work. - -echo Now I need an installation prefix. I will use /usr/local unless -printf "you give me a better idea here: " -if [ -n "$backdoor" ]; then - prefix=$backdoor - printf "%s (specified on command line)\n" $prefix -else - read prefix -fi - -PREFIX=${prefix:-/usr/local} - -echo Okay, time to install this puppy. - -echo s,%BANGPERL%,!$usethisperl,\; > install.pl -echo s,%PREFIX%,$PREFIX,\; >> install.pl -set -x -mkdir -p $PREFIX/bin || (mkdir $PREFIX; mkdir $PREFIX/bin) -$usethisperl -p install.pl cowsay > $PREFIX/bin/cowsay -chmod a+x $PREFIX/bin/cowsay -ln -s cowsay $PREFIX/bin/cowthink -mkdir -p $PREFIX/man/man1 || ($mkdir $PREFIX; mkdir $PREFIX/man; mkdir $PREFIX/man/man1) -$usethisperl -p install.pl cowsay.1 > $PREFIX/man/man1/cowsay.1 -chmod a+r $PREFIX/man/man1/cowsay.1 -ln -s cowsay.1 $PREFIX/man/man1/cowthink.1 -mkdir -p $PREFIX/share/cows || (mkdir $PREFIX; mkdir $PREFIX/share; mkdir $PREFIX/share/cows) -tar -cf - $filelist | (cd $PREFIX/share && tar -xvf -) -set +x - -echo Okay, let us see if the install actually worked. - -if [ ! -f $PREFIX/share/cows/default.cow ]; then - echo The default cow file did not make it across! - echo Ooops, it failed...sorry! - exit 1 -fi - -echo Installation complete! Enjoy the cows! diff --git a/externals/cowsay/pgp_public_key.txt b/externals/cowsay/pgp_public_key.txt deleted file mode 100644 index 135735e6f9..0000000000 --- a/externals/cowsay/pgp_public_key.txt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: 2.6.2 - -mQCNAzNS+H4AAAEEAMilCcxLMIqMNXhZoeHjbeJGnHoKP0JpKDejz66qBlDwP+du -FvVBHkyNIuU3orKe7l/aXIR8TcpjrxdcmrjjzwuB1aV48V4swT7v9UXvv9YP41Pd -1pXYXNelXHmE0eKSfcnkkFmYTJBXPaPNTJ3rpZpZOEW3SfgrrheqQm6w/6IJAAUR -tBpUb255IE1vbnJvZSA8dG9ueUBub2cubmV0PrQdVG9ueSBNb25yb2UgPHRtb25y -b2VAbm9nLm5ldD6JAJUDBRA2bDA5F6pCbrD/ogkBASOZA/9XtYSpcPjpi62MTEZl -l+wV1svtlUlPvKkDE7FB9bwnMbF1FgGhTe/H4/8qDu20m5eGxMX58Ri7HPXWjjJ/ -CrUWMzGVbg1JBkgh+d9QvEywmR0j4WezaifW1nCbxk0GrW1PjJyGb3kx7vrIF1Km -xt6VwxTgfJzjIioBJFb4EiDyaLQnVG9ueSBNb25yb2UgPHRtb25yb2VAQ1NVQS5C -ZXJrZWxleS5FRFU+ -=WpM4 ------END PGP PUBLIC KEY BLOCK----- diff --git a/externals/pear-figlet/Text/Figlet.php b/externals/pear-figlet/Text/Figlet.php index cc121facb3..167d3e1aa3 100644 --- a/externals/pear-figlet/Text/Figlet.php +++ b/externals/pear-figlet/Text/Figlet.php @@ -140,20 +140,23 @@ class Text_Figlet if (!$compressed) { /* ZIPed font */ if (fread($fp, 2) == 'PK') { - if (!function_exists('zip_open')) { - return self::raiseError('Cannot load ZIP compressed fonts since' - . ' ZIP PHP extension is not available.', - 5); - } - fclose($fp); - if (!($fp = zip_open($filename))) { - return self::raiseError('Cannot open figlet font file ' . $filename, 2); + $zip = new ZipArchive(); + + $zip_flags = 0; + if(defined('ZipArchive::RDONLY')) { + $zip_flags = ZipArchive::RDONLY; // Flag available since PHP 7.4, unnecessary before } - $name = zip_entry_name(zip_read($fp)); - zip_close($fp); + $open_result = $zip->open($filename, $zip_flags); + if ($open_result !== true) { + return self::raiseError('Cannot open figlet font file ' . + $filename . ', got error: ' . $open_result, 2); + } + + $name = $zip->getNameIndex(0); + $zip->close(); if (!($fp = fopen('zip://' . realpath($filename) . '#' . $name, 'rb'))) { return self::raiseError('Cannot open figlet font file ' . $filename, 2); @@ -231,7 +234,7 @@ class Text_Figlet $i = hexdec(substr($i, 2)); } else { // If octal - if ($i{0} === '0' && $i !== '0' || substr($i, 0, 2) == '-0') { + if ($i[0] === '0' && $i !== '0' || substr($i, 0, 2) == '-0') { $i = octdec($i); } } @@ -274,7 +277,7 @@ class Text_Figlet $lt = hexdec(substr($str, $i+2, 4)); $i += 5; } else { - $lt = ord($str{$i}); + $lt = ord($str[$i]); } $hb = preg_quote($this->hardblank, '/'); diff --git a/resources/celerity/map.php b/resources/celerity/map.php index c0805e16a6..84d27ab4aa 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,13 +7,13 @@ */ return array( 'names' => array( - 'conpherence.pkg.css' => '0e3cf785', + 'conpherence.pkg.css' => '76ed87e3', 'conpherence.pkg.js' => '020aebcf', - 'core.pkg.css' => 'b239afaa', - 'core.pkg.js' => '66c49ca1', + 'core.pkg.css' => '0cb47e9d', + 'core.pkg.js' => '2eeda9e0', 'dark-console.pkg.js' => '187792c2', - 'differential.pkg.css' => '609e63d4', - 'differential.pkg.js' => 'c60bec1b', + 'differential.pkg.css' => '525f9a1d', + 'differential.pkg.js' => '46fcb3af', 'diffusion.pkg.css' => '42c75c37', 'diffusion.pkg.js' => '78c9885d', 'maniphest.pkg.css' => '35995d6d', @@ -41,7 +41,7 @@ return array( 'rsrc/css/application/base/main-menu-view.css' => '89fc16b6', 'rsrc/css/application/base/notification-menu.css' => '4df1ee30', 'rsrc/css/application/base/phui-theme.css' => '35883b37', - 'rsrc/css/application/base/standard-page-view.css' => 'a374f94c', + 'rsrc/css/application/base/standard-page-view.css' => 'e08c7462', 'rsrc/css/application/chatlog/chatlog.css' => 'abdc76ee', 'rsrc/css/application/conduit/conduit-api.css' => 'ce2cfc41', 'rsrc/css/application/config/config-options.css' => '16c920ae', @@ -53,7 +53,7 @@ return array( 'rsrc/css/application/conpherence/header-pane.css' => 'c9a3db8e', 'rsrc/css/application/conpherence/menu.css' => '67f4680d', 'rsrc/css/application/conpherence/message-pane.css' => 'd244db1e', - 'rsrc/css/application/conpherence/notification.css' => '6a3d4e58', + 'rsrc/css/application/conpherence/notification.css' => '85c48def', 'rsrc/css/application/conpherence/participant-pane.css' => '69e0058a', 'rsrc/css/application/conpherence/transaction.css' => '3a3f5e7e', 'rsrc/css/application/contentsource/content-source-view.css' => 'cdf0d579', @@ -63,7 +63,7 @@ return array( 'rsrc/css/application/diff/diff-tree-view.css' => 'e2d3e222', 'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d', 'rsrc/css/application/differential/add-comment.css' => '7e5900d9', - 'rsrc/css/application/differential/changeset-view.css' => 'bf159129', + 'rsrc/css/application/differential/changeset-view.css' => '8b9caefe', 'rsrc/css/application/differential/core.css' => '7300a73e', 'rsrc/css/application/differential/phui-inline-comment.css' => 'a864426f', 'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d', @@ -77,7 +77,7 @@ return array( 'rsrc/css/application/feed/feed.css' => 'd8b6e3f8', 'rsrc/css/application/files/global-drag-and-drop.css' => '1d2713a4', 'rsrc/css/application/flag/flag.css' => '2b77be8d', - 'rsrc/css/application/harbormaster/harbormaster.css' => 'd98decda', + 'rsrc/css/application/harbormaster/harbormaster.css' => 'cd0ce059', 'rsrc/css/application/herald/herald-test.css' => '7e7bbdae', 'rsrc/css/application/herald/herald.css' => '648d39e2', 'rsrc/css/application/maniphest/report.css' => '3d53188b', @@ -110,7 +110,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => 'ce5a50bd', 'rsrc/css/application/uiexample/example.css' => 'b4795059', 'rsrc/css/core/core.css' => 'a708bd25', - 'rsrc/css/core/remarkup.css' => '5baa3bd9', + 'rsrc/css/core/remarkup.css' => '3480e1fe', 'rsrc/css/core/syntax.css' => '548567f6', 'rsrc/css/core/z-index.css' => 'ac3bfcd4', 'rsrc/css/diviner/diviner-shared.css' => '4bd263b0', @@ -121,10 +121,10 @@ return array( 'rsrc/css/fuel/fuel-handle-list.css' => '2c4cbeca', 'rsrc/css/fuel/fuel-map.css' => 'd6e31510', 'rsrc/css/fuel/fuel-menu.css' => '21f5d199', - 'rsrc/css/layout/phabricator-source-code-view.css' => '6b31244f', + 'rsrc/css/layout/phabricator-source-code-view.css' => '49656486', 'rsrc/css/phui/button/phui-button-bar.css' => 'a4aa75c4', 'rsrc/css/phui/button/phui-button-simple.css' => '1ff278aa', - 'rsrc/css/phui/button/phui-button.css' => 'e434f171', + 'rsrc/css/phui/button/phui-button.css' => 'f9d0f9c8', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '9597d706', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'ccd7e4e2', 'rsrc/css/phui/calendar/phui-calendar-month.css' => 'cb758c42', @@ -133,12 +133,12 @@ return array( 'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0', 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc', 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e', - 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'af98a277', + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => '9275ff55', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46', 'rsrc/css/phui/phui-action-list.css' => '1b0085b2', 'rsrc/css/phui/phui-action-panel.css' => '6c386cbf', 'rsrc/css/phui/phui-badge.css' => '666e25ad', - 'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d', + 'rsrc/css/phui/phui-basic-nav-view.css' => 'a5693cf0', 'rsrc/css/phui/phui-big-info-view.css' => '362ad37b', 'rsrc/css/phui/phui-box.css' => '5ed3b8cb', 'rsrc/css/phui/phui-bulk-editor.css' => '374d5e30', @@ -182,8 +182,8 @@ return array( 'rsrc/css/phui/phui-two-column-view.css' => 'f96d319f', 'rsrc/css/phui/workboards/phui-workboard-color.css' => '3a1c21ff', 'rsrc/css/phui/workboards/phui-workboard.css' => '74fc9d98', - 'rsrc/css/phui/workboards/phui-workcard.css' => '913441b6', - 'rsrc/css/phui/workboards/phui-workpanel.css' => '3ae89b20', + 'rsrc/css/phui/workboards/phui-workcard.css' => '62056e3b', + 'rsrc/css/phui/workboards/phui-workpanel.css' => 'bc06f022', 'rsrc/css/sprite-login.css' => '35d1510c', 'rsrc/css/sprite-tokens.css' => 'f1896dc5', 'rsrc/css/syntax/syntax-default.css' => '055fc231', @@ -461,6 +461,7 @@ return array( 'rsrc/js/core/MultirowRowManager.js' => '5b54c823', 'rsrc/js/core/Notification.js' => 'a9b91e3f', 'rsrc/js/core/Prefab.js' => '5793d835', + 'rsrc/js/core/RemarkupMetadata.js' => 'e40c4991', 'rsrc/js/core/ShapedRequest.js' => '995f5102', 'rsrc/js/core/TextAreaUtils.js' => 'f340a484', 'rsrc/js/core/Title.js' => '43bc9360', @@ -473,7 +474,7 @@ return array( 'rsrc/js/core/behavior-copy.js' => 'cf32921f', 'rsrc/js/core/behavior-detect-timezone.js' => '78bc5d94', 'rsrc/js/core/behavior-device.js' => 'ac2b1e01', - 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '3277c62d', + 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '6bc7ccf7', 'rsrc/js/core/behavior-fancy-datepicker.js' => 'b545d0a0', 'rsrc/js/core/behavior-form.js' => '55d7b788', 'rsrc/js/core/behavior-gesture.js' => 'b58d1a2a', @@ -489,7 +490,7 @@ return array( 'rsrc/js/core/behavior-more.js' => '506aa3f4', 'rsrc/js/core/behavior-object-selector.js' => '98ef467f', 'rsrc/js/core/behavior-oncopy.js' => 'da8f5259', - 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '54262396', + 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '6d347847', 'rsrc/js/core/behavior-read-only-warning.js' => 'b9109f8f', 'rsrc/js/core/behavior-redirect.js' => '407ee861', 'rsrc/js/core/behavior-refresh-csrf.js' => '46116c01', @@ -553,13 +554,13 @@ return array( 'conpherence-header-pane-css' => 'c9a3db8e', 'conpherence-menu-css' => '67f4680d', 'conpherence-message-pane-css' => 'd244db1e', - 'conpherence-notification-css' => '6a3d4e58', + 'conpherence-notification-css' => '85c48def', 'conpherence-participant-pane-css' => '69e0058a', 'conpherence-thread-manager' => 'aec8e38c', 'conpherence-transaction-css' => '3a3f5e7e', 'd3' => '9d068042', 'diff-tree-view-css' => 'e2d3e222', - 'differential-changeset-view-css' => 'bf159129', + 'differential-changeset-view-css' => '8b9caefe', 'differential-core-view-css' => '7300a73e', 'differential-revision-add-comment-css' => '7e5900d9', 'differential-revision-comment-css' => '7dbc8d1d', @@ -578,7 +579,7 @@ return array( 'fuel-map-css' => 'd6e31510', 'fuel-menu-css' => '21f5d199', 'global-drag-and-drop-css' => '1d2713a4', - 'harbormaster-css' => 'd98decda', + 'harbormaster-css' => 'cd0ce059', 'herald-css' => '648d39e2', 'herald-rule-editor' => '2633bef7', 'herald-test-css' => '7e7bbdae', @@ -589,7 +590,7 @@ return array( 'javelin-behavior-aphlict-listen' => '4e61fa88', 'javelin-behavior-aphlict-status' => 'c3703a16', 'javelin-behavior-aphront-basic-tokenizer' => '3b4899b0', - 'javelin-behavior-aphront-drag-and-drop-textarea' => '3277c62d', + 'javelin-behavior-aphront-drag-and-drop-textarea' => '6bc7ccf7', 'javelin-behavior-aphront-form-disable-on-submit' => '55d7b788', 'javelin-behavior-aphront-more' => '506aa3f4', 'javelin-behavior-audio-source' => '3dc5ad43', @@ -653,7 +654,7 @@ return array( 'javelin-behavior-phabricator-notification-example' => '29819b75', 'javelin-behavior-phabricator-object-selector' => '98ef467f', 'javelin-behavior-phabricator-oncopy' => 'da8f5259', - 'javelin-behavior-phabricator-remarkup-assist' => '54262396', + 'javelin-behavior-phabricator-remarkup-assist' => '6d347847', 'javelin-behavior-phabricator-reveal-content' => 'b105a3a6', 'javelin-behavior-phabricator-search-typeahead' => '1cb7d027', 'javelin-behavior-phabricator-show-older-transactions' => '8b5c7d65', @@ -799,12 +800,13 @@ return array( 'phabricator-object-selector-css' => 'ee77366f', 'phabricator-phtize' => '2f1db1ed', 'phabricator-prefab' => '5793d835', - 'phabricator-remarkup-css' => '5baa3bd9', + 'phabricator-remarkup-css' => '3480e1fe', + 'phabricator-remarkup-metadata' => 'e40c4991', 'phabricator-search-results-css' => '9ea70ace', 'phabricator-shaped-request' => '995f5102', 'phabricator-slowvote-css' => '1694baed', - 'phabricator-source-code-view-css' => '6b31244f', - 'phabricator-standard-page-view' => 'a374f94c', + 'phabricator-source-code-view-css' => '49656486', + 'phabricator-standard-page-view' => 'e08c7462', 'phabricator-textareautils' => 'f340a484', 'phabricator-title' => '43bc9360', 'phabricator-tooltip' => '83754533', @@ -822,12 +824,12 @@ return array( 'phriction-document-css' => '03380da0', 'phui-action-panel-css' => '6c386cbf', 'phui-badge-view-css' => '666e25ad', - 'phui-basic-nav-view-css' => '56ebd66d', + 'phui-basic-nav-view-css' => 'a5693cf0', 'phui-big-info-view-css' => '362ad37b', 'phui-box-css' => '5ed3b8cb', 'phui-bulk-editor-css' => '374d5e30', 'phui-button-bar-css' => 'a4aa75c4', - 'phui-button-css' => 'e434f171', + 'phui-button-css' => 'f9d0f9c8', 'phui-button-simple-css' => '1ff278aa', 'phui-calendar-css' => 'f11073aa', 'phui-calendar-day-css' => '9597d706', @@ -868,7 +870,7 @@ return array( 'phui-oi-color-css' => 'b517bfa0', 'phui-oi-drag-ui-css' => 'da15d3dc', 'phui-oi-flush-ui-css' => '490e2e2e', - 'phui-oi-list-view-css' => 'af98a277', + 'phui-oi-list-view-css' => '9275ff55', 'phui-oi-simple-ui-css' => '6a30fa46', 'phui-pager-css' => 'd022c7ad', 'phui-pinboard-view-css' => '1f08f5d8', @@ -884,8 +886,8 @@ return array( 'phui-two-column-view-css' => 'f96d319f', 'phui-workboard-color-css' => '3a1c21ff', 'phui-workboard-view-css' => '74fc9d98', - 'phui-workcard-view-css' => '913441b6', - 'phui-workpanel-view-css' => '3ae89b20', + 'phui-workcard-view-css' => '62056e3b', + 'phui-workpanel-view-css' => 'bc06f022', 'phuix-action-list-view' => 'c68f183f', 'phuix-action-view' => 'a8f573a9', 'phuix-autocomplete' => '2fbe234d', @@ -1201,13 +1203,6 @@ return array( 'javelin-install', 'javelin-util', ), - '3277c62d' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-json', - 'phabricator-drag-and-drop-file-upload', - 'phabricator-textareautils', - ), '32db8374' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1252,9 +1247,6 @@ return array( 'trigger-rule', 'trigger-rule-type', ), - '3ae89b20' => array( - 'phui-workcard-view-css', - ), '3b4899b0' => array( 'javelin-behavior', 'phabricator-prefab', @@ -1424,17 +1416,6 @@ return array( '541f81c3' => array( 'javelin-install', ), - 54262396 => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'phabricator-phtize', - 'phabricator-textareautils', - 'javelin-workflow', - 'javelin-vector', - 'phuix-autocomplete', - 'javelin-mask', - ), '548567f6' => array( 'syntax-default-css', ), @@ -1567,6 +1548,13 @@ return array( 'javelin-workflow', 'javelin-magical-init', ), + '6bc7ccf7' => array( + 'javelin-behavior', + 'javelin-dom', + 'phabricator-drag-and-drop-file-upload', + 'phabricator-textareautils', + 'phabricator-remarkup-metadata', + ), '6cfa0008' => array( 'javelin-dom', 'javelin-dynval', @@ -1575,6 +1563,18 @@ return array( 'javelin-install', 'javelin-util', ), + '6d347847' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'phabricator-phtize', + 'phabricator-textareautils', + 'phabricator-remarkup-metadata', + 'javelin-workflow', + 'javelin-vector', + 'phuix-autocomplete', + 'javelin-mask', + ), 70245195 => array( 'javelin-behavior', 'javelin-stratcom', @@ -1699,6 +1699,9 @@ return array( 'javelin-dom', 'phabricator-busy', ), + '8b9caefe' => array( + 'phui-inline-comment-view-css', + ), '8badee71' => array( 'javelin-install', 'javelin-util', @@ -1999,8 +2002,8 @@ return array( 'javelin-uri', 'phabricator-notification', ), - 'bf159129' => array( - 'phui-inline-comment-view-css', + 'bc06f022' => array( + 'phui-workcard-view-css', ), 'c03f2fb4' => array( 'javelin-install', @@ -2126,6 +2129,11 @@ return array( 'javelin-dom', 'phuix-dropdown-menu', ), + 'e40c4991' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-json', + ), 'e4c7622a' => array( 'javelin-magical-init', 'javelin-install', diff --git a/scripts/celerity/generate_sprites.php b/scripts/celerity/generate_sprites.php index ccdd194b36..a85f9266ae 100755 --- a/scripts/celerity/generate_sprites.php +++ b/scripts/celerity/generate_sprites.php @@ -3,80 +3,6 @@ require_once dirname(dirname(__FILE__)).'/__init_script__.php'; -$args = new PhutilArgumentParser($argv); -$args->setTagline(pht('regenerate CSS sprite sheets')); -$args->setSynopsis(<<parseStandardArguments(); -$args->parse( - array( - array( - 'name' => 'force', - 'help' => pht('Force regeneration even if sources have not changed.'), - ), - )); - -$root = dirname(phutil_get_library_root('phabricator')); -$webroot = $root.'/webroot/rsrc'; -$webroot = Filesystem::readablePath($webroot); - -$generator = new CeleritySpriteGenerator(); - -$sheets = array( - 'tokens' => $generator->buildTokenSheet(), - 'login' => $generator->buildLoginSheet(), -); - -list($err) = exec_manual('optipng'); -if ($err) { - $have_optipng = false; - echo phutil_console_format( - " %s %s\n%s\n", - pht('WARNING'), - pht('`%s` not found in PATH.', 'optipng'), - pht('Sprites will not be optimized! Install `%s`!', 'optipng')); -} else { - $have_optipng = true; -} - -foreach ($sheets as $name => $sheet) { - - $sheet->setBasePath($root); - - $manifest_path = $root.'/resources/sprite/manifest/'.$name.'.json'; - if (!$args->getArg('force')) { - if (Filesystem::pathExists($manifest_path)) { - $data = Filesystem::readFile($manifest_path); - $data = phutil_json_decode($data); - if (!$sheet->needsRegeneration($data)) { - continue; - } - } - } - - $sheet - ->generateCSS($webroot."/css/sprite-{$name}.css") - ->generateManifest($root."/resources/sprite/manifest/{$name}.json"); - - foreach ($sheet->getScales() as $scale) { - if ($scale == 1) { - $sheet_name = "sprite-{$name}.png"; - } else { - $sheet_name = "sprite-{$name}-X{$scale}.png"; - } - - $full_path = "{$webroot}/image/{$sheet_name}"; - $sheet->generateImage($full_path, $scale); - - if ($have_optipng) { - echo pht('Optimizing...')."\n"; - phutil_passthru('optipng -o7 -clobber %s', $full_path); - } - } -} - -echo pht('Done.')."\n"; +echo pht('This script was replaced with `%s`!.', './bin/celerity sprites'); +echo "\n"; +exit(13); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6a6bf37aed..17560e11d1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -318,6 +318,7 @@ phutil_register_library_map(array( 'CelerityDefaultPostprocessor' => 'applications/celerity/postprocessor/CelerityDefaultPostprocessor.php', 'CelerityHighContrastPostprocessor' => 'applications/celerity/postprocessor/CelerityHighContrastPostprocessor.php', 'CelerityLargeFontPostprocessor' => 'applications/celerity/postprocessor/CelerityLargeFontPostprocessor.php', + 'CelerityManagementGenerateSpritesWorkflow' => 'applications/celerity/management/CelerityManagementGenerateSpritesWorkflow.php', 'CelerityManagementMapWorkflow' => 'applications/celerity/management/CelerityManagementMapWorkflow.php', 'CelerityManagementSyntaxWorkflow' => 'applications/celerity/management/CelerityManagementSyntaxWorkflow.php', 'CelerityManagementWorkflow' => 'applications/celerity/management/CelerityManagementWorkflow.php', @@ -2975,6 +2976,7 @@ phutil_register_library_map(array( 'PhabricatorCountdownApplication' => 'applications/countdown/application/PhabricatorCountdownApplication.php', 'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php', 'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php', + 'PhabricatorCountdownCreateCapability' => 'applications/countdown/capability/PhabricatorCountdownCreateCapability.php', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php', 'PhabricatorCountdownDefaultEditCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultEditCapability.php', 'PhabricatorCountdownDefaultViewCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultViewCapability.php', @@ -6310,6 +6312,7 @@ phutil_register_library_map(array( 'CelerityDefaultPostprocessor' => 'CelerityPostprocessor', 'CelerityHighContrastPostprocessor' => 'CelerityPostprocessor', 'CelerityLargeFontPostprocessor' => 'CelerityPostprocessor', + 'CelerityManagementGenerateSpritesWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementSyntaxWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow', @@ -9376,6 +9379,7 @@ phutil_register_library_map(array( 'PhabricatorCountdownApplication' => 'PhabricatorApplication', 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorCountdownCreateCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCountdownDefaultViewCapability' => 'PhabricatorPolicyCapability', diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php index 58fc6f9346..2561e397b6 100644 --- a/src/aphront/AphrontRequest.php +++ b/src/aphront/AphrontRequest.php @@ -448,7 +448,7 @@ final class AphrontRequest extends Phobject { } private function getPrefixedCookieName($name) { - if (strlen($this->cookiePrefix)) { + if (phutil_nonempty_string($this->cookiePrefix)) { return $this->cookiePrefix.'_'.$name; } else { return $name; diff --git a/src/aphront/response/AphrontFileResponse.php b/src/aphront/response/AphrontFileResponse.php index 980d1ee5dd..6508ad6020 100644 --- a/src/aphront/response/AphrontFileResponse.php +++ b/src/aphront/response/AphrontFileResponse.php @@ -8,7 +8,16 @@ final class AphrontFileResponse extends AphrontResponse { private $compressResponse; private $mimeType; + + /** + * Download filename + * + * This is NULL as default or a string. + * + * @var string|null + */ private $download; + private $rangeMin; private $rangeMax; private $allowOrigins = array(); @@ -18,14 +27,30 @@ final class AphrontFileResponse extends AphrontResponse { return $this; } + /** + * Set a download filename + * + * @param $download string + * @return self + */ public function setDownload($download) { + + // Make sure we have a populated string if (!phutil_nonempty_string($download)) { $download = 'untitled'; } + $this->download = $download; return $this; } + /** + * Get the download filename + * + * If this was never set, NULL is given. + * + * @return string|null + */ public function getDownload() { return $this->download; } @@ -113,7 +138,7 @@ final class AphrontFileResponse extends AphrontResponse { $headers[] = array('Content-Length', $content_len); } - if (strlen($this->getDownload())) { + if (phutil_nonempty_string($this->getDownload())) { $headers[] = array('X-Download-Options', 'noopen'); $filename = $this->getDownload(); diff --git a/src/aphront/response/AphrontResponse.php b/src/aphront/response/AphrontResponse.php index 5dae168c73..355177e316 100644 --- a/src/aphront/response/AphrontResponse.php +++ b/src/aphront/response/AphrontResponse.php @@ -327,7 +327,7 @@ abstract class AphrontResponse extends Phobject { } if ($value instanceof PhutilSafeHTML) { - // TODO: Javelin supports implicity conversion of '__html' objects to + // TODO: Javelin supports implicit conversion of '__html' objects to // JX.HTML, but only for Ajax responses, not behaviors. Just leave things // as they are for now (where behaviors treat responses as HTML or plain // text at their discretion). diff --git a/src/applications/audit/editor/PhabricatorAuditEditor.php b/src/applications/audit/editor/PhabricatorAuditEditor.php index 7b97ea515a..9c2a5d7e96 100644 --- a/src/applications/audit/editor/PhabricatorAuditEditor.php +++ b/src/applications/audit/editor/PhabricatorAuditEditor.php @@ -700,7 +700,7 @@ final class PhabricatorAuditEditor PhabricatorAuditTransaction::MAILTAG_COMMIT => pht('A commit is created.'), PhabricatorAuditTransaction::MAILTAG_ACTION_CONCERN => - pht('A commit has a concerned raised against it.'), + pht('A commit has a concern raised against it.'), PhabricatorAuditTransaction::MAILTAG_ACTION_ACCEPT => pht('A commit is accepted.'), PhabricatorAuditTransaction::MAILTAG_ACTION_RESIGN => diff --git a/src/applications/auth/constants/PhabricatorCookies.php b/src/applications/auth/constants/PhabricatorCookies.php index 2573bf3ec6..9dc9d823b2 100644 --- a/src/applications/auth/constants/PhabricatorCookies.php +++ b/src/applications/auth/constants/PhabricatorCookies.php @@ -89,7 +89,7 @@ final class PhabricatorCookies extends Phobject { // temporary and clearing it when users log out. $value = $request->getCookie(self::COOKIE_CLIENTID); - if (!strlen($value)) { + if (!phutil_nonempty_string($value)) { $request->setTemporaryCookie( self::COOKIE_CLIENTID, Filesystem::readRandomCharacters(16)); @@ -164,7 +164,7 @@ final class PhabricatorCookies extends Phobject { // Old cookies look like: /uri // New cookies look like: timestamp,/uri - if (!strlen($cookie)) { + if (!phutil_nonempty_string($cookie)) { return null; } diff --git a/src/applications/auth/controller/PhabricatorAuthController.php b/src/applications/auth/controller/PhabricatorAuthController.php index aee93b98d6..8bba90a1e6 100644 --- a/src/applications/auth/controller/PhabricatorAuthController.php +++ b/src/applications/auth/controller/PhabricatorAuthController.php @@ -282,7 +282,7 @@ abstract class PhabricatorAuthController extends PhabricatorController { $viewer, PhabricatorAuthLoginMessageType::MESSAGEKEY); - if (!strlen($text)) { + if (!phutil_nonempty_string($text)) { return null; } diff --git a/src/applications/auth/controller/PhabricatorAuthRegisterController.php b/src/applications/auth/controller/PhabricatorAuthRegisterController.php index 9fbf30d092..a71e576476 100644 --- a/src/applications/auth/controller/PhabricatorAuthRegisterController.php +++ b/src/applications/auth/controller/PhabricatorAuthRegisterController.php @@ -18,7 +18,7 @@ final class PhabricatorAuthRegisterController $invite = $this->loadInvite(); $is_setup = false; - if (strlen($account_key)) { + if (phutil_nonempty_string($account_key)) { $result = $this->loadAccountForRegistrationOrLinking($account_key); list($account, $provider, $response) = $result; $is_default = false; @@ -244,9 +244,9 @@ final class PhabricatorAuthRegisterController $require_real_name = PhabricatorEnv::getEnvConfig('user.require-real-name'); - $e_username = strlen($value_username) ? null : true; + $e_username = phutil_nonempty_string($value_username) ? null : true; $e_realname = $require_real_name ? true : null; - $e_email = strlen($value_email) ? null : true; + $e_email = phutil_nonempty_string($value_email) ? null : true; $e_password = true; $e_captcha = true; diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php index 6dfc957f48..88bbcb5f8e 100644 --- a/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php @@ -54,7 +54,7 @@ final class PhabricatorAuthSSHKeyEditController $cancel_uri); $v_name = $key->getName(); - $e_name = strlen($v_name) ? null : true; + $e_name = phutil_nonempty_string($v_name) ? null : true; $v_key = $key->getEntireKey(); $e_key = strlen($v_key) ? null : true; diff --git a/src/applications/auth/controller/PhabricatorAuthStartController.php b/src/applications/auth/controller/PhabricatorAuthStartController.php index 5789740e14..76c7eb9df5 100644 --- a/src/applications/auth/controller/PhabricatorAuthStartController.php +++ b/src/applications/auth/controller/PhabricatorAuthStartController.php @@ -98,7 +98,7 @@ final class PhabricatorAuthStartController } $next_uri = $request->getStr('next'); - if (!strlen($next_uri)) { + if (!phutil_nonempty_string($next_uri)) { if ($this->getDelegatingController()) { // Only set a next URI from the request path if this controller was // delegated to, which happens when a user tries to view a page which @@ -112,7 +112,7 @@ final class PhabricatorAuthStartController } if (!$request->isFormPost()) { - if (strlen($next_uri)) { + if (phutil_nonempty_string($next_uri)) { PhabricatorCookies::setNextURICookie($request, $next_uri); } PhabricatorCookies::setClientIDCookie($request); diff --git a/src/applications/auth/controller/config/PhabricatorAuthEditController.php b/src/applications/auth/controller/config/PhabricatorAuthEditController.php index 693fc5bffd..2dbdbc9a10 100644 --- a/src/applications/auth/controller/config/PhabricatorAuthEditController.php +++ b/src/applications/auth/controller/config/PhabricatorAuthEditController.php @@ -99,10 +99,10 @@ final class PhabricatorAuthEditController if (!$errors) { if ($is_new) { - if (!strlen($config->getProviderType())) { + if (!phutil_nonempty_string($config->getProviderType())) { $config->setProviderType($provider->getProviderType()); } - if (!strlen($config->getProviderDomain())) { + if (!phutil_nonempty_string($config->getProviderDomain())) { $config->setProviderDomain($provider->getProviderDomain()); } } diff --git a/src/applications/auth/controller/message/PhabricatorAuthMessageViewController.php b/src/applications/auth/controller/message/PhabricatorAuthMessageViewController.php index 5665744463..a1abb6d37c 100644 --- a/src/applications/auth/controller/message/PhabricatorAuthMessageViewController.php +++ b/src/applications/auth/controller/message/PhabricatorAuthMessageViewController.php @@ -103,7 +103,7 @@ final class PhabricatorAuthMessageViewController ->setViewer($viewer); $full_description = $message_type->getFullDescription(); - if (strlen($full_description)) { + if (phutil_nonempty_string($full_description)) { $view->addTextContent(new PHUIRemarkupView($viewer, $full_description)); } else { $short_description = $message_type->getShortDescription(); @@ -111,7 +111,7 @@ final class PhabricatorAuthMessageViewController } $message_text = $message->getMessageText(); - if (strlen($message_text)) { + if (phutil_nonempty_string($message_text)) { $view->addSectionHeader( pht('Message Preview'), PHUIPropertyListView::ICON_SUMMARY); @@ -120,7 +120,7 @@ final class PhabricatorAuthMessageViewController } $default_text = $message_type->getDefaultMessageText(); - if (strlen($default_text)) { + if (phutil_nonempty_string($default_text)) { $view->addSectionHeader( pht('Default Message'), PHUIPropertyListView::ICON_SUMMARY); diff --git a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php index 1dac49bcf9..44bb7e97f6 100644 --- a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php +++ b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php @@ -83,7 +83,7 @@ final class PhabricatorAuthFactorProviderViewController $custom_enroll = $provider->getEnrollMessage(); - if (strlen($custom_enroll)) { + if (phutil_nonempty_string($custom_enroll)) { $view->addSectionHeader( pht('Custom Enroll Message'), PHUIPropertyListView::ICON_SUMMARY); diff --git a/src/applications/auth/factor/PhabricatorAuthFactor.php b/src/applications/auth/factor/PhabricatorAuthFactor.php index fefd9b5fd1..79ea17de7f 100644 --- a/src/applications/auth/factor/PhabricatorAuthFactor.php +++ b/src/applications/auth/factor/PhabricatorAuthFactor.php @@ -413,8 +413,8 @@ abstract class PhabricatorAuthFactor extends Phobject { $sync_type = PhabricatorAuthMFASyncTemporaryTokenType::TOKENTYPE; $sync_token = null; - $sync_key = $request->getStr($this->getMFASyncTokenFormKey()); - if (strlen($sync_key)) { + $sync_key = $request->getStr($this->getMFASyncTokenFormKey(), ''); + if ($sync_key !== '') { $sync_key_digest = PhabricatorHash::digestWithNamedKey( $sync_key, PhabricatorAuthMFASyncTemporaryTokenType::DIGEST_KEY); diff --git a/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php b/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php index 4c1c31f146..0d729837b4 100644 --- a/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php @@ -169,7 +169,7 @@ final class PhabricatorPhabricatorAuthProvider phutil_tag( 'tt', array(), - '`example.oauthserver`')))); + 'example.oauthserver')))); } else { $form ->appendChild( diff --git a/src/applications/auth/storage/PhabricatorAuthChallenge.php b/src/applications/auth/storage/PhabricatorAuthChallenge.php index 0b740e5fa7..05d00c3e6e 100644 --- a/src/applications/auth/storage/PhabricatorAuthChallenge.php +++ b/src/applications/auth/storage/PhabricatorAuthChallenge.php @@ -56,7 +56,7 @@ final class PhabricatorAuthChallenge AphrontRequest $request) { assert_instances_of($challenges, __CLASS__); - $token_list = $request->getStr(self::HTTPKEY); + $token_list = $request->getStr(self::HTTPKEY, ''); $token_list = explode(' ', $token_list); $token_map = array(); diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index ba1edc26d3..9e1ea7d5ba 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -235,6 +235,11 @@ abstract class PhabricatorApplication return array(); } + /** + * Get the Application Overview in raw Remarkup + * + * @return string|null + */ public function getOverview() { return null; } diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php index db9d456094..d1b1fcfc8e 100644 --- a/src/applications/base/controller/PhabricatorController.php +++ b/src/applications/base/controller/PhabricatorController.php @@ -74,7 +74,7 @@ abstract class PhabricatorController extends AphrontController { $session_engine = new PhabricatorAuthSessionEngine(); $phsid = $request->getCookie(PhabricatorCookies::COOKIE_SESSION); - if (strlen($phsid)) { + if (phutil_nonempty_string($phsid)) { $session_user = $session_engine->loadUserForSession( PhabricatorAuthSession::TYPE_WEB, $phsid); diff --git a/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php index c37ba6c944..4fde813223 100644 --- a/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php +++ b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php @@ -56,7 +56,7 @@ final class PhabricatorCalendarICSFileImportEngine public function getDisplayName(PhabricatorCalendarImport $import) { $filename_key = PhabricatorCalendarImportICSFileTransaction::PARAMKEY_NAME; $filename = $import->getParameter($filename_key); - if (strlen($filename)) { + if (phutil_nonempty_string($filename)) { return pht('ICS File "%s"', $filename); } else { return pht('ICS File'); diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php index 26a968d13d..51abdd8cad 100644 --- a/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php @@ -53,7 +53,7 @@ final class PhabricatorCalendarImportICSFileTransaction $new_value = $object->getParameter(self::PARAMKEY_FILE); foreach ($xactions as $xaction) { $new_value = $xaction->getNewValue(); - if (!strlen($new_value)) { + if (!phutil_nonempty_string($new_value)) { continue; } diff --git a/src/applications/celerity/controller/CelerityResourceController.php b/src/applications/celerity/controller/CelerityResourceController.php index 702fcefb2c..547c881df8 100644 --- a/src/applications/celerity/controller/CelerityResourceController.php +++ b/src/applications/celerity/controller/CelerityResourceController.php @@ -113,7 +113,7 @@ abstract class CelerityResourceController extends PhabricatorController { $range = AphrontRequest::getHTTPHeader('Range'); - if (strlen($range)) { + if (phutil_nonempty_string($range)) { $response->setContentLength(strlen($data)); list($range_begin, $range_end) = $response->parseHTTPRange($range); diff --git a/src/applications/celerity/management/CelerityManagementGenerateSpritesWorkflow.php b/src/applications/celerity/management/CelerityManagementGenerateSpritesWorkflow.php new file mode 100644 index 0000000000..52735b00f7 --- /dev/null +++ b/src/applications/celerity/management/CelerityManagementGenerateSpritesWorkflow.php @@ -0,0 +1,108 @@ +setName('sprites') + ->setExamples('**sprites** [options]') + ->setSynopsis(pht('Rebuild CSS sprite sheets.')) + ->setArguments( + array( + array( + 'name' => 'force', + 'help' => pht('Force regeneration even no sources have changed.'), + ), + array( + 'name' => 'no-map', + 'help' => + pht( + 'Do not invoke `%s` after updating sprites', + 'celerity map'), + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $resources_map = CelerityPhysicalResources::getAll(); + + $console = PhutilConsole::getConsole(); + + $root = dirname(phutil_get_library_root('phorge')); + $webroot = $root.'/webroot/rsrc'; + $webroot = Filesystem::readablePath($webroot); + + $generator = new CeleritySpriteGenerator(); + + $sheets = array( + 'tokens' => $generator->buildTokenSheet(), + 'login' => $generator->buildLoginSheet(), + ); + + list($err) = exec_manual('optipng'); + if ($err) { + $have_optipng = false; + $console->writeErr( + " %s %s\n%s\n", + pht('WARNING'), + pht('`%s` not found in PATH.', 'optipng'), + pht('Sprites will not be optimized! Install `%s`!', 'optipng')); + } else { + $have_optipng = true; + } + + foreach ($sheets as $name => $sheet) { + + $sheet->setBasePath($root); + + $manifest_path = $root.'/resources/sprite/manifest/'.$name.'.json'; + if (!$args->getArg('force')) { + if (Filesystem::pathExists($manifest_path)) { + $data = Filesystem::readFile($manifest_path); + $data = phutil_json_decode($data); + if (!$sheet->needsRegeneration($data)) { + continue; + } + } + } + + $sheet + ->generateCSS($webroot."/css/sprite-{$name}.css") + ->generateManifest($root."/resources/sprite/manifest/{$name}.json"); + + foreach ($sheet->getScales() as $scale) { + if ($scale == 1) { + $sheet_name = "sprite-{$name}.png"; + } else { + $sheet_name = "sprite-{$name}-X{$scale}.png"; + } + + $full_path = "{$webroot}/image/{$sheet_name}"; + $sheet->generateImage($full_path, $scale); + + if ($have_optipng) { + $console->writeOut("%s\n", pht('Optimizing...')); + phutil_passthru('optipng -o7 -clobber %s', $full_path); + } + } + } + + $run_map = !$args->getArg('no-map'); + + if ($run_map) { + $console->writeOut( + "%s\n", + pht('Done generating sprites - updating map...')); + $map_flow = id($args->getWorkflows())['map']; + // this is very hacky, but it works because `map` has no arguments. + $map_flow->execute($args); + } else { + $console->writeOut("%s\n", pht('Done.')); + return 0; + } + + } + + +} diff --git a/src/applications/conduit/controller/PhabricatorConduitAPIController.php b/src/applications/conduit/controller/PhabricatorConduitAPIController.php index a4d5fdd568..3ae402cf56 100644 --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -37,7 +37,7 @@ final class PhabricatorConduitAPIController // TODO: The relationship between ConduitAPIRequest and ConduitCall is a // little odd here and could probably be improved. Specifically, the // APIRequest is a sub-object of the Call, which does not parallel the - // role of AphrontRequest (which is an indepenent object). + // role of AphrontRequest (which is an independent object). // In particular, the setUser() and getUser() existing independently on // the Call and APIRequest is very awkward. diff --git a/src/applications/conduit/query/PhabricatorConduitSearchEngine.php b/src/applications/conduit/query/PhabricatorConduitSearchEngine.php index 06ba536dfe..3dc5617bb5 100644 --- a/src/applications/conduit/query/PhabricatorConduitSearchEngine.php +++ b/src/applications/conduit/query/PhabricatorConduitSearchEngine.php @@ -39,7 +39,7 @@ final class PhabricatorConduitSearchEngine $query->withIsInternal(false); $contains = $saved->getParameter('nameContains'); - if (strlen($contains)) { + if (phutil_nonempty_string($contains)) { $query->withNameContains($contains); } diff --git a/src/applications/config/check/PhabricatorBinariesSetupCheck.php b/src/applications/config/check/PhabricatorBinariesSetupCheck.php index b87282fcc7..9bbf8a367e 100644 --- a/src/applications/config/check/PhabricatorBinariesSetupCheck.php +++ b/src/applications/config/check/PhabricatorBinariesSetupCheck.php @@ -104,7 +104,17 @@ final class PhabricatorBinariesSetupCheck extends PhabricatorSetupCheck { switch ($vcs['versionControlSystem']) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $bad_versions = array(); + $bad_versions = array( + // We need 2.5.0 to use "git cat-file -t -- :" + // https://we.phorge.it/T15179 + '< 2.5.0' => pht( + 'The minimum supported version of Git on the server is %s, '. + 'which was released in %s. In older versions, the Git server '. + 'may not be able to escape arguments with the "--" operator. '. + 'Note: your users do not require a particular version of Git.', + '2.5.0', + '2015'), + ); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $bad_versions = array( diff --git a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php index 608bac675e..df5821665c 100644 --- a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php +++ b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php @@ -53,7 +53,7 @@ final class PhabricatorDaemonsSetupCheck extends PhabricatorSetupCheck { } $expect_user = PhabricatorEnv::getEnvConfig('phd.user'); - if (strlen($expect_user)) { + if (phutil_nonempty_string($expect_user)) { try { $all_daemons = id(new PhabricatorDaemonLogQuery()) diff --git a/src/applications/config/check/PhabricatorDatabaseSetupCheck.php b/src/applications/config/check/PhabricatorDatabaseSetupCheck.php index a5989f37b3..d3f6d52f04 100644 --- a/src/applications/config/check/PhabricatorDatabaseSetupCheck.php +++ b/src/applications/config/check/PhabricatorDatabaseSetupCheck.php @@ -106,7 +106,7 @@ final class PhabricatorDatabaseSetupCheck extends PhabricatorSetupCheck { 'The "InnoDB" engine is not available in MySQL (on host "%s"). '. 'Enable InnoDB in your MySQL configuration.'. "\n\n". - '(If you aleady created tables, MySQL incorrectly used some other '. + '(If you already created tables, MySQL incorrectly used some other '. 'engine to create them. You need to convert them or drop and '. 'reinitialize them.)', $ref_key); diff --git a/src/applications/config/controller/PhabricatorConfigConsoleController.php b/src/applications/config/controller/PhabricatorConfigConsoleController.php index 4773a8ab60..f70398bc5f 100644 --- a/src/applications/config/controller/PhabricatorConfigConsoleController.php +++ b/src/applications/config/controller/PhabricatorConfigConsoleController.php @@ -85,14 +85,14 @@ final class PhabricatorConfigConsoleController $rows = array(); foreach ($versions as $name => $info) { $branchpoint = $info['branchpoint']; - if (strlen($branchpoint)) { + if (phutil_nonempty_string($branchpoint)) { $branchpoint = substr($branchpoint, 0, 12); } else { $branchpoint = null; } $version = $info['hash']; - if (strlen($version)) { + if (phutil_nonempty_string($version)) { $version = substr($version, 0, 12); } else { $version = pht('Unknown'); diff --git a/src/applications/config/controller/module/PhabricatorConfigModuleController.php b/src/applications/config/controller/module/PhabricatorConfigModuleController.php index 4f3f9c57cb..355166fea6 100644 --- a/src/applications/config/controller/module/PhabricatorConfigModuleController.php +++ b/src/applications/config/controller/module/PhabricatorConfigModuleController.php @@ -9,7 +9,7 @@ final class PhabricatorConfigModuleController $all_modules = PhabricatorConfigModule::getAllModules(); - if (!strlen($key)) { + if (!phutil_nonempty_string($key)) { $key = head_key($all_modules); } diff --git a/src/applications/config/controller/services/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/services/PhabricatorConfigDatabaseStatusController.php index 09f4f344b5..40c4cfdf8c 100644 --- a/src/applications/config/controller/services/PhabricatorConfigDatabaseStatusController.php +++ b/src/applications/config/controller/services/PhabricatorConfigDatabaseStatusController.php @@ -837,7 +837,7 @@ final class PhabricatorConfigDatabaseStatusController $parts = array(); foreach ($properties as $key => $property) { - if (!strlen($property)) { + if (!phutil_nonempty_string($property)) { continue; } diff --git a/src/applications/config/controller/settings/PhabricatorConfigSettingsListController.php b/src/applications/config/controller/settings/PhabricatorConfigSettingsListController.php index 8513150134..0d34250bb8 100644 --- a/src/applications/config/controller/settings/PhabricatorConfigSettingsListController.php +++ b/src/applications/config/controller/settings/PhabricatorConfigSettingsListController.php @@ -7,7 +7,7 @@ final class PhabricatorConfigSettingsListController $viewer = $request->getViewer(); $filter = $request->getURIData('filter'); - if (!strlen($filter)) { + if (!phutil_nonempty_string($filter)) { $filter = 'settings'; } diff --git a/src/applications/config/option/PhabricatorConfigOption.php b/src/applications/config/option/PhabricatorConfigOption.php index 6d7f88bdfb..6b38bbb6d6 100644 --- a/src/applications/config/option/PhabricatorConfigOption.php +++ b/src/applications/config/option/PhabricatorConfigOption.php @@ -156,11 +156,22 @@ final class PhabricatorConfigOption return $this->summary; } + /** + * Set the human Description of this Config + * + * @param string|null $description Description as raw Remarkup + * @return self + */ public function setDescription($description) { $this->description = $description; return $this; } + /** + * Get the human Description of this Config + * + * @return string|null Description as raw Remarkup + */ public function getDescription() { return $this->description; } @@ -205,7 +216,7 @@ final class PhabricatorConfigOption public function newDescriptionRemarkupView(PhabricatorUser $viewer) { $description = $this->getDescription(); - if (!strlen($description)) { + if (!phutil_nonempty_string($description)) { return null; } diff --git a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php index cca8794055..36cbd9bd51 100644 --- a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php +++ b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php @@ -74,7 +74,7 @@ of each approach are: - If you use mailing lists, recipients may sometimes get duplicate mail. - Getting threading to work properly is easier, and threading settings - can be customzied by each user. + can be customized by each user. - "Reply All" will never send extra mail to other users involved in the thread. - Required if private reply-to addresses are configured. diff --git a/src/applications/config/view/PhabricatorSetupIssueView.php b/src/applications/config/view/PhabricatorSetupIssueView.php index 003725d5fc..bfeae20684 100644 --- a/src/applications/config/view/PhabricatorSetupIssueView.php +++ b/src/applications/config/view/PhabricatorSetupIssueView.php @@ -73,20 +73,22 @@ final class PhabricatorSetupIssueView extends AphrontView { 'Install these %d PHP extension(s):', count($extensions)); $install_info = pht( - 'You can usually install a PHP extension using %s or %s. Common '. - 'package names are %s or %s. Try commands like these:', + 'You can usually install a PHP extension using %s, %s, or %s. A '. + 'common package name is %s. Try commands like these:', phutil_tag('tt', array(), 'apt-get'), + phutil_tag('tt', array(), 'dnf'), phutil_tag('tt', array(), 'yum'), - hsprintf('php-%s', pht('extname')), - hsprintf('php5-%s', pht('extname'))); + hsprintf('php-%s', pht('extname'))); // TODO: We should do a better job of detecting how to install extensions // on the current system. $install_commands = hsprintf( - "\$ sudo apt-get install php5-extname ". + "\$ sudo apt-get install php-extname ". "# Debian / Ubuntu\n". - "\$ sudo yum install php-extname ". - "# Red Hat / Derivatives"); + "\$ sudo dnf install php-extname ". + "# Red Hat / Derivatives\n". + "\$ sudo yum install php-extname ". + "# Older Red Hat versions"); $fallback_info = pht( "If those commands don't work, try Google. The process of installing ". diff --git a/src/applications/conpherence/query/ConpherenceThreadQuery.php b/src/applications/conpherence/query/ConpherenceThreadQuery.php index 99fd18878e..34bbf7e6b0 100644 --- a/src/applications/conpherence/query/ConpherenceThreadQuery.php +++ b/src/applications/conpherence/query/ConpherenceThreadQuery.php @@ -135,7 +135,8 @@ final class ConpherenceThreadQuery } protected function buildGroupClause(AphrontDatabaseConnection $conn_r) { - if ($this->participantPHIDs !== null || strlen($this->fulltext)) { + if ($this->participantPHIDs !== null || + phutil_nonempty_string($this->fulltext)) { return qsprintf($conn_r, 'GROUP BY thread.id'); } else { return $this->buildApplicationSearchGroupClause($conn_r); @@ -152,7 +153,7 @@ final class ConpherenceThreadQuery id(new ConpherenceParticipant())->getTableName()); } - if (strlen($this->fulltext)) { + if (phutil_nonempty_string($this->fulltext)) { $joins[] = qsprintf( $conn, 'JOIN %T idx ON idx.threadPHID = thread.phid', @@ -234,7 +235,7 @@ final class ConpherenceThreadQuery $this->participantPHIDs); } - if (strlen($this->fulltext)) { + if (phutil_nonempty_string($this->fulltext)) { $where[] = qsprintf( $conn, 'MATCH(idx.corpus) AGAINST (%s IN BOOLEAN MODE)', diff --git a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php index cbaf43b0a9..77e54157cf 100644 --- a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php +++ b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php @@ -106,7 +106,7 @@ final class ConpherenceThreadSearchEngine $engines = array(); $fulltext = $query->getParameter('fulltext'); - if (strlen($fulltext) && $conpherences) { + if (phutil_nonempty_string($fulltext) && $conpherences) { $context = $this->loadContextMessages($conpherences, $fulltext); $author_phids = array(); diff --git a/src/applications/console/controller/DarkConsoleController.php b/src/applications/console/controller/DarkConsoleController.php index 3a677920ee..3c4f82feba 100644 --- a/src/applications/console/controller/DarkConsoleController.php +++ b/src/applications/console/controller/DarkConsoleController.php @@ -25,8 +25,9 @@ final class DarkConsoleController extends PhabricatorController { return $response; } + // This should be '0' when closed and '1' when opened $visible = $request->getStr('visible'); - if (strlen($visible)) { + if (phutil_nonempty_string($visible)) { $this->writeDarkConsoleSetting( PhabricatorDarkConsoleVisibleSetting::SETTINGKEY, (int)$visible); diff --git a/src/applications/console/core/DarkConsoleCore.php b/src/applications/console/core/DarkConsoleCore.php index 437d6f0be7..73065b900e 100644 --- a/src/applications/console/core/DarkConsoleCore.php +++ b/src/applications/console/core/DarkConsoleCore.php @@ -124,6 +124,9 @@ final class DarkConsoleCore extends Phobject { } else if (is_resource($data)) { return ''; } else { + // This is very probably not a string in strict sense + $data = phutil_string_cast($data); + // Truncate huge strings. Since the data doesn't really matter much, // just truncate bytes to avoid PhutilUTF8StringTruncator overhead. $length = strlen($data); diff --git a/src/applications/countdown/application/PhabricatorCountdownApplication.php b/src/applications/countdown/application/PhabricatorCountdownApplication.php index b3b5a79da2..e205ba64c3 100644 --- a/src/applications/countdown/application/PhabricatorCountdownApplication.php +++ b/src/applications/countdown/application/PhabricatorCountdownApplication.php @@ -50,6 +50,10 @@ final class PhabricatorCountdownApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( + PhabricatorCountdownCreateCapability::CAPABILITY => array( + 'default' => PhabricatorPolicies::POLICY_USER, + 'caption' => pht('Default create policy for countdowns.'), + ), PhabricatorCountdownDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for new countdowns.'), 'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST, diff --git a/src/applications/countdown/capability/PhabricatorCountdownCreateCapability.php b/src/applications/countdown/capability/PhabricatorCountdownCreateCapability.php new file mode 100644 index 0000000000..057b6c22d9 --- /dev/null +++ b/src/applications/countdown/capability/PhabricatorCountdownCreateCapability.php @@ -0,0 +1,16 @@ +getURI(); } + protected function getCreateNewObjectPolicy() { + return $this->getApplication()->getPolicy( + PhabricatorCountdownCreateCapability::CAPABILITY); + } + protected function buildCustomEditFields($object) { $epoch_value = $object->getEpoch(); if ($epoch_value === null) { diff --git a/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php index a229fcb41c..845ce9ee06 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php @@ -13,12 +13,12 @@ final class PhabricatorDashboardQueryPanelInstallController $e_name = true; $v_engine = $request->getStr('engine'); - if (!strlen($v_engine)) { + if (!phutil_nonempty_string($v_engine)) { $v_engine = $request->getURIData('engineKey'); } $v_query = $request->getStr('query'); - if (!strlen($v_query)) { + if (!phutil_nonempty_string($v_query)) { $v_query = $request->getURIData('queryKey'); } diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php index 4ab76d18b5..f40c0a05a1 100644 --- a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php @@ -15,7 +15,7 @@ final class PhabricatorDashboardPanelEditController // editing. $context_phid = $request->getStr('contextPHID'); - if (strlen($context_phid)) { + if (phutil_nonempty_string($context_phid)) { $context = id(new PhabricatorObjectQuery()) ->setViewer($viewer) ->withPHIDs(array($context_phid)) diff --git a/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php index eb1be21954..27e1335f6e 100644 --- a/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php +++ b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php @@ -17,16 +17,16 @@ abstract class PhabricatorDashboardObjectInstallWorkflow $target_identifier = head($target_tokens); } - if (!strlen($target_identifier)) { + if (!phutil_nonempty_string($target_identifier)) { $target_identifier = $request->getStr('target'); } - if (!strlen($target_identifier)) { + if (!phutil_nonempty_string($target_identifier)) { $target_identifier = $this->getMode(); } $target = null; - if (strlen($target_identifier)) { + if (phutil_nonempty_string($target_identifier)) { $targets = array(); if (ctype_digit($target_identifier)) { @@ -74,7 +74,7 @@ abstract class PhabricatorDashboardObjectInstallWorkflow } $errors = array(); - if (strlen($target_identifier)) { + if (phutil_nonempty_string($target_identifier)) { if (!$target) { $errors[] = pht('Choose a valid object.'); } else if (!$can_edit) { diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php index 91c6d17833..54c26dd9d3 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php @@ -111,9 +111,11 @@ final class PhabricatorDashboardTabsPanelType $name = pht('Unnamed Tab'); } + $is_selected = (string)$idx === (string)$selected; + $tab_view = id(new PHUIListItemView()) ->setHref('#') - ->setSelected((string)$idx === (string)$selected) + ->setSelected($is_selected) ->addSigil('dashboard-tab-panel-tab') ->setMetadata(array('panelKey' => $idx)) ->setName($name); @@ -286,7 +288,7 @@ final class PhabricatorDashboardTabsPanelType 'div', array( 'id' => $content_id, - 'style' => ($idx == $selected) ? null : 'display: none', + 'style' => $is_selected ? null : 'display: none', ), $panel_content); diff --git a/src/applications/differential/customfield/DifferentialBranchField.php b/src/applications/differential/customfield/DifferentialBranchField.php index 2387e3cd3f..60291b6be3 100644 --- a/src/applications/differential/customfield/DifferentialBranchField.php +++ b/src/applications/differential/customfield/DifferentialBranchField.php @@ -36,8 +36,8 @@ final class DifferentialBranchField } private function getBranchDescription(DifferentialDiff $diff) { - $branch = $diff->getBranch(); - $bookmark = $diff->getBookmark(); + $branch = coalesce($diff->getBranch(), ''); + $bookmark = coalesce($diff->getBookmark(), ''); if (strlen($branch) && strlen($bookmark)) { return pht('%s (bookmark) on %s (branch)', $bookmark, $branch); diff --git a/src/applications/differential/editor/DifferentialRevisionEditEngine.php b/src/applications/differential/editor/DifferentialRevisionEditEngine.php index 74fee82219..995179a864 100644 --- a/src/applications/differential/editor/DifferentialRevisionEditEngine.php +++ b/src/applications/differential/editor/DifferentialRevisionEditEngine.php @@ -307,7 +307,7 @@ final class DifferentialRevisionEditEngine pht('Hold as Draft')) ->setTransactionType( DifferentialRevisionHoldDraftTransaction::TRANSACTIONTYPE) - ->setDescription(pht('Hold revision as as draft.')) + ->setDescription(pht('Hold revision as draft.')) ->setConduitDescription( pht( 'Change autosubmission from draft state after builds finish.')) diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index 345fdff72a..b935b09b2d 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -218,7 +218,7 @@ final class DifferentialTransactionEditor // No "$", to allow for branches like T123_demo. $match = null; - if (preg_match('/^T(\d+)/i', $branch, $match)) { + if ($branch !== null && preg_match('/^T(\d+)/i', $branch, $match)) { $task_id = $match[1]; $tasks = id(new ManiphestTaskQuery()) ->setViewer($this->getActor()) diff --git a/src/applications/differential/xaction/DifferentialRevisionPlanChangesTransaction.php b/src/applications/differential/xaction/DifferentialRevisionPlanChangesTransaction.php index 144152526d..381a61a09d 100644 --- a/src/applications/differential/xaction/DifferentialRevisionPlanChangesTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionPlanChangesTransaction.php @@ -86,7 +86,7 @@ final class DifferentialRevisionPlanChangesTransaction if ($object->isClosed()) { throw new Exception( pht( - 'You can not plan changes to this this revision because it has '. + 'You can not plan changes to this revision because it has '. 'already been closed.')); } diff --git a/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php index 345e63fc3b..e37e3ccaf6 100644 --- a/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php @@ -30,7 +30,7 @@ final class DiffusionBranchQueryConduitAPIMethod $repository = $drequest->getRepository(); $contains = $request->getValue('contains'); - if (strlen($contains)) { + if (phutil_nonempty_string($contains)) { // See PHI958 (and, earlier, PHI720). If "patterns" are provided, pass // them to "git branch ..." to let callers test for reachability from @@ -80,7 +80,7 @@ final class DiffusionBranchQueryConduitAPIMethod ->setRepository($repository); $contains = $request->getValue('contains'); - if (strlen($contains)) { + if (phutil_nonempty_string($contains)) { $query->withContainsCommit($contains); } diff --git a/src/applications/diffusion/controller/DiffusionBranchTableController.php b/src/applications/diffusion/controller/DiffusionBranchTableController.php index 13f566a57b..63b1dbc592 100644 --- a/src/applications/diffusion/controller/DiffusionBranchTableController.php +++ b/src/applications/diffusion/controller/DiffusionBranchTableController.php @@ -26,7 +26,7 @@ final class DiffusionBranchTableController extends DiffusionController { ); $contains = $drequest->getSymbolicCommit(); - if (strlen($contains)) { + if (phutil_nonempty_string($contains)) { $params['contains'] = $contains; } diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index b3595c1b72..618ee1a631 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -97,19 +97,19 @@ abstract class DiffusionController extends PhabricatorController { AphrontRequest $request) { $short_name = $request->getURIData('repositoryShortName'); - if (strlen($short_name)) { + if (phutil_nonempty_string($short_name)) { // If the short name ends in ".git", ignore it. $short_name = preg_replace('/\\.git\z/', '', $short_name); return $short_name; } $identifier = $request->getURIData('repositoryCallsign'); - if (strlen($identifier)) { + if (phutil_nonempty_string($identifier)) { return $identifier; } $id = $request->getURIData('repositoryID'); - if (strlen($id)) { + if (phutil_nonempty_string($id)) { return (int)$id; } @@ -153,7 +153,7 @@ abstract class DiffusionController extends PhabricatorController { if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) { $branch_name = $drequest->getBranch(); - if (strlen($branch_name)) { + if (phutil_nonempty_string($branch_name)) { $repository_name .= ' ('.$branch_name.')'; } } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php index dfb84cc3f0..e6d07d418f 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php @@ -40,7 +40,7 @@ final class DiffusionRepositoryManagePanelsController } $selected = $request->getURIData('panel'); - if (!strlen($selected)) { + if (!phutil_nonempty_string($selected)) { $selected = head_key($panels); } diff --git a/src/applications/diffusion/controller/DiffusionServeController.php b/src/applications/diffusion/controller/DiffusionServeController.php index 3040328fbf..89430eef37 100644 --- a/src/applications/diffusion/controller/DiffusionServeController.php +++ b/src/applications/diffusion/controller/DiffusionServeController.php @@ -43,8 +43,8 @@ final class DiffusionServeController extends DiffusionController { return null; } - $content_type = $request->getHTTPHeader('Content-Type'); - $user_agent = idx($_SERVER, 'HTTP_USER_AGENT'); + $content_type = $request->getHTTPHeader('Content-Type', ''); + $user_agent = idx($_SERVER, 'HTTP_USER_AGENT', ''); $request_type = $request->getHTTPHeader('X-Phabricator-Request-Type'); // This may have a "charset" suffix, so only match the prefix. diff --git a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php index fdd477f874..6ad26a399a 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php @@ -219,7 +219,7 @@ final class DiffusionRepositoryBasicsManagementPanel $view->addProperty(pht('Type'), $type); $callsign = $repository->getCallsign(); - if (!strlen($callsign)) { + if (!phutil_nonempty_string($callsign)) { $callsign = phutil_tag('em', array(), pht('No Callsign')); } $view->addProperty(pht('Callsign'), $callsign); diff --git a/src/applications/diffusion/request/DiffusionGitRequest.php b/src/applications/diffusion/request/DiffusionGitRequest.php index a283fff206..16953f5996 100644 --- a/src/applications/diffusion/request/DiffusionGitRequest.php +++ b/src/applications/diffusion/request/DiffusionGitRequest.php @@ -3,6 +3,9 @@ final class DiffusionGitRequest extends DiffusionRequest { protected function isStableCommit($symbol) { + if ($symbol === null) { + return false; + } return preg_match('/^[a-f0-9]{40}\z/', $symbol); } diff --git a/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php b/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php index e0662b1e1a..cc9da44723 100644 --- a/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php +++ b/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php @@ -41,7 +41,7 @@ final class DiffusionRepositoryDatasource $parts[] = $name; $slug = $repository->getRepositorySlug(); - if (strlen($slug)) { + if (phutil_nonempty_string($slug)) { $parts[] = $slug; } diff --git a/src/applications/diviner/query/DivinerBookQuery.php b/src/applications/diviner/query/DivinerBookQuery.php index 2d6527ec96..e809099c7e 100644 --- a/src/applications/diviner/query/DivinerBookQuery.php +++ b/src/applications/diviner/query/DivinerBookQuery.php @@ -133,7 +133,7 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery { $this->phids); } - if (strlen($this->nameLike)) { + if (phutil_nonempty_string($this->nameLike)) { $where[] = qsprintf( $conn, 'name LIKE %~', @@ -147,7 +147,7 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery { $this->names); } - if (strlen($this->namePrefix)) { + if (phutil_nonempty_string($this->namePrefix)) { $where[] = qsprintf( $conn, 'name LIKE %>', diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php index 38b99208a7..d62e6a1e18 100644 --- a/src/applications/diviner/storage/DivinerLiveSymbol.php +++ b/src/applications/diviner/storage/DivinerLiveSymbol.php @@ -182,7 +182,7 @@ final class DivinerLiveSymbol extends DivinerDAO public function setTitle($value) { $this->writeField('title', $value); - if (strlen($value)) { + if (phutil_nonempty_string($value)) { $slug = DivinerAtomRef::normalizeTitleString($value); $hash = PhabricatorHash::digestForIndex($slug); $this->titleSlugHash = $hash; diff --git a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php index 86b75c8480..866e8b9ee6 100644 --- a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php +++ b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php @@ -194,7 +194,7 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow { $identifier = $args->getArg('repository'); $repository = null; - if (strlen($identifier)) { + if (phutil_nonempty_string($identifier)) { $repository = id(new PhabricatorRepositoryQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withIdentifiers(array($identifier)) diff --git a/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php index 4f827f7603..f1406d3efd 100644 --- a/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php +++ b/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php @@ -183,12 +183,21 @@ final class PhabricatorFilesComposeAvatarBuiltinFile 'image/png'); } + /** + * Convert a color from RGBA to a value usable in PHP-GD. + * Each RGB color should be expressed as an integer from 0 to 255. + * The Alpha Channel should be expressed as a float from 0 to 1. + * @param array $rgba array( int Red, int Green, int Blue, float Alpha ) + * @return int + */ private static function rgba2gd($rgba) { + // When working with a truecolor image, we can use bitwise operations + // https://www.php.net/manual/en/function.imagecolorallocate.php#49168 $r = $rgba[0]; $g = $rgba[1]; $b = $rgba[2]; $a = $rgba[3]; - $a = (1 - $a) * 255; + $a = round(((1 - $a) * 255), 0); return ($a << 24) | ($r << 16) | ($g << 8) | $b; } diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php index 8189b30a21..b292b6f4b8 100644 --- a/src/applications/files/controller/PhabricatorFileDataController.php +++ b/src/applications/files/controller/PhabricatorFileDataController.php @@ -29,7 +29,7 @@ final class PhabricatorFileDataController extends PhabricatorFileController { $request_kind = $request->getURIData('kind'); $is_download = ($request_kind === 'download'); - if (!strlen($alt) || $main_domain == $alt_domain) { + if (!phutil_nonempty_string($alt) || $main_domain == $alt_domain) { // No alternate domain. $should_redirect = false; $is_alternate_domain = false; @@ -69,7 +69,7 @@ final class PhabricatorFileDataController extends PhabricatorFileController { // an initial request for bytes 0-1 of the audio file, and things go south // if we can't respond with a 206 Partial Content. $range = $request->getHTTPHeader('range'); - if (strlen($range)) { + if (phutil_nonempty_string($range)) { list($begin, $end) = $response->parseHTTPRange($range); } diff --git a/src/applications/files/controller/PhabricatorFileViewController.php b/src/applications/files/controller/PhabricatorFileViewController.php index 389fc66247..2dea0a51ce 100644 --- a/src/applications/files/controller/PhabricatorFileViewController.php +++ b/src/applications/files/controller/PhabricatorFileViewController.php @@ -311,7 +311,7 @@ final class PhabricatorFileViewController extends PhabricatorFileController { $file->getStorageHandle()); $custom_alt = $file->getCustomAltText(); - if (strlen($custom_alt)) { + if (phutil_nonempty_string($custom_alt)) { $finfo->addProperty(pht('Custom Alt Text'), $custom_alt); } diff --git a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php index 5a4cb77340..f43689bbba 100644 --- a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php +++ b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php @@ -60,12 +60,12 @@ abstract class PhabricatorDocumentRenderingEngine } $encode_setting = $request->getStr('encode'); - if (strlen($encode_setting)) { + if (phutil_nonempty_string($encode_setting)) { $engine->setEncodingConfiguration($encode_setting); } $highlight_setting = $request->getStr('highlight'); - if (strlen($highlight_setting)) { + if (phutil_nonempty_string($highlight_setting)) { $engine->setHighlightingConfiguration($highlight_setting); } diff --git a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php index 9f37bdcaab..a81cb33726 100644 --- a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php +++ b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php @@ -197,7 +197,7 @@ final class PhabricatorEmbedFileRemarkupRule $alt = $options['alt']; } - if (!strlen($alt)) { + if (!phutil_nonempty_string($alt)) { $alt = $file->getAltText(); } @@ -346,10 +346,11 @@ final class PhabricatorEmbedFileRemarkupRule } private function parseDimension($string) { - $string = trim($string); - - if (preg_match('/^(?:\d*\\.)?\d+%?$/', $string)) { - return $string; + if ($string !== null) { + $string = trim($string); + if (preg_match('/^(?:\d*\\.)?\d+%?$/', $string)) { + return $string; + } } return null; diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index 355aa2d215..44e35c6b72 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -1278,7 +1278,7 @@ final class PhabricatorFile extends PhabricatorFileDAO public function getAltText() { $alt = $this->getCustomAltText(); - if (strlen($alt)) { + if (phutil_nonempty_string($alt)) { return $alt; } diff --git a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php index 76aacbe36f..cd65c9a197 100644 --- a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php +++ b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php @@ -67,7 +67,7 @@ final class PhabricatorGlobalUploadTargetView extends AphrontView { require_celerity_resource('global-drag-and-drop-css'); $hint_text = $this->getHintText(); - if (!strlen($hint_text)) { + if (!phutil_nonempty_string($hint_text)) { $hint_text = "\xE2\x87\xAA ".pht('Drop Files to Upload'); } diff --git a/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php b/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php index dcf3c6f76f..c3151910e4 100644 --- a/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php +++ b/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php @@ -27,12 +27,12 @@ final class PhabricatorFileAltTextTransaction $old_value = $this->getOldValue(); $new_value = $this->getNewValue(); - if (!strlen($old_value)) { + if (!phutil_nonempty_string($old_value)) { return pht( '%s set the alternate text for this file to %s.', $this->renderAuthor(), $this->renderNewValue()); - } else if (!strlen($new_value)) { + } else if (!phutil_nonempty_string($new_value)) { return pht( '%s removed the alternate text for this file (was %s).', $this->renderAuthor(), diff --git a/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php b/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php index 1bd7094799..65f27ae374 100644 --- a/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php +++ b/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php @@ -99,7 +99,7 @@ final class HarbormasterBuildMessageResumeTransaction throw new HarbormasterMessageException( pht('Unable to Resume Build'), pht( - 'You can not resume this build beacuse it is already resuming.')); + 'You can not resume this build because it is already resuming.')); } if ($build->isRestarting()) { diff --git a/src/applications/herald/typeahead/HeraldRuleDatasource.php b/src/applications/herald/typeahead/HeraldRuleDatasource.php index 88343bd433..6b73bc0ab6 100644 --- a/src/applications/herald/typeahead/HeraldRuleDatasource.php +++ b/src/applications/herald/typeahead/HeraldRuleDatasource.php @@ -22,7 +22,7 @@ final class HeraldRuleDatasource $query = id(new HeraldRuleQuery()) ->setViewer($viewer); - if (preg_match('/^[hH]\d+\z/', $raw_query)) { + if (($raw_query !== null) && preg_match('/^[hH]\d+\z/', $raw_query)) { $id = trim($raw_query, 'hH'); $id = (int)$id; $query->withIDs(array($id)); diff --git a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php index dbf1586366..c3ebd825db 100644 --- a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php +++ b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php @@ -31,7 +31,7 @@ final class PhabricatorHomeLauncherProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php b/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php index a002b59da5..9a53e8fad7 100644 --- a/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php +++ b/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php @@ -26,7 +26,7 @@ final class PhabricatorHomeProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php index 14ebca9d04..ac3e181889 100644 --- a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php +++ b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php @@ -127,12 +127,12 @@ final class LegalpadDocumentSignatureSearchEngine } $name_contains = $saved->getParameter('nameContains'); - if (strlen($name_contains)) { + if (phutil_nonempty_string($name_contains)) { $query->withNameContains($name_contains); } $email_contains = $saved->getParameter('emailContains'); - if (strlen($email_contains)) { + if (phutil_nonempty_string($email_contains)) { $query->withEmailContains($email_contains); } diff --git a/src/applications/maniphest/controller/ManiphestReportController.php b/src/applications/maniphest/controller/ManiphestReportController.php index 6fc19ece98..a7efe89194 100644 --- a/src/applications/maniphest/controller/ManiphestReportController.php +++ b/src/applications/maniphest/controller/ManiphestReportController.php @@ -186,7 +186,10 @@ final class ManiphestReportController extends ManiphestController { switch ($row['transactionType']) { case ManiphestTaskStatusTransaction::TRANSACTIONTYPE: // NOTE: Hack to avoid json_decode(). - $oldv = trim($row['oldValue'], '"'); + $oldv = $row['oldValue']; + if ($oldv !== null) { + $oldv = trim($oldv, '"'); + } $newv = trim($row['newValue'], '"'); break; case ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE: diff --git a/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php b/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php index 5a69199874..3b24dff590 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php +++ b/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php @@ -97,8 +97,17 @@ final class ManiphestTaskPointsTransaction return 'fa-calculator'; } + /** + * Normalize your Story Points from generic stuff to double or null. + * @param mixed $value Your raw Story Points + * @return double|null + */ private function getValueForPoints($value) { - if (!strlen($value)) { + // The Point can be various types also thanks to Conduit API + // like integers, floats, null, and strings of course. + // Everything meaningful must be printable as a string. + $is_empty = phutil_string_cast($value) === ''; + if ($is_empty) { $value = null; } if ($value !== null) { diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index 8be6d73a1d..8cceeb7396 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -114,7 +114,7 @@ final class PhabricatorApplicationDetailViewController } $overview = $application->getOverview(); - if (strlen($overview)) { + if (phutil_nonempty_string($overview)) { $overview = new PHUIRemarkupView($viewer, $overview); $properties->addSectionHeader( pht('Overview'), PHUIPropertyListView::ICON_SUMMARY); diff --git a/src/applications/meta/panel/PhabricatorApplicationConfigurationPanel.php b/src/applications/meta/panel/PhabricatorApplicationConfigurationPanel.php index 358a6f753b..d96132c9b0 100644 --- a/src/applications/meta/panel/PhabricatorApplicationConfigurationPanel.php +++ b/src/applications/meta/panel/PhabricatorApplicationConfigurationPanel.php @@ -24,7 +24,13 @@ abstract class PhabricatorApplicationConfigurationPanel return $this->application; } - public function getPanelURI($path = null) { + /** + * Get the URI for this application configuration panel. + * + * @param string? Optional path to append. + * @return string Relative URI for the panel. + */ + public function getPanelURI($path = '') { $app_key = get_class($this->getApplication()); $panel_key = $this->getPanelKey(); $base = "/applications/panel/{$app_key}/{$panel_key}/"; diff --git a/src/applications/meta/query/PhabricatorAppSearchEngine.php b/src/applications/meta/query/PhabricatorAppSearchEngine.php index ee938abbbb..e68570fe1c 100644 --- a/src/applications/meta/query/PhabricatorAppSearchEngine.php +++ b/src/applications/meta/query/PhabricatorAppSearchEngine.php @@ -45,7 +45,7 @@ final class PhabricatorAppSearchEngine ->withUnlisted(false); $name = $saved->getParameter('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { $query->withNameContains($name); } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php b/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php index e38c7f9801..0d9b89c684 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php @@ -421,7 +421,7 @@ final class PhabricatorMetaMTAMailViewController $properties->addProperty(pht('Message PHID'), $mail->getPHID()); $details = $mail->getMessage(); - if (!strlen($details)) { + if (!phutil_nonempty_string($details)) { $details = phutil_tag('em', array(), pht('None')); } $properties->addProperty(pht('Status Details'), $details); diff --git a/src/applications/multimeter/controller/MultimeterSampleController.php b/src/applications/multimeter/controller/MultimeterSampleController.php index 190a839f63..0aca60f0e1 100644 --- a/src/applications/multimeter/controller/MultimeterSampleController.php +++ b/src/applications/multimeter/controller/MultimeterSampleController.php @@ -10,7 +10,7 @@ final class MultimeterSampleController extends MultimeterController { $viewer = $this->getViewer(); $group_map = $this->getColumnMap(); - $group = explode('.', $request->getStr('group')); + $group = explode('.', $request->getStr('group', '')); $group = array_intersect($group, array_keys($group_map)); $group = array_fuse($group); diff --git a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php index ea60acb54c..e93b3df7e9 100644 --- a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php +++ b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php @@ -26,7 +26,7 @@ final class PhabricatorOwnersPackageDatasource // If the user is querying by monogram explicitly, like "O123", do an ID // search. Otherwise, do an ngram substring search. - if (preg_match('/^[oO]\d+\z/', $raw_query)) { + if ($raw_query && preg_match('/^[oO]\d+\z/', $raw_query)) { $id = trim($raw_query, 'oO'); $id = (int)$id; $query->withIDs(array($id)); diff --git a/src/applications/people/cache/PhabricatorUserProfileImageCacheType.php b/src/applications/people/cache/PhabricatorUserProfileImageCacheType.php index 8babff859f..195d880fff 100644 --- a/src/applications/people/cache/PhabricatorUserProfileImageCacheType.php +++ b/src/applications/people/cache/PhabricatorUserProfileImageCacheType.php @@ -91,6 +91,9 @@ final class PhabricatorUserProfileImageCacheType } public function isRawCacheDataValid(PhabricatorUser $user, $key, $data) { + if ($data === null) { + return false; + } $parts = explode(',', $data, 2); $version = reset($parts); return ($version === $this->getCacheVersion($user)); diff --git a/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php b/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php index 868cc13da1..4bbbb2466e 100644 --- a/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php +++ b/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php @@ -118,14 +118,14 @@ final class PhabricatorPeopleWelcomeMailEngine $recipient = $this->getRecipient(); $custom_body = $this->getWelcomeMessage(); - if (strlen($custom_body)) { + if (phutil_nonempty_string($custom_body)) { return $this->newRemarkupText($custom_body); } $default_body = PhabricatorAuthMessage::loadMessageText( $recipient, PhabricatorAuthWelcomeMailMessageType::MESSAGEKEY); - if (strlen($default_body)) { + if (phutil_nonempty_string($default_body)) { return $this->newRemarkupText($default_body); } diff --git a/src/applications/people/menuitem/PhabricatorPeopleBadgesProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleBadgesProfileMenuItem.php index 71f3aa1392..470eb52f12 100644 --- a/src/applications/people/menuitem/PhabricatorPeopleBadgesProfileMenuItem.php +++ b/src/applications/people/menuitem/PhabricatorPeopleBadgesProfileMenuItem.php @@ -22,7 +22,7 @@ final class PhabricatorPeopleBadgesProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/people/menuitem/PhabricatorPeopleCommitsProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleCommitsProfileMenuItem.php index b6c1c446cc..20e1b1f35a 100644 --- a/src/applications/people/menuitem/PhabricatorPeopleCommitsProfileMenuItem.php +++ b/src/applications/people/menuitem/PhabricatorPeopleCommitsProfileMenuItem.php @@ -22,7 +22,7 @@ final class PhabricatorPeopleCommitsProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php index 43d2271a79..127d48ae39 100644 --- a/src/applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php +++ b/src/applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php @@ -22,7 +22,7 @@ final class PhabricatorPeopleManageProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php index cfa760fcd6..1c823ec091 100644 --- a/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php +++ b/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php @@ -22,7 +22,7 @@ final class PhabricatorPeopleRevisionsProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php index 5dea58cb29..baffadc6d8 100644 --- a/src/applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php +++ b/src/applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php @@ -22,7 +22,7 @@ final class PhabricatorPeopleTasksProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/people/query/PhabricatorPeopleSearchEngine.php b/src/applications/people/query/PhabricatorPeopleSearchEngine.php index 57ed133df4..bdeab953ec 100644 --- a/src/applications/people/query/PhabricatorPeopleSearchEngine.php +++ b/src/applications/people/query/PhabricatorPeopleSearchEngine.php @@ -200,6 +200,7 @@ final class PhabricatorPeopleSearchEngine protected function getBuiltinQueryNames() { $names = array( 'active' => pht('Active'), + 'admin' => pht('Administrators'), 'all' => pht('All'), ); @@ -221,6 +222,9 @@ final class PhabricatorPeopleSearchEngine case 'active': return $query ->setParameter('isDisabled', false); + case 'admin': + return $query + ->setParameter('isAdmin', true); case 'approval': return $query ->setParameter('needsApproval', true) diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index 5edfb2d537..82f1affe82 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -1159,7 +1159,7 @@ final class PhabricatorUser } public function getSSHKeyDefaultName() { - return 'id_rsa_phabricator'; + return 'id_rsa_phorge'; } public function getSSHKeyNotifyPHIDs() { diff --git a/src/applications/phame/controller/PhameLiveController.php b/src/applications/phame/controller/PhameLiveController.php index 472f73c8c1..e87cfad138 100644 --- a/src/applications/phame/controller/PhameLiveController.php +++ b/src/applications/phame/controller/PhameLiveController.php @@ -87,7 +87,7 @@ abstract class PhameLiveController extends PhameController { $this->isExternal = $is_external; $this->isLive = $is_live; - if (strlen($post_id)) { + if (phutil_nonempty_string($post_id)) { $post_query = id(new PhamePostQuery()) ->setViewer($viewer) ->needHeaderImage(true) diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index 95507d61dc..717658ec03 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -169,7 +169,7 @@ final class PhameBlog extends PhameDAO } public function getLiveURI() { - if (strlen($this->getDomain())) { + if (phutil_nonempty_string($this->getDomain())) { return $this->getExternalLiveURI(); } else { return $this->getInternalLiveURI(); diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index 21149f07c2..5291bcd465 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -67,7 +67,8 @@ final class PhamePost extends PhameDAO $blog = $this->getBlog(); $is_draft = $this->isDraft(); $is_archived = $this->isArchived(); - if (strlen($blog->getDomain()) && !$is_draft && !$is_archived) { + if (phutil_nonempty_string($blog->getDomain()) && + !$is_draft && !$is_archived) { return $this->getExternalLiveURI(); } else { return $this->getInternalLiveURI(); diff --git a/src/applications/pholio/controller/PholioImageUploadController.php b/src/applications/pholio/controller/PholioImageUploadController.php index 0ff5e061f5..44d7ea7eed 100644 --- a/src/applications/pholio/controller/PholioImageUploadController.php +++ b/src/applications/pholio/controller/PholioImageUploadController.php @@ -18,7 +18,7 @@ final class PholioImageUploadController extends PholioController { return new Aphront404Response(); } - if (!strlen($title)) { + if (!phutil_nonempty_string($title)) { $title = $file->getName(); } diff --git a/src/applications/phortune/storage/PhortuneMerchant.php b/src/applications/phortune/storage/PhortuneMerchant.php index 6e0bf81e22..25426d3b28 100644 --- a/src/applications/phortune/storage/PhortuneMerchant.php +++ b/src/applications/phortune/storage/PhortuneMerchant.php @@ -157,7 +157,7 @@ final class PhortuneMerchant extends PhortuneDAO } public function describeAutomaticCapability($capability) { - return pht("A merchant's members an always view and edit it."); + return pht("A merchant's members can always view and edit it."); } } diff --git a/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php b/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php index 08b8b69422..20272fda27 100644 --- a/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php +++ b/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php @@ -17,7 +17,7 @@ final class PhortuneAccountNameTransaction $old = $this->getOldValue(); $new = $this->getNewValue(); - if (strlen($old) && strlen($new)) { + if (phutil_nonempty_string($old) && phutil_nonempty_string($new)) { return pht( '%s renamed this account from %s to %s.', $this->renderAuthor(), diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index 1476b24c46..d59541c401 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -556,7 +556,7 @@ final class PhrictionTransactionEditor ->setContent($this->getOldContent()->getContent()) ->setDescription(''); - if (strlen($this->getDescription())) { + if (phutil_nonempty_string($this->getDescription())) { $content->setDescription($this->getDescription()); } diff --git a/src/applications/project/controller/PhabricatorProjectMembersAddController.php b/src/applications/project/controller/PhabricatorProjectMembersAddController.php index 79c66dc5b1..572e71f51a 100644 --- a/src/applications/project/controller/PhabricatorProjectMembersAddController.php +++ b/src/applications/project/controller/PhabricatorProjectMembersAddController.php @@ -27,9 +27,14 @@ final class PhabricatorProjectMembersAddController $copy = pht('Parent projects and milestones do not support adding '. 'members. You can add members directly to any non-parent subproject.'); + $subprojects_uri = "/project/subprojects/{$id}/"; + return $this->newDialog() ->setTitle(pht('Unsupported Project')) ->appendParagraph($copy) + ->setSubmitURI($subprojects_uri) + ->addSubmitButton(pht('See Subprojects')) + ->setDisableWorkflowOnSubmit(true) ->addCancelButton($done_uri); } diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php index 1fd8b3c677..7f25905748 100644 --- a/src/applications/project/controller/PhabricatorProjectMoveController.php +++ b/src/applications/project/controller/PhabricatorProjectMoveController.php @@ -24,9 +24,11 @@ final class PhabricatorProjectMoveController $ordering = id(clone $ordering) ->setViewer($viewer); + // When the Workboard view is "Group By " the header provides + // that context in JSON form $edit_header = null; $raw_header = $request->getStr('header'); - if (strlen($raw_header)) { + if (phutil_nonempty_string($raw_header)) { $edit_header = phutil_json_decode($raw_header); } else { $edit_header = array(); diff --git a/src/applications/project/controller/PhabricatorProjectUpdateController.php b/src/applications/project/controller/PhabricatorProjectUpdateController.php index 7cbd77b4cb..5707693654 100644 --- a/src/applications/project/controller/PhabricatorProjectUpdateController.php +++ b/src/applications/project/controller/PhabricatorProjectUpdateController.php @@ -38,9 +38,14 @@ final class PhabricatorProjectUpdateController $copy = pht('Parent projects and milestones do not support adding '. 'members. You can add members directly to any non-parent subproject.'); + $subprojects_uri = "/project/subprojects/{$id}/"; + return $this->newDialog() ->setTitle(pht('Unsupported Project')) ->appendParagraph($copy) + ->setSubmitURI($subprojects_uri) + ->addSubmitButton(pht('See Subprojects')) + ->setDisableWorkflowOnSubmit(true) ->addCancelButton($done_uri); } diff --git a/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php index a3021e0239..ec7b88d599 100644 --- a/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php @@ -31,7 +31,7 @@ final class PhabricatorProjectDetailsProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php index 9b8a769318..656bbbe9a3 100644 --- a/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php @@ -31,7 +31,7 @@ final class PhabricatorProjectManageProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php index 11a57d3a5b..e3c7f9fceb 100644 --- a/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php @@ -21,7 +21,7 @@ final class PhabricatorProjectMembersProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/menuitem/PhabricatorProjectReportsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectReportsProfileMenuItem.php index 8639b6d72c..3b0acdf375 100644 --- a/src/applications/project/menuitem/PhabricatorProjectReportsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectReportsProfileMenuItem.php @@ -46,7 +46,7 @@ final class PhabricatorProjectReportsProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php index b1782e8f1c..39b25c1f00 100644 --- a/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php @@ -29,7 +29,7 @@ final class PhabricatorProjectSubprojectsProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php index 34152f85e7..2f0fbb284b 100644 --- a/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php @@ -38,7 +38,7 @@ final class PhabricatorProjectWorkboardProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/project/state/PhabricatorWorkboardViewState.php b/src/applications/project/state/PhabricatorWorkboardViewState.php index 04f8498d49..0d5d94f1f2 100644 --- a/src/applications/project/state/PhabricatorWorkboardViewState.php +++ b/src/applications/project/state/PhabricatorWorkboardViewState.php @@ -41,7 +41,7 @@ final class PhabricatorWorkboardViewState $this->requestState['filter'] = $request->getStr('filter'); } - if (strlen($request->getURIData('queryKey'))) { + if (phutil_nonempty_string($request->getURIData('queryKey'))) { $this->requestState['filter'] = $request->getURIData('queryKey'); } @@ -169,7 +169,7 @@ final class PhabricatorWorkboardViewState public function getQueryKey() { $request_query = idx($this->requestState, 'filter'); - if (strlen($request_query)) { + if (phutil_nonempty_string($request_query)) { return $request_query; } @@ -203,7 +203,7 @@ final class PhabricatorWorkboardViewState $default_query = $project->getDefaultWorkboardFilter(); - if (strlen($default_query)) { + if (phutil_nonempty_string($default_query)) { return $default_query; } diff --git a/src/applications/project/typeahead/PhabricatorProjectDatasource.php b/src/applications/project/typeahead/PhabricatorProjectDatasource.php index 5b999a997f..86478a5e1e 100644 --- a/src/applications/project/typeahead/PhabricatorProjectDatasource.php +++ b/src/applications/project/typeahead/PhabricatorProjectDatasource.php @@ -21,7 +21,9 @@ final class PhabricatorProjectDatasource $raw_query = $this->getRawQuery(); // Allow users to type "#qa" or "qa" to find "Quality Assurance". - $raw_query = ltrim($raw_query, '#'); + if ($raw_query !== null) { + $raw_query = ltrim($raw_query, '#'); + } $tokens = self::tokenizeString($raw_query); $query = id(new PhabricatorProjectQuery()) @@ -83,7 +85,7 @@ final class PhabricatorProjectDatasource } $slug = $proj->getPrimarySlug(); - if (!strlen($slug)) { + if (!phutil_nonempty_string($slug)) { foreach ($proj->getSlugs() as $slug_object) { $slug = $slug_object->getSlug(); if (strlen($slug)) { @@ -132,7 +134,7 @@ final class PhabricatorProjectDatasource ->setPriorityType('proj') ->setClosed($closed); - if (strlen($slug)) { + if (phutil_nonempty_string($slug)) { $proj_result->setAutocomplete('#'.$slug); } @@ -142,7 +144,7 @@ final class PhabricatorProjectDatasource $proj_result->addAttribute($proj->getDisplayIconName()); $description = idx($descriptions, $phid); - if (strlen($description)) { + if (phutil_nonempty_string($description)) { $summary = PhabricatorMarkupEngine::summarizeSentence($description); $proj_result->addAttribute($summary); } diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php index 0955d54b98..c23fc41624 100644 --- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php +++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php @@ -50,7 +50,7 @@ final class PhabricatorRepositoryEditor // If the repository does not have a local path yet, assign it one based // on its ID. We can't do this earlier because we won't have an ID yet. $local_path = $object->getLocalPath(); - if (!strlen($local_path)) { + if (!phutil_nonempty_string($local_path)) { $local_key = 'repository.default-local-path'; $local_root = PhabricatorEnv::getEnvConfig($local_key); diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php index 65fe0adaad..6c2f64b31c 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php @@ -23,7 +23,7 @@ final class PhabricatorRepositoryManagementMaintenanceWorkflow 'name' => 'stop', 'help' => pht( 'Take repositories out of maintenance mode, returning them '. - 'to normal serice.'), + 'to normal service.'), ), array( 'name' => 'repositories', diff --git a/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php b/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php index 5e894333f6..a6177c20b5 100644 --- a/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php @@ -132,7 +132,7 @@ final class PhabricatorRepositoryRefCursorQuery $name_hashes); } - if (strlen($this->datasourceQuery)) { + if (phutil_nonempty_string($this->datasourceQuery)) { $where[] = qsprintf( $conn, 'refNameRaw LIKE %>', diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index 5c7c9ff33d..b05be618c0 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -217,7 +217,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO $monograms[] = 'R'.$this->getID(); $callsign = $this->getCallsign(); - if (strlen($callsign)) { + if (phutil_nonempty_string($callsign)) { $monograms[] = 'r'.$callsign; } diff --git a/src/applications/repository/storage/PhabricatorRepositoryURI.php b/src/applications/repository/storage/PhabricatorRepositoryURI.php index 26db694a66..774df1fd95 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryURI.php +++ b/src/applications/repository/storage/PhabricatorRepositoryURI.php @@ -752,7 +752,7 @@ final class PhabricatorRepositoryURI // without requiring an index rebuild. $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host'); - if (strlen($ssh_host)) { + if (phutil_nonempty_string($ssh_host)) { $domain_map[''] = $ssh_host; } diff --git a/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php b/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php index c3dd6f3d60..0ffb963b71 100644 --- a/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php +++ b/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php @@ -517,7 +517,7 @@ final class PhabricatorChangeParserTestCase '/dir', null, null, - // TODO: This might reasonbly be considered a bug in the parser; it + // TODO: This might reasonably be considered a bug in the parser; it // should probably be COPY_AWAY. DifferentialChangeType::TYPE_CHILD, DifferentialChangeType::FILE_DIRECTORY, diff --git a/src/applications/repository/xaction/PhabricatorRepositoryDefaultBranchTransaction.php b/src/applications/repository/xaction/PhabricatorRepositoryDefaultBranchTransaction.php index 23eebf60c8..949e394b91 100644 --- a/src/applications/repository/xaction/PhabricatorRepositoryDefaultBranchTransaction.php +++ b/src/applications/repository/xaction/PhabricatorRepositoryDefaultBranchTransaction.php @@ -17,12 +17,12 @@ final class PhabricatorRepositoryDefaultBranchTransaction $old = $this->getOldValue(); $new = $this->getNewValue(); - if (!strlen($new)) { + if (!phutil_nonempty_string($new)) { return pht( '%s removed %s as the default branch.', $this->renderAuthor(), $this->renderOldValue()); - } else if (!strlen($old)) { + } else if (!phutil_nonempty_string($old)) { return pht( '%s set the default branch to %s.', $this->renderAuthor(), diff --git a/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php b/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php index e81ecbe80b..f7a127005a 100644 --- a/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php +++ b/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php @@ -52,7 +52,7 @@ final class PhabricatorRepositoryIdentityAssignTransaction foreach ($xactions as $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); - if (!strlen($new)) { + if ($new === null || !strlen($new)) { continue; } diff --git a/src/applications/repository/xaction/PhabricatorRepositorySVNSubpathTransaction.php b/src/applications/repository/xaction/PhabricatorRepositorySVNSubpathTransaction.php index 10de2d9980..43ebefa015 100644 --- a/src/applications/repository/xaction/PhabricatorRepositorySVNSubpathTransaction.php +++ b/src/applications/repository/xaction/PhabricatorRepositorySVNSubpathTransaction.php @@ -17,12 +17,12 @@ final class PhabricatorRepositorySVNSubpathTransaction $old = $this->getOldValue(); $new = $this->getNewValue(); - if (!strlen($new)) { + if ($new === null || !strlen($new)) { return pht( '%s removed %s as the "Import Only" path.', $this->renderAuthor(), $this->renderOldValue()); - } else if (!strlen($old)) { + } else if ($old === null || !$old) { return pht( '%s set the repository "Import Only" path to %s.', $this->renderAuthor(), diff --git a/src/applications/search/compiler/PhutilSearchQueryCompiler.php b/src/applications/search/compiler/PhutilSearchQueryCompiler.php index c3f93e16c9..951939b52c 100644 --- a/src/applications/search/compiler/PhutilSearchQueryCompiler.php +++ b/src/applications/search/compiler/PhutilSearchQueryCompiler.php @@ -103,7 +103,9 @@ final class PhutilSearchQueryCompiler private function tokenizeQuery($query) { $maximum_bytes = 1024; - + if ($query === null) { + $query = ''; + } $query_bytes = strlen($query); if ($query_bytes > $maximum_bytes) { throw new PhutilSearchQueryCompilerSyntaxException( @@ -295,7 +297,7 @@ final class PhutilSearchQueryCompiler $use_substring = true; } else if (phutil_preg_match('/^_/', $value)) { // See T13632. Assume users searching for any term that begins - // with an undescore intend to perform substring search if they + // with an underscore intend to perform substring search if they // don't provide an explicit search function. $use_substring = true; } diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php index 290623e149..b7b512156f 100644 --- a/src/applications/search/controller/PhabricatorApplicationSearchController.php +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -115,7 +115,7 @@ final class PhabricatorApplicationSearchController if ($this->queryKey == 'advanced') { $run_query = false; $query_key = $request->getStr('query'); - } else if (!strlen($this->queryKey)) { + } else if (!phutil_nonempty_string($this->queryKey)) { $found_query_data = false; if ($request->isHTTPGet() || $request->isQuicksand()) { @@ -775,7 +775,7 @@ final class PhabricatorApplicationSearchController $force_nux) { // Don't render NUX if the user has clicked away from the default page. - if (strlen($this->getQueryKey())) { + if (phutil_nonempty_string($this->getQueryKey())) { return null; } diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index 95f1ffafa3..076a9a1e52 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -179,7 +179,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { $order = $saved->getParameter('order'); $builtin = $query->getBuiltinOrderAliasMap(); - if (strlen($order) && isset($builtin[$order])) { + if (phutil_nonempty_string($order) && isset($builtin[$order])) { $query->setOrder($order); } else { // If the order is invalid or not available, we choose the first @@ -872,7 +872,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { protected function readBoolFromRequest( AphrontRequest $request, $key) { - if (!strlen($request->getStr($key))) { + if (!phutil_nonempty_string($request->getStr($key))) { return null; } return $request->getBool($key); @@ -1137,7 +1137,8 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { $viewer = $this->requireViewer(); $query_key = $request->getValue('queryKey'); - if (!strlen($query_key)) { + $is_empty_query_key = phutil_string_cast($query_key) === ''; + if ($is_empty_query_key) { $saved_query = new PhabricatorSavedQuery(); } else if ($this->isBuiltinQuery($query_key)) { $saved_query = $this->buildSavedQueryFromBuiltin($query_key); diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index aedbcc787f..8799ae8f0b 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -135,7 +135,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { if ($is_view) { $selected_item = $this->selectViewItem($view_list, $item_id); } else { - if (!strlen($item_id)) { + if (!phutil_nonempty_scalar($item_id)) { $item_id = self::ITEM_MANAGE; } $selected_item = $this->selectEditItem($view_list, $item_id); @@ -1308,7 +1308,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { // render the default view instead. $selected_view = null; - if (strlen($item_id)) { + if (phutil_nonempty_string($item_id)) { $item_views = $view_list->getViewsWithItemIdentifier($item_id); if ($item_views) { $selected_view = head($item_views); diff --git a/src/applications/search/engine/PhabricatorProfileMenuItemView.php b/src/applications/search/engine/PhabricatorProfileMenuItemView.php index d947afcba6..7f0dd1d397 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuItemView.php +++ b/src/applications/search/engine/PhabricatorProfileMenuItemView.php @@ -140,7 +140,7 @@ final class PhabricatorProfileMenuItemView ->setName($this->getName()); $uri = $this->getURI(); - if (strlen($uri)) { + if (phutil_nonempty_string($uri)) { if ($this->getIsExternalLink()) { if (!PhabricatorEnv::isValidURIForLink($uri)) { $uri = '#'; @@ -176,7 +176,7 @@ final class PhabricatorProfileMenuItemView } $tooltip = $this->getTooltip(); - if (strlen($tooltip)) { + if (phutil_nonempty_string($tooltip)) { $view->setTooltip($tooltip); } diff --git a/src/applications/search/field/PhabricatorSearchDateField.php b/src/applications/search/field/PhabricatorSearchDateField.php index 41decd9503..8f43494222 100644 --- a/src/applications/search/field/PhabricatorSearchDateField.php +++ b/src/applications/search/field/PhabricatorSearchDateField.php @@ -17,7 +17,7 @@ final class PhabricatorSearchDateField } protected function validateControlValue($value) { - if (!strlen($value)) { + if (!phutil_nonempty_scalar($value)) { return; } @@ -32,7 +32,7 @@ final class PhabricatorSearchDateField } protected function parseDateTime($value) { - if (!strlen($value)) { + if (!phutil_nonempty_scalar($value)) { return null; } diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php index 9d89c52ff8..717bba7c39 100644 --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -117,7 +117,7 @@ final class PhabricatorDashboardProfileMenuItem return pht('Archived Dashboard'); } - if (strlen($this->getName($config))) { + if (phutil_nonempty_string($this->getName($config))) { return $this->getName($config); } else { return $dashboard->getName(); diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 71e3d7e8a5..23d5ad3f30 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -71,7 +71,7 @@ final class PhabricatorEditEngineProfileMenuItem if (!$form) { return pht('(Restricted/Invalid Form)'); } - if (strlen($this->getName($config))) { + if (phutil_nonempty_string($this->getName($config))) { return $this->getName($config); } else { return $form->getName(); diff --git a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php index 89ac4a5633..83c3133705 100644 --- a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php @@ -31,7 +31,7 @@ final class PhabricatorManageProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { return $name; } diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php index 773a0f09ac..2dc0270d24 100644 --- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php @@ -126,7 +126,7 @@ abstract class PhabricatorProfileMenuItem extends Phobject { $result = $xaction['new']; } - return !strlen($result); + return !phutil_nonempty_string($result); } final protected function newError($title, $message, $xaction = null) { diff --git a/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php index a888bb3175..665bb42b2f 100644 --- a/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php @@ -172,7 +172,7 @@ final class PhabricatorEmailAddressesSettingsPanel $email = null; $errors = array(); if ($request->isDialogFormPost()) { - $email = trim($request->getStr('email')); + $email = trim($request->getStr('email', '')); if ($new == 'verify') { // The user clicked "Done" from the "an email has been sent" dialog. @@ -184,7 +184,7 @@ final class PhabricatorEmailAddressesSettingsPanel new PhabricatorSettingsAddEmailAction(), 1); - if (!strlen($email)) { + if (!phutil_nonempty_string($email)) { $e_email = pht('Required'); $errors[] = pht('Email is required.'); } else if (!PhabricatorUserEmail::isValidAddress($email)) { diff --git a/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php b/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php index 3a49b6c3c3..2782851d93 100644 --- a/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php @@ -39,7 +39,7 @@ final class PhabricatorExternalEditorSettingsPanel $viewer = $this->getViewer(); $pattern = $viewer->getUserSetting(PhabricatorEditorSetting::SETTINGKEY); - if (!strlen($pattern)) { + if (!phutil_nonempty_string($pattern)) { return null; } diff --git a/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php b/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php index 0054610c28..492544bef6 100644 --- a/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php @@ -257,7 +257,7 @@ final class PhabricatorMultiFactorSettingsPanel // example, with SMS). if (!$request->isFormPost() || !$request->getBool('mfa.start')) { $enroll = $selected_provider->getEnrollMessage(); - if (!strlen($enroll)) { + if (!phutil_nonempty_string($enroll)) { $enroll = $selected_provider->getEnrollDescription($viewer); } diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php index d7fcbc2c7a..d88425598f 100644 --- a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php @@ -15,7 +15,7 @@ final class PhabricatorSpacesNamespaceNameTransaction public function getTitle() { $old = $this->getOldValue(); - if (!strlen($old)) { + if (!phutil_nonempty_string($old)) { return pht( '%s created this space.', $this->renderAuthor()); diff --git a/src/applications/transactions/bulk/PhabricatorBulkEngine.php b/src/applications/transactions/bulk/PhabricatorBulkEngine.php index 0091321245..e2d2c02a29 100644 --- a/src/applications/transactions/bulk/PhabricatorBulkEngine.php +++ b/src/applications/transactions/bulk/PhabricatorBulkEngine.php @@ -153,7 +153,7 @@ abstract class PhabricatorBulkEngine extends Phobject { ->setViewer($viewer); $query_key = $request->getURIData('queryKey'); - if (strlen($query_key)) { + if (phutil_nonempty_string($query_key)) { if ($search_engine->isBuiltinQuery($query_key)) { $saved = $search_engine->buildSavedQueryFromBuiltin($query_key); } else { diff --git a/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php b/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php index 82eaf08e83..10709bb79f 100644 --- a/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php +++ b/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php @@ -21,7 +21,7 @@ basis for essentially all edits and comments. Reviewing the transaction record allows you to see who edited an object, when, and how their edit changed things. -One common reason to call this method is that you're implmenting a webhook and +One common reason to call this method is that you're implementing a webhook and just received a notification that an object has changed. See the Webhooks documentation for more detailed discussion of this use case. diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 60ccdaa401..f70e172a99 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -941,7 +941,7 @@ abstract class PhabricatorEditEngine } } else { $form_key = $request->getURIData('formKey'); - if (strlen($form_key)) { + if (phutil_nonempty_string($form_key)) { $config = $this->loadEditEngineConfigurationWithIdentifier($form_key); if (!$config) { @@ -971,14 +971,14 @@ abstract class PhabricatorEditEngine } $page_key = $request->getURIData('pageKey'); - if (!strlen($page_key)) { + if (!phutil_nonempty_string($page_key)) { $pages = $this->getPages($object); if ($pages) { $page_key = head_key($pages); } } - if (strlen($page_key)) { + if (phutil_nonempty_string($page_key)) { $page = $this->selectPage($object, $page_key); if (!$page) { return new Aphront404Response(); @@ -1169,7 +1169,7 @@ abstract class PhabricatorEditEngine if ($this->getIsCreate()) { $template = $request->getStr('template'); - if (strlen($template)) { + if (phutil_nonempty_string($template)) { $template_object = $this->newObjectFromIdentifier( $template, array( diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php index 2028f10d90..26811d7534 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php @@ -95,7 +95,7 @@ abstract class PhabricatorEditEngineAPIMethod $section[] = $type->getConduitDescription(); $type_documentation = $type->getConduitDocumentation(); - if (strlen($type_documentation)) { + if (phutil_nonempty_string($type_documentation)) { $section[] = $type_documentation; } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php index d177595a2b..0d1b6cf425 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -43,11 +43,27 @@ final class PhabricatorEditEngineSubtype return $this->icon; } + /** + * Set the text of the tag + * + * This is usually the 'name' key of your subtype map. + * Sometime this is an uppercase text like 'BUG' for a 'bug' subtype name. + * + * @param string|null $text + * @return self + */ public function setTagText($text) { $this->tagText = $text; return $this; } + /** + * Get the text of the tag + * + * @see PhabricatorEditEngineSubtype::setTagText() + * + * @return string|null + */ public function getTagText() { return $this->tagText; } @@ -89,7 +105,7 @@ final class PhabricatorEditEngineSubtype } public function hasTagView() { - return (bool)strlen($this->getTagText()); + return phutil_nonempty_string($this->getTagText()); } public function newTagView() { diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php index 7eafbc60cf..4c72d63214 100644 --- a/src/applications/transactions/editfield/PhabricatorEditField.php +++ b/src/applications/transactions/editfield/PhabricatorEditField.php @@ -169,11 +169,20 @@ abstract class PhabricatorEditField extends Phobject { return $this->conduitDescription; } + /** + * Set the Conduit documentation in raw Remarkup. + * @param string|null $conduit_documentation + * @return self + */ public function setConduitDocumentation($conduit_documentation) { $this->conduitDocumentation = $conduit_documentation; return $this; } + /** + * Get the Conduit documentation in raw Remarkup. + * @return string|null + */ public function getConduitDocumentation() { return $this->conduitDocumentation; } @@ -418,7 +427,7 @@ abstract class PhabricatorEditField extends Phobject { } $instructions = $this->getControlInstructions(); - if (strlen($instructions)) { + if (phutil_nonempty_string($instructions)) { $form->appendRemarkupInstructions($instructions); } diff --git a/src/applications/transactions/editfield/PhabricatorTextEditField.php b/src/applications/transactions/editfield/PhabricatorTextEditField.php index 68854cf2e2..d915d4db75 100644 --- a/src/applications/transactions/editfield/PhabricatorTextEditField.php +++ b/src/applications/transactions/editfield/PhabricatorTextEditField.php @@ -18,7 +18,7 @@ final class PhabricatorTextEditField $control = new AphrontFormTextControl(); $placeholder = $this->getPlaceholder(); - if (strlen($placeholder)) { + if (phutil_nonempty_string($placeholder)) { $control->setPlaceholder($placeholder); } diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 77b5fbfbb6..0e7333b342 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -391,7 +391,7 @@ abstract class PhabricatorApplicationTransactionEditor $new = $this->getTransactionNewValue($object, $xaction); $xaction->setNewValue($new); - // Apply an optional transformation to convert "external" tranaction + // Apply an optional transformation to convert "external" transaction // values (provided by APIs) into "internal" values. $old = $xaction->getOldValue(); @@ -617,7 +617,7 @@ abstract class PhabricatorApplicationTransactionEditor return true; case PhabricatorTransactions::TYPE_SPACE: $space_phid = $xaction->getNewValue(); - if (!strlen($space_phid)) { + if (!phutil_nonempty_string($space_phid)) { // If an install has no Spaces or the Spaces controls are not visible // to the viewer, we might end up with the empty string here instead // of a strict `null`, because some controller just used `getStr()` diff --git a/src/applications/transactions/storage/PhabricatorModularTransactionType.php b/src/applications/transactions/storage/PhabricatorModularTransactionType.php index 7d5e3c533e..e2f0a02239 100644 --- a/src/applications/transactions/storage/PhabricatorModularTransactionType.php +++ b/src/applications/transactions/storage/PhabricatorModularTransactionType.php @@ -334,12 +334,28 @@ abstract class PhabricatorModularTransactionType return $this->getEditor()->getIsNewObject(); } + /** + * Check whenever a new transaction's value is considered an "empty text" + * @param mixed $value A string, null, an integer... + * @param array $xactions Transactions + */ final protected function isEmptyTextTransaction($value, array $xactions) { foreach ($xactions as $xaction) { $value = $xaction->getNewValue(); } - return !strlen($value); + // The $value can be a lot of stuff, null, string, integer and maybe more. + // We cast to string to answer the question "Is this string empty?". + // Note: Don't use phutil_nonempty_stringlike() since it was not designed + // for integers. + // Note: Don't use phutil_nonempty_scalar() since very probably we could + // receive a boolean, causing exceptions. + // https://we.phorge.it/T15239 + $value_clean = phutil_string_cast($value); + + // We made our lives easier and we don't need strlen(something) + // and we should not. + return $value_clean === ''; } /** diff --git a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php index 2d55c5f663..5753c3cded 100644 --- a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php +++ b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php @@ -39,7 +39,7 @@ final class PhabricatorTypeaheadModularDatasourceController $parameters = array(); $raw_parameters = $request->getStr('parameters'); - if (strlen($raw_parameters)) { + if (phutil_nonempty_string($raw_parameters)) { try { $parameters = phutil_json_decode($raw_parameters); } catch (PhutilJSONParserException $ex) { diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php index 5594044c42..8a396c1ed3 100644 --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php @@ -28,7 +28,7 @@ abstract class PhabricatorTypeaheadCompositeDatasource // We only need to do a prefix phase query if there's an actual query // string. If the user didn't type anything, nothing can possibly match it. - if (strlen($this->getRawQuery())) { + if (phutil_nonempty_string($this->getRawQuery())) { $phases[] = self::PHASE_PREFIX; } @@ -207,7 +207,11 @@ abstract class PhabricatorTypeaheadCompositeDatasource } protected function sliceResults(array $results) { - $offset = $this->getOffset(); + if ($this->getOffset()) { + $offset = $this->getOffset(); + } else { + $offset = 0; + } $limit = $this->getLimit(); if ($offset || $limit) { diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php index 29a8d4b7ba..a35a8e8f0f 100644 --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php @@ -464,7 +464,11 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject { // We're looking for a "(" so that a string like "members(q" is identified // and parsed as a function call. This allows us to start generating // results immediately, before the user fully types out "members(quack)". - return (strpos($token, '(') !== false); + if ($token) { + return (strpos($token, '(') !== false); + } else { + return false; + } } diff --git a/src/docs/contributor/bug_reports.diviner b/src/docs/contributor/bug_reports.diviner index 3ded817a48..6fed325c5c 100644 --- a/src/docs/contributor/bug_reports.diviner +++ b/src/docs/contributor/bug_reports.diviner @@ -144,7 +144,13 @@ to file a report. It is **particularly critical** that you include reproduction steps. -You can file a report [[ https://we.phorge.it/maniphest/task/edit/form/2/ | on this instance]]. +Community Members - that is, members of #community - can +[[ https://we.phorge.it/maniphest/task/edit/form/2/ | file a report directly +on this instance]]. + +Potential members - i.e., everyone else - please use Ponder to +[[ https://we.phorge.it/ponder/question/create/ | Ask for support ]] from the +Community Members. Next Steps diff --git a/src/docs/contributor/database.diviner b/src/docs/contributor/database.diviner index fc39c1ff1c..dc553678a8 100644 --- a/src/docs/contributor/database.diviner +++ b/src/docs/contributor/database.diviner @@ -134,7 +134,7 @@ eventually, but there isn't a strong case for them at the present time. PHIDs ===== -Each globally referencable object in Phorge has an associated PHID +Each globally referenceable object in Phorge has an associated PHID ("Phorge ID") which serves as a global identifier, similar to a GUID. We use PHIDs for referencing data in different databases. diff --git a/src/docs/contributor/general_coding_standards.diviner b/src/docs/contributor/general_coding_standards.diviner index 5127aebbfc..532b922f9f 100644 --- a/src/docs/contributor/general_coding_standards.diviner +++ b/src/docs/contributor/general_coding_standards.diviner @@ -142,7 +142,7 @@ example. = Documentation, Comments and Formatting = - Prefer to remove code by deleting it over removing it by commenting it out. - It shall live forever in source control, and can be retrieved therefrom if + It shall live forever in source control, and can be retrieved there from if it is ever again called upon. - In source code, use only ASCII printable characters plus space and linefeed. Do not use UTF-8 or other multibyte encodings. diff --git a/src/docs/contributor/php_coding_standards.diviner b/src/docs/contributor/php_coding_standards.diviner index bb54478fa3..6c68d194ca 100644 --- a/src/docs/contributor/php_coding_standards.diviner +++ b/src/docs/contributor/php_coding_standards.diviner @@ -176,3 +176,7 @@ diffs which add elements to the array affect only one line. return $this->favoriteFood; } } + +# Extra Readings + +* @{article:PHP Pitfalls} diff --git a/src/docs/flavor/php_pitfalls.diviner b/src/docs/flavor/php_pitfalls.diviner index e15ca9e2bb..b280cb2394 100644 --- a/src/docs/flavor/php_pitfalls.diviner +++ b/src/docs/flavor/php_pitfalls.diviner @@ -49,18 +49,7 @@ If a value is not truthy, it is "falsey". These values are falsey in PHP: false // boolean array() // empty array -Disregarding some bizarre edge cases, all other values are truthy. Note that -because "0" is falsey, this sort of thing (intended to prevent users from making -empty comments) is wrong in PHP: - - COUNTEREXAMPLE - if ($comment_text) { - make_comment($comment_text); - } - -This is wrong because it prevents users from making the comment "0". //THIS -COMMENT IS TOTALLY AWESOME AND I MAKE IT ALL THE TIME SO YOU HAD BETTER NOT -BREAK IT!!!// A better test is probably `strlen()`. +Disregarding some bizarre edge cases, all other values are truthy. In addition to truth tests with `if`, PHP has two special truthiness operators which look like functions but aren't: `empty()` and `isset()`. These operators @@ -92,16 +81,16 @@ variables. `empty()` evaluates truthiness exactly opposite of `if()`. `isset()` returns `true` for everything except `null`. This is the truth table: -| Value | `if()` | `empty()` | `isset()` | -|-------|--------|-----------|-----------| -| `null` | `false` | `true` | `false` | -| `0` | `false` | `true` | `true` | -| `0.0` | `false` | `true` | `true` | -| `"0"` | `false` | `true` | `true` | -| `""` | `false` | `true` | `true` | -| `false` | `false` | `true` | `true` | -| `array()` | `false` | `true` | `true` | -| Everything else | `true` | `false` | `true` | +| Value | `if()` | `empty()` | `isset()` | +|---------------|--------|-----------|-----------| +| `null` | `false`| `true` | `false` | +| `0` | `false`| `true` | `true` | +| `0.0` | `false`| `true` | `true` | +| `"0"` | `false`| `true` | `true` | +| `""` | `false`| `true` | `true` | +|`false` | `false`| `true` | `true` | +|`array()` | `false`| `true` | `true` | +|Everything else| `true` | `false` | `true` | The value of these operators is that they accept undeclared variables and do not issue a warning. Specifically, if you try to do this you get a warning: @@ -138,6 +127,64 @@ Put another way, use `isset()` if you want to type `if ($value !== null)` but are testing something that may not be declared. Use `empty()` if you want to type `if (!$value)` but you are testing something that may not be declared. += Check for non-empty strings = + +As already mentioned, note that you cannot just use an `if` or `empty()` to +check for a non-empty string, mostly because "0" is falsey, so you cannot rely +on this sort of thing to prevent users from making empty comments: + + COUNTEREXAMPLE + if ($comment_text) { + make_comment($comment_text); + } + +This is wrong because it prevents users from making the comment "0". + +//THE COMMENT "0" IS TOTALLY AWESOME AND I MAKE IT ALL THE TIME SO YOU HAD +BETTER NOT BREAK IT!!!// + +Another way //was// also `strlen()`: + + COUNTEREXAMPLE + if (strlen($comment_text)) { + make_comment($comment_text); + } + +But using `strlen(null)` causes a deprecation warning since PHP 8.1. Also, +using `strlen()` uses too many CPU cycles to just check of a non-empty. + +In short, outside Phorge, this is a general way to check for non-empty strings +for most wild input types: + +```lang=php + $value_str = (string) $value; + if ($value_str !== '') { + // do something + } +``` + +To do the same thing in Phorge, use this better and safer approach: + +```lang=php + $value_str = phutil_string_cast($value); + if ($value_str !== '') { + // do something + } +``` + +And, if you are 100% sure that you are __only__ working with string and +null, evaluate this instead: + +```lang=php + if (phutil_nonempty_string($value)) { + // do something + } +``` + +WARNING: The function `phutil_nonempty_string()` is designed to throw a nice +exception if it receives `true`, `false`, an array, an object or anything +alien that is not a string and not null. Do your evaluations. + = usort(), uksort(), and uasort() are Slow = This family of functions is often extremely slow for large datasets. You should diff --git a/src/docs/user/configuration/configuring_inbound_email.diviner b/src/docs/user/configuration/configuring_inbound_email.diviner index dfebfde7aa..c7c9818057 100644 --- a/src/docs/user/configuration/configuring_inbound_email.diviner +++ b/src/docs/user/configuration/configuring_inbound_email.diviner @@ -60,7 +60,7 @@ as the "From" address when it sends mail. The exact address it uses can be configured with `metamta.default-address`. When a user takes an action that generates mail, Phorge sets the -"Reply-To" addresss for the mail to that user's name and address. This means +"Reply-To" address for the mail to that user's name and address. This means that users can reply to email to discuss changes, but: the conversation won't be recorded in Phorge; and users will not be able to use email commands to take actions or make edits. diff --git a/src/docs/user/installation_guide.diviner b/src/docs/user/installation_guide.diviner index 7306155917..1a09a2a3d6 100644 --- a/src/docs/user/installation_guide.diviner +++ b/src/docs/user/installation_guide.diviner @@ -79,8 +79,11 @@ You will also need: - **MySQL**: You need MySQL. We strongly recommend MySQL 5.5 or newer. You will need a server with multiple databases. - - **PHP**: You need PHP 5.5 or newer. Note that PHP 8.1 and above are not - fully supported. + - **PHP**: You need a PHP engine: + - PHP 5 - 5.5 or newer. + - PHP 7 - 7.1 or newer. + - PHP 8 - **Not yet supported**. We're working on it as fast as we can, + and expect to support PHP 8 Real Soon Now. - **git**: You need git 2.5.0 or newer on the server. No particular version is needed on your clients. @@ -121,7 +124,7 @@ Here's a general description of what you need to install: - PHP (usually "php") - Required PHP extensions: mbstring, iconv, mysql (or mysqli), curl, pcntl (these might be something like "php-mysql" or "php5-mysqlnd") - - Optional PHP extensions: gd + - Optional PHP extensions: gd, zip If you already have LAMP setup, you've probably already got everything you need. It may also be helpful to refer to the install scripts above, even if they don't diff --git a/src/docs/user/userguide/multi_factor_auth.diviner b/src/docs/user/userguide/multi_factor_auth.diviner index cccf3e12b9..d445727e6c 100644 --- a/src/docs/user/userguide/multi_factor_auth.diviner +++ b/src/docs/user/userguide/multi_factor_auth.diviner @@ -134,7 +134,7 @@ Providers may be in these states: - **Active**: Users may add new factors. Users will be prompted to respond to challenges from these providers when they take a sensitive action. - **Deprecated**: Users may not add new factors, but they will still be - asked to respond to challenges from exising factors. + asked to respond to challenges from existing factors. - **Disabled**: Users may not add new factors, and existing factors will not be used. If MFA is required and a user only has disabled factors, they will be forced to add a new factor. diff --git a/src/docs/user/userguide/webhooks.diviner b/src/docs/user/userguide/webhooks.diviner index c2d0678b26..47b02cc261 100644 --- a/src/docs/user/userguide/webhooks.diviner +++ b/src/docs/user/userguide/webhooks.diviner @@ -178,7 +178,7 @@ Retries and Rate Limiting Test requests are never retried: they execute exactly once. Live requests are automatically retried. If your endpoint does not return a -HTTP 2XX response, the request will be retried regularly until it suceeds. +HTTP 2XX response, the request will be retried regularly until it succeeds. Retries will continue until the request succeeds or is garbage collected. By default, this is after 7 days. diff --git a/src/infrastructure/contentsource/PhabricatorContentSource.php b/src/infrastructure/contentsource/PhabricatorContentSource.php index ee77052113..de36f50b1f 100644 --- a/src/infrastructure/contentsource/PhabricatorContentSource.php +++ b/src/infrastructure/contentsource/PhabricatorContentSource.php @@ -81,6 +81,13 @@ abstract class PhabricatorContentSource extends Phobject { )); } + /** + * Get the internal source name + * + * This is usually coming from a SOURCECONST constant. + * + * @return string|null + */ final public function getSource() { return $this->source; } diff --git a/src/infrastructure/contentsource/PhabricatorUnknownContentSource.php b/src/infrastructure/contentsource/PhabricatorUnknownContentSource.php index a0dfd042d7..7b8c063b8a 100644 --- a/src/infrastructure/contentsource/PhabricatorUnknownContentSource.php +++ b/src/infrastructure/contentsource/PhabricatorUnknownContentSource.php @@ -7,7 +7,7 @@ final class PhabricatorUnknownContentSource public function getSourceName() { $source = $this->getSource(); - if (strlen($source)) { + if ($source) { return pht('Unknown ("%s")', $source); } else { return pht('Unknown'); diff --git a/src/infrastructure/customfield/field/PhabricatorCustomField.php b/src/infrastructure/customfield/field/PhabricatorCustomField.php index 9e2bf6895f..4e55348c36 100644 --- a/src/infrastructure/customfield/field/PhabricatorCustomField.php +++ b/src/infrastructure/customfield/field/PhabricatorCustomField.php @@ -1679,7 +1679,7 @@ abstract class PhabricatorCustomField extends Phobject { foreach ($map as $field_key => $field) { // For now, only support overriding standard custom fields. In the // future there's no technical or product reason we couldn't let you - // override (some properites of) other fields like "Title", but they + // override (some properties of) other fields like "Title", but they // don't usually support appropriate "setX()" methods today. if (!($field instanceof PhabricatorStandardCustomField)) { // For fields that are proxies on top of StandardCustomField, which diff --git a/src/infrastructure/customfield/field/PhabricatorCustomFieldList.php b/src/infrastructure/customfield/field/PhabricatorCustomFieldList.php index 8ae5529f95..60a5171cdd 100644 --- a/src/infrastructure/customfield/field/PhabricatorCustomFieldList.php +++ b/src/infrastructure/customfield/field/PhabricatorCustomFieldList.php @@ -89,7 +89,7 @@ final class PhabricatorCustomFieldList extends Phobject { $field_handles = array_select_keys($handles, $phids[$field_key]); $instructions = $field->getInstructionsForEdit(); - if (strlen($instructions)) { + if (phutil_nonempty_string($instructions)) { $form->appendRemarkupInstructions($instructions); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php index f06c30d482..e8a5b99e0d 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php @@ -24,7 +24,8 @@ final class PhabricatorStandardCustomFieldInt public function getValueForStorage() { $value = $this->getFieldValue(); - if (strlen($value)) { + $is_nonempty = phutil_string_cast($value) !== ''; + if ($is_nonempty) { return $value; } else { return null; diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php index b0b9a3ef8e..54f54c7503 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php @@ -30,7 +30,7 @@ final class PhabricatorStandardCustomFieldRemarkup public function renderPropertyViewValue(array $handles) { $value = $this->getFieldValue(); - if (!strlen($value)) { + if (!phutil_nonempty_string($value)) { return null; } diff --git a/src/infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php b/src/infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php index f705fa4377..752d895952 100644 --- a/src/infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php +++ b/src/infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php @@ -42,6 +42,11 @@ final class PHUIDiffTableOfContentsItemView extends AphrontView { return $this; } + /** + * Get the Coverage, expressed as a string, each letter with this meaning: + * N: Not Executable, C: Covered, U: Uncovered. + * @return string|null + */ public function getCoverage() { return $this->coverage; } @@ -139,7 +144,7 @@ final class PHUIDiffTableOfContentsItemView extends AphrontView { $not_applicable = '-'; $coverage = $this->getCoverage(); - if (!strlen($coverage)) { + if (!phutil_nonempty_string($coverage)) { return $not_applicable; } @@ -157,7 +162,7 @@ final class PHUIDiffTableOfContentsItemView extends AphrontView { $not_applicable = '-'; $coverage = $this->getCoverage(); - if (!strlen($coverage)) { + if (!phutil_nonempty_string($coverage)) { return $not_applicable; } diff --git a/src/infrastructure/javelin/markup.php b/src/infrastructure/javelin/markup.php index 533baad65e..8a040031cc 100644 --- a/src/infrastructure/javelin/markup.php +++ b/src/infrastructure/javelin/markup.php @@ -77,7 +77,28 @@ function phabricator_form(PhabricatorUser $user, $attributes, $content) { $is_post = (strcasecmp($http_method, 'POST') === 0); $http_action = idx($attributes, 'action'); - $is_absolute_uri = preg_match('#^(https?:|//)#', $http_action); + + if ($http_action === null) { + // Not sure what this is. + $is_absolute_uri = false; + + } else if ($http_action instanceof PhutilURI) { + // This is the happy path, I think + + // For now, this is close enough - I suspect we'll stay with "https" schema + // for the rest of eternity. + $protocol = $http_action->getProtocol(); + $is_absolute_uri = ($protocol == 'http' || $protocol == 'https'); + + } else if (is_string($http_action)) { + // Also good path? + $is_absolute_uri = preg_match('#^(https?:|//)#', $http_action); + } else { + throw new Exception( + pht( + 'Unexpected object type provided as `action` - %s', + gettype($http_action))); + } if ($is_post) { diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupLiteralBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupLiteralBlockRule.php index 4f30ad089e..505c7ecfd1 100644 --- a/src/infrastructure/markup/blockrule/PhutilRemarkupLiteralBlockRule.php +++ b/src/infrastructure/markup/blockrule/PhutilRemarkupLiteralBlockRule.php @@ -7,7 +7,7 @@ final class PhutilRemarkupLiteralBlockRule extends PhutilRemarkupBlockRule { } public function getMatchingLineCount(array $lines, $cursor) { - // NOTE: We're consuming all continguous blocks of %%% literals, so this: + // NOTE: We're consuming all contiguous blocks of %%% literals, so this: // // %%%a%%% // %%%b%%% diff --git a/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php index 56bab68e44..c5344a692c 100644 --- a/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php +++ b/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php @@ -212,6 +212,7 @@ final class PhabricatorKeyboardRemarkupRule extends PhutilRemarkupRule { 'line-height: 0.6rem;', 'border-radius: 3px;', 'box-shadow: inset 0 -1px 0 rgba(71, 87, 120, 0.08);', + '-webkit-user-select: none;', 'user-select: none;', 'background: #f7f7f7;', 'border: 1px solid #C7CCD9;', diff --git a/src/infrastructure/markup/syntax/highlighter/xhpast/PhutilXHPASTSyntaxHighlighterFuture.php b/src/infrastructure/markup/syntax/highlighter/xhpast/PhutilXHPASTSyntaxHighlighterFuture.php index c34153ba42..f617122ec8 100644 --- a/src/infrastructure/markup/syntax/highlighter/xhpast/PhutilXHPASTSyntaxHighlighterFuture.php +++ b/src/infrastructure/markup/syntax/highlighter/xhpast/PhutilXHPASTSyntaxHighlighterFuture.php @@ -32,7 +32,7 @@ final class PhutilXHPASTSyntaxHighlighterFuture extends FutureProxy { // We perform two passes here: one using the AST to find symbols we care // about -- particularly, class names and function names. These are used - // in the crossreference stuff to link into Diffusion. After we've done our + // in the cross-reference stuff to link into Diffusion. After we've done our // AST pass, we do a followup pass on the token stream to catch all the // simple stuff like strings and comments. diff --git a/src/infrastructure/parser/PhutilPygmentizeParser.php b/src/infrastructure/parser/PhutilPygmentizeParser.php index 35c1d5739c..39b0e441c5 100644 --- a/src/infrastructure/parser/PhutilPygmentizeParser.php +++ b/src/infrastructure/parser/PhutilPygmentizeParser.php @@ -32,7 +32,7 @@ final class PhutilPygmentizeParser extends Phobject { $c = $block[$ii]; switch ($mode) { case 'text': - // We're in general text between tags, and just passing characers + // We're in general text between tags, and just passing characters // through unmodified. if ($c == '<') { $mode = 'tag'; diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 42ccad3316..6ad91b52ea 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -2449,7 +2449,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery PhabricatorSearchNgrams $index, $value) { - if (strlen($value)) { + if (phutil_nonempty_string($value)) { $this->ngrams[] = array( 'index' => $index, 'value' => $value, diff --git a/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php b/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php index 93f623338f..88ec92daba 100644 --- a/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php +++ b/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php @@ -290,12 +290,12 @@ abstract class PhabricatorLiskDAO extends LiskDAO { } protected function getUTF8StringFromStorage($string, $encoding) { - if ($encoding == 'utf8') { + if ($encoding == 'utf8' || !phutil_nonempty_string($string)) { return $string; } if (function_exists('mb_detect_encoding')) { - if (strlen($encoding)) { + if (phutil_nonempty_string($encoding)) { $try_encodings = array( $encoding, ); diff --git a/src/view/AphrontDialogView.php b/src/view/AphrontDialogView.php index b8b00a6b3e..14aa4a19b6 100644 --- a/src/view/AphrontDialogView.php +++ b/src/view/AphrontDialogView.php @@ -51,6 +51,15 @@ final class AphrontDialogView return $this->isStandalone; } + /** + * Set the URI associated to the Submit Button + * + * If you want a normal link and not any form submission, + * see also: setDisableWorkflowOnSubmit(false). + * + * @param string $uri + * @return self + */ public function setSubmitURI($uri) { $this->submitURI = $uri; return $this; @@ -92,6 +101,15 @@ final class AphrontDialogView return $this->resizeX; } + /** + * Add a Submit Button and specify its text + * + * If you want to associate an URI for this Button, + * see also: setSubmitURI(). + * + * @param string $text Text shown for that button + * @return self + */ public function addSubmitButton($text = null) { if (!$text) { $text = pht('Okay'); @@ -228,6 +246,14 @@ final class AphrontDialogView return $this->appendChild($form->buildLayoutView()); } + /** + * Enable or Disable a Workflow on Submit + * + * For example, if your Submit Button should be a normal link, + * without activating any Workflow, you can set false. + * @param bool $disable_workflow_on_submit + * @return self + */ public function setDisableWorkflowOnSubmit($disable_workflow_on_submit) { $this->disableWorkflowOnSubmit = $disable_workflow_on_submit; return $this; diff --git a/src/view/control/AphrontTableView.php b/src/view/control/AphrontTableView.php index a3c0a49be4..ab1f6be0ed 100644 --- a/src/view/control/AphrontTableView.php +++ b/src/view/control/AphrontTableView.php @@ -135,7 +135,7 @@ final class AphrontTableView extends AphrontView { $col_classes = array(); foreach ($this->columnClasses as $key => $class) { - if (strlen($class)) { + if (phutil_nonempty_string($class)) { $col_classes[] = $class; } else { $col_classes[] = null; @@ -392,7 +392,7 @@ final class AphrontTableView extends AphrontView { // white-space: pre to prevent wrapping. We need to append a character // (  -- nonbreaking space) afterward to give the bounds div height // (alternatively, we could hard-code the line height). This is gross but - // it's not clear that there's a better appraoch. + // it's not clear that there's a better approach. return phutil_tag( 'div', diff --git a/src/view/form/control/AphrontFormControl.php b/src/view/form/control/AphrontFormControl.php index 0125fa87b3..83e0207241 100644 --- a/src/view/form/control/AphrontFormControl.php +++ b/src/view/form/control/AphrontFormControl.php @@ -56,11 +56,22 @@ abstract class AphrontFormControl extends AphrontView { return $this->label; } + /** + * Set the Caption + * The Caption shows a tip usually nearby the related input field. + * @param string|PhutilSafeHTML|null + * @return self + */ public function setCaption($caption) { $this->caption = $caption; return $this; } + /** + * Get the Caption + * The Caption shows a tip usually nearby the related input field. + * @return string|PhutilSafeHTML|null + */ public function getCaption() { return $this->caption; } @@ -172,7 +183,7 @@ abstract class AphrontFormControl extends AphrontView { $this->renderInput()); $error = null; - if (strlen($this->getError())) { + if ($this->getError()) { $error = $this->getError(); if ($error === true) { $error = phutil_tag( @@ -187,7 +198,7 @@ abstract class AphrontFormControl extends AphrontView { } } - if (strlen($this->getLabel())) { + if (phutil_nonempty_string($this->getLabel())) { $label = phutil_tag( 'label', array( @@ -203,7 +214,11 @@ abstract class AphrontFormControl extends AphrontView { $custom_class .= ' aphront-form-control-nolabel'; } - if (strlen($this->getCaption())) { + // The Caption can be stuff like PhutilSafeHTML and other objects that + // can be casted to a string. After this cast we have never null. + $has_caption = phutil_string_cast($this->getCaption()) !== ''; + + if ($has_caption) { $caption = phutil_tag( 'div', array('class' => 'aphront-form-caption'), diff --git a/src/view/form/control/AphrontFormTokenizerControl.php b/src/view/form/control/AphrontFormTokenizerControl.php index fe80c86f81..7af8fcae32 100644 --- a/src/view/form/control/AphrontFormTokenizerControl.php +++ b/src/view/form/control/AphrontFormTokenizerControl.php @@ -68,7 +68,7 @@ final class AphrontFormTokenizerControl extends AphrontFormControl { $datasource->setViewer($this->getUser()); $placeholder = null; - if (!strlen($this->placeholder)) { + if (!phutil_nonempty_string($this->placeholder)) { $placeholder = $datasource->getPlaceholderText(); } diff --git a/src/view/form/control/PhabricatorRemarkupControl.php b/src/view/form/control/PhabricatorRemarkupControl.php index 67afd10630..ba7950bcc9 100644 --- a/src/view/form/control/PhabricatorRemarkupControl.php +++ b/src/view/form/control/PhabricatorRemarkupControl.php @@ -128,6 +128,8 @@ final class PhabricatorRemarkupControl 'disabled' => $this->getDisabled(), 'sendOnEnter' => $this->getSendOnEnter(), 'rootID' => $root_id, + 'remarkupMetadataID' => $metadata_id, + 'remarkupMetadataValue' => $metadata_value, 'autocompleteMap' => (object)array( 64 => array( // "@" 'datasourceURI' => $user_datasource->getDatasourceURI(), diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index b2d5a716d4..c7c8b5b534 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -92,12 +92,21 @@ final class AphrontSideNavFilterView extends AphrontView { return $this->getMenuView()->getItem($key); } + /** + * Add a thing in the menu + * + * @param string $key Internal name + * @param string $name Human name + * @param mixed $uri Destination URI. For example as string or as PhutilURI. + * @param string $type Item type. For example see PHUIListItemView constants. + * @param string $icon Icon name + */ private function addThing($key, $name, $uri, $type, $icon = null) { $item = id(new PHUIListItemView()) ->setName($name) ->setType($type); - if (strlen($icon)) { + if (phutil_nonempty_string($icon)) { $item->setIcon($icon); } @@ -145,7 +154,7 @@ final class AphrontSideNavFilterView extends AphrontView { public function selectFilter($key, $default = null) { $this->selectedFilter = $default; - if ($this->menu->getItem($key) && strlen($key)) { + if ($this->menu->getItem($key) && phutil_nonempty_string($key)) { $this->selectedFilter = $key; } return $this->selectedFilter; diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index 6f6ce56cad..17ce1db8bb 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -188,7 +188,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView } } - if (strlen($prefix)) { + if (phutil_nonempty_string($prefix)) { $title = $prefix.' '.$title; } diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index 6a69c4feaa..f0b2bbbe83 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -333,7 +333,7 @@ final class PhabricatorMainMenuView extends AphrontView { $wordmark_text = PhabricatorCustomLogoConfigType::getLogoWordmark(); - if (!strlen($wordmark_text)) { + if (!phutil_nonempty_string($wordmark_text)) { $wordmark_text = PlatformSymbols::getPlatformServerName(); } diff --git a/src/view/phui/PHUIInfoView.php b/src/view/phui/PHUIInfoView.php index cefeedbe5f..58898d40d2 100644 --- a/src/view/phui/PHUIInfoView.php +++ b/src/view/phui/PHUIInfoView.php @@ -19,6 +19,12 @@ final class PHUIInfoView extends AphrontTagView { private $flush; private $icon; + /** + * Set a title + * + * @param string|null $title + * @return self + */ public function setTitle($title) { $this->title = $title; return $this; @@ -147,7 +153,7 @@ final class PHUIInfoView extends AphrontTagView { } $title = $this->title; - if ($title || strlen($title)) { + if ($title || phutil_nonempty_string($title)) { $title = phutil_tag( 'h1', array( diff --git a/src/view/phui/PHUIObjectItemListView.php b/src/view/phui/PHUIObjectItemListView.php index fbc3904586..629feb9139 100644 --- a/src/view/phui/PHUIObjectItemListView.php +++ b/src/view/phui/PHUIObjectItemListView.php @@ -120,7 +120,7 @@ final class PHUIObjectItemListView extends AphrontTagView { require_celerity_resource('phui-oi-color-css'); $header = null; - if (strlen($this->header)) { + if (phutil_nonempty_string($this->header)) { $header = phutil_tag( 'h1', array( diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php index 4bb9c3ea6a..600db9f3b7 100644 --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -83,11 +83,29 @@ final class PHUIObjectItemView extends AphrontTagView { return $this->object; } + /** + * Set the href attribute + * + * @param string|PhutilURI|null $href + * @return self + */ public function setHref($href) { + + // We have not a very clear idea about what this method should receive + // So, let's log alien stuff for some time + // https://we.phorge.it/T15316 + self::requireValidHref($href, 'href'); + $this->href = $href; return $this; } + /** + * Get the href attribute + * + * @see PHUIObjectItemView::setHref() + * @return string|PhutilURI|null + */ public function getHref() { return $this->href; } @@ -136,7 +154,19 @@ final class PHUIObjectItemView extends AphrontTagView { return $this; } + /** + * Set the image href attribute + * + * @param string|PhutilURI|null $image_href + * @return self + */ public function setImageHref($image_href) { + + // We have not a very clear idea about what this method should receive + // So, let's log alien stuff for some time + // https://we.phorge.it/T15316 + self::requireValidHref($image_href, 'image_href'); + $this->imageHref = $image_href; return $this; } @@ -659,7 +689,8 @@ final class PHUIObjectItemView extends AphrontTagView { $this->getImageIcon()); } - if ($image && (strlen($this->href) || strlen($this->imageHref))) { + if ($image && (phutil_nonempty_stringlike($this->href) || + phutil_nonempty_stringlike($this->imageHref))) { $image_href = ($this->imageHref) ? $this->imageHref : $this->href; $image = phutil_tag( 'a', @@ -873,7 +904,7 @@ final class PHUIObjectItemView extends AphrontTagView { 'class' => 'phui-oi-status-icon', ); - if (strlen($label)) { + if (phutil_nonempty_string($label)) { $options['sigil'] = 'has-tooltip'; $options['meta'] = array('tip' => $label, 'size' => 300); } @@ -898,4 +929,30 @@ final class PHUIObjectItemView extends AphrontTagView { return javelin_tag('span', $options, ''); } + + /** + * Receive a href attribute and check if it has expected values + * + * TODO: Feel free to remove after 2023, if no more new reports arrive. + * + * https://we.phorge.it/T15316 + * + * @param mixed $href Value to be checked + * @param string $variable_name Human reference + */ + private static function requireValidHref($href, $variable_name) { + + // We have not a very clear idea about what a "href" should be + if (is_object($href) && !($href instanceof PhutilURI)) { + + // We log stuff with a kind stack trace + phlog(new Exception(pht( + 'The variable %s received an unexpected type: %s. '. + 'Please share this stack trace as comment in Task %s', + $variable_name, + get_class($href), + 'https://we.phorge.it/T15316'))); + } + } + } diff --git a/src/view/phui/PHUISegmentBarSegmentView.php b/src/view/phui/PHUISegmentBarSegmentView.php index 6bd3c530ef..d786e89eaa 100644 --- a/src/view/phui/PHUISegmentBarSegmentView.php +++ b/src/view/phui/PHUISegmentBarSegmentView.php @@ -26,6 +26,11 @@ final class PHUISegmentBarSegmentView extends AphrontTagView { return $this; } + /** + * Set a Tooltip. + * @param string|null $tooltip + * @return self + */ public function setTooltip($tooltip) { $this->tooltip = $tooltip; return $this; @@ -55,7 +60,7 @@ final class PHUISegmentBarSegmentView extends AphrontTagView { $left = sprintf('%.2f%%', $left); $tooltip = $this->tooltip; - if (strlen($tooltip)) { + if (phutil_nonempty_string($tooltip)) { Javelin::initBehavior('phabricator-tooltips'); $sigil = 'has-tooltip'; diff --git a/src/view/phui/PHUITagView.php b/src/view/phui/PHUITagView.php index cd6321a852..dc837c7156 100644 --- a/src/view/phui/PHUITagView.php +++ b/src/view/phui/PHUITagView.php @@ -100,7 +100,24 @@ final class PHUITagView extends AphrontTagView { return $this; } + /** + * Set the href attribute + * + * @param string|null $href + * @return self + */ public function setHref($href) { + + // We have not a very clear idea about what this method should receive + // We suspect that PhutilURI should be allowed... but let's log everything! + // https://we.phorge.it/T15316 + if (is_object($href)) { + phlog(sprintf( + 'Received unexpected type for href: %s. '. + 'Please paste this log as comment in https://we.phorge.it/T15316', + get_class($href))); + } + $this->href = $href; return $this; } @@ -126,7 +143,7 @@ final class PHUITagView extends AphrontTagView { } protected function getTagName() { - return strlen($this->href) ? 'a' : 'span'; + return phutil_nonempty_stringlike($this->href) ? 'a' : 'span'; } public function setContextObject($context_object) { diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css index ee74139e69..eec00154cf 100644 --- a/webroot/rsrc/css/application/base/standard-page-view.css +++ b/webroot/rsrc/css/application/base/standard-page-view.css @@ -74,6 +74,7 @@ body.white-background { text-decoration: none; border-radius: 3px; box-shadow: inset 0 -1px 0 rgba({$alphablue}, 0.08); + -webkit-user-select: none; user-select: none; color: {$darkgreytext}; background: {$lightgreybackground}; diff --git a/webroot/rsrc/css/application/conpherence/notification.css b/webroot/rsrc/css/application/conpherence/notification.css index 21e73047a6..fd24e775f1 100644 --- a/webroot/rsrc/css/application/conpherence/notification.css +++ b/webroot/rsrc/css/application/conpherence/notification.css @@ -84,3 +84,8 @@ font-weight: normal; color: {$greytext}; } + +/* On small devices the Persistent Chat is already hidden, and so its option */ +.device .phabricator-notification-header .persistent-option { + display: none; +} diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index 5788bd68bc..88bbcfa421 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -432,37 +432,27 @@ unselectable. */ .differential-diff.copy-l > tbody > tr > td, .differential-diff.copy-r > tbody > tr > td { - -moz-user-select: none; - -ms-user-select: none; -webkit-user-select: none; user-select: none; } .differential-diff.copy-l > tbody > tr > td:nth-child(2) { - -moz-user-select: auto; - -ms-user-select: auto; -webkit-user-select: auto; user-select: auto; } .differential-diff.copy-l > tbody > tr > td.show-more:nth-child(2) { - -moz-user-select: none; - -ms-user-select: none; -webkit-user-select: none; user-select: none; } .differential-diff.copy-r > tbody > tr > td:nth-child(5) { - -moz-user-select: auto; - -ms-user-select: auto; -webkit-user-select: auto; user-select: auto; } .differential-diff.copy-l > tbody > tr.inline > td, .differential-diff.copy-r > tbody > tr.inline > td { - -moz-user-select: none; - -ms-user-select: none; -webkit-user-select: none; user-select: none; } diff --git a/webroot/rsrc/css/application/harbormaster/harbormaster.css b/webroot/rsrc/css/application/harbormaster/harbormaster.css index 2fa5af7b22..0b9aed76f8 100644 --- a/webroot/rsrc/css/application/harbormaster/harbormaster.css +++ b/webroot/rsrc/css/application/harbormaster/harbormaster.css @@ -44,10 +44,7 @@ background-color: {$paste.highlight}; border-right: 1px solid {$paste.border}; - -moz-user-select: -moz-none; - -khtml-user-select: none; -webkit-user-select: none; - -ms-user-select: none; user-select: none; } diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index 38e03290d7..7f1c51cac9 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -66,6 +66,7 @@ line-height: 0.6rem; border-radius: 3px; box-shadow: inset 0 -1px 0 rgba({$alphablue},0.08); + -webkit-user-select: none; user-select: none; background: {$lightgreybackground}; border: 1px solid {$lightgreyborder}; diff --git a/webroot/rsrc/css/layout/phabricator-source-code-view.css b/webroot/rsrc/css/layout/phabricator-source-code-view.css index 71e3516003..b16b158004 100644 --- a/webroot/rsrc/css/layout/phabricator-source-code-view.css +++ b/webroot/rsrc/css/layout/phabricator-source-code-view.css @@ -76,10 +76,7 @@ th.phabricator-source-line a:hover { .phabricator-source-blame-skip, .phabricator-source-blame-info { - -moz-user-select: -moz-none; - -khtml-user-select: none; -webkit-user-select: none; - -ms-user-select: none; user-select: none; } diff --git a/webroot/rsrc/css/phui/button/phui-button.css b/webroot/rsrc/css/phui/button/phui-button.css index 22ad96779d..b84b4895f7 100644 --- a/webroot/rsrc/css/phui/button/phui-button.css +++ b/webroot/rsrc/css/phui/button/phui-button.css @@ -9,8 +9,6 @@ input[type="submit"] { font: {$basefont}; -webkit-font-smoothing: antialiased; -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; } diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css index e64989f8cd..0ae87aafcf 100644 --- a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css @@ -675,8 +675,8 @@ ul.phui-oi-list-view .phui-oi-selected .phui-oi-selectable { cursor: pointer; - user-select: none; -webkit-user-select: none; + user-select: none; } /* When the list selection state can be toggled on the client (as in the bulk diff --git a/webroot/rsrc/css/phui/phui-basic-nav-view.css b/webroot/rsrc/css/phui/phui-basic-nav-view.css index a545ad35ce..f718c673ab 100644 --- a/webroot/rsrc/css/phui/phui-basic-nav-view.css +++ b/webroot/rsrc/css/phui/phui-basic-nav-view.css @@ -23,7 +23,7 @@ overflow: hidden; } -.phabricator-home.device-phone .phabricator-nav-content { +.phabricator-home.device-phone .phui-navigation-shell .phabricator-nav-local { display: none; } diff --git a/webroot/rsrc/css/phui/workboards/phui-workcard.css b/webroot/rsrc/css/phui/workboards/phui-workcard.css index d9acef12ef..eea7d7b043 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workcard.css +++ b/webroot/rsrc/css/phui/workboards/phui-workcard.css @@ -28,9 +28,6 @@ .phui-workcard.phui-oi .phui-oi-objname { -webkit-touch-callout: text; -webkit-user-select: text; - -khtml-user-select: text; - -moz-user-select: text; - -ms-user-select: text; user-select: text; } diff --git a/webroot/rsrc/css/phui/workboards/phui-workpanel.css b/webroot/rsrc/css/phui/workboards/phui-workpanel.css index 5ee54f2deb..e1f6d3296b 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workpanel.css +++ b/webroot/rsrc/css/phui/workboards/phui-workpanel.css @@ -29,9 +29,6 @@ .phui-workboard-view { -webkit-touch-callout: none; -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; } diff --git a/webroot/rsrc/js/core/RemarkupMetadata.js b/webroot/rsrc/js/core/RemarkupMetadata.js new file mode 100644 index 0000000000..14469b25f5 --- /dev/null +++ b/webroot/rsrc/js/core/RemarkupMetadata.js @@ -0,0 +1,49 @@ +/** + * @requires javelin-install + * javelin-dom + * javelin-json + * @provides phabricator-remarkup-metadata + * @javelin + */ + +JX.install('RemarkupMetadata', { + + construct: function(metadataValue, metadataID) { + if (JX.RemarkupMetadata._metadataValue == null) { + JX.RemarkupMetadata._metadataValue = {}; + } + if (!JX.RemarkupMetadata._metadataValue.hasOwnProperty(metadataID)) { + JX.RemarkupMetadata._metadataValue[metadataID] = metadataValue; + } + this._metadataNode = JX.$(metadataID); + this._metadataID = metadataID; + }, + + statics: { + _metadataValue: null + }, + + members: { + _metadataNode: null, + _metadataID: null, + + _writeMetadata: function() { + this._metadataNode.value = JX.JSON.stringify( + JX.RemarkupMetadata._metadataValue[this._metadataID]); + }, + + getMetadata: function(key, default_value) { + if (JX.RemarkupMetadata._metadataValue[this._metadataID] + .hasOwnProperty(key)) { + return JX.RemarkupMetadata._metadataValue[this._metadataID][key]; + } + return default_value; + }, + + setMetadata: function(key, value) { + JX.RemarkupMetadata._metadataValue[this._metadataID][key] = value; + this._writeMetadata(); + } + } + +}); diff --git a/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js b/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js index 8cf14349b0..4d8629cd8c 100644 --- a/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js +++ b/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js @@ -2,36 +2,15 @@ * @provides javelin-behavior-aphront-drag-and-drop-textarea * @requires javelin-behavior * javelin-dom - * javelin-json * phabricator-drag-and-drop-file-upload * phabricator-textareautils + * phabricator-remarkup-metadata */ JX.behavior('aphront-drag-and-drop-textarea', function(config) { var target = JX.$(config.target); - var metadata_node = JX.$(config.remarkupMetadataID); - var metadata_value = config.remarkupMetadataValue; - - function set_metadata(key, value) { - metadata_value[key] = value; - write_metadata(); - } - - function get_metadata(key, default_value) { - if (metadata_value.hasOwnProperty(key)) { - return metadata_value[key]; - } - return default_value; - } - - function write_metadata() { - metadata_node.value = JX.JSON.stringify(metadata_value); - } - - write_metadata(); - if (JX.PhabricatorDragAndDropFileUpload.isSupported()) { var drop = new JX.PhabricatorDragAndDropFileUpload(target) .setURI(config.uri) @@ -48,9 +27,15 @@ JX.behavior('aphront-drag-and-drop-textarea', function(config) { drop.listen('didUpload', function(file) { JX.TextAreaUtils.insertFileReference(target, file); - var phids = get_metadata('attachedFilePHIDs', []); - phids.push(file.getPHID()); - set_metadata('attachedFilePHIDs', phids); + if(config.remarkupMetadataID) { + // Try to auto-attach files by default + // https://we.phorge.it/T15106 + var metadata = new JX.RemarkupMetadata(config.remarkupMetadataValue, + config.remarkupMetadataID); + var phids = metadata.getMetadata('attachedFilePHIDs', []); + phids.push(file.getPHID()); + metadata.setMetadata('attachedFilePHIDs', phids); + } }); drop.start(); diff --git a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js index 89d23ef60f..b93075c36e 100644 --- a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js +++ b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js @@ -5,6 +5,7 @@ * javelin-dom * phabricator-phtize * phabricator-textareautils + * phabricator-remarkup-metadata * javelin-workflow * javelin-vector * phuix-autocomplete @@ -255,6 +256,12 @@ JX.behavior('phabricator-remarkup-assist', function(config) { .setURI(file.uri); JX.TextAreaUtils.insertFileReference(area, upload); + + var metadata = new JX.RemarkupMetadata( + config.remarkupMetadataValue, config.remarkupMetadataID); + var phids = metadata.getMetadata('attachedFilePHIDs', []); + phids.push(file.phid); + metadata.setMetadata('attachedFilePHIDs', phids); } }) .start();