├── crm ├── __init__.py ├── wsgi.py ├── urls.py ├── settings.py └── cadastro.sql ├── cadastro ├── __init__.py ├── tests.py ├── admin.py ├── static │ ├── css │ │ └── base.css │ └── js │ │ ├── bootstrap.js │ │ └── jquery-1.10.2.js ├── forms.py ├── templates │ ├── index.html │ ├── cadastro.html │ ├── _pagination.html │ ├── lista.html │ └── base.html ├── managers.py ├── models.py └── views.py ├── requirements.txt ├── .gitignore ├── README.md └── manage.py /crm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cadastro/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django 2 | Unipath -------------------------------------------------------------------------------- /cadastro/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /cadastro/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from cadastro.models import Inscricao 3 | 4 | admin.site.register(Inscricao) 5 | -------------------------------------------------------------------------------- /cadastro/static/css/base.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin-top: 50px; 3 | height:100%; 4 | } 5 | 6 | .initial-p { 7 | padding-top: 25px; 8 | } 9 | -------------------------------------------------------------------------------- /cadastro/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django import forms 3 | from models import Inscricao 4 | 5 | class InscricaoForm(forms.ModelForm): 6 | 7 | class Meta: 8 | model = Inscricao -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | include 4 | lib 5 | local 6 | man 7 | share 8 | Scripts 9 | .Python 10 | *.pyc 11 | *~ 12 | *.sqlite3 13 | .DS_Store 14 | .env 15 | crm/staticfiles 16 | 17 | .db 18 | *.sqlite3 19 | .venv 20 | -------------------------------------------------------------------------------- /cadastro/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Cadastro de Clientes

7 |
8 |
9 | {% endblock content %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CRM é um projeto que visa mostrar a forma mais simples de iniciar um projeto Django. E ele irá crescer e será melhorado aos poucos. 2 | 3 | > Este projeto é utilizado no tutorial pythonclub. 4 | 5 | http://pythonclub.com.br/criar-site-com-form-lista-30-min.html 6 | -------------------------------------------------------------------------------- /cadastro/managers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | 4 | 5 | class ClientesManager(models.Manager): 6 | 7 | def get_queryset(self): 8 | qs = super(ClientesManager, self).get_queryset() 9 | qs = qs.objects.with_counts() 10 | return qs 11 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "crm.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /crm/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for crm project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "crm.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /crm/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import patterns, include, url 3 | from cadastro.views import * 4 | 5 | from django.contrib import admin 6 | admin.autodiscover() 7 | 8 | urlpatterns = patterns( 9 | 'cadastro.views', 10 | url(r'^$', 'home', name='home'), 11 | url(r'^cadastro/$', Criar.as_view(), name='cadastro'), 12 | url(r'^lista/$', Listar.as_view(), name='lista'), 13 | url(r'^admin/', include(admin.site.urls)), 14 | ) 15 | -------------------------------------------------------------------------------- /cadastro/templates/cadastro.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 | {% csrf_token %} 7 | {{ form.non_field_errors }} 8 | {% for field in form %} 9 |
10 |
11 | {{ field.errors }} 12 | {{ field.label }} 13 |
14 |
15 | {{ field }} 16 |
17 |
18 | {% endfor %} 19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 | {% endblock content %} -------------------------------------------------------------------------------- /cadastro/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | 4 | 5 | class Inscricao(models.Model): 6 | nome = models.CharField(max_length=100) 7 | cpf = models.CharField('CPF', max_length=11, unique=True) 8 | idade = models.IntegerField() 9 | email = models.EmailField(unique=True) 10 | telefone = models.CharField(max_length=20, blank=True) 11 | criado_em = models.DateTimeField('criado em', auto_now_add=True) 12 | 13 | class Meta: 14 | ordering = ['criado_em'] 15 | verbose_name = (u'nome') 16 | verbose_name_plural = (u'nomes') 17 | 18 | def __unicode__(self): 19 | return self.nome 20 | 21 | def _get_dobro_idade(self): 22 | return self.idade * 2 23 | dobro_idade = property(_get_dobro_idade) 24 | -------------------------------------------------------------------------------- /cadastro/templates/_pagination.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /cadastro/templates/lista.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |

Lista de Clientes

5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% for inscricao in page_obj %} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% empty %} 31 |

Sem itens na lista.

