Mailing List Archive

Re: [8500] Added support for copying and pasting elements in the story
This uses the 'Clone' module. Should I add it to the modules list in
lib/Bric/Admin.pod?

Adrian

brewt@bricolage.cc wrote:
> Revision
> 8500 <http://viewsvn.bricolage.cc/?rev=8500&view=rev>
> Author
> brewt
> Date
> 2009-03-12 13:23:30 -0700 (Thu, 12 Mar 2009)
>
>
> Log Message
>
> Added support for copying and pasting elements in the story profile. Cut support isn't included due to limitations in UI space (need to re-organize the delete/copy icons), but should be trivial to add.
>
>
> Modified Paths
>
> * bricolage/trunk/comp/media/css/style.css
> <#bricolagetrunkcompmediacssstylecss>
> * bricolage/trunk/comp/media/js/lib.js <#bricolagetrunkcompmediajslibjs>
> * bricolage/trunk/comp/widgets/container_prof/container.mc
> <#bricolagetrunkcompwidgetscontainer_profcontainermc>
> * bricolage/trunk/comp/widgets/container_prof/field.mc
> <#bricolagetrunkcompwidgetscontainer_proffieldmc>
> * bricolage/trunk/lib/Bric/App/Callback/ContainerProf.pm
> <#bricolagetrunklibBricAppCallbackContainerProfpm>
> * bricolage/trunk/lib/Bric/Changes.pod
> <#bricolagetrunklibBricChangespod>
> * bricolage/trunk/lib/Bric/Util/Language/de_de.pm
> <#bricolagetrunklibBricUtilLanguagede_depm>
> * bricolage/trunk/lib/Bric/Util/Language/it_it.pm
> <#bricolagetrunklibBricUtilLanguageit_itpm>
> * bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm
> <#bricolagetrunklibBricUtilLanguagept_ptpm>
> * bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm
> <#bricolagetrunklibBricUtilLanguageru_rupm>
> * bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm
> <#bricolagetrunklibBricUtilLanguagezh_cnpm>
> * bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm
> <#bricolagetrunklibBricUtilLanguagezh_twpm>
>
>
> Added Paths
>
> * bricolage/trunk/comp/media/images/copy.png
> <#bricolagetrunkcompmediaimagescopypng>
>
>
> Diff
>
>
> Modified: bricolage/trunk/comp/media/css/style.css (8499 => 8500)
>
>
> --- bricolage/trunk/comp/media/css/style.css 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/comp/media/css/style.css 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -688,9 +688,16 @@
> }
> #containerprof .content .delete {
> position: absolute;
> - top: 0; right: 0;
> + top: 5px; right: 0;
> }
> -#containerprof .container .delete { top: 5px; }
> +#containerprof .content > .delete { top: 0; }
> +#containerprof .container > .content > .delete { top: 8px; }
> +#containerprof .content .copy {
> + position: absolute;
> + top: 24px; right: 0;
> +}
> +#containerprof .content > .copy { top: 19px; }
> +#containerprof .container > .content > .copy { top: 27px; }
> #containerprof .actions { background: transparent; }
> #containerprof .actions button { background: transparent; border: none; margin: 0 10px 0 0; padding: 2px; }
> #containerprof div.popup-menu ul li { white-space: normal; }
>
>
> Added: bricolage/trunk/comp/media/images/copy.png
>
>
> (Binary files differ)
>
> Property changes on: bricolage/trunk/comp/media/images/copy.png
> ___________________________________________________________________
>
>
> Added: svn:mime-type ( => )
>
>
>
> Modified: bricolage/trunk/comp/media/js/lib.js
> ===================================================================
> --- bricolage/trunk/comp/media/js/lib.js 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/comp/media/js/lib.js 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -1544,6 +1544,40 @@
> }
> },
>
> + copyElement: function(container_id, element_id) {
> + Container.refresh(container_id, {
> + extraParameters: 'container_prof|copy_cb=' + element_id
> + });
> + },
> +
> + /*
> + Update the Paste item on all the "Add Element" popup menus.
> + input:
> + id - the container or field type id (cont_* or data_*) of the element in the buffer
> + text - the text to show for the menu item
> + */
> + updatePaste: function(id, text) {
> + $$('.actions .popup-menu ul').each(function (menu) {
> + var found = false;
> + var links = menu.getElementsByTagName('a');
> + for (var i = 0; i < links.length - 1; i++) {
> + if (links[i].getAttribute('rel') == id) {
> + found = true;
> + break;
> + }
> + }
> +
> + // The last element of the list is always Paste
> + if (found) {
> + links[links.length - 1].parentNode.style.display = '';
> + links[links.length - 1].innerHTML = text;
> + }
> + else {
> + links[links.length - 1].parentNode.style.display = 'none';
> + }
> + });
> + },
> +
> toggle: function( eid, anchor ) {
> Effect.toggle('element_' + eid, 'blind', {duration: 0.3});
> Effect.toggle('element_' + eid + '_hint', 'blind', {duration: 0.3});
>
>
> Modified:
> bricolage/trunk/comp/widgets/container_prof/container.mc (8499
> => 8500)
>
>
> --- bricolage/trunk/comp/widgets/container_prof/container.mc 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/comp/widgets/container_prof/container.mc 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -73,12 +73,18 @@
> <div id="element_<% $id %>_add_desks" class="popup-menu" style="display: none; width: 10em; padding: 0;">
> <ul>
> % foreach my $opt (@$elem_opts) {
> - <li><a href="#" onclick="Container.addElement(<% $id %>, '<% $opt->[0] %>'); return false"><% $opt->[1] %></a></li>
> + <li><a href="#" onclick="Container.addElement(<% $id %>, '<% $opt->[0] %>'); return false" rel="<% $opt->[0] %>"><% $opt->[1] %></a></li>
> % }
> + <li style="display: none !important"><a href="#" onclick="Container.addElement(<% $id %>, 'copy_buffer'); return false">Paste</a></li>
> </ul>
> </div>
> </div>
> +% if (keys %paste) {
> + <script type="text/javascript">
> + Container.updatePaste('<% $paste{id} %>', '<% $paste{text} %>');
> + </script>
> % }
> +% }
>
> <span style="cursor: pointer;" id="<% $top_level ? 'bulk_edit_this_cb' : 'bulk_edit_' . $id %>" onclick="customSubmit('theForm','<% $top_level ? 'container_prof|bulk_edit_this_cb' : 'container_prof|bulk_edit_cb' %>','<% $id %>')" > <img src="/media/images/bulk-edit.png" alt="Bulk Edit" />Bulk Edit</span>
> </div>
> @@ -94,16 +100,27 @@
> % if ( $minimum_occurrence < $parent->get_elem_occurrence($element->get_key_name) ) {
> <div class="delete">
> <& '/widgets/profile/button.mc',
> - disp => $lang->maketext("Delete"),
> - name => 'delete_' . $name,
> - button => 'delete',
> - extension => 'png',
> + disp => $lang->maketext("Delete"),
> + name => 'delete_' . $name,
> + button => 'delete',
> + extension => 'png',
> globalImage => 1,
> - js => q{onclick="Container.deleteElement(} . $element->get_parent_id . qq{, '$name'); return false;"},
> - useTable => 0
> + js => q{onclick="Container.deleteElement(} . $element->get_parent_id . qq{, '$name'); return false;"},
> + useTable => 0
> &>
> </div>
> % }
> +<div class="copy">
> + <& '/widgets/profile/button.mc',
> + disp => $lang->maketext("Copy"),
> + name => 'copy_' . $name,
> + button => 'copy',
> + extension => 'png',
> + globalImage => 1,
> + js => q{onclick="Container.copyElement(} . $element->get_parent_id . ', ' . $element->get_id . qq{); return false;"},
> + useTable => 0
> + &>
> +</div>
> % }
>
> </div>
> @@ -144,4 +161,18 @@
> $element->get_possible_field_types,
> grep { chk_authz($_, READ, 1) } $element->get_possible_containers
> ];
> +
> +my %paste;
> +my $buffer = get_state_data('copy_buffer', 'buffer');
> +if ($buffer) {
> + my $buff_type = $buffer->is_container ? $buffer->get_element_type : $buffer->get_field_type;
> + my $id = ($buff_type->can('get_sites') ? 'cont_' : 'data_') . $buff_type->get_id;
> +
> +# Info about the element in the buffer that is used to determine if it can be
> +# added to the containers on the page
> + %paste = (
> + id => $id,
> + text => $lang->maketext('Paste ([_1])', $buffer->get_name),
> + );
> +}
> </%init>
>
>
> Modified: bricolage/trunk/comp/widgets/container_prof/field.mc
> (8499 => 8500)
>
>
> --- bricolage/trunk/comp/widgets/container_prof/field.mc 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/comp/widgets/container_prof/field.mc 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -34,7 +34,20 @@
> &>
> </div>
> % }
> +% unless ($element->is_autopopulated) {
> + <div class="copy">
> + <& '/widgets/profile/button.mc',
> + disp => $lang->maketext("Copy"),
> + name => 'copy_' . $name,
> + button => 'copy',
> + extension => 'png',
> + globalImage => 1,
> + js => q{onclick="Container.copyElement(} . $element->get_parent_id . ', ' . $element->get_id . qq{); return false;"},
> + useTable => 0
> + &>
> + </div>
> </div>
> +% }
>
> <%args>
> $widget
>
>
> Modified: bricolage/trunk/lib/Bric/App/Callback/ContainerProf.pm
> (8499 => 8500)
>
>
> --- bricolage/trunk/lib/Bric/App/Callback/ContainerProf.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/App/Callback/ContainerProf.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -25,6 +25,7 @@
> use Bric::Biz::Workflow qw(:wf_const);
> eval { require Text::Levenshtein };
> require Text::Soundex if $@;
> +use Clone;
>
> my $STORY_URL = '/workflow/profile/story/';
> my $STORY_CONT = '/workflow/profile/story/container/';
> @@ -128,16 +129,28 @@
> $a_obj = $pkgs{$key}->lookup({ id => $element->get_object_instance_id });
> }
>
> - my ($type, $id) = unpack('A5 A*', $field);
> -
> my $element_type;
> - if ($type eq 'cont_') {
> - $element_type = Bric::Biz::ElementType->lookup({ id => $id });
> - $element->add_container($element_type)->set_displayed(1);
> - } else {
> - $element_type = Bric::Biz::ElementType::Parts::FieldType->lookup({ id => $id });
> - $element->add_field($element_type);
> + # Pasting an element from the copy buffer
> + if ($field eq 'copy_buffer') {
> + my $copy_buffer = get_state_data('copy_buffer', 'buffer');
> + if ($copy_buffer) {
> + my $clone = Clone::clone($copy_buffer)->prepare_clone;
> + $element_type = $clone->is_container ? $clone->get_element_type : $clone->get_field_type;
> + $element->add_element($clone);
> + }
> }
> + else {
> + my ($type, $id) = unpack('A5 A*', $field);
> +
> + if ($type eq 'cont_') {
> + $element_type = Bric::Biz::ElementType->lookup({ id => $id });
> + $element->add_container($element_type)->set_displayed(1);
> + } else {
> + $element_type = Bric::Biz::ElementType::Parts::FieldType->lookup({ id => $id });
> + $element->add_field($element_type);
> + }
> + }
> +
> # If an element is added, we want to display the parent.
> $element->set_displayed(1);
> $element->save;
> @@ -161,6 +174,20 @@
> # $element->save;
> }
>
> +sub copy : Callback {
> + my $self = shift;
> + $self->_drift_correction;
> + my $param = $self->params;
> + return if $param->{_inconsistent_state_};
> +
> + my $widget = $self->class_key;
> +
> + my $element = get_state_data($widget, 'element');
> + my $copy_element = $self->_locate_subelement($element, $self->value, 1);
> +
> + set_state_data('copy_buffer', 'buffer', $copy_element);
> +}
> +
> sub pick_related_media : Callback {
> my $self = shift;
> $self->_drift_correction;
> @@ -571,7 +598,7 @@
> }
>
> sub _locate_subelement {
> - my ($self, $element, $locate_id) = @_;
> + my ($self, $element, $locate_id, $inc_fields) = @_;
> $locate_id ||= $self->value;
>
> {
> @@ -580,9 +607,13 @@
> }
>
> foreach my $t ($element->get_elements) {
> + if ($inc_fields) {
> + no warnings 'uninitialized';
> + return $t if $t->get_id == $locate_id;
> + }
> next unless $t->is_container;
>
> - my $locate_element = $self->_locate_subelement($t, $locate_id);
> + my $locate_element = $self->_locate_subelement($t, $locate_id, $inc_fields);
> return $locate_element if $locate_element;
> }
> }
>
>
> Modified: bricolage/trunk/lib/Bric/Changes.pod (8499 => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Changes.pod 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Changes.pod 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -106,6 +106,11 @@
> Cover date is now required at the database level. It has always been required
> in the UI. [David]
>
> +=item *
> +
> +Added support for copying and pasting elements in the story profile.
> +[Adrian Yee]
> +
> =back
>
> =head2 Bug Fixes
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/de_de.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/de_de.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/de_de.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -788,6 +788,7 @@
> To Translate:
> 'Invalid codeselect code (didn't return an array ref of even size)' => 'Ungültiger codeselect Code (didn't return an array ref of even size)',
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> +'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
>
>
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/it_it.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/it_it.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/it_it.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -603,6 +603,7 @@
> 'Could not create a thumbnail for [_1]: [_2]' => 'Could not create a thumbnail for [_1]: [_2]',
> 'Toggle "[_1]"' => 'Toggle \xFC[_1]\xFD',
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> + 'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
> =end comment
>
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -774,6 +774,7 @@
> 'Delete this Source' => 'Delete this Source',
> 'Delete this Workflow' => 'Delete this Workflow',
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> + 'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
> =end comment
>
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -770,6 +770,7 @@
>
> To Translate:
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> + 'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
> ==end comment
>
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -642,6 +642,7 @@
> 'Could not create a thumbnail for [_1]: [_2]' => 'Could not create a thumbnail for [_1]: [_2]',
> 'Toggle "[_1]"' => 'Toggle “[_1]”',
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> + 'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
> =end comment
>
>
>
> Modified: bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm (8499
> => 8500)
>
>
> --- bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm 2009-03-12 18:10:39 UTC (rev 8499)
> +++ bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm 2009-03-12 20:23:30 UTC (rev 8500)
> @@ -768,6 +768,7 @@
> 'Could not create a thumbnail for [_1]: [_2]' => 'Could not create a thumbnail for [_1]: [_2]',
> 'Toggle "[_1]"' => 'Toggle “[_1]”',
> 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
> + 'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
>
> Notice:
>
>
Re: [8500] Added support for copying and pasting elements in the story [ In reply to ]
On Mar 12, 2009, at 1:28 PM, Adrian Yee wrote:

> This uses the 'Clone' module. Should I add it to the modules list
> in lib/Bric/Admin.pod?

yes please.

David
Re: [8500] Added support for copying and pasting elements in the story [ In reply to ]
On Mar 12, 2009, at 4:59 PM, David E. Wheeler wrote:

> On Mar 12, 2009, at 1:28 PM, Adrian Yee wrote:
>
>> This uses the 'Clone' module. Should I add it to the modules list
>> in lib/Bric/Admin.pod?

Will that properly make it a required module? My version of trunk
just broke for lack of clone after updating.

-Matt
Re: [8500] Added support for copying and pasting elements in the story [ In reply to ]
On Mar 12, 2009, at 2:24 PM, Matt Rolf wrote:

>>> This uses the 'Clone' module. Should I add it to the modules list
>>> in lib/Bric/Admin.pod?
>
> Will that properly make it a required module? My version of trunk
> just broke for lack of clone after updating.

Yes, that makes it required.

Best,

David