mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 16:52:41 +01:00
Add JS support for replacing Pholio mocks 1:1
Summary: Ref T3572. Needs some CSS tweaks, but this lets you drag an image on top of another image to replace it. There's no server-side or transaction support (and I'm not planning to build that), I just wanted to clear the way on the JS side. You'll get an additional array posted called `replaces`. Keys are old file PHIDs; values are new file PHIDs. Note that a key may not exist yet (if a user adds an image, and then also replaces that same image). In this case, the server should just treat it as an add. Test Plan: Dragged images on top of other images. Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T3572 Differential Revision: https://secure.phabricator.com/D6499
This commit is contained in:
parent
83c29da594
commit
87871b3588
6 changed files with 166 additions and 47 deletions
|
@ -2234,7 +2234,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-behavior-pholio-mock-edit' =>
|
'javelin-behavior-pholio-mock-edit' =>
|
||||||
array(
|
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',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -3744,7 +3744,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'pholio-edit-css' =>
|
'pholio-edit-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/89db9291/rsrc/css/application/pholio/pholio-edit.css',
|
'uri' => '/res/01a56a3b/rsrc/css/application/pholio/pholio-edit.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -10,6 +10,10 @@ final class PholioImageUploadController extends PholioController {
|
||||||
$viewer = $request->getUser();
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
$phid = $request->getStr('filePHID');
|
$phid = $request->getStr('filePHID');
|
||||||
|
$replaces_phid = $request->getStr('replacesPHID');
|
||||||
|
$title = $request->getStr('title');
|
||||||
|
$description = $request->getStr('description');
|
||||||
|
|
||||||
$file = id(new PhabricatorFileQuery())
|
$file = id(new PhabricatorFileQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withPHIDs(array($phid))
|
->withPHIDs(array($phid))
|
||||||
|
@ -18,14 +22,20 @@ final class PholioImageUploadController extends PholioController {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strlen($title)) {
|
||||||
|
$title = $file->getName();
|
||||||
|
}
|
||||||
|
|
||||||
$image = id(new PholioImage())
|
$image = id(new PholioImage())
|
||||||
->attachFile($file)
|
->attachFile($file)
|
||||||
->setName($file->getName())
|
->setName($title)
|
||||||
|
->setDescription($description)
|
||||||
->makeEphemeral();
|
->makeEphemeral();
|
||||||
|
|
||||||
$view = id(new PholioUploadedImageView())
|
$view = id(new PholioUploadedImageView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setImage($image);
|
->setImage($image)
|
||||||
|
->setReplacesPHID($replaces_phid);
|
||||||
|
|
||||||
$content = array(
|
$content = array(
|
||||||
'markup' => $view,
|
'markup' => $view,
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
final class PholioUploadedImageView extends AphrontView {
|
final class PholioUploadedImageView extends AphrontView {
|
||||||
|
|
||||||
private $image;
|
private $image;
|
||||||
|
private $replacesPHID;
|
||||||
|
|
||||||
|
public function setReplacesPHID($replaces_phid) {
|
||||||
|
$this->replacesPHID = $replaces_phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setImage(PholioImage $image) {
|
public function setImage(PholioImage $image) {
|
||||||
$this->image = $image;
|
$this->image = $image;
|
||||||
|
@ -18,6 +24,7 @@ final class PholioUploadedImageView extends AphrontView {
|
||||||
$image = $this->image;
|
$image = $this->image;
|
||||||
$file = $image->getFile();
|
$file = $image->getFile();
|
||||||
$phid = $file->getPHID();
|
$phid = $file->getPHID();
|
||||||
|
$replaces_phid = $this->replacesPHID;
|
||||||
|
|
||||||
$thumb = phutil_tag(
|
$thumb = phutil_tag(
|
||||||
'img',
|
'img',
|
||||||
|
@ -32,13 +39,23 @@ final class PholioUploadedImageView extends AphrontView {
|
||||||
$title = id(new AphrontFormTextControl())
|
$title = id(new AphrontFormTextControl())
|
||||||
->setName('title_'.$phid)
|
->setName('title_'.$phid)
|
||||||
->setValue($image->getName())
|
->setValue($image->getName())
|
||||||
|
->setSigil('image-title')
|
||||||
->setLabel(pht('Title'));
|
->setLabel(pht('Title'));
|
||||||
|
|
||||||
$description = id(new AphrontFormTextAreaControl())
|
$description = id(new AphrontFormTextAreaControl())
|
||||||
->setName('description_'.$phid)
|
->setName('description_'.$phid)
|
||||||
->setValue($image->getDescription())
|
->setValue($image->getDescription())
|
||||||
|
->setSigil('image-description')
|
||||||
->setLabel(pht('Description'));
|
->setLabel(pht('Description'));
|
||||||
|
|
||||||
|
$thumb_frame = javelin_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'pholio-thumb-frame',
|
||||||
|
'sigil' => 'pholio-thumb-frame',
|
||||||
|
),
|
||||||
|
$thumb);
|
||||||
|
|
||||||
$content = hsprintf(
|
$content = hsprintf(
|
||||||
'<div class="thumb-box">
|
'<div class="thumb-box">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
|
@ -53,7 +70,7 @@ final class PholioUploadedImageView extends AphrontView {
|
||||||
</div>',
|
</div>',
|
||||||
$file->getName(),
|
$file->getName(),
|
||||||
$remove,
|
$remove,
|
||||||
$thumb,
|
$thumb_frame,
|
||||||
$title,
|
$title,
|
||||||
$description);
|
$description);
|
||||||
|
|
||||||
|
@ -65,15 +82,28 @@ final class PholioUploadedImageView extends AphrontView {
|
||||||
'value' => $phid,
|
'value' => $phid,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$replaces_input = phutil_tag(
|
||||||
|
'input',
|
||||||
|
array(
|
||||||
|
'type' => 'hidden',
|
||||||
|
'name' => 'replaces['.$replaces_phid.']',
|
||||||
|
'value' => $phid,
|
||||||
|
));
|
||||||
|
|
||||||
return javelin_tag(
|
return javelin_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'pholio-uploaded-image',
|
'class' => 'pholio-uploaded-image',
|
||||||
'sigil' => 'pholio-drop-image',
|
'sigil' => 'pholio-drop-image',
|
||||||
|
'meta' => array(
|
||||||
|
'filePHID' => $file->getPHID(),
|
||||||
|
'replacesPHID' => $replaces_phid,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
$content,
|
$content,
|
||||||
$input,
|
$input,
|
||||||
|
$replaces_input,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,16 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
|
||||||
private $readOnly;
|
private $readOnly;
|
||||||
private $customClass;
|
private $customClass;
|
||||||
private $placeHolder;
|
private $placeHolder;
|
||||||
|
private $sigil;
|
||||||
|
|
||||||
|
public function setSigil($sigil) {
|
||||||
|
$this->sigil = $sigil;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSigil() {
|
||||||
|
return $this->sigil;
|
||||||
|
}
|
||||||
|
|
||||||
public function setPlaceHolder($place_holder) {
|
public function setPlaceHolder($place_holder) {
|
||||||
$this->placeHolder = $place_holder;
|
$this->placeHolder = $place_holder;
|
||||||
|
@ -61,7 +71,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
|
||||||
$classes[] = $this->customClass;
|
$classes[] = $this->customClass;
|
||||||
$classes = trim(implode(' ', $classes));
|
$classes = trim(implode(' ', $classes));
|
||||||
|
|
||||||
return phutil_tag(
|
return javelin_tag(
|
||||||
'textarea',
|
'textarea',
|
||||||
array(
|
array(
|
||||||
'name' => $this->getName(),
|
'name' => $this->getName(),
|
||||||
|
@ -70,6 +80,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
|
||||||
'class' => $classes,
|
'class' => $classes,
|
||||||
'style' => $this->getControlStyle(),
|
'style' => $this->getControlStyle(),
|
||||||
'id' => $this->getID(),
|
'id' => $this->getID(),
|
||||||
|
'sigil' => $this->sigil,
|
||||||
'placeholder' => $this->getPlaceHolder(),
|
'placeholder' => $this->getPlaceHolder(),
|
||||||
),
|
),
|
||||||
// NOTE: This needs to be string cast, because if we pass `null` the
|
// NOTE: This needs to be string cast, because if we pass `null` the
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.pholio-uploaded-image {
|
.pholio-uploaded-image {
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid transparent;
|
||||||
margin: 0 0 12px 0;
|
margin: 0 0 12px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -30,13 +32,13 @@
|
||||||
border-bottom: 1px solid #D5D9DF;
|
border-bottom: 1px solid #D5D9DF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pholio-uploaded-image .thumb-box .thumb {
|
.pholio-thumb-frame {
|
||||||
background: white;
|
background: #ffffff;
|
||||||
padding: 12px 0px 0px 0px;
|
padding: 12px 0px 0px 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pholio-uploaded-image .thumb-box .thumb img {
|
.pholio-uploaded-image .thumb-box .pholio-thumb-frame img {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,15 @@
|
||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pholio-uploaded-image.pholio-drop-active,
|
||||||
.pholio-edit-drop.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};
|
border-color: {$green};
|
||||||
background-color: {$lightgreen};
|
background-color: {$lightgreen};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,44 +17,6 @@ JX.behavior('pholio-mock-edit', function(config) {
|
||||||
|
|
||||||
var uploading = [];
|
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 )---------------------------------------------------- */
|
/* -( 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 )---------------------------------------------------------- */
|
/* -( Rendering )---------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,4 +153,9 @@ JX.behavior('pholio-mock-edit', function(config) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Init )--------------------------------------------------------------- */
|
||||||
|
|
||||||
|
build_add_control(nodes.drop);
|
||||||
|
build_list_controls(nodes.list);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue