Making a remote javascript library loaded dynamically by AUI and be an AUI plugin

    In the real world project, there are times when a team develops some feature like google map, twitter, facebook that need remote javascript library between several portlets but for the same portal. There are many similiar features that needs to resuse many codes. We want out code to be consistence and easily to be managed and more importantly we don't want to waste time on mutiple people working on the same feature that ultimate increase the cost of a project and once there's a bug or requirement modification(people love to do that), that the whole team need to change their own code, which is really frustrating for the whole team.

    TWO ways we think of to solve this (actually there are more solutions):

    1. Making a shared js and code standard that everybody can read it and copy it to each own code.  This method still can not guarantee a developer that use the right code without updating their js file to the up-to-date.

    2. Making a global portlet as a dependency of the portlets. This portlet will mainly be set layout.static.portlets.all=<portletID>  in portal.properties and add a <liferay-util:html-top> tag to view.jsp page that loads the remote javascript libiary , and that all pages in the portal loaded the remote javascript library.

BUT, when using code like <script src="https://maps.googleapis.com/maps/api/js?sensor=false&amp;libraries=places" type="text/javascript"></script>, in some network environment like some companies or countries, facebook, google does not work very well, so the whole portal pages became extreamly slow to wait the until loading timeout. In my test sample, The longest time to wait a loading of facebook script on a page that does not use any feature was 11.98s and 1m 24s for loading google map script under a total refreshing page (shift + refresh).

    Why do we have to do this, load a unused script in a page in such a poor network environment? This really ruins the work of our core engineer. Core Engineers took really huge effort on decreasing some ms of loading time, but we just can simply increase seconds of loading time by adding 2 scripts. Fanstastic devil

    We don't have to do this. We can easily get rid of the features at the requirement analysis period.

    Once the features were made sure to use, we would choose a better way to handel this. At least, not let every page to load the script that is not useful.

    So We can still make a global portlet as a dependency, and load the script that we need. BUT, this script is not from the remote site directilly. This will be an aui plugin that handels the connection when we need. So that solves the problem.

For example to load twitter's script, the summary script is like this

AUI().add('aui-twitter', function(A) {


 var Lang = A.Lang,

 TWITTER = 'twitter',

 TWITTER_ADDR = '',

 /*this version only support share button yet*/

 TWITTER_BUTTON = 

 '<a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>'

 ;


 var Twitter = A.Component.create({


   NAME: TWITTER,


   ARRTS: {

   },

   prototype: {

     initializer: function() {

       var instance = this;

       instance._loadScript();

     },

    _loadScript: function() {

      A.Get.script(

        'https://platform.twitter.com/widgets.js',

        {

          onSuccess: function() {

           //alert("load twitter script success");

          }

        }

      );

    },

    createTwitterButton: function(options) {

      var instance = this;

      var button = A.Node.create(TWITTER_BUTTON);

      var dataLang = (options.dataLang != null ? options.dataLang : instance.LANG.ENGLISH);

      var dataCount = (options.dataCount != null ? options.dataCount : instance.COUNT_ALIGN.HORIZONTAL);

     var dataURL = (options.dataURL != null ? options.dataURL : '');


     if(options.largeButton) {

       button.setAttribute('data-size', 'large');

      }


      button.setAttribute('data-lang', dataLang);

      button.setAttribute('data-count', dataCount);

      button.setAttribute('data-url', dataURL);


      A.one(options.contentBox).append(button);


      return button;


    },


    //can add more features


    COUNT_ALIGN: {

      HORIZONTAL: 'horizontal',

      VERTICAL: 'vertical'

    },

    LANG: {

      ARABIC: 'ar',

      CHINESE_SIMPLIFIED: 'zh-cn',

      CHINESE_TRADITIONAL: 'zh-tw',

      DUTCH: 'nl',

      ENGLISH: 'en', //can add other languages

    }

   }

});


A.Twitter = Twitter;

}, '@VERSION@', {skinnable:false, requires:['aui-base', 'get']});
 
 
Once the script is loaded, if an aui object is not generated, the script won't be loaded.
In the jsp page can simply add code like:
 
<div id="<portlet:namespace />twitter-share"></div>

<aui:script use="aui-base, aui-twitter">

  AUI().use(''aui-twitter', function(A) {

    var tObj = new A.Twitter();

    var btnOpt = {

      contentBox: "#<portlet:namespace />twitter-share",
      dataLang: tObj.LANG.ENGLISH,
      dataCount: tObj.COUNT_ALIGN.VERTICAL,
      largeButton: true
    };

    tObj.createTwitterButton(btnOpt);

  });
</aui:script>

 

If AUI can have an official plugin to support those famous libraries like google and facebook and etc it would be nicer. :)

Blogs
That's a good idea Zhao Jin, congratulations for your blogpost emoticon
Thanks Zeno, extendingly, I am still thinking about loading js in Hook. But how to load google API key is still a question.