From d8037c05130786c84c439e20962fc02952defe05 Mon Sep 17 00:00:00 2001 From: Michael Jett Date: Mon, 27 Aug 2012 16:17:22 -0400 Subject: [PATCH 01/10] Redirect URL UI initial commit --- .../src/main/webapp/resources/template/client.html | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openid-connect-server/src/main/webapp/resources/template/client.html b/openid-connect-server/src/main/webapp/resources/template/client.html index a00976175..4250c4492 100644 --- a/openid-connect-server/src/main/webapp/resources/template/client.html +++ b/openid-connect-server/src/main/webapp/resources/template/client.html @@ -73,6 +73,19 @@

You may enter multiple URIs separated by a new lines

+ + + + + + + + + + + + +
http://google.com
From 5377a2bac4ff2e60af8431778c215304b7328f5b Mon Sep 17 00:00:00 2001 From: Michael Jett Date: Mon, 27 Aug 2012 17:12:02 -0400 Subject: [PATCH 02/10] Redirect URI UI updates --- .../src/main/webapp/resources/template/client.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openid-connect-server/src/main/webapp/resources/template/client.html b/openid-connect-server/src/main/webapp/resources/template/client.html index 4250c4492..2f54e18ab 100644 --- a/openid-connect-server/src/main/webapp/resources/template/client.html +++ b/openid-connect-server/src/main/webapp/resources/template/client.html @@ -77,12 +77,12 @@ - - + + - +
http://google.com
From 306e07bc3638988c46e7d88b579fe2d2f544cb68 Mon Sep 17 00:00:00 2001 From: Michael Jett Date: Mon, 27 Aug 2012 23:46:06 -0400 Subject: [PATCH 03/10] UI Dynamic List updates --- .../src/main/webapp/resources/js/app.js | 149 ++++++++++++------ .../webapp/resources/template/client.html | 30 ++-- 2 files changed, 113 insertions(+), 66 deletions(-) diff --git a/openid-connect-server/src/main/webapp/resources/js/app.js b/openid-connect-server/src/main/webapp/resources/js/app.js index 4e1fdc26e..2ee60ba20 100644 --- a/openid-connect-server/src/main/webapp/resources/js/app.js +++ b/openid-connect-server/src/main/webapp/resources/js/app.js @@ -1,4 +1,17 @@ + var URIModel = Backbone.Model.extend({ + + validate: function(){ + + var expression = /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i; + var regex = new RegExp(expression); + + if (!this.get("uri").match(regex)) { + return "Invalid URI"; + } + } + + }); var ClientModel = Backbone.Model.extend({ @@ -36,26 +49,9 @@ refreshTokenValiditySeconds: { required: true, type:"number" - }, - registeredRedirectUri: { - custom: 'validateURI' } }, - validateURI: function(attributeName, attributeValue) { - - var expression = /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i; - var regex = new RegExp(expression); - - - for (var i in attributeValue) { - if (!attributeValue[i].match(regex)) { - return "Invalid URI"; - } - } - - - }, // We can pass it default values. defaults:{ @@ -91,6 +87,79 @@ url:"api/clients" }); + + + var URIView = Backbone.View.extend({ + + tagName: 'tr', + + events:{ + "click .icon-minus-sign":function() { this.model.destroy(); } + }, + + initialize:function () { + + if (!this.template) { + this.template = _.template($('#tmpl-uri').html()); + } + + this.model.bind('destroy', this.remove, this); + + }, + + render:function () { + this.$el.html(this.template(this.model.toJSON())); + return this; + } + }); + + var URIListView = Backbone.View.extend({ + + tagName: "table", + + events:{ + "click button": "addItem" + }, + + initialize:function () { + + if (!this.template) { + this.template = _.template($('#tmpl-uri-list').html()); + } + + this.$el.addClass("table-condensed"); + this.collection.bind('add', this.render, this); + + }, + + addItem:function() { + var input_value = $("input", this.el).val().trim(); + + var uri = new URIModel({uri:input_value}); + + // if it's valid and doesn't already exist + if (uri.isValid() && this.collection.where({uri: input_value}).length < 1) { + this.collection.add(uri); + } + }, + + render:function (eventName) { + + this.$el.html(this.template()); + + _self = this; + + _.each(this.collection.models, function (model) { + var el = new URIView({model:model}).render().el; + $("tbody", _self.el).append(el); + }, this); + + return this; + } + + }); + + var BreadCrumbView = Backbone.View.extend({ tagName: 'ul', @@ -222,6 +291,8 @@ if (!this.template) { this.template = _.template($('#tmpl-client-form').html()); } + + this.registeredRedirectUriCollection = new Backbone.Collection(); }, events:{ @@ -291,12 +362,6 @@ $('.control-group').removeClass('error'); - // do some trimming to the redirect URI to allow null value - var registeredRedirectUri = $.trim($('#registeredRedirectUri textarea').val()).replace(/ /g,'').split("\n"); - if (registeredRedirectUri.length == 1 && registeredRedirectUri[0] == "") { - registeredRedirectUri = []; - } - // build the grant type object var authorizedGrantTypes = []; $.each(["authorization_code","client_credentials","password","implicit"],function(index,type) { @@ -319,7 +384,7 @@ clientId:$('#clientId input').val(), clientSecret: clientSecret, generateClientSecret:generateClientSecret, - registeredRedirectUri:registeredRedirectUri, + registeredRedirectUri: this.registeredRedirectUriCollection.pluck("uri"), clientDescription:$('#clientDescription textarea').val(), allowRefresh:$('#allowRefresh').is(':checked'), authorizedGrantTypes: authorizedGrantTypes, @@ -349,7 +414,16 @@ render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); - + + _self = this; + + // build and bind registered redirect URI collection and view + _.each(this.model.get("registeredRedirectUri"), function (registeredRedirectUri) { + _self.registeredRedirectUriCollection.add(new URIModel({uri:registeredRedirectUri})); + }); + + $("#registeredRedirectUri .controls",this.el).html(new URIListView({collection: this.registeredRedirectUriCollection}).render().el); + return this; }, @@ -358,28 +432,7 @@ } }); - var URLListView = Backbone.View.extend({ - tagName: 'span', - - initialize:function () { - }, - - events:{ - "click .btn-primary":"save" - }, - - save:function () { - - }, - - render:function (eventName) { - - // append and render - $(this.el).html($('#tmpl-url-list').html()); - return this; - } - }); // Router @@ -397,10 +450,6 @@ this.clientList = new ClientCollection(); this.clientListView = new ClientListView({model:this.clientList}); - this.whiteListView = new URLListView(); - this.blackListView = new URLListView(); - - this.breadCrumbView = new BreadCrumbView({ collection:new Backbone.Collection() }); diff --git a/openid-connect-server/src/main/webapp/resources/template/client.html b/openid-connect-server/src/main/webapp/resources/template/client.html index 2f54e18ab..49974390a 100644 --- a/openid-connect-server/src/main/webapp/resources/template/client.html +++ b/openid-connect-server/src/main/webapp/resources/template/client.html @@ -70,22 +70,6 @@
- -

You may enter multiple URIs separated by a new lines

- - - - - - - - - - - - -
http://google.com
@@ -234,4 +218,18 @@ <% } else { %>
  • <%=text%>
  • <% } %> + + + + + \ No newline at end of file From 0aa6da67de94592262f1d391e1f670b9cb00e169 Mon Sep 17 00:00:00 2001 From: Michael Jett Date: Tue, 28 Aug 2012 12:03:08 -0400 Subject: [PATCH 04/10] Bootstrap JS Upgrade --- .../resources/bootstrap2/js/bootstrap.js | 2456 ++++++++++------- .../resources/bootstrap2/js/bootstrap.min.js | 3 +- 2 files changed, 1386 insertions(+), 1073 deletions(-) diff --git a/openid-connect-server/src/main/webapp/resources/bootstrap2/js/bootstrap.js b/openid-connect-server/src/main/webapp/resources/bootstrap2/js/bootstrap.js index ca868671c..39ad031e4 100644 --- a/openid-connect-server/src/main/webapp/resources/bootstrap2/js/bootstrap.js +++ b/openid-connect-server/src/main/webapp/resources/bootstrap2/js/bootstrap.js @@ -1,5 +1,5 @@ /* =================================================== - * bootstrap-transition.js v2.0.2 + * bootstrap-transition.js v2.1.0 * http://twitter.github.com/bootstrap/javascript.html#transitions * =================================================== * Copyright 2012 Twitter, Inc. @@ -17,619 +17,49 @@ * limitations under the License. * ========================================================== */ -!function( $ ) { + +!function ($) { $(function () { - "use strict" + "use strict"; // jshint ;_; - /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) * ======================================================= */ $.support.transition = (function () { - var thisBody = document.body || document.documentElement - , thisStyle = thisBody.style - , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined - return support && { - end: (function () { - var transitionEnd = "TransitionEnd" - if ( $.browser.webkit ) { - transitionEnd = "webkitTransitionEnd" - } else if ( $.browser.mozilla ) { - transitionEnd = "transitionend" - } else if ( $.browser.opera ) { - transitionEnd = "oTransitionEnd" + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] } - return transitionEnd - }()) + } + + }()) + + return transitionEnd && { + end: transitionEnd } + })() }) -}( window.jQuery );/* ========================================================== - * bootstrap-alert.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#alerts - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function( $ ){ - - "use strict" - - /* ALERT CLASS DEFINITION - * ====================== */ - - var dismiss = '[data-dismiss="alert"]' - , Alert = function ( el ) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype = { - - constructor: Alert - - , close: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.trigger('close') - - e && e.preventDefault() - - $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) - - $parent - .trigger('close') - .removeClass('in') - - function removeElement() { - $parent - .trigger('closed') - .remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent.on($.support.transition.end, removeElement) : - removeElement() - } - - } - - - /* ALERT PLUGIN DEFINITION - * ======================= */ - - $.fn.alert = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('alert') - if (!data) $this.data('alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.alert.Constructor = Alert - - - /* ALERT DATA-API - * ============== */ - - $(function () { - $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) - }) - -}( window.jQuery );/* ============================================================ - * bootstrap-button.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#buttons - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - -!function( $ ){ - - "use strict" - - /* BUTTON PUBLIC CLASS DEFINITION - * ============================== */ - - var Button = function ( element, options ) { - this.$element = $(element) - this.options = $.extend({}, $.fn.button.defaults, options) - } - - Button.prototype = { - - constructor: Button - - , setState: function ( state ) { - var d = 'disabled' - , $el = this.$element - , data = $el.data() - , val = $el.is('input') ? 'val' : 'html' - - state = state + 'Text' - data.resetText || $el.data('resetText', $el[val]()) - - $el[val](data[state] || this.options[state]) - - // push to event loop to allow forms to submit - setTimeout(function () { - state == 'loadingText' ? - $el.addClass(d).attr(d, d) : - $el.removeClass(d).removeAttr(d) - }, 0) - } - - , toggle: function () { - var $parent = this.$element.parent('[data-toggle="buttons-radio"]') - - $parent && $parent - .find('.active') - .removeClass('active') - - this.$element.toggleClass('active') - } - - } - - - /* BUTTON PLUGIN DEFINITION - * ======================== */ - - $.fn.button = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('button') - , options = typeof option == 'object' && option - if (!data) $this.data('button', (data = new Button(this, options))) - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - $.fn.button.defaults = { - loadingText: 'loading...' - } - - $.fn.button.Constructor = Button - - - /* BUTTON DATA-API - * =============== */ - - $(function () { - $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) - }) - -}( window.jQuery );/* ========================================================== - * bootstrap-carousel.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#carousel - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function( $ ){ - - "use strict" - - /* CAROUSEL CLASS DEFINITION - * ========================= */ - - var Carousel = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.carousel.defaults, options) - this.options.slide && this.slide(this.options.slide) - this.options.pause == 'hover' && this.$element - .on('mouseenter', $.proxy(this.pause, this)) - .on('mouseleave', $.proxy(this.cycle, this)) - } - - Carousel.prototype = { - - cycle: function () { - this.interval = setInterval($.proxy(this.next, this), this.options.interval) - return this - } - - , to: function (pos) { - var $active = this.$element.find('.active') - , children = $active.parent().children() - , activePos = children.index($active) - , that = this - - if (pos > (children.length - 1) || pos < 0) return - - if (this.sliding) { - return this.$element.one('slid', function () { - that.to(pos) - }) - } - - if (activePos == pos) { - return this.pause().cycle() - } - - return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) - } - - , pause: function () { - clearInterval(this.interval) - this.interval = null - return this - } - - , next: function () { - if (this.sliding) return - return this.slide('next') - } - - , prev: function () { - if (this.sliding) return - return this.slide('prev') - } - - , slide: function (type, next) { - var $active = this.$element.find('.active') - , $next = next || $active[type]() - , isCycling = this.interval - , direction = type == 'next' ? 'left' : 'right' - , fallback = type == 'next' ? 'first' : 'last' - , that = this - - this.sliding = true - - isCycling && this.pause() - - $next = $next.length ? $next : this.$element.find('.item')[fallback]() - - if ($next.hasClass('active')) return - - if (!$.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger('slide') - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid') - } else { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - this.$element.trigger('slide') - this.$element.one($.support.transition.end, function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { that.$element.trigger('slid') }, 0) - }) - } - - isCycling && this.cycle() - - return this - } - - } - - - /* CAROUSEL PLUGIN DEFINITION - * ========================== */ - - $.fn.carousel = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('carousel') - , options = typeof option == 'object' && option - if (!data) $this.data('carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (typeof option == 'string' || (option = options.slide)) data[option]() - else data.cycle() - }) - } - - $.fn.carousel.defaults = { - interval: 5000 - , pause: 'hover' - } - - $.fn.carousel.Constructor = Carousel - - - /* CAROUSEL DATA-API - * ================= */ - - $(function () { - $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) - $target.carousel(options) - e.preventDefault() - }) - }) - -}( window.jQuery );/* ============================================================= - * bootstrap-collapse.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#collapse - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - -!function( $ ){ - - "use strict" - - var Collapse = function ( element, options ) { - this.$element = $(element) - this.options = $.extend({}, $.fn.collapse.defaults, options) - - if (this.options["parent"]) { - this.$parent = $(this.options["parent"]) - } - - this.options.toggle && this.toggle() - } - - Collapse.prototype = { - - constructor: Collapse - - , dimension: function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - , show: function () { - var dimension = this.dimension() - , scroll = $.camelCase(['scroll', dimension].join('-')) - , actives = this.$parent && this.$parent.find('.in') - , hasData - - if (actives && actives.length) { - hasData = actives.data('collapse') - actives.collapse('hide') - hasData || actives.data('collapse', null) - } - - this.$element[dimension](0) - this.transition('addClass', 'show', 'shown') - this.$element[dimension](this.$element[0][scroll]) - - } - - , hide: function () { - var dimension = this.dimension() - this.reset(this.$element[dimension]()) - this.transition('removeClass', 'hide', 'hidden') - this.$element[dimension](0) - } - - , reset: function ( size ) { - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - [dimension](size || 'auto') - [0].offsetWidth - - this.$element[size ? 'addClass' : 'removeClass']('collapse') - - return this - } - - , transition: function ( method, startEvent, completeEvent ) { - var that = this - , complete = function () { - if (startEvent == 'show') that.reset() - that.$element.trigger(completeEvent) - } - - this.$element - .trigger(startEvent) - [method]('in') - - $.support.transition && this.$element.hasClass('collapse') ? - this.$element.one($.support.transition.end, complete) : - complete() - } - - , toggle: function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - } - - /* COLLAPSIBLE PLUGIN DEFINITION - * ============================== */ - - $.fn.collapse = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('collapse') - , options = typeof option == 'object' && option - if (!data) $this.data('collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.collapse.defaults = { - toggle: true - } - - $.fn.collapse.Constructor = Collapse - - - /* COLLAPSIBLE DATA-API - * ==================== */ - - $(function () { - $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $(target).collapse(option) - }) - }) - -}( window.jQuery );/* ============================================================ - * bootstrap-dropdown.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#dropdowns - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - - -!function( $ ){ - - "use strict" - - /* DROPDOWN CLASS DEFINITION - * ========================= */ - - var toggle = '[data-toggle="dropdown"]' - , Dropdown = function ( element ) { - var $el = $(element).on('click.dropdown.data-api', this.toggle) - $('html').on('click.dropdown.data-api', function () { - $el.parent().removeClass('open') - }) - } - - Dropdown.prototype = { - - constructor: Dropdown - - , toggle: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - , isActive - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.length || ($parent = $this.parent()) - - isActive = $parent.hasClass('open') - - clearMenus() - !isActive && $parent.toggleClass('open') - - return false - } - - } - - function clearMenus() { - $(toggle).parent().removeClass('open') - } - - - /* DROPDOWN PLUGIN DEFINITION - * ========================== */ - - $.fn.dropdown = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('dropdown') - if (!data) $this.data('dropdown', (data = new Dropdown(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.dropdown.Constructor = Dropdown - - - /* APPLY TO STANDARD DROPDOWN ELEMENTS - * =================================== */ - - $(function () { - $('html').on('click.dropdown.data-api', clearMenus) - $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) - }) - -}( window.jQuery );/* ========================================================= - * bootstrap-modal.js v2.0.2 +}(window.jQuery); +/* ========================================================= + * bootstrap-modal.js v2.1.0 * http://twitter.github.com/bootstrap/javascript.html#modals * ========================================================= * Copyright 2012 Twitter, Inc. @@ -648,17 +78,19 @@ * ========================================================= */ -!function( $ ){ +!function ($) { + + "use strict"; // jshint ;_; - "use strict" /* MODAL CLASS DEFINITION * ====================== */ - var Modal = function ( content, options ) { + var Modal = function (element, options) { this.options = options - this.$element = $(content) + this.$element = $(element) .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + this.options.remote && this.$element.find('.modal-body').load(this.options.remote) } Modal.prototype = { @@ -671,19 +103,24 @@ , show: function () { var that = this + , e = $.Event('show') - if (this.isShown) return + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return $('body').addClass('modal-open') this.isShown = true - this.$element.trigger('show') - escape.call(this) - backdrop.call(this, function () { + this.escape() + + this.backdrop(function () { var transition = $.support.transition && that.$element.hasClass('fade') - !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } that.$element .show() @@ -692,7 +129,12 @@ that.$element[0].offsetWidth // force reflow } - that.$element.addClass('in') + that.$element + .addClass('in') + .attr('aria-hidden', false) + .focus() + + that.enforceFocus() transition ? that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : @@ -701,109 +143,120 @@ }) } - , hide: function ( e ) { + , hide: function (e) { e && e.preventDefault() - if (!this.isShown) return - var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + this.isShown = false $('body').removeClass('modal-open') - escape.call(this) + this.escape() + + $(document).off('focusin.modal') this.$element - .trigger('hide') .removeClass('in') + .attr('aria-hidden', true) $.support.transition && this.$element.hasClass('fade') ? - hideWithTransition.call(this) : - hideModal.call(this) + this.hideWithTransition() : + this.hideModal() } - } - - - /* MODAL PRIVATE METHODS - * ===================== */ - - function hideWithTransition() { - var that = this - , timeout = setTimeout(function () { - that.$element.off($.support.transition.end) - hideModal.call(that) - }, 500) - - this.$element.one($.support.transition.end, function () { - clearTimeout(timeout) - hideModal.call(that) - }) - } - - function hideModal( that ) { - this.$element - .hide() - .trigger('hidden') - - backdrop.call(this) - } - - function backdrop( callback ) { - var that = this - , animate = this.$element.hasClass('fade') ? 'fade' : '' - - if (this.isShown && this.options.backdrop) { - var doAnimate = $.support.transition && animate - - this.$backdrop = $('