tag:blogger.com,1999:blog-2677139025720110032024-03-13T07:24:01.581-04:00Maxime Tremblay's BlogMaxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-267713902572011003.post-42549313505339532392018-08-20T15:21:00.002-04:002020-03-17T16:19:15.324-04:00Include or Exclude Columns in an Interactive Report Export<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/08/20/include-or-exclude-columns-in';
</script>
<div class="separator" style="clear: both; display: none; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTVjcAJRv0i1_RFPtoHw1dELehi6z1C6bZWtgMbt-eZBKRLRneCHz3k_wgfH0s5X6n19fOzZUMAAW-rLsJW94LWrB8Ed_2c2pzyd-zpRiFthtRy-7P5kNYsHmfVPdcOQeuukRyeRl-DM/s1600/IR_download.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="588" data-original-width="774" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTVjcAJRv0i1_RFPtoHw1dELehi6z1C6bZWtgMbt-eZBKRLRneCHz3k_wgfH0s5X6n19fOzZUMAAW-rLsJW94LWrB8Ed_2c2pzyd-zpRiFthtRy-7P5kNYsHmfVPdcOQeuukRyeRl-DM/s320/IR_download.png" width="320" /></a></div>
You might have noticed that for the Classic Reports and the Interactive Grids there's an option to include or exclude a column in the report's export.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAtkYeU4vxx-K_4AsTW-KTAgDhnS8FOYB5eaeiWOJGS5puM5RieFto0UgdYGZNaUlGjQhgYoTCgadmuImL4AXCRaUspQ06U-TFFjDMso2BSfC3xRnipdx5d-Zqk7tZc0fmjaa_vvD8O9c/s1600/include_in_export.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="181" data-original-width="672" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAtkYeU4vxx-K_4AsTW-KTAgDhnS8FOYB5eaeiWOJGS5puM5RieFto0UgdYGZNaUlGjQhgYoTCgadmuImL4AXCRaUspQ06U-TFFjDMso2BSfC3xRnipdx5d-Zqk7tZc0fmjaa_vvD8O9c/s320/include_in_export.png" width="320" /></a></div>
<br />
Unfortunately, that option is not available for the Interactive Reports.<br />
<br />
In order to export a report, APEX submits the page using a request that is then used to generate the corresponding file. This can be verified by having a look at the network tab in DevTools:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL-7wA6ZieWaGCL_MKbxwv4wYOiHb3nfgnUx5teO438c55cgHg7pxJ3BdOudxk6C1ZYXie67GmMmbW_zb-Nuct1cTOLSNYdXIvooPowtiW0qN8dzbPMa6U5ToaEfE5ohmGQbLFs69w7Sk/s1600/IR_request.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="705" data-original-width="1600" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL-7wA6ZieWaGCL_MKbxwv4wYOiHb3nfgnUx5teO438c55cgHg7pxJ3BdOudxk6C1ZYXie67GmMmbW_zb-Nuct1cTOLSNYdXIvooPowtiW0qN8dzbPMa6U5ToaEfE5ohmGQbLFs69w7Sk/s400/IR_request.png" width="400" /></a></div>
<br />
As we can see, a request is used to export the report, except for the Email option.<br />
<br />
If we look at the request's details for the Email export:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNFSynJmdbGYqgD97b2nEtCoo5cerG1mR-U106vbnpQeRkWj7LoTuUPKv2tHKXa_2VsgxpVsfKim7eIMZqQ9yrKpADKO81s0RE7mR6bBImSI5x1vloU0lmbraisgVA0c4wP7v0H2RaXJg/s1600/IR_request_email.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1279" data-original-width="1600" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNFSynJmdbGYqgD97b2nEtCoo5cerG1mR-U106vbnpQeRkWj7LoTuUPKv2tHKXa_2VsgxpVsfKim7eIMZqQ9yrKpADKO81s0RE7mR6bBImSI5x1vloU0lmbraisgVA0c4wP7v0H2RaXJg/s400/IR_request_email.png" width="400" /></a></div>
<br />
We can see that it's making an AJAX call and that it sets the <i>p_widget_action</i> to "SEND_EMAIL" which is saved in the wwv_flow package as g_widget_action.<br />
<br />
Using the above, we can remove a column from the export by adding a server-side condition that checks the request and the widget action as follow:<br />
<br />
<pre class="line-numbers"><code class="language-sql">nvl(:request, 'EMPTY') not in ('CSV','XLS','PDF','RTF','HTMLD')
and nvl(wwv_flow.g_widget_action, 'EMPTY') <> 'SEND_EMAIL'</code></pre>
<br />
That condition will work if there is only one interactive report on the page. If there is more than one report, the requests will be different.<br />
<br />
As we can see here:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNisJTwK4-_5kW-zIL8EeyMYCvoFZoqFPbwIjGnw3C3kIMSPLJ_v87pNn2PGsoJoHaJ4aOdpGZQoPwdi39uM9AAJnniliB1kjU-D9cysMJG8Nj2oMsVNUbYEDTrDhJ9GGdf-F9yWbpOmk/s1600/IR_request_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="863" data-original-width="1600" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNisJTwK4-_5kW-zIL8EeyMYCvoFZoqFPbwIjGnw3C3kIMSPLJ_v87pNn2PGsoJoHaJ4aOdpGZQoPwdi39uM9AAJnniliB1kjU-D9cysMJG8Nj2oMsVNUbYEDTrDhJ9GGdf-F9yWbpOmk/s400/IR_request_2.png" width="400" /></a></div>
<br />
The requests are going to be using this pattern:<br />
<pre><code class="language-none">IR[R<region id>]_<export type></code></pre>
<br />
If we take that into consideration and include it into the previous condition, we will have this:<br />
<br />
<pre class="line-numbers"><code class="language-sql">nvl(substr(:request, instr(:request, '_', -1) + 1), 'EMPTY') not in ('CSV','XLS','PDF','RTF','HTMLD')
and nvl(wwv_flow.g_widget_action, 'EMPTY') <> 'SEND_EMAIL'</code></pre>
<br />
In order to centralize the condition and avoid code being duplicated/replicated everywhere that we need to use this, it's best to create an authorization schema that we can use instead of using the server-side condition. <br />
<br />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-5323943750654403242018-05-18T07:46:00.000-04:002020-03-17T16:19:42.646-04:00Lazy Loading Report<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/05/18/lazy-loading-report';
</script>
I was recently asked to have a look at an APEX page that took some time to load. That particular page was accessed using the navigation menu. Since the load time was longer than usual, users were often clicking multiple times on it while waiting.<br />
<br />
As usual, I turned debug mode on and had a look at the result. It turned out to be the underlying query of the page's report that was slow.<br />
<br />
We were able to fine-tune the query to make everything load faster. But it still took a couple of seconds to render.<br />
<br />
What I did was to make the report lazy load the data, similar to what the Interactive Grid can do.<br />
<br />
The idea is the following<br />
<ol>
<li>Create a hidden item on the page</li>
<li>Create a computation using the "After Regions" point to set the item to 'Y'</li>
<li>In the report, add a where clause that checks if the item's value is equal to 'Y'</li>
<li>Create a dynamic action on page load that refreshes the report</li>
</ol>
What this is doing is that when the report is being rendered for the first time, the calculation has not been executed and the item is still null so that the report will show nothing.<br />
Then, the calculation will be executed and the dynamic actions will refresh the report showing the expected results.<br />
<br />
Don't get me wrong here, the overall process is still going to take the exact same time.<br />
If the page is taking 10 seconds to load, it will still take 10 seconds for the page to fully load.<br />
But, the user experience is going to be a lot better because now the page will load instantaneously, then the report will take some time to load while displaying the processing icon.<br />
<br />
Here's what the query would look like<br />
<pre class="line-numbers"><code class="language-sql">select /* your columns */
from /* your tables */
where 1 = 1
and nvl(:P1_IS_LOADED, 'N') = 'Y'
</code></pre>
<br />
If you also need to be able to download the report, you'll need to add another condition so that it can work:<br />
<pre class="line-numbers"><code class="language-sql">select /* your columns */
from /* your tables */
where 1 = 1
and ( /* Standard Page Load */
nvl(:P1_IS_LOADED, 'N') = 'Y'
/* Report Download */
or substr(:request, instr(:request, '_', -1) + 1) in ('CSV','XLS','PDF','RTF','HTMLD')
/* Report Email */
or wwv_flow.g_widget_action = 'SEND_EMAIL'
)
</code></pre>
<br />
For more information about the above condition, you can have a look <a href="https://max-tremblay.blogspot.com/2018/08/include-or-exclude-columns-in.html" target="_blank">here</a>.
<br />
<br />
Here's what the end result looks like compared to the standard behaviour:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg18FWbxTvEBvFY1TaoNJXmrZolGkB3ysaObCv7u7eAK8or-y52JVFGTsKJDhF3COf0xY_zgTPqBRDg5yjqWGWdU8oS73ZVpSn14rCD2NaDsrTcBD0eZOgfyjlfd_3hbwWIHWNRYnpZ5g8/s1600/Lazy+Load+Report.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="355" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg18FWbxTvEBvFY1TaoNJXmrZolGkB3ysaObCv7u7eAK8or-y52JVFGTsKJDhF3COf0xY_zgTPqBRDg5yjqWGWdU8oS73ZVpSn14rCD2NaDsrTcBD0eZOgfyjlfd_3hbwWIHWNRYnpZ5g8/s320/Lazy+Load+Report.gif" width="570" /></a></div>
<br />
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:3500" target="_blank">Demo Application</a><br />
<br />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com9tag:blogger.com,1999:blog-267713902572011003.post-47761110719191830852018-03-02T21:57:00.000-05:002020-03-17T16:19:58.249-04:00APEX 5.2 Page Designer Style for APEX 5.1<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/03/02/apex-52-page-designer-style-for-apex-51';
</script>
Have you been playing, trying and testing stuff on the Early Adapter of APEX 5.2.<br />
If you haven't, it's still available (as of writing this) for you to try at <a href="https://apexea.oracle.com/" target="_blank">apexea.oracle.com</a>.<br />
<br />
If you have, you probably noticed that the user interface of the page designer was refined and is looking better than ever.<br />
<br />
APEX 5.2 Page Designer:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNiWQh9LDsVO3_B69NJhmxNahPAKEfZZsBC7OAh43vAmC2xfJauRp8WOCOIdVmCapaMDXaOZWNHEf9GmHqx_OGxSkjFu-mt4Vo2I945jau2yD0X1kR6r9D3Fu2mVeNbxmPUByJKUzLPLw/s1600/APEX5.2EA1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNiWQh9LDsVO3_B69NJhmxNahPAKEfZZsBC7OAh43vAmC2xfJauRp8WOCOIdVmCapaMDXaOZWNHEf9GmHqx_OGxSkjFu-mt4Vo2I945jau2yD0X1kR6r9D3Fu2mVeNbxmPUByJKUzLPLw/s640/APEX5.2EA1.png" width="570" /></a></div>
<br />
APEX 5.1 Page Designer:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg0kjwpWP4SmGkf4019q_LjxqYAosWh16R9U-bjjgTKT1Yqt7HRAJFoEbwyDIhokI8Y8SYRQ7CL7RUPC5zy4rpG5ePz1YRC1-afIhOzzMpX3oz5NXeHFo0ZECyv0kVDVzppaXod0zyfD8/s1600/APEX5.1-Standard.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg0kjwpWP4SmGkf4019q_LjxqYAosWh16R9U-bjjgTKT1Yqt7HRAJFoEbwyDIhokI8Y8SYRQ7CL7RUPC5zy4rpG5ePz1YRC1-afIhOzzMpX3oz5NXeHFo0ZECyv0kVDVzppaXod0zyfD8/s640/APEX5.1-Standard.png" width="570" /></a></div>
<br />
<br />
After a while, you'll get use to the new look of the page designer and going back to 5.1 might feel weird.<br />
<br />
Wouldn't it be nice if we could have the same look and feel on APEX 5.1.<br />
<br />
We can actually achieve that and it's not that difficult.<br />
<br />
The following is relying on CSS only, no JavaScript required. So there's no risk of breaking the page designer or any of its functionalities.<br />
<br />
So how can we do it?<br />
<br />
There's a super useful extension I used: <a href="https://userstyles.org/" target="_blank">Stylish</a><br />
It's available on <a href="https://chrome.google.com/webstore/detail/.../fjnbnpbmkenffdnngjfgmeleoegfcffe" target="_blank">Chrome</a>, <a href="https://addons.mozilla.org/en-US/firefox/addon/stylish/" target="_blank">Firefox</a> and <a href="https://addons.opera.com/en/extensions/details/stylish/" target="_blank">Opera</a>.<br />
<br />
What it does is inject CSS for whatever website your tell it to.<br />
<br />
How to set everything up:<br />
<u>Step 1.</u> Install the extension<br />
<br />
<u>Step 2.</u> Create a new style<br />
<br />
<u>Step 3.</u> Copy and paste the following code<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-css"><code>/*-------------------------------------
* APEX 18.1 Page Designer Style for APEX 5.1
* Version: 1.1 (2018-03-16)
* Author: Maxime Tremblay
*
* https://max-tremblay.blogspot.ca/2018/03/apex-52-page-designer-style-for-apex-51.html
*
* To be used with the Stylish Addon: https://userstyles.org/
* - Chrome: https://chrome.google.com/webstore/detail/stylish-custom-themes-for/fjnbnpbmkenffdnngjfgmeleoegfcffe
* - Firefox: https://addons.mozilla.org/en-US/firefox/addon/stylish/
* - Opera: https://addons.opera.com/en-gb/extensions/details/stylish/
*
* Use with regexp URL: https?://(?:(?!apexea.oracle.com).)*f\?p=4000:4500.*
* or any other URL you wish
*
* Using Gist: https://gist.github.com/maxime-tremblay/59c46c9f441801b6de0c88f72d0d63d9
* Served using: https://rawgit.com/
*
*-------------------------------------
*/
/* You can use the rawgit URL or copy everything from the Gist */
@import url('https://rawgit.com/maxime-tremblay/59c46c9f441801b6de0c88f72d0d63d9/raw/aa9877dad692317aa676b63911b6366631ee772d/APEX18.1-Page_Designer_for_APEX5.1.css');
</code></pre>
</blockquote>
<br />
<u>Step 4.</u> Define what website it should be applied to.<br />
<br />
<section class="language-markup">Since I'm working with APEX 5.1 everywhere, I'm using the regular expression <code>https?://(?:(?!apexea.oracle.com).)*f\?p=4000:4500.*</code> to apply it everywhere except apexea.oracle.com.</section><br />
<br />
Here's the end result:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1S_P4jmZXoq1DVL6OqE-qwlWkn4eoge23h3DME1lRv4YajdhBjYJ3cxuhuvXJ2DSOYfa8NrvSHZhRJSEwTv_ITnt9dpbs1J-C8oUX0_W1WPKLAlpKo_W9IHrGSTcSZazdEMXbspPAKIE/s1600/APEX5.1-Custom.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1S_P4jmZXoq1DVL6OqE-qwlWkn4eoge23h3DME1lRv4YajdhBjYJ3cxuhuvXJ2DSOYfa8NrvSHZhRJSEwTv_ITnt9dpbs1J-C8oUX0_W1WPKLAlpKo_W9IHrGSTcSZazdEMXbspPAKIE/s640/APEX5.1-Custom.png" width="570" /></a></div>
<br />
Of course not everything is the exact same. Everything that relies on new CSS classes or anything new will obviously not be replicated.<br />
<br />
Here's a list of small differences<br />
<ul>
<li>Never element are not strikethrough</li>
<li>Elements with unsaved changes don't have the left border highlight</li>
<li>The property editor header is looking differently (buttons removed in 5.2 and search filter moved).</li>
</ul>
<br />
I've been using this for a couple of weeks now and I have to say that I really love it.<br />
<br />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0tag:blogger.com,1999:blog-267713902572011003.post-74776505608356835542018-03-01T09:07:00.000-05:002020-03-17T16:20:09.071-04:00Datepicker Customization<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/03/01/datepicker-customization';
</script>
<div class="separator" style="clear: both; display: none; text-align: center;">
<img border="0" data-original-height="652" data-original-width="759" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy_yl-7PN2vY4jrQLiWx0n_GGuI-GmMC7vgQ6GhnaLYA1soxUz-SWKPUxL48bQd28FM8vS5Yw02Wov73GlHCA8EyDCudtl120_9keT_KQJ9op_jyysxkXCOmGWyvdGpHEbXQ5i_bVOPQ0/s320/Datepicker.png" width="320" /></div>
Back in 2010, the Oracle Application Express release 4.0 included the jQuery JavaScript library as well as the jQuery UI JavaScript library. With it came the new revision of the datepicker item based on the jQuery UI's widget as we have it today. Most of the widget's options are available to us as item attributes.<br />
But, there might come a time when you get asked or need to change some option that is not available.<br />
<br />
Maybe you need to change the first day of the week to Monday instead of Sunday, or need to disable some days, etc.<br />
<br />
For a list of all available options and the utility functions, you should have a look at the <a href="http://api.jqueryui.com/1.10/datepicker/" target="_blank">Datepicker Widget API Documentation</a>.<br />
<br />
There are a couple of nice hidden features that you might not know existed.<br />
Let's have a look at a couple of them.<br />
<br />
Changing the first day of the week to Mondays
<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>$('#P1000_DATE_3').datepicker("option", "firstDay", 1);
</code></pre>
</blockquote>
<br />
Disabling the selection of weekends using built-in utility function.<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>$('#P1000_DATE_4').datepicker("option", "beforeShowDay", $.datepicker.noWeekends);
</code></pre>
</blockquote>
<br />
Disabling the selection of Mondays<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>function disableMondays(pDate){
var lTooltipDate = "Tooltip for disabled dates";
if (pDate.getDay() === 1) {
return [false, 'disabledDayClass', lTooltipDate];
}
else {
return [true, null, null];
}
}
$('#P1000_DATE_5').datepicker("option", "beforeShowDay", function(date) {return disableMondays(date);});
</code></pre>
</blockquote>
<br />
However, if you change an option for a datepicker item, you'll notice that the icon trigger will look different.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIujRymXXiM4pfgzHzk8QwXounwug1VGJ7bnIuQNrIsReuCdXzb4A16lvriqe9VkPPl6nm-2lBmVqKkP69T1QIuGZ5umVWdBxCXFviSB-qY2sVVnOeuZKtHzxrIhbqBH6uBtElarF0xHw/s1600/Datepicker-APEX5.0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="1054" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIujRymXXiM4pfgzHzk8QwXounwug1VGJ7bnIuQNrIsReuCdXzb4A16lvriqe9VkPPl6nm-2lBmVqKkP69T1QIuGZ5umVWdBxCXFviSB-qY2sVVnOeuZKtHzxrIhbqBH6uBtElarF0xHw/s400/Datepicker-APEX5.0.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCa-XFNmu8q2pBqe5etG0nXimZ_auPw700CHVAL9d2z4OD6ARtp3GPXMBevjUqcp_J7ruUWa2Du6pRFpOZts-sluoeNNhqVfJXPnTX3im403MfWoX5uUOk1Z5dv2WfBsfU2ExYtrEBQ90/s1600/Datepicker-APEX5.1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="1048" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCa-XFNmu8q2pBqe5etG0nXimZ_auPw700CHVAL9d2z4OD6ARtp3GPXMBevjUqcp_J7ruUWa2Du6pRFpOZts-sluoeNNhqVfJXPnTX3im403MfWoX5uUOk1Z5dv2WfBsfU2ExYtrEBQ90/s400/Datepicker-APEX5.1.png" width="400" /></a></div>
<br />
So what's going on exactly?<br />
Let's have a look at the html.<br />
<br />
Before changing an option:<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-html"><code><input type="text" class="datepicker apex-item-text apex-item-datepicker hasDatepicker" id="P1000_DATE_1" name="P1000_DATE_1" maxlength="" size="30" value="" autocomplete="off"></code>
<code class="highlight"><button type="button" class="ui-datepicker-trigger a-Button a-Button--calendar"></code>
<code> <span class="a-Icon icon-calendar"></span>
<span class="u-VisuallyHidden">Popup Calendar: Date<span></span></span>
</button>
</code></pre>
</blockquote>
<br />
After changing an option:<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-html"><code><input type="text" class="datepicker apex-item-text apex-item-datepicker hasDatepicker" id="P1000_DATE_1" name="P1000_DATE_1" maxlength="" size="30" value="" autocomplete="off"></code>
<code class="highlight"><button type="button" class="ui-datepicker-trigger"></code>
<code> <span class="a-Icon icon-calendar"></span>
<span class="u-VisuallyHidden">Popup Calendar: Date<span></span></span>
</button>
</code>
</pre>
</blockquote>
<br />
We can see that the button element is missing two APEX classes after an option is changed:<br />
<blockquote class="tr_bq">
<pre class="language-html"><code>a-Button a-Button--calendar</code></pre>
</blockquote>
<br />
So, to fix the issue with the button trigger we simply need to add the classes back.<br />
That's also exactly what APEX is doing on page load for each datepicker item.<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>(function() {
apex.widget.datepicker("#P1000_DATE_1", {
"buttonImageOnly": false,
"buttonText": "\u003Cspan class=\u0022a-Icon icon-calendar\u0022\u003E\u003C\u002Fspan\u003E\u003Cspan class=\u0022u-VisuallyHidden\u0022\u003EPopup Calendar: Date\u003Cspan\u003E",
"showTime": false,
"defaultDate": new Date(2018, 1, 26, 20, 32, 47),
"showOn": "button",
"showOtherMonths": false,
"changeMonth": false,
"changeYear": false
}, "dd-M-y", "en");</code>
<code class="highlight"> apex.jQuery('#P1000_DATE_1').next('button').addClass('a-Button a-Button--calendar');</code>
<code>})();
</code></pre>
</blockquote>
<br />
Having a look again at our first example (changing the first day of the week to Mondays). We should use something like this.<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>$('#P1000_DATE_3').datepicker("option", "firstDay", 1).next('button').addClass('a-Button a-Button--calendar');
</code></pre>
</blockquote>
Now, what if you would like to change an option for every datepicker in your application.<br />
<br />
Once a datepicker is initialized a "hasDatepicker" class is added to the element. So instead of using the item ID as the jQuery selector, we could use that class and have the code execute on page load.<br />
<blockquote class="tr_bq">
<pre class="line-numbers language-javascript"><code>$('.hasDatepicker').datepicker("option", "firstDay", 1).next('button').addClass('a-Button a-Button--calendar');
</code></pre>
</blockquote>
<style>
pre > code.highlight {
outline: .4em solid red;
outline-offset: .4em;
}
</style>
<br />
If the previous code is not working as expected, it my be due to a timing issue. Since the code to customize the datepicker items is executed on page load and that the dapicker are initialized on page load also. The customizing code could be running before the actual initialization. To fix that you can add a short delay to it.<br />
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:3200" target="_blank">Demo Application</a><br />
<br />
Enjoy!
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-7094648721448142042018-02-10T23:25:00.000-05:002020-03-17T16:20:51.666-04:00Switch and Radio as Pill Custom Colors<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/02/10/switch-and-radio-as-pill-custom-colors';
</script>
<div class="separator" style="display: none;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiifDVfX9JHnDwaoGk0nnMlO_PbHY6g6oDvAedvo_hfOhhbRq_3wd57DM57x-Q4TVe9HEC6pNpcHdYxTREZPWCYxZxbXOdWNFUb1-G-R9rfRsjSBCTCjqYlfbTFyfzTUqd7bi-pBjDP5iM/s1600/custom_color.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1120" data-original-width="888" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiifDVfX9JHnDwaoGk0nnMlO_PbHY6g6oDvAedvo_hfOhhbRq_3wd57DM57x-Q4TVe9HEC6pNpcHdYxTREZPWCYxZxbXOdWNFUb1-G-R9rfRsjSBCTCjqYlfbTFyfzTUqd7bi-pBjDP5iM/s320/custom_color.png" width="253" /></a></div>
There are two easy ways to have Toggle-like items in your applications.<br />
<br />
One way is by using the Switch item type that will like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNPAESSSu7wsVhUiCRSWi5ABZ6NiJiN8Ob6NyJMblwkn4zNW0gNkTL1PeK0m12wqAw2_JF7yDOOoy-1gO0dESwHzKPKkzqk3Bk9llgnpNf1F4Zr-QH8k-zh3OAm5BlAKwycs_0_ZhCQuI/s1600/switch_item.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="98" data-original-width="416" height="75" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNPAESSSu7wsVhUiCRSWi5ABZ6NiJiN8Ob6NyJMblwkn4zNW0gNkTL1PeK0m12wqAw2_JF7yDOOoy-1gO0dESwHzKPKkzqk3Bk9llgnpNf1F4Zr-QH8k-zh3OAm5BlAKwycs_0_ZhCQuI/s320/switch_item.png" width="320" /></a></div>
<br />
If your switch items are displayed as select lists rather than as toggle items, you will need to go in your application's Shared Components, then in the Components Settings and edit the Switch item to change the Display Style attribute to Switch.<br />
<br />
Another way is by using a Radio item. You'll need to change some attributes so that the item is displayed as a toggle.<br />
<br />
First, you'll need to change the Number of Columns attributes to at least the amount of values you have. I like to use 999 so that if a new value is added to the list, I won't have to change the attribute again.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeoT_nJq8_Jt4gB24WN_U9wvKeqbkdC7OBU6n7JRD3YgM1FaMTweVg3XkxYSXuzjHAkoq6qjdsDDRG8yvgz8VOFkF90OXE9zGJ9RMP7EprbBzM2y1dU8uypWsYqrIPw6waDWrwzGhR5uA/s1600/radio_as_pill_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="618" data-original-width="952" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeoT_nJq8_Jt4gB24WN_U9wvKeqbkdC7OBU6n7JRD3YgM1FaMTweVg3XkxYSXuzjHAkoq6qjdsDDRG8yvgz8VOFkF90OXE9zGJ9RMP7EprbBzM2y1dU8uypWsYqrIPw6waDWrwzGhR5uA/s320/radio_as_pill_1.png" width="320" /></a></div>
<br />
Then you'll need to change the Template Options so that the Radio Group Display is set to "Display as Pill Button".<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfy4oWQChF4rdnJULIU-8_xzgLeDLvD-18rMCMD0oSDzDLpo-4wOmqYOjuA1kMsdiZ3hBRz0isu1IKimJipIxNM3_tFfYb1LiLNujRFhWsCsbz4R9tmYaKllflqqWteTDRf55w1VaEWGY/s1600/radio_as_pill_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1012" data-original-width="1036" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfy4oWQChF4rdnJULIU-8_xzgLeDLvD-18rMCMD0oSDzDLpo-4wOmqYOjuA1kMsdiZ3hBRz0isu1IKimJipIxNM3_tFfYb1LiLNujRFhWsCsbz4R9tmYaKllflqqWteTDRf55w1VaEWGY/s320/radio_as_pill_2.png" width="320" /></a></div>
You will get a radio item that looks like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTK-36JNTUUK_71rJspbk16DVnUyuzzRsHblshIFeYcEiL2bELJeokiM7YtuyS6Vr287SuY0PuV2DG9D9BvQKNoW2KiQ165giniGWVLg1QBRIdtzK_FYRau6oLwNAKAC7JRYviS8cStL8/s1600/radio_Item.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="98" data-original-width="450" height="69" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTK-36JNTUUK_71rJspbk16DVnUyuzzRsHblshIFeYcEiL2bELJeokiM7YtuyS6Vr287SuY0PuV2DG9D9BvQKNoW2KiQ165giniGWVLg1QBRIdtzK_FYRau6oLwNAKAC7JRYviS8cStL8/s320/radio_Item.png" width="320" /></a></div>
<br />
Now, let's customize their colors.<br />
<br />
<h2>
Custom On/Off Colors</h2>
Let's define this CSS<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-css">/* Custom On/Off Color - No Color */
.t-Form-fieldContainer--radioButtonGroup .customOnOffColor.apex-item-radio input:checked + label,
.customOnOffColor.apex-button-group input:checked+label {
background-color: #EF9A9A;
}
/* Custom On/Off Color - Yes Color */
.t-Form-fieldContainer--radioButtonGroup .customOnOffColor.apex-item-radio input[value=Y]:checked + label,
.customOnOffColor.apex-button-group input[value=Y]:checked+label {
background-color:#A5D6A7
}
</code></pre>
</blockquote>
In order to have the items use custom colors, we only need to set the CSS Classes to "customOnOffColor".<br />
<br />
The yes value will be green and any other value will be red, like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmNvu-l6T3QEX47fmXEB3PcwJmOHb3QL4ccU8Y_X8AzLDzJeFIuFmo37yyTUj8nkOidUe4y81Z5Ioqa4Bg8AMZc-5W3ofihE0jZvFyVMgLIotf-PxcANlNWWis9EiVO80BAcll1OmTV_c/s1600/custom_on_off_colors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="520" data-original-width="888" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmNvu-l6T3QEX47fmXEB3PcwJmOHb3QL4ccU8Y_X8AzLDzJeFIuFmo37yyTUj8nkOidUe4y81Z5Ioqa4Bg8AMZc-5W3ofihE0jZvFyVMgLIotf-PxcANlNWWis9EiVO80BAcll1OmTV_c/s320/custom_on_off_colors.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h2>
Custom On Color</h2>
Let's define this CSS
<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-css">/* Custom On Color */
.t-Form-fieldContainer--radioButtonGroup .customOnColor.apex-item-radio input:checked + label,
.customOnColor.apex-button-group input:checked+label {
background-color: #B3E5FC;
}
</code></pre>
</blockquote>
In order to have the items use custom color, we only need to set the CSS Classes to "customOnColor".<br />
<br />
The selected value will be blue, like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNjGF9uqglVEBpIyUBb_XY3l1XEO_gdR5cbs0fKof8NRnPonI5eb5ckqUEjeoKZW8yh0Zx2ml1GnRq5HxELZ0DIjTDKAeYw11Ii7g5YZOFpq7uzTtSDbS5ImbsEeLkF0T9dMxGVE-K350/s1600/custom_on_colors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="886" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNjGF9uqglVEBpIyUBb_XY3l1XEO_gdR5cbs0fKof8NRnPonI5eb5ckqUEjeoKZW8yh0Zx2ml1GnRq5HxELZ0DIjTDKAeYw11Ii7g5YZOFpq7uzTtSDbS5ImbsEeLkF0T9dMxGVE-K350/s320/custom_on_colors.png" width="320" /></a></div>
<br />
<br />
For both the custom On/Off and On only colors, if you'd like to apply it for all items (Switch and Radio as Pill), you can simply remove the classes names from the above CSS.<br />
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2800" target="_blank">Demo Application</a><br />
<br />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-78532501398301895442018-01-29T13:49:00.000-05:002020-03-17T16:21:01.200-04:00Use Font APEX and Font Awesome Simultaneously<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/01/29/use-font-apex-and-font-awesome';
</script>
<div>
APEX 5.0 gave us the ability to include the Font Awesome library in our applications. In APEX 5.1, Font APEX was added the the list of icon library. </div>
<div>
<br /></div>
<div>
Taken from the Universal Theme Sample Application:</div>
<div>
<blockquote class="tr_bq" style="border-left: 2px solid lightgray; padding-left: 10px;">
Font APEX is an all new icon library designed to complement Universal Theme. It was designed as a replacement for Font Awesome, the web's leading icon library, and therefore contains almost all of the Font Awesome icons, re-drawn on a 16x16 grid as line-icons, to match the aesthetic we wanted. We wanted to make it a seamless switch to go from Font Awesome to Font APEX, and therefore use the same "fa" prefix for the icons, making it easier than ever to move to entirely new icon library.</blockquote>
</div>
<div>
To include either Font Awesome or Font APEX in our application, we need to go under the application's Shared Components, then under Themes, select the theme and under the Icons section, we can select the library that we want to include.<br />
<br /></div>
<div>
What if we would, for some reason, like to include the two libraries and use some icons from one and some icons from the other.</div>
<div>
<br /></div>
<div>
Unfortunately, the library attribute only enables us to select one of them.</div>
<div>
<br /></div>
<div>
On top of that, since the two libraries are using the same "fa" prefix, we can't simply include both files.</div>
<div>
<br /></div>
<div>
On the other hand, Font Awesome includes the LESS and Sass files so that we can customize and build the library ourselves.</div>
<div>
<br />
<h2>
What we'll do</h2>
</div>
<div>
The idea is to include the Font APEX library using the built-in attributes. We'll then need to customize Font Awesome so that it uses a different prefix, build it and include that custom version into our application.</div>
<div>
<br /></div>
<h2>
Building our customized Font Awesome</h2>
<div>
First, we'll need to head over to <a href="http://fontawesome.io/" target="_blank">http://fontawesome.io</a> and download the library.</div>
<div>
Once extracted, we get 4 folders:<br />
<ul>
<li>css</li>
<li>fonts</li>
<li>less </li>
<li>scss</li>
</ul>
Looking at either the LESS or Sass folder we'll see the different files required to build the library. You can choose whichever one you're most familiar with.<br />
<br />
For what we're trying to achieve, we can focus specifically on the "variables" and the "font-awesome" files.</div>
<div>
<br />
The variables file allows us to replace the "fa-css-prefix" variable.</div>
<div>
By default, it's set to "fa", but let's change it to something different like "fawe".</div>
<div>
<br /></div>
<div>
Then, we can build the customized version of the library using the "font-awesome" file.<br />
<br />
You can build LESS and Sass files with most text editors. There are also many desktop applications that are able to compile LESS and Sass.</div>
<br />
<br />
Once our customized Font Awesome is built, we need to upload it to our application (either in the Static Files or on your Web Server).<br />
<br />
<h2>
Using Font APEX and Font Awesome</h2>
First, we'll need to include our custom Font Awesome library. We can add it under the Shared Components by going into the User Interface Attributes and then selecting the Desktop interface. Under the Cascading Style Sheets Section, we can add the references to our file. <br />
<br />
Something like this:<br />
<blockquote class="tr_bq">
<pre><code class="language-html">#APP_IMAGES#font-awesome/4.7.0/css/custom-font-awesome#MIN#.css</code></pre>
</blockquote>
<br />
Using Font APEX will be just as usual. Use the corresponding "fa" class as seen on
<br />
<div class="shortcut-url">
<a href="https://apex.oracle.com/fontapex" target="_blank">https://apex.oracle.com/fontapex </a></div>
<blockquote class="tr_bq">
<pre><code class="language-html"><i class="fa fa-cog" aria-hidden="true"></i>
<i class="fa fa-trash-o" aria-hidden="true"></i>
<i class="fa fa-bars" aria-hidden="true"></i>
<i class="fa fa-envelope-o" aria-hidden="true"></i>
<i class="fa fa-key" aria-hidden="true"></i>
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
<i class="fa fa-battery-half" aria-hidden="true"></i>
</code></pre>
</blockquote>
<br />
In order to use our customized Font Awesome, we will need to use our custom class prefix. In our case: "fawe".
<br />
<blockquote class="tr_bq">
<pre><code class="language-html"><i class="fawe fawe-cog" aria-hidden="true"></i>
<i class="fawe fawe-trash-o" aria-hidden="true"></i>
<i class="fawe fawe-bars" aria-hidden="true"></i>
<i class="fawe fawe-envelope-o" aria-hidden="true"></i>
<i class="fawe fawe-key" aria-hidden="true"></i>
<i class="fawe fawe-shopping-cart" aria-hidden="true"></i>
<i class="fawe fawe-battery-half" aria-hidden="true"></i>
</code></pre>
</blockquote>
You'll then be able to use both at the same time, like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjTZWP69-NMjYwfiOmnU4FRx2av-a5ct91WjKUHLsitNd77KnlKL5HIviSGFmKhcUpjk9NUFSY1CSx-v3FUtbXMZMu8y4JRVVhM8e6AIhDQX4RoYsydXFFJUtoqMPs-J3zOC-E9GDhlD0/s1600/Icons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="144" data-original-width="687" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjTZWP69-NMjYwfiOmnU4FRx2av-a5ct91WjKUHLsitNd77KnlKL5HIviSGFmKhcUpjk9NUFSY1CSx-v3FUtbXMZMu8y4JRVVhM8e6AIhDQX4RoYsydXFFJUtoqMPs-J3zOC-E9GDhlD0/s640/Icons.png" width="640" /></a></div>
<br />
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2000" target="_blank">Demo Application</a><br />
<br class="Apple-interchange-newline" />
You can also get the custom Font Awesome library: <a href="https://drive.google.com/file/d/10b9jedIyqSNzOKdvF7HR3xFRkE85zG7a" rel="nofollow" target="_blank">here</a><br />
<br class="Apple-interchange-newline" />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-52433058706600337462018-01-17T18:33:00.000-05:002020-03-17T16:21:08.670-04:00Custom Confirm Dialog Button Labels<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2018/01/17/custom-confirm-dialog-button-labels';
</script>
Some time ago, someone on the apex.world Slack channel asked a question about the APEX confirm dialog. The question was if it was possible to change the labels of the confirm dialog buttons from "Cancel/Ok" to "No/Yes".<br />
<br />
If we look at the <a href="https://docs.oracle.com/database/apex-5.1/AEAPI/JavaScript-APIs.htm#AEAPI266" target="_blank">JavaScript APIs</a> documentation we can see that there are three different ways that we can display a confirmation dialog:<br />
<ul>
<li>apex.confirm</li>
<li>apex.page.confirm</li>
<li>apex.message.confirm</li>
</ul>
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
<u>Note</u><br />
The confirm function from the page namespace is different from the one in the confirm namespace. They both render the same confirmation dialog though.<br />
<br />
<i>apex.confirm</i>: Alias for the apex.page.confirm function.<br />
<br />
<i>apex.page.confirm</i>: Displays a confirmation dialog showing a message (pMessage) and OK and Cancel buttons. Depending on the user's choice, submits the page setting the request value to pRequest, or does not submit the page.<br />
<br />
<i>apex.message.confirm</i>: Displays a confirmation dialog showing a message (pMessage), and OK and Cancel buttons. The callback function passed as the pCallback parameter is called when the dialog is closed, and passes true if OK is pressed and false otherwise.</blockquote>
<br />
The following JavaScript code:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">apex.message.confirm( "Are you sure?", function( okPressed ) {
console.log(okPressed ? 'Ok' : 'Cancel');
});</code></pre>
</blockquote>
<br />
Would display this dialog:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOiAK7pxqDUl2_0LiYd6T91YAMzMWSqkMzI4A6_9wb4WobAw9dMrvLb0ui_UpuCBNsJe9m38XijYQOGQqvbEY-eOnzWeG-8Fb4tZTmYG9VjxmaJqo-qJ1IeEMgzokeFYNgeusP91D7FEg/s1600/confirm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="381" data-original-width="872" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOiAK7pxqDUl2_0LiYd6T91YAMzMWSqkMzI4A6_9wb4WobAw9dMrvLb0ui_UpuCBNsJe9m38XijYQOGQqvbEY-eOnzWeG-8Fb4tZTmYG9VjxmaJqo-qJ1IeEMgzokeFYNgeusP91D7FEg/s320/confirm.png" width="320" /></a></div>
<br />
Now, back to the original question. What if we would like to change those button labels.<br />
<br />
If we have a look at the JavaScript code of the apex.message.confirm function, we can see that the labels are based on some apex.lang messages (APEX.DIALOG.OK and APEX.DIALOG.CANCEL) and that there is no built-in way to change the labels.<br />
<br />
But...<br />
<br />
What we can do is change the values (using the JavaScript API of the <a href="http://apex.lang/" target="_blank">apex.lang</a> namespace) of the two messages and then call the confirm function. We should also revert the changes to the messages after that so that everything remains as it was initially.<br />
<br />
Ok, so let's create a wrapper function on apex.message.confirm (the same also works for apex.page.confirm) and add two parameters for the button labels.<br />
<br />
The function could look like this:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">function customConfirm( pMessage, pCallback, pOkLabel, pCancelLabel ){
var l_original_messages = {"APEX.DIALOG.OK": apex.lang.getMessage("APEX.DIALOG.OK"),
"APEX.DIALOG.CANCEL": apex.lang.getMessage("APEX.DIALOG.CANCEL")};
//change the button labels messages
apex.lang.addMessages({"APEX.DIALOG.OK": pOkLabel});
apex.lang.addMessages({"APEX.DIALOG.CANCEL": pCancelLabel});
//show the confirm dialog
apex.message.confirm(pMessage, pCallback);
//changes the button labels messages back to their original values
apex.lang.addMessages({"APEX.DIALOG.OK": l_original_messages["APEX.DIALOG.OK"]});
apex.lang.addMessages({"APEX.DIALOG.CANCEL": l_original_messages["APEX.DIALOG.CANCEL"]});
}
</code></pre>
</blockquote>
<br />
Then, calling our function:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">customConfirm( "Are you sure?", function( okPressed ) {
console.log(okPressed ? 'Ok' : 'Cancel');
}, "Yes", "No");</code></pre>
</blockquote>
<br />
Would result in this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWZKRRS2Yiea0RCFKUrjiCkY06wanMXgGikQngS_QJvEGX5NbufE9jh1h6kSG0He-WS3tewpyJAH59jjO-uy1dl0Y9eo7zCeQFsCAgaCauoZH6lEjsu1F6aA08cIMMSoeJ4v3c1Di51Hc/s1600/custom_confirm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="386" data-original-width="862" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWZKRRS2Yiea0RCFKUrjiCkY06wanMXgGikQngS_QJvEGX5NbufE9jh1h6kSG0He-WS3tewpyJAH59jjO-uy1dl0Y9eo7zCeQFsCAgaCauoZH6lEjsu1F6aA08cIMMSoeJ4v3c1Di51Hc/s320/custom_confirm.png" width="320" /></a></div>
<br />
or anything you want, like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRnTpf5Q8X3XWPFZGQlrOsk73Gs0hhR3Ay-HWDDRg7y49LF5b-CrmbVKswWmJdPR_1JvX16PDP_GaZAsOcp1ZYNTtfPTeQvkjt1jb35Auv3vuPNM3eejVSkYCWBcPpFM_eL03sI6QUoaE/s1600/custom_confirm2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="876" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRnTpf5Q8X3XWPFZGQlrOsk73Gs0hhR3Ay-HWDDRg7y49LF5b-CrmbVKswWmJdPR_1JvX16PDP_GaZAsOcp1ZYNTtfPTeQvkjt1jb35Auv3vuPNM3eejVSkYCWBcPpFM_eL03sI6QUoaE/s320/custom_confirm2.png" width="320" /></a></div>
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:1700" target="_blank">Demo Application</a><br />
<br class="Apple-interchange-newline" />
Enjoy!Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com15tag:blogger.com,1999:blog-267713902572011003.post-8031341771552174252017-09-25T22:35:00.000-04:002020-03-17T16:26:18.461-04:00Auto Expanding Menu on Hover<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2017/09/25/auto-expanding-menu-on-hover';
</script>
Today someone on the apex.world Slack asked a question about having the side navigation menu auto-expand when hovering it. So I thought I would share this with others as well.<br />
<br />
It can be easily be done using only a couple of JavaScript lines of code:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">(function(ut, $) {
var TREE_NAV_WIDGET_KEY = 'nav';
$(window).on('theme42ready', function() {
/* Make sure that the navigation menu is collapsed on page load */
if (ut.toggleWidgets.isExpanded(TREE_NAV_WIDGET_KEY)){
ut.toggleWidgets.collapseWidget(TREE_NAV_WIDGET_KEY);
}
/* Expand on mouse over, collapse on mouse out */
$('.apex-side-nav.js-navCollapsed .t-Body-nav').hover(
function(){
ut.toggleWidgets.expandWidget(TREE_NAV_WIDGET_KEY);
},
function() {
ut.toggleWidgets.collapseWidget(TREE_NAV_WIDGET_KEY);
}
);
});
})(apex.theme42, apex.jQuery);</code>
</pre>
</blockquote>
First thing we need to do is make sure that the side navigation is collapsed.<br />
Then we add a hovering handler using the jQuery <a href="https://api.jquery.com/hover/" target="_blank">.hover()</a> on the navigation menu container.<br />
<br />
You'll end up with something like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOD48zPVz-ACsikXP0CuRTZviby2RD6LY5WusYSQTFTBoaFyEdlRwpaJ3Rr5J89CxawwwFHj93eYcx5kd_cVIpr6Kgw1LhR4WPlQ6d3DkHaHapfR8B_-evTZd2DrNI_jQmpXw-rZFKBvg/s1600/Auto-Expanding-Menu-Hover.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="579" data-original-width="888" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOD48zPVz-ACsikXP0CuRTZviby2RD6LY5WusYSQTFTBoaFyEdlRwpaJ3Rr5J89CxawwwFHj93eYcx5kd_cVIpr6Kgw1LhR4WPlQ6d3DkHaHapfR8B_-evTZd2DrNI_jQmpXw-rZFKBvg/s400/Auto-Expanding-Menu-Hover.gif" width="530" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Have fun<br />
<br />
You can have a look at it in action in my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:1200" target="_blank">Demo Application</a>
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
<u>Edit 09-27</u><br />
Now triggers the <a href="https://apex.oracle.com/pls/apex/f?p=42:6200" target="_blank">custom navigation menu event</a>.<br />
Also calls the delayResize function so that any sticky headers get resized correctly when the side navigation menu is expanded and collapsed.<br />
<br />
<u>Edit 09-28</u><br />
Rewrote to use namespacing, wrapped using the "theme42ready" event and replaced the collapsed/expand calls with the universal theme functions.</blockquote>
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com21tag:blogger.com,1999:blog-267713902572011003.post-65813747795735838102017-09-08T16:29:00.002-04:002020-03-17T16:22:20.512-04:00APEX Items the Application Builder Style<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2017/09/08/apex-items-application-builder-style';
</script>
The APEX application builder has the items look and feel different compared to what you get in a regular application.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGiv3vA29L6Uu_OZlN2OfRfbcvg2KntqvP-mU8H-E-BGqILebHyDNvJpw7gwC5eQbWBYSGfz-obHpaJSxGk7I3b9gI7xVJnkQW1XgSUu2tuBWHzgC5p1GRaXyzp0s56Fte4EhSjvzn8-E/s1600/Page+Designer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="178" data-original-width="661" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGiv3vA29L6Uu_OZlN2OfRfbcvg2KntqvP-mU8H-E-BGqILebHyDNvJpw7gwC5eQbWBYSGfz-obHpaJSxGk7I3b9gI7xVJnkQW1XgSUu2tuBWHzgC5p1GRaXyzp0s56Fte4EhSjvzn8-E/s400/Page+Designer.png" width="400" /></a></div>
<br />
You might think that they are looking good and that you would like to display them the same way in your application.<br />
<br />
Here's the CSS you can use to do just that:
<br />
<pre class="line-numbers"><code class="language-css">/* Removes borders from items */
.t-Form-inputContainer input[type="text"],
.t-Form-inputContainer input.text_field,
.t-Form-inputContainer input.password,
.t-Form-inputContainer input.datepicker,
.t-Form-inputContainer span.display_only,
.t-Form-inputContainer input.popup_lov,
.t-Form-inputContainer select,
.u-TF-item--text,
.u-TF-item--datepicker,
.u-TF-item--select,
.a-IRR-selectList[size="1"],
.t-Form-inputContainer select.selectlist[size="1"],
.t-Form-inputContainer select.yes_no,
.u-TF-item--select {
background-color: transparent;
border-top-color: transparent;
border-left-color: transparent;
border-right-color: transparent;
}
/* Removes decoration of the popup lov button */
.a-Button.a-Button--popupLOV {
background-color: transparent;
box-shadow: none;
}
.a-Button.a-Button--popupLOV:hover {
background-color: #f8f8f8;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.125) inset;
}
/* Removes borders when displaying inline error */
.t-Form-inputContainer input[type="text"].apex-page-item-error,
.t-Form-inputContainer input.text_field.apex-page-item-error,
.t-Form-inputContainer input.password.apex-page-item-error,
.t-Form-inputContainer input.datepicker.apex-page-item-error,
.t-Form-inputContainer span.display_only.apex-page-item-error,
.t-Form-inputContainer input.popup_lov.apex-page-item-error,
.t-Form-inputContainer select.apex-page-item-error,
.u-TF-item--text.apex-page-item-error,
.u-TF-item--textarea.apex-page-item-error,
.u-TF-item--datepicker.apex-page-item-error,
.u-TF-item--select.apex-page-item-error{
border-top-color: transparent;
border-left-color: transparent;
border-right-color: transparent;
}
/* Removes borders when displaying inline error (required with valid state) */
.t-Form-inputContainer input[type="text"].apex-page-item-error:required:valid,
.t-Form-inputContainer input.text_field.apex-page-item-error:required:valid,
.t-Form-inputContainer input.password.apex-page-item-error:required:valid,
.t-Form-inputContainer input.datepicker.apex-page-item-error:required:valid,
.t-Form-inputContainer span.display_only.apex-page-item-error:required:valid,
.t-Form-inputContainer input.popup_lov.apex-page-item-error:required:valid,
.t-Form-inputContainer select.apex-page-item-error:required:valid,
.u-TF-item--text.apex-page-item-error:required:valid,
.u-TF-item--textarea.apex-page-item-error:required:valid,
.u-TF-item--datepicker.apex-page-item-error:required:valid,
.u-TF-item--select.apex-page-item-error:required:valid {
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
}
/* Fix the select list error border color */
.t-Form-inputContainer select.apex-page-item-error{
border-color: #eb6562;
}</code></pre>
<br />
Basically, the CSS will hide the top, left and right border of the items, while keeping the bottom border as well as the border's defined color. When the item is focused, all borders will be displayed as usual.<br />
<br />
You'll end up with something like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhjlV68_obCEHSP0K3ZhSr-LVJapQMd38XWIT4huJhgrnWdWIfV-zHP1vW32mrMUohNjCMBR4ejVsZIYxScBapDXsq6pYQJezAFKXdIJ_mYcSCf_F3_44-Q_xsM9wGuXUgCbWVqezzONc/s1600/APEX_Items_Builder_Style.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="947" data-original-width="841" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhjlV68_obCEHSP0K3ZhSr-LVJapQMd38XWIT4huJhgrnWdWIfV-zHP1vW32mrMUohNjCMBR4ejVsZIYxScBapDXsq6pYQJezAFKXdIJ_mYcSCf_F3_44-Q_xsM9wGuXUgCbWVqezzONc/s640/APEX_Items_Builder_Style.gif" width="568" /></a></div>
<br />
<span id="goog_1740975607"></span>
Have fun
<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:3300" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-46205035297057180782017-02-24T15:46:00.000-05:002020-03-17T16:22:33.492-04:00Overriding the Default Properties of Inline Dialogs<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2017/02/24/overriding-default-properties-of-inline';
</script>
When using inline modal, you can display them using the <code class="language-javascript">openModal</code> JavaScript function.<br />
<br />
That function is wrapping the jQuery UI Dialog Open method.<br />
<pre class="line-numbers"><code class="language-javascript">/* **********************************************
From Theme42.js
********************************************** */
window.openModal = function(pDialogId, pDialogTriggerId, pSetFocusId, pClear) {
$("#" + pDialogId).dialog("open")
}
</code></pre><br />
What we can do to override the default properties is to set them either on page or right before calling the Open method.<br />
<br />
Let's say we would like to have a smaller dialog (e.g. height of 200px)<br />
<br />
<br />
<h2><u>Option 1</u></h2>
On page load<br />
<pre class="line-numbers"><code class="language-javascript">$('#INLINE_REGION_STATIC_ID').dialog('option', 'height', 200);
</code></pre>
<br />
Then you can use<br />
<pre class="line-numbers"><code class="language-javascript">openModal('INLINE_REGION_STATIC_ID');
</code></pre>
or<br />
<pre class="line-numbers"><code class="language-javascript">$('#INLINE_REGION_STATIC_ID').dialog('open');
</code></pre>
<br />
<h2><u>Option 2</u></h2>
When openning the Dialog:<br />
<pre class="line-numbers"><code class="language-javascript">$('#INLINE_REGION_STATIC_ID').dialog('option', 'height', 200).dialog('open')
</code></pre>
<br />
For more information, you can have a look at the <a href="http://api.jqueryui.com/dialog/" target="_blank">Dialog Widget documentation</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0tag:blogger.com,1999:blog-267713902572011003.post-37149391320239919232017-02-03T07:50:00.000-05:002020-03-17T16:22:40.074-04:00Using Font Apex in Apex 5.0<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2017/02/03/using-font-apex-in-apex-50';
</script>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsUWxT7fp-pk9QYUgnROX0f8tkJkC4FwDPRX3KtWBLEsLHcXeL2372krYC6257z20kNAzrmsydN3wSxGEbO6RTLx7qZrLeNNZbafOg2OJ1leUX85RgsNROF7ir_kLtsG1im3UA5xi9xgs/s1600/FontApex.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsUWxT7fp-pk9QYUgnROX0f8tkJkC4FwDPRX3KtWBLEsLHcXeL2372krYC6257z20kNAzrmsydN3wSxGEbO6RTLx7qZrLeNNZbafOg2OJ1leUX85RgsNROF7ir_kLtsG1im3UA5xi9xgs/s1600/FontApex.png" /></a></div>
<br />
Apex 5.1 introduced Font Apex, a new icon library designed to complement Universal Theme and to replace Font Awesome. The same "fa" prefix for the icons was kept so that it's easier to move from Font Awesome to this entirely new icon library.<br />
<br />
Font APEX comes with a number of customizations built-in, enabling us to easily control the size, animation, rotation, and even add modifiers on top of icons. You can try customizing your icons using the Icon Builder in the <a href="https://apex.oracle.com/fontapex" target="_blank">Universal Theme sample application</a>.<br />
<br />
What if you are still on Apex 5.0 and would like to use it?<br />
<br />
Don't worry you are able to do so.<br />
Here's how you can do it.<br />
<br />
First let's get the Font Apex library files.<br />
You can get them from the <a href="http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html" target="_blank">Apex 5.1 installation</a> file under the "images\libraries\font-apex" folder (or from <a href="https://drive.google.com/uc?export=download&id=0BzJsLftbKSZSbkwzNGtzak1KaDQ" target="_blank">here</a>)<br />
Then you will need to import these files in your application (let's do it using the Static Application Files for the sake of simplicity, but you could also import them in the Static Workspace Files or copy them on your web server).<br />
<br />
Note: zipping the font-apex folder will enable us to upload only that zipped file instead of every single file from the folder using the zip file will also keep the folder structure.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAfW43MkHVzJXkV426JBqaiOdFlRswDpGv-PsBy1gjH6n__U0hy9zB9eoMLSn4CGGWiJI8BIxulWuYN-hwhdEUKaX7k4XQVhRQ6dNgKEKUI7q-u3NozCCxg1-HPi-EkIW5JCceflUz0pI/s1600/upload_files.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" class="noBorder noBackground" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAfW43MkHVzJXkV426JBqaiOdFlRswDpGv-PsBy1gjH6n__U0hy9zB9eoMLSn4CGGWiJI8BIxulWuYN-hwhdEUKaX7k4XQVhRQ6dNgKEKUI7q-u3NozCCxg1-HPi-EkIW5JCceflUz0pI/s400/upload_files.png" width="550" /></a></div>
<br />
<br />
You will end up with the following files:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVyo5YEqGY0kN6V8_2XKmXUuJQwgYIZr1YaIato9Ie4wlqTCPES6wUMry_mdb7GFPx3rQj6OLgUbVXmgWGBsXOcWkFxaCwWZ6eM9ZLCFWRz21gMn2pJrVmN606YXDU-o5dlssZLMkHrQ/s1600/upload_files_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" class="noBorder noBackground" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVyo5YEqGY0kN6V8_2XKmXUuJQwgYIZr1YaIato9Ie4wlqTCPES6wUMry_mdb7GFPx3rQj6OLgUbVXmgWGBsXOcWkFxaCwWZ6eM9ZLCFWRz21gMn2pJrVmN606YXDU-o5dlssZLMkHrQ/s400/upload_files_2.png" width="550" /></a></div>
<br />
<br />
Then, let's remove the Font Awesome and include the Font Apex.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicmQp9xe-hJtIGIjmdgCyqmqFEbgpZ16P0jDJd253znqNCXZbQZVlRvaTpsXBB6CkXmP0LPigevV9_NmxZtRKdyrylGczkYiLrVnorG8MnHiBZmQpWGsSxG_IpyVyS2jDq_H1AKIJQvHo/s1600/include_files.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" class="noBorder noBackground" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicmQp9xe-hJtIGIjmdgCyqmqFEbgpZ16P0jDJd253znqNCXZbQZVlRvaTpsXBB6CkXmP0LPigevV9_NmxZtRKdyrylGczkYiLrVnorG8MnHiBZmQpWGsSxG_IpyVyS2jDq_H1AKIJQvHo/s640/include_files.png" width="550" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
Notes:
<br />
Step 4 removes the Font Awesome reference.<br />
Step 5 uses the Font Apex CSS file reference from above step. Notice that the .min was replaced by #MIN#<br />
<blockquote class="tr_bq">
<u>From help text:</u><br />
<i>If you provide a minified version of your file you can use the substitution string #MIN# to include .min or #MIN_DIRECTORY# to include minified/ in your file URL for a regular page view and an empty string if the page is viewed in debug mode. </i></blockquote>
</blockquote>
<br />
At this point, if you try to run your application, you should be able to see most of the Font Apex icons.<br />
<br />
There are some tweaks we still need to do so that everything is displayed nicely.<br />
First, there is still a class that uses the "font-family: font-awesome;", which is used by the expand/collapse navigation menu button.<br />
<br />
The other thing we need to change is the height of the icons.<br />
Font Awesome uses 14x14 icons whereas Font Apex uses 16x16 icons. Some icons might not be displayed correctly. The expand/collapse navigation menu button is also one of those.<br />
<br />
Here's the CSS that is required to fix these.<br />
<br />
<pre class="line-numbers"><code class="language-css">.t-Icon[class*=' fa-'],.t-Icon[class^=fa-]{
font-family: font-apex!important;
font-size: initial;
}
.t-TreeNav .a-TreeView-node--topLevel>.a-TreeView-content .fa{
font-size: initial;
}
</code></pre>
<br />
Enjoy Font Apex in your Apex 5.0 applications!
<br />
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
Edit 1: The Custom Prefix Class attribute needs to be set to "fa"<br />
<br />
Edit 2: Scott Wesley has a nice followup to this: <a href="http://www.grassroots-oracle.com/2017/03/font-apex-between-versions.html" target="_blank">http://www.grassroots-oracle.com/2017/03/font-apex-between-versions.html</a></blockquote>
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com7tag:blogger.com,1999:blog-267713902572011003.post-26890639389510571262016-12-02T16:03:00.004-05:002020-03-17T16:22:46.436-04:00Overlay Side Navigation Menu<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/12/02/overlay-side-navigation-menu';
</script>
In the last couple of weeks, I've been playing with the side navigation menu. By default, the side navigation menu "pushes" the page content back and forth as it expands and collapses.<br />
Which looks just like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRc703MQDopVl6hdyx1ioFvxY-6WLgGqhPiRCb9VRUo7e0dxL-eDhpnHmaMLJnFjOb8jBiFFAWcVzDK3WxoICrV-eYkyrDj2gpJs6Z0As_7ZV2_GkeKNEbaz3AwIeLdX-c2A3PthFUo-Q/s1600/Default+Side+Menu.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRc703MQDopVl6hdyx1ioFvxY-6WLgGqhPiRCb9VRUo7e0dxL-eDhpnHmaMLJnFjOb8jBiFFAWcVzDK3WxoICrV-eYkyrDj2gpJs6Z0As_7ZV2_GkeKNEbaz3AwIeLdX-c2A3PthFUo-Q/s320/Default+Side+Menu.gif" width="255" /></a></div>
<br />
<br />
By overriding the Universal Theme's CSS related to the side navigation menu, I was able to make the menu display as an overlay.<br />
<br />
I've also tested the solution on the Apex 5.1 EA2 and noticed that the html markup of the menu changed quite a bit in order to handle RTL applications.<br />
<br />
You can retrieve both CSS here:<br />
<a href="https://github.com/maxime-tremblay/apex-css-overlay-sidemenu" target="_blank">https://github.com/maxime-tremblay/apex-css-overlay-sidemenu</a><br />
<br />
Then will need to include the corresponding CSS file either in the theme roller's custom CSS attribute or as an external file in your application's CSS files.<br />
<br />
Additionally, by default, the side navigation menu remembers the previous state it was in. So if on a page you expand the menu and refresh it, the menu will be rendered as expanded.<br />
<br />
What we can do to prevent that from happening is have some JavaScript code execute on page load that is going to collapse the menu if it's expanded.<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">$('.t-PageBody.js-navExpanded #t_Button_navControl').click();
</code></pre>
</blockquote>
<br />
That code can be executed as a dynamic action on page 0 or in a global JavaScript file so that it's going to affect all pages in the application.<br />
<br />
You will get something that looks like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRLajjVHeIEMumq4SKtwQM7_Sw2WYwHQwxMCTvF65OAsv6YgCvZvZfM6o8ZAPAae_tMQv0rCuEOk36Va0u8uRygDT9vhuqYtYb7qjzlSUCAkghKGaW7LT7r7bUi-ikHEFzAWalhwjZrsA/s1600/Overlay+Side+Menu.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRLajjVHeIEMumq4SKtwQM7_Sw2WYwHQwxMCTvF65OAsv6YgCvZvZfM6o8ZAPAae_tMQv0rCuEOk36Va0u8uRygDT9vhuqYtYb7qjzlSUCAkghKGaW7LT7r7bUi-ikHEFzAWalhwjZrsA/s320/Overlay+Side+Menu.gif" width="255" /></a></div>
<br />
<br />
If you would like to have the menu be fullscreen you can simply uncomment the fullscreen part at the end of the CSS file.<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2600" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com10tag:blogger.com,1999:blog-267713902572011003.post-18839803850599634992016-11-24T12:13:00.000-05:002020-03-17T16:22:55.232-04:00Right Side Column Page and Validation Error Message Region<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/11/24/right-side-column-page-and-validation';
</script>
If you ever used the "Right Side Column" page template, you might have noticed that the validation error message region is displayed under the right side region's expand/collapse trigger button.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP8mS5qOrWKCduZTILo5ra4aBwz5K-vSf8t-hAojvoZRJo4tAjYt6MhobYHK_3DS-iSknUPh-uuWc8qCuI5Sit8FvyQPOvPIDBEpSxhN4rbgi9HR4Grj6qjd2aXW_gOgqKsJXZyl39PWE/s1600/Right+Side+Column+Page+and+Validation+Error+Message+Region.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP8mS5qOrWKCduZTILo5ra4aBwz5K-vSf8t-hAojvoZRJo4tAjYt6MhobYHK_3DS-iSknUPh-uuWc8qCuI5Sit8FvyQPOvPIDBEpSxhN4rbgi9HR4Grj6qjd2aXW_gOgqKsJXZyl39PWE/s400/Right+Side+Column+Page+and+Validation+Error+Message+Region.png" width="400" /></a></div>
<br />
As you can see above, the expand/collapse trigger button is on top of the close notification "X" button.<br />
<br />
There are two ways to go in order to fix that, both using CSS only.<br />
<br />
<u>The first method</u> is to add some right margin to the notification region.<br />
<br />
<blockquote>
<pre class="line-numbers"><code class="language-css">.js-rightExpanded .t-Body-content .t-Body-alert,
.js-rightCollapsed .t-Body-content .t-Body-alert {
margin-right: 40px; /* Width of the right side region's trigger button */
}
</code></pre>
</blockquote>
<br />
It will then look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAP1nKp6RWStseHEIm_be2-HnLxDWhv1O8hv9Onb8aANltTrQfuVS4mYiE3moaW5tux-DLCmRZ4rMNUaW2RAgrlUVyR2eeA3NEOL5uidGJf_6TMN5zvLKipwfrmyXB2Z7pDU9LynxNoGE/s1600/Right+Side+Column+Page+and+Validation+Error+Message+Region+-+Fix+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAP1nKp6RWStseHEIm_be2-HnLxDWhv1O8hv9Onb8aANltTrQfuVS4mYiE3moaW5tux-DLCmRZ4rMNUaW2RAgrlUVyR2eeA3NEOL5uidGJf_6TMN5zvLKipwfrmyXB2Z7pDU9LynxNoGE/s400/Right+Side+Column+Page+and+Validation+Error+Message+Region+-+Fix+2.png" width="400" /></a></div>
<br />
<u>The second method</u> is to reposition the notification region on top of the right side region's trigger button.<br />
<br />
<blockquote>
<pre class="line-numbers"><code class="language-css">.js-rightExpanded .t-Body-content .t-Body-alert,
.js-rightCollapsed .t-Body-content .t-Body-alert {
position: relative; /* Need to position the div for the z-index to work */
z-index: 500; /* z-index of right side column is 490 */
}
</code></pre>
</blockquote>
<br />
It will then look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDZU2aCwgd5SdFs2y9wdUWuYcGXsAJRAANWu9ra0Ue1fUtSejPHW7ji5ka2HSf1z3gd2nNg9wZcquzmLm93fbDrhvmgG243zrHsNXu275n7sQlIHia76K0OYkKxx5zrMlxV7f7oK8OvVU/s1600/Right+Side+Column+Page+and+Validation+Error+Message+Region-+Fix+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDZU2aCwgd5SdFs2y9wdUWuYcGXsAJRAANWu9ra0Ue1fUtSejPHW7ji5ka2HSf1z3gd2nNg9wZcquzmLm93fbDrhvmgG243zrHsNXu275n7sQlIHia76K0OYkKxx5zrMlxV7f7oK8OvVU/s400/Right+Side+Column+Page+and+Validation+Error+Message+Region-+Fix+1.png" width="400" /></a></div>
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-55603488341413311822016-11-24T12:04:00.000-05:002020-03-17T16:23:02.713-04:00Interactive Report Alternating Rows<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/11/24/interactive-report-alternating-rows';
</script>
<img border="0" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC-xuOSGBR_Vg-j4FhipO6W9JhIBxfllddc6gD90j3NYCkyBGntAyTYOgEcMthM89N4kDt6JQZ77LdWYCk_7it3U_YTiUdAhiEgCWrlq89vTa2w3fT_AiueMPuD4PBXMIvKnb0clt7MBY/s200/Alternating+Rows+2.png" style="display: none;" width="200" />
<br />
For classic reports there is a region attribute template option to have the rows have alternating row color.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkn7vc_WfwAUTAab3PYzp3fvanCi8VEGQnbagtD7JfHbZnbW-h4yqTNp-3cyc0fcpA5YOa0Q1SJ5Wj-xCh66GrCgDb7fiqm63Qk1qmHPlnJpIaOaEqRx9PbEt1wMqtNVKxaZfPEu7Jo6Q/s1600/Alternating+Rows+-+Classic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkn7vc_WfwAUTAab3PYzp3fvanCi8VEGQnbagtD7JfHbZnbW-h4yqTNp-3cyc0fcpA5YOa0Q1SJ5Wj-xCh66GrCgDb7fiqm63Qk1qmHPlnJpIaOaEqRx9PbEt1wMqtNVKxaZfPEu7Jo6Q/s320/Alternating+Rows+-+Classic.png" width="320" /></a></div>
<br />
That template option is not part of the interactive report template options.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhtNeYURGk2l-HgDJ67Z9ArUjWIyMobBlpvzGfZGGGZPfd3hstJN-_P44-SUlszyymSteNo8gMbxr1oUXFa4KmH6GjaiT2SDvqpuGuBy6v_bU1P7uD5Q3BgHEhJBV29rV2rNDX8sOU9gE/s1600/Alternating+Rows+-+Interactive.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhtNeYURGk2l-HgDJ67Z9ArUjWIyMobBlpvzGfZGGGZPfd3hstJN-_P44-SUlszyymSteNo8gMbxr1oUXFa4KmH6GjaiT2SDvqpuGuBy6v_bU1P7uD5Q3BgHEhJBV29rV2rNDX8sOU9gE/s320/Alternating+Rows+-+Interactive.png" width="320" /></a></div>
<br />
We can achieve the same effect in an interactive using once again some CSS.<br />
<br />
<pre class="line-numbers"><code class="language-css">.customAlternatingRow .a-IRR-table tr:nth-child(odd) td {
background-color: yellow;
}
.customAlternatingRow .a-IRR-table tr:nth-child(even) td {
background-color: yellowgreen;
}
</code></pre>
<br />
The only thing left to do is to add the "customAlternatingRow" class to your region (under Appearance, CSS Classes) or at the page level.<br />
<br />
It will then look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8C3yEkZPayxhlnLSeZaOPd-8Gdn53JzBc3nuYb5GYyIaI3giUc-8Ge3f4ExlnMKF7uyQSUokZMkZfIIlCmG21ocW8r23mPrmq1QDq1iY2Lwps8EUEm4OaLWRW3XOkRnG2SRbCP_9BcBk/s1600/Alternating+Rows.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8C3yEkZPayxhlnLSeZaOPd-8Gdn53JzBc3nuYb5GYyIaI3giUc-8Ge3f4ExlnMKF7uyQSUokZMkZfIIlCmG21ocW8r23mPrmq1QDq1iY2Lwps8EUEm4OaLWRW3XOkRnG2SRbCP_9BcBk/s400/Alternating+Rows.png" width="400" /></a></div>
<br />
The classic report is using <span style="background-color: #fcfcfc; border-color: #000; display: inline-block; height: 15px; width: 15px;"> </span> <span style="font-family: "courier new" , "courier" , monospace;">#fcfcfc</span> (very light gray) for the odd rows and nothing for the even rows.<br />
<br />
<pre class="line-numbers"><code class="language-css">.customAlternatingRow .a-IRR-table tr:nth-child(odd) td {
background-color: #fcfcfc;
}
</code></pre>
<br />
Which would look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC-xuOSGBR_Vg-j4FhipO6W9JhIBxfllddc6gD90j3NYCkyBGntAyTYOgEcMthM89N4kDt6JQZ77LdWYCk_7it3U_YTiUdAhiEgCWrlq89vTa2w3fT_AiueMPuD4PBXMIvKnb0clt7MBY/s1600/Alternating+Rows+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC-xuOSGBR_Vg-j4FhipO6W9JhIBxfllddc6gD90j3NYCkyBGntAyTYOgEcMthM89N4kDt6JQZ77LdWYCk_7it3U_YTiUdAhiEgCWrlq89vTa2w3fT_AiueMPuD4PBXMIvKnb0clt7MBY/s400/Alternating+Rows+2.png" width="400" /></a></div>
<br />
<br />
If you would like to also change the highlighted/hovered row color, you can use the following CSS:<br />
<br />
<pre class="line-numbers"><code class="language-css">.customRowHighlight .a-IRR-table tr:hover td {
background-color: #f9f9f9;
}
</code></pre>
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
<b><i><u>Note:</u></i></b><br />
If you would like this to be applied on all interactive reports in your application, simply remove the ".customAlternatingRow" and/or ".customRowHighlight" from the CSS.</blockquote>
<br />
Browser Support of the :nth-child() Selector (from <a href="http://www.w3schools.com/cssref/sel_nth-child.asp" target="_blank">w3schools</a>)<br />
<br />
<table style="border-collapse: collapse;">
<tbody>
<tr style="background-color: rgba(255, 255, 255, .8);">
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px 11px 16px; text-align: left; vertical-align: middle; width: 150px;">Selector</th>
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px; vertical-align: middle; width: 80px;" title="Chrome">Chrome</th>
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px; vertical-align: middle; width: 80px;" title="Internet Explorer / Edge">IE</th>
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px; vertical-align: middle; width: 80px;" title="Firefox">Firefox</th>
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px; vertical-align: middle; width: 80px;" title="Safari">Safari</th>
<th style="border: 1px solid rgba(0 , 0 , 0 , 0.2); color: #555555; font-weight: normal; height: 32px; padding: 11px 5px; vertical-align: middle; width: 80px;" title="Opera">Opera</th>
</tr>
<tr style="background-color: rgba(255,255,255,.9);">
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px 8px 8px 16px; vertical-align: top;">:nth-child()</td>
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px; text-align: center; vertical-align: top;">4.0</td>
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px; text-align: center; vertical-align: top;">9.0</td>
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px; text-align: center; vertical-align: top;">3.5</td>
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px; text-align: center; vertical-align: top;">3.2</td>
<td style="border: 1px solid rgba(0, 0, 0, .2); color: #555555; padding: 8px; text-align: center; vertical-align: top;">9.6</td>
</tr>
</tbody>
</table>
<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2900" target="_blank">Demo Application</a>
<br />
<br />
<br />Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com7tag:blogger.com,1999:blog-267713902572011003.post-25049219970710137872016-11-21T09:48:00.000-05:002020-03-17T16:23:09.885-04:00Auto Publish All Translations When Importing an Application<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/11/21/auto-publish-all-translations-when';
</script>
When working with translated application, once everything is done in the source application, you need to seed all the translations, then translate what needs to be and then publish all the translations.<br />
When migrating the application, you will have two choices.<br />
<br />
<ol>
<li>Export the source application and export all mapped translated applications. Then import all the application in the other environment</li>
<li>Export the source application only including the translations (export preferences attribute). Then import the application in the other environment. Then publish all translations.</li>
</ol>
<br />
I usually go with the second method.<br />
If the person that migrates the application knows their way around Apex, it's not that big of a deal.<br />
But when it's not the developer that migrates the applications (e.g. when it's the DBAs), it can be more complicated to explain them the complete procedure.<br />
Furthermore, it could happen that the person who imports the application simply forgets to publish the translations afterwards.<br />
<br />
I thought it would be great if the option to include translations when exporting the application also published them when importing the application, but unfortunately, it's not the case.<br />
<br />
One thing you can do is to use the apex_lang.publish_application API<br />
<a href="http://docs.oracle.com/cd/E59726_01/doc.50/e39149/apex_lang.htm#CHDCBEDE" target="_blank">http://docs.oracle.com/cd/E59726_01/doc.50/e39149/apex_lang.htm#CHDCBEDE</a><br />
<br />
You can use it just like in the API's documentation example as a script you would need to run after the import process.<br />
<br />
But it would be great if that was executed as part of the install process.<br />
<br />
Supporting Objects to the rescue!!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoNSjAB6-u2fLbdkkMpo1zEzoOU6f1EJ0SHjQb-HNJUNXXDfYluiyXYbAgLPJ794B1Vp7-N2MdBUEuD1mJSvYNJMV9Q5_h2kawlLn325f9A-J4OqP1i-TDnJWZUbf5eKjKkClgrCLqplY/s1600/apt+-+supporting+objects.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Supporting Objects" border="0" height="95" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoNSjAB6-u2fLbdkkMpo1zEzoOU6f1EJ0SHjQb-HNJUNXXDfYluiyXYbAgLPJ794B1Vp7-N2MdBUEuD1mJSvYNJMV9Q5_h2kawlLn325f9A-J4OqP1i-TDnJWZUbf5eKjKkClgrCLqplY/s400/apt+-+supporting+objects.png" title="Supporting Objects" width="400" /></a></div>
<br />
<br />
What we need to do is to create an Installation Script from scratch using the Editor that simply calls the API.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8dQnzXj9me17mahNmUDv1phnHvS5UPq_dI3acHiNWzougcTWtTPkxRh0Jhbo3jmCCLv5sCp9UucTKxem5YX6z5QsN7PUVITF0u-w6-rC1qU-ktZOUrFQMOJgiudjh_q8dpXFtJmatUZg/s1600/apt+-+create+installation+script+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8dQnzXj9me17mahNmUDv1phnHvS5UPq_dI3acHiNWzougcTWtTPkxRh0Jhbo3jmCCLv5sCp9UucTKxem5YX6z5QsN7PUVITF0u-w6-rC1qU-ktZOUrFQMOJgiudjh_q8dpXFtJmatUZg/s400/apt+-+create+installation+script+1.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFIOtiVfiAlGSRDoVVXTqwb-x99U2MjVBfGC3szZtyDQhn6XfGzQa5CjahTA8hPddR6ASCNK69tjp_MqEQmcv7T_gB-sAsVLCVN4z1DGWP0jIseXHFQScRJF8ux6jvmmkSwEkXw2KJFJM/s1600/apt+-+create+installation+script+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFIOtiVfiAlGSRDoVVXTqwb-x99U2MjVBfGC3szZtyDQhn6XfGzQa5CjahTA8hPddR6ASCNK69tjp_MqEQmcv7T_gB-sAsVLCVN4z1DGWP0jIseXHFQScRJF8ux6jvmmkSwEkXw2KJFJM/s400/apt+-+create+installation+script+2.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCl1qV4r6YuzDOHLujtTRdnkXdG8XCdOenwzEOF24EYA26O_5DiTFt_y1mXZaw2dvF7bwGF26PlfuVjd4luOJxyUei7yPXUIbINfaXvcX8wrx-aSX_AX7bKA8ibfAYd9G24_0_YJyYpk/s1600/apt+-+create+installation+script+3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCl1qV4r6YuzDOHLujtTRdnkXdG8XCdOenwzEOF24EYA26O_5DiTFt_y1mXZaw2dvF7bwGF26PlfuVjd4luOJxyUei7yPXUIbINfaXvcX8wrx-aSX_AX7bKA8ibfAYd9G24_0_YJyYpk/s400/apt+-+create+installation+script+3.png" width="400" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Ej9WuxCQSmmPPygrSdrJtwmANCX-AB90kliAcCVwJUUCXgSiXETH-pM-WnBjdNOYukKjy7fUidCJEn8n16wtH-c0chn5wPz1LedtF0MGF0dN7hcqiyAVbJAvGMHiT1xz5nmzeYjYMhs/s1600/apt+-+create+installation+script+4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Ej9WuxCQSmmPPygrSdrJtwmANCX-AB90kliAcCVwJUUCXgSiXETH-pM-WnBjdNOYukKjy7fUidCJEn8n16wtH-c0chn5wPz1LedtF0MGF0dN7hcqiyAVbJAvGMHiT1xz5nmzeYjYMhs/s400/apt+-+create+installation+script+4.png" width="400" /></a></div>
<span id="goog_1599088203"></span><span id="goog_1599088204"></span><br />
<br />
<br />
Use below code:<br />
<pre class="line-numbers"><code class="language-sql">
declare
-- if using apex 5.0+, you can use 'apex_application_install.get_application_id' to retrieve the application id
-- otherwise, you need to hardcode the application id
l_app_id number := apex_application_install.get_application_id;
begin
for i in (select primary_application_id, translated_app_language
from apex_application_trans_map
where primary_application_id = l_app_id)
loop
apex_lang.publish_application(i.primary_application_id, i.translated_app_language);
end loop;
end;
/
</code></pre>
<br />
Then, when you'll export your application, make sure you include the supporting objects and that you export the translations.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5My_euRCFBsczH73Hs6uqkuPvnSadCg9ip0GLf343XsiL-x5bME3iCJE33aRgmIWtKRk_Zgn_Jxol7y1c9h6xe9DhmwCDvzU_eJcg5EtnIJsqg7-HQCd-6QZS-t0hwr93PW6Tg0Z8cnk/s1600/apt+-+export+application.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5My_euRCFBsczH73Hs6uqkuPvnSadCg9ip0GLf343XsiL-x5bME3iCJE33aRgmIWtKRk_Zgn_Jxol7y1c9h6xe9DhmwCDvzU_eJcg5EtnIJsqg7-HQCd-6QZS-t0hwr93PW6Tg0Z8cnk/s400/apt+-+export+application.png" width="400" /></a></div>
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
Note: Depending on how you will import the application, the "Export Supporting Object Definitions" attribute has to be set to either "Yes" or "Yes and Install on Import Automatically".<br />
<br />
Looking at the attribute's help:
<br />
<ul>
<li><b>Yes</b> Includes supporting object definitions in the application export. Does not automatically load supporting objects when invoked from a command line.</li>
</ul>
<ul>
<li><b>Yes and Install on Import Automatically</b> Includes supporting object definitions and a call to install supporting objects in the application export. This option is valid only for command line installs. When application imports from the command line, it automatically installs or upgrades the supporting objects.</li>
</ul>
So, if you import the application from Apex either will work, but if you import from a command line, you should set the attribute to "Yes and Install on Import Automatically".</blockquote>
<br />
When you'll import the application, simply choose to install the supporting objects.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQqPV8w55qzoGy59_g7ZMeCcvrf9kxOnVYylY0jLuhR87zIqpRaSsDBXQjEQvJYhuT3VtvmebE_YJC7MRmvbSz2conKhtDsm1bXnX03Y5XW_p6abGWNmcNG_oYrIPyKndBm4kGFRgxW10/s1600/apt+-+install+application+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQqPV8w55qzoGy59_g7ZMeCcvrf9kxOnVYylY0jLuhR87zIqpRaSsDBXQjEQvJYhuT3VtvmebE_YJC7MRmvbSz2conKhtDsm1bXnX03Y5XW_p6abGWNmcNG_oYrIPyKndBm4kGFRgxW10/s400/apt+-+install+application+1.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHKaIZ5dk5VKrnY_jJvE8uJyoXZBt4zqL9dnR2oJiYsfWKOBEeBKnwP9ItZZYIUyykJy_fokSEQt0eY6n9F2y8FpTFPGd1azzaGWiU5SRWoaInYtfXdPvoolLB_4lvRnle8EksRdyLUOg/s1600/apt+-+install+application+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHKaIZ5dk5VKrnY_jJvE8uJyoXZBt4zqL9dnR2oJiYsfWKOBEeBKnwP9ItZZYIUyykJy_fokSEQt0eY6n9F2y8FpTFPGd1azzaGWiU5SRWoaInYtfXdPvoolLB_4lvRnle8EksRdyLUOg/s400/apt+-+install+application+2.png" width="400" /></a></div>
<br />
<br />
Voila, your application's translations will be automatically published as part of the import process.<br />
<br />
EDIT: Added a note regarding the "Export Supporting Object Definitions" attribute.Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com2tag:blogger.com,1999:blog-267713902572011003.post-57363136472023912722016-11-14T15:42:00.001-05:002020-03-17T16:23:19.288-04:00Required Asterisk Left of Item Label<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/11/14/required-asterisk-left-of-item-label';
</script>
If you ever had a customer asked you to move the required asterisk of the item's label before the item itself, you probably had to copy the existing template and move the span that holds the asterisk before the item itself then you had to go through all you labels to change the template.<br />
<br />
Lately, I've been testing my demo application in the EA of Apex 5.1 and looking at the code and how things changed from 5.0 to 5.1.<br />
<br />
Among all the changes, I noticed that the Apex team started to use the CSS3 <a href="http://www.w3schools.com/cssreF/css3_pr_order.asp" target="_blank">order property</a>.<br />
<blockquote class="tr_bq">
<b>Definition</b><br />
The order property specifies the order of a flexible item relative to the rest of the flexible items inside the same container.<br />
<b>Note:</b> If the element is not a flexible item, the order property has no effect.</blockquote>
<br />
Basically, this property can reorder items within the same container granted that the container is using the flex property.<br />
<br />
To move the asterisk span using only CSS, we can use the following code:
<br />
<pre class="line-numbers"><code class="language-css">.t-Form-fieldContainer .t-Form-labelContainer {
display: flex; /* Make sure the container is using flex */
justify-content: flex-end; /* Keep items right aligned */
}
.t-Form--labelsAbove .t-Form-fieldContainer .t-Form-labelContainer,
.t-Form--leftLabels .t-Form-fieldContainer .t-Form-labelContainer,
.t-Form-fieldContainer.t-Form-fieldContainer--stacked .t-Form-labelContainer {
justify-content: flex-start; /* Keep items left aligned */
}
.t-Form-fieldContainer .t-Form-labelContainer .t-Form-required{
order: 1; /* Asterisk as first element */
}
.t-Form-fieldContainer .t-Form-labelContainer .t-Form-label{
order: 2; /* Label as second element */
}</code></pre>
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2700" target="_blank">Demo Application</a>
<br />
<br />
EDIT1: Fix an issue with above labels.
<br />
<br />
EDIT2: Fix an issue with "Blank with Attributes" region template.<br />
<br />
EDIT3: Apex 5.1 now handles the required asterisk using CSS only and the position now depends on the label's alignment.<br />
Right aligned: asterisk before<br />
Left aligned: asterisk afterMaxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0tag:blogger.com,1999:blog-267713902572011003.post-75719011421482501492016-11-04T12:53:00.002-04:002020-03-17T16:23:53.473-04:00Handling Dialog Cancel Event<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/11/04/handling-dialog-cancel-event';
</script>
If you ever had to handle a modal dialog close to trigger some action on the parent page, you probably used a dynamic action using the "Dialog Closed" event.<br />
<br />
When closing a modal dialog there are two ways to do it.<br />
<ol>
<li>Close</li>
<ul>
<li>Using an after submit process of type "Close Dialog";</li>
<li>Using a dynamic action with a "Close Dialog" action;</li>
<li>Branching to a page that has a "Normal" page mode.</li>
</ul>
<li>Cancel</li>
<ul>
<li>Using a dynamic action with a "Cancel Dialog" action;</li>
<li>Clicking on the top right "X" icon/button.</li>
</ul>
</ol>
<br />
When using a branch to close the modal dialog, the modal dialog will close then it's parent will branch to the specified page.<br />
<br />
Except when using the branch method, when you close the modal dialog, Apex will trigger a "Dialog Close" event. Then, on the parent page, you will be able to handle it using a dynamic action "Dialog Closed" event.<br />
The thing is that the cancel methods will not trigger any event on the parent page. So, by default, you won't be able to handle the dialog close when it was cancelled.<br />
<br />
One way to have both the close and cancel method trigger an even on the parent page would be to override the dialog close event (Apex is using <a href="http://api.jqueryui.com/dialog/" target="_blank">jQuery's UI Dialog Widget</a>).<br />
<br />
So what we will do is this.<br />
<br />
You will need to define the following JavaScript function (either on the parent pages, on page 0 or in your JavaScript global library file)<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">function customEvent(event, data){
apex.event.trigger(document, event, data);
}
</code></pre>
</blockquote>
<br />
Then, under the modal dialog page attributes, in the dialog section, set the "Attributes" to:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">close: function() { customEvent('customDialogClose', {modalPageId: 'MODAL_CLOSE_FIXED'});}
</code></pre>
</blockquote>
<br />
What this will do is that it will trigger (on the parent page) the event "customDialogClose".<br />
The second parameter is a data attribute that could be used to differentiate modals between each other. It can can be useful if you are calling more than one on the parent page or if you want to send data back to the parent page.<br />
<br />
Finally, in your parent page you can define a custom dynamic action as follow:
<br />
<blockquote class="tr_bq">
<pre><code class="language-none">Event: Custom
Custom Event: customDialogClose
Selection Type: JavaScript Expression
JavaScript Expression: document
</code></pre>
</blockquote>
<br />
One thing to note is that the default close event will still be triggered when using the close method.<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2500" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com6tag:blogger.com,1999:blog-267713902572011003.post-42241462423186452712016-10-17T12:37:00.001-04:002020-03-17T16:24:03.996-04:00iOS Modal Scrolling<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/10/17/ios-modal-scrolling';
</script>
If you ever tried to scroll a modal page from within Safari on iOS you probably noticed that what is getting scrolled is the parent page content and not the actual modal content.<br />
<br />
There is a simple fix for that:<br />
<pre class="line-numbers"><code class="language-css">body .ui-dialog .ui-dialog-content{
-webkit-overflow-scrolling: touch;
}</code></pre>
<br />
If you're not using the built-in modal, the idea is to add the css property to the wrapping element of the iframe.<br />
Let's say you're using Skillbuilders' Modal Plugin, you can use the following:
<br />
<pre class="line-numbers"><code class="language-css">#cboxLoadedContent{
-webkit-overflow-scrolling: touch;
}</code></pre>
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2400" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0tag:blogger.com,1999:blog-267713902572011003.post-40047120606950354702016-10-11T10:53:00.000-04:002020-03-17T16:24:18.677-04:00Return Page Item From an AJAX Callback Process<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/10/11/return-page-item-from-ajax-callback';
</script>
Recently, I was working on a form that had multiple items retrieved when a select list item changed. The select list triggered a dynamic action that executed some PL/SQL code and returned item values.<br />
<br />
It was looking like that:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiieXB4KqapoZC9E5T4AONQbwC9tKqdBKEexoIbWIYlt3GszkiJphr4avF_hAHIoWzj7Vy-SvyrY7v3KIufqPPrcGPTxjZqXTpNaWdimRTILs6PwHHi_Dr4R2krKzzWVHsKLxdsQFPB3QU/s1600/da-plsql.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiieXB4KqapoZC9E5T4AONQbwC9tKqdBKEexoIbWIYlt3GszkiJphr4avF_hAHIoWzj7Vy-SvyrY7v3KIufqPPrcGPTxjZqXTpNaWdimRTILs6PwHHi_Dr4R2krKzzWVHsKLxdsQFPB3QU/s640/da-plsql.png" width="427" /></a></div>
<br />
At some point, the process became "too big" for the "Execute PL/SQL Code" action (it can only hold up to 4000 characters).<br />
<br />
So, I decided to move everything to a page "AJAX Callback" process which can hold up to 32767 characters.<br />
<br />
So I replaced the dynamic action "Execute PL/SQL Code" action with an "Execute JavaScript" action as follow:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-js">/* Show a processing image */
var lSpinner$ = apex.util.showSpinner();
apex.server.process("SOME_PROCESS",
{pageItems: "#P2300_LOV"
},
{success: function(pData) {
/* If the AJAX is successful set the value or the returned items */
if (pData.success === true){
/* Loop through the array and set the value of each item */
for (var i=0; i < pData.items.length; i++){
apex.item(pData.items[i].id).setValue(pData.items[i].value);
}
}
/* Remove the processing image */
lSpinner$.remove();
},
error: function(request, status, error) {
alert(request.responseText);
/* Remove the processing image */
lSpinner$.remove();
}
}
);
</code></pre>
</blockquote>
<br />
And I created the AJAX Callback as follow:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-sql">declare
/* Local variables */
/* Utility function to output item's id and value */
procedure output_json_item(p_item_name in varchar2,
p_item_value in varchar2
)
as
begin
apex_json.open_object;
apex_json.write('id', p_item_name);
apex_json.write('value', p_item_value, true); /* true so that null values are written as well */
apex_json.close_object;
end output_json_item;
begin
/* ********************** *
* PL/SQL Process Content *
* ********************** */
if :P2300_LOV = '1' then
:P2300_ITEM1 := 1;
:P2300_ITEM2 := 1;
:P2300_ITEM3 := 1;
:P2300_ITEM4 := 1;
elsif :P2300_LOV = '2' then
:P2300_ITEM1 := 2;
:P2300_ITEM2 := 2;
:P2300_ITEM3 := 2;
:P2300_ITEM4 := 2;
elsif :P2300_LOV = '3' then
:P2300_ITEM1 := 3;
:P2300_ITEM2 := 3;
:P2300_ITEM3 := 3;
:P2300_ITEM4 := 3;
end if;
apex_json.open_object;
apex_json.write('success', true);
apex_json.open_array('items');
/* Call the utility procedure for every item you want to return */
output_json_item('P2300_ITEM1', :P2300_ITEM1);
output_json_item('P2300_ITEM2', :P2300_ITEM2);
output_json_item('P2300_ITEM3', :P2300_ITEM3);
output_json_item('P2300_ITEM4', :P2300_ITEM4);
apex_json.close_array;
apex_json.close_object;
exception
when others then
apex_json.open_object;
apex_json.write('success', false);
apex_json.write('message', sqlerrm);
apex_json.close_object;
end;
</code></pre>
</blockquote>
<br />
The idea here is to have PL/SQL AJAX Callback execute and if it successfully completes, it will be returning the list of items along with their values as JSON on which we are going to loop through and set the items' value using the JavaScript item API.<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2300" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com9tag:blogger.com,1999:blog-267713902572011003.post-85188067472663486992016-09-29T20:22:00.003-04:002020-03-17T16:24:27.110-04:00Customizing Cards Report<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/09/29/customizing-cards-report';
</script>
The other day I was working on a cards report for a customer and they wanted to have the cards on the same line be of equal height. They also wanted to have some kind of visual indicator of what card was currently being hovered.<br />
<br />
Here's what the built-in card report looks like:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn1knGWu9rX8umacxdIseDfw3kY77gJbkzUOOAV9Pwf5Tv-06_O_T_Zt5ZsYKGymukIiNyeVjrHAJ5TGWDV-lweKb-oaNnjswRRMU7SNX_qGoCGx9ISpMh5vYcXwyOwRO2lDNKaVySXn8/s1600/cards-standard.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn1knGWu9rX8umacxdIseDfw3kY77gJbkzUOOAV9Pwf5Tv-06_O_T_Zt5ZsYKGymukIiNyeVjrHAJ5TGWDV-lweKb-oaNnjswRRMU7SNX_qGoCGx9ISpMh5vYcXwyOwRO2lDNKaVySXn8/s640/cards-standard.png" width="550" /></a></div>
<br />
<br />
First, let's have a look at the equal height for the cards on the same line.<br />
For this we'll be using the flexbox properties. If you're not familiar with flexbox, you can have a look at this article: <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" target="_blank">A Complete Guide to Flexbox</a>.<br />
<br />
Add following class to you region's CSS Class Attribute: "t-Cards--equal-height" and the following CSS to your page.<br />
<pre class="line-numbers"><code class="language-css">.t-Cards--equal-height .t-Cards {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.t-Cards--equal-height .t-Cards .t-Cards-item {
margin-bottom: 10px; /* Adds some space between lines */
}
.t-Cards--equal-height .t-Cards .t-Cards-item .t-Card,
.t-Cards--equal-height .t-Cards .t-Cards-item .t-Card .t-Card-wrap {
height: 100%;
}
</code></pre>
<br />
Result will look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhli4kN5x-P5acXkvtXfOAZtPUIq285kP7cujS2vBx2RkDjvvx5WYrnr-yfnzYQ7gMCywemzklXnHUK_BjRN9_yQSM5UxLit591X7znxrKDMOksTjxCNeSDpOUep9qY6au7swC0gSPEYtI/s1600/cards-equal-height.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhli4kN5x-P5acXkvtXfOAZtPUIq285kP7cujS2vBx2RkDjvvx5WYrnr-yfnzYQ7gMCywemzklXnHUK_BjRN9_yQSM5UxLit591X7znxrKDMOksTjxCNeSDpOUep9qY6au7swC0gSPEYtI/s400/cards-equal-height.png" width="550" /></a></div>
<br />
<br />
Now, let's highlight the header when hovering a card.<br />
Add following class to you region's CSS Class Attribute: "t-Cards--header-highlight" and the following CSS to your page.<br />
<pre class="line-numbers"><code class="language-css">.t-Cards--header-highlight .t-Cards .t-Cards-item .t-Card:hover .t-Card-titleWrap{
background-color: #c8102e;
}
.t-Cards--header-highlight .t-Cards .t-Cards-item .t-Card:hover .t-Card-titleWrap .t-Card-title {
color: #fff;
}
.t-Cards--header-highlight .t-Cards .t-Cards-item .t-Card:hover .t-Card-wrap {
border: 1px solid rgba(0,0,0,.05);
box-shadow: 0 2px 2px rgba(0,0,0,.05);
}
/* Featured Style Padding/Margin Fix */
.t-Cards--header-highlight .t-Cards.t-Cards--featured .t-Cards-item .t-Card .t-Card-titleWrap {
margin: 0 !important;
padding: 24px 16px;
}
.t-Cards--header-highlight .t-Cards.t-Cards--featured .t-Cards-item .t-Card .t-Card-body {
margin: 0 16px 24px 16px !important;
}
</code></pre>
<br />
The second part of the above CSS is to change the cards's margin to padding, we need to do this because the background-color is not affecting the margins, but it is for the paddings.<br />
<br />
Result will look like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjTIxF-Qo9eXON63W1LOpRFCgcm7V7wY_Q6Jc2a_eRniYh4Nv453sQniLpkkoCxZVPiqOdG3n8HxRpDpnZDuOBQug-o-fmI_CwtIZSud7hl3LDad0y4DGKJ0LQYhqxkUJfpCdvsPGb1m4/s1600/cards-hover.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjTIxF-Qo9eXON63W1LOpRFCgcm7V7wY_Q6Jc2a_eRniYh4Nv453sQniLpkkoCxZVPiqOdG3n8HxRpDpnZDuOBQug-o-fmI_CwtIZSud7hl3LDad0y4DGKJ0LQYhqxkUJfpCdvsPGb1m4/s400/cards-hover.png" width="550" /></a></div>
<br />
<br />
The above CSS works for all cards report styles (Basic, Compact and Featured).
<br />
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2200" target="_blank">Demo Application</a><br />
<br />
EDIT: Apex 5.1 displays cards with equal height by default.Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0tag:blogger.com,1999:blog-267713902572011003.post-32318138677438109672016-09-20T15:28:00.001-04:002020-03-17T16:24:40.646-04:00Securing Ajax Callback Process<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/09/20/securing-ajax-callback-process';
</script>
When navigating from a report page to the corresponding detail page, it's always a good practice to enable the parameters checksum to prevent users from tampering with the item values that are in the url.<br />
<br />
To enable arguments checksum, you must first set the "Page Access Protection" attribute under the page attribute security section to "Arguments must have checksum" and then for each item that is going to be assigned from the url, you need to set the "Session State Protection" to one of the "Checksum Required" value (have a look at the item's help for more details about the different types of checksum).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9NiaiVMqBd2G2hTe3WAU1QJh5UgQkkX-PutjmZTjw3lTixR_2Tl4fnurd_UKKv30xKNjqLSWjwszYNSr0aJF88I-16z-lIpZ8flqtoF6x9rwSrbhnyL_4xv3t-xZNFZyHsYAxrBR0DGM/s1600/arguments-checksum.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9NiaiVMqBd2G2hTe3WAU1QJh5UgQkkX-PutjmZTjw3lTixR_2Tl4fnurd_UKKv30xKNjqLSWjwszYNSr0aJF88I-16z-lIpZ8flqtoF6x9rwSrbhnyL_4xv3t-xZNFZyHsYAxrBR0DGM/s400/arguments-checksum.png" width="400" /></a></div>
<br />
<br />
That way the user is not going to be able to change any value from the url.<br />
<br />
I recently had to implement a similar concept using button in a report that were calling an AJAX Callback Process from a dynamic action.<br />
<br />
Here's what my report's SQL Query looked like:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-sql">select '<button onclick="void(0);"'
|| ' data-data1="' || some_table_id || '"'
|| ' data-data2="' || some_value || '"'
--|| ' data-data3="' || sys.dbms_crypto.hash(utl_raw.cast_to_raw(some_table_id || some_value || to_char(nvl(last_update_date, creation_date), :DATETIMEFORMAT)), 3) || '"' /* Where 3 -> SHA-1 from sys.dbms_crypto.hash_sh1 */
|| ' data-data3="' || apex_util.get_hash(apex_t_varchar2(some_table_id, some_value, to_char(nvl(last_update_date, creation_date), :DATETIMEFORMAT))) || '"'
|| ' class="t-Button t-Button--hot t-Button--small actionButton"'
|| ' type="button"><span class="t-Button-label">Some Action</span></button>'
/* Rest of the query */
from some_table
where /* where clauses */
</code></pre>
</blockquote>
Where data1 and data2 are the values that are needed in the AJAX Callback Process and data3 is the checksum for the previous values.<br />
To have a stronger checksum and to ensure that it is only used once, I added the record's last update date to it.<br />
DATETIMEFORMAT is an application substitution string.<br />
<br />
Note: in order to be able to use dbms_crypto, it needs to be granted to the current user (not required with the apex_util.get_hash function.<br />
For more information on the Apex API, read this <a href="http://docs.oracle.com/cd/E59726_01/doc.50/e39149/apex_util.htm#AEAPI30207" target="_blank">GET_HASH Function</a>.<br />
<br />
The corresponding dynamic action to handle the button click was as follow:<br />
<blockquote class="tr_bq">
Dynamic Action:
Event: Click<br />
jQuery Selector: ".actionButton"<br />
<pre class="line-numbers"><code class="language-javascript">var lSpinner$ = apex.util.showSpinner();
var lReportRegion$ = $(this.affectedElements);
apex.server.process("AJAX_PROCESS_NAME",
{x01: $(this.triggeringElement).data('data1'),
x02: $(this.triggeringElement).data('data2'),
x03: $(this.triggeringElement).data('data3')
},
{success: function( pData ) {
if (pData.success === true){
/* Show Sucess Message */
showSuccessMessage(pData.message);
/* Refresh Region */
lReportRegion$.trigger('apexrefresh');
}
else{
/* Show Error Message */
showErrorMessage([pData.message]);
}
lSpinner$.remove();
}
}
);
</code></pre>
</blockquote>
In the previous code, I'm using the affected element attribute to refresh my report region.<br />
<br />
Here's the AJAX Callback Process:<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-sql">declare
l_some_table_id number;
l_some_value varchar2(50);
l_checksum varchar2(32767);
--l_checksum raw(32767); --sys.dbms_crypto.hash returns raw
--l_hash_type pls_integer := sys.dbms_crypto.hash_sh1;
l_last_update varchar2(100);
begin
/* Retrieve parameters */
l_some_table_id := to_number(apex_application.g_x01);
l_some_value := apex_application.g_x02;
l_checksum := apex_application.g_x03;
select to_char(nvl(last_update_date, creation_date), :DATETIMEFORMAT)
into l_last_update
from some_table
where some_table_id = l_some_table_id;
/* Validate the checksum */
--if l_checksum = sys.dbms_crypto.hash(utl_raw.cast_to_raw(l_some_table_id || l_some_value || l_last_update), l_hash_type) then
if l_checksum = apex_util.get_hash(apex_t_varchar2(l_some_table_id, l_some_value, l_last_update)) then
/* Do something */
apex_json.open_object;
apex_json.write('success', true);
apex_json.write('message', 'Action Processed.');
apex_json.close_object;
else
apex_json.open_object;
apex_json.write('success', false);
apex_json.write('message', 'Invalid Action.');
apex_json.close_object;
end if;
exception
when no_data_found then
apex_json.open_object;
apex_json.write('success', false);
apex_json.write('message', 'Invalid Action.');
apex_json.close_object;
when others then
apex_json.open_object;
apex_json.write('success', false);
apex_json.write('message', 'Invalid Action.');
apex_json.close_object;
end;
</code></pre>
</blockquote>
<br />
<br />
Basically what we do in the process is to recreate a checksum based on the parameters' values and to compare it with the checksum parameter and if they match we execute the code that needs to run.
<br />
<br />
Note: Edited above code to use the Apex API: apex_util.get_hash. Commented out everything related to dbms_crypto for reference purpose.Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com2tag:blogger.com,1999:blog-267713902572011003.post-7906603684809508492016-09-09T11:30:00.002-04:002020-03-17T16:26:23.497-04:00Adding a Clear Icon to an Item<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/09/09/adding-clear-icon-to-item';
</script>
Here's how to add a clear icon to an item (similar to the calendar icon of the datepicker item).<br />
Since the datepicker's icon has the same look and feel as what we want, let's reuse the same CSS and html.<br />
<br />
Let's inspect the html code of the datepicker's icon:<br />
<br />
<pre class="line-numbers"><code class="language-html"><button class="ui-datepicker-trigger a-Button a-Button--calendar" type="button">
<span class="a-Icon icon-calendar"></span>
<span class="u-VisuallyHidden">Popup Calendar: Date Picker</span>
</button>
</code></pre>
<br />
<ul>
<li>ui-datepicker-trigger: class used to handle the click event<ul>
<li>Let's rename that to 'clearItem-trigger'</li>
</ul>
</li>
<li>a-Button: standard look and feel of buttons<ul>
<li>Let's reuse it as we want the same look and feel</li>
</ul>
</li>
<li>a-Button--calendar: additional css for the calendar icon<ul>
<li>Let's rename that to 'a-Button--clearInput'</li>
</ul>
</li>
<li>icon-calendar: image of the calendar</li>
<ul>
<li>Let's replace it with a clear icon: 'icon-remove'</li>
</ul>
</ul>
We can then retrieve and adapt the CSS for the above classes from the Core.min.css.<br />
We will then have the following CSS:<br />
<pre class="line-numbers"><code class="language-css">.t-Form-inputContainer .a-Button--clearInput{
margin-left: -.1rem;
order: 3; /* Apex 5.1: Set the correct order */
}
.t-Form--large .a-Button.a-Button--clearInput,
.t-Form-fieldContainer--large .a-Button.a-Button--clearInput {
padding: .8rem 1.2rem
}
.t-Form--xlarge .a-Button.a-Button--clearInput,
.t-Form-fieldContainer--xlarge .a-Button.a-Button--clearInput {
padding: 1.4rem 1.2rem
}
.t-Form--login .a-Button.a-Button--clearInput {
padding: 1rem 1.2rem
}
</code></pre>
<br />
That's for the visual aspect of the icon.<br />
Let's now add the following JavaScript code that will add the remove icon and that will handle the click event.<br />
<br />
JavaScript code on page page load:<br />
<pre class="line-numbers"><code class="language-javascript">$('.clearInput').each(function(){
var lTriggerHtml = '<button class="clearInput-trigger a-Button a-Button--clearInput" data-item_id="' + $(this).attr('id') + '" type="button">'
+ '<span class="a-Icon icon-remove"></span>'
+ '<span class="u-VisuallyHidden">Clear Item\'s Value</span>'
+ '</button>';
$(this).after(lTriggerHtml);
});
$('.clearInput-trigger').click(function(){
$('#' + $(this).data('item_id')).val('');
});
</code></pre>
<br />
The first part will add the clear button after each element that has the 'clearInput' class.<br />
The second part is used to handle the click event.<br />
<br />
Now you simply have to add the 'clearInput' class (under the item's Advanced properties) to each item you want the clear button to be added.<br />
<br />
One thing to note is that the above code will not trigger the item's change event.<br />
If you would also like to trigger the change event, we could add an additionnal CSS class to the item like 'clearInput--change' and update the second part of the JavaScript code to:<br />
<br />
We need to add the two following classes:<br />
<pre class="line-numbers"><code class="language-javascript">$('.clearInput-trigger').click(function(){
var triggeringElement = $('#' + $(this).data('item_id'));
triggeringElement.val('');
if (triggeringElement.hasClass('clearInput--change')){
triggeringElement.change();
}
});
</code></pre>
<br />
We also need to update the JavaScript Code that adds the button so that it assigns the corresponding CSS class to the button.<br />
<pre class="line-numbers"><code class="language-javascript">$('.clearInput').each(function(){
var lClearInputClass = $(this).hasClass('clearInput--inside') ? 'a-Button--clearInputInside': 'a-Button--clearInput';
var lTriggerHtml = '<button class="clearInput-trigger a-Button ' + lClearInputClass + '" data-item_id="' + $(this).attr('id') + '" type="button">'
+ '<span class="a-Icon icon-remove"></span>'
+ '<span class="u-VisuallyHidden">Clear Item\'s Value</span>'
+ '</button>';
$(this).after(lTriggerHtml);
});
</code></pre>
<br />
Now supposed that you would like to have the icon be inside the element.<br />
You need to have the element has right padding (equal to the width of the icon, 32px in our case) and you need to move the icon left by the same amount.<br />
<br />
<pre class="line-numbers"><code class="language-css">.clearInput--inside{
padding-right: 32px !important;
}
.t-Form-inputContainer .a-Button--clearInputInside{
margin-left: -32px;
}
</code></pre>
<br />
Simply have to set the 'clearInput clearInput--inside' class (under the item's Advanced properties) to each item you want the clear button to be added inside.<br />
<br />
Final JavaScript:<br />
<pre class="line-numbers"><code class="language-javascript">$('.clearInput').each(function(){
var lClearInputClass = $(this).hasClass('clearInput--inside') ? 'a-Button--clearInputInside': 'a-Button--clearInput';
var lTriggerHtml = '<button class="clearInput-trigger a-Button ' + lClearInputClass + '" data-item_id="' + $(this).attr('id') + '" type="button">'
+ '<span class="a-Icon icon-remove"></span>'
+ '<span class="u-VisuallyHidden">Clear Item\'s Value</span>'
+ '</button>';
$(this).after(lTriggerHtml);
});
$('.clearInput-trigger').click(function(){
var triggeringElement = $('#' + $(this).data('item_id'));
triggeringElement.val('');
if (triggeringElement.hasClass('clearInput--change')){
triggeringElement.change();
}
});
</code></pre>
<br />
Final CSS:<br />
<pre class="line-numbers"><code class="language-css">.clearInput--inside{
padding-right: 32px !important;
}
.t-Form-inputContainer .a-Button--clearInputInside{
margin-left: -32px;
}
.t-Form-inputContainer .a-Button--clearInput{
margin-left: -.1rem;
order: 3; /* Apex 5.1: Set the correct order */
}
.t-Form--large .a-Button.a-Button--clearInput,
.t-Form-fieldContainer--large .a-Button.a-Button--clearInput {
padding: .8rem 1.2rem
}
.t-Form--xlarge .a-Button.a-Button--clearInput,
.t-Form-fieldContainer--xlarge .a-Button.a-Button--clearInput {
padding: 1.4rem 1.2rem
}
.t-Form--login .a-Button.a-Button--clearInput {
padding: 1rem 1.2rem
}</code></pre>
<br />
Here's the end result:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsgaCHcx6vIgHCJ2TBxxLAdESQqYwTOr79TLwZ_jUL1WGEKWe_pit4EpLd8o5FPDuxhWF76AEkPaz7pgl5Pd43qtodAp3CrAL-o2gWL3cmK37cXtcrF8WQOLpkT9hfudn0t_qfKUFt8G0/s1600/input_clear_icon.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsgaCHcx6vIgHCJ2TBxxLAdESQqYwTOr79TLwZ_jUL1WGEKWe_pit4EpLd8o5FPDuxhWF76AEkPaz7pgl5Pd43qtodAp3CrAL-o2gWL3cmK37cXtcrF8WQOLpkT9hfudn0t_qfKUFt8G0/s640/input_clear_icon.gif" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:2100" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com1tag:blogger.com,1999:blog-267713902572011003.post-45831363397043506832016-06-07T15:15:00.002-04:002020-03-17T16:26:31.233-04:00Close Modal Dialog When Clicking Outside<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/06/07/close-modal-dialog-when-clicking-outside';
</script>
<div class="separator" style="clear: both; display: none; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVI5QmGhpVjXrbkFQeUS9oTdeSTYD3M2_h6veXoYcuQyq2TsrxCtFoFBJZmWnHQzrr5dTnUZwyPPlc8CnlaV5ftVzrC1Bin7wGx9cm_WOO28wBjpyOV8cAsgcFzIJa0O_NzdbHl84BLA4/s1600/close_dialog_click_outside.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVI5QmGhpVjXrbkFQeUS9oTdeSTYD3M2_h6veXoYcuQyq2TsrxCtFoFBJZmWnHQzrr5dTnUZwyPPlc8CnlaV5ftVzrC1Bin7wGx9cm_WOO28wBjpyOV8cAsgcFzIJa0O_NzdbHl84BLA4/s320/close_dialog_click_outside.gif" width="320" /></a>
</div>
<div>
A couple weeks ago someone on apex.world slack asked a question regarding how to capture the cancel dialog event.</div>
<br />
<div>
Juergen Schuster came up with a solution using the dialog's page attribute "Attributes" (under the Dialog section) to add/define the dialog with a custom close callback when initializing it.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipyzgjsfzR9F9ajbde0IWyabg5INKpbCGmbzSew6QWXyfm7trlyKu4kxGmManGvDwNW2tCAzMXTDvCSTF4cX5HUdMiWGv8tLHTt1dsrZPCtWy4m8IHVf_MpM48wX0ogNZR4UhN5PQKchU/s1600/dialog_attribute.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipyzgjsfzR9F9ajbde0IWyabg5INKpbCGmbzSew6QWXyfm7trlyKu4kxGmManGvDwNW2tCAzMXTDvCSTF4cX5HUdMiWGv8tLHTt1dsrZPCtWy4m8IHVf_MpM48wX0ogNZR4UhN5PQKchU/s320/dialog_attribute.png" width="320" /></a>
</div>
<br />
<div>
Using the same logic we can use it to define a new open callback that will trigger the close dialog method when clicking outside the dialog.</div>
<br />
<div>
Let's define the following JavaScript function on the parent page (if you're going to be using this in more than one place, I suggest you define it either on the page 0 or in a global javascript file)<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">function closeDialogClickOutside(elem){
$('.ui-widget-overlay').click(function(){
$(elem).dialog('close');
});
}
</code></pre>
</blockquote>
</div>
<br />
<div>
Then we simply have to set call the function when the dialog opens.<br />
Which we can do by setting the Dialog's attribute "Attributes" to this:
<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">open: function( event, ui ) { closeDialogClickOutside(this); }
</code></pre>
</blockquote>
</div>
<div>
<br />
Here's what you will get:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVI5QmGhpVjXrbkFQeUS9oTdeSTYD3M2_h6veXoYcuQyq2TsrxCtFoFBJZmWnHQzrr5dTnUZwyPPlc8CnlaV5ftVzrC1Bin7wGx9cm_WOO28wBjpyOV8cAsgcFzIJa0O_NzdbHl84BLA4/s1600/close_dialog_click_outside.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="" border="0" height="347" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVI5QmGhpVjXrbkFQeUS9oTdeSTYD3M2_h6veXoYcuQyq2TsrxCtFoFBJZmWnHQzrr5dTnUZwyPPlc8CnlaV5ftVzrC1Bin7wGx9cm_WOO28wBjpyOV8cAsgcFzIJa0O_NzdbHl84BLA4/s640/close_dialog_click_outside.gif" title="" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:1800" target="_blank">Demo Application</a>Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com5tag:blogger.com,1999:blog-267713902572011003.post-91750310734259624412016-05-04T21:07:00.000-04:002020-03-17T16:25:30.758-04:00Button in Region Title<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/05/04/button-in-region-title';
</script>
<br />
<blockquote class="tr_bq" style="background-color: rgba(0 , 0 , 0 , 0.2); border-radius: 30px; padding: 30px;">
Note: Instead of using the below code, it's easier to simply use the built-in button positions. Have a look at my demo application for a preview of the all the button position.</blockquote>
If you ever needed to display a button in a report header. You probably tried the "Right of Title" button position and got something like this :<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3IqRWsHSQsA1iikIDE5cuWtnr1r639WJg3jUvuWqbr58feyvJKjbQZD8_ZTKNE7-OmyLHYTVReOEdbEnpb4cBRQujQcVMSebtWLYoL0vgD6vMvs1tQWXd18bU9zLCSh7ijthR3Vbm2bo/s1600/default_button_region.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3IqRWsHSQsA1iikIDE5cuWtnr1r639WJg3jUvuWqbr58feyvJKjbQZD8_ZTKNE7-OmyLHYTVReOEdbEnpb4cBRQujQcVMSebtWLYoL0vgD6vMvs1tQWXd18bU9zLCSh7ijthR3Vbm2bo/s1600/default_button_region.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<br /></div>
<div>
The button is not right aligned in the region header, similar to what we get in an interactive report region using "Right of Interactive Report Search Bar" button region. You could always copy the region template and change it so that there is one button position in the header, but then you loose the subscription to the UT and you also have to copy every template you would want this to work.</div>
<div>
<br /></div>
<div>
We can achieve all that by simply using some CSS.</div>
<div>
<br /></div>
<div>
Let's start by defining the required CSS:</div>
<pre class="brush: css">/* Make sure the title container is stretched */
.buttonInHeader .t-Region-headerItems.t-Region-headerItems--title h2,
.buttonInHeaderWithExpand .t-Region-headerItems.t-Region-headerItems--title h2{
display: block;
}
/* Have the buttons float right */
.buttonInHeader .t-Region-headerItems.t-Region-headerItems--title button,
.buttonInHeaderWithExpand .t-Region-headerItems.t-Region-headerItems--title button{
float: right;
margin-left: 5px;
}
/* Add extra space for the expand button */
.buttonInHeaderWithExpand .t-Region-headerItems.t-Region-headerItems--buttons{
width: 40px;
}
</pre>
<div>
<br />
I like to add these class in the Theme Roller CSS so that I can then use them from anywhere.
<br />
<br />
Then we can simply add the class name in the region Class attribute.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiV2RG1ZPlJtZI1Eo-oS4fAGCZZmenluPRd9SeaW_xyNahY4yoO6W1ciK_kAvBZJS9RsE46xCoGcUzk2rNoe0mx5lwoZn3QcXPbYEvR5rGMVvgOj7v9mVEgZW9b8pS_-ukqAI1cLs80u8/s1600/button_region_attributes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiV2RG1ZPlJtZI1Eo-oS4fAGCZZmenluPRd9SeaW_xyNahY4yoO6W1ciK_kAvBZJS9RsE46xCoGcUzk2rNoe0mx5lwoZn3QcXPbYEvR5rGMVvgOj7v9mVEgZW9b8pS_-ukqAI1cLs80u8/s400/button_region_attributes.png" width="400" /></a></div>
<br />
<br />
And you will get this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu1HW45NHX0WogN63NKAD4a7T5F4lgElMTwgMiKyqsvs-16F088Hfg3bPM-rvUMu8MbHGA2364tZOHyFDLc1YzCTaYjUsYS2F53dwKOWv_6QE9nMfStgU-IrJ4SzhQA2baq1SH8jx-Vd4/s1600/custom_button_region.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu1HW45NHX0WogN63NKAD4a7T5F4lgElMTwgMiKyqsvs-16F088Hfg3bPM-rvUMu8MbHGA2364tZOHyFDLc1YzCTaYjUsYS2F53dwKOWv_6QE9nMfStgU-IrJ4SzhQA2baq1SH8jx-Vd4/s1600/custom_button_region.png" /></a></div>
<br /></div>
<div style="clear: both;">
One thing to remember is that when you have multiple buttons, they will need to be reversed in the page designer because of the float.</div>
<br />
You can have a look at my <a href="http://max-playground.ddns.net/ords/f?p=DEMO:1600" target="_blank">Demo Application</a>
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com4tag:blogger.com,1999:blog-267713902572011003.post-68854730554791060482016-04-05T12:02:00.000-04:002020-03-17T16:25:34.361-04:00Copy Theme Roller Theme From One Application to Another<!-- New Domain Redirect -->
<script type='text/javascript'>
location.href = 'https://askmax.blog/2016/04/05/copy-theme-roller-theme-from-one';
</script>
Here is how you can copy a theme roller custom theme from one application to the other.<br />
<br />
From the application that has theme your source theme, open theme roller.
Then open the developer tools and in the console run the following command<br />
<blockquote class="tr_bq">
<pre class="line-numbers"><code class="language-javascript">apex.utr.config()</code></pre>
</blockquote>
Copy that line to your clipboard.<br />
<br />
Then in the destination application, open the theme roller and the developer tools.<br />
Paste it into the console to load the configuration into Theme Roller.<br />
<br />
Then you will only need to save this configuration as a new theme.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj94bQ9tIQsjgE2yXiSbKMopQ75zunu2zXfoDVKrTXCm1DcPc255OTM-CbXYzfKxYmfKqV0JkB0u0yAkssxVThxF8FxsPL4n3dCxdkddVzyXHZpGxCOWK1wmW8LuVFc8QkC89g3hQkDUwE/s1600/copy_universal_theme.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj94bQ9tIQsjgE2yXiSbKMopQ75zunu2zXfoDVKrTXCm1DcPc255OTM-CbXYzfKxYmfKqV0JkB0u0yAkssxVThxF8FxsPL4n3dCxdkddVzyXHZpGxCOWK1wmW8LuVFc8QkC89g3hQkDUwE/s640/copy_universal_theme.gif" /></a></div>
Maxime Tremblayhttp://www.blogger.com/profile/07663723545046859479noreply@blogger.com0