Add the logic of InputData on new FW
authorc00149107 <chenchuanyu@huawei.com>
Mon, 27 Feb 2017 11:44:05 +0000 (19:44 +0800)
committerc00149107 <chenchuanyu@huawei.com>
Mon, 27 Feb 2017 11:44:05 +0000 (19:44 +0800)
Add the logic of InputData on new FW

Change-Id: Ic4ae180db7f081b849f6ec46f4239c6f7490aafb
Issue-ID:GSO-232
Signed-off-by: c00149107 <chenchuanyu@huawei.com>
lifecyclemgr/src/main/webapp/lifecyclemgr/i18n/lcm-template-parameters-i18n-en-US.properties [new file with mode: 0644]
lifecyclemgr/src/main/webapp/lifecyclemgr/index.html
lifecyclemgr/src/main/webapp/lifecyclemgr/js/DataService.js
lifecyclemgr/src/main/webapp/lifecyclemgr/js/app.js
lifecyclemgr/src/main/webapp/lifecyclemgr/js/bootbox.min.js [new file with mode: 0644]
lifecyclemgr/src/main/webapp/lifecyclemgr/js/jquery.i18n.properties-1.0.9.js [new file with mode: 0644]

diff --git a/lifecyclemgr/src/main/webapp/lifecyclemgr/i18n/lcm-template-parameters-i18n-en-US.properties b/lifecyclemgr/src/main/webapp/lifecyclemgr/i18n/lcm-template-parameters-i18n-en-US.properties
new file mode 100644 (file)
index 0000000..31819ae
--- /dev/null
@@ -0,0 +1,95 @@
+domainHost=Domain
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac1_ip=Left AC
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac1_peer_ip=Left CE IP
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac1_port=Left Port
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac1_route=Left Route
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac1_svlan=Left VLAN
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac2_ip=Right AC
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac2_peer_ip=Right CE IP
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac2_port=Right Port
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac2_route=Right Route
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.ac2_svlan=Right VLAN
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.description=Description
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.name=Service Name
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.pe1_ip=Left PE IP
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.pe2_ip=Right PE IP
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.serviceType=Service Type
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.technology=Technology
+tosca.nodes.sdn.ext.NS.ns_underlayervpn.topology=Topology
+tosca.nodes.sdn.ext.NS.enterprise2DC.dcFWIP=Firewall IP
+tosca.nodes.sdn.ext.NS.enterprise2DC.dcGWIP=Gateway IP
+tosca.nodes.sdn.ext.NS.enterprise2DC.dcLBIP=Load Balancer IP
+tosca.nodes.sdn.ext.NS.enterprise2DC.description=Description
+tosca.nodes.sdn.ext.NS.enterprise2DC.id=ID
+tosca.nodes.sdn.ext.NS.enterprise2DC.name=Service Name
+tosca.nodes.sdn.ext.NS.enterprise2DC.siteAccessPortVlan=ThinCPE VLAN
+tosca.nodes.sdn.ext.NS.enterprise2DC.siteCidr=Enterprise cidr
+tosca.nodes.sdn.ext.NS.enterprise2DC.siteThinCpeIP=ThinCPE IP
+tosca.nodes.sdn.ext.NS.enterprise2DC.siteVNI=ThinCPE VxLAN ID
+tosca.nodes.sdn.ext.NS.enterprise2DC.vCPE_MgrIp=vCPE IP
+tosca.nodes.sdn.ext.NS.enterprise2DC.vpcName=VPC Name
+tosca.nodes.sdn.ext.NS.enterprise2DC.vpcSubnetCidr=VPC cidr
+tosca.nodes.sdn.ext.NS.enterprise2DC.vpcSubnetName=VPC Subnet Name
+tosca.nodes.sdn.ext.NS.enterprise2DC.vpcVNI=VPC VxLAN ID
+tosca.nodes.nfv.NS.VBRAS_NS.externalDataNetworkName=External Data Network Name
+tosca.nodes.nfv.NS.VBRAS_NS.externalManageNetworkName=External Management Network Name
+tosca.nodes.nfv.NS.VCPE_NS.sfc_data_network=SFC Data Network Name
+tosca.nodes.nfv.NS.VCPE_NS.externalManageNetworkName=External Management Network Name
+tosca.nodes.nfv.NS.VCPE_NS.NatIpRange=Nat Ip Range
+tosca.nodes.nfv.NS.VCPE_NS.m6000_mng_ip=M6000 Mng IP
+tosca.nodes.nfv.NS.VCPE_NS.externalPluginManageNetworkName=External Plugin Management Network Name
+tosca.nodes.nfv.NS.VCPE_NS.externalDataNetworkName=External Data Network Name
+tosca.nodes.nfv.NS.POP_NS.sfc_data_network=SFC Data Network Name
+tosca.nodes.nfv.NS.POP_NS.externalManageNetworkName=External Management Network Name
+tosca.nodes.nfv.NS.POP_NS.NatIpRange=Nat Ip Range
+tosca.nodes.nfv.NS.POP_NS.m6000_mng_ip=M6000 Mng IP
+tosca.nodes.nfv.NS.POP_NS.externalPluginManageNetworkName=External Plugin Management Network Name
+tosca.nodes.nfv.NS.POP_NS.externalCompanyFtpDataNetworkName=External Company Ftp Data Network Name
+tosca.nodes.nfv.NS.POP_NS.externalDataNetworkName=External Data Network Name
+ac1_ip=Left AC
+ac1_peer_ip=Left CE IP
+ac1_port=Left Port
+ac1_route=Left Route
+ac1_svlan=Left VLAN
+ac2_ip=Right AC
+ac2_peer_ip=Right CE IP
+ac2_port=Right Port
+ac2_route=Right Route
+ac2_svlan=Right VLAN
+description=Description
+name=Service Name
+pe1_ip=Left PE IP
+pe2_ip=Right PE IP
+serviceType=Service Type
+technology=Technology
+topology=Topology
+dcFWIP=Firewall IP
+dcGWIP=Gateway IP
+dcLBIP=Load Balancer IP
+description=Description
+id=ID
+name=Service Name
+siteAccessPortVlan=ThinCPE VLAN
+siteCidr=Enterprise cidr
+siteThinCpeIP=ThinCPE IP
+siteVNI=ThinCPE VxLAN ID
+vCPE_MgrIp=vCPE IP
+vpcName=VPC Name
+vpcSubnetCidr=VPC cidr
+vpcSubnetName=VPC Subnet Name
+vpcVNI=VPC VxLAN ID
+externalDataNetworkName=External Data Network Name
+externalManageNetworkName=External Management Network Name
+sfc_data_network=SFC Data Network Name
+externalManageNetworkName=External Management Network Name
+NatIpRange=Nat Ip Range
+m6000_mng_ip=M6000 Mng IP
+externalPluginManageNetworkName=External Plugin Management Network Name
+externalDataNetworkName=External Data Network Name
+sfc_data_network=SFC Data Network Name
+externalManageNetworkName=External Management Network Name
+NatIpRange=Nat Ip Range
+m6000_mng_ip=M6000 Mng IP
+externalPluginManageNetworkName=External Plugin Management Network Name
+externalCompanyFtpDataNetworkName=External Company Ftp Data Network Name
+externalDataNetworkName=External Data Network Name
\ No newline at end of file
index ad6a359..a23411e 100644 (file)
@@ -22,6 +22,7 @@
     <script src="js/DataService.js"></script>
     <script src="js/mustache.js"></script>
     <script src="js/bootbox.min.js"></script>
