<!-- 
/*
Copyright 2017 apHarmony

This file is part of jsHarmony.

jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this package.  If not, see <http://www.gnu.org/licenses/>.
*/
-->
<script type="text/x-tutorial-info">
{
  "ID": "model_buttons",
  "Title": "Model Buttons",
  "Menu": ["Models","Models Overview"],
  "Code": [
    "/models/ModelButtons_Cust_Listing.json",
    "/models/ModelButtons_Cust.json",
    "/models/ModelButtons_Cust_Listing_Grouped.json",
    "/models/ModelButtons_Cust_Listing_JavaScript.json",
    "/models/ModelButtons_Icons.json",
    "/models/ModelButtons_Icons.onroute.js"
  ],
  "Demo": [
    { "url": "jsHarmonyTutorials/ModelButtons_Cust_Listing", "title": "Grid Buttons" },
    { "url": "jsHarmonyTutorials/ModelButtons_Cust?action=update&cust_id=2", "title": "Form Buttons" },
    { "url": "jsHarmonyTutorials/ModelButtons_Cust_Listing_Grouped", "title": "Buttons w/ Drop-down Groups" },
    { "url": "jsHarmonyTutorials/ModelButtons_Cust_Listing_JavaScript", "title": "JavaScript Button Links" },
    { "url": "jsHarmonyTutorials/ModelButtons_Icons", "title": "Icon Listing" }
  ]
}
</script>

<h3>Buttons Overview</h3>
Buttons are displayed in the top-right of each model.  
<%-getScreenshot('jsHarmonyTutorials/ModelButtons_Cust_Listing?popup=1','Model Buttons')%>

Custom buttons can be added to the button toolbar by adding to the model.buttons array:
<pre>
{
  "buttons":[
    {"link":"insert:Cust"}
  ],
}
</pre>

<h3>Button Text, Icon, and Style</h3>
Buttons have a variety of properties for configuring text, icon, and style:
<pre>
{
  "buttons":[
    {
      "name":"insertCust",
      "link":"insert:Cust",
      "text":"Add %%%CAPTION%%%",
      "icon":"insert",
      "style":"border:2px solid black;",
      "class":"Cust_Listing_buttonInsertC",
      "nl":true
    }
  ],
}
</pre>
<div style="padding-bottom:15px;">
  <b>button.name</b><br/>
  The name of the button.  Every button name should be unique.  Button names are optional, but recommended.  Names are required when modifying buttons in inheriting models.
</div>
<div style="padding-bottom:15px;">
  <b>button.text</b><br/>
  The text attribute modifies the text to the right of the button.  The keyword %%%CAPTION%%% will insert the model caption into the button text.  Setting the text to blank will display only the icon.
</div>
<div style="padding-bottom:15px;">
  <b>button.icon</b><br/>
  The icon attribute changes the button icon.  Set the icon to "none" to hide the icon and display only text.<br/>
  <br/>
  Icon images are loaded via "/images/icon_ICONNAME.png".  For instance, the "insert" icon can be overwritten by uploading a new image to "public/images/icon_insert.png" in the Application root.<br/>
  <br/>
  The following built-in icons are available in jsHarmony:
  <%-getScreenshot('jsHarmonyTutorials/ModelButtons_Icons?popup=1','Model Buttons')%>
</div>
<div style="padding-bottom:15px;">
  <b>button.style</b><br/>
  The style attribute enables adding custom CSS to the "A" button element
</div>
<div style="padding-bottom:15px;">
  <b>button.class</b><br/>
  The class attribute enables adding custom CSS class to the "A" button element
</div>
<div>
  <b>button.nl</b> &nbsp; (line break)<br/>
  The nl attribute adds a new line before the start of the button.  This can be useful for organizing multiple buttons into rows.
</div>

<h3>Default Button Styles</h3>
Button styles are automatically applied to any button links beginning with "insert:", "browse:", or "update:".  The default button styles can be modified in app.config.js.
<pre>
config.default_buttons = <%=JSON.stringify((req?req.getJSH().Config.default_buttons:null),null,4)%>
</pre>

