From: Rezende & Pedro & Carlos & Raphael Date: Fri, 3 Oct 2014 20:19:32 +0000 (-0300) Subject: Merge branch 'fibre' of ssh://git.onelab.eu/git/myslice into fibre X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=e45ccc4c4c327a81cc6a001ceff0655358ea09c5;hp=e494918d8e6d9dab21b9ff30c3c2db2157dc0a20;p=myslice.git Merge branch 'fibre' of ssh://git.onelab.eu/git/myslice into fibre --- diff --git a/activity/__init__.py b/activity/__init__.py index d570662e..6157bae7 100644 --- a/activity/__init__.py +++ b/activity/__init__.py @@ -1,61 +1,92 @@ # # Activity monitor # +# Client is authenticated with an API key and a secret +# The API key is a 64 chars string (digits and letters) that is passed to the request +# The secret is a 64 chars string that is used to sign the request +# The generated signature is a SHA256 hes digest import urllib, urllib2 import threading -from datetime import datetime +import hmac +import hashlib +import base64 +import time +import datetime +from myslice.configengine import ConfigEngine +config = ConfigEngine() +if config.activity and config.activity.apikey : + apikey = config.activity.apikey +else : + # apikey will be necessary + apikey = None -def logWrite(request, action, message): - url = "http://localhost:5000/log" +if config.activity and config.activity.secret : + secret = config.activity.secret +else : + # secret will be necessary + secret = None + +if config.activity and config.activity.server : + server = config.activity.server +else : + # default log server + server = "http://athos.ipv6.lip6.fr/activity/push/log" + +def logWrite(request, action, message, objects = None): + + if not apikey : + print "===============>> activity: no apikey" + return + if not secret : + print "===============>> activity: no secret" + return + + timestamp = time.mktime(datetime.datetime.today().timetuple()) + ip = getClientIp(request) log = { - "date" : datetime.today(), - "client_ip" : getClientIp(request), - "host" : request.get_host(), - "referrer" : request.META.get('HTTP_REFERER'), - "user" : request.user + "timestamp" : timestamp, + "client_ip" : ip, + "host" : request.get_host(), + "referrer" : request.META.get('HTTP_REFERER'), + "user" : request.user, + "action" : action, + "message" : message, + "apikey" : apikey, + "signature" : sign(secret, "%s%s%s%s" % (timestamp, ip, request.user, action)), + "slice" : None, + "resource" : None } + if objects and 'slice' in objects : + log['slice'] = objects['slice'] + + if objects and 'resource' in objects : + log['resource'] = objects['resource'] + try : - result = urllib2.urlopen(url, urllib.urlencode(log)) + result = urllib2.urlopen(server, urllib.urlencode(log)) + print "===============>> activity: " + action + " <" + request.user + "> " + message content = result.read() except urllib2.URLError as e: - print "Error: connection to " + url + " impossible, logging disabled" + print "===============>> activity: connection to " + server + " impossible, could not log action" -def spawnThread(request, action, message): - print "aaaaaaaaa" +def log(request, action, message, objects = None): # Create a new thread in Daemon mode to send the log entry - t = threading.Thread(target=logWrite, args=(request, action, message)) + t = threading.Thread(target=logWrite, args=(request, action, message, objects)) t.setDaemon(True) t.start() -def userLogin(request): - spawnThread(request, 'userlogin', 'User logged in') - -def userLogout(request): - spawnThread(request, 'userlogout', 'User logged out') - -def userRegistration(request): - spawnThread(request, 'userregistration', 'User registered') - -def userSliceRequest(request): - spawnThread(request, 'userslicerequest', 'User requested a slice') - -def userContactSupport(request): - spawnThread(request, 'usercontactsupport', 'User contacted suppport') - -def userAddResource(request): - spawnThread(request, 'useraddresource', 'User added resource to slice') - -def userDelResource(request): - spawnThread(request, 'userdelresource', 'User removed resource from slice') - - def getClientIp(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') - return ip \ No newline at end of file + return ip + +# +# sign the request with the secret key +def sign(secret, message): + return hmac.new(secret, msg=message, digestmod=hashlib.sha256).hexdigest() \ No newline at end of file diff --git a/activity/institution.py b/activity/institution.py new file mode 100644 index 00000000..73a23696 --- /dev/null +++ b/activity/institution.py @@ -0,0 +1,11 @@ +# +# log functions for institution activity +# + +import activity + +def joined(request): + activity.log(request, "institution.join", "Institution joined") + +def join(request): + activity.log(request, "institution.join.view", "Institution view join form") \ No newline at end of file diff --git a/activity/slice.py b/activity/slice.py new file mode 100644 index 00000000..f7f1eff4 --- /dev/null +++ b/activity/slice.py @@ -0,0 +1,11 @@ +# +# log functions for slice +# + +import activity + +def validate(request, o): + activity.log(request, "slice.validate", "Slice validation", o) + +def resource(request, o): + activity.log(request, "slice.resource", "Resource reservation", o) \ No newline at end of file diff --git a/activity/user.py b/activity/user.py new file mode 100644 index 00000000..a2790e8a --- /dev/null +++ b/activity/user.py @@ -0,0 +1,29 @@ +# +# log functions for user activity +# + +import activity + +def login(request, state=None): + if state is not None : + activity.log(request, "user.login." + state, "User log in") + else : + activity.log(request, "user.login", "User log in") + +def logout(request): + activity.log(request, "user.logout", "User log out") + +def signup(request): + activity.log(request, "user.signup.view", "User sign up") + +def registered(request): + activity.log(request, "user.signup", "User registered") + +def contact(request): + activity.log(request, "user.contact", "User sent a contact request") + +def slice(request): + activity.log(request, "user.slice", "User requested a slice") + +def resource(request): + activity.log(request, "user.resource", "User added a resource to a slice") \ No newline at end of file diff --git a/auth/views.py b/auth/views.py index 104d11c9..b959e730 100644 --- a/auth/views.py +++ b/auth/views.py @@ -1,12 +1,18 @@ from django.contrib.auth import logout from django.http import HttpResponseRedirect +import activity.user + # hard question : where should we redirect requests to logout if user is not logged in ? def logout_user (request): # check that we're indeed logged in if not request.user.is_authenticated(): return HttpResponseRedirect ('/') print "LOGGING OUT" + + # log user activity + activity.user.logout(request) + logout(request) return HttpResponseRedirect ('/') diff --git a/debian/deb-cheat-sheet b/debian/deb-cheat-sheet index 182c3d3c..3d3f1bc1 100644 --- a/debian/deb-cheat-sheet +++ b/debian/deb-cheat-sheet @@ -21,3 +21,7 @@ dpkg -i foo.deb - or, if this has deps that need to be pulled through apt-get: gdebi foo.deb (install with apt-get install -y gdebi-core) + +--- find which package a file belongs to +apt-file search /path/to/file +(can be installed with : sudo apt-get install apt-file) diff --git a/manifoldapi/manifoldproxy.py b/manifoldapi/manifoldproxy.py index 76f61654..433a854b 100644 --- a/manifoldapi/manifoldproxy.py +++ b/manifoldapi/manifoldproxy.py @@ -55,10 +55,12 @@ with the query passed using POST""" admin_user, admin_password = ConfigEngine().manifold_admin_user_password() manifold_api_session_auth = {'AuthMethod': 'password', 'Username': admin_user, 'AuthString': admin_password} else: - print manifold_query - print request.session['manifold'] - manifold_api_session_auth = request.session['manifold']['auth'] - + if 'manifold' in request.session: + manifold_api_session_auth = request.session['manifold']['auth'] + else: + json_answer=json.dumps({'code':0,'value':[]}) + return HttpResponse (json_answer, mimetype="application/json") + if debug_empty and manifold_query.action.lower()=='get': json_answer=json.dumps({'code':0,'value':[]}) print "By-passing : debug_empty & 'get' request : returning a fake empty list" diff --git a/manifoldapi/static/css/manifold.css b/manifoldapi/static/css/manifold.css index 535950e3..dfb4ab5c 100644 --- a/manifoldapi/static/css/manifold.css +++ b/manifoldapi/static/css/manifold.css @@ -17,3 +17,7 @@ display:none; z-index:100; } +.loading img { + vertical-align:middle; + margin-right:15px; +} diff --git a/manifoldapi/static/js/manifold.js b/manifoldapi/static/js/manifold.js index 30cb75e3..31d4b000 100644 --- a/manifoldapi/static/js/manifold.js +++ b/manifoldapi/static/js/manifold.js @@ -344,13 +344,21 @@ function QueryStore() { default_set = (default_set === undefined) ? STATE_SET_OUT : default_set; var self = this; - var query_ext = this.find_analyzed_query_ext(query_uuid); - var record_key = manifold.metadata.get_key(query_ext.query.object); + var key, object, query_ext, record_key; + + query_ext = this.find_analyzed_query_ext(query_uuid); + object = query_ext.query.object; + if (object.indexOf(':') != -1) { + object = object.split(':')[1]; + } + record_key = manifold.metadata.get_key(object); + // ["start_time", "resource", "end_time"] + // ["urn"] + $.each(records, function(i, record) { //var key = manifold.metadata.get_key(query_ext.query.object); - // ["start_time", "resource", "end_time"] - // ["urn"] + var record_key_value = manifold.record_get_value(record, record_key); query_ext.records.put(record_key_value, record); @@ -553,6 +561,8 @@ function QueryStore() { this.iter_records(query_uuid, function(record_key, record) { var is_reserved, is_pending, in_set, is_unconfigured; + + /* By default, a record is visible unless a filter says the opposite */ var visible = true; var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET); @@ -622,13 +632,16 @@ function QueryStore() { if (op == '=' || op == '==') { if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a") visible = false; + }else if (op == 'included') { + /* By default, the filter returns false unless the record + * field match at least one value of the included statement + */ + visible = false; $.each(value, function(i,x) { if(x == col_value){ visible = true; return false; // ~ break - }else{ - visible = false; } }); }else if (op == '!=') { @@ -659,7 +672,7 @@ function QueryStore() { }); var end = new Date().getTime(); - console.log("APPLY FILTERS took", end - start, "ms"); + console.log("APPLY FILTERS [", filters, "] took", end - start, "ms"); } @@ -1202,7 +1215,15 @@ var manifold = { make_record: function(object, record) { // To make an object a record, we just add the hash function - var key = manifold.metadata.get_key(object); + var key, new_object; + + if (object.indexOf(':') != -1) { + new_object = object.split(':')[1]; + } else { + new_object = object; + } + + key = manifold.metadata.get_key(new_object); record.hashCode = manifold.record_hashcode(key.sort()); record.equals = manifold.record_equals(key); diff --git a/manifoldapi/static/js/plugin.js b/manifoldapi/static/js/plugin.js index 495bdc7d..82a3cd03 100644 --- a/manifoldapi/static/js/plugin.js +++ b/manifoldapi/static/js/plugin.js @@ -19,6 +19,108 @@ ManifoldApp.filter('offset', function() { }; }); +// http://stackoverflow.com/questions/19992090/angularjs-group-by-directive +ManifoldApp.filter('groupBy', ['$parse', function ($parse) { + return function (list, group_by) { + + var filtered = []; + var prev_item = null; + var group_changed = false; + // this is a new field which is added to each item where we append "_CHANGED" + // to indicate a field change in the list + //was var new_field = group_by + '_CHANGED'; - JB 12/17/2013 + var new_field = 'group_by_CHANGED'; + + // loop through each item in the list + angular.forEach(list, function (item) { + + group_changed = false; + + // if not the first item + if (prev_item !== null) { + + // check if any of the group by field changed + + //force group_by into Array + group_by = angular.isArray(group_by) ? group_by : [group_by]; + + //check each group by parameter + for (var i = 0, len = group_by.length; i < len; i++) { + if ($parse(group_by[i])(prev_item) !== $parse(group_by[i])(item)) { + group_changed = true; + } + } + + + }// otherwise we have the first item in the list which is new + else { + group_changed = true; + } + + // if the group changed, then add a new field to the item + // to indicate this + if (group_changed) { + item[new_field] = true; + } else { + item[new_field] = false; + } + + filtered.push(item); + prev_item = item; + + }); + + return filtered; + }; +}]); + +// https://github.com/angular-ui/angular-ui-OLDREPO/blob/master/modules/filters/unique/unique.js +/** + * Filters out all duplicate items from an array by checking the specified key + * @param [key] {string} the name of the attribute of each object to compare for uniqueness + if the key is empty, the entire object will be compared + if the key === false then no filtering will be performed + * @return {array} + */ +ManifoldApp.filter('unique', function () { + + return function (items, filterOn) { + + if (filterOn === false) { + return items; + } + + if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) { + var hashCheck = {}, newItems = []; + + var extractValueToCompare = function (item) { + if (angular.isObject(item) && angular.isString(filterOn)) { + return item[filterOn]; + } else { + return item; + } + }; + + angular.forEach(items, function (item) { + var valueToCheck, isDuplicate = false; + + for (var i = 0; i < newItems.length; i++) { + if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) { + isDuplicate = true; + break; + } + } + if (!isDuplicate) { + newItems.push(item); + } + + }); + items = newItems; + } + return items; + }; +}); + // INHERITANCE // http://alexsexton.com/blog/2010/02/using-inheritance-patterns-to-organize-large-jquery-applications/ // We will use John Resig's proposal @@ -318,7 +420,7 @@ var Plugin = Class.extend({ // you can also call spin_presets() yourself and tweak what you need to, like topmenuvalidation does spin: function (message) { if (!message) { - message = 'Please be patient, this can take a minute or two.'; + message = 'Please be patient, this operation can take a minute or two.'; } $('div.loading').fadeIn('fast'); $('div.loading').find('.message').text(message); diff --git a/myslice/monitor.ini.dist b/myslice/monitor.ini.dist new file mode 100644 index 00000000..4613e1a1 --- /dev/null +++ b/myslice/monitor.ini.dist @@ -0,0 +1,33 @@ +[monitor] +cert = myslice/sfa.cert +pkey = myslice/sfa.pkey + +[onelab] +name = OneLab +url = http://portal.onelab.eu:12345 +type = registry + +[ple] +name=PlanetLab Europe +url = http://sfa3.planet-lab.eu:12346 +type = am + +[nitos] +name = NITOS +url = https://nitlab.inf.uth.gr:8001/RPC2 +type = am + +[iotlab] +name = FIT IoT-Lab +url = http://194.199.16.169:52347 +type = am + +#[virtualwall] +#name = VirtualWall +#url = http://www.wall2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0 +#type = am + +#[w-ilab.t] +#name = w-ilab.t +#url = http://www.wilab2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0 +#type = am diff --git a/myslice/myslice.ini.localhost b/myslice/myslice.ini.localhost index 0467c0ba..524e7be9 100644 --- a/myslice/myslice.ini.localhost +++ b/myslice/myslice.ini.localhost @@ -2,3 +2,6 @@ url = https://localhost:7080 admin_user = admin admin_password = admin + +[myslice] +theme = onelab diff --git a/myslice/theme.py b/myslice/theme.py index d44b854e..e16326b0 100644 --- a/myslice/theme.py +++ b/myslice/theme.py @@ -14,12 +14,12 @@ class ThemeView (object): def template(self): # Load a template from the theme directory if it exists # else load it from the common templates dir - print "THEME = ",self.theme - print "TEMPLATE = ",self.template_name - print "TEMPLATE_DIRS = ",TEMPLATE_DIRS + #print "THEME = ",self.theme + #print "TEMPLATE = ",self.template_name + #print "TEMPLATE_DIRS = ",TEMPLATE_DIRS filename = self.theme + '_' + self.template_name - print any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) - print (os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) + #print any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) + #print (os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) if any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS): return filename else: diff --git a/myslice/urls.py b/myslice/urls.py index b318cb00..7b8dea1e 100644 --- a/myslice/urls.py +++ b/myslice/urls.py @@ -19,7 +19,14 @@ import portal.newsview import plugins.cafe.edelberto +from portal.about import AboutView from portal.registrationview import RegistrationView +from portal.accountview import AccountView, account_process +from portal.institution import InstitutionView + +from portal.supportview import SupportView +from portal.contactview import ContactView + from portal.termsview import TermsView home_view=portal.homeview.HomeView.as_view() @@ -85,7 +92,7 @@ urls = [ (r'^credentials/(?P[^/]+)/?$', 'rest.credentials.dispatch'), # # REST monitoring - #(r'^monitor/sfa/getversion/?$', 'rest.monitor.sfaGetVersion'), + (r'^monitor/services/?$', 'rest.monitor.servicesStatus'), # #(r'^view/?', include('view.urls')), #(r'^list/slices', 'view.list.slices') @@ -101,12 +108,19 @@ urls = [ (r'^testbeds/(?P[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()), (r'^measurements/(?P[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()), (r'^experiment/(?P[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()), - # + + url(r'^about/?$', AboutView.as_view(), name='about'), + + url(r'^institution/?$', InstitutionView.as_view(), name='institution'), (r'^management/requests/?$', portal.managementtabrequests.ManagementRequestsView.as_view()), (r'^management/about/?$', portal.managementtababout.ManagementAboutView.as_view()), # - url(r'^register/?$', RegistrationView.as_view(), name='registration'), + url(r'^register/?$', RegistrationView.as_view(), name='registration'), + url(r'^account/?$', AccountView.as_view(), name='account'), + url(r'^account/account_process/?$', account_process), + url(r'^contact/?$', ContactView.as_view(), name='contact'), url(r'^terms/?$', TermsView.as_view(), name='terms'), + url(r'^support/?$', SupportView.as_view(), name='support'), # url(r'^portal/', include('portal.urls')), diff --git a/plugins/apply/templates/apply.html b/plugins/apply/templates/apply.html index 1a9e8058..f05af49d 100644 --- a/plugins/apply/templates/apply.html +++ b/plugins/apply/templates/apply.html @@ -6,11 +6,10 @@ @@ -43,6 +42,6 @@ - + diff --git a/plugins/googlemap/__init__.py b/plugins/googlemap/__init__.py index 08f2a7bc..8005de29 100644 --- a/plugins/googlemap/__init__.py +++ b/plugins/googlemap/__init__.py @@ -8,7 +8,7 @@ class GoogleMap (Plugin): # googlemap_key : mandatory googlemap API v3 key # latitude,longitude, zoom : the starting point # apparently at some point there has been support for a boolean 'checkboxes' input arg but seems dropped - def __init__ (self, query, googlemap_api_key=None, latitude=43., longitude=7., zoom=4, **settings): + def __init__ (self, query, googlemap_api_key=None, latitude=50., longitude=50, zoom=3, **settings): Plugin.__init__ (self, **settings) self.query=query self.googlemap_api_key=googlemap_api_key diff --git a/plugins/googlemap/static/js/googlemap.js b/plugins/googlemap/static/js/googlemap.js index 3d187571..a3d9ba27 100644 --- a/plugins/googlemap/static/js/googlemap.js +++ b/plugins/googlemap/static/js/googlemap.js @@ -83,8 +83,11 @@ GOOGLEMAP_BGCOLOR_REMOVED = 2; on_show: function(e) { if (debug) messages.debug("googlemap.on_show"); - var googlemap = e.data; - google.maps.event.trigger(googlemap.map, 'resize'); + var self = e.data; + var center = new google.maps.LatLng(self.options.latitude, self.options.longitude); + + google.maps.event.trigger(self.map, 'resize'); + self.map.setCenter(center); }, /************************************************************************** diff --git a/plugins/querytable/__init__.py b/plugins/querytable/__init__.py index 2182e709..995e935e 100644 --- a/plugins/querytable/__init__.py +++ b/plugins/querytable/__init__.py @@ -34,7 +34,8 @@ Current implementation makes the following assumptions """ MAP = { - 'network_hrn' : 'Testbed', + 'facility_name' : 'Facility', + 'testbed_name' : 'Testbed', 'hostname' : 'Resource name', 'type' : 'Type', } diff --git a/plugins/querytable/static/js/querytable.js b/plugins/querytable/static/js/querytable.js index 4b9e5461..7ddf300d 100644 --- a/plugins/querytable/static/js/querytable.js +++ b/plugins/querytable/static/js/querytable.js @@ -12,7 +12,8 @@ QUERYTABLE_BGCOLOR_REMOVED = 2; var QUERYTABLE_MAP = { - 'Testbed': 'network_hrn', + 'Facility': 'facility_name', + 'Testbed': 'testbed_name', 'Resource name': 'hostname', 'Type': 'type', }; diff --git a/plugins/querytable/templates/querytable.html b/plugins/querytable/templates/querytable.html index c843926f..8da79d4a 100644 --- a/plugins/querytable/templates/querytable.html +++ b/plugins/querytable/templates/querytable.html @@ -2,7 +2,7 @@ - {% if checkboxes %}{% endif %} + {% if checkboxes %}{% endif %} {% for column, field in columns.items %} {% endfor %} {% for column, field in hidden_columns.items %} {% endfor %} diff --git a/plugins/scheduler2/static/js/scheduler2.js b/plugins/scheduler2/static/js/scheduler2.js index 04665c66..6b55b92a 100755 --- a/plugins/scheduler2/static/js/scheduler2.js +++ b/plugins/scheduler2/static/js/scheduler2.js @@ -815,6 +815,7 @@ var SCHEDULER_COLWIDTH = 50; var num_hidden_cells; $("#DateToRes").datepicker({ + dateFormat: "D, d M yy", onRender: function(date) { return date.valueOf() < now.valueOf() ? 'disabled' : ''; } diff --git a/plugins/scheduler2/templates/scheduler.html b/plugins/scheduler2/templates/scheduler.html index fee3a7df..e554f2b1 100755 --- a/plugins/scheduler2/templates/scheduler.html +++ b/plugins/scheduler2/templates/scheduler.html @@ -8,22 +8,28 @@
-
- -
-
- -
-
-
-
- - - +
+
+
+ +
+
+ + + +
+
-
-
-
+
+
+
+ +
+
+
+
+
+
diff --git a/plugins/testbeds/__init__.py b/plugins/testbeds/__init__.py index c72f6676..436dc0ee 100644 --- a/plugins/testbeds/__init__.py +++ b/plugins/testbeds/__init__.py @@ -2,13 +2,11 @@ from unfold.plugin import Plugin class TestbedsPlugin(Plugin): - def __init__ (self, query=None, query_networks=None, **settings): + def __init__ (self, query=None, **settings): Plugin.__init__ (self, **settings) # Until we have a proper way to access queries in Python self.query = query - self.query_networks = query_networks - self.query_networks_uuid = query_networks.query_uuid if query_networks else None def template_file (self): return "testbeds.html" @@ -28,7 +26,7 @@ class TestbedsPlugin(Plugin): # query_uuid will pass self.query results to the javascript # and will be available as "record" in : # on_new_record: function(record) - return ['plugin_uuid', 'domid', 'query_uuid', 'query_networks_uuid'] + return ['plugin_uuid', 'domid', 'query_uuid'] def export_json_settings (self): return True diff --git a/plugins/testbeds/static/js/testbeds.js b/plugins/testbeds/static/js/testbeds.js index 623bc91c..e628a679 100644 --- a/plugins/testbeds/static/js/testbeds.js +++ b/plugins/testbeds/static/js/testbeds.js @@ -20,37 +20,115 @@ /* Plugin instance */ $scope.instance = null; + $scope.facility_names = Array(); + $scope.testbed_names = new Object(); + /* Models */ - $scope.testbeds = Array(); + //$scope.testbeds = Array(); + $scope._facility_active = new Object(); + $scope._testbed_active = new Object(); + + $scope.is_facility_active = function(facility) + { + return (($scope._facility_active[facility] === undefined) || $scope._facility_active[facility]); + }; + + $scope.is_testbed_active = function(facility, testbed) + { + return (($scope._testbed_active[facility] === undefined) || + ($scope._testbed_active[facility][testbed] === undefined) || + ($scope._testbed_active[facility][testbed])); + }; + $scope.set_facility_active = function(facility, value) + { + $scope._facility_active[facility] = value; + }; + + $scope.set_testbed_active = function(facility, testbed, value) + { + if ($scope._testbed_active[facility] === undefined) + $scope._testbed_active[facility] = new Object(); + $scope._testbed_active[facility][testbed] = value; + }; + /* Click event */ - $scope.select = function(testbed) + + $scope.select_facility = function(facility) { var selected, prev_selected, num, num_selected, num_prev_selected, filter; - prev_selected = $.map($scope.testbeds, function(x, i) { - return x.active ? x.network_hrn : null; + prev_selected = $.map($scope.facility_names, function(x, i) { + return $scope.is_facility_active(x) ? x : null; }); - testbed.active = !testbed.active; + $scope.set_facility_active(facility, ! $scope.is_facility_active(facility)); - selected = $.map($scope.testbeds, function(x, i) { - return x.active ? x.network_hrn : null; + selected = $.map($scope.facility_names, function(x, i) { + return $scope.is_facility_active(x) ? x : null; }); - num = $scope.testbeds.length; + num = $scope.facility_names.length; + prev_num_selected = prev_selected.length; + num_selected = selected.length; + + if ((prev_num_selected != 0) && (prev_num_selected != num)) { + // Remove previous filter + filter = ['facility_name', 'included', prev_selected]; + manifold.raise_event($scope.instance.options.query_uuid, FILTER_REMOVED, filter); + } + + if (num_selected != num) { + filter = ['facility_name', 'included', selected]; + manifold.raise_event($scope.instance.options.query_uuid, FILTER_ADDED, filter); + } + }; + + $scope.select_testbed = function(facility, testbed) + { + var selected, prev_selected, num, num_selected, num_prev_selected, filter; + + prev_selected = Array(); + $.each($scope.facility_names, function(i, facility_name) { + $.each($scope.testbed_names[facility_name], function(j, testbed_name) { + if ($scope.is_testbed_active(facility_name, testbed_name)) { + // XXX We should have a joint facility/testbed filter + prev_selected.push(testbed_name); + } + }); + + }); + + $scope.set_testbed_active(facility, testbed, ! $scope.is_testbed_active(facility, testbed)); + + selected = Array(); + $.each($scope.facility_names, function(i, facility_name) { + $.each($scope.testbed_names[facility_name], function(j, testbed_name) { + if ($scope.is_testbed_active(facility_name, testbed_name)) { + // XXX We should have a joint facility/testbed filter + selected.push(testbed_name); + } + }); + + }); + + num = 0; + $.each($scope.facility_names, function(i, facility_name) { + num += $scope.testbed_names[facility_name].length; + }); prev_num_selected = prev_selected.length; num_selected = selected.length; - if ((prev_num_selected != 0) && (prev_num_selected != num)) { // Remove previous filter - filter = ['network_hrn', 'included', prev_selected]; + // XXX We should have a joint facility/testbed filter + filter = ['testbed_name', 'included', prev_selected]; manifold.raise_event($scope.instance.options.query_uuid, FILTER_REMOVED, filter); } - if ((num_selected != 0) && (num_selected != num)) { - filter = ['network_hrn', 'included', selected]; + if (num_selected != num) { + // XXX We should have a joint facility/testbed filter + filter = ['testbed_name', 'included', selected]; manifold.raise_event($scope.instance.options.query_uuid, FILTER_ADDED, filter); } }; @@ -80,7 +158,6 @@ this._super(options, element); /* Member variables */ - this.filters = Array(); this.testbeds = Array(); this._get_scope().instance = this; @@ -94,6 +171,7 @@ /* HANDLERS */ /* When a filter is added/removed, update the list of filters local to the plugin */ + /* on_filter_added: function(filter) { this.filters.push(filter); @@ -125,36 +203,30 @@ } } }, - + */ // ... be sure to list all events here - on_networks_query_done: function() + on_query_done: function() { - this.set_networks(); - }, - -/* - var self = this; - console.log('query network DONE'); - $("[id^='testbeds-filter_']").on('click',function(e) { - $(this).toggleClass("active"); - - // avoid multiple calls when an event is raised to manifold.js - e.stopPropagation(); - - value = this.dataset['platform']; - // handle the hrn that include . in their name (has to be in sync with the data from SFA) - //value = value.replace(/\./g,"\\."); - key = "network_hrn"; - op = "included"; - return $(this).hasClass('active') ? self._addFilter(key, op, value) : self._removeFilter(key, op, value); + var scope, query_ext, resources; + scope = this._get_scope(); + query_ext = manifold.query_store.find_analyzed_query_ext(this.options.query_uuid); + resources = query_ext.records.values(); + + $.each(resources, function(i, resource) { + if ($.inArray(resource.facility_name, scope.facility_names) == -1) + scope.facility_names.push(resource.facility_name); + if (scope.testbed_names[resource.facility_name] === undefined) + scope.testbed_names[resource.facility_name] = Array(); + if ($.inArray(resource.testbed_name, scope.testbed_names[resource.facility_name]) == -1) + scope.testbed_names[resource.facility_name].push(resource.testbed_name); }); - - },*/ - /* INTERNAL FUNCTIONS */ + scope.$apply(); + }, - set_networks: function() + /* + on_networks_query_done: function() { var scope = this._get_scope(); var query_ext = manifold.query_store.find_analyzed_query_ext(this.options.query_networks_uuid); @@ -162,12 +234,16 @@ $.each(scope.testbeds, function(i, testbed) { testbed.active = true }); scope.$apply(); }, +*/ + + /* INTERNAL FUNCTIONS */ _get_scope : function() { return angular.element('[ng-controller=TestbedsCtrl]').scope() }, +/* _addFilter: function(key, op, value) { values = Array(); @@ -187,6 +263,7 @@ // Update the filter with the new list of values, ex: [ple,nitos,wilab] manifold.raise_event(this.options.query_uuid, FILTER_ADDED, [key, op, values]); }, + _removeFilter: function(key, op, value) { console.log("remove "+value); @@ -213,7 +290,7 @@ manifold.raise_event(this.options.query_uuid, FILTER_ADDED, [key, op, values]); } } - +*/ }); /* Plugin registration */ diff --git a/plugins/testbeds/templates/testbeds.html b/plugins/testbeds/templates/testbeds.html index 22f7f0ac..296e5efb 100644 --- a/plugins/testbeds/templates/testbeds.html +++ b/plugins/testbeds/templates/testbeds.html @@ -1,24 +1,34 @@
-
Testbeds
+
Facilities
- diff --git a/plugins/univbris/__init__.py b/plugins/univbris/__init__.py index ca96b6f6..89b3ec5e 100644 --- a/plugins/univbris/__init__.py +++ b/plugins/univbris/__init__.py @@ -5,14 +5,21 @@ class Univbris(Plugin): def __init__ (self, query=None, **settings): Plugin.__init__ (self, **settings) self.query=query + self.query_uuid = query.query_uuid if query else None + print "called univbris plugin" def template_file (self): - return "univbris.html" + try: + return "univbris_welcome.html" + except Exception: + print "error template" def requirements (self): reqs = { - 'js_files' : [ - 'js/univbris.js' + 'js_files' : [ "js/spin-presets.js", "js/spin.min.js", "js/jquery.spin.js", + "js/manifold.js", "js/manifold-query.js", + "js/unfold-helper.js", + 'js/univbris.js', ], 'css_files': [ 'css/univbris.css', @@ -24,7 +31,7 @@ class Univbris(Plugin): # query_uuid will pass self.query results to the javascript # and will be available as "record" in : # on_new_record: function(record) - return ['plugin_uuid', 'domid', 'query_uuid'] + return ['plugin_uuid', 'domid', 'query_uuid','init_key',] def export_json_settings (self): return True diff --git a/plugins/univbris/static/js/univbris.js b/plugins/univbris/static/js/univbris.js index 4c84a90c..a22201e9 100644 --- a/plugins/univbris/static/js/univbris.js +++ b/plugins/univbris/static/js/univbris.js @@ -1,6 +1,6 @@ /** - * univbris: test plugin for Bristol University - * Version: 0.1 + * univbris: test ofam plugin for Bristol University + * Version: 0.2 * Description: just testing plugin in myslice * Requires: js/plugin.js * URL: http://www.myslice.info @@ -13,94 +13,21 @@ var Univbris = Plugin.extend({ - /** XXX to check - * @brief Plugin constructor - * @param options : an associative array of setting values - * @param element : - * @return : a jQuery collection of objects on which the plugin is - * applied, which allows to maintain chainability of calls - */ init: function(options, element) { - // Call the parent constructor, see FAQ when forgotten this._super(options, element); - - /* Member variables */ - - /* Plugin events */ - - /* Setup query and record handlers */ - - // Explain this will allow query events to be handled - // What happens when we don't define some events ? - // Some can be less efficient this.listen_query(options.query_uuid); - this.listen_query(options.query_uuid, 'all'); - - /* GUI setup and event binding */ - // call function - - alert("univbris plugin 2"); }, - /* PLUGIN EVENTS */ - // on_show like in querytable - - - /* GUI EVENTS */ - - // a function to bind events here: click change - // how to raise manifold events - - - /* GUI MANIPULATION */ - - // We advise you to write function to change behaviour of the GUI - // Will use naming helpers to access content _inside_ the plugin - // always refer to these functions in the remaining of the code - - show_hide_button: function() - { - // this.id, this.el, this.cl, this.elts - // same output as a jquery selector with some guarantees - }, + on_query_done: function() + { + $("#univbris_welcome").hide(); + jQuery("#univbris_flowspace_selection").show(); + }, - /* TEMPLATES */ - - // see in the html template - // How to load a template, use of mustache - - /* QUERY HANDLERS */ - - // How to make sure the plugin is not desynchronized - // He should manifest its interest in filters, fields or records - // functions triggered only if the proper listen is done - - // no prefix - - on_filter_added: function(filter) - { - - }, - - // ... be sure to list all events here - - /* RECORD HANDLERS */ - on_all_new_record: function(record) - { - // - }, - - /* INTERNAL FUNCTIONS */ - _dummy: function() { - // only convention, not strictly enforced at the moment - }, }); - /* Plugin registration */ $.plugin('Univbris', Univbris); - // TODO Here use cases for instanciating plugins in different ways like in the pastie. - })(jQuery); diff --git a/plugins/univbris/templates/univbris.html b/plugins/univbris/templates/univbris.html index f8aec26c..64e50d11 100644 --- a/plugins/univbris/templates/univbris.html +++ b/plugins/univbris/templates/univbris.html @@ -1,4 +1,2 @@ -
-

Bristol University Island Infrastructure Monitoring

-

information to follow

-
+

gathering information from testbeds

+ diff --git a/plugins/univbris/templates/univbris_welcome.html b/plugins/univbris/templates/univbris_welcome.html new file mode 100644 index 00000000..09cc7b7a --- /dev/null +++ b/plugins/univbris/templates/univbris_welcome.html @@ -0,0 +1,2 @@ +

...gathering information from testbeds...

+ diff --git a/plugins/univbrisfoam/__init__.py b/plugins/univbrisfoam/__init__.py index b732618b..254fda21 100644 --- a/plugins/univbrisfoam/__init__.py +++ b/plugins/univbrisfoam/__init__.py @@ -40,7 +40,7 @@ Current implementation makes the following assumptions as we use 'aoColumnDefs' instead. """ - def __init__ (self, query=None, query_all=None, + def __init__ (self, query=None, query_all=None, sync_query=None, checkboxes=False, columns=None, init_key=None, datatables_options={}, **settings): @@ -49,6 +49,7 @@ Current implementation makes the following assumptions # Until we have a proper way to access queries in Python self.query_all = query_all self.query_all_uuid = query_all.query_uuid if query_all else None + self.sync_query_uuid = sync_query.query_uuid if sync_query else None self.checkboxes = checkboxes # XXX We need to have some hidden columns until we properly handle dynamic queries if columns is not None: @@ -115,6 +116,6 @@ Current implementation makes the following assumptions # the list of things passed to the js plugin def json_settings_list (self): return ['plugin_uuid', 'domid', - 'query_uuid', 'query_all_uuid', + 'query_uuid', 'query_all_uuid', 'sync_query_uuid', 'checkboxes', 'datatables_options', 'hidden_columns', 'init_key',] diff --git a/plugins/univbrisfoam/static/js/univbrisfoam.js b/plugins/univbrisfoam/static/js/univbrisfoam.js index 22ba431b..cbf72ae8 100644 --- a/plugins/univbrisfoam/static/js/univbrisfoam.js +++ b/plugins/univbrisfoam/static/js/univbrisfoam.js @@ -7,8 +7,12 @@ (function($){ var debug=false; + window.query_itr2=0; + table_links=[]; //debug=true + regex_filter="((packet)|(compute))"; + var UnivbrisFoam = Plugin.extend({ init: function(options, element) { @@ -62,9 +66,12 @@ /* Setup query and record handlers */ this.listen_query(options.query_uuid); this.listen_query(options.query_all_uuid, 'all'); + this.listen_query(options.sync_query_uuid,'sync'); /* GUI setup and event binding */ this.initialize_table(); + + jQuery( "#univbris_foam_ports_selection" ).hide(); }, @@ -95,7 +102,7 @@ // Customize the position of Datatables elements (length,filter,button,...) // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>", - sDom: "<'row'<'col-xs-2'l><'col-xs-9'r><'col-xs-2'f>>t<'row'<'col-xs-5'i><'col-xs-5'p>><'next'>", + sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-5'p>>", // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now // hopefully this would come with dataTables v1.10 ? // in any case, search for 'sPaginationType' all over the code for more comments @@ -158,7 +165,7 @@ //self.hide_column(field); }); - $('').appendTo('div.next'); + //$('').appendTo('div.next'); //type="submit" @@ -197,14 +204,14 @@ jQuery( "#univbris_flowspace_selection" ).show(); //$("#multi_flowpspace_ports_selected").append(''); - $("form#uob_form :input[type=checkbox]").each(function(){ - var input = $(this); // This is the jquery object of the input, do what you will - //alert("id: "+ input.attr('id') + " checked: "+ input.is(':checked')); - if(input.is(':checked')==true){ - //alert("got true"); - $("#multi_flowpspace_ports_selected").append(''); - } - }); + //$("form#uob_form :input[type=checkbox]").each(function(){ + // var input = $(this); // This is the jquery object of the input, do what you will + // //alert("id: "+ input.attr('id') + " checked: "+ input.is(':checked')); + // if(input.is(':checked')==true){ + // //alert("got true"); + // $("#multi_flowpspace_ports_selected").append(''); + // } + //}); jQuery( "#univbris_foam_ports_selection" ).hide(); //jQuery( "#univbris_flowspace_selection" ).hide(); @@ -256,6 +263,32 @@ return result; }, + fnLinkClick:function(link){ + //console.log("link has been clicked: "); + //console.log(link.target.id); + + var svg_links = svg.selectAll(".link"); + for(var i=0;i - + diff --git a/plugins/univbrisfoam/templates/univbrisfoam.html b/plugins/univbrisfoam/templates/univbrisfoam.html index 77493974..89a65db6 100644 --- a/plugins/univbrisfoam/templates/univbrisfoam.html +++ b/plugins/univbrisfoam/templates/univbrisfoam.html @@ -19,4 +19,5 @@
{{ column }}{{ column }}
+
diff --git a/plugins/univbrisfv/__init__.py b/plugins/univbrisfv/__init__.py index a44a0ab7..93653b9f 100644 --- a/plugins/univbrisfv/__init__.py +++ b/plugins/univbrisfv/__init__.py @@ -40,7 +40,7 @@ Current implementation makes the following assumptions as we use 'aoColumnDefs' instead. """ - def __init__ (self, query=None, query_all=None, + def __init__ (self, query=None, query_all=None, sync_query=None, checkboxes=False, columns=None, init_key=None, datatables_options={}, **settings): @@ -49,6 +49,7 @@ Current implementation makes the following assumptions # Until we have a proper way to access queries in Python self.query_all = query_all self.query_all_uuid = query_all.query_uuid if query_all else None + self.sync_query_uuid = sync_query.query_uuid if sync_query else None self.checkboxes = checkboxes # XXX We need to have some hidden columns until we properly handle dynamic queries if columns is not None: @@ -118,6 +119,6 @@ Current implementation makes the following assumptions # the list of things passed to the js plugin def json_settings_list (self): return ['plugin_uuid', 'domid', - 'query_uuid', 'query_all_uuid', + 'query_uuid', 'query_all_uuid', 'sync_query_uuid', 'checkboxes', 'datatables_options', 'hidden_columns', 'init_key',] diff --git a/plugins/univbrisfv/__init__1.py b/plugins/univbrisfv/__init__1.py index 73cd5520..853bc1ee 100644 --- a/plugins/univbrisfv/__init__1.py +++ b/plugins/univbrisfv/__init__1.py @@ -1,15 +1,14 @@ from unfold.plugin import Plugin class UnivbrisFv (Plugin): - """ - //////////////////////////////////////// - modified querytable for univbris foam - /////////////////////////////////////// - """ +""" +//////////////////////////////////////// +modified querytable for univbris foam +///////////////////////////////////////""" def __init__ (self, init_key=None,datatables_options={}, **settings): - Plugin.__init__ (self, **settings) - self.columns = list (['switch dpid','port no<->peer dpid/port no.','selected']) + Plugin.__init__ (self, **settings) + self.columns = list (['switch dpid','port no<->peer dpid/port no.','selected']) self.init_key=init_key self.datatables_options=datatables_options diff --git a/plugins/univbrisfv/static/js/univbrisfv.js b/plugins/univbrisfv/static/js/univbrisfv.js index 82581ab2..7cefef60 100644 --- a/plugins/univbrisfv/static/js/univbrisfv.js +++ b/plugins/univbrisfv/static/js/univbrisfv.js @@ -11,8 +11,10 @@ pk_flowspace_index=0; opt_flowspace_index=0; + pk_mode=0; fvf_add=1; fvf_nrow=0; + var UnivbrisFv = Plugin.extend({ @@ -95,8 +97,11 @@ initialize_table: function() { + + /* Transforms the table into DataTable, and keep a pointer to it */ var self = this; + //alert(self.options); var actual_options = { // Customize the position of Datatables elements (length,filter,button,...) // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time @@ -179,7 +184,7 @@ $('').appendTo('div.buttons');**/ - jQuery( "#univbris_flowspace_selection" ).hide(); + //jQuery( "#univbris_flowspace_selection" ).hide(); //$('next link').appendTo('div.submit'); @@ -189,121 +194,354 @@ //this.new_record("t"); //this.new_record("t"); this._querytable_draw_callback(); - + jQuery("#univbris_flowspace_selection").hide(); }, // initialize_table fnButsubmit:function(e){ - alert("submitting"); - var rows = $("#univbris_flowspace_selection__table").dataTable().fnGetNodes(); - var cells=[]; - for(var i=0;i=7){ + //alert(controller.substring(0,4)) + if(controller.substring(0,4)=="tcp:" | controller.substring(0,4)=="ssl:"){ + var controller_ip=controller.substring(4,controller.length); + //alert(controller_ip) + var index=controller_ip.indexOf(":") + if (index!=-1){ + var controller_ip1=controller_ip.substring(0,index); + //alert(controller_ip1); + var ip_validator= /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + if (!controller_ip1.match(ip_validator)){ + throw "Incorrect IP format"; + } + //else{ + // throw "incorrect ip"; + //} + + var controller_port=controller_ip.substring(index+1,controller_ip.length); + if(!isNaN(controller_port)){ + controller_port=parseInt(controller_port,10); + if (!((controller_port >0) & (controller_port <65536))){ + //if(controller_port >0){ + throw "Incorrect controller port"; + } + //else{ + // throw "correct port"; + //} + } + else{ + throw "Incorrect controller port"; + } + } + else{ + throw "Incorrect controller specified"; + } + } + else{ + throw "Controller must start with tcp: or ssl:"; + } + + } + else{ + throw "Incorrect controller specified"; + } + //end of validation of controller field + + var rows = $("#univbris_flowspace_selection__table").dataTable().fnGetNodes(); + var cells=[]; + + var json_rspec={}; + json_rspec["controller"]=controller; + var groups_rspec=[]; + var matches_rspec=[]; + + if (rows.length <=0) { + throw "No Flowspace defined" + } + + + var queryStringToJSON = function (url) { + if (url === '') return ''; + var pairs = (url || location.search).slice(1).split('&'); + var result = {}; + for (var idx in pairs) { + if ($.isNumeric(idx)) { + var pair = pairs[idx].split('='); + if (!!pair[0]){ + result[pair[0].toLowerCase()] = decodeURIComponent(pair[1].replace(/\+/g, " ") || ''); + } + } + } + return result; } - } - var controller= $('#controller_loc').val(); + for(var i=0;i "+$("#flowspace_name").val()+"

"; - this.table.fnDeleteRow(fvf_nrow); - this.table.fnAddData([string, 'Edit', 'Delete']); - jQuery( "#univbris_flowspace_selection" ).show(); - //onclick=\'fnEdit("test");\' - //alert("myserialise: "+form); - //alert("added flowspace:" + sData); - }, @@ -641,6 +879,8 @@ on_all_query_done: function() { if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines"); + + this.table.fnAddData (this.buffered_lines); this.buffered_lines=[]; diff --git a/plugins/univbrisfv/templates/univbrisfv.html b/plugins/univbrisfv/templates/univbrisfv.html index 44d51af8..8ddb249d 100644 --- a/plugins/univbrisfv/templates/univbrisfv.html +++ b/plugins/univbrisfv/templates/univbrisfv.html @@ -21,7 +21,7 @@ - ' + ' diff --git a/plugins/univbrisfvf/static/js/univbrisfvf.js b/plugins/univbrisfvf/static/js/univbrisfvf.js index a21e5246..0422bd7c 100644 --- a/plugins/univbrisfvf/static/js/univbrisfvf.js +++ b/plugins/univbrisfvf/static/js/univbrisfvf.js @@ -7,7 +7,9 @@ (function($){ var debug=false; - debug=true + debug=true; + sync_query_uuid=""; + var UnivbrisFvf = Plugin.extend({ @@ -171,55 +173,122 @@ fnCancel:function(e){ //var sData=$("#uob_fv_table_form").find("input").serialize(); //alert("add flowspace:" + sData); + //alert("cancel"); + jQuery("#uob_ofv_table_form").hide(); jQuery("#uob_fv_table_form").hide(); + jQuery( "#univbris_foam_ports_selection" ).hide(); jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + /*var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var nodes = $('input',port_table.fnGetNodes()); + for(var i=0;i "+$("#flowspace_name").val()+"

"; + this.table = $("#univbris_flowspace_selection__table").dataTable(); + var val_status=validateFvfForm(); + if (val_status == true){ + pk_flowspace_index=1+pk_flowspace_index; + flowspace=sData; + var m_form=form+","+form2; + var string = "

"+$("#flowspace_name").val()+"

"; + if(fvf_add==1){ + this.table.fnAddData([string, 'Edit', 'Delete']); + } + else{ + this.table.fnDeleteRow(fvf_nrow); this.table.fnAddData([string, 'Edit', 'Delete']); - jQuery( "#univbris_flowspace_selection" ).show(); - } + } + jQuery( "#univbris_foam_ports_selection" ).hide(); + jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + } + else{ + alert("validation failed"); + jQuery("#uob_fv_table_form").show(); + jQuery("#uob_ofv_table_form").hide(); + jQuery( "#univbris_foam_ports_selection" ).show(); + } + } + else{ + + var sData=$("#uob_ofv_table_form").find("input").serialize(); + var form =serializeAnything("#uob_ofv_table_form"); + var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var form2=$('input',port_table.fnGetNodes()).serialize(); + var nodes = $('input',port_table.fnGetNodes()); + + this.table = $("#univbris_flowspace_selection__table").dataTable(); + + var val_status=validateoFvfForm(); + if (val_status == true){ + opt_flowspace_index=1+opt_flowspace_index; + flowspace=sData; + var m_form=form+","+form2; + var string = "

"+$("#oflowspace_name").val()+"

"; + if(fvf_add==1){ + this.table.fnAddData([string, 'Edit', 'Delete']); + } + else{ + this.table.fnDeleteRow(fvf_nrow); + this.table.fnAddData([string, 'Edit', 'Delete']); + } + jQuery( "#univbris_foam_ports_selection" ).hide(); + jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + } + else{ + alert("validation failed"); + jQuery("#uob_ofv_table_form").show(); + jQuery("#uob_fv_table_form").hide(); + jQuery( "#univbris_foam_ports_selection" ).show(); + } + + } + /*} else{ jQuery("#uob_fv_table_form").hide(); + jQuery("#uob_ofv_table_form").hide(); var sData=$("#uob_fv_table_form").find("input").serialize(); var form =serializeAnything("#uob_fv_table_form"); + //var form2=serializeAnything("#uob_form"); + + var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var form2=$('input',port_table.fnGetNodes()).serialize(); this.table = $("#univbris_flowspace_selection__table").dataTable(); flowspace=sData; - - var string = "

"+$("#flowspace_name").val()+"

"; + var m_form=form+","+form2; + var string = "

"+$("#flowspace_name").val()+"

"; this.table.fnDeleteRow(fvf_nrow); this.table.fnAddData([string, 'Edit', 'Delete']); + + jQuery( "#univbris_foam_ports_selection" ).hide(); jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); - } + }*/ }, - fnModflowspace:function(e){ - //alert("modify"); - - jQuery("#uob_fv_table_form").hide(); - var sData=$("#uob_fv_table_form").find("input").serialize(); - var form =serializeAnything("#uob_fv_table_form"); - this.table = $("#univbris_flowspace_selection__table").dataTable(); - flowspace=sData; - alert(form+"\n"+sData); - - var string = "

"+$("#flowspace_name").val()+"

"; - this.table.fnDeleteRow(fvf_nrow); - this.table.fnAddData([string, 'Edit', 'Delete']); - jQuery( "#univbris_flowspace_selection" ).show(); - }, - /** * @brief Determine index of key in the table columns * @param key @@ -311,24 +380,6 @@ line.push("first"); } - - /*if (typeof colnames[j] == 'undefined') { - line.push('...'); - } else if (colnames[j] == 'hostname') { - if (record['type'] == 'resource,link') - //TODO: we need to add source/destination for links - line.push(''); - else - line.push(record['hostname']); - - } else if (colnames[j] == 'hrn' && typeof(record) != 'undefined') { - line.push(' '+record['hrn']); - } else { - if (record[colnames[j]]) - line.push(record[colnames[j]]); - else - line.push(''); - }*/ } // catch up with the last column if checkboxes were requested @@ -635,9 +686,9 @@ $("#addflowspaceform").unbind('click').click(this, this.fnAddflowspace); } else{ - $("[id='addflowspaceform'").unbind('click').click(this, this.fnModflowspace); + $("[id='addflowspaceform']").unbind('click').click(this, this.fnModflowspace); } - $("#cancel_addflowspaceform").unbind('click').click(this,this.fnCancel); + $("#cancel_addflowspaceform").unbind('click').click(this,this.fnCancel); if (!this.table) return; @@ -717,38 +768,521 @@ })(jQuery); +function deserializeDT(d){ -function fnPopTable(e){ - //alert("e: "+e); - //this.table = $("#univbris_flowspace_selection__table").dataTable(); - //alert(this.table); - /**var rows = $("#univbris_flowspace_selection__table").dataTable().fnGetNodes(); - for(var i=0;i= 19) { + status=true; + } + + if (port_selected==false & checked == 18){ + alert("you need to select at least one port"); + } + else if (port_selected==false & checked <= 18){ + alert("you need to select at least one port and correct other flowspace parameter errors"); + } + else if (port_selected==true & checked <= 18){ + alert("you need to correct other flowspace parameter errors"); + } + + //alert("validator status:"+status+" checked:"+checked); + return status; +} + +function validateoFvfForm(){ + var status = false; + var checked =0; + + //row 1 validation + if (wavelengthValidator($('#uob_ofv_table_wavelength').val())==false){ + $("#uob_ofv_table_wavelength").addClass('error'); + $("#uob_ofv_table_wavelength_error").show(); + } + else { + checked++; + } + + + + //validate that at least one port is selected + var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var nodes = $('input',port_table.fnGetNodes()); + + var port_selected=false; + for(var i=0;i= 2) { + status=true; + } + + if (port_selected==false & checked == 1){ + alert("you need to select at least one port"); + } + else if (port_selected==false & checked <= 1){ + alert("you need to select at least one port and correct other flowspace parameter errors"); + } + else if (port_selected==true & checked <= 1){ + alert("you need to correct other flowspace parameter errors"); + } + + //alert("validator status:"+status+" checked:"+checked); + return status; +} + + function fnGetSelected( oTableLocal ) { @@ -777,7 +1311,28 @@ function serializeAnything (form){ }); return toReturn.join("&").replace(/%20/g, "+"); +} + +function hideFvfError(){ + $("[id*=_error]").hide(); + console + $("#uob_fv_table_form :input").each(function(){ + try{ + $(this).removeClass('error'); + } + catch (err){ + } + + }); + + $("#uob_ofv_table_form :input").each(function(){ + try{ + $(this).removeClass('error'); + } + catch (err){ + } + }); } diff --git a/plugins/univbrisfvf/templates/univbrisfv.html b/plugins/univbrisfvf/templates/univbrisfv.html index 44d51af8..d6900f63 100644 --- a/plugins/univbrisfvf/templates/univbrisfv.html +++ b/plugins/univbrisfvf/templates/univbrisfv.html @@ -21,7 +21,7 @@ - ' + ' diff --git a/plugins/univbrisfvf/templates/univbrisfvf.html b/plugins/univbrisfvf/templates/univbrisfvf.html index 63973cb3..bb531c5f 100644 --- a/plugins/univbrisfvf/templates/univbrisfvf.html +++ b/plugins/univbrisfvf/templates/univbrisfvf.html @@ -9,22 +9,37 @@ .multiselect label { display:block; } - l + .multiselect-on { color:#ffffff; background-color:#000099; } + +.error{ +border:2px solid red; +} +
- +

+ + + + + + + @@ -46,10 +65,12 @@ + @@ -63,6 +84,9 @@ + @@ -76,6 +100,9 @@ + @@ -89,6 +116,9 @@ + @@ -102,6 +132,9 @@ + @@ -115,6 +148,9 @@ + @@ -128,6 +164,9 @@ + @@ -141,19 +180,13 @@ + - - - - +
Flowspace Name - + +
+
from
+
+
to
+
MAC Source @@ -37,6 +52,10 @@ +

mac format should be ff:ff:ff:ff:ff:ff

+
MAC Destination - +

mac format should be ff:ff:ff:ff:ff:ff

+
Ethernet Type +

dl type format should be hex format: 0xffff

+
VLAN ID +

vlan value should be integer between 1 and 4095

+
IP Source +

ip format should be xxx.xxx.xxx.xxx

+
IP Destination +

ip format should be xxx.xxx.xxx.xxx

+
IP Protocol +

ip protocol should be integer between 0 and 255

+
TCP/UDP Source +

tcp value should be integer between 0 and 65535

+
TCP/UDP Destination +

tcp value should be integer between 0 and 65535

+
Ports - - -
-
-
-
diff --git a/plugins/univbrisfvfo/__init__.py b/plugins/univbrisfvfo/__init__.py new file mode 100644 index 00000000..b774faee --- /dev/null +++ b/plugins/univbrisfvfo/__init__.py @@ -0,0 +1,87 @@ +from unfold.plugin import Plugin + +class UnivbrisFvfo (Plugin): + + """ + +//////////////////////////////////////// + +modified querytable for univbris foam +/////////////////////////////////////// + +A plugin for displaying a query as a list + +More accurately, we consider a subject entity (say, a slice) +that can be linked to any number of related entities (say, resources, or users) +The 'query' argument will correspond to the subject, while +'query_all' will fetch the complete list of +possible candidates for the relationship. + +Current implementation makes the following assumptions +* query will only retrieve for the related items a list of fields + that corresponds to the initial set of fields displayed in the table +* query_all on the contrary is expected to return the complete set of + available attributes that may be of interest, so that using a QueryEditor + one can easily extend this table without having to query the backend +* checkboxes is a boolean flag, set to true if a rightmost column + with checkboxes is desired +* optionally pass columns as the initial set of columns + if None then this is taken from the query's fields +* init_key is the name of a column that should appear in both queries + and used internally in the plugin for checkboxes initialization. + If not specified, metadata will be used to find out a primary key. + However in the case of nodes & slice for example, the default key + as returned by the metadata would be 'urn', but 'urn' could only + be used for this purpose if it gets displayed initially, which is + not necessarily a good idea. + This is why a slice view would use 'hrn' here instead. +* datatables_options are passed to dataTables as-is; + however please refrain from passing an 'aoColumns' + as we use 'aoColumnDefs' instead. +""" + + def __init__ (self, query=None, query_all=None, + checkboxes=False, columns=None, + init_key=None, + datatables_options={}, **settings): + Plugin.__init__ (self, **settings) + self.query = query + # Until we have a proper way to access queries in Python + self.query_all = query_all + self.query_all_uuid = query_all.query_uuid if query_all else None + + + def template_file (self): + return "univbrisfvfo.html" + + def template_env (self, request): + env={} + env.update(self.__dict__) + #env['columns']=self.columns + return env + + def requirements (self): + reqs = { + 'js_files' : [ "js/spin-presets.js", "js/spin.min.js", "js/jquery.spin.js", + "js/dataTables.js", "js/dataTables.bootstrap.js", "js/with-datatables.js", + "js/manifold.js", "js/manifold-query.js", + "js/unfold-helper.js", + # querytable.js needs to be loaded after dataTables.js as it extends + # dataTableExt.afnSortData + "js/univbrisfvfo.js", + ] , + 'css_files': [ "css/dataTables.bootstrap.css", + # hopefully temporary, when/if datatables supports sPaginationType=bootstrap3 + # for now we use full_numbers, with our own ad hoc css + "css/dataTables.full_numbers.css", + "css/univbrisfvfo.css", + ], + } + return reqs + + # the list of things passed to the js plugin + def json_settings_list (self): + return ['plugin_uuid', 'domid', + 'query_uuid', 'query_all_uuid', + 'checkboxes', 'datatables_options', + 'hidden_columns', 'init_key',] diff --git a/plugins/univbrisfvfo/static/css/univbrisfvfo.css b/plugins/univbrisfvfo/static/css/univbrisfvfo.css new file mode 100644 index 00000000..4b518d3c --- /dev/null +++ b/plugins/univbrisfvfo/static/css/univbrisfvfo.css @@ -0,0 +1,65 @@ + +/* the bottom of the datatable needs more space */ +div.univbrisfvf-spacer { padding: 8px 4px 15px 4px; } + +div.UnivbrisFv table.dataTable th { + font: bold 12px/22px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; + color: #4f6b72; + border-right: 1px solid #C1DAD7; + border-bottom: 1px solid #C1DAD7; + border-top: 1px solid #C1DAD7; + letter-spacing: 1px; + text-transform: uppercase; + text-align: left; + padding: 8px 12px 4px 20px; + vertical-align:middle; +/* background: #CAE8EA url(../img/tablesort-header.jpg) no-repeat; */ +} + +div.UnivbrisFv table.dataTable th.checkbox { + padding-left: 14px; +} + +div.UnivbrisFv table.dataTable td, div.UnivbrisFv table.dataTable textarea, div.UnivbrisFv table.dataTable input [type="text"] { + font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; + color: #660099; + border-right: 1px solid #C1DAD7; + border-bottom: 1px solid #C1DAD7; +} +div.UnivbrisFv table.dataTable td { + padding: 4px 8px 4px 8px; + /* this applies on even rows only, odd ones have a setting in bootstrap of rbg 249.249.249 */ + background-color: #f4f4f4; + color: #660099; +} +div.UnivbrisFv table.dataTable td a { + font-weight:normal; +} +/* these come from bootstrap */ +div.UnivbrisFv div.dataTables_info { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +/* one could think or using repeat-x here but that's not working because of the arrows + * we might need to make these wider some day + * and/or to add background-color: #caebea + * which would look less conspicuous in case of overflow +*/ + +div.UnivbrisFv table.dataTable thead .sorting { background: url('../img/tablesort-header-sortable.png') no-repeat; } +div.UnivbrisFv table.dataTable thead .sorting_asc { background: url('../img/tablesort-header-up.png') no-repeat; } +div.UnivbrisFv table.dataTable thead .sorting_desc { background: url('../img/tablesort-header-down.png') no-repeat; } +/* this icons set does not have that exact equivalent - using an approximation for now */ +div.UnivbrisFv table.dataTable thead .sorting_asc_disabled { background: url('../img/tablesort-header.png') repeat-x; } +div.UnivbrisFv table.dataTable thead .sorting_desc_disabled { background: url('../img/tablesort-header.png') repeat-x; } + +/* the footers are not active */ +div.UnivbrisFv table.dataTable tfoot { + background: url('../img/tablesort-header.png') repeat-x; + background-color: #caebea; +} +/* and when sorting is turned off it's useful to set this on header too */ +div.UnivbrisFv table.dataTable thead { + background: url('../img/tablesort-header.png') repeat-x; + background-color: #caebea; +} diff --git a/plugins/univbrisfvfo/static/img/README b/plugins/univbrisfvfo/static/img/README new file mode 100644 index 00000000..5df2d69b --- /dev/null +++ b/plugins/univbrisfvfo/static/img/README @@ -0,0 +1,2 @@ +these styling elements come from plekit with a simple transition to png +they're currently not all used in myslice diff --git a/plugins/univbrisfvfo/static/img/tablesort-bullet1.png b/plugins/univbrisfvfo/static/img/tablesort-bullet1.png new file mode 100644 index 00000000..4304f360 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-bullet1.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-bullet2.png b/plugins/univbrisfvfo/static/img/tablesort-bullet2.png new file mode 100644 index 00000000..4f181e19 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-bullet2.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-col-alt.png b/plugins/univbrisfvfo/static/img/tablesort-col-alt.png new file mode 100644 index 00000000..8179f830 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-col-alt.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-gradient.png b/plugins/univbrisfvfo/static/img/tablesort-gradient.png new file mode 100644 index 00000000..26558a49 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-gradient.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-header-down.png b/plugins/univbrisfvfo/static/img/tablesort-header-down.png new file mode 100644 index 00000000..c8ed6576 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-header-down.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-header-sortable.png b/plugins/univbrisfvfo/static/img/tablesort-header-sortable.png new file mode 100644 index 00000000..0c169040 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-header-sortable.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-header-up.png b/plugins/univbrisfvfo/static/img/tablesort-header-up.png new file mode 100644 index 00000000..d12fe2a5 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-header-up.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-header.png b/plugins/univbrisfvfo/static/img/tablesort-header.png new file mode 100644 index 00000000..cff526f9 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-header.png differ diff --git a/plugins/univbrisfvfo/static/img/tablesort-td-alt.png b/plugins/univbrisfvfo/static/img/tablesort-td-alt.png new file mode 100644 index 00000000..ef5ab358 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/tablesort-td-alt.png differ diff --git a/plugins/univbrisfvfo/static/img/toggle-hidden.png b/plugins/univbrisfvfo/static/img/toggle-hidden.png new file mode 100755 index 00000000..023f22a8 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/toggle-hidden.png differ diff --git a/plugins/univbrisfvfo/static/img/toggle-visible.png b/plugins/univbrisfvfo/static/img/toggle-visible.png new file mode 100755 index 00000000..baf6c286 Binary files /dev/null and b/plugins/univbrisfvfo/static/img/toggle-visible.png differ diff --git a/plugins/univbrisfvfo/static/js/univbrisfvfo.js b/plugins/univbrisfvfo/static/js/univbrisfvfo.js new file mode 100644 index 00000000..7d502a85 --- /dev/null +++ b/plugins/univbrisfvfo/static/js/univbrisfvfo.js @@ -0,0 +1,1266 @@ +/** + * Description: display a query result in a datatables-powered + * Copyright (c) 2012-2013 UPMC Sorbonne Universite - INRIA + * License: GPLv3 + */ + +(function($){ + + var debug=false; + debug=true; + + + var UnivbrisFvfo = Plugin.extend({ + + init: function(options, element) { + //alert("foam init called"); + this.classname="univbrisfvfo"; + this._super(options, element); + + //alert(this.options.hidden_columns); + /* Member variables */ + // in general we expect 2 queries here + // query_uuid refers to a single object (typically a slice) + // query_all_uuid refers to a list (typically resources or users) + // these can return in any order so we keep track of which has been received yet + //this.received_all_query = false; + //this.received_query = false; + + // We need to remember the active filter for datatables filtering + this.filters = Array(); + + // an internal buffer for records that are 'in' and thus need to be checked + this.buffered_records_to_check = []; + // an internal buffer for keeping lines and display them in one call to fnAddData + this.buffered_lines = []; + + /* Events */ + // xx somehow non of these triggers at all for now + //this.elmt().on('show', this, this.on_show); + //this.elmt().on('shown.bs.tab', this, this.on_show); + //this.elmt().on('resize', this, this.on_resize); + + //var query = manifold.query_store.find_analyzed_query(this.options.query_uuid); + //this.object = query.object; + + //// we need 2 different keys + // * canonical_key is the primary key as derived from metadata (typically: urn) + // and is used to communicate about a given record with the other plugins + // * init_key is a key that both kinds of records + // (i.e. records returned by both queries) must have (typically: hrn or hostname) + // in general query_all will return well populated records, but query + // returns records with only the fields displayed on startup + var keys = manifold.metadata.get_key(this.object); + this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined; + // + this.init_key = this.options.init_key; + // have init_key default to canonical_key + this.init_key = this.init_key || this.canonical_key; + // sanity check + if ( ! this.init_key ) messages.warning ("UnivbrisFvfo : cannot find init_key"); + if ( ! this.canonical_key ) messages.warning ("UnivbrisFvfo : cannot find canonical_key"); + if (debug) messages.debug("UnivbrisFvfo: canonical_key="+this.canonical_key+" init_key="+this.init_key); + + /* Setup query and record handlers */ + //this.listen_query(options.query_uuid); + //this.listen_query(options.query_all_uuid, 'all'); + + /* GUI setup and event binding */ + //this.initialize_table(); + //alert("init fvf"); + jQuery("#uob_ofv_table_form").hide(); + + //$('').appendTo('#fvf_table_button'); + + //$('').appendTo('#fvf_table_button'); + + this._querytable_draw_callback(); + }, + + /* PLUGIN EVENTS */ + + on_show: function(e) { + if (debug) messages.debug("univbrisfvfo.on_show"); + var self = e.data; + self.table.fnAdjustColumnSizing(); + }, + + on_resize: function(e) { + if (debug) messages.debug("univbrisfvfo.on_resize"); + var self = e.data; + self.table.fnAdjustColumnSizing(); + }, + + /* GUI EVENTS */ + + /* GUI MANIPULATION */ + + initialize_table: function() + { + /* Transforms the table into DataTable, and keep a pointer to it */ + var self = this; + var actual_options = { + // Customize the position of Datatables elements (length,filter,button,...) + // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time + //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>", + //sDom: "<'row'<'col-xs-2'l><'col-xs-9'r><'col-xs-2'f>>t<'row'<'col-xs-5'i><'col-xs-5'p>><'next'>", + sDom: "<'row'<'col-xs-9'r>t<'buttons'>", + // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now + // hopefully this would come with dataTables v1.10 ? + // in any case, search for 'sPaginationType' all over the code for more comments + sPaginationType: 'bootstrap', + // Handle the null values & the error : Datatables warning Requested unknown parameter + // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2 + aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}], + // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty + // sScrollX: '100%', /* Horizontal scrolling */ + bProcessing: false, /* Loading */ + fnDrawCallback: function() { self._querytable_draw_callback.call(self);} + //fnFooterCallback: function() {self._univbrisfvf_footer_callback.call(self,nFoot, aData, iStart, iEnd, aiDisplay)};} + // XXX use $.proxy here ! + }; + // the intention here is that options.datatables_options as coming from the python object take precedence + // xxx DISABLED by jordan: was causing errors in datatables.js + // xxx turned back on by Thierry - this is the code that takes python-provided options into account + // check your datatables_options tag instead + // however, we have to accumulate in aoColumnDefs from here (above) + // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs) + if ( 'aoColumnDefs' in this.options.datatables_options) { + actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']); + delete this.options.datatables_options['aoColumnDefs']; + } + $.extend(actual_options, this.options.datatables_options ); + this.table = $("#univbris_flowspace_form__table").dataTable(actual_options); + + //alert(this.table); + + /* Setup the SelectAll button in the dataTable header */ + /* xxx not sure this is still working */ + var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid); + oSelectAll.html("Select All"); + oSelectAll.button(); + oSelectAll.css('font-size','11px'); + oSelectAll.css('float','right'); + oSelectAll.css('margin-right','15px'); + oSelectAll.css('margin-bottom','5px'); + oSelectAll.unbind('click'); + oSelectAll.click(this._selectAll); + + /* Add a filtering function to the current table + * Note: we use closure to get access to the 'options' + */ + $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { + /* No filtering if the table does not match */ + if (oSettings.nTable.id != self.options.plugin_uuid + '__table') + return true; + return self._querytable_filter.call(self, oSettings, aData, iDataIndex); + }); + + //alert(this.options.hidden_columns); + + /* Processing hidden_columns */ + $.each(this.options.hidden_columns, function(i, field) { + //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field); + //alert (field); + self.hide_column(field); + //self.hide_column(field); + }); + + }, // initialize_table + + + fnCancel:function(e){ + //var sData=$("#uob_fv_table_form").find("input").serialize(); + //alert("add flowspace:" + sData); + //alert("cancel"); + + jQuery("#uob_ofv_table_form").hide(); + jQuery( "#univbris_foam_ports_selection" ).hide(); + jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + /*var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var nodes = $('input',port_table.fnGetNodes()); + for(var i=0;i "+$("#flowspace_name").val()+"

"; + this.table.fnAddData([string, 'Edit', 'Delete']); + jQuery( "#univbris_foam_ports_selection" ).hide(); + jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + } + else{ + alert("validation failed"); + jQuery("#uob_ofv_table_form").show(); + jQuery( "#univbris_foam_ports_selection" ).show(); + } + } + else{ + jQuery("#uob_fv_table_form").hide(); + var sData=$("#uob_fv_table_form").find("input").serialize(); + var form =serializeAnything("#uob_fv_table_form"); + //var form2=serializeAnything("#uob_form"); + + var port_table=$("#univbris_foam_ports_selection__table").dataTable(); + var form2=$('input',port_table.fnGetNodes()).serialize(); + this.table = $("#univbris_flowspace_selection__table").dataTable(); + flowspace=sData; + var m_form=form+","+form2; + var string = "

"+$("#flowspace_name").val()+"

"; + this.table.fnDeleteRow(fvf_nrow); + this.table.fnAddData([string, 'Edit', 'Delete']); + + jQuery( "#univbris_foam_ports_selection" ).hide(); + jQuery( "#univbris_flowspace_selection" ).show(); + jQuery('#topo_plugin').hide(); + + } + }, + + + /** + * @brief Determine index of key in the table columns + * @param key + * @param cols + */ + getColIndex: function(key, cols) { + var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; }); + return (tabIndex.length > 0) ? tabIndex[0] : -1; + }, // getColIndex + + // create a checkbox tag + // computes 'id' attribute from canonical_key + // computes 'init_id' from init_key for initialization phase + // no need to used convoluted ids with plugin-uuid or others, since + // we search using table.$ which looks only in this table + checkbox_html : function (record) { + var result=""; + // Prefix id with plugin_uuid + result += "
a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + div.innerHTML = ""; + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + support.noCloneEvent = true; + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + fragment = div = input = null; +})(); + + +(function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) + for ( i in { submit: true, change: true, focusin: true }) { + eventName = "on" + i; + + if ( !(support[ i + "Bubbles" ] = eventName in window) ) { + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && ( + // Support: IE < 9 + src.returnValue === false || + // Support: Android < 4.0 + src.getPreventDefault && src.getPreventDefault() ) ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!support.noCloneEvent || !support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + deletedIds.push( id ); + } + } + } + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "