2016-01-28 2 views
1

Я ищу способ создания настраиваемой кнопки действий, которая позволяет мне создать новый DataObject с pre заполненный контент из другого объекта DataObject. В качестве простого примера: когда у меня есть электронное письмо и нажмите кнопку «ответ» в моем почтовом клиенте, я получаю новое окно с предварительно заполненным контентом из письма раньше. Мне нужна именно эта функция для моей кнопки. Эта кнопка должна появиться рядом с каждым объектом DataObject в GridField.Silverstripe 3.2: Как создать пользовательскую кнопку действий в CMS для создания нового объекта Data и его заполнения из другого.

Так что я знаю, как сделать кнопку и добавить его в мой GridField (->https://docs.silverstripe.org/en/3.2/developer_guides/forms/how_tos/create_a_gridfield_actionprovider/), и я знаю, как идти к новому DataObject:

Controller::curr()->redirect($gridField->Link('item/new')); 

Я также обнаружил, что есть дублировать функции для DataObjects:

public function duplicate($doWrite = true) { 
     $className = $this->class; 
     $clone = new $className($this->toMap(), false, $this->model); 
     $clone->ID = 0; 

     $clone->invokeWithExtensions('onBeforeDuplicate', $this, $doWrite); 
     if($doWrite) { 
      $clone->write(); 
      $this->duplicateManyManyRelations($this, $clone); 
     } 
     $clone->invokeWithExtensions('onAfterDuplicate', $this, $doWrite); 

     return $clone; 
    } 

Может быть, это проще, чем я думаю, но в данный момент я просто не понимаю, как переписать это, чтобы получить то, что мне нужно. Может ли кто-нибудь дать мне подсказку?

+0

Итак, вы не знаете, как совместить настраиваемое действие сетки и дублирующее действие? Правильно ли я понял вашу проблему? –

+0

Да. Я мог бы использовать часть повторяющегося действия, но новый объект данных не должен быть добавлен в базу данных. Пользователь должен иметь возможность изменять содержимое перед сохранением и созданием нового объекта данных, поэтому необходимо перенаправить (или всплывающее окно) к еще не добавленному, но уже предварительно заполненному новому объекту данных. Это возможно? – iraira

+0

Ах, хм, не знаю, но это будет полезно. Я постараюсь найти что-то, когда я нахожусь дома через несколько часов. –

ответ

1

Это точно не самое чистое решение, но я думаю, что он должен сделать трюк.

Сначала создадим настраиваемое действие сетки. Здесь мы будем сохранять все доступные записи в сеансе и добавить строку запроса в URL, так что мы будем знать, какой объект мы хотим «клон»

public function getColumnContent($gridField, $record, $columnName) { 
    if(!$record->canEdit()) return; 

    $field = GridField_FormAction::create(
     $gridField, 
     'clone'.$record->ID, 
     'Clone', 
     'clone', 
     array('RecordID' => $record->ID) 
    ); 

    $values = Session::get('ClonedData'); 
    $data = $record->data()->toMap(); 

    if($arr = $values) { 
     $arr[$record->ID] = $data; 
    } else { 
     $arr = array(
      $record->ID => $data 
     ); 
    } 

    Session::set('ClonedData', $arr); 

    return $field->Field(); 
} 

public function getActions($gridField) { 
    return array('clone'); 
} 

public function handleAction(GridField $gridField, $actionName, $arguments, $data) { 
    if($actionName == 'clone') { 
     $id = $arguments['RecordID']; 
     Controller::curr()->redirect($gridField->Link("item/new/?cloneID=$id")); 
    } 
} 

после добавления этого нового компонента к нашему gridfield,

$gridField->getConfig()->addComponent(new GridFieldCustomAction()); 

Нам нужно будет привести данные в новую форму. Для этого добавьте этот код непосредственно над «return $ fields» в вашей функции getCMSFields, чтобы он выполнялся каждый раз, когда мы будем открывать этот вид объекта.

$values = Session::get('ClonedData'); 

if($values) { 
    Session::clear('ClonedData'); 
    $json = json_encode($values); 
    $fields->push(LiteralField::create('ClonedData', "<div id='cloned-data' style='display:none;'>$json</div>")); 
} 

В конце концов нам нужно вернуть содержимое обратно в поля. Мы сделаем это с небольшим количеством javascript, поэтому сначала вам нужно создать новый файл script.js и включить его в бэкэнд ss (или просто использовать существующий).

(function($) { 
    $('#cloned-data').entwine({ 
    onmatch: function() { 
     var data = JSON.parse($(this).text()), 
      id = getParameterByName('cloneID'); 

     if(id && data) { 
     var obj = data[id]; 

     if(obj) { 
      $.each(obj, function(i, val) { 
      $('[name=' + i + ']').val(val); 
      }); 
     } 
     } 
    } 
    }); 

    // http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript#answer-901144 
    function getParameterByName(name) { 
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); 
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), 
     results = regex.exec(location.search); 
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); 
    } 
})(jQuery); 

И все ... довольно сложно. Надеюсь, что это решит вашу проблему.

+0

Большое спасибо! Это именно то, что я искал. Прекрасно работает для меня! Благодарим вас за действительно хорошее пошаговое описание! Это было легко понять и интегрировать в мой код! Вы сделали мой день! :) – iraira

+0

После некоторого времени тестирования, похоже, проблема с кодеком entwine и htmleditorfield. Он работает только в первый раз. Когда я вернусь из клонированного нового объекта Date без сохранения, а затем снова нажмите «clone», отсутствует клонированное содержимое htmleditorfield. Все остальные поля отлично работают. У вас есть идея, как с этим бороться? – iraira

+0

sry У меня сейчас очень мало времени, но я думаю, что для этой работы с полями htmleditor вам нужно изменить функцию, чтобы определить, является ли поле htmleditorfield, а затем использовать метод tinymce setContent http: // archive .tinymce.com/wiki.php/API3: method.tinymce.Editor.setContent –

Смежные вопросы