32 | {% endfor %} 33 | 34 |
NomeCPFIdadeDobro da IdadeEmailTelefoneCriado em
{{ inscricao.nome }}{{ inscricao.cpf }}{{ inscricao.idade }}{{ inscricao.dobro_idade }}{{ inscricao.email }}{{ inscricao.telefone }}{{ inscricao.criado_em|date:"d/m/Y" }}
35 |
36 | 37 |
38 | 39 | 40 | {% include "_pagination.html" %} 41 | 42 | {% endblock content %} -------------------------------------------------------------------------------- /cadastro/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.shortcuts import render 3 | from django.shortcuts import render_to_response 4 | from django.views.generic import CreateView, ListView 5 | from django.core.urlresolvers import reverse_lazy 6 | from django.core.paginator import Paginator 7 | 8 | from cadastro.models import Inscricao 9 | from cadastro.forms import InscricaoForm 10 | 11 | 12 | def home(request): 13 | return render(request, 'index.html') 14 | 15 | 16 | class Criar(CreateView): 17 | template_name = 'cadastro.html' 18 | model = Inscricao 19 | success_url = reverse_lazy('lista') 20 | 21 | 22 | class Listar(ListView): 23 | template_name = 'lista.html' 24 | model = Inscricao 25 | context_object = 'inscricao_list' 26 | paginate_by = 5 27 | 28 | 29 | def lista(request): 30 | # pagination 31 | inscricoes_list = Inscricao.objects.all() 32 | paginator = Paginator(inscricoes_list, 2) 33 | 34 | try: 35 | page = int(request.GET.get('page', '1')) 36 | except: 37 | page = 1 38 | try: 39 | inscricao = paginator.page(page) 40 | except(EmptyPage, InvalidPage): 41 | inscricao = paginator.page(paginator.num_pages) 42 | return render_to_response('lista.html', 43 | {'inscricao': inscricao}) 44 | -------------------------------------------------------------------------------- /cadastro/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% block title %} 11 | Título 12 | {% endblock title %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 44 | 45 | {% block content %} 46 | 47 | {% endblock content %} 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /crm/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for crm project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.6/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.6/ref/settings/ 9 | """ 10 | 11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 12 | # import os 13 | # BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | # Unipath aqui 15 | from unipath import Path 16 | BASE_DIR = Path(__file__).parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'z_e56zqn)721@cu*gsgtf&elh(sobueh@jul2o*4(cm$lj-%%^' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | TEMPLATE_DEBUG = True 29 | 30 | ALLOWED_HOSTS = [] 31 | 32 | 33 | # Application definition 34 | 35 | INSTALLED_APPS = ( 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | 'cadastro', 43 | ) 44 | 45 | MIDDLEWARE_CLASSES = ( 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ) 53 | 54 | ROOT_URLCONF = 'crm.urls' 55 | 56 | WSGI_APPLICATION = 'crm.wsgi.application' 57 | 58 | 59 | # Database 60 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases 61 | 62 | DATABASES = { 63 | 'default': { 64 | 'ENGINE': 'django.db.backends.sqlite3', 65 | #'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 66 | 'NAME': BASE_DIR.child('db.sqlite3'), # Unipath aqui 67 | } 68 | } 69 | 70 | # Internationalization 71 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 72 | 73 | LANGUAGE_CODE = 'pt-br' 74 | 75 | TIME_ZONE = 'UTC' 76 | 77 | USE_I18N = True 78 | 79 | USE_L10N = True 80 | 81 | USE_TZ = True 82 | 83 | 84 | # Static files (CSS, JavaScript, Images) 85 | # https://docs.djangoproject.com/en/1.6/howto/static-files/ 86 | 87 | STATIC_URL = '/static/' 88 | -------------------------------------------------------------------------------- /crm/cadastro.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Regis da Silva', '12345678910', 35, 'regis@email.com', '11 5310-0000','2014-06-20 23:59:59'); 2 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Abel da Silva', '11111111111', 10, 'abel@email', '11 1000-000', '2014-06-21 23:59:59'); 3 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Bianca Sousa', '11111111112', 12, 'bianca@email', '11 2000-000', '2014-06-21 23:59:59'); 4 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Eloisa dos Santos', '11111111113', 1, 'eloisa@email', '11 3000-000', '2014-06-22 23:59:59'); 5 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Carol', '11111111114', 15, 'carol@email', '11 4000-000', '2014-06-23 23:59:59'); 6 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Eduardo', '11111111115', 20, 'eduardo@email', '11 5000-000', '2014-06-24 23:59:59'); 7 | INSERT INTO cadastro_inscricao VALUES (NULL, 'João Henrique', '11111111116', 19, 'joao@email', '11 6000-000', '2014-06-24 23:59:59'); 8 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Caio', '11111111117', 22, 'caio@email', '11 7000-000', '2014-06-25 23:59:59'); 9 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Ana Beatriz', '11111111118', 25, 'ana@email', '11 8000-000', '2014-06-25 23:59:59'); 10 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Fernanda Salomão', '11111111119', 30, 'fernanda@email', '11 9000-000', '2014-06-25 23:59:59'); 11 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Arthur da Silva', '73540011210', 29, 'arthur@email.com', '3542-0000' , '2014-06-14 23:59:59'); 12 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Jose Fernando', '73540011211', 28, 'jose@email.com', '3542-0001' , '2014-06-14 23:59:59'); 13 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Luiz Augusto', '73540011212', 27, 'luiz@email.com', '3542-0002' , '2014-06-14 23:59:59'); 14 | INSERT INTO cadastro_inscricao VALUES (NULL, 'David Luis', '73540011213', 32, 'david@email.com', '3542-0003' , '2014-06-14 23:59:59'); 15 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Pedro Paulo', '73540011214', 11, 'pedro@email.com', '3542-0004' , '2014-06-14 23:59:59'); 16 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Rogerio Figueiredo', '73540011215', 15, 'rogerio@email.com', '3542-0005' , '2014-06-14 23:59:59'); 17 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Bruna Bezerra', '73540011216', 15, 'bruna@email.com', '3542-0006' , '2014-06-14 23:59:59'); 18 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Victor Augusto', '73540011217', 21, 'victor@email.com', '3542-0007' , '2014-06-14 23:59:59'); 19 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Denis Mendonça', '73540011218', 17, 'denis@email.com', '3542-0008' , '2014-06-14 23:59:59'); 20 | INSERT INTO cadastro_inscricao VALUES (NULL, 'Gabriela', '73540011219', 14, 'gabriela@email.com', '3542-0009' , '2014-06-14 23:59:59'); 21 | -------------------------------------------------------------------------------- /cadastro/static/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | if (typeof jQuery === 'undefined') { throw new Error('Bootstrap requires jQuery') } 8 | 9 | /* ======================================================================== 10 | * Bootstrap: transition.js v3.1.0 11 | * http://getbootstrap.com/javascript/#transitions 12 | * ======================================================================== 13 | * Copyright 2011-2014 Twitter, Inc. 14 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 15 | * ======================================================================== */ 16 | 17 | 18 | +function ($) { 19 | 'use strict'; 20 | 21 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 22 | // ============================================================ 23 | 24 | function transitionEnd() { 25 | var el = document.createElement('bootstrap') 26 | 27 | var transEndEventNames = { 28 | 'WebkitTransition' : 'webkitTransitionEnd', 29 | 'MozTransition' : 'transitionend', 30 | 'OTransition' : 'oTransitionEnd otransitionend', 31 | 'transition' : 'transitionend' 32 | } 33 | 34 | for (var name in transEndEventNames) { 35 | if (el.style[name] !== undefined) { 36 | return { end: transEndEventNames[name] } 37 | } 38 | } 39 | 40 | return false // explicit for ie8 ( ._.) 41 | } 42 | 43 | // http://blog.alexmaccaw.com/css-transitions 44 | $.fn.emulateTransitionEnd = function (duration) { 45 | var called = false, $el = this 46 | $(this).one($.support.transition.end, function () { called = true }) 47 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 48 | setTimeout(callback, duration) 49 | return this 50 | } 51 | 52 | $(function () { 53 | $.support.transition = transitionEnd() 54 | }) 55 | 56 | }(jQuery); 57 | 58 | /* ======================================================================== 59 | * Bootstrap: alert.js v3.1.0 60 | * http://getbootstrap.com/javascript/#alerts 61 | * ======================================================================== 62 | * Copyright 2011-2014 Twitter, Inc. 63 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 64 | * ======================================================================== */ 65 | 66 | 67 | +function ($) { 68 | 'use strict'; 69 | 70 | // ALERT CLASS DEFINITION 71 | // ====================== 72 | 73 | var dismiss = '[data-dismiss="alert"]' 74 | var Alert = function (el) { 75 | $(el).on('click', dismiss, this.close) 76 | } 77 | 78 | Alert.prototype.close = function (e) { 79 | var $this = $(this) 80 | var selector = $this.attr('data-target') 81 | 82 | if (!selector) { 83 | selector = $this.attr('href') 84 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 85 | } 86 | 87 | var $parent = $(selector) 88 | 89 | if (e) e.preventDefault() 90 | 91 | if (!$parent.length) { 92 | $parent = $this.hasClass('alert') ? $this : $this.parent() 93 | } 94 | 95 | $parent.trigger(e = $.Event('close.bs.alert')) 96 | 97 | if (e.isDefaultPrevented()) return 98 | 99 | $parent.removeClass('in') 100 | 101 | function removeElement() { 102 | $parent.trigger('closed.bs.alert').remove() 103 | } 104 | 105 | $.support.transition && $parent.hasClass('fade') ? 106 | $parent 107 | .one($.support.transition.end, removeElement) 108 | .emulateTransitionEnd(150) : 109 | removeElement() 110 | } 111 | 112 | 113 | // ALERT PLUGIN DEFINITION 114 | // ======================= 115 | 116 | var old = $.fn.alert 117 | 118 | $.fn.alert = function (option) { 119 | return this.each(function () { 120 | var $this = $(this) 121 | var data = $this.data('bs.alert') 122 | 123 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 124 | if (typeof option == 'string') data[option].call($this) 125 | }) 126 | } 127 | 128 | $.fn.alert.Constructor = Alert 129 | 130 | 131 | // ALERT NO CONFLICT 132 | // ================= 133 | 134 | $.fn.alert.noConflict = function () { 135 | $.fn.alert = old 136 | return this 137 | } 138 | 139 | 140 | // ALERT DATA-API 141 | // ============== 142 | 143 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 144 | 145 | }(jQuery); 146 | 147 | /* ======================================================================== 148 | * Bootstrap: button.js v3.1.0 149 | * http://getbootstrap.com/javascript/#buttons 150 | * ======================================================================== 151 | * Copyright 2011-2014 Twitter, Inc. 152 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 153 | * ======================================================================== */ 154 | 155 | 156 | +function ($) { 157 | 'use strict'; 158 | 159 | // BUTTON PUBLIC CLASS DEFINITION 160 | // ============================== 161 | 162 | var Button = function (element, options) { 163 | this.$element = $(element) 164 | this.options = $.extend({}, Button.DEFAULTS, options) 165 | this.isLoading = false 166 | } 167 | 168 | Button.DEFAULTS = { 169 | loadingText: 'loading...' 170 | } 171 | 172 | Button.prototype.setState = function (state) { 173 | var d = 'disabled' 174 | var $el = this.$element 175 | var val = $el.is('input') ? 'val' : 'html' 176 | var data = $el.data() 177 | 178 | state = state + 'Text' 179 | 180 | if (!data.resetText) $el.data('resetText', $el[val]()) 181 | 182 | $el[val](data[state] || this.options[state]) 183 | 184 | // push to event loop to allow forms to submit 185 | setTimeout($.proxy(function () { 186 | if (state == 'loadingText') { 187 | this.isLoading = true 188 | $el.addClass(d).attr(d, d) 189 | } else if (this.isLoading) { 190 | this.isLoading = false 191 | $el.removeClass(d).removeAttr(d) 192 | } 193 | }, this), 0) 194 | } 195 | 196 | Button.prototype.toggle = function () { 197 | var changed = true 198 | var $parent = this.$element.closest('[data-toggle="buttons"]') 199 | 200 | if ($parent.length) { 201 | var $input = this.$element.find('input') 202 | if ($input.prop('type') == 'radio') { 203 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 204 | else $parent.find('.active').removeClass('active') 205 | } 206 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 207 | } 208 | 209 | if (changed) this.$element.toggleClass('active') 210 | } 211 | 212 | 213 | // BUTTON PLUGIN DEFINITION 214 | // ======================== 215 | 216 | var old = $.fn.button 217 | 218 | $.fn.button = function (option) { 219 | return this.each(function () { 220 | var $this = $(this) 221 | var data = $this.data('bs.button') 222 | var options = typeof option == 'object' && option 223 | 224 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 225 | 226 | if (option == 'toggle') data.toggle() 227 | else if (option) data.setState(option) 228 | }) 229 | } 230 | 231 | $.fn.button.Constructor = Button 232 | 233 | 234 | // BUTTON NO CONFLICT 235 | // ================== 236 | 237 | $.fn.button.noConflict = function () { 238 | $.fn.button = old 239 | return this 240 | } 241 | 242 | 243 | // BUTTON DATA-API 244 | // =============== 245 | 246 | $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { 247 | var $btn = $(e.target) 248 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 249 | $btn.button('toggle') 250 | e.preventDefault() 251 | }) 252 | 253 | }(jQuery); 254 | 255 | /* ======================================================================== 256 | * Bootstrap: carousel.js v3.1.0 257 | * http://getbootstrap.com/javascript/#carousel 258 | * ======================================================================== 259 | * Copyright 2011-2014 Twitter, Inc. 260 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 261 | * ======================================================================== */ 262 | 263 | 264 | +function ($) { 265 | 'use strict'; 266 | 267 | // CAROUSEL CLASS DEFINITION 268 | // ========================= 269 | 270 | var Carousel = function (element, options) { 271 | this.$element = $(element) 272 | this.$indicators = this.$element.find('.carousel-indicators') 273 | this.options = options 274 | this.paused = 275 | this.sliding = 276 | this.interval = 277 | this.$active = 278 | this.$items = null 279 | 280 | this.options.pause == 'hover' && this.$element 281 | .on('mouseenter', $.proxy(this.pause, this)) 282 | .on('mouseleave', $.proxy(this.cycle, this)) 283 | } 284 | 285 | Carousel.DEFAULTS = { 286 | interval: 5000, 287 | pause: 'hover', 288 | wrap: true 289 | } 290 | 291 | Carousel.prototype.cycle = function (e) { 292 | e || (this.paused = false) 293 | 294 | this.interval && clearInterval(this.interval) 295 | 296 | this.options.interval 297 | && !this.paused 298 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 299 | 300 | return this 301 | } 302 | 303 | Carousel.prototype.getActiveIndex = function () { 304 | this.$active = this.$element.find('.item.active') 305 | this.$items = this.$active.parent().children() 306 | 307 | return this.$items.index(this.$active) 308 | } 309 | 310 | Carousel.prototype.to = function (pos) { 311 | var that = this 312 | var activeIndex = this.getActiveIndex() 313 | 314 | if (pos > (this.$items.length - 1) || pos < 0) return 315 | 316 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) 317 | if (activeIndex == pos) return this.pause().cycle() 318 | 319 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 320 | } 321 | 322 | Carousel.prototype.pause = function (e) { 323 | e || (this.paused = true) 324 | 325 | if (this.$element.find('.next, .prev').length && $.support.transition) { 326 | this.$element.trigger($.support.transition.end) 327 | this.cycle(true) 328 | } 329 | 330 | this.interval = clearInterval(this.interval) 331 | 332 | return this 333 | } 334 | 335 | Carousel.prototype.next = function () { 336 | if (this.sliding) return 337 | return this.slide('next') 338 | } 339 | 340 | Carousel.prototype.prev = function () { 341 | if (this.sliding) return 342 | return this.slide('prev') 343 | } 344 | 345 | Carousel.prototype.slide = function (type, next) { 346 | var $active = this.$element.find('.item.active') 347 | var $next = next || $active[type]() 348 | var isCycling = this.interval 349 | var direction = type == 'next' ? 'left' : 'right' 350 | var fallback = type == 'next' ? 'first' : 'last' 351 | var that = this 352 | 353 | if (!$next.length) { 354 | if (!this.options.wrap) return 355 | $next = this.$element.find('.item')[fallback]() 356 | } 357 | 358 | if ($next.hasClass('active')) return this.sliding = false 359 | 360 | var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) 361 | this.$element.trigger(e) 362 | if (e.isDefaultPrevented()) return 363 | 364 | this.sliding = true 365 | 366 | isCycling && this.pause() 367 | 368 | if (this.$indicators.length) { 369 | this.$indicators.find('.active').removeClass('active') 370 | this.$element.one('slid.bs.carousel', function () { 371 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) 372 | $nextIndicator && $nextIndicator.addClass('active') 373 | }) 374 | } 375 | 376 | if ($.support.transition && this.$element.hasClass('slide')) { 377 | $next.addClass(type) 378 | $next[0].offsetWidth // force reflow 379 | $active.addClass(direction) 380 | $next.addClass(direction) 381 | $active 382 | .one($.support.transition.end, function () { 383 | $next.removeClass([type, direction].join(' ')).addClass('active') 384 | $active.removeClass(['active', direction].join(' ')) 385 | that.sliding = false 386 | setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) 387 | }) 388 | .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) 389 | } else { 390 | $active.removeClass('active') 391 | $next.addClass('active') 392 | this.sliding = false 393 | this.$element.trigger('slid.bs.carousel') 394 | } 395 | 396 | isCycling && this.cycle() 397 | 398 | return this 399 | } 400 | 401 | 402 | // CAROUSEL PLUGIN DEFINITION 403 | // ========================== 404 | 405 | var old = $.fn.carousel 406 | 407 | $.fn.carousel = function (option) { 408 | return this.each(function () { 409 | var $this = $(this) 410 | var data = $this.data('bs.carousel') 411 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 412 | var action = typeof option == 'string' ? option : options.slide 413 | 414 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 415 | if (typeof option == 'number') data.to(option) 416 | else if (action) data[action]() 417 | else if (options.interval) data.pause().cycle() 418 | }) 419 | } 420 | 421 | $.fn.carousel.Constructor = Carousel 422 | 423 | 424 | // CAROUSEL NO CONFLICT 425 | // ==================== 426 | 427 | $.fn.carousel.noConflict = function () { 428 | $.fn.carousel = old 429 | return this 430 | } 431 | 432 | 433 | // CAROUSEL DATA-API 434 | // ================= 435 | 436 | $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 437 | var $this = $(this), href 438 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 439 | var options = $.extend({}, $target.data(), $this.data()) 440 | var slideIndex = $this.attr('data-slide-to') 441 | if (slideIndex) options.interval = false 442 | 443 | $target.carousel(options) 444 | 445 | if (slideIndex = $this.attr('data-slide-to')) { 446 | $target.data('bs.carousel').to(slideIndex) 447 | } 448 | 449 | e.preventDefault() 450 | }) 451 | 452 | $(window).on('load', function () { 453 | $('[data-ride="carousel"]').each(function () { 454 | var $carousel = $(this) 455 | $carousel.carousel($carousel.data()) 456 | }) 457 | }) 458 | 459 | }(jQuery); 460 | 461 | /* ======================================================================== 462 | * Bootstrap: collapse.js v3.1.0 463 | * http://getbootstrap.com/javascript/#collapse 464 | * ======================================================================== 465 | * Copyright 2011-2014 Twitter, Inc. 466 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 467 | * ======================================================================== */ 468 | 469 | 470 | +function ($) { 471 | 'use strict'; 472 | 473 | // COLLAPSE PUBLIC CLASS DEFINITION 474 | // ================================ 475 | 476 | var Collapse = function (element, options) { 477 | this.$element = $(element) 478 | this.options = $.extend({}, Collapse.DEFAULTS, options) 479 | this.transitioning = null 480 | 481 | if (this.options.parent) this.$parent = $(this.options.parent) 482 | if (this.options.toggle) this.toggle() 483 | } 484 | 485 | Collapse.DEFAULTS = { 486 | toggle: true 487 | } 488 | 489 | Collapse.prototype.dimension = function () { 490 | var hasWidth = this.$element.hasClass('width') 491 | return hasWidth ? 'width' : 'height' 492 | } 493 | 494 | Collapse.prototype.show = function () { 495 | if (this.transitioning || this.$element.hasClass('in')) return 496 | 497 | var startEvent = $.Event('show.bs.collapse') 498 | this.$element.trigger(startEvent) 499 | if (startEvent.isDefaultPrevented()) return 500 | 501 | var actives = this.$parent && this.$parent.find('> .panel > .in') 502 | 503 | if (actives && actives.length) { 504 | var hasData = actives.data('bs.collapse') 505 | if (hasData && hasData.transitioning) return 506 | actives.collapse('hide') 507 | hasData || actives.data('bs.collapse', null) 508 | } 509 | 510 | var dimension = this.dimension() 511 | 512 | this.$element 513 | .removeClass('collapse') 514 | .addClass('collapsing') 515 | [dimension](0) 516 | 517 | this.transitioning = 1 518 | 519 | var complete = function () { 520 | this.$element 521 | .removeClass('collapsing') 522 | .addClass('collapse in') 523 | [dimension]('auto') 524 | this.transitioning = 0 525 | this.$element.trigger('shown.bs.collapse') 526 | } 527 | 528 | if (!$.support.transition) return complete.call(this) 529 | 530 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 531 | 532 | this.$element 533 | .one($.support.transition.end, $.proxy(complete, this)) 534 | .emulateTransitionEnd(350) 535 | [dimension](this.$element[0][scrollSize]) 536 | } 537 | 538 | Collapse.prototype.hide = function () { 539 | if (this.transitioning || !this.$element.hasClass('in')) return 540 | 541 | var startEvent = $.Event('hide.bs.collapse') 542 | this.$element.trigger(startEvent) 543 | if (startEvent.isDefaultPrevented()) return 544 | 545 | var dimension = this.dimension() 546 | 547 | this.$element 548 | [dimension](this.$element[dimension]()) 549 | [0].offsetHeight 550 | 551 | this.$element 552 | .addClass('collapsing') 553 | .removeClass('collapse') 554 | .removeClass('in') 555 | 556 | this.transitioning = 1 557 | 558 | var complete = function () { 559 | this.transitioning = 0 560 | this.$element 561 | .trigger('hidden.bs.collapse') 562 | .removeClass('collapsing') 563 | .addClass('collapse') 564 | } 565 | 566 | if (!$.support.transition) return complete.call(this) 567 | 568 | this.$element 569 | [dimension](0) 570 | .one($.support.transition.end, $.proxy(complete, this)) 571 | .emulateTransitionEnd(350) 572 | } 573 | 574 | Collapse.prototype.toggle = function () { 575 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 576 | } 577 | 578 | 579 | // COLLAPSE PLUGIN DEFINITION 580 | // ========================== 581 | 582 | var old = $.fn.collapse 583 | 584 | $.fn.collapse = function (option) { 585 | return this.each(function () { 586 | var $this = $(this) 587 | var data = $this.data('bs.collapse') 588 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 589 | 590 | if (!data && options.toggle && option == 'show') option = !option 591 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 592 | if (typeof option == 'string') data[option]() 593 | }) 594 | } 595 | 596 | $.fn.collapse.Constructor = Collapse 597 | 598 | 599 | // COLLAPSE NO CONFLICT 600 | // ==================== 601 | 602 | $.fn.collapse.noConflict = function () { 603 | $.fn.collapse = old 604 | return this 605 | } 606 | 607 | 608 | // COLLAPSE DATA-API 609 | // ================= 610 | 611 | $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { 612 | var $this = $(this), href 613 | var target = $this.attr('data-target') 614 | || e.preventDefault() 615 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 616 | var $target = $(target) 617 | var data = $target.data('bs.collapse') 618 | var option = data ? 'toggle' : $this.data() 619 | var parent = $this.attr('data-parent') 620 | var $parent = parent && $(parent) 621 | 622 | if (!data || !data.transitioning) { 623 | if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') 624 | $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 625 | } 626 | 627 | $target.collapse(option) 628 | }) 629 | 630 | }(jQuery); 631 | 632 | /* ======================================================================== 633 | * Bootstrap: dropdown.js v3.1.0 634 | * http://getbootstrap.com/javascript/#dropdowns 635 | * ======================================================================== 636 | * Copyright 2011-2014 Twitter, Inc. 637 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 638 | * ======================================================================== */ 639 | 640 | 641 | +function ($) { 642 | 'use strict'; 643 | 644 | // DROPDOWN CLASS DEFINITION 645 | // ========================= 646 | 647 | var backdrop = '.dropdown-backdrop' 648 | var toggle = '[data-toggle=dropdown]' 649 | var Dropdown = function (element) { 650 | $(element).on('click.bs.dropdown', this.toggle) 651 | } 652 | 653 | Dropdown.prototype.toggle = function (e) { 654 | var $this = $(this) 655 | 656 | if ($this.is('.disabled, :disabled')) return 657 | 658 | var $parent = getParent($this) 659 | var isActive = $parent.hasClass('open') 660 | 661 | clearMenus() 662 | 663 | if (!isActive) { 664 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 665 | // if mobile we use a backdrop because click events don't delegate 666 | $('