Editing campaigns
Code
Create the file campaignedit.php in the folder actions with the following content:
- function campaignedit($lang, $arglist=false) {
- global $supported_languages;
- $campaign=$page=false;
- if (is_array($arglist)) {
- if (isset($arglist[0])) {
- $campaign=$arglist[0];
- }
- if (isset($arglist[1])) {
- $page=$arglist[1];
- }
- }
- $clang=false;
- foreach ($supported_languages as $slang) {
- if (isset($_POST[$slang])) {
- $clang=$slang;
- break;
- }
- }
- if (!$clang) {
- if (isset($_POST['clang'])) {
- $clang = $_POST['clang'];
- }
- else if (isset($_GET['clang'])) {
- $clang = $_GET['clang'];
- }
- else {
- $clang=$lang;
- }
- if (!in_array($clang, $supported_languages)) {
- return run('error/notfound', $lang);
- }
- }
- if (!$campaign) {
- return run('error/notfound', $lang);
- }
- if (!$page) {
- require_once 'actions/campaigneditsummary.php';
- return campaigneditsummary($lang, $clang, $campaign);
- }
- require_once 'actions/campaigneditpage.php';
- return campaigneditpage($lang, $clang, $campaign, $page);
- }
Create the file campaigneditsummary.php in the folder actions with the following content:
- require_once 'readarg.php';
- require_once 'strtofname.php';
- require_once 'userhasrole.php';
- require_once 'userprofile.php';
- require_once 'models/thread.inc';
- function campaigneditsummary($lang, $clang, $thread) {
- global $with_toolbar;
- $user_id=user_profile('id');
- if (!$user_id) {
- return run('error/unauthorized', $lang);
- }
- $thread_id = thread_id($thread);
- if (!$thread_id) {
- return run('error/notfound', $lang);
- }
- $r = thread_get($lang, $thread_id);
- if (!$r) {
- return run('error/notfound', $lang);
- }
- extract($r); /* thread_user_id thread_type thread_title */
- if ($thread_type != 'campaign') {
- return run('error/notfound', $lang);
- }
- if ($thread_user_id != $user_id and !user_has_role('administrator')) {
- return run('error/notfound', $lang);
- }
- $confirmed=false;
- $action='init';
- if (isset($_POST['thread_reorder'])) {
- $action='reorder';
- }
- else if (isset($_POST['node_create'])) {
- $action='create';
- }
- else if (isset($_POST['node_copy'])) {
- $action='copy';
- }
- else if (isset($_POST['node_delete'])) {
- $action='delete';
- }
- else if (isset($_POST['node_confirmdelete'])) {
- $action='delete';
- $confirmed=true;
- }
- $new_node_name=$new_node_title=$new_node_number=false;
- $old_node_number=false;
- $p=false;
- switch($action) {
- case 'create':
- case 'delete':
- case 'copy':
- case 'reorder':
- if (isset($_POST['new_node_title'])) {
- $new_node_title=readarg($_POST['new_node_title']);
- $new_node_name = strtofname($new_node_title);
- }
- if (isset($_POST['new_node_number'])) {
- $new_node_number=readarg($_POST['new_node_number']);
- }
- if (isset($_POST['old_node_number'])) {
- $old_node_number=readarg($_POST['old_node_number']);
- }
- if (isset($_POST['p'])) {
- $p=$_POST['p']; // DON'T readarg!
- }
- break;
- default:
- break;
- }
- $thread_contents = array();
- $r = thread_get_contents($clang, $thread_id); /* node_id node_number node_ignored node_name node_title node_cloud thread_image */
- if (!$r or count($r) != count($p)) {
- $p = false;
- }
- if ($r) {
- $pos=1;
- $thread_url = url('campaignedit', $lang) . '/' . $thread_id;
- foreach ($r as $c) {
- $c['node_url'] = $thread_url . '/' . $c['node_id'];
- $c['pos'] = $p ? $p[$pos] : $pos;
- $thread_contents[$pos] = $c;
- $pos++;
- }
- }
- $missing_new_node_title=false;
- $bad_new_node_title=false;
- $bad_new_node_number=false;
- $missing_old_node_number=false;
- $bad_old_node_number=false;
- switch($action) {
- case 'copy':
- case 'create':
- if (!$new_node_title) {
- $missing_new_node_title = true;
- }
- else if (!$new_node_name) {
- $bad_new_node_title = true;
- }
- else if (!preg_match('#^\w+(-\w+)*$#', $new_node_name)) {
- $bad_new_node_title = true;
- }
- if (!$new_node_number) {
- $new_node_number = false;
- }
- else if (!is_numeric($new_node_number)) {
- $bad_new_node_number = true;
- }
- else if ($new_node_number < 1 or $new_node_number > count($thread_contents) + 1) {
- $bad_new_node_number = true;
- }
- break;
- default:
- break;
- }
- switch($action) {
- case 'copy':
- case 'delete':
- if (!$old_node_number) {
- $missing_old_node_number = true;
- }
- else if (!is_numeric($old_node_number)) {
- $bad_old_node_number = true;
- }
- else if ($old_node_number < 1 or $old_node_number > count($thread_contents)) {
- $bad_old_node_number = true;
- }
- break;
- default:
- break;
- }
- $confirm_delete_node=false;
- switch($action) {
- case 'create':
- case 'copy':
- if ($missing_new_node_title or $bad_new_node_title or $bad_new_node_number) {
- break;
- }
- if ($action == 'copy') {
- if ($missing_old_node_number or $bad_old_node_number) {
- break;
- }
- $node_id = $thread_contents[$old_node_number]['node_id'];
- $np = thread_copy_node($clang, $thread_user_id, $thread_id, $node_id, $new_node_name, $new_node_title, $new_node_number);
- }
- else {
- $np = thread_create_node($clang, $thread_user_id, $thread_id, $new_node_name, $new_node_title, $new_node_number);
- }
- if (!$np) {
- break;
- }
- extract($np); /* node_id node_number */
- $node_ignored = false;
- $node_title = $new_node_title;
- $node_url = url('campaignedit', $lang) . '/' . $thread_id . '/' . $node_id;
- $pos = $node_number;
- if ($thread_contents) {
- foreach ($thread_contents as &$c) {
- if ($c['node_number'] >= $pos) {
- $c['node_number']++;
- }
- if ($c['pos'] >= $pos) {
- $c['pos']++;
- }
- }
- array_splice($thread_contents, $pos-1, 0, array(compact('node_id', 'node_title', 'node_number', 'node_ignored', 'node_url', 'pos')));
- }
- else {
- $pos=1;
- $thread_contents=array($pos => compact('node_id', 'node_title', 'node_number', 'node_ignored', 'node_url', 'pos'));
- }
- $new_node_name=$new_node_title=false;
- $new_node_number=$node_number+1;
- $old_node_number = false;
- break;
- case 'delete':
- if ($missing_old_node_number or $bad_old_node_number) {
- break;
- }
- if (!$confirmed) {
- $confirm_delete_node=true;
- break;
- }
- $node_id = $thread_contents[$old_node_number]['node_id'];
- $r = thread_delete_node($thread_id, $node_id);
- if (!$r) {
- break;
- }
- unset($thread_contents[$old_node_number]);
- $thread_contents = array_values($thread_contents);
- foreach ($thread_contents as &$c) {
- if ($c['node_number'] >= $old_node_number) {
- $c['node_number']--;
- }
- if ($c['pos'] >= $old_node_number) {
- $c['pos']--;
- }
- }
- $old_node_number = false;
- break;
- case 'reorder':
- if (!$p) {
- break;
- }
- $neworder=range(1, count($p));
- array_multisort($p, SORT_NUMERIC, $neworder);
- $number=1;
- $nc=array();
- foreach ($neworder as $i) {
- $c = &$thread_contents[$i];
- if ($c['node_number'] != $number) {
- thread_set_node_number($thread_id, $c['node_id'], $number);
- $c['node_number'] = $number;
- }
- $c['pos']=$number;
- $nc[$number++] = $c;
- }
- $thread_contents = $nc;
- break;
- default:
- break;
- }
- head('title', $thread_title ? $thread_title : $thread_id);
- head('description', false);
- head('keywords', false);
- head('robots', 'noindex, nofollow');
- $viewsms=url('campaign', $clang) . '/'. $thread_id . '?' . 'slang=' . $lang;
- $admin=true;
- $banner = build('banner', $lang, $with_toolbar ? false : compact('viewsms', 'admin'));
- $toolbar = $with_toolbar ? build('toolbar', $lang, compact('viewsms', 'admin')) : false;
- $inlanguages=view('inlanguages', false, compact('clang'));
- $errors = compact('missing_new_node_title', 'bad_new_node_title', 'bad_new_node_number', 'missing_old_node_number', 'bad_old_node_number');
- $content = view('campaigneditsummary', $lang, compact('clang', 'inlanguages', 'thread_title', 'thread_id', 'thread_contents', 'new_node_name', 'new_node_title', 'new_node_number', 'old_node_number', 'confirm_delete_node', 'errors'));
- $output = layout('editing', compact('toolbar', 'banner', 'content'));
- return $output;
- }
Create the view campaigneditsummary in English and in French in the files views/en/campaigneditsummary.phtml and views/fr/campaigneditsummary.phtml:
- <?php extract($errors); ?>
- <h3<?php if ($thread_title): ?> title="<?php echo $thread_id; ?>"<?php endif; ?>><?php echo htmlspecialchars($thread_title ? $thread_title : $thread_id , ENT_COMPAT, 'UTF-8'); ?></h3>
- <form method="post" class="compact">
- <input name="clang" type="hidden" value="<?php echo $clang; ?>" />
- <p>
- <?php echo $inlanguages; ?>
- </p>
- <p>
- <input class="submit submit_add" id="node_create" name="node_create" type="submit" value="Add" />
- campaign
- <input id="new_node_title" name="new_node_title" type="text" size="50" maxlength="100" value="<?php echo htmlspecialchars($new_node_title, ENT_COMPAT, 'UTF-8'); ?>" title="Title" onkeypress="return focusonenter(event, 'new_node_number')"/>
- <span class="nowrap">
- #
- <input id="new_node_number" name="new_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($new_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Number" onkeypress="return submitonenter(event, 'node_create')"/>
- </span>
- </p>
- <?php if ($thread_contents): ?>
- <div id="threadcontent">
- <fieldset class="block">
- <legend>Titles</legend>
- <table id="nodelist">
- <tbody>
- <?php
- $i=1;
- $maxlen=strlen(count($thread_contents))+1;
- foreach ($thread_contents as $c) {
- extract($c); /* pos, node_id node_title, node_url, node_number, node_ignored */
- $node_url .= '?' . 'clang=' . $clang;
- ?>
- <tr>
- <td><input name="p[<?php echo $i; ?>]" type="text" size="2" maxlength="<?php echo $maxlen; ?>" value="<?php echo $pos; ?>" /></td>
- <td><a href="<?php echo $node_url; ?>" title="<?php echo $node_id; ?>"><?php echo $node_title ? htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8') : $node_id; ?></a></td>
- </tr>
- <?php
- $i++;
- }
- ?>
- </tbody>
- </table>
- </fieldset>
- <p>
- <input class="submit submit_sort" id="thread_reorder" name="thread_reorder" type="submit" value="Sort" />
- list or
- <input class="submit submit_copy" id="node_copy" name="node_copy" type="submit" value="Copy" />
- or
- <input class="submit submit_delete" id="node_delete" name="node_delete" type="submit" value="Delete" />
- campaign
- <span class="nowrap">
- #
- <input id="old_node_number" name="old_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($old_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Number" onkeypress="return submitonenter(event, 'node_delete')"/>
- </span>
- <?php if ($confirm_delete_node): ?>
- <input class="submit submit_confirm" id="node_confirmdelete" name="node_confirmdelete" type="submit" value="Confirm" />
- <?php endif; ?>
- </p>
- </div>
- <?php endif; ?>
- </form>
- <?php
- $focus=false;
- if ($missing_new_node_title or $bad_new_node_title) {
- $focus='#new_node_title';
- }
- else if ($bad_new_node_number) {
- $focus='#new_node_number';
- }
- else if ($missing_old_node_number or $bad_old_node_number) {
- $focus='#old_node_number';
- }
- else if ($confirm_delete_node) {
- $focus='#old_node_number';
- }
- ?>
- <?php if ($focus): ?>
- <?php head('javascript', 'jquery.scrollTo', 'screen'); ?>
- <script>
- $(function() {$('<?php echo $focus; ?>').focus(); $.scrollTo('<?php echo $focus; ?>', {offset: -200}); });
- </script>
- <?php endif; ?>
- <?php extract($errors); ?>
- <h3<?php if ($thread_title): ?> title="<?php echo $thread_id; ?>"<?php endif; ?>><?php echo htmlspecialchars($thread_title ? $thread_title : $thread_id , ENT_COMPAT, 'UTF-8'); ?></h3>
- <form method="post" class="compact">
- <input name="clang" type="hidden" value="<?php echo $clang; ?>" />
- <p>
- <?php echo $inlanguages; ?>
- </p>
- <p>
- <input class="submit submit_add" id="node_create" name="node_create" type="submit" value="Ajouter" />
- la campagne
- <input id="new_node_title" name="new_node_title" type="text" size="50" maxlength="100" value="<?php echo htmlspecialchars($new_node_title, ENT_COMPAT, 'UTF-8'); ?>" title="Titre" onkeypress="return focusonenter(event, 'new_node_number')"/>
- <span class="nowrap">
- #
- <input id="new_node_number" name="new_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($new_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Numéro" onkeypress="return submitonenter(event, 'node_create')"/>
- </span>
- </p>
- <?php if ($thread_contents): ?>
- <div id="threadcontent">
- <fieldset class="block">
- <legend>Titres</legend>
- <table id="nodelist">
- <tbody>
- <?php
- $i=1;
- $maxlen=strlen(count($thread_contents))+1;
- foreach ($thread_contents as $c) {
- extract($c); /* pos, node_id node_title, node_url, node_number, node_ignored */
- $node_url .= '?' . 'clang=' . $clang;
- ?>
- <tr>
- <td><input name="p[<?php echo $i; ?>]" type="text" size="2" maxlength="<?php echo $maxlen; ?>" value="<?php echo $pos; ?>" /></td>
- <td><a href="<?php echo $node_url; ?>" title="<?php echo $node_id; ?>"><?php echo $node_title ? htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8') : $node_id; ?></a></td>
- </tr>
- <?php
- $i++;
- }
- ?>
- </tbody>
- </table>
- </fieldset>
- <p>
- <input class="submit submit_sort" id="thread_reorder" name="thread_reorder" type="submit" value="Trier" />
- la liste ou
- <input class="submit submit_copy" id="node_copy" name="node_copy" type="submit" value="Copier" />
- ou
- <input class="submit submit_delete" id="node_delete" name="node_delete" type="submit" value="Supprimer" />
- la campagne
- <span class="nowrap">
- #
- <input id="old_node_number" name="old_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($old_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Numéro" onkeypress="return submitonenter(event, 'node_delete')"/>
- </span>
- <?php if ($confirm_delete_node): ?>
- <input class="submit submit_confirm" id="node_confirmdelete" name="node_confirmdelete" type="submit" value="Confirmer" />
- <?php endif; ?>
- </p>
- </div>
- <?php endif; ?>
- </form>
- <?php
- $focus=false;
- if ($missing_new_node_title or $bad_new_node_title) {
- $focus='#new_node_title';
- }
- else if ($bad_new_node_number) {
- $focus='#new_node_number';
- }
- else if ($missing_old_node_number or $bad_old_node_number) {
- $focus='#old_node_number';
- }
- else if ($confirm_delete_node) {
- $focus='#old_node_number';
- }
- ?>
- <?php if ($focus): ?>
- <?php head('javascript', 'jquery.scrollTo', 'screen'); ?>
- <script>
- $(function() {$('<?php echo $focus; ?>').focus(); $.scrollTo('<?php echo $focus; ?>', {offset: -200}); });
- </script>
- <?php endif; ?>
Create the file campaigneditpage.php in the folder actions with the following content:
- require_once 'userhasrole.php';
- require_once 'userprofile.php';
- require_once 'models/thread.inc';
- function campaigneditpage($lang, $clang, $thread, $node) {
- global $with_toolbar, $supported_contents, $limited_contents;
- $user_id=user_profile('id');
- if (!$user_id) {
- return run('error/unauthorized', $lang);
- }
- $thread_id = thread_id($thread);
- if (!$thread_id) {
- return run('error/notfound', $lang);
- }
- $node_id = thread_node_id($thread_id, $node, $clang);
- if (!$node_id) {
- return run('error/notfound', $lang);
- }
- $r = thread_get($clang, $thread_id);
- if (!$r) {
- return run('error/notfound', $lang);
- }
- extract($r); /* thread_user_id thread_type thread_name thread_title thread_abstract thread_cloud */
- if ($thread_type != 'campaign') {
- return run('error/notfound', $lang);
- }
- if ($thread_user_id != $user_id and !user_has_role('administrator')) {
- return run('error/notfound', $lang);
- }
- $content_types=$limited_contents['campaign'];
- $node_editor = build('nodeeditor', $lang, $clang, $node_id, $content_types);
- $node_name=$node_title=false;
- $r = thread_get_node($clang, $thread_id, $node_id);
- if ($r) {
- extract($r); /* node_name node_title */
- }
- head('title', $node_title ? $node_title : $node_id);
- head('description', false);
- head('keywords', false);
- head('robots', 'noindex, nofollow');
- $banner=$toolbar=false;
- $headline_text=translate('campaignsummary:title', $lang);
- $headline_url=url('campaignedit', $lang) . '/' . $thread_id . '?' . 'clang=' . $clang;
- $headline = compact('headline_text', 'headline_url');
- $viewsms=url('campaign', $clang) . '/'. $thread_id . '/' . $node_id;
- $banner = build('banner', $lang, $with_toolbar ? compact('headline') : compact('headline', 'viewsms'));
- $toolbar = $with_toolbar ? build('toolbar', $lang, compact('viewsms')) : false;
- $prev_node_label=$prev_node_url=false;
- $r=thread_node_prev($clang, $thread_id, $node_id);
- if ($r) {
- extract($r);
- $prev_node_label = $prev_node_title ? $prev_node_title : $prev_node_id;
- $prev_node_url=url('campaignedit', $lang) . '/' . $thread_id . '/'. $prev_node_id . '?' . 'clang=' . $clang;
- }
- $next_node_label=$next_node_url=false;
- $r=thread_node_next($clang, $thread_id, $node_id);
- if ($r) {
- extract($r);
- $next_node_label = $next_node_title ? $next_node_title : $next_node_id;
- $next_node_url=url('campaignedit', $lang) . '/' . $thread_id . '/'. $next_node_id . '?' . 'clang=' . $clang;
- }
- $title = view('headline', false, $headline);
- $sidebar = view('sidebar', false, compact('title'));
- $content = view('campaigneditpage', $lang, compact('node_editor', 'node_id', 'node_title', 'prev_node_url', 'prev_node_label', 'next_node_url', 'next_node_label'));
- $output = layout('editing', compact('toolbar', 'banner', 'content', 'sidebar'));
- return $output;
- }
Create the view campaigneditpage in English and in French in the files views/en/campaigneditpage.phtml and views/fr/campaigneditpage.phtml:
- <h3<?php if ($node_title): ?> title="<?php echo $node_id; ?>"<?php endif; ?>><?php echo htmlspecialchars($node_title ? $node_title : $node_id , ENT_COMPAT, 'UTF-8'); ?></h3>
- <?php if ($next_node_url or $prev_node_url): ?>
- <p class="navigation menu">
- <?php if ($prev_node_url): ?>
- <a class="previous" href="<?php echo $prev_node_url; ?>"><span><</span></a>
- <a href="<?php echo $prev_node_url; ?>"><?php echo htmlspecialchars($prev_node_label, ENT_COMPAT, 'UTF-8'); ?></a>
- <?php endif; ?>
- <?php if ($next_node_url and $prev_node_url): ?>
- |
- <?php endif; ?>
- <?php if ($next_node_url): ?>
- <a href="<?php echo $next_node_url; ?>"><?php echo htmlspecialchars($next_node_label, ENT_COMPAT, 'UTF-8'); ?></a>
- <a class="next" href="<?php echo $next_node_url; ?>"><span>></span></a>
- <?php endif; ?>
- </p>
- <?php endif; ?>
- <?php echo $node_editor; ?>
- <h3<?php if ($node_title): ?> title="<?php echo $node_id; ?>"<?php endif; ?>><?php echo htmlspecialchars($node_title ? $node_title : $node_id , ENT_COMPAT, 'UTF-8'); ?></h3>
- <?php if ($next_node_url or $prev_node_url): ?>
- <p class="navigation menu">
- <?php if ($prev_node_url): ?>
- <a class="previous" href="<?php echo $prev_node_url; ?>"><span><</span></a>
- <a href="<?php echo $prev_node_url; ?>"><?php echo htmlspecialchars($prev_node_label, ENT_COMPAT, 'UTF-8'); ?></a>
- <?php endif; ?>
- <?php if ($next_node_url and $prev_node_url): ?>
- |
- <?php endif; ?>
- <?php if ($next_node_url): ?>
- <a href="<?php echo $next_node_url; ?>"><?php echo htmlspecialchars($next_node_label, ENT_COMPAT, 'UTF-8'); ?></a>
- <a class="next" href="<?php echo $next_node_url; ?>"><span>></span></a>
- <?php endif; ?>
- </p>
- <?php endif; ?>
- <?php echo $node_editor; ?>
Create the URL for the action campaignedit in English and in French in the file aliases.inc:
- 'edit/campaign' => 'campaignedit',
- 'edition/campagne' => 'campaignedit',
Edit the file actions/campaignsummary.php:
- global $system_languages, $with_toolbar;
- $slang=false;
- if (isset($_GET['slang'])) {
- $slang = $_GET['slang'];
- }
- else {
- $slang=$lang;
- }
- if (!in_array($slang, $system_languages)) {
- return run('error/notfound', $lang);
- }
- $editsms=url('campaignedit', $slang) . '/'. $campaign_id . '?' . 'clang=' . $lang;
- $banner = build('banner', $lang, $with_toolbar ? compact('headline', 'search') : compact('headline', 'search', 'editsms'));
- $toolbar = $with_toolbar ? build('toolbar', $lang, compact('editsms')) : false;
Edit the file actions/campaignpage.php:
- global $system_languages, $with_toolbar;
- $slang=false;
- if (isset($_GET['slang'])) {
- $slang = $_GET['slang'];
- }
- else {
- $slang=$lang;
- }
- if (!in_array($slang, $system_languages)) {
- return run('error/notfound', $lang);
- }
- $banner = build('banner', $lang, $with_toolbar ? compact('headline', 'search') : compact('headline', 'search', 'editsms'));
- $toolbar = $with_toolbar ? build('toolbar', $lang, compact('editsms')) : false;
Edit the file blocks/banner.php:
- $is_client = user_has_role('client');
- case 'editsms':
- if ($param) {
- if ($is_client or $is_admin) {
- $edit_page=$param;
- }
- }
- break;
- case 'viewsms':
- if ($param) {
- if ($is_client or $is_admin) {
- $view_page=$param;
- }
- }
- break;
Edit the file blocks/toolbar.php:
- $is_client = user_has_role('client');
- case 'editsms':
- if ($param) {
- if ($is_client or $is_admin) {
- $edit_page=$param;
- }
- }
- break;
- case 'viewsms':
- if ($param) {
- if ($is_client or $is_admin) {
- $view_page=$param;
- }
- }
- break;
Test
Connect
as a client, e.g. barfoo.
Click on the large phone
to display the list of campaigns.
BarFoo
Click on the keyboard
to switch to editing mode.
BarFoo
campaign #
list or or campaign #
Git
- /izendsms.com
- actions
- campaignedit.php
- campaigneditpage.php
- campaigneditsummary.php
- campaignpage.php
- campaignsummary.php
- blocks
- banner.php
- toolbar.php
- includes
- aliases.inc
- views
- en
- campaigneditpage.phtml
- campaigneditsummary.phtml
- fr
- campaigneditpage.phtml
- campaigneditsummary.phtml
- en
- actions
Commit this version:
$ git status
$ git add actions blocks/toolbar.php views includes
$ git commit -m'Adds editing campaigns'
Comments