CRM-20034 - Expose OR grouping to api explorer
authorColeman Watts <coleman@civicrm.org>
Thu, 16 Feb 2017 03:33:03 +0000 (22:33 -0500)
committerColeman Watts <coleman@civicrm.org>
Thu, 16 Feb 2017 04:01:09 +0000 (23:01 -0500)
templates/CRM/Admin/Page/APIExplorer.js
templates/CRM/Admin/Page/APIExplorer.tpl

index 3bca15f509650d2449ba684b479ac2bc20904598..9ce648292072ba7008f98b3655316bff574818ec 100644 (file)
@@ -20,8 +20,7 @@
     docCodeTpl = _.template($('#doc-code-tpl').html()),
     joinTpl = _.template($('#join-tpl').html()),
 
-    // The following apis do not support the syntax for joins
-    // FIXME: the solution is to convert these apis to use _civicrm_api3_basic_get
+    // The following apis do not use Api3SelectQuery so do not support advanced features like joins or OR
     NO_JOINS = ['Contact', 'Contribution', 'Pledge', 'Participant'],
 
     // These types of entityRef don't require any input to open
       }
     });
     if (entity && action) {
+      handleAndOr();
       formatQuery();
     }
   }
    */
   function renderJoinSelector() {
     $('#api-join').hide();
-    if (!_.includes(NO_JOINS, entity) && _.includes(['get', 'getsingle'], action)) {
+    if (!_.includes(NO_JOINS, entity) && _.includes(['get', 'getsingle', 'getcount'], action)) {
       var joinable = {};
       (function recurse(fields, joinable, prefix, depth, entities) {
         _.each(fields, function(field) {
     }
   }
 
+  function handleAndOr() {
+    if (!_.includes(NO_JOINS, entity) && _.includes(['get', 'getsingle', 'getcount'], action)) {
+      var or = [];
+      $('tr.api-param-row').each(function() {
+        if ($(this).next().is('tr.api-param-row') && $('input.api-param-name', this).val()) {
+          $('.api-and-or', this).show();
+        } else {
+          $(this).removeClass('or').find('.api-and-or').hide();
+        }
+      });
+      $('tr.api-param-row.or').each(function() {
+        var val = $(this).next().find('input.api-param-name').val();
+        if (val) {
+          if ($(this).prev().is('.or')) {
+            or[or.length - 1].push(val);
+          } else {
+            or.push([$('input.api-param-name', this).val(), val]);
+          }
+        }
+      });
+      if (or.length) {
+        params.options = params.options || {};
+        params.options.or = or;
+      }
+    } else {
+      $('.api-and-or').hide();
+    }
+  }
+
+  function toggleAndOr() {
+    $(this).closest('tr').toggleClass('or');
+    buildParams();
+  }
+
   $(document).ready(function() {
     // Set up tabs - bind active tab to document hash because... it's cool?
     document.location.hash = document.location.hash || 'explorer';
         $(this).closest('tr').remove();
         buildParams();
       })
-      .on('change', 'select.api-chain-entity', getChainedAction);
+      .on('click', '.api-and-or > span', toggleAndOr)
+      .on('change', 'select.api-chain-entity', getChainedAction)
+      .on('sortupdate', buildParams)
+      .sortable({
+        handle: '.api-sort-handle',
+        items: '.api-chain-row, .api-param-row'
+      });
     $('#api-join').on('change', 'input', onSelectJoin);
     $('#example-entity').on('change', getExamples);
     $('#example-action').on('change', getExample);
index fea4a10bcd9224eec877e9a6711bf5535f27f2cc..df992f8827a6b72cc8f3b1a84661e2201e8f664f 100644 (file)
@@ -50,6 +50,9 @@
     margin-top: 1em;
     overflow: auto;
   }
+  #api-params tr td {
+    padding-top: 13px;
+  }
   #api-params-table th:first-child,
   #api-params-table td:first-child {
     width: 35%;
   #api-params-table th:first-child + th + th {
     width: 65%
   }
+  #api-params .api-sort-handle {
+    margin-right: 10px;
+    cursor: move;
+  }
+  #api-params tr td > .crm-i,
+  #api-params tr td > a .crm-i {
+    color: lightgrey;
+  }
+  #api-params tr:hover td > .crm-i,
+  #api-params tr:hover td > a .crm-i {
+    color: grey;
+  }
+  #api-params .api-and-or {
+    margin-left: 1.2em;
+    font-size: .8em;
+    position: relative;
+    top: 5px;
+    width: 10em;
+    margin-bottom: -9px;
+  }
+  #api-params .api-and-or > span {
+    padding: 0 1em;
+    background: white;
+    cursor: pointer;
+  }
+  #api-params .api-or,
+  #api-params tr.or .api-and {
+    color: lightgrey;
+  }
+  #api-params tr.or .api-or {
+    color: inherit;
+  }
+  #api-params .api-and-or .crm-i {
+    transform: rotate(180deg);
+  }
+  #api-params tr.or .api-and-or .crm-i {
+    transform: initial;
+  }
+  #api-params .api-and-or:hover .crm-i {
+    color: #2786c2;
+  }
+  #api-params tr.or {
+    border-top: 3px solid lightgrey;
+    border-left: 3px solid lightgrey;
+    border-right: 3px solid lightgrey;
+  }
+  #api-params tr.or + tr {
+    border-left: 3px solid lightgrey;
+    border-right: 3px solid lightgrey;
+    border-bottom: 3px solid lightgrey;
+  }
+  #api-params tr.or + tr.or {
+    border-top: none;
+    border-bottom: none;
+  }
   #api-generated td:first-child {
     width: 60px;
   }
 {strip}
 <script type="text/template" id="api-param-tpl">
   <tr class="api-param-row">
-    <td><input style="width: 100%;" class="crm-form-text api-param-name api-input" value="<%= name %>" placeholder="{ts}Parameter{/ts}" /></td>
+    <td>
+      <i class="crm-i api-sort-handle fa-arrows"></i>
+      <input style="width: 90%;" class="crm-form-text api-param-name api-input" value="<%= name %>" placeholder="{ts}Parameter{/ts}" />
+      <div class="api-and-or"><span><span class="api-and">{ts}AND{/ts}</span> <i class="crm-i fa-toggle-on"></i> <span class="api-or">{ts}OR{/ts}</span></span></div>
+    </td>
     <td>
       {literal}
       <% if (noOps) { %>
 <script type="text/template" id="api-chain-tpl">
   <tr class="api-chain-row">
     <td>
-      <select style="width: 100%;" class="crm-form-select api-chain-entity">
+      <i class="crm-i api-sort-handle fa-arrows"></i>
+      <select style="width: 90%;" class="crm-form-select api-chain-entity">
         <option value=""></option>
         {foreach from=$entities.values item=entity}
           <option value="{$entity}" {if !empty($entities.deprecated) && in_array($entity, $entities.deprecated)}class="strikethrough"{/if}>