<h3>Button Groups</h3>
Button Groups combine buttons into a drop-down menu.
<%-getScreenshot('jsHarmonyTutorials/ModelButtons_Cust_Listing_Grouped?popup=1','Model Buttons',{ onload:function(){     return new Promise(function(resolve){
  jshInstance.$('.xelemModelButtons_Cust_Listing_Grouped.xactions_dropdown').click()
  return resolve();
}); } })%>
Button groups can be defined via the "group" attribute, that specifies the name of the drop-down menu:
<pre>
{
  "buttons":[
    {"group":"Actions","link":"insert:ModelButtons_Cust","icon":"insert"},
    {"group":"Actions","link":"ModelButtons_Cust_Listing","icon":"search","text":"View Customers"}
  ]
}
</pre>

<h3>Link / Bindings</h3>
The "link" attribute sets the button's action and target model.  Links have the following syntax:
<pre>
insert:MODELID&amp;[i]parameter[/i]
browse:MODELID&amp;[i]parameter[/i]
update:MODELID&amp;[i]parameter[/i]
savenew:MODELID&amp;[i]parameter[/i]

[i]parameter[/i] :=
  tabs={\"PARENT_MODEL\":\"SELECTED_TAB_MODEL\"}
</pre>
The parameter is currently only used to set tabs on the button link.<br/>
<br/>
Each of the three actions generate a different URL:
<ul>
  <li>
    <b>insert:</b><br/>
    Opens a form for adding new data<br/>
    /MODELID?action=insert
  </li>
  <li>
    <b>browse:</b><br/>
    Opens a form for read-only viewing data, or viewing a grid<br/>
    /MODELID?action=browse
  </li>
  <li>
    <b>update:</b><br/>
    Opens a form for updating data, or viewing a grid<br/>
    /MODELID?action=update
  </li>
  <li>
    <b>savenew:</b><br/>
    Saves the data first, and on success, opens a form for adding new data<br/>
    /MODELID?action=insert
  </li>
</ul>

Bindings define the querystring parameters that will be passed in the button link.  Bindings are evaluated client-side on load, and are defined as follows:
<pre>
{
  "CHILD_FIELD1": "PARENT_FIELD", //Data bindings
  "CHILD_FIELD2": "'CONSTANT'"    //Character string bindings
}
</pre>
In the example above, assuming that the value of PARENT_FIELD was "5", the bindings would generate the following URL:
<pre>
/MODELID?action=update&CHILD_FIELD1=5&CHILD_FIELD2=CONSTANT
</pre>

If bindings are not defined, the system will automatically try to generate them.  The algorithm for automatic bindings can be found in the <a href="/tutorials/model_bindings#automatic_bindings">Automatic Bindings</a> tutorial<br/>
<br/>
More information about bindings can be found in the <a href="/tutorials/model_bindings">Model Bindings</a> tutorials.

<h4>Link Querystring Generation</h4>

The model id and action parameter are generated based on the link target above.  Next:
<ol>
  <li>If the link target model is the same as the current model, all querystring parameters will be copied to the link.</li>
  <li>If tabs are defined in the "link" attribute, they are added to the querystring</li>
  <li>Bindings are then added to the querystring, and evaluated client-side on load</li>
</ol>

<h4>Examples</h4>
<pre>
{
  "buttons":[
    {
      "link": "update:Cust_Container",
      "bindings": { "cust_id": "cust_id_billto" }
    }
  ]
}
//When cust_id_billto is "5" on the parent form
URL: /Cust_Container?action=update&cust_id=5

{
  "buttons":[
    {
      "link": "update:EW",
      "bindings": { "item_id": "item_id" }
    }
  ]
}
//When item_id is "3" on the parent form
URL: /Item?action=update&item_id=3

{
  "buttons":[
    {
      "link": "update:Cust_Container&tabs={\"Cust_Container\":\"Cust_Contact_Listing\"}",
      "bindings": { "cust_id": "cust_id" }
    }
  ]
}
//When cust_id is "1" on the parent form
URL: /Cust_Listing?action=update&cust_id=1tabs={"Cust_Container":"Cust_Contact_Listing"}
</pre>

<h3>JavaScript</h3>
Buttons can run JavaScript by prefixing the link attribute with "js:"<br/>
The following variables are added to the JavaScript namespace:
<ul>
  <li><b>modelid</b>: The model id of the form where the button is located</li>
</ul>
<pre>
{
  "buttons":[
    {
      "link": "js:XExt.Alert('The current model is '+modelid);",
      "text": "Current Model ID"
    }
  ]
}
</pre>
The following are common JavaScript functions used in buttons:

<h4>XExt.navTo(url)</h4>
<pre>
Redirects to a target URL
@param string url : The target URL
@return false

Example: XExt.navTo('/Cust_Container?cust_id=4')
</pre>

<h4>XExt.popupForm(modelid, action, params, windowparams, win)</h4>
<pre>
Opens a model in a popup window
@param string modelid      : The target model id
@param string action       : The model action, must be "insert", "update", or "browse"
@param object params       : Querystring parameters for the popup, ex. { "cust_id": 4 }
@param object windowparams : Parameters passed to window.open
                             Default: { width: 1000, height: 600, resizable: 1, scrollbars: 1 }
@param window win          : (Optional) Target window for the redirect.
                             If passed as a parameter, no new window is created.
                             The win parameter is useful to avoid popup blockers,
                             when the window needs to be created before running an AJAX request.
@return window             : The resulting popup window object

Note: If the window width and height is not specified, it will default to:
        1. The model.popup size if available
        2. 1000 x 600

Example: XExt.popupForm('Cust_Container','update',{'cust_id':XModels[modelid].controller.form.Data.cust_id()},{width:850,height:600});
</pre>

<h4>XExt.popupReport (modelid, params, windowparams, win)</h4>
<pre>
Opens a report PDF in a popup window
@param string modelid      : The target report model id
@param object params       : Querystring parameters for the report, ex. { "cust_id": 4 }
@param object windowparams : Parameters passed to window.open
                             Default: { width: 1000, height: 600, resizable: 1, scrollbars: 1 }
@param window win          : (Optional) Target window for the redirect.
                             If passed as a parameter, no new window is created.
                             The win parameter is useful to avoid popup blockers,
                             when the window needs to be created before running an AJAX request.
@return window             : The resulting popup window object

Note: If the window width and height is not specified, it will default to:
        1. The model.popup size if available
        2. 1000 x 600

Example: XExt.popupReport('jsHarmonyFactory/Reports/SysUser_Listing',{ 'sys_user_sts': 'ACTIVE' },{width:850,height:600});
</pre>

<h3>Hiding Buttons via Actions / Security / Roles</h3>
Buttons can be restricted to be hidden based on the current action, or based on the current user's roles.
<pre>
{
  "buttons":[
    {
      "link":"update:Cust_Container",
      "actions":"BIU",
      "roles": {
        "main":{"DADMIN":"*"},
        "client": {"CSYSADMIN":"I"}
      }
    }
  ],
}
</pre>

<ul>
  <li>If the querystring action is set to "insert", only buttons with the "B" or "I" actions will be shown.</li>
  <li>If the querystring action is set to "update", only buttons with the "B" or "U" actions will be shown.</li>
  <li>If the querystring action is set to "browse", only buttons with the "B" actions will be shown.</li>
  <li>Otherwise, only buttons with the "B" action will be shown.</li>
</ul>

<h4>Roles</h4>
Roles can be used to further limit button access.  When roles are defined, they are cross-applied with the "actions".<br/>
Users without role access will not see the button.  Users with DEV or SYSADMIN access have access to all buttons.

<h4>Hiding Based on the Link Target (hide_when_target_inaccessible)</h4>
By default, buttons with links starting with "insert:" will be hidden if the user does not have "I" access to the link target.  Disable this functionality by setting hide_when_target_inaccessible to false:
<pre>
{
  "buttons":[
    "link":"insert:Cust",
    "hide_when_target_inaccessible": false
  ]
}
</pre>

<h3>Hiding System Buttons</h3>
All models have built-in buttons, based on the model layout.  The built-in system buttons can be hidden via the model.hide_system_buttons property:
<pre>
{

  "hide_system_buttons": ["export","search","print","insert"]
}
</pre>
The following system buttons can be hidden, depending on the model layout:

<h4>Grid</h4>
<ul>
  <li><b>clear</b> <i>(Displayed in inline popups, such as Popup LOV and Duplicate)</i></li>
  <li><b>search</b></li>
  <li><b>print</b></li>
  <li><b>export</b> <i>(Automatically hidden in Popup LOV and Duplicate)</i></li>
  <li><b>insert</b></li>
  <li><b>help</b></li>
</ul>

<h4>Form, Form-m, Exec, and Multisel</h4>
<ul>
  <li><b>print</b></li>
  <li><b>help</b></li>
</ul>
