In the last blog post I talked about the idea of using region plugins for defining query sources rather than acting as a standalone plugin, and the post before that: transforming apex button references into different Ext form items. This post is focused on bringing those two approaches together. i.e. in our development environment we used a stripped down region plugin to define a query source which is used to supply the list of radio items in an Ext Button Menu within the parent region/report.
Perhaps the following two images will explain what I’m failing to do with words…
In the above two images; the first shows the display of two separate menu’s with different items (it’s been photoshopped to show you two tabs of the tabpanel as the menu’s are on separate tabs). The second shows the APEX IDE and the menu plugins which are used to define the query source for the menu items.
The difference in approach to the “A button is not always a button” post is that instead of building a json object in the page header with our shortcuts and using a function to clean some malformed JSON outputted by our templates. We changed the design to generate the entire region toolbar JSON object in the page header, as it allowed a more cleaner and maintainable approach and opened up the ability to query the APEX data dictionary and process sub regions as we looped through each parent region at a time.
The following code example from our initial prototype (which only works for one menu button per region) should give you an idea of how we query the APEX data dictionary to build the toolbar object
--
-- Lets loop through all our page regions to create our region toolbar for each
--
FOR c IN
( SELECT *
FROM apex_application_page_regions
WHERE application_id = v_app_id
AND page_id = v_page_id
AND source_type NOT IN ('EXT_BUTTON_MENU') -- ignore our stripped pseudo plugins
AND extjs_utils.auth_condition_check(condition_type,condition_expression1,condition_expression2,authorization_scheme) = 0
) LOOP
v_toolbarObj := JSON_LIST();
--
-- Lets loop through all our page buttons to create our region toolbar
--
FOR c1 IN
( SELECT pb.region_id
, label
, nvl(redirect_url,'apex.submit('''||button_name||''');') link
, button_attributes
, template
FROM apex_application_page_buttons pb
, apex_application_temp_button tmp
, apex_applications app
WHERE pb.application_id = v_app_id
AND pb.page_id = v_page_id
AND pb.region_id = c.region_id
AND tmp.application_id = pb.application_id
AND app.application_id = pb.application_id
AND tmp.template_name = pb.button_template
AND tmp.theme_number = app.theme_number
AND extjs_utils.auth_condition_check(pb.condition_type,pb.condition_expression1,pb.condition_expression2,pb.authorization_scheme) = 0
ORDER by pb.button_sequence
) LOOP
--
-- Lets check our button attributes for shortcuts
--
v_shortcut_name := regexp_replace(c1.button_attributes, '.*"(EXT_\w+)".*','\1');
v_shortcut_name := CASE v_shortcut_name
WHEN c1.button_attributes THEN NULL
ELSE v_shortcut_name
END;
IF v_shortcut_name IS NOT NULL THEN
FOR c2 IN
( SELECT shortcut_name
, shortcut
FROM apex_application_shortcuts
WHERE application_id = v_app_id
AND shortcut_name = v_shortcut_name
) LOOP
v_shortcut := c2.shortcut;
--
-- Lets loop through our shortcut and replace our menu references with a JSON object
--
WHILE instr(v_shortcut,'#MENU:') > 0 LOOP
FOR c3 IN
( SELECT source_type
, region_source menu_sql
FROM apex_application_page_regions
WHERE application_id = v_app_id
AND page_id = v_page_id
AND parent_region_id = c.region_id
AND source_type = 'EXT_BUTTON_MENU'
) LOOP
--
-- Lets execute our query and return the result encoded in a JSON object
--
v_json := sql_to_json( p_sql => c3.menu_sql );
v_shortcut := regexp_replace(v_shortcut,'(\$MENU:\w+\$)',v_json,1,1)..........
In the above we query all the regions on the page and ignore any of our pseudo plugin regions. We then build up the toolbar JSON object with the assistance of PLJSON and then loop through each of the buttons defined for the region and use the defined button template and make the necessary string replacements e.g. #BUTTON_ATTRIBUTES#. But before we do, we check the button attributes to see if a custom MENU shortcut has been defined and if so we extract the shortcut name and query the shortcut source. We then extract any MENU definition in the shortcut source and then in the c3 cursor loop we query “apex_application_page_regions” and check the source type matches our plugin name and we use this SQL definition and execute it to get the results for the named menu.
So what it allows us to do from a development point of view is define a single button template e.g. radio menu, and use our pseudo plugins SQL to define the menu items. Essentially our toolbar menu button is made up of a button template, shortcut, and plugin region. All three components can be subscribed and published across all applications in the workspace so we get the benfit of code centralization and any additional custom config for the button menu can be defined by either using multiple shortcuts or some additional config in #BUTTON_ATTRIBUTES#.
In order to make sure the plugin region never displays, we use a template named either “Ext.Exclude” which wraps the content in a DIV with style=”display:none;”. Optionally we can use another template named “Ext.Destroy” which uses the Ext.onReady function and removes the region/DIV from the DOM on page load. Both come in very handy in different situations. We simply ignore regions which have these templates assigned to them within our viewport generation code.
Note: you will see this error in the region source when you use a stripped plugin like we have
ORA-20100: No render function has been defined for plug-in PLUGIN_EXT_BUTTON_MENU
however this is never visible because the template we define either destroys the region or hides it from display.





