Adds working deposit and purchases.

- Switch to bootstrap.
 - Still no balance checking or form feedback messages.
This commit is contained in:
nikolark committed 2012-02-22 05:22:04 +01:00
1 parent ce8190c870
commit fc400dffd4
36 files changed
+9218 -797

No files matched your search

+14 -13
View File
@@ -2,17 +2,18 @@ from django import forms
from models import *
class OrderForm(forms.Form):
pass
class OrderLineForm(forms.ModelForm):
#product = forms.CharField(required=True, widget=forms.HiddenInput)
#amount = forms.IntegerField(required=True)
class OrderForm(forms.ModelForm):
# TODO : validate that the customer can afford the order
class Meta:
model = OrderLine
fields = ('amount','product')
widgets = {
'product': forms.HiddenInput(),
'amount': forms.TextInput(attrs={'size': '2'}),
}
# TODO : Validation
model = Order
fields = ('customer',)
class OrderLineForm(forms.Form):
product = forms.IntegerField(required=True)
amount = forms.IntegerField(required=True)
unit_price = forms.FloatField(required=True)
class DepositForm(forms.ModelForm):
class Meta:
model = Transaction
+2 -2
View File
@@ -21,12 +21,12 @@ class Product(models.Model):
updated = models.DateTimeField(auto_now=True)
class Order(models.Model):
user = models.ForeignKey(User)
customer = models.ForeignKey(User)
order_sum = models.FloatField(db_column='sum')
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return "{0}: {1} kr".format(self.user, self.order_sum)
return "{0}: {1} kr".format(self.customer, self.order_sum)
class OrderLine(models.Model):
order = models.ForeignKey(Order)
+1
View File
@@ -2,4 +2,5 @@ from django.conf.urls.defaults import patterns, include, url
urlpatterns = patterns('main.views',
url(r'^register/$', 'register', name='register'),
url(r'^deposit/$', 'deposit', name='deposit'),
)
+54 -12
View File
@@ -26,22 +26,64 @@ def home(request):
form = AuthenticationForm(request)
return render_to_response('home.html', locals(), context_instance=RequestContext(request))
@login_required
def register(request):
if request.method == "POST":
# TODO: Form processing is not working at all
form = OrderLineForm(data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect( reverse('main.views.register') )
products = Product.objects.all()
users = User.objects.all()
# Formset for orderlines
# FIXME: Like this?
#OrderLineFormSet = formset_factory(OrderLineForm, extra=products.count())
#formset = OrderLineFormSet()
users = User.objects.filter(userprofile__balance__gt=0)
users_js = "[{0}]".format(
",".join(['"'+user+'"' for user in users.values_list('username', flat=True)]))
# multiple orderlines (one per product)
OrderLineFormSet = formset_factory(OrderLineForm)
if request.method == "POST":
orderform = OrderForm(request.POST)
formset = OrderLineFormSet(request.POST)
if formset.is_valid() and orderform.is_valid():
order_sum = sum([orderline['amount'] * orderline['unit_price'] for orderline in formset.cleaned_data])
order = orderform.save(commit=False)
order.order_sum = order_sum
order.save()
profile = order.customer.get_profile()
profile.balance -= order.order_sum
profile.save()
for ol in formset.cleaned_data:
if ol['amount'] > 0:
product = Product.objects.get(pk=ol['product'])
OrderLine.objects.create(
order=order,
product=product,
amount=ol['amount'],
unit_price=ol['unit_price'])
return HttpResponseRedirect( reverse('main.views.register') )
else:
# errors
orderform = OrderForm(request.POST)
formset = OrderLineFormSet(request.POST)
else:
orderform = OrderForm()
formset = OrderLineFormSet()
return render_to_response('register.html', locals(), context_instance=RequestContext(request))
def deposit(request):
users = User.objects.all()
if request.method == "POST":
form = DepositForm(request.POST)
if form.is_valid():
transaction = form.save()
profile = transaction.user.get_profile()
profile.balance += transaction.amount
profile.save()
return HttpResponseRedirect( reverse('main.views.deposit') )
else:
form = DepositForm(request.POST)
else:
form = DepositForm()
return render_to_response('deposit.html', locals(), context_instance=RequestContext(request))
def logout(request):
auth_logout(request)
return render_to_response('registration/logout.html', locals(), context_instance=RequestContext(request))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

+2 -2
View File
@@ -1,4 +1,5 @@
# Require any additional compass plugins here.
require 'compass_twitter_bootstrap'
# Set this to the root of your project when deployed:
http_path = "/"
@@ -9,12 +10,11 @@ javascripts_dir = "javascripts"
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false
line_comments = false
# If you prefer the indented syntax, you might want to regenerate this
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File renamed without changes.
File renamed without changes.
File renamed without changes.
-16
View File
@@ -1,16 +0,0 @@
@import "blueprint";
// To generate css equivalent to the blueprint css but with your configuration applied, uncomment:
// +blueprint-ie
//Recommended Blueprint configuration with scoping and semantic layout:
body.bp {
@include blueprint-ie(true);
// Note: Blueprint centers text to fix IE6 container centering.
// This means all your texts will be centered under all version of IE by default.
// If your container does not have the .container class, don't forget to restore
// the correct behavior to your main container (but not the body tag!)
// Example:
// .my-container
// text-align: left
}
-10
View File
@@ -1,10 +0,0 @@
// Here is where you can define your constants for your application and to configure the blueprint framework.
// Feel free to delete these if you want keep the defaults:
$blueprint-grid-columns: 24;
$blueprint-container-size: 950px;
$blueprint-grid-margin: 10px;
// Use this to calculate the width based on the total width.
// Or you can set $blueprint-grid-width to a fixed value and unset $blueprint-container-size -- it will be calculated for you.
$blueprint-grid-width: ($blueprint-container-size + $blueprint-grid-margin) / $blueprint-grid-columns - $blueprint-grid-margin;
-6
View File
@@ -1,6 +0,0 @@
// Only apply the blueprint form styles to forms with
// a class of "bp". This makes it easier to style
// forms from scratch if you need to.
form.bp {
@include blueprint-form; }
-16
View File
@@ -1,16 +0,0 @@
// Import the non-default scaffolding module to help us get started.
@import "blueprint/scaffolding";
// This configuration will only apply the
// blueprint styles to pages with a body class of "bp"
// This makes it easier to have pages without blueprint styles
// when you're using a single/combined stylesheet.
body.bp {
@include blueprint-typography(true);
@include blueprint-utilities;
@include blueprint-debug;
@include blueprint-interaction;
// Remove the scaffolding when you're ready to start doing visual design.
// Or leave it in if you're happy with how blueprint looks out-of-the-box
@include blueprint-scaffolding; }
-38
View File
@@ -1,38 +0,0 @@
// Page layout can be done using mixins applied to your semantic classes and IDs
// For instance this layout defines a two column layout on pages with
// a body class of "two-col".
//
// The markup would look like:
// <div id="container">
// <div id="header"></div>
// <div id="sidebar"></div>
// <div id="content"></div>
// <div id="footer"></div>
// </div>
//
// and the layout would look like:
// +------------------------+
// | #header |
// +--------+---------------+
// | | |
// |#sidebar| #content |
// | | |
// +------------------------+
// | #footer |
// +--------+---------------+
body.two-col {
#container {
@include container; }
#header, #footer {
@include column($blueprint-grid-columns); }
#sidebar {
// One third of the grid columns, rounding down. With 24 cols, this is 8.
$sidebar-columns: floor($blueprint-grid-columns / 3);
@include column($sidebar-columns); }
#content {
// Two thirds of the grid columns, rounding up.
// With 24 cols, this is 16.
$content-columns: ceil(2 * $blueprint-grid-columns / 3);
// true means it's the last column in the row
@include column($content-columns, true); } }
+1 -5
View File
@@ -1,5 +1 @@
@import "blueprint";
//Recommended Blueprint configuration with scoping and semantic layout:
body.bp {
@include blueprint-print(true); }
@import "compass_twitter_bootstrap";
+20 -36
View File
@@ -1,30 +1,9 @@
// This import applies a global reset to any page that imports this stylesheet.
@import "blueprint/reset";
// To configure blueprint, edit the partials/base.sass file.
@import "partials/base";
// Import all the default blueprint modules so that we can access their mixins.
@import "blueprint";
// Combine the partials into a single screen stylesheet.
@import "partials/page";
@import "partials/form";
@import "partials/two_col";
@import "compass";
//@import "compass";
@import "compass_twitter_bootstrap";
body {
background-color: $blueprint-background-color;
#header {
nav {
margin:2em;
ul {
@include inline-block-list;
}
}
}
#register {
@@ -33,16 +12,15 @@ body {
@include inline-block-list;
li {
img { }
padding: 1em;
padding: 1.5em;
text-align: center;
width: 100px;
&:hover {
background-color: darken($blueprint-background-color, 20%);
background-color: #dddddd;
}
&.selected {
background-color: darken($blueprint-background-color, 20%);
&.marked {
background-color: #dddddd;
}
}
}
@@ -56,19 +34,25 @@ body {
text-align: center;
&:hover {
background-color: darken($blueprint-background-color, 20%);
background-color: #dddddd;
}
}
}
}
#total {
div {
color: #ffffff;
background-color: #222;
padding: 10px;
min-width:115px;
h2 {
color: #ffffff;
}
}
}
button {
margin-top:10px;
}
input[type=submit] {
padding: 1em;
padding-left: 1.5em;
padding-right: 1.5em;
position:relative;
left: 100px;
}
section {
margin-bottom:2em;
-85
View File
@@ -1,85 +0,0 @@
body.bp {
text-align: center;
}
* html body.bp legend {
margin: 0px -8px 16px 0;
padding: 0;
}
html > body.bp p code {
*white-space: normal;
}
body.bp .container {
text-align: left;
}
body.bp sup {
vertical-align: text-top;
}
body.bp sub {
vertical-align: text-bottom;
}
body.bp hr {
margin: -8px auto 11px;
}
body.bp img {
-ms-interpolation-mode: bicubic;
}
body.bp fieldset {
padding-top: 0;
}
body.bp legend {
margin-top: -0.2em;
margin-bottom: 1em;
margin-left: -0.5em;
}
body.bp fieldset, body.bp #IE8#HACK {
padding-top: 1.4em;
}
body.bp legend, body.bp #IE8#HACK {
margin-top: 0;
margin-bottom: 0;
}
body.bp textarea {
overflow: auto;
}
body.bp label {
position: relative;
top: -0.25em;
}
body.bp input.text {
margin: 0.5em 0;
background-color: white;
border: 1px solid #bbbbbb;
}
body.bp input.text:focus {
border: 1px solid #666666;
}
body.bp input.title {
margin: 0.5em 0;
background-color: white;
border: 1px solid #bbbbbb;
}
body.bp input.title:focus {
border: 1px solid #666666;
}
body.bp input.checkbox {
position: relative;
top: 0.25em;
}
body.bp input.radio {
position: relative;
top: 0.25em;
}
body.bp input.button {
position: relative;
top: 0.25em;
}
body.bp textarea {
margin: 0.5em 0;
}
body.bp select {
margin: 0.5em 0;
}
body.bp button {
position: relative;
top: 0.25em;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+136
View File
@@ -0,0 +1,136 @@
/* =============================================================
* bootstrap-collapse.js v2.0.0
* 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.addClass('collapse')
}
, 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 )
+95
View File
@@ -0,0 +1,95 @@
/* ===========================================================
* bootstrap-popover.js v2.0.0
* http://twitter.github.com/bootstrap/javascript.html#popovers
* ===========================================================
* 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 Popover = function ( element, options ) {
this.init('popover', element, options)
}
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
========================================== */
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
constructor: Popover
, setContent: function () {
var $tip = this.tip()
, title = this.getTitle()
, content = this.getContent()
$tip.find('.popover-title')[ $.type(title) == 'object' ? 'append' : 'html' ](title)
$tip.find('.popover-content > *')[ $.type(content) == 'object' ? 'append' : 'html' ](content)
$tip.removeClass('fade top bottom left right in')
}
, hasContent: function () {
return this.getTitle() || this.getContent()
}
, getContent: function () {
var content
, $e = this.$element
, o = this.options
content = $e.attr('data-content')
|| (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
content = content.toString().replace(/(^\s*|\s*$)/, "")
return content
}
, tip: function() {
if (!this.$tip) {
this.$tip = $(this.options.template)
}
return this.$tip
}
})
/* POPOVER PLUGIN DEFINITION
* ======================= */
$.fn.popover = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('popover')
, options = typeof option == 'object' && option
if (!data) $this.data('popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.popover.Constructor = Popover
$.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
placement: 'right'
, content: ''
, template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
})
}( window.jQuery )
+270
View File
@@ -0,0 +1,270 @@
/* ===========================================================
* bootstrap-tooltip.js v2.0.0
* http://twitter.github.com/bootstrap/javascript.html#tooltips
* Inspired by the original jQuery.tipsy by Jason Frame
* ===========================================================
* 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"
/* TOOLTIP PUBLIC CLASS DEFINITION
* =============================== */
var Tooltip = function ( element, options ) {
this.init('tooltip', element, options)
}
Tooltip.prototype = {
constructor: Tooltip
, init: function ( type, element, options ) {
var eventIn
, eventOut
this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
this.enabled = true
if (this.options.trigger != 'manual') {
eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
}
this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
}
, getOptions: function ( options ) {
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay
, hide: options.delay
}
}
return options
}
, enter: function ( e ) {
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
if (!self.options.delay || !self.options.delay.show) {
self.show()
} else {
self.hoverState = 'in'
setTimeout(function() {
if (self.hoverState == 'in') {
self.show()
}
}, self.options.delay.show)
}
}
, leave: function ( e ) {
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
if (!self.options.delay || !self.options.delay.hide) {
self.hide()
} else {
self.hoverState = 'out'
setTimeout(function() {
if (self.hoverState == 'out') {
self.hide()
}
}, self.options.delay.hide)
}
}
, show: function () {
var $tip
, inside
, pos
, actualWidth
, actualHeight
, placement
, tp
if (this.hasContent() && this.enabled) {
$tip = this.tip()
this.setContent()
if (this.options.animation) {
$tip.addClass('fade')
}
placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement
inside = /in/.test(placement)
$tip
.remove()
.css({ top: 0, left: 0, display: 'block' })
.appendTo(inside ? this.$element : document.body)
pos = this.getPosition(inside)
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
switch (inside ? placement.split(' ')[1] : placement) {
case 'bottom':
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'top':
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'left':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
break
case 'right':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
break
}
$tip
.css(tp)
.addClass(placement)
.addClass('in')
}
}
, setContent: function () {
var $tip = this.tip()
$tip.find('.tooltip-inner').html(this.getTitle())
$tip.removeClass('fade in top bottom left right')
}
, hide: function () {
var that = this
, $tip = this.tip()
$tip.removeClass('in')
function removeWithAnimation() {
var timeout = setTimeout(function () {
$tip.off($.support.transition.end).remove()
}, 500)
$tip.one($.support.transition.end, function () {
clearTimeout(timeout)
$tip.remove()
})
}
$.support.transition && this.$tip.hasClass('fade') ?
removeWithAnimation() :
$tip.remove()
}
, fixTitle: function () {
var $e = this.$element
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
}
}
, hasContent: function () {
return this.getTitle()
}
, getPosition: function (inside) {
return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
width: this.$element[0].offsetWidth
, height: this.$element[0].offsetHeight
})
}
, getTitle: function () {
var title
, $e = this.$element
, o = this.options
title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
title = title.toString().replace(/(^\s*|\s*$)/, "")
return title
}
, tip: function () {
return this.$tip = this.$tip || $(this.options.template)
}
, validate: function () {
if (!this.$element[0].parentNode) {
this.hide()
this.$element = null
this.options = null
}
}
, enable: function () {
this.enabled = true
}
, disable: function () {
this.enabled = false
}
, toggleEnabled: function () {
this.enabled = !this.enabled
}
, toggle: function () {
this[this.tip().hasClass('in') ? 'hide' : 'show']()
}
}
/* TOOLTIP PLUGIN DEFINITION
* ========================= */
$.fn.tooltip = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('tooltip')
, options = typeof option == 'object' && option
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tooltip.Constructor = Tooltip
$.fn.tooltip.defaults = {
animation: true
, delay: 0
, selector: false
, placement: 'top'
, trigger: 'hover'
, title: ''
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
}
}( window.jQuery )
+271
View File
@@ -0,0 +1,271 @@
/* =============================================================
* bootstrap-typeahead.js v2.0.1
* http://twitter.github.com/bootstrap/javascript.html#typeahead
* =============================================================
* 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 Typeahead = function ( element, options ) {
this.$element = $(element)
this.options = $.extend({}, $.fn.typeahead.defaults, options)
this.matcher = this.options.matcher || this.matcher
this.sorter = this.options.sorter || this.sorter
this.highlighter = this.options.highlighter || this.highlighter
this.$menu = $(this.options.menu).appendTo('body')
this.source = this.options.source
this.shown = false
this.listen()
}
Typeahead.prototype = {
constructor: Typeahead
, select: function () {
var val = this.$menu.find('.active').attr('data-value')
this.$element.val(val)
return this.hide()
}
, show: function () {
var pos = $.extend({}, this.$element.offset(), {
height: this.$element[0].offsetHeight
})
this.$menu.css({
top: pos.top + pos.height
, left: pos.left
})
this.$menu.show()
this.shown = true
return this
}
, hide: function () {
this.$menu.hide()
this.shown = false
return this
}
, lookup: function (event) {
var that = this
, items
, q
this.query = this.$element.val()
if (!this.query) {
return this.shown ? this.hide() : this
}
items = $.grep(this.source, function (item) {
if (that.matcher(item)) return item
})
items = this.sorter(items)
if (!items.length) {
return this.shown ? this.hide() : this
}
return this.render(items.slice(0, this.options.items)).show()
}
, matcher: function (item) {
return ~item.toLowerCase().indexOf(this.query.toLowerCase())
}
, sorter: function (items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, item
while (item = items.shift()) {
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
else if (~item.indexOf(this.query)) caseSensitive.push(item)
else caseInsensitive.push(item)
}
return beginswith.concat(caseSensitive, caseInsensitive)
}
, highlighter: function (item) {
return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
})
}
, render: function (items) {
var that = this
items = $(items).map(function (i, item) {
i = $(that.options.item).attr('data-value', item)
i.find('a').html(that.highlighter(item))
return i[0]
})
items.first().addClass('active')
this.$menu.html(items)
return this
}
, next: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, next = active.next()
if (!next.length) {
next = $(this.$menu.find('li')[0])
}
next.addClass('active')
}
, prev: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, prev = active.prev()
if (!prev.length) {
prev = this.$menu.find('li').last()
}
prev.addClass('active')
}
, listen: function () {
this.$element
.on('blur', $.proxy(this.blur, this))
.on('keypress', $.proxy(this.keypress, this))
.on('keyup', $.proxy(this.keyup, this))
if ($.browser.webkit || $.browser.msie) {
this.$element.on('keydown', $.proxy(this.keypress, this))
}
this.$menu
.on('click', $.proxy(this.click, this))
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
}
, keyup: function (e) {
e.stopPropagation()
e.preventDefault()
switch(e.keyCode) {
case 40: // down arrow
case 38: // up arrow
break
case 9: // tab
case 13: // enter
if (!this.shown) return
this.select()
break
case 27: // escape
this.hide()
break
default:
this.lookup()
}
}
, keypress: function (e) {
e.stopPropagation()
if (!this.shown) return
switch(e.keyCode) {
case 9: // tab
case 13: // enter
case 27: // escape
e.preventDefault()
break
case 38: // up arrow
e.preventDefault()
this.prev()
break
case 40: // down arrow
e.preventDefault()
this.next()
break
}
}
, blur: function (e) {
var that = this
e.stopPropagation()
e.preventDefault()
setTimeout(function () { that.hide() }, 150)
}
, click: function (e) {
e.stopPropagation()
e.preventDefault()
this.select()
}
, mouseenter: function (e) {
this.$menu.find('.active').removeClass('active')
$(e.currentTarget).addClass('active')
}
}
/* TYPEAHEAD PLUGIN DEFINITION
* =========================== */
$.fn.typeahead = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('typeahead')
, options = typeof option == 'object' && option
if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.typeahead.defaults = {
source: []
, items: 8
, menu: '<ul class="typeahead dropdown-menu"></ul>'
, item: '<li><a href="#"></a></li>'
}
$.fn.typeahead.Constructor = Typeahead
/* TYPEAHEAD DATA-API
* ================== */
$(function () {
$('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
var $this = $(this)
if ($this.data('typeahead')) return
e.preventDefault()
$this.typeahead($this.data())
})
})
}( window.jQuery );
+4
View File
@@ -0,0 +1,4 @@
/*! jQuery v1.7.1 jquery.com | jquery.org/license */
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;iLine truncated
f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.cLine truncated
{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacitLine truncated
+40 -6
View File
@@ -1,26 +1,60 @@
$(document).ready(function() {
function enable_all_customers() {
$("li.customer").each(function(i) {
$(this).removeClass("selected");
$(this).removeClass("marked");
$(this).show();
});
}
function filter_customers(typed) {
/* FIXME: Does not work well. */
setTimeout(function() {
$("li.customer").each(function(i) {
if($(this).children("span.name").text().indexOf(typed) == -1) {
$(this).hide();
$(this).removeClass("marked");
} else {
$(this).show();
}
/* Full match */
if($(this).children("span.name").text() == typed) {
$(this).addClass("marked");
}
});
}, 50);
}
/* Customer search */
$('.typeahead').typeahead();
$('#id_customer_name').keydown(function(event) {
filter_customers(event.srcElement.value);
});
/* Customer selection */
$("li.customer").click( function() {
enable_all_customers();
/* Disable the customer button just clicked */
$(this).addClass("selected");
/* Update the field */
$("input[name=customer]").val($(this).children("span.name").text());
$(this).addClass("marked");
/* Update the typeahead field */
var username = $(this).children("span.name").text()
$("#id_customer_typeahead").val(username);
/* Update the select field */
var id = $(this).children("span.id").text()
$("#id_customer option").removeAttr('selected');
$("#id_customer option[value="+id+"]").attr('selected','selected');
});
/* Product amount controls */
$("li.product").click( function() {
var form_field = $(this).children("input[type=text]");
var qty = Number(form_field.val()) + 1;
form_field.val(qty);
/* Update total*/
var sale_price_int = Number($(this).children("span.sale_price_int").text());
var cur_total = Number($("span.total_text").text())
$("span.total_text").html(cur_total + sale_price_int);
});
/* Form reset */
$("input[type=reset]").click( function() {
$("input[name=customer]").val("");
$("button[type=reset]").click( function() {
$('#id_customer option').removeAttr('selected');
$("#id_customer_typeahead").val("");
$("span.total_text").html("");
enable_all_customers();
});
+12 -10
View File
@@ -3,31 +3,33 @@
<head>
<title>{%block title%}BBS{%endblock%}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/static/gaute/stylesheets/screen.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="/static/gaute/stylesheets/print.css" type="text/css" media="print">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ STATIC_URL }}gaute/stylesheets/screen.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="{{ STATIC_URL }}gaute/stylesheets/print.css" type="text/css" media="print">
<!--[if lt IE 8]>
<link rel="stylesheet" href="/static/gaute/stylesheets/ie.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="{{ STATIC_URL }}gaute/stylesheets/ie.css" type="text/css" media="screen, projection">
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script src="/static/js/register.js"></script>
{%block headinc %}
{%endblock%}
</head>
<body class="bp three-col">
<body>
<header id="header">
{%block header%}
{% include "nav.html" %}
{%endblock%}
</header>
<div id="container">
<div id="container" class="container-fluid">
{%block content%}
{%endblock%}
</div>
<div id="footer">
<div id="footer" class="row-fluid span12">
{%block footer %}
<img src="/static/DNSlogo.png" />
<img src="{{ STATIC_URL }}gaute/img/edb_brick.png" />
{%endblock%}
</div>
</div>
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/bootstrap-collapse.js"></script>
{%block tailinc %}
{%endblock%}
</body>
+21
View File
@@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block header %}
{% include "nav.html" with active="deposit" %}
{% endblock %}
{% block content %}
<section id="deposit" class="row-fluid">
<div class="span12">
<form id="order" method="post" class="form-stacked" autocomplete="off">
{% csrf_token %}
<fieldset>
{{form}}
</fieldset>
<div class="form-actions">
  <button type="submit" class="btn btn-large btn-primary" name="submit_order">Sett inn</button>
  <a href="{% url register %}" class="btn">Avbryt</a>
</div>
</form>
</div>
</section>
{% endblock %}
+6 -2
View File
@@ -1,8 +1,12 @@
{% extends "base.html" %}
{%block header%}
<h1>Biceps Bar System</h1>
{% include "nav.html" with active="home" %}
{%endblock%}
{%block content%}
<a href="/register/">Kasse</a>
<div class="row-fluid">
<section class="span4">
<h1>Biceps Bar System</h1>
</section>
</div>
{%endblock%}
+25
View File
@@ -0,0 +1,25 @@
<nav class="navbar">
<div class="navbar-inner">
<div class="container">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a href="/" class="brand">Biceps Bar System - BBS</a>
<div class="nav-collapse">
<ul class="nav">
{% if active %}
<li class="{% if active = "register" %}active{% endif %}"><a href="/register"><i class="icon-home icon-white"></i> Kjøp drikke</a></li>
<li class="{% if active = "deposit" %}active{% endif %}"><a href="/deposit">Sett inn penger</a></li>
<li class="{% if active = "remove_purchase" %}active{% endif %}"><a href="#"> Fjern kjøp</a></li>
{% if request.user.is_superuser %}
<li><a href="/admin">Administrasjon</a></li>
{% endif %}
{% endif %}
</ul>
</div>
</div>
</div>
</nav>
+60 -32
View File
@@ -1,51 +1,79 @@
{% extends "base.html" %}
{% block header %}
<h1>Biceps Bar System</h1>
<nav>
<ul>
<li><a href="{% url main.views.logout %}">Logout</a></li>
</ul>
</nav>
{% include "nav.html" with active="register" %}
{% endblock %}
{% block content %}
<section id="register">
<form id="order" method="post">
<section id="register" class="row-fluid">
<form id="order" method="post" autocomplete="off">
<fieldset>
{% csrf_token %}
<section id="customer">
<h2>Velg kunde</h2>
<input type="hidden" name="customer" value="" />
<ul>
<!-- Formset validation fields -->
<input type="hidden" name="form-TOTAL_FORMS" value="{{ products|length }}" id="id_form-TOTAL_FORMS" />
<input type="hidden" name="form-INITIAL_FORMS" value="{{ products|length }}" id="id_form-INITIAL_FORMS" />
<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
<section id="customer" class="row-fluid">
<div class="span12">
<h2>Hvem kjøper?</h2>
<!-- Typeahead customer field -->
<input name="customer_name" id="id_customer_typeahead" value="" data-provide="typeahead" data-source="{{users_js}}" />
<!-- Actual customer select field (hidden) -->
<div style="display:none;">{{orderform.customer }}</div>
{% if users %}
<ul class="well">
{% for user in users %}
<li class="customer">
{% if user.get_profile.image %}
  <img class="profile" src="{{ user.get_profile.image.url }}" /><br />
{% else %}
  <img class="profile" src="/static/gaute/images/unknown.png" /><br />
  <img class="profile" src="{{ STATIC_URL }}gaute/img/unknown.png" /><br />
{% endif %}
<span class="name">{{ user }}</span> ({{ user.get_profile.balance }})</li>
{% endfor %}
</ul>
</section>
<section id="products">
<h2>Velg antall</h2>
<ul>
{% for product in products %}
<li id="form-{{forloop.counter0}}" class="product"><input type="hidden" name="form-{{ forloop.counter0 }}-product" value="{{product.id }}" />
<input type="text" id="form-{{ forloop.counter0 }}-amount" name="form-{{ forloop.counter0 }}-amount" value="0" size="2" />
{% if product.image %}
<img class="product" src="{{ product.image.url }}" /><br />
{% else %}
<img class="product" src="/static/gaute/images/product.png" /><br />
{% endif %}
{{ product.name }}
<span class="name">{{ user }}</span> ({{ user.get_profile.balance }})
<span class="id" style="display:none;">{{ user.id }}</span>
</li>
</li>
{% endfor %}
</ul>
{%else%}
<div class="alert alert-error">Ingen har positiv saldo i BBS.</div>
{%endif%}
</div>
</section>
<section id="total"><h3>Totalt</h3><span class="total_text"></span></section>
  <input type="reset" id="reset" value="Start på nytt" />
  <input type="submit" id="submit_order" name="submit_order" value="Kjøp" />
<section id="products" class="row-fluid">
<div class="span12">
<h2>Kjøper hva?</h2>
<ul class="well">
{% for product in products %}
<li id="form-{{forloop.counter0}}" class="product"><input type="hidden" name="form-{{ forloop.counter0 }}-product" value="{{product.id }}" />
<input type="text" id="form-{{ forloop.counter0 }}-amount" name="form-{{ forloop.counter0 }}-amount" value="0" class="span2" size="2" />
<input type="hidden" name="form-{{ forloop.counter0 }}-unit_price" value="{{product.sale_price_int }}" />
{% if product.image %}
<img class="product" src="{{ product.image.url }}" /><br />
{% else %}
<img class="product" src="{{ STATIC_URL }}gaute/img/product.png" /><br />
{% endif %}
<span class="name">{{ product.name }}</span> - <span class="sale_price_int">{{product.sale_price_int|floatformat:0}}</span>
</li>
{% endfor %}
</ul>
</div>
</section>
<section id="total" class="row-fluid">
<div class="span2">
<h2>Totalt: <span class="total_text"></span></h2>
</div>
</section>
</fieldset>
<div class="form-actions">
  <button type="submit" class="btn btn-large btn-primary" name="submit_order">Kjøp</button>
  <button type="reset" class="btn">Start på nytt</button>
</div>
</form>
</section>
{% endblock %}
{% block tailinc %}
<script src="{{ STATIC_URL }}js/bootstrap-typeahead.js"></script>
<script src="{{ STATIC_URL }}js/register.js"></script>
{% endblock %}
+1 -1
View File
@@ -3,7 +3,7 @@ from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', 'main.views.home', name='home'),
url(r'^$', 'main.views.register', name='home'),
url(r'', include('main.urls')),
url(r'^accounts/login/$', 'django.contrib.auth.views.login'),
url(r'^logout/$', 'main.views.logout'),