+    <script type="text/javascript" src="js/jquery.i18n.properties-1.0.9.js"></script>
 </head>
 
 <body ng-app="lcApp" onload="loadTemplate()">
index c31a748..275141d 100644 (file)
@@ -28,7 +28,7 @@ app.factory("DataService", function($http, $log){
                  'serviceId': ""})*/
             }).then(function(response){
                 //$log.info(response);
-                lcData = response;
+                lcData = response.data;
                 return response;
             });
         },
@@ -36,7 +36,7 @@ app.factory("DataService", function($http, $log){
             var returnData = null;
             if(lcData) {
                 for (var i = 0; i < lcData.length; i++) {
-                    if(lcData[i].id == id) {
+                    if(lcData[i].serviceId == id) {
                         returnData = lcData[i].inputParameters;
                         break;
                     }
@@ -341,8 +341,7 @@ function getParamId(identify, param) {
  * @returns resource string
  */
 function getParamLabel(nodeType, param) {
-    //var name = $.i18n.prop(nodeType + '.' + param.name);
-    var name = param.name;
+    var name = $.i18n.prop(nodeType + '.' + param.name);
     if (name.length === 0 || name.slice(0, 1) === '[') {
         name = param.name;
     }
index 8a4d1e3..b03824e 100644 (file)
@@ -97,6 +97,12 @@ var app = angular.module("lcApp", ["ui.router", "ngTable"])/*, 'ui.bootstrap', '
         $scope.param="lctableData";\r
 \r
         $scope.init = function() {\r
+            jQuery.i18n.properties({\r
+                language : 'en-US',\r
+                name : 'lcm-template-parameters-i18n',\r
+                path : 'i18n/',\r
+                mode : 'map'\r
+            });\r
             DataService.loadGetServiceData()\r
                 .then(function (data) {\r
                     if (data) {\r
@@ -342,7 +348,7 @@ var app = angular.module("lcApp", ["ui.router", "ngTable"])/*, 'ui.bootstrap', '
             $.when(DataService.createService(serviceBaseInfo))\r
                 .then(function (response) {\r
                     $log.info(response);\r
-                    if(response.sataus === 'checkfailed'){\r
+                    if(response.status === 'checkfailed'){\r
                         return;\r
                     }else if (response.status === 'finished') {\r
                         $.when(queryService(response.serviceId)).then(function(serviceInstance){  \r
@@ -552,18 +558,9 @@ var app = angular.module("lcApp", ["ui.router", "ngTable"])/*, 'ui.bootstrap', '
         console.log("inputDataCtrl --> $stateParams.id:: " + $stateParams.id);\r
         $scope.inputData = DataService.getSavedLCData($stateParams.id);\r
         $log.info($scope.inputData);\r
-        /*for(var i = 0; i < $scope.inputData.length; i++) {\r
-            //var def_button_tpl = $(modelTemplate).filter('#defaultButtons').html();\r
-            $("#inputDataElements").appendChild("<span>Shahid</span>");\r
-\r
-        }*/\r
-\r
         $("div.inputDataElements").html("");\r
-        for (var prop in $scope.inputData) {\r
-            //console.log('obj.' + prop, '=', $scope.inputData[prop]);\r
-            //$("#inputDataElements").append("<div><span>"+prop+": </span><span>"+$scope.inputData[prop]+"</span></div>");\r
-            $("div.inputDataElements").append('<div class="mT15 form-group row" style="margin-top:35px;"><div class="col-md-2 col-xs-2 col-lg-2 col-sm-2" align="left"><label class="control-label"><span style="font-size:16px;">'+ prop + ':</span></label></div><div class="col-md-3 col-xs-3 col-lg-3 col-sm-3"><input  type="text" name="" maxlength="256" data-toggle="tooltip" data-placement="top" title="'+ $scope.inputData[prop] + '" value="'+ $scope.inputData[prop] + '" readonly disabled/></div></div>');\r
-        }\r
+        $("div.inputDataElements").append(convertInputsToUI('', 'show', $scope.inputData));\r
+\r
     })\r
 \r
 \r
diff --git a/lifecyclemgr/src/main/webapp/lifecyclemgr/js/bootbox.min.js b/lifecyclemgr/src/main/webapp/lifecyclemgr/js/bootbox.min.js
new file mode 100644 (file)
index 0000000..a7ea24f
--- /dev/null
@@ -0,0 +1,6 @@
+/**
+ * bootbox.js v4.3.0
+ *
+ * http://bootboxjs.com/license.txt
+ */
+!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["jquery"],b):"object"==typeof exports?module.exports=b(require("jquery")):a.bootbox=b(a.jQuery)}(this,function a(b,c){"use strict";function d(a){var b=q[o.locale];return b?b[a]:q.en[a]}function e(a,c,d){a.stopPropagation(),a.preventDefault();var e=b.isFunction(d)&&d(a)===!1;e||c.modal("hide")}function f(a){var b,c=0;for(b in a)c++;return c}function g(a,c){var d=0;b.each(a,function(a,b){c(a,b,d++)})}function h(a){var c,d;if("object"!=typeof a)throw new Error("Please supply an object of options");if(!a.message)throw new Error("Please specify a message");return a=b.extend({},o,a),a.buttons||(a.buttons={}),a.backdrop=a.backdrop?"static":!1,c=a.buttons,d=f(c),g(c,function(a,e,f){if(b.isFunction(e)&&(e=c[a]={callback:e}),"object"!==b.type(e))throw new Error("button with key "+a+" must be an object");e.label||(e.label=a),e.className||(e.className=2>=d&&f===d-1?"btn-primary":"btn-default")}),a}function i(a,b){var c=a.length,d={};if(1>c||c>2)throw new Error("Invalid argument length");return 2===c||"string"==typeof a[0]?(d[b[0]]=a[0],d[b[1]]=a[1]):d=a[0],d}function j(a,c,d){return b.extend(!0,{},a,i(c,d))}function k(a,b,c,d){var e={className:"bootbox-"+a,buttons:l.apply(null,b)};return m(j(e,d,c),b)}function l(){for(var a={},b=0,c=arguments.length;c>b;b++){var e=arguments[b],f=e.toLowerCase(),g=e.toUpperCase();a[f]={label:d(g)}}return a}function m(a,b){var d={};return g(b,function(a,b){d[b]=!0}),g(a.buttons,function(a){if(d[a]===c)throw new Error("button key "+a+" is not allowed (options are "+b.join("\n")+")")}),a}var n={dialog:"<div class='bootbox modal' tabindex='-1' role='dialog'><div class='modal-dialog'><div class='modal-content'><div class='modal-body'><div class='bootbox-body'></div></div></div></div></div>",header:"<div class='modal-header'><h4 class='modal-title'></h4></div>",footer:"<div class='modal-footer'></div>",closeButton:"<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>",form:"<form class='bootbox-form'></form>",inputs:{text:"<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",textarea:"<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",email:"<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",select:"<select class='bootbox-input bootbox-input-select form-control'></select>",checkbox:"<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",date:"<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",time:"<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",number:"<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",password:"<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"}},o={locale:"en",backdrop:!0,animate:!0,className:null,closeButton:!0,show:!0,container:"body"},p={};p.alert=function(){var a;if(a=k("alert",["ok"],["message","callback"],arguments),a.callback&&!b.isFunction(a.callback))throw new Error("alert requires callback property to be a function when provided");return a.buttons.ok.callback=a.onEscape=function(){return b.isFunction(a.callback)?a.callback():!0},p.dialog(a)},p.confirm=function(){var a;if(a=k("confirm",["cancel","confirm"],["message","callback"],arguments),a.buttons.cancel.callback=a.onEscape=function(){return a.callback(!1)},a.buttons.confirm.callback=function(){return a.callback(!0)},!b.isFunction(a.callback))throw new Error("confirm requires a callback");return p.dialog(a)},p.prompt=function(){var a,d,e,f,h,i,k;if(f=b(n.form),d={className:"bootbox-prompt",buttons:l("cancel","confirm"),value:"",inputType:"text"},a=m(j(d,arguments,["title","callback"]),["cancel","confirm"]),i=a.show===c?!0:a.show,a.message=f,a.buttons.cancel.callback=a.onEscape=function(){return a.callback(null)},a.buttons.confirm.callback=function(){var c;switch(a.inputType){case"text":case"textarea":case"email":case"select":case"date":case"time":case"number":case"password":c=h.val();break;case"checkbox":var d=h.find("input:checked");c=[],g(d,function(a,d){c.push(b(d).val())})}return a.callback(c)},a.show=!1,!a.title)throw new Error("prompt requires a title");if(!b.isFunction(a.callback))throw new Error("prompt requires a callback");if(!n.inputs[a.inputType])throw new Error("invalid prompt type");switch(h=b(n.inputs[a.inputType]),a.inputType){case"text":case"textarea":case"email":case"date":case"time":case"number":case"password":h.val(a.value);break;case"select":var o={};if(k=a.inputOptions||[],!k.length)throw new Error("prompt with select requires options");g(k,function(a,d){var e=h;if(d.value===c||d.text===c)throw new Error("given options in wrong format");d.group&&(o[d.group]||(o[d.group]=b("<optgroup/>").attr("label",d.group)),e=o[d.group]),e.append("<option value='"+d.value+"'>"+d.text+"</option>")}),g(o,function(a,b){h.append(b)}),h.val(a.value);break;case"checkbox":var q=b.isArray(a.value)?a.value:[a.value];if(k=a.inputOptions||[],!k.length)throw new Error("prompt with checkbox requires options");if(!k[0].value||!k[0].text)throw new Error("given options in wrong format");h=b("<div/>"),g(k,function(c,d){var e=b(n.inputs[a.inputType]);e.find("input").attr("value",d.value),e.find("label").append(d.text),g(q,function(a,b){b===d.value&&e.find("input").prop("checked",!0)}),h.append(e)})}return a.placeholder&&h.attr("placeholder",a.placeholder),a.pattern&&h.attr("pattern",a.pattern),f.append(h),f.on("submit",function(a){a.preventDefault(),a.stopPropagation(),e.find(".btn-primary").click()}),e=p.dialog(a),e.off("shown.bs.modal"),e.on("shown.bs.modal",function(){h.focus()}),i===!0&&e.modal("show"),e},p.dialog=function(a){a=h(a);var c=b(n.dialog),d=c.find(".modal-dialog"),f=c.find(".modal-body"),i=a.buttons,j="",k={onEscape:a.onEscape};if(g(i,function(a,b){j+="<button data-bb-handler='"+a+"' type='button' class='btn "+b.className+"'>"+b.label+"</button>",k[a]=b.callback}),f.find(".bootbox-body").html(a.message),a.animate===!0&&c.addClass("fade"),a.className&&c.addClass(a.className),"large"===a.size&&d.addClass("modal-lg"),"small"===a.size&&d.addClass("modal-sm"),a.title&&f.before(n.header),a.closeButton){var l=b(n.closeButton);a.title?c.find(".modal-header").prepend(l):l.css("margin-top","-10px").prependTo(f)}return a.title&&c.find(".modal-title").html(a.title),j.length&&(f.after(n.footer),c.find(".modal-footer").html(j)),c.on("hidden.bs.modal",function(a){a.target===this&&c.remove()}),c.on("shown.bs.modal",function(){c.find(".btn-primary:first").focus()}),c.on("escape.close.bb",function(a){k.onEscape&&e(a,c,k.onEscape)}),c.on("click",".modal-footer button",function(a){var d=b(this).data("bb-handler");e(a,c,k[d])}),c.on("click",".bootbox-close-button",function(a){e(a,c,k.onEscape)}),c.on("keyup",function(a){27===a.which&&c.trigger("escape.close.bb")}),b(a.container).append(c),c.modal({backdrop:a.backdrop,keyboard:!1,show:!1}),a.show&&c.modal("show"),c},p.setDefaults=function(){var a={};2===arguments.length?a[arguments[0]]=arguments[1]:a=arguments[0],b.extend(o,a)},p.hideAll=function(){return b(".bootbox").modal("hide"),p};var q={br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},cs:{OK:"OK",CANCEL:"Zrušit",CONFIRM:"Potvrdit"},da:{OK:"OK",CANCEL:"Annuller",CONFIRM:"Accepter"},de:{OK:"OK",CANCEL:"Abbrechen",CONFIRM:"Akzeptieren"},el:{OK:"Εντάξει",CANCEL:"Ακύρωση",CONFIRM:"Επιβεβαίωση"},en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},et:{OK:"OK",CANCEL:"Katkesta",CONFIRM:"OK"},fi:{OK:"OK",CANCEL:"Peruuta",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},he:{OK:"אישור",CANCEL:"ביטול",CONFIRM:"אישור"},id:{OK:"OK",CANCEL:"Batal",CONFIRM:"OK"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"},ja:{OK:"OK",CANCEL:"キャンセル",CONFIRM:"確認"},lt:{OK:"Gerai",CANCEL:"Atšaukti",CONFIRM:"Patvirtinti"},lv:{OK:"Labi",CANCEL:"Atcelt",CONFIRM:"Apstiprināt"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},no:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},pl:{OK:"OK",CANCEL:"Anuluj",CONFIRM:"Potwierdź"},pt:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Confirmar"},ru:{OK:"OK",CANCEL:"Отмена",CONFIRM:"Применить"},sv:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},tr:{OK:"Tamam",CANCEL:"İptal",CONFIRM:"Onayla"},zh_CN:{OK:"OK",CANCEL:"取消",CONFIRM:"确认"},zh_TW:{OK:"OK",CANCEL:"取消",CONFIRM:"確認"}};return p.init=function(c){return a(c||b)},p});
\ No newline at end of file
diff --git a/lifecyclemgr/src/main/webapp/lifecyclemgr/js/jquery.i18n.properties-1.0.9.js b/lifecyclemgr/src/main/webapp/lifecyclemgr/js/jquery.i18n.properties-1.0.9.js
new file mode 100644 (file)
index 0000000..5f9b195
--- /dev/null
@@ -0,0 +1,479 @@
+/******************************************************************************
+ * jquery.i18n.properties
+ * 
+ * Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 
+ * MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+ * 
+ * @version     1.0.x
+ * @author      Nuno Fernandes
+ * @url         www.codingwithcoffee.com
+ * @inspiration Localisation assistance for jQuery (http://keith-wood.name/localisation.html)
+ *              by Keith Wood (kbwood{at}iinet.com.au) June 2007
+ * 
+ *****************************************************************************/
+
+(function($) {
+$.i18n = {};
+
+/** Map holding bundle keys (if mode: 'map') */
+$.i18n.map = {};
+    
+/**
+ * Load and parse message bundle files (.properties),
+ * making bundles keys available as javascript variables.
+ * 
+ * i18n files are named <name>.js, or <name>_<language>.js or <name>_<language>_<country>.js
+ * Where:
+ *      The <language> argument is a valid ISO Language Code. These codes are the lower-case, 
+ *      two-letter codes as defined by ISO-639. You can find a full list of these codes at a 
+ *      number of sites, such as: http://www.loc.gov/standards/iso639-2/englangn.html
+ *      The <country> argument is a valid ISO Country Code. These codes are the upper-case,
+ *      two-letter codes as defined by ISO-3166. You can find a full list of these codes at a
+ *      number of sites, such as: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
+ * 
+ * Sample usage for a bundles/Messages.properties bundle:
+ * $.i18n.properties({
+ *      name:      'Messages', 
+ *      language:  'en_US',
+ *      path:      'bundles'
+ * });
+ * @param  name                        (string/string[], optional) names of file to load (eg, 'Messages' or ['Msg1','Msg2']). Defaults to "Messages"
+ * @param  language            (string, optional) language/country code (eg, 'en', 'en_US', 'pt_PT'). if not specified, language reported by the browser will be used instead.
+ * @param  path                        (string, optional) path of directory that contains file to load
+ * @param  mode                        (string, optional) whether bundles keys are available as JavaScript variables/functions or as a map (eg, 'vars' or 'map')
+ * @param  cache        (boolean, optional) whether bundles should be cached by the browser, or forcibly reloaded on each page load. Defaults to false (i.e. forcibly reloaded)
+ * @param  encoding    (string, optional) the encoding to request for bundles. Property file resource bundles are specified to be in ISO-8859-1 format. Defaults to UTF-8 for backward compatibility.
+ * @param  callback     (function, optional) callback function to be called after script is terminated
+ */
+$.i18n.properties = function(settings) {
+       // set up settings
+    var defaults = {
+        name:           'Messages',
+        language:       '',
+        path:           '',  
+        mode:           'vars',
+        cache:                 false,
+        encoding:       'UTF-8',
+        callback:       null
+    };
+    settings = $.extend(defaults, settings);    
+    if(settings.language === null || settings.language == '') {
+          settings.language = $.i18n.browserLang();
+       }
+       if(settings.language === null) {settings.language='';}
+       
+       // load and parse bundle files
+       var files = getFiles(settings.name);
+       for(i=0; i<files.length; i++) {
+               // 1. load base (eg, Messages.properties)
+               //loadAndParseFile(settings.path + files[i] + '.properties', settings);
+        // 2. with language code (eg, Messages_pt.properties)
+               //if(settings.language.length >= 2) {
+        //    loadAndParseFile(settings.path + files[i] + '-' + settings.language.substring(0, 2) +'.properties', settings);
+               //}
+               // 3. with language code and country code (eg, Messages_pt_PT.properties)
+               // 将寻找资源文件的顺序倒置
+        if(settings.language.length >= 5) {
+            loadAndParseFile(settings.path + files[i] + '-' + settings.language.substring(0, 5) +'.properties', settings);
+        } else if(settings.language.length >= 2) {
+            loadAndParseFile(settings.path + files[i] + '-' + settings.language.substring(0, 2) +'.properties', settings);
+               } else {
+                       loadAndParseFile(settings.path + files[i] + '.properties', settings);
+               }
+       }
+       
+       // call callback
+       if(settings.callback){ settings.callback(); }
+};
+
+
+/**
+ * When configured with mode: 'map', allows access to bundle values by specifying its key.
+ * Eg, jQuery.i18n.prop('com.company.bundles.menu_add')
+ */
+$.i18n.prop = function(key /* Add parameters as function arguments as necessary  */) {
+       var value = $.i18n.map[key];
+       if (value == null)
+               return '[' + key + ']';
+       
+//     if(arguments.length < 2) // No arguments.
+//    //if(key == 'spv.lbl.modified') {alert(value);}
+//             return value;
+       
+//     if (!$.isArray(placeHolderValues)) {
+//             // If placeHolderValues is not an array, make it into one.
+//             placeHolderValues = [placeHolderValues];
+//             for (var i=2; i<arguments.length; i++)
+//                     placeHolderValues.push(arguments[i]);
+//     }
+
+       // Place holder replacement
+       /**
+        * Tested with:
+        *   test.t1=asdf ''{0}''
+        *   test.t2=asdf '{0}' '{1}'{1}'zxcv
+        *   test.t3=This is \"a quote" 'a''{0}''s'd{fgh{ij'
+        *   test.t4="'''{'0}''" {0}{a}
+        *   test.t5="'''{0}'''" {1}
+        *   test.t6=a {1} b {0} c
+        *   test.t7=a 'quoted \\ s\ttringy' \t\t x
+        *
+        * Produces:
+        *   test.t1, p1 ==> asdf 'p1'
+        *   test.t2, p1 ==> asdf {0} {1}{1}zxcv
+        *   test.t3, p1 ==> This is "a quote" a'{0}'sd{fgh{ij
+        *   test.t4, p1 ==> "'{0}'" p1{a}
+        *   test.t5, p1 ==> "'{0}'" {1}
+        *   test.t6, p1 ==> a {1} b p1 c
+        *   test.t6, p1, p2 ==> a p2 b p1 c
+        *   test.t6, p1, p2, p3 ==> a p2 b p1 c
+        *   test.t7 ==> a quoted \ s   tringy           x
+        */
+       
+       var i;
+       if (typeof(value) == 'string') {
+        // Handle escape characters. Done separately from the tokenizing loop below because escape characters are 
+               // active in quoted strings.
+        i = 0;
+        while ((i = value.indexOf('\\', i)) != -1) {
+                  if (value[i+1] == 't')
+                          value = value.substring(0, i) + '\t' + value.substring((i++) + 2); // tab
+                  else if (value[i+1] == 'r')
+                          value = value.substring(0, i) + '\r' + value.substring((i++) + 2); // return
+                  else if (value[i+1] == 'n')
+                          value = value.substring(0, i) + '\n' + value.substring((i++) + 2); // line feed
+                  else if (value[i+1] == 'f')
+                          value = value.substring(0, i) + '\f' + value.substring((i++) + 2); // form feed
+                  else if (value[i+1] == '\\')
+                          value = value.substring(0, i) + '\\' + value.substring((i++) + 2); // \
+                  else
+                          value = value.substring(0, i) + value.substring(i+1); // Quietly drop the character
+        }
+               
+               // Lazily convert the string to a list of tokens.
+               var arr = [], j, index;
+               i = 0;
+               while (i < value.length) {
+                       if (value[i] == '\'') {
+                               // Handle quotes
+                               if (i == value.length-1)
+                                       value = value.substring(0, i); // Silently drop the trailing quote
+                               else if (value[i+1] == '\'')
+                                       value = value.substring(0, i) + value.substring(++i); // Escaped quote
+                               else {
+                                       // Quoted string
+                                       j = i + 2;
+                                       while ((j = value.indexOf('\'', j)) != -1) {
+                                               if (j == value.length-1 || value[j+1] != '\'') {
+                                                       // Found start and end quotes. Remove them
+                                                       value = value.substring(0,i) + value.substring(i+1, j) + value.substring(j+1);
+                                                       i = j - 1;
+                                                       break;
+                                               }
+                                               else {
+                                                       // Found a double quote, reduce to a single quote.
+                                                       value = value.substring(0,j) + value.substring(++j);
+                                               }
+                                       }
+                                       
+                                       if (j == -1) {
+                                               // There is no end quote. Drop the start quote
+                                               value = value.substring(0,i) + value.substring(i+1);
+                                       }
+                               }
+                       }
+                       else if (value[i] == '{') {
+                               // Beginning of an unquoted place holder.
+                               j = value.indexOf('}', i+1);
+                               if (j == -1)
+                                       i++; // No end. Process the rest of the line. Java would throw an exception
+                               else {
+                                       // Add 1 to the index so that it aligns with the function arguments.
+                                       index = parseInt(value.substring(i+1, j));
+                                       if (!isNaN(index) && index >= 0) {
+                                               // Put the line thus far (if it isn't empty) into the array
+                                               var s = value.substring(0, i);
+                                               if (s != "")
+                                                       arr.push(s);
+                                               // Put the parameter reference into the array
+                                               arr.push(index);
+                                               // Start the processing over again starting from the rest of the line.
+                                               i = 0;
+                                               value = value.substring(j+1);
+                                       }
+                                       else
+                                               i = j + 1; // Invalid parameter. Leave as is.
+                               }
+                       }
+                       else
+                               i++;
+               }
+               
+               // Put the remainder of the no-empty line into the array.
+               if (value != "")
+                       arr.push(value);
+               value = arr;
+               
+               // Make the array the value for the entry.
+               $.i18n.map[key] = arr;
+       }
+       
+       if (value.length == 0)
+               return "";
+       if (value.lengh == 1 && typeof(value[0]) == "string")
+               return value[0];
+       
+       var s = "";
+       for (i=0; i<value.length; i++) {
+               if (typeof(value[i]) == "string")
+                       s += value[i];
+               // Must be a number
+               else if (value[i] + 1 < arguments.length)
+                       s += arguments[value[i] + 1];
+               else
+                       s += "{"+ value[i] +"}";
+       }
+       
+       return s;
+};
+
+/** Language reported by browser, normalized code */
+$.i18n.browserLang = function() {
+       return normaliseLanguageCode(navigator.language /* Mozilla */ || navigator.userLanguage /* IE */);
+}
+
+
+/** Load and parse .properties files */
+function loadAndParseFile(filename, settings) {
+       $.ajax({
+        url:        filename,
+        async:      false,
+        cache:         settings.cache,
+        contentType:'text/plain;charset='+ settings.encoding,
+        dataType:   'text',
+        success:    function(data, status) {
+                                       parseData(data, settings.mode); 
+                                       }
+    });
+}
+
+/** Parse .properties files */
+function parseData(data, mode) {
+   var parsed = '';
+   var parameters = data.split( /\n/ );
+   var regPlaceHolder = /(\{\d+\})/g;
+   var regRepPlaceHolder = /\{(\d+)\}/g;
+   var unicodeRE = /(\\u.{4})/ig;
+   for(var i=0; i<parameters.length; i++ ) {
+       parameters[i] = parameters[i].replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+       if(parameters[i].length > 0 && parameters[i].match("^#")!="#") { // skip comments
+           var pair = parameters[i].split('=');
+           if(pair.length > 0) {
+               /** Process key & value */
+               var name = unescape(pair[0]).replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+               var value = pair.length == 1 ? "" : pair[1];
+               // process multi-line values
+               while(value.match(/\\$/)=="\\") {
+                               value = value.substring(0, value.length - 1);
+                               value += parameters[++i].replace( /\s\s*$/, '' ); // right trim
+               }               
+               // Put values with embedded '='s back together
+               for(var s=2;s<pair.length;s++){ value +='=' + pair[s]; }
+               value = value.replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+               
+               /** Mode: bundle keys in a map */
+               if(mode == 'map' || mode == 'both') {
+                   // handle unicode chars possibly left out
+                   var unicodeMatches = value.match(unicodeRE);
+                   if(unicodeMatches) {
+                     for(var u=0; u<unicodeMatches.length; u++) {
+                        value = value.replace( unicodeMatches[u], unescapeUnicode(unicodeMatches[u]));
+                     }
+                   }
+                   // add to map
+                   $.i18n.map[name] = value;
+               }
+               
+               /** Mode: bundle keys as vars/functions */
+               if(mode == 'vars' || mode == 'both') {
+                   value = value.replace( /"/g, '\\"' ); // escape quotation mark (")
+                   
+                   // make sure namespaced key exists (eg, 'some.key') 
+                   checkKeyNamespace(name);
+                   
+                   // value with variable substitutions
+                   if(regPlaceHolder.test(value)) {
+                       var parts = value.split(regPlaceHolder);
+                       // process function args
+                       var first = true;
+                       var fnArgs = '';
+                       var usedArgs = [];
+                       for(var p=0; p<parts.length; p++) {
+                           if(regPlaceHolder.test(parts[p]) && (usedArgs.length == 0 || usedArgs.indexOf(parts[p]) == -1)) {
+                               if(!first) {fnArgs += ',';}
+                               fnArgs += parts[p].replace(regRepPlaceHolder, 'v$1');
+                               usedArgs.push(parts[p]);
+                               first = false;
+                           }
+                       }
+                       parsed += name + '=function(' + fnArgs + '){';
+                       // process function body
+                       var fnExpr = '"' + value.replace(regRepPlaceHolder, '"+v$1+"') + '"';
+                       parsed += 'return ' + fnExpr + ';' + '};';
+                       
+                   // simple value
+                   }else{
+                       parsed += name+'="'+value+'";';
+                   }
+               } // END: Mode: bundle keys as vars/functions
+           } // END: if(pair.length > 0)
+       } // END: skip comments
+   }
+   eval(parsed);
+}
+
+/** Make sure namespace exists (for keys with dots in name) */
+// TODO key parts that start with numbers quietly fail. i.e. month.short.1=Jan
+function checkKeyNamespace(key) {
+       var regDot = /\./;
+       if(regDot.test(key)) {
+               var fullname = '';
+               var names = key.split( /\./ );
+               for(var i=0; i<names.length; i++) {
+                       if(i>0) {fullname += '.';}
+                       fullname += names[i];
+                       if(eval('typeof '+fullname+' == "undefined"')) {
+                               eval(fullname + '={};');
+                       }
+               }
+       }
+}
+
+/** Make sure filename is an array */
+function getFiles(names) {
+       return (names && names.constructor == Array) ? names : [names];
+}
+
+/** Ensure language code is in the format aa_AA. */
+function normaliseLanguageCode(lang) {
+    lang = lang.toLowerCase();
+    if(lang.length > 3) {
+        lang = lang.substring(0, 3) + lang.substring(3).toUpperCase();
+    }
+    return lang;
+}
+
+/** Unescape unicode chars ('\u00e3') */
+function unescapeUnicode(str) {
+  // unescape unicode codes
+  var codes = [];
+  var code = parseInt(str.substr(2), 16);
+  if (code >= 0 && code < Math.pow(2, 16)) {
+     codes.push(code);
+  }
+  // convert codes to text
+  var unescaped = '';
+  for (var i = 0; i < codes.length; ++i) {
+    unescaped += String.fromCharCode(codes[i]);
+  }
+  return unescaped;
+}
+
+/* Cross-Browser Split 1.0.1
+(c) Steven Levithan <stevenlevithan.com>; MIT License
+An ECMA-compliant, uniform cross-browser split method */
+var cbSplit;
+// avoid running twice, which would break `cbSplit._nativeSplit`'s reference to the native `split`
+if (!cbSplit) {    
+  cbSplit = function(str, separator, limit) {
+      // if `separator` is not a regex, use the native `split`
+      if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
+        if(typeof cbSplit._nativeSplit == "undefined")
+          return str.split(separator, limit);
+        else
+          return cbSplit._nativeSplit.call(str, separator, limit);
+      }
+  
+      var output = [],
+          lastLastIndex = 0,
+          flags = (separator.ignoreCase ? "i" : "") +
+                  (separator.multiline  ? "m" : "") +
+                  (separator.sticky     ? "y" : ""),
+          separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
+          separator2, match, lastIndex, lastLength;
+  
+      str = str + ""; // type conversion
+      if (!cbSplit._compliantExecNpcg) {
+          separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
+      }
+  
+      /* behavior for `limit`: if it's...
+      - `undefined`: no limit.
+      - `NaN` or zero: return an empty array.
+      - a positive number: use `Math.floor(limit)`.
+      - a negative number: no limit.
+      - other: type-convert, then use the above rules. */
+      if (limit === undefined || +limit < 0) {
+          limit = Infinity;
+      } else {
+          limit = Math.floor(+limit);
+          if (!limit) {
+              return [];
+          }
+      }
+  
+      while (match = separator.exec(str)) {
+          lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser
+  
+          if (lastIndex > lastLastIndex) {
+              output.push(str.slice(lastLastIndex, match.index));
+  
+              // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
+              if (!cbSplit._compliantExecNpcg && match.length > 1) {
+                  match[0].replace(separator2, function () {
+                      for (var i = 1; i < arguments.length - 2; i++) {
+                          if (arguments[i] === undefined) {
+                              match[i] = undefined;
+                          }
+                      }
+                  });
+              }
+  
+              if (match.length > 1 && match.index < str.length) {
+                  Array.prototype.push.apply(output, match.slice(1));
+              }
+  
+              lastLength = match[0].length;
+              lastLastIndex = lastIndex;
+  
+              if (output.length >= limit) {
+                  break;
+              }
+          }
+  
+          if (separator.lastIndex === match.index) {
+              separator.lastIndex++; // avoid an infinite loop
+          }
+      }
+  
+      if (lastLastIndex === str.length) {
+          if (lastLength || !separator.test("")) {
+              output.push("");
+          }
+      } else {
+          output.push(str.slice(lastLastIndex));
+      }
+  
+      return output.length > limit ? output.slice(0, limit) : output;
+  };
+  
+  cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
+  cbSplit._nativeSplit = String.prototype.split;
+
+} // end `if (!cbSplit)`
+String.prototype.split = function (separator, limit) {
+    return cbSplit(this, separator, limit);
+};
+
+})(jQuery);
+                
\ No newline at end of file