diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index d6f118f30a..562ac01d7a 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -2234,7 +2234,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-pholio-mock-edit' => array( - 'uri' => '/res/ad171300/rsrc/js/application/pholio/behavior-pholio-mock-edit.js', + 'uri' => '/res/e537a994/rsrc/js/application/pholio/behavior-pholio-mock-edit.js', 'type' => 'js', 'requires' => array( @@ -3744,7 +3744,7 @@ celerity_register_resource_map(array( ), 'pholio-edit-css' => array( - 'uri' => '/res/89db9291/rsrc/css/application/pholio/pholio-edit.css', + 'uri' => '/res/01a56a3b/rsrc/css/application/pholio/pholio-edit.css', 'type' => 'css', 'requires' => array( diff --git a/src/applications/pholio/controller/PholioImageUploadController.php b/src/applications/pholio/controller/PholioImageUploadController.php index 67b68478a5..f24c7adb7d 100644 --- a/src/applications/pholio/controller/PholioImageUploadController.php +++ b/src/applications/pholio/controller/PholioImageUploadController.php @@ -10,6 +10,10 @@ final class PholioImageUploadController extends PholioController { $viewer = $request->getUser(); $phid = $request->getStr('filePHID'); + $replaces_phid = $request->getStr('replacesPHID'); + $title = $request->getStr('title'); + $description = $request->getStr('description'); + $file = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) @@ -18,14 +22,20 @@ final class PholioImageUploadController extends PholioController { return new Aphront404Response(); } + if (!strlen($title)) { + $title = $file->getName(); + } + $image = id(new PholioImage()) ->attachFile($file) - ->setName($file->getName()) + ->setName($title) + ->setDescription($description) ->makeEphemeral(); $view = id(new PholioUploadedImageView()) ->setUser($viewer) - ->setImage($image); + ->setImage($image) + ->setReplacesPHID($replaces_phid); $content = array( 'markup' => $view, diff --git a/src/applications/pholio/view/PholioUploadedImageView.php b/src/applications/pholio/view/PholioUploadedImageView.php index d5d0746b25..2c2b77ea0b 100644 --- a/src/applications/pholio/view/PholioUploadedImageView.php +++ b/src/applications/pholio/view/PholioUploadedImageView.php @@ -6,6 +6,12 @@ final class PholioUploadedImageView extends AphrontView { private $image; + private $replacesPHID; + + public function setReplacesPHID($replaces_phid) { + $this->replacesPHID = $replaces_phid; + return $this; + } public function setImage(PholioImage $image) { $this->image = $image; @@ -18,6 +24,7 @@ final class PholioUploadedImageView extends AphrontView { $image = $this->image; $file = $image->getFile(); $phid = $file->getPHID(); + $replaces_phid = $this->replacesPHID; $thumb = phutil_tag( 'img', @@ -32,13 +39,23 @@ final class PholioUploadedImageView extends AphrontView { $title = id(new AphrontFormTextControl()) ->setName('title_'.$phid) ->setValue($image->getName()) + ->setSigil('image-title') ->setLabel(pht('Title')); $description = id(new AphrontFormTextAreaControl()) ->setName('description_'.$phid) ->setValue($image->getDescription()) + ->setSigil('image-description') ->setLabel(pht('Description')); + $thumb_frame = javelin_tag( + 'div', + array( + 'class' => 'pholio-thumb-frame', + 'sigil' => 'pholio-thumb-frame', + ), + $thumb); + $content = hsprintf( '
@@ -53,7 +70,7 @@ final class PholioUploadedImageView extends AphrontView {
', $file->getName(), $remove, - $thumb, + $thumb_frame, $title, $description); @@ -65,15 +82,28 @@ final class PholioUploadedImageView extends AphrontView { 'value' => $phid, )); + $replaces_input = phutil_tag( + 'input', + array( + 'type' => 'hidden', + 'name' => 'replaces['.$replaces_phid.']', + 'value' => $phid, + )); + return javelin_tag( 'div', array( 'class' => 'pholio-uploaded-image', 'sigil' => 'pholio-drop-image', + 'meta' => array( + 'filePHID' => $file->getPHID(), + 'replacesPHID' => $replaces_phid, + ), ), array( $content, $input, + $replaces_input, )); } diff --git a/src/view/form/control/AphrontFormTextAreaControl.php b/src/view/form/control/AphrontFormTextAreaControl.php index bd36122ee9..9087a7e24b 100644 --- a/src/view/form/control/AphrontFormTextAreaControl.php +++ b/src/view/form/control/AphrontFormTextAreaControl.php @@ -13,6 +13,16 @@ class AphrontFormTextAreaControl extends AphrontFormControl { private $readOnly; private $customClass; private $placeHolder; + private $sigil; + + public function setSigil($sigil) { + $this->sigil = $sigil; + return $this; + } + + public function getSigil() { + return $this->sigil; + } public function setPlaceHolder($place_holder) { $this->placeHolder = $place_holder; @@ -61,7 +71,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl { $classes[] = $this->customClass; $classes = trim(implode(' ', $classes)); - return phutil_tag( + return javelin_tag( 'textarea', array( 'name' => $this->getName(), @@ -70,6 +80,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl { 'class' => $classes, 'style' => $this->getControlStyle(), 'id' => $this->getID(), + 'sigil' => $this->sigil, 'placeholder' => $this->getPlaceHolder(), ), // NOTE: This needs to be string cast, because if we pass `null` the diff --git a/webroot/rsrc/css/application/pholio/pholio-edit.css b/webroot/rsrc/css/application/pholio/pholio-edit.css index 3d4c15f779..28cab33343 100644 --- a/webroot/rsrc/css/application/pholio/pholio-edit.css +++ b/webroot/rsrc/css/application/pholio/pholio-edit.css @@ -3,6 +3,8 @@ */ .pholio-uploaded-image { + padding: 4px; + border: 1px solid transparent; margin: 0 0 12px 0; overflow: hidden; } @@ -30,13 +32,13 @@ border-bottom: 1px solid #D5D9DF; } -.pholio-uploaded-image .thumb-box .thumb { - background: white; +.pholio-thumb-frame { + background: #ffffff; padding: 12px 0px 0px 0px; width: 100%; } -.pholio-uploaded-image .thumb-box .thumb img { +.pholio-uploaded-image .thumb-box .pholio-thumb-frame img { margin: 0 auto; } @@ -93,7 +95,15 @@ color: #666666; } +.pholio-uploaded-image.pholio-drop-active, .pholio-edit-drop.pholio-drop-active { + border-style: solid; + border-color: {$green}; + background-color: {$lightgreen}; +} + +.pholio-replacing { + opacity: 0.5; border-color: {$green}; background-color: {$lightgreen}; } diff --git a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-edit.js b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-edit.js index d6213be13c..c4cb69c050 100644 --- a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-edit.js +++ b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-edit.js @@ -17,44 +17,6 @@ JX.behavior('pholio-mock-edit', function(config) { var uploading = []; - var drop = new JX.PhabricatorDragAndDropFileUpload(nodes.drop) - .setURI(config.uploadURI); - - drop.listen('didBeginDrag', function(e) { - JX.DOM.alterClass(nodes.drop, 'pholio-drop-active', true); - }); - - drop.listen('didEndDrag', function(e) { - JX.DOM.alterClass(nodes.drop, 'pholio-drop-active', false); - }); - - drop.listen('willUpload', function(file) { - var node = render_uploading(); - uploading.push({node: node, file: file}); - nodes.list.appendChild(node); - }); - - drop.listen('didUpload', function(file) { - var node; - for (var ii = 0; ii < uploading.length; ii++) { - if (uploading[ii].file === file) { - node = uploading[ii].node; - uploading.splice(ii, 1); - break; - } - } - - JX.DOM.setContent(node, pht('uploaded')); - - new JX.Workflow(config.renderURI, {filePHID: file.getPHID()}) - .setHandler(function(response) { - JX.DOM.replace(node, JX.$H(response.markup)); - }) - .start(); - }); - - drop.start(); - /* -( Deleting Images )---------------------------------------------------- */ @@ -77,6 +39,97 @@ JX.behavior('pholio-mock-edit', function(config) { }); +/* -( Build )-------------------------------------------------------------- */ + + + var build_drop_upload = function(node) { + var drop = new JX.PhabricatorDragAndDropFileUpload(node) + .setURI(config.uploadURI); + + drop.listen('didBeginDrag', function(e) { + JX.DOM.alterClass(node, 'pholio-drop-active', true); + }); + + drop.listen('didEndDrag', function(e) { + JX.DOM.alterClass(node, 'pholio-drop-active', false); + }); + + return drop; + }; + + var build_add_control = function(add_node) { + var drop = build_drop_upload(add_node); + + drop.listen('willUpload', function(file) { + var node = render_uploading(); + uploading.push({node: node, file: file}); + nodes.list.appendChild(node); + }); + + drop.listen('didUpload', function(file) { + var node; + for (var ii = 0; ii < uploading.length; ii++) { + if (uploading[ii].file === file) { + node = uploading[ii].node; + uploading.splice(ii, 1); + break; + } + } + + JX.DOM.setContent(node, pht('uploaded')); + + new JX.Workflow(config.renderURI, {filePHID: file.getPHID()}) + .setHandler(function(response) { + var new_node = JX.$H(response.markup).getFragment().firstChild; + build_update_control(new_node); + + JX.DOM.replace(node, new_node); + }) + .start(); + }); + + drop.start(); + }; + + var build_list_controls = function(list_node) { + var nodes = JX.DOM.scry(list_node, 'div', 'pholio-drop-image'); + for (var ii = 0; ii < nodes.length; ii++) { + build_update_control(nodes[ii]); + } + }; + + var build_update_control = function(node) { + var drop = build_drop_upload(node); + + drop.listen('willUpload', function(file) { + JX.DOM.alterClass(node, 'pholio-replacing', true); + }); + + drop.listen('didUpload', function(file) { + var node_data = JX.Stratcom.getData(node); + + var data = { + filePHID: file.getPHID(), + replacesPHID: node_data.replacesPHID || node_data.filePHID || null, + title: JX.DOM.find(node, 'input', 'image-title').value, + description: JX.DOM.find(node, 'textarea', 'image-description').value + }; + + new JX.Workflow(config.renderURI, data) + .setHandler(function(response) { + var new_node = JX.$H(response.markup).getFragment().firstChild; + build_update_control(new_node); + + JX.DOM.replace(node, new_node); + JX.DOM.alterClass(node, 'pholio-replacing', false); + }) + .start(); + }); + + drop.start(); + }; + + /* -( Rendering )---------------------------------------------------------- */ @@ -100,4 +153,9 @@ JX.behavior('pholio-mock-edit', function(config) { }; +/* -( Init )--------------------------------------------------------------- */ + + build_add_control(nodes.drop); + build_list_controls(nodes.list); + });