Commit 4a787868 authored by Aleksanr Zavatskiy's avatar Aleksanr Zavatskiy

Merge remote-tracking branch 'upstream/master'

parent 6f60919a
......@@ -3,8 +3,8 @@ from flask.globals import _request_ctx_stack
from flask.ext.admin.babel import gettext, ngettext
from flask.ext.admin import helpers as h
__all__ = ['Select2Widget', 'DatePickerWidget', 'DateTimePickerWidget', 'RenderTemplateWidget',
'Select2TagsWidget', ]
__all__ = ['Select2Widget', 'DatePickerWidget', 'DateTimePickerWidget',
'RenderTemplateWidget', 'Select2TagsWidget', 'MarkItUpWidget', ]
class Select2Widget(widgets.Select):
......@@ -40,7 +40,7 @@ class DatePickerWidget(widgets.TextInput):
"""
Date picker widget.
You must include bootstrap-datepicker.js and form.js for styling to work.
You must include bootstrap-datetimepicker.js and form.js for styling to work.
"""
def __call__(self, field, **kwargs):
kwargs['data-role'] = u'datepicker'
......@@ -51,13 +51,23 @@ class DateTimePickerWidget(widgets.TextInput):
"""
Datetime picker widget.
You must include bootstrap-datepicker.js and form.js for styling to work.
You must include bootstrap-datetimepicker.js and form.js for styling to work.
"""
def __call__(self, field, **kwargs):
kwargs['data-role'] = u'datetimepicker'
kwargs['data-format'] = u'yyyy-MM-dd hh:mm:ss'
return super(DateTimePickerWidget, self).__call__(field, **kwargs)
class MarkItUpWidget(widgets.TextArea):
""" MarkItUp <http://markitup.jaysalvat.com/home/> widget.
"""
def __call__(self, field, **kwargs):
kwargs['data-role'] = u'markitup'
return super(MarkItUpWidget, self).__call__(field, **kwargs)
class RenderTemplateWidget(object):
"""
WTForms widget that renders Jinja2 template
......
......@@ -106,10 +106,10 @@
processAjaxWidget($el, name);
return true;
case 'datepicker':
$el.datepicker();
$el.datetimepicker({pickTime: false});
return true;
case 'datetimepicker':
$el.datepicker({displayTime: true});
$el.datetimepicker();
return true;
}
};
......
.datepicker {
background-color: #ffffff;
border-color: #999;
border-color: rgba(0, 0, 0, 0.2);
border-style: solid;
border-width: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-webkit-background-clip: padding-box;
-moz-background-clip: padding-box;
background-clip: padding-box;
display: none;
position: absolute;
z-index: 900;
margin-left: 0;
margin-right: 0;
margin-bottom: 18px;
padding-bottom: 4px;
width: 218px;
}
.datepicker .nav {
font-weight: bold;
width: 100%;
padding: 4px 0;
background-color: #f5f5f5;
color: #808080;
border-bottom: 1px solid #ddd;
-webkit-box-shadow: inset 0 1px 0 #ffffff;
-moz-box-shadow: inset 0 1px 0 #ffffff;
box-shadow: inset 0 1px 0 #ffffff;
zoom: 1;
}
.datepicker .nav:before, .datepicker .nav:after {
display: table;
content: "";
zoom: 1;
*display: inline;
}
.datepicker .nav:after {
clear: both;
}
.datepicker .nav span {
display: block;
float: left;
text-align: center;
height: 28px;
line-height: 28px;
position: relative;
}
.datepicker .nav .bg {
width: 100%;
background-color: #fdf5d9;
height: 28px;
position: absolute;
top: 0;
left: 0;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker .nav .fg {
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.datepicker .button {
cursor: pointer;
padding: 0 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker .button:hover {
background-color: #808080;
color: #ffffff;
}
.datepicker .months {
float: left;
margin-left: 4px;
}
.datepicker .months .name {
width: 72px;
padding: 0;
}
.datepicker .years {
float: right;
margin-right: 4px;
}
.datepicker .years .name {
width: 36px;
padding: 0;
}
.datepicker .dow, .datepicker .days div {
float: left;
width: 30px;
line-height: 25px;
text-align: center;
}
.datepicker .dow {
font-weight: bold;
color: #808080;
}
.datepicker .calendar {
padding: 4px;
}
.datepicker .days div {
cursor: pointer;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker .days div:hover {
background-color: #0064cd;
color: #ffffff;
}
.datepicker .overlap {
color: #bfbfbf;
}
.datepicker .today {
background-color: #fee9cc;
}
.datepicker .selected {
background-color: #bfbfbf;
color: #ffffff;
}
.datepicker .time {
clear: both;
padding-top: 8px;
margin-left: 4px;
}
.datepicker .time label {
text-align: center;
}
.datepicker .time input {
width: 200px;
}
/* ===========================================================
* bootstrap-datepicker.js v1.3.0
* http://twitter.github.com/bootstrap/javascript.html#datepicker
* ===========================================================
* Copyright 2011 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.
*
* Contributed by Scott Torborg - github.com/storborg
* Loosely based on jquery.date_input.js by Jon Leighton, heavily updated and
* rewritten to match bootstrap javascript approach and add UI features.
*
* Enhancements and fixes by Serge S. Koval - github.com/mrjoes
*
* =========================================================== */
!function ( $ ) {
var all = [];
function clearDatePickers(except) {
var ii;
for(ii = 0; ii < all.length; ii++) {
if(all[ii] != except) {
all[ii].hide();
}
}
}
function DatePicker( element, options ) {
this.$el = $(element);
this.proxy('show').proxy('ahead').proxy('hide').proxy('keyHandler').proxy('selectDate');
var options = $.extend({}, $.fn.datepicker.defaults, options );
// If custom parse/format function was not passed in options and time-based display
// is enabled, use time-compatible parse/format functions
if (options.displayTime && !!!options.parse && !!!options.format) {
options.parse = this.parseDateTime;
}
$.extend(this, options);
this.$el.data('datepicker', this);
all.push(this);
this.init();
}
DatePicker.prototype = {
init: function() {
var $months = this.nav('months', 1);
var $years = this.nav('years', 12);
var $nav = $('<div>').addClass('nav').append($months, $years);
this.$month = $('.name', $months);
this.$year = $('.name', $years);
$calendar = $("<div>").addClass('calendar');
// Populate day of week headers, realigned by startOfWeek.
for (var i = 0; i < this.shortDayNames.length; i++) {
$calendar.append('<div class="dow">' + this.shortDayNames[(i + this.startOfWeek) % 7] + '</div>');
};
this.$days = $('<div>').addClass('days');
$calendar.append(this.$days);
this.$picker = $('<div>')
.addClass('datepicker')
.append($nav, $calendar)
.insertAfter(this.$el);
this.$picker.children()
.click(function(e) { e.stopPropagation() })
// Use this to prevent accidental text selection.
.mousedown(function(e) { e.preventDefault() });
if (this.displayTime) {
this.$time = $('<div class="time">')
.append('<label for="_time">Time</label>')
.append('<input id="_time" type="text" />')
.click(function(e) { e.stopPropagation(); });
this.$picker.append(this.$time);
}
this.$el
.focus(this.show)
.click(this.show)
.change($.proxy(function() { this.selectDate(); }, this));
this.selectDate();
this.hide();
}
, nav: function( c, months ) {
var $subnav = $('<div>' +
'<span class="prev button">&larr;</span>' +
'<span class="name"></span>' +
'<span class="next button">&rarr;</span>' +
'</div>').addClass(c)
$('.prev', $subnav).click($.proxy(function() { this.ahead(-months, 0) }, this));
$('.next', $subnav).click($.proxy(function() { this.ahead(months, 0) }, this));
return $subnav;
}
, updateName: function($area, s) {
// Update either the month or year field, with a background flash
// animation.
var cur = $area.find('.fg').text(),
$fg = $('<div>').addClass('fg').append(s);
$area.empty();
if(cur != s) {
var $bg = $('<div>').addClass('bg');
$area.append($bg, $fg);
$bg.fadeOut('slow', function() {
$(this).remove();
});
} else {
$area.append($fg);
}
}
, selectMonth: function(date) {
this.displayedDate = date;
var newMonth = new Date(date.getFullYear(), date.getMonth(), 1);
if (!this.curMonth || !(this.curMonth.getFullYear() == newMonth.getFullYear() &&
this.curMonth.getMonth() == newMonth.getMonth())) {
this.curMonth = newMonth;
var rangeStart = this.rangeStart(date), rangeEnd = this.rangeEnd(date);
var num_days = this.daysBetween(rangeStart, rangeEnd);
this.$days.empty();
for (var ii = 0; ii <= num_days; ii++) {
var thisDay = new Date(rangeStart.getFullYear(), rangeStart.getMonth(), rangeStart.getDate() + ii, 12, 00);
var $day = $('<div>').attr('date', this.format(thisDay));
$day.text(thisDay.getDate());
if (thisDay.getMonth() != date.getMonth()) {
$day.addClass('overlap');
};
this.$days.append($day);
};
this.updateName(this.$month, this.monthNames[date.getMonth()]);
this.updateName(this.$year, this.curMonth.getFullYear());
$('div', this.$days).click($.proxy(function(e) {
var $targ = $(e.target);
// The date= attribute is used here to provide relatively fast
// selectors for setting certain date cells.
this.update($targ.attr("date"));
// Don't consider this selection final if we're just going to an
// adjacent month.
if(!$targ.hasClass('overlap')) {
this.hide();
}
}, this));
$("[date='" + this.format(new Date()) + "']", this.$days).addClass('today');
};
$('.selected', this.$days).removeClass('selected');
$('[date="' + this.selectedDateStr + '"]', this.$days).addClass('selected');
}
, selectDate: function(date) {
if (typeof(date) == "undefined") {
date = this.parse(this.$el.val());
};
if (!date) {
date = new Date();
if (this.displayTime) {
date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
}
this.selectedDate = date;
this.displayedDate = date;
this.selectedDateStr = this.format(this.selectedDate);
this.selectMonth(this.selectedDate);
if (this.displayTime) {
$('input', this.$time).val(this.formatTime(date));
}
}
, update: function(s) {
if (this.displayTime)
s = s + ' ' + this.getTimeString()
this.$el.val(s).change();
}
, show: function(e) {
e && e.stopPropagation();
// Hide all other datepickers.
clearDatePickers(this);
this.selectDate();
var offset = this.$el.offset();
this.$picker.css({
top: offset.top + this.$el.outerHeight() + 2,
left: offset.left
}).show();
$('html').on('keydown', this.keyHandler);
}
, hide: function() {
this.$picker.hide();
$('html').off('keydown', this.keyHandler);
}
, keyHandler: function(e) {
// Keyboard navigation shortcuts.
switch (e.keyCode)
{
case 9:
case 27:
// Tab or escape hides the datepicker. In this case, just return
// instead of breaking, so that the e doesn't get stopped.
this.hide(); return;
case 13:
// Enter selects the currently highlighted date.
this.update(this.selectedDateStr); this.hide(); break;
default:
return;
}
e.preventDefault();
}
, getTimeString: function(s) {
var time = $('input', this.$time).val();
return this.getTime(time);
}
, pad: function(s) {
if (s.length === 1)
s = '0' + s;
return s;
}
, parse: function(s) {
// Parse a partial RFC 3339 string into a Date.
var m;
if ((m = s.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2})$/))) {
return new Date(m[1], m[2] - 1, m[3]);
} else {
return null;
}
}
, parseDateTime: function(s) {
// Parse a partial RFC 3339 string into a Date.
var m;
if ((m = s.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2}) (\d{2,2}):(\d{2,2}):(\d{2,2})$/))) {
return new Date(m[1], m[2] - 1, m[3], m[4], m[5], m[6]);
} else {
return null;
}
}
, validateTime: function(s) {
return s.match(/^(\d{2,2}):(\d{2,2}):(\d{2,2})$/);
}
, getTime: function(s) {
if (this.validateTime(s)) {
return s;
} else {
// Time without seconds
if (s.match(/^(\d{2,2}):(\d{2,2})$/)) {
return s + ':00';
}
}
return '00:00:00';
}
, format: function(date) {
// Format a Date into a string as specified by RFC 3339.
var month = this.pad((date.getMonth() + 1).toString()),
dom = this.pad(date.getDate().toString());
return date.getFullYear() + '-' + month + "-" + dom;
}
, formatTime: function(date) {
var hour = this.pad(date.getHours().toString()),
min = this.pad(date.getMinutes().toString()),
sec = this.pad(date.getSeconds().toString());
return hour + ':' + min + ':' + sec;
}
, ahead: function(months, days) {
// Move ahead ``months`` months and ``days`` days, both integers, can be
// negative.
this.selectMonth(new Date(this.displayedDate.getFullYear(),
this.displayedDate.getMonth() + months,
this.displayedDate.getDate() + days));
}
, proxy: function(meth) {
// Bind a method so that it always gets the datepicker instance for
// ``this``. Return ``this`` so chaining calls works.
this[meth] = $.proxy(this[meth], this);
return this;
}
, daysBetween: function(start, end) {
// Return number of days between ``start`` Date object and ``end``.
var start = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
var end = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate());
return (end - start) / 86400000;
}
, findClosest: function(dow, date, direction) {
// From a starting date, find the first day ahead of behind it that is
// a given day of the week.
var difference = direction * (Math.abs(date.getDay() - dow - (direction * 7)) % 7);
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + difference);
}
, rangeStart: function(date) {
// Get the first day to show in the current calendar view.
return this.findClosest(this.startOfWeek,
new Date(date.getFullYear(), date.getMonth()),
-1);
}
, rangeEnd: function(date) {
// Get the last day to show in the current calendar view.
return this.findClosest((this.startOfWeek - 1) % 7,
new Date(date.getFullYear(), date.getMonth() + 1, 0),
1);
}
};
/* DATEPICKER PLUGIN DEFINITION
* ============================ */
$.fn.datepicker = function( options ) {
return this.each(function() { new DatePicker(this, options); });
};
$(function() {
$('html').click(clearDatePickers);
});
$.fn.datepicker.DatePicker = DatePicker;
$.fn.datepicker.defaults = {
monthNames: ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"]
, shortDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
, startOfWeek: 1
, displayTime: false
};
}( window.jQuery || window.ender );
/*!
* Datepicker for Bootstrap
*
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-datetimepicker-widget{top:0;left:0;width:250px;padding:4px;margin-top:1px;z-index:3000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:6px}.bootstrap-datetimepicker-widget:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:7px}.bootstrap-datetimepicker-widget.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget>ul{list-style-type:none;margin:0}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:100%;font-weight:bold;font-size:1.2em}.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator{width:4px;padding:0;margin:0}.bootstrap-datetimepicker-widget .datepicker>div{display:none}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#999}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{color:#fff;background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget td.active:hover,.bootstrap-datetimepicker-widget td.active:hover:hover,.bootstrap-datetimepicker-widget td.active:active,.bootstrap-datetimepicker-widget td.active:hover:active,.bootstrap-datetimepicker-widget td.active.active,.bootstrap-datetimepicker-widget td.active:hover.active,.bootstrap-datetimepicker-widget td.active.disabled,.bootstrap-datetimepicker-widget td.active:hover.disabled,.bootstrap-datetimepicker-widget td.active[disabled],.bootstrap-datetimepicker-widget td.active:hover[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.bootstrap-datetimepicker-widget td.active:active,.bootstrap-datetimepicker-widget td.active:hover:active,.bootstrap-datetimepicker-widget td.active.active,.bootstrap-datetimepicker-widget td.active:hover.active{background-color:#039 \9}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:block;width:47px;height:54px;line-height:54px;float:left;margin:2px;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{color:#fff;background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget td span.active:hover,.bootstrap-datetimepicker-widget td span.active:active,.bootstrap-datetimepicker-widget td span.active.active,.bootstrap-datetimepicker-widget td span.active.disabled,.bootstrap-datetimepicker-widget td span.active[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.bootstrap-datetimepicker-widget td span.active:active,.bootstrap-datetimepicker-widget td span.active.active{background-color:#039 \9}.bootstrap-datetimepicker-widget td span.old{color:#999}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget th.switch{width:145px}.bootstrap-datetimepicker-widget th.next,.bootstrap-datetimepicker-widget th.prev{font-size:21px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.input-append.date .add-on i,.input-prepend.date .add-on i{display:block;cursor:pointer;width:16px;height:16px}.bootstrap-datetimepicker-widget.left-oriented:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.left-oriented:after{left:auto;right:7px}
/**
* @license
* =========================================================
* bootstrap-datetimepicker.js
* http://www.eyecon.ro/bootstrap-datepicker
* =========================================================
* Copyright 2012 Stefan Petre
*
* Contributions:
* - Andrew Rowls
* - Thiago de Arruda
*
* 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($) {
// Picker object
var smartPhone = (window.orientation != undefined);
var DateTimePicker = function(element, options) {
this.id = dpgId++;
this.init(element, options);
};
var dateToDate = function(dt) {
if (typeof dt === 'string') {
return new Date(dt);
}
return dt;
};
DateTimePicker.prototype = {
constructor: DateTimePicker,
init: function(element, options) {
var icon;
if (!(options.pickTime || options.pickDate))
throw new Error('Must choose at least one picker');
this.options = options;
this.$element = $(element);
this.language = options.language in dates ? options.language : 'en'
this.pickDate = options.pickDate;
this.pickTime = options.pickTime;
this.isInput = this.$element.is('input');
this.component = false;
if (this.$element.find('.input-append').length || this.$element.find('.input-prepend').length)
this.component = this.$element.find('.add-on');
this.format = options.format;
if (!this.format) {
if (this.isInput) this.format = this.$element.data('format');
else this.format = this.$element.find('input').data('format');
if (!this.format) this.format = 'MM/dd/yyyy';
}
this._compileFormat();
if (this.component) {
icon = this.component.find('i');
}
if (this.pickTime) {
if (icon && icon.length) this.timeIcon = icon.data('time-icon');
if (!this.timeIcon) this.timeIcon = 'icon-time';
icon && icon.addClass(this.timeIcon);
}
if (this.pickDate) {
if (icon && icon.length) this.dateIcon = icon.data('date-icon');
if (!this.dateIcon) this.dateIcon = 'icon-calendar';
icon && icon.removeClass(this.timeIcon);
icon && icon.addClass(this.dateIcon);
}
this.widget = $(getTemplate(this.timeIcon, options.pickDate, options.pickTime, options.pick12HourFormat, options.pickSeconds, options.collapse)).appendTo('body');
this.minViewMode = options.minViewMode||this.$element.data('date-minviewmode')||0;
if (typeof this.minViewMode === 'string') {
switch (this.minViewMode) {
case 'months':
this.minViewMode = 1;
break;
case 'years':
this.minViewMode = 2;
break;
default:
this.minViewMode = 0;
break;
}
}
this.viewMode = options.viewMode||this.$element.data('date-viewmode')||0;
if (typeof this.viewMode === 'string') {
switch (this.viewMode) {
case 'months':
this.viewMode = 1;
break;
case 'years':
this.viewMode = 2;
break;
default:
this.viewMode = 0;
break;
}
}
this.startViewMode = this.viewMode;
this.weekStart = options.weekStart||this.$element.data('date-weekstart')||0;
this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
this.setStartDate(options.startDate || this.$element.data('date-startdate'));
this.setEndDate(options.endDate || this.$element.data('date-enddate'));
this.fillDow();
this.fillMonths();
this.fillHours();
this.fillMinutes();
this.fillSeconds();
this.update();
this.showMode();
this._attachDatePickerEvents();
},
show: function(e) {
this.widget.show();
this.height = this.component ? this.component.outerHeight() : this.$element.outerHeight();
this.place();
this.$element.trigger({
type: 'show',
date: this._date
});
this._attachDatePickerGlobalEvents();
if (e) {
e.stopPropagation();
e.preventDefault();
}
},
disable: function(){
this.$element.find('input').prop('disabled',true);
this._detachDatePickerEvents();
},
enable: function(){
this.$element.find('input').prop('disabled',false);
this._attachDatePickerEvents();
},
hide: function() {
// Ignore event if in the middle of a picker transition
var collapse = this.widget.find('.collapse')
for (var i = 0; i < collapse.length; i++) {
var collapseData = collapse.eq(i).data('collapse');
if (collapseData && collapseData.transitioning)
return;
}
this.widget.hide();
this.viewMode = this.startViewMode;
this.showMode();
this.set();
this.$element.trigger({
type: 'hide',
date: this._date
});
this._detachDatePickerGlobalEvents();
},
set: function() {
var formatted = '';
if (!this._unset) formatted = this.formatDate(this._date);
if (!this.isInput) {
var input = this.$element.find('input');
input.val(formatted);
this._resetMaskPos(input);
this.$element.data('date', formatted);
} else {
this.$element.val(formatted);
this._resetMaskPos(this.$element);
}
},
setValue: function(newDate) {
if (!newDate) {
this._unset = true;
} else {
this._unset = false;
}
if (typeof newDate === 'string') {
this._date = this.parseDate(newDate);
} else if(newDate) {
this._date = new Date(newDate);
}
this.set();
this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0);
this.fillDate();
this.fillTime();
},
getDate: function() {
if (this._unset) return null;
return new Date(this._date.valueOf());
},
setDate: function(date) {
if (!date) this.setValue(null);
else this.setValue(date.valueOf());
},
setStartDate: function(date) {
if (date instanceof Date) {
this.startDate = date;
} else if (typeof date === 'string') {
this.startDate = new UTCDate(date);
if (! this.startDate.getUTCFullYear()) {
this.startDate = -Infinity;
}
} else {
this.startDate = -Infinity;
}
if (this.viewDate) {
this.update();
}
},
setEndDate: function(date) {
if (date instanceof Date) {
this.endDate = date;
} else if (typeof date === 'string') {
this.endDate = new UTCDate(date);
if (! this.endDate.getUTCFullYear()) {
this.endDate = Infinity;
}
} else {
this.endDate = Infinity;
}
if (this.viewDate) {
this.update();
}
},
getLocalDate: function() {
if (this._unset) return null;
var d = this._date;
return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(),
d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
},
setLocalDate: function(localDate) {
if (!localDate) this.setValue(null);
else
this.setValue(Date.UTC(
localDate.getFullYear(),
localDate.getMonth(),
localDate.getDate(),
localDate.getHours(),
localDate.getMinutes(),
localDate.getSeconds(),
localDate.getMilliseconds()));
},
place: function(){
var position = 'absolute';
var offset = this.component ? this.component.offset() : this.$element.offset();
this.width = this.component ? this.component.outerWidth() : this.$element.outerWidth();
offset.top = offset.top + this.height;
var $window = $(window);
if ( this.options.width != undefined ) {
this.widget.width( this.options.width );
}
if ( this.options.orientation == 'left' ) {
this.widget.addClass( 'left-oriented' );
offset.left = offset.left - this.widget.width() + 20;
}
if (this._isInFixed()) {
position = 'fixed';
offset.top -= $window.scrollTop();
offset.left -= $window.scrollLeft();
}
if ($window.width() < offset.left + this.widget.outerWidth()) {
offset.right = $window.width() - offset.left - this.width;
offset.left = 'auto';
this.widget.addClass('pull-right');
} else {
offset.right = 'auto';
this.widget.removeClass('pull-right');
}
this.widget.css({
position: position,
top: offset.top,
left: offset.left,
right: offset.right
});
},
notifyChange: function(){
this.$element.trigger({
type: 'changeDate',
date: this.getDate(),
localDate: this.getLocalDate()
});
},
update: function(newDate){
var dateStr = newDate;
if (!dateStr) {
if (this.isInput) {
dateStr = this.$element.val();
} else {
dateStr = this.$element.find('input').val();
}
if (dateStr) {
this._date = this.parseDate(dateStr);
}
if (!this._date) {
var tmp = new Date()
this._date = UTCDate(tmp.getFullYear(),
tmp.getMonth(),
tmp.getDate(),
tmp.getHours(),
tmp.getMinutes(),
tmp.getSeconds(),
tmp.getMilliseconds())
}
}
this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0);
this.fillDate();
this.fillTime();
},
fillDow: function() {
var dowCnt = this.weekStart;
var html = $('<tr>');
while (dowCnt < this.weekStart + 7) {
html.append('<th class="dow">' + dates[this.language].daysMin[(dowCnt++) % 7] + '</th>');
}
this.widget.find('.datepicker-days thead').append(html);
},
fillMonths: function() {
var html = '';
var i = 0
while (i < 12) {
html += '<span class="month">' + dates[this.language].monthsShort[i++] + '</span>';
}
this.widget.find('.datepicker-months td').append(html);
},
fillDate: function() {
var year = this.viewDate.getUTCFullYear();
var month = this.viewDate.getUTCMonth();
var currentDate = UTCDate(
this._date.getUTCFullYear(),
this._date.getUTCMonth(),
this._date.getUTCDate(),
0, 0, 0, 0
);
var startYear = typeof this.startDate === 'object' ? this.startDate.getUTCFullYear() : -Infinity;
var startMonth = typeof this.startDate === 'object' ? this.startDate.getUTCMonth() : -1;
var endYear = typeof this.endDate === 'object' ? this.endDate.getUTCFullYear() : Infinity;
var endMonth = typeof this.endDate === 'object' ? this.endDate.getUTCMonth() : 12;
this.widget.find('.datepicker-days').find('.disabled').removeClass('disabled');
this.widget.find('.datepicker-months').find('.disabled').removeClass('disabled');
this.widget.find('.datepicker-years').find('.disabled').removeClass('disabled');
this.widget.find('.datepicker-days th:eq(1)').text(
dates[this.language].months[month] + ' ' + year);
var prevMonth = UTCDate(year, month-1, 28, 0, 0, 0, 0);
var day = DPGlobal.getDaysInMonth(
prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
prevMonth.setUTCDate(day);
prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7);
if ((year == startYear && month <= startMonth) || year < startYear) {
this.widget.find('.datepicker-days th:eq(0)').addClass('disabled');
}
if ((year == endYear && month >= endMonth) || year > endYear) {
this.widget.find('.datepicker-days th:eq(2)').addClass('disabled');
}
var nextMonth = new Date(prevMonth.valueOf());
nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
nextMonth = nextMonth.valueOf();
var html = [];
var row;
var clsName;
while (prevMonth.valueOf() < nextMonth) {
if (prevMonth.getUTCDay() === this.weekStart) {
row = $('<tr>');
html.push(row);
}
clsName = '';
if (prevMonth.getUTCFullYear() < year ||
(prevMonth.getUTCFullYear() == year &&
prevMonth.getUTCMonth() < month)) {
clsName += ' old';
} else if (prevMonth.getUTCFullYear() > year ||
(prevMonth.getUTCFullYear() == year &&
prevMonth.getUTCMonth() > month)) {
clsName += ' new';
}
if (prevMonth.valueOf() === currentDate.valueOf()) {
clsName += ' active';
}
if ((prevMonth.valueOf() + 86400000) <= this.startDate) {
clsName += ' disabled';
}
if (prevMonth.valueOf() > this.endDate) {
clsName += ' disabled';
}
row.append('<td class="day' + clsName + '">' + prevMonth.getUTCDate() + '</td>');
prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
}
this.widget.find('.datepicker-days tbody').empty().append(html);
var currentYear = this._date.getUTCFullYear();
var months = this.widget.find('.datepicker-months').find(
'th:eq(1)').text(year).end().find('span').removeClass('active');
if (currentYear === year) {
months.eq(this._date.getUTCMonth()).addClass('active');
}
if (currentYear - 1 < startYear) {
this.widget.find('.datepicker-months th:eq(0)').addClass('disabled');
}
if (currentYear + 1 > endYear) {
this.widget.find('.datepicker-months th:eq(2)').addClass('disabled');
}
for (var i = 0; i < 12; i++) {
if ((year == startYear && startMonth > i) || (year < startYear)) {
$(months[i]).addClass('disabled');
} else if ((year == endYear && endMonth < i) || (year > endYear)) {
$(months[i]).addClass('disabled');
}
}
html = '';
year = parseInt(year/10, 10) * 10;
var yearCont = this.widget.find('.datepicker-years').find(
'th:eq(1)').text(year + '-' + (year + 9)).end().find('td');
this.widget.find('.datepicker-years').find('th').removeClass('disabled');
if (startYear > year) {
this.widget.find('.datepicker-years').find('th:eq(0)').addClass('disabled');
}
if (endYear < year+9) {
this.widget.find('.datepicker-years').find('th:eq(2)').addClass('disabled');
}
year -= 1;
for (var i = -1; i < 11; i++) {
html += '<span class="year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + ((year < startYear || year > endYear) ? ' disabled' : '') + '">' + year + '</span>';
year += 1;
}
yearCont.html(html);
},
fillHours: function() {
var table = this.widget.find(
'.timepicker .timepicker-hours table');
table.parent().hide();
var html = '';
if (this.options.pick12HourFormat) {
var current = 1;
for (var i = 0; i < 3; i += 1) {
html += '<tr>';
for (var j = 0; j < 4; j += 1) {
var c = current.toString();
html += '<td class="hour">' + padLeft(c, 2, '0') + '</td>';
current++;
}
html += '</tr>'
}
} else {
var current = 0;
for (var i = 0; i < 6; i += 1) {
html += '<tr>';
for (var j = 0; j < 4; j += 1) {
var c = current.toString();
html += '<td class="hour">' + padLeft(c, 2, '0') + '</td>';
current++;
}
html += '</tr>'
}
}
table.html(html);
},
fillMinutes: function() {
var table = this.widget.find(
'.timepicker .timepicker-minutes table');
table.parent().hide();
var html = '';
var current = 0;
for (var i = 0; i < 5; i++) {
html += '<tr>';
for (var j = 0; j < 4; j += 1) {
var c = current.toString();
html += '<td class="minute">' + padLeft(c, 2, '0') + '</td>';
current += 3;
}
html += '</tr>';
}
table.html(html);
},
fillSeconds: function() {
var table = this.widget.find(
'.timepicker .timepicker-seconds table');
table.parent().hide();
var html = '';
var current = 0;
for (var i = 0; i < 5; i++) {
html += '<tr>';
for (var j = 0; j < 4; j += 1) {
var c = current.toString();
html += '<td class="second">' + padLeft(c, 2, '0') + '</td>';
current += 3;
}
html += '</tr>';
}
table.html(html);
},
fillTime: function() {
if (!this._date)
return;
var timeComponents = this.widget.find('.timepicker span[data-time-component]');
var table = timeComponents.closest('table');
var is12HourFormat = this.options.pick12HourFormat;
var hour = this._date.getUTCHours();
var period = 'AM';
if (is12HourFormat) {
if (hour >= 12) period = 'PM';
if (hour === 0) hour = 12;
else if (hour != 12) hour = hour % 12;
this.widget.find(
'.timepicker [data-action=togglePeriod]').text(period);
}
hour = padLeft(hour.toString(), 2, '0');
var minute = padLeft(this._date.getUTCMinutes().toString(), 2, '0');
var second = padLeft(this._date.getUTCSeconds().toString(), 2, '0');
timeComponents.filter('[data-time-component=hours]').text(hour);
timeComponents.filter('[data-time-component=minutes]').text(minute);
timeComponents.filter('[data-time-component=seconds]').text(second);
},
click: function(e) {
e.stopPropagation();
e.preventDefault();
this._unset = false;
var target = $(e.target).closest('span, td, th');
if (target.length === 1) {
if (! target.is('.disabled')) {
switch(target[0].nodeName.toLowerCase()) {
case 'th':
switch(target[0].className) {
case 'switch':
this.showMode(1);
break;
case 'prev':
case 'next':
var vd = this.viewDate;
var navFnc = DPGlobal.modes[this.viewMode].navFnc;
var step = DPGlobal.modes[this.viewMode].navStep;
if (target[0].className === 'prev') step = step * -1;
vd['set' + navFnc](vd['get' + navFnc]() + step);
this.fillDate();
this.set();
break;
}
break;
case 'span':
if (target.is('.month')) {
var month = target.parent().find('span').index(target);
this.viewDate.setUTCMonth(month);
} else {
var year = parseInt(target.text(), 10) || 0;
this.viewDate.setUTCFullYear(year);
}
if (this.viewMode !== 0) {
this._date = UTCDate(
this.viewDate.getUTCFullYear(),
this.viewDate.getUTCMonth(),
this.viewDate.getUTCDate(),
this._date.getUTCHours(),
this._date.getUTCMinutes(),
this._date.getUTCSeconds(),
this._date.getUTCMilliseconds()
);
this.notifyChange();
}
this.showMode(-1);
this.fillDate();
this.set();
break;
case 'td':
if (target.is('.day')) {
var day = parseInt(target.text(), 10) || 1;
var month = this.viewDate.getUTCMonth();
var year = this.viewDate.getUTCFullYear();
if (target.is('.old')) {
if (month === 0) {
month = 11;
year -= 1;
} else {
month -= 1;
}
} else if (target.is('.new')) {
if (month == 11) {
month = 0;
year += 1;
} else {
month += 1;
}
}
this._date = UTCDate(
year, month, day,
this._date.getUTCHours(),
this._date.getUTCMinutes(),
this._date.getUTCSeconds(),
this._date.getUTCMilliseconds()
);
this.viewDate = UTCDate(
year, month, Math.min(28, day) , 0, 0, 0, 0);
this.fillDate();
this.set();
this.notifyChange();
}
break;
}
}
}
},
actions: {
incrementHours: function(e) {
this._date.setUTCHours(this._date.getUTCHours() + 1);
},
incrementMinutes: function(e) {
this._date.setUTCMinutes(this._date.getUTCMinutes() + 1);
},
incrementSeconds: function(e) {
this._date.setUTCSeconds(this._date.getUTCSeconds() + 1);
},
decrementHours: function(e) {
this._date.setUTCHours(this._date.getUTCHours() - 1);
},
decrementMinutes: function(e) {
this._date.setUTCMinutes(this._date.getUTCMinutes() - 1);
},
decrementSeconds: function(e) {
this._date.setUTCSeconds(this._date.getUTCSeconds() - 1);
},
togglePeriod: function(e) {
var hour = this._date.getUTCHours();
if (hour >= 12) hour -= 12;
else hour += 12;
this._date.setUTCHours(hour);
},
showPicker: function() {
this.widget.find('.timepicker > div:not(.timepicker-picker)').hide();
this.widget.find('.timepicker .timepicker-picker').show();
},
showHours: function() {
this.widget.find('.timepicker .timepicker-picker').hide();
this.widget.find('.timepicker .timepicker-hours').show();
},
showMinutes: function() {
this.widget.find('.timepicker .timepicker-picker').hide();
this.widget.find('.timepicker .timepicker-minutes').show();
},
showSeconds: function() {
this.widget.find('.timepicker .timepicker-picker').hide();
this.widget.find('.timepicker .timepicker-seconds').show();
},
selectHour: function(e) {
var tgt = $(e.target);
var value = parseInt(tgt.text(), 10);
if (this.options.pick12HourFormat) {
var current = this._date.getUTCHours();
if (current >= 12) {
if (value != 12) value = (value + 12) % 24;
} else {
if (value === 12) value = 0;
else value = value % 12;
}
}
this._date.setUTCHours(value);
this.actions.showPicker.call(this);
},
selectMinute: function(e) {
var tgt = $(e.target);
var value = parseInt(tgt.text(), 10);
this._date.setUTCMinutes(value);
this.actions.showPicker.call(this);
},
selectSecond: function(e) {
var tgt = $(e.target);
var value = parseInt(tgt.text(), 10);
this._date.setUTCSeconds(value);
this.actions.showPicker.call(this);
}
},
doAction: function(e) {
e.stopPropagation();
e.preventDefault();
if (!this._date) this._date = UTCDate(1970, 0, 0, 0, 0, 0, 0);
var action = $(e.currentTarget).data('action');
var rv = this.actions[action].apply(this, arguments);
this.set();
this.fillTime();
this.notifyChange();
return rv;
},
stopEvent: function(e) {
e.stopPropagation();
e.preventDefault();
},
// part of the following code was taken from
// http://cloud.github.com/downloads/digitalBush/jquery.maskedinput/jquery.maskedinput-1.3.js
keydown: function(e) {
var self = this, k = e.which, input = $(e.target);
if (k == 8 || k == 46) {
// backspace and delete cause the maskPosition
// to be recalculated
setTimeout(function() {
self._resetMaskPos(input);
});
}
},
keypress: function(e) {
var k = e.which;
if (k == 8 || k == 46) {
// For those browsers which will trigger
// keypress on backspace/delete
return;
}
var input = $(e.target);
var c = String.fromCharCode(k);
var val = input.val() || '';
val += c;
var mask = this._mask[this._maskPos];
if (!mask) {
return false;
}
if (mask.end != val.length) {
return;
}
if (!mask.pattern.test(val.slice(mask.start))) {
val = val.slice(0, val.length - 1);
while ((mask = this._mask[this._maskPos]) && mask.character) {
val += mask.character;
// advance mask position past static
// part
this._maskPos++;
}
val += c;
if (mask.end != val.length) {
input.val(val);
return false;
} else {
if (!mask.pattern.test(val.slice(mask.start))) {
input.val(val.slice(0, mask.start));
return false;
} else {
input.val(val);
this._maskPos++;
return false;
}
}
} else {
this._maskPos++;
}
},
change: function(e) {
var input = $(e.target);
var val = input.val();
if (this._formatPattern.test(val)) {
this.update();
this.setValue(this._date.getTime());
this.notifyChange();
this.set();
} else if (val && val.trim()) {
this.setValue(this._date.getTime());
if (this._date) this.set();
else input.val('');
} else {
if (this._date) {
this.setValue(null);
// unset the date when the input is
// erased
this.notifyChange();
this._unset = true;
}
}
this._resetMaskPos(input);
},
showMode: function(dir) {
if (dir) {
this.viewMode = Math.max(this.minViewMode, Math.min(
2, this.viewMode + dir));
}
this.widget.find('.datepicker > div').hide().filter(
'.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
},
destroy: function() {
this._detachDatePickerEvents();
this._detachDatePickerGlobalEvents();
this.widget.remove();
this.$element.removeData('datetimepicker');
this.component && this.component.removeData('datetimepicker');
},
formatDate: function(d) {
return this.format.replace(formatReplacer, function(match) {
var methodName, property, rv, len = match.length;
if (match === 'ms')
len = 1;
property = dateFormatComponents[match].property
if (property === 'Hours12') {
rv = d.getUTCHours();
if (rv === 0) rv = 12;
else if (rv !== 12) rv = rv % 12;
} else if (property === 'Period12') {
if (d.getUTCHours() >= 12) return 'PM';
else return 'AM';
} else {
methodName = 'get' + property;
rv = d[methodName]();
}
if (methodName === 'getUTCMonth') rv = rv + 1;
if (methodName === 'getUTCYear') rv = rv + 1900 - 2000;
return padLeft(rv.toString(), len, '0');
});
},
parseDate: function(str) {
var match, i, property, methodName, value, parsed = {};
if (!(match = this._formatPattern.exec(str)))
return null;
for (i = 1; i < match.length; i++) {
property = this._propertiesByIndex[i];
if (!property)
continue;
value = match[i];
if (/^\d+$/.test(value))
value = parseInt(value, 10);
parsed[property] = value;
}
return this._finishParsingDate(parsed);
},
_resetMaskPos: function(input) {
var val = input.val();
for (var i = 0; i < this._mask.length; i++) {
if (this._mask[i].end > val.length) {
// If the mask has ended then jump to
// the next
this._maskPos = i;
break;
} else if (this._mask[i].end === val.length) {
this._maskPos = i + 1;
break;
}
}
},
_finishParsingDate: function(parsed) {
var year, month, date, hours, minutes, seconds, milliseconds;
year = parsed.UTCFullYear;
if (parsed.UTCYear) year = 2000 + parsed.UTCYear;
if (!year) year = 1970;
if (parsed.UTCMonth) month = parsed.UTCMonth - 1;
else month = 0;
date = parsed.UTCDate || 1;
hours = parsed.UTCHours || 0;
minutes = parsed.UTCMinutes || 0;
seconds = parsed.UTCSeconds || 0;
milliseconds = parsed.UTCMilliseconds || 0;
if (parsed.Hours12) {
hours = parsed.Hours12;
}
if (parsed.Period12) {
if (/pm/i.test(parsed.Period12)) {
if (hours != 12) hours = (hours + 12) % 24;
} else {
hours = hours % 12;
}
}
return UTCDate(year, month, date, hours, minutes, seconds, milliseconds);
},
_compileFormat: function () {
var match, component, components = [], mask = [],
str = this.format, propertiesByIndex = {}, i = 0, pos = 0;
while (match = formatComponent.exec(str)) {
component = match[0];
if (component in dateFormatComponents) {
i++;
propertiesByIndex[i] = dateFormatComponents[component].property;
components.push('\\s*' + dateFormatComponents[component].getPattern(
this) + '\\s*');
mask.push({
pattern: new RegExp(dateFormatComponents[component].getPattern(
this)),
property: dateFormatComponents[component].property,
start: pos,
end: pos += component.length
});
}
else {
components.push(escapeRegExp(component));
mask.push({
pattern: new RegExp(escapeRegExp(component)),
character: component,
start: pos,
end: ++pos
});
}
str = str.slice(component.length);
}
this._mask = mask;
this._maskPos = 0;
this._formatPattern = new RegExp(
'^\\s*' + components.join('') + '\\s*$');
this._propertiesByIndex = propertiesByIndex;
},
_attachDatePickerEvents: function() {
var self = this;
// this handles date picker clicks
this.widget.on('click', '.datepicker *', $.proxy(this.click, this));
// this handles time picker clicks
this.widget.on('click', '[data-action]', $.proxy(this.doAction, this));
this.widget.on('mousedown', $.proxy(this.stopEvent, this));
if (this.pickDate && this.pickTime) {
this.widget.on('click.togglePicker', '.accordion-toggle', function(e) {
e.stopPropagation();
var $this = $(this);
var $parent = $this.closest('ul');
var expanded = $parent.find('.collapse.in');
var closed = $parent.find('.collapse:not(.in)');
if (expanded && expanded.length) {
var collapseData = expanded.data('collapse');
if (collapseData && collapseData.transitioning) return;
expanded.collapse('hide');
closed.collapse('show')
$this.find('i').toggleClass(self.timeIcon + ' ' + self.dateIcon);
self.$element.find('.add-on i').toggleClass(self.timeIcon + ' ' + self.dateIcon);
}
});
}
if (this.isInput) {
this.$element.on({
'focus': $.proxy(this.show, this),
'change': $.proxy(this.change, this)
});
if (this.options.maskInput) {
this.$element.on({
'keydown': $.proxy(this.keydown, this),
'keypress': $.proxy(this.keypress, this)
});
}
} else {
this.$element.on({
'change': $.proxy(this.change, this)
}, 'input');
if (this.options.maskInput) {
this.$element.on({
'keydown': $.proxy(this.keydown, this),
'keypress': $.proxy(this.keypress, this)
}, 'input');
}
if (this.component){
this.component.on('click', $.proxy(this.show, this));
} else {
this.$element.on('click', $.proxy(this.show, this));
}
}
},
_attachDatePickerGlobalEvents: function() {
$(window).on(
'resize.datetimepicker' + this.id, $.proxy(this.place, this));
$(document).on(
'mousedown.datetimepicker' + this.id, $.proxy(this.hide, this));
},
_detachDatePickerEvents: function() {
this.widget.off('click', '.datepicker *', this.click);
this.widget.off('click', '[data-action]');
this.widget.off('mousedown', this.stopEvent);
if (this.pickDate && this.pickTime) {
this.widget.off('click.togglePicker');
}
if (this.isInput) {
this.$element.off({
'focus': this.show,
'change': this.change
});
if (this.options.maskInput) {
this.$element.off({
'keydown': this.keydown,
'keypress': this.keypress
});
}
} else {
this.$element.off({
'change': this.change
}, 'input');
if (this.options.maskInput) {
this.$element.off({
'keydown': this.keydown,
'keypress': this.keypress
}, 'input');
}
if (this.component){
this.component.off('click', this.show);
} else {
this.$element.off('click', this.show);
}
}
},
_detachDatePickerGlobalEvents: function () {
$(window).off('resize.datetimepicker' + this.id);
if (!this.isInput) {
$(document).off('mousedown.datetimepicker' + this.id);
}
},
_isInFixed: function() {
if (this.$element) {
var parents = this.$element.parents();
var inFixed = false;
for (var i=0; i<parents.length; i++) {
if ($(parents[i]).css('position') == 'fixed') {
inFixed = true;
break;
}
};
return inFixed;
} else {
return false;
}
}
};
$.fn.datetimepicker = function ( option, val ) {
return this.each(function () {
var $this = $(this),
data = $this.data('datetimepicker'),
options = typeof option === 'object' && option;
if (!data) {
$this.data('datetimepicker', (data = new DateTimePicker(
this, $.extend({}, $.fn.datetimepicker.defaults,options))));
}
if (typeof option === 'string') data[option](val);
});
};
$.fn.datetimepicker.defaults = {
maskInput: false,
pickDate: true,
pickTime: true,
pick12HourFormat: false,
pickSeconds: true,
startDate: -Infinity,
endDate: Infinity,
collapse: true
};
$.fn.datetimepicker.Constructor = DateTimePicker;
var dpgId = 0;
var dates = $.fn.datetimepicker.dates = {
en: {
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"],
daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
months: ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"],
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"]
}
};
var dateFormatComponents = {
dd: {property: 'UTCDate', getPattern: function() { return '(0?[1-9]|[1-2][0-9]|3[0-1])\\b';}},
MM: {property: 'UTCMonth', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}},
yy: {property: 'UTCYear', getPattern: function() {return '(\\d{2})\\b'}},
yyyy: {property: 'UTCFullYear', getPattern: function() {return '(\\d{4})\\b';}},
hh: {property: 'UTCHours', getPattern: function() {return '(0?[0-9]|1[0-9]|2[0-3])\\b';}},
mm: {property: 'UTCMinutes', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}},
ss: {property: 'UTCSeconds', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}},
ms: {property: 'UTCMilliseconds', getPattern: function() {return '([0-9]{1,3})\\b';}},
HH: {property: 'Hours12', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}},
PP: {property: 'Period12', getPattern: function() {return '(AM|PM|am|pm|Am|aM|Pm|pM)\\b';}}
};
var keys = [];
for (var k in dateFormatComponents) keys.push(k);
keys[keys.length - 1] += '\\b';
keys.push('.');
var formatComponent = new RegExp(keys.join('\\b|'));
keys.pop();
var formatReplacer = new RegExp(keys.join('\\b|'), 'g');
function escapeRegExp(str) {
// http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function padLeft(s, l, c) {
if (l < s.length) return s;
else return Array(l - s.length + 1).join(c || ' ') + s;
}
function getTemplate(timeIcon, pickDate, pickTime, is12Hours, showSeconds, collapse) {
if (pickDate && pickTime) {
return (
'<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
'<ul>' +
'<li' + (collapse ? ' class="collapse in"' : '') + '>' +
'<div class="datepicker">' +
DPGlobal.template +
'</div>' +
'</li>' +
'<li class="picker-switch accordion-toggle"><a><i class="' + timeIcon + '"></i></a></li>' +
'<li' + (collapse ? ' class="collapse"' : '') + '>' +
'<div class="timepicker">' +
TPGlobal.getTemplate(is12Hours, showSeconds) +
'</div>' +
'</li>' +
'</ul>' +
'</div>'
);
} else if (pickTime) {
return (
'<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
'<div class="timepicker">' +
TPGlobal.getTemplate(is12Hours, showSeconds) +
'</div>' +
'</div>'
);
} else {
return (
'<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
'<div class="datepicker">' +
DPGlobal.template +
'</div>' +
'</div>'
);
}
}
function UTCDate() {
return new Date(Date.UTC.apply(Date, arguments));
}
var DPGlobal = {
modes: [
{
clsName: 'days',
navFnc: 'UTCMonth',
navStep: 1
},
{
clsName: 'months',
navFnc: 'UTCFullYear',
navStep: 1
},
{
clsName: 'years',
navFnc: 'UTCFullYear',
navStep: 10
}],
isLeapYear: function (year) {
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
},
getDaysInMonth: function (year, month) {
return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
},
headTemplate:
'<thead>' +
'<tr>' +
'<th class="prev">&lsaquo;</th>' +
'<th colspan="5" class="switch"></th>' +
'<th class="next">&rsaquo;</th>' +
'</tr>' +
'</thead>',
contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
};
DPGlobal.template =
'<div class="datepicker-days">' +
'<table class="table-condensed">' +
DPGlobal.headTemplate +
'<tbody></tbody>' +
'</table>' +
'</div>' +
'<div class="datepicker-months">' +
'<table class="table-condensed">' +
DPGlobal.headTemplate +
DPGlobal.contTemplate+
'</table>'+
'</div>'+
'<div class="datepicker-years">'+
'<table class="table-condensed">'+
DPGlobal.headTemplate+
DPGlobal.contTemplate+
'</table>'+
'</div>';
var TPGlobal = {
hourTemplate: '<span data-action="showHours" data-time-component="hours" class="timepicker-hour"></span>',
minuteTemplate: '<span data-action="showMinutes" data-time-component="minutes" class="timepicker-minute"></span>',
secondTemplate: '<span data-action="showSeconds" data-time-component="seconds" class="timepicker-second"></span>'
};
TPGlobal.getTemplate = function(is12Hours, showSeconds) {
return (
'<div class="timepicker-picker">' +
'<table class="table-condensed"' +
(is12Hours ? ' data-hour-format="12"' : '') +
'>' +
'<tr>' +
'<td><a href="#" class="btn" data-action="incrementHours"><i class="icon-chevron-up"></i></a></td>' +
'<td class="separator"></td>' +
'<td><a href="#" class="btn" data-action="incrementMinutes"><i class="icon-chevron-up"></i></a></td>' +
(showSeconds ?
'<td class="separator"></td>' +
'<td><a href="#" class="btn" data-action="incrementSeconds"><i class="icon-chevron-up"></i></a></td>': '')+
(is12Hours ? '<td class="separator"></td>' : '') +
'</tr>' +
'<tr>' +
'<td>' + TPGlobal.hourTemplate + '</td> ' +
'<td class="separator">:</td>' +
'<td>' + TPGlobal.minuteTemplate + '</td> ' +
(showSeconds ?
'<td class="separator">:</td>' +
'<td>' + TPGlobal.secondTemplate + '</td>' : '') +
(is12Hours ?
'<td class="separator"></td>' +
'<td>' +
'<button type="button" class="btn btn-primary" data-action="togglePeriod"></button>' +
'</td>' : '') +
'</tr>' +
'<tr>' +
'<td><a href="#" class="btn" data-action="decrementHours"><i class="icon-chevron-down"></i></a></td>' +
'<td class="separator"></td>' +
'<td><a href="#" class="btn" data-action="decrementMinutes"><i class="icon-chevron-down"></i></a></td>' +
(showSeconds ?
'<td class="separator"></td>' +
'<td><a href="#" class="btn" data-action="decrementSeconds"><i class="icon-chevron-down"></i></a></td>': '') +
(is12Hours ? '<td class="separator"></td>' : '') +
'</tr>' +
'</table>' +
'</div>' +
'<div class="timepicker-hours" data-action="selectHour">' +
'<table class="table-condensed">' +
'</table>'+
'</div>'+
'<div class="timepicker-minutes" data-action="selectMinute">' +
'<table class="table-condensed">' +
'</table>'+
'</div>'+
(showSeconds ?
'<div class="timepicker-seconds" data-action="selectSecond">' +
'<table class="table-condensed">' +
'</table>'+
'</div>': '')
);
}
})(window.jQuery)
// ----------------------------------------------------------------------------
// markItUp! Universal MarkUp Engine, JQuery plugin
// v 1.1.x
// Dual licensed under the MIT and GPL licenses.
// ----------------------------------------------------------------------------
// Copyright (C) 2007-2012 Jay Salvat
// http://markitup.jaysalvat.com/
// ----------------------------------------------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ----------------------------------------------------------------------------
(function($) {
$.fn.markItUp = function(settings, extraSettings) {
var method, params, options, ctrlKey, shiftKey, altKey; ctrlKey = shiftKey = altKey = false;
if (typeof settings == 'string') {
method = settings;
params = extraSettings;
}
options = { id: '',
nameSpace: '',
root: '',
previewHandler: false,
previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes'
previewInElement: '',
previewAutoRefresh: true,
previewPosition: 'after',
previewTemplatePath: '~/templates/preview.html',
previewParser: false,
previewParserPath: '',
previewParserVar: 'data',
resizeHandle: true,
beforeInsert: '',
afterInsert: '',
onEnter: {},
onShiftEnter: {},
onCtrlEnter: {},
onTab: {},
markupSet: [ { /* set */ } ]
};
$.extend(options, settings, extraSettings);
// compute markItUp! path
if (!options.root) {
$('script').each(function(a, tag) {
miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/);
if (miuScript !== null) {
options.root = miuScript[1];
}
});
}
// Quick patch to keep compatibility with jQuery 1.9
var uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
var matched = uaMatch( navigator.userAgent );
var browser = {};
if (matched.browser) {
browser[matched.browser] = true;
browser.version = matched.version;
}
if (browser.chrome) {
browser.webkit = true;
} else if (browser.webkit) {
browser.safari = true;
}
return this.each(function() {
var $$, textarea, levels, scrollPosition, caretPosition, caretOffset,
clicked, hash, header, footer, previewWindow, template, iFrame, abort;
$$ = $(this);
textarea = this;
levels = [];
abort = false;
scrollPosition = caretPosition = 0;
caretOffset = -1;
options.previewParserPath = localize(options.previewParserPath);
options.previewTemplatePath = localize(options.previewTemplatePath);
if (method) {
switch(method) {
case 'remove':
remove();
break;
case 'insert':
markup(params);
break;
default:
$.error('Method ' + method + ' does not exist on jQuery.markItUp');
}
return;
}
// apply the computed path to ~/
function localize(data, inText) {
if (inText) {
return data.replace(/("|')~\//g, "$1"+options.root);
}
return data.replace(/^~\//, options.root);
}
// init and build editor
function init() {
id = ''; nameSpace = '';
if (options.id) {
id = 'id="'+options.id+'"';
} else if ($$.attr("id")) {
id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"';
}
if (options.nameSpace) {
nameSpace = 'class="'+options.nameSpace+'"';
}
$$.wrap('<div '+nameSpace+'></div>');
$$.wrap('<div '+id+' class="markItUp"></div>');
$$.wrap('<div class="markItUpContainer"></div>');
$$.addClass("markItUpEditor");
// add the header before the textarea
header = $('<div class="markItUpHeader"></div>').insertBefore($$);
$(dropMenus(options.markupSet)).appendTo(header);
// add the footer after the textarea
footer = $('<div class="markItUpFooter"></div>').insertAfter($$);
// add the resize handle after textarea
if (options.resizeHandle === true && browser.safari !== true) {
resizeHandle = $('<div class="markItUpResizeHandle"></div>')
.insertAfter($$)
.bind("mousedown.markItUp", function(e) {
var h = $$.height(), y = e.clientY, mouseMove, mouseUp;
mouseMove = function(e) {
$$.css("height", Math.max(20, e.clientY+h-y)+"px");
return false;
};
mouseUp = function(e) {
$("html").unbind("mousemove.markItUp", mouseMove).unbind("mouseup.markItUp", mouseUp);
return false;
};
$("html").bind("mousemove.markItUp", mouseMove).bind("mouseup.markItUp", mouseUp);
});
footer.append(resizeHandle);
}
// listen key events
$$.bind('keydown.markItUp', keyPressed).bind('keyup', keyPressed);
// bind an event to catch external calls
$$.bind("insertion.markItUp", function(e, settings) {
if (settings.target !== false) {
get();
}
if (textarea === $.markItUp.focused) {
markup(settings);
}
});
// remember the last focus
$$.bind('focus.markItUp', function() {
$.markItUp.focused = this;
});
if (options.previewInElement) {
refreshPreview();
}
}
// recursively build header with dropMenus from markupset
function dropMenus(markupSet) {
var ul = $('<ul></ul>'), i = 0;
$('li:hover > ul', ul).css('display', 'block');
$.each(markupSet, function() {
var button = this, t = '', title, li, j;
title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||'');
key = (button.key) ? 'accesskey="'+button.key+'"' : '';
if (button.separator) {
li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul);
} else {
i++;
for (j = levels.length -1; j >= 0; j--) {
t += levels[j]+"-";
}
li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'">'+(button.name||'')+'</a></li>')
.bind("contextmenu.markItUp", function() { // prevent contextmenu on mac and allow ctrl+click
return false;
}).bind('click.markItUp', function(e) {
e.preventDefault();
}).bind("focusin.markItUp", function(){
$$.focus();
}).bind('mouseup', function() {
if (button.call) {
eval(button.call)();
}
setTimeout(function() { markup(button) },1);
return false;
}).bind('mouseenter.markItUp', function() {
$('> ul', this).show();
$(document).one('click', function() { // close dropmenu if click outside
$('ul ul', header).hide();
}
);
}).bind('mouseleave.markItUp', function() {
$('> ul', this).hide();
}).appendTo(ul);
if (button.dropMenu) {
levels.push(i);
$(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu));
}
}
});
levels.pop();
return ul;
}
// markItUp! markups
function magicMarkups(string) {
if (string) {
string = string.toString();
string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g,
function(x, a) {
var b = a.split('|!|');
if (altKey === true) {
return (b[1] !== undefined) ? b[1] : b[0];
} else {
return (b[1] === undefined) ? "" : b[0];
}
}
);
// [![prompt]!], [![prompt:!:value]!]
string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g,
function(x, a) {
var b = a.split(':!:');
if (abort === true) {
return false;
}
value = prompt(b[0], (b[1]) ? b[1] : '');
if (value === null) {
abort = true;
}
return value;
}
);
return string;
}
return "";
}
// prepare action
function prepare(action) {
if ($.isFunction(action)) {
action = action(hash);
}
return magicMarkups(action);
}
// build block to insert
function build(string) {
var openWith = prepare(clicked.openWith);
var placeHolder = prepare(clicked.placeHolder);
var replaceWith = prepare(clicked.replaceWith);
var closeWith = prepare(clicked.closeWith);
var openBlockWith = prepare(clicked.openBlockWith);
var closeBlockWith = prepare(clicked.closeBlockWith);
var multiline = clicked.multiline;
if (replaceWith !== "") {
block = openWith + replaceWith + closeWith;
} else if (selection === '' && placeHolder !== '') {
block = openWith + placeHolder + closeWith;
} else {
string = string || selection;
var lines = [string], blocks = [];
if (multiline === true) {
lines = string.split(/\r?\n/);
}
for (var l = 0; l < lines.length; l++) {
line = lines[l];
var trailingSpaces;
if (trailingSpaces = line.match(/ *$/)) {
blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces);
} else {
blocks.push(openWith + line + closeWith);
}
}
block = blocks.join("\n");
}
block = openBlockWith + block + closeBlockWith;
return { block:block,
openBlockWith:openBlockWith,
openWith:openWith,
replaceWith:replaceWith,
placeHolder:placeHolder,
closeWith:closeWith,
closeBlockWith:closeBlockWith
};
}
// define markup to insert
function markup(button) {
var len, j, n, i;
hash = clicked = button;
get();
$.extend(hash, { line:"",
root:options.root,
textarea:textarea,
selection:(selection||''),
caretPosition:caretPosition,
ctrlKey:ctrlKey,
shiftKey:shiftKey,
altKey:altKey
}
);
// callbacks before insertion
prepare(options.beforeInsert);
prepare(clicked.beforeInsert);
if ((ctrlKey === true && shiftKey === true) || button.multiline === true) {
prepare(clicked.beforeMultiInsert);
}
$.extend(hash, { line:1 });
if ((ctrlKey === true && shiftKey === true)) {
lines = selection.split(/\r?\n/);
for (j = 0, n = lines.length, i = 0; i < n; i++) {
if ($.trim(lines[i]) !== '') {
$.extend(hash, { line:++j, selection:lines[i] } );
lines[i] = build(lines[i]).block;
} else {
lines[i] = "";
}
}
string = { block:lines.join('\n')};
start = caretPosition;
len = string.block.length + ((browser.opera) ? n-1 : 0);
} else if (ctrlKey === true) {
string = build(selection);
start = caretPosition + string.openWith.length;
len = string.block.length - string.openWith.length - string.closeWith.length;
len = len - (string.block.match(/ $/) ? 1 : 0);
len -= fixIeBug(string.block);
} else if (shiftKey === true) {
string = build(selection);
start = caretPosition;
len = string.block.length;
len -= fixIeBug(string.block);
} else {
string = build(selection);
start = caretPosition + string.block.length ;
len = 0;
start -= fixIeBug(string.block);
}
if ((selection === '' && string.replaceWith === '')) {
caretOffset += fixOperaBug(string.block);
start = caretPosition + string.openBlockWith.length + string.openWith.length;
len = string.block.length - string.openBlockWith.length - string.openWith.length - string.closeWith.length - string.closeBlockWith.length;
caretOffset = $$.val().substring(caretPosition, $$.val().length).length;
caretOffset -= fixOperaBug($$.val().substring(0, caretPosition));
}
$.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );
if (string.block !== selection && abort === false) {
insert(string.block);
set(start, len);
} else {
caretOffset = -1;
}
get();
$.extend(hash, { line:'', selection:selection });
// callbacks after insertion
if ((ctrlKey === true && shiftKey === true) || button.multiline === true) {
prepare(clicked.afterMultiInsert);
}
prepare(clicked.afterInsert);
prepare(options.afterInsert);
// refresh preview if opened
if (previewWindow && options.previewAutoRefresh) {
refreshPreview();
}
// reinit keyevent
shiftKey = altKey = ctrlKey = abort = false;
}
// Substract linefeed in Opera
function fixOperaBug(string) {
if (browser.opera) {
return string.length - string.replace(/\n*/g, '').length;
}
return 0;
}
// Substract linefeed in IE
function fixIeBug(string) {
if (browser.msie) {
return string.length - string.replace(/\r*/g, '').length;
}
return 0;
}
// add markup
function insert(block) {
if (document.selection) {
var newSelection = document.selection.createRange();
newSelection.text = block;
} else {
textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length);
}
}
// set a selection
function set(start, len) {
if (textarea.createTextRange){
// quick fix to make it work on Opera 9.5
if (browser.opera && browser.version >= 9.5 && len == 0) {
return false;
}
range = textarea.createTextRange();
range.collapse(true);
range.moveStart('character', start);
range.moveEnd('character', len);
range.select();
} else if (textarea.setSelectionRange ){
textarea.setSelectionRange(start, start + len);
}
textarea.scrollTop = scrollPosition;
textarea.focus();
}
// get the selection
function get() {
textarea.focus();
scrollPosition = textarea.scrollTop;
if (document.selection) {
selection = document.selection.createRange().text;
if (browser.msie) { // ie
var range = document.selection.createRange(), rangeCopy = range.duplicate();
rangeCopy.moveToElementText(textarea);
caretPosition = -1;
while(rangeCopy.inRange(range)) {
rangeCopy.moveStart('character');
caretPosition ++;
}
} else { // opera
caretPosition = textarea.selectionStart;
}
} else { // gecko & webkit
caretPosition = textarea.selectionStart;
selection = textarea.value.substring(caretPosition, textarea.selectionEnd);
}
return selection;
}
// open preview window
function preview() {
if (typeof options.previewHandler === 'function') {
previewWindow = true;
} else if (options.previewInElement) {
previewWindow = $(options.previewInElement);
} else if (!previewWindow || previewWindow.closed) {
if (options.previewInWindow) {
previewWindow = window.open('', 'preview', options.previewInWindow);
$(window).unload(function() {
previewWindow.close();
});
} else {
iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>');
if (options.previewPosition == 'after') {
iFrame.insertAfter(footer);
} else {
iFrame.insertBefore(header);
}
previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1];
}
} else if (altKey === true) {
if (iFrame) {
iFrame.remove();
} else {
previewWindow.close();
}
previewWindow = iFrame = false;
}
if (!options.previewAutoRefresh) {
refreshPreview();
}
if (options.previewInWindow) {
previewWindow.focus();
}
}
// refresh Preview window
function refreshPreview() {
renderPreview();
}
function renderPreview() {
var phtml;
if (options.previewHandler && typeof options.previewHandler === 'function') {
options.previewHandler( $$.val() );
} else if (options.previewParser && typeof options.previewParser === 'function') {
var data = options.previewParser( $$.val() );
writeInPreview(localize(data, 1) );
} else if (options.previewParserPath !== '') {
$.ajax({
type: 'POST',
dataType: 'text',
global: false,
url: options.previewParserPath,
data: options.previewParserVar+'='+encodeURIComponent($$.val()),
success: function(data) {
writeInPreview( localize(data, 1) );
}
});
} else {
if (!template) {
$.ajax({
url: options.previewTemplatePath,
dataType: 'text',
global: false,
success: function(data) {
writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) );
}
});
}
}
return false;
}
function writeInPreview(data) {
if (options.previewInElement) {
$(options.previewInElement).html(data);
} else if (previewWindow && previewWindow.document) {
try {
sp = previewWindow.document.documentElement.scrollTop
} catch(e) {
sp = 0;
}
previewWindow.document.open();
previewWindow.document.write(data);
previewWindow.document.close();
previewWindow.document.documentElement.scrollTop = sp;
}
}
// set keys pressed
function keyPressed(e) {
shiftKey = e.shiftKey;
altKey = e.altKey;
ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false;
if (e.type === 'keydown') {
if (ctrlKey === true) {
li = $('a[accesskey="'+((e.keyCode == 13) ? '\\n' : String.fromCharCode(e.keyCode))+'"]', header).parent('li');
if (li.length !== 0) {
ctrlKey = false;
setTimeout(function() {
li.triggerHandler('mouseup');
},1);
return false;
}
}
if (e.keyCode === 13 || e.keyCode === 10) { // Enter key
if (ctrlKey === true) { // Enter + Ctrl
ctrlKey = false;
markup(options.onCtrlEnter);
return options.onCtrlEnter.keepDefault;
} else if (shiftKey === true) { // Enter + Shift
shiftKey = false;
markup(options.onShiftEnter);
return options.onShiftEnter.keepDefault;
} else { // only Enter
markup(options.onEnter);
return options.onEnter.keepDefault;
}
}
if (e.keyCode === 9) { // Tab key
if (shiftKey == true || ctrlKey == true || altKey == true) {
return false;
}
if (caretOffset !== -1) {
get();
caretOffset = $$.val().length - caretOffset;
set(caretOffset, 0);
caretOffset = -1;
return false;
} else {
markup(options.onTab);
return options.onTab.keepDefault;
}
}
}
}
function remove() {
$$.unbind(".markItUp").removeClass('markItUpEditor');
$$.parent('div').parent('div.markItUp').parent('div').replaceWith($$);
var relativeRef = $$.parent('div').parent('div.markItUp').parent('div');
if (relativeRef.length) {
relativeRef.replaceWith($$);
}
$$.data('markItUp', null);
}
init();
});
};
$.fn.markItUpRemove = function() {
return this.each(function() {
$(this).markItUp('remove');
}
);
};
$.markItUp = function(settings) {
var options = { target:false };
$.extend(options, settings);
if (options.target) {
return $(options.target).each(function() {
$(this).focus();
$(this).trigger('insertion', [options]);
});
} else {
$('textarea').trigger('insertion', [options]);
}
};
})(jQuery);
// ----------------------------------------------------------------------------
// markItUp!
// ----------------------------------------------------------------------------
// Copyright (C) 2011 Jay Salvat
// http://markitup.jaysalvat.com/
// ----------------------------------------------------------------------------
// Html tags
// http://en.wikipedia.org/wiki/html
// ----------------------------------------------------------------------------
// Basic set. Feel free to add more tags
// ----------------------------------------------------------------------------
var mySettings = {
onShiftEnter: {keepDefault:false, replaceWith:'<br />\n'},
onCtrlEnter: {keepDefault:false, openWith:'\n<p>', closeWith:'</p>'},
onTab: {keepDefault:false, replaceWith:' '},
markupSet: [
{name:'Bold', key:'B', openWith:'(!(<strong>|!|<b>)!)', closeWith:'(!(</strong>|!|</b>)!)' },
{name:'Italic', key:'I', openWith:'(!(<em>|!|<i>)!)', closeWith:'(!(</em>|!|</i>)!)' },
{name:'Stroke through', key:'S', openWith:'<del>', closeWith:'</del>' },
{separator:'---------------' },
{name:'Bulleted List', openWith:' <li>', closeWith:'</li>', multiline:true, openBlockWith:'<ul>\n', closeBlockWith:'\n</ul>'},
{name:'Numeric List', openWith:' <li>', closeWith:'</li>', multiline:true, openBlockWith:'<ol>\n', closeBlockWith:'\n</ol>'},
{separator:'---------------' },
{name:'Picture', key:'P', replaceWith:'<img src="[![Source:!:http://]!]" alt="[![Alternative text]!]" />' },
{name:'Link', key:'L', openWith:'<a href="[![Link:!:http://]!]"(!( title="[![Title]!]")!)>', closeWith:'</a>', placeHolder:'Your text to link...' },
{separator:'---------------' },
{name:'Clean', className:'clean', replaceWith:function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") } },
{name:'Preview', className:'preview', call:'preview'}
]
}
/* -------------------------------------------------------------------
// markItUp!
// By Jay Salvat - http://markitup.jaysalvat.com/
// ------------------------------------------------------------------*/
.markItUp .markItUpButton1 a {
background-image:url(images/bold.png);
}
.markItUp .markItUpButton2 a {
background-image:url(images/italic.png);
}
.markItUp .markItUpButton3 a {
background-image:url(images/stroke.png);
}
.markItUp .markItUpButton4 a {
background-image:url(images/list-bullet.png);
}
.markItUp .markItUpButton5 a {
background-image:url(images/list-numeric.png);
}
.markItUp .markItUpButton6 a {
background-image:url(images/picture.png);
}
.markItUp .markItUpButton7 a {
background-image:url(images/link.png);
}
.markItUp .markItUpButton8 a {
background-image:url(images/clean.png);
}
.markItUp .preview a {
background-image:url(images/preview.png);
}
/* -------------------------------------------------------------------
// markItUp! Universal MarkUp Engine, JQuery plugin
// By Jay Salvat - http://markitup.jaysalvat.com/
// ------------------------------------------------------------------*/
.markItUp * {
margin:0px; padding:0px;
outline:none;
}
.markItUp a:link,
.markItUp a:visited {
color:#000;
text-decoration:none;
}
.markItUp {
width:700px;
margin:5px 0 5px 0;
border:5px solid #F5F5F5;
}
.markItUpContainer {
border:1px solid #3C769D;
background:#FFF url(images/bg-container.png) repeat-x top left;
padding:5px 5px 2px 5px;
font:11px Verdana, Arial, Helvetica, sans-serif;
}
.markItUpEditor {
font:12px 'Courier New', Courier, monospace;
padding:5px 5px 5px 35px;
border:3px solid #3C769D;
width:643px;
height:320px;
background:#FFF url(images/bg-editor.png) no-repeat;
clear:both;
line-height:18px;
overflow:auto;
}
.markItUpPreviewFrame {
overflow:auto;
background-color:#FFFFFF;
border:1px solid #3C769D;
width:99.9%;
height:300px;
margin:5px 0;
}
.markItUpFooter {
width:100%;
cursor:n-resize;
}
.markItUpResizeHandle {
overflow:hidden;
width:22px; height:5px;
margin-left:auto;
margin-right:auto;
background-image:url(images/handle.png);
cursor:n-resize;
}
/***************************************************************************************/
/* first row of buttons */
.markItUpHeader ul li {
list-style:none;
float:left;
position:relative;
}
.markItUpHeader ul li ul{
display:none;
}
.markItUpHeader ul li:hover > ul{
display:block;
}
.markItUpHeader ul .markItUpDropMenu {
background:transparent url(images/menu.png) no-repeat 115% 50%;
margin-right:5px;
}
.markItUpHeader ul .markItUpDropMenu li {
margin-right:0px;
}
.markItUpHeader ul .markItUpSeparator {
margin:0 10px;
width:1px;
height:16px;
overflow:hidden;
background-color:#CCC;
}
.markItUpHeader ul ul .markItUpSeparator {
width:auto; height:1px;
margin:0px;
}
/* next rows of buttons */
.markItUpHeader ul ul {
display:none;
position:absolute;
top:18px; left:0px;
background:#F5F5F5;
border:1px solid #3C769D;
height:inherit;
}
.markItUpHeader ul ul li {
float:none;
border-bottom:1px solid #3C769D;
}
.markItUpHeader ul ul .markItUpDropMenu {
background:#F5F5F5 url(images/submenu.png) no-repeat 100% 50%;
}
/* next rows of buttons */
.markItUpHeader ul ul ul {
position:absolute;
top:-1px; left:150px;
}
.markItUpHeader ul ul ul li {
float:none;
}
.markItUpHeader ul a {
display:block;
width:16px; height:16px;
text-indent:-10000px;
background-repeat:no-repeat;
padding:3px;
margin:0px;
}
.markItUpHeader ul ul a {
display:block;
padding-left:0px;
text-indent:0;
width:120px;
padding:5px 5px 5px 25px;
background-position:2px 50%;
}
.markItUpHeader ul ul a:hover {
color:#FFF;
background-color:#3C769D;
}
/***************************************************************************************/
.html .markItUpEditor {
background-image:url(images/bg-editor-html.png);
}
.markdown .markItUpEditor {
background-image:url(images/bg-editor-markdown.png);
}
.textile .markItUpEditor {
background-image:url(images/bg-editor-textile.png);
}
.bbcode .markItUpEditor {
background-image:url(images/bg-editor-bbcode.png);
}
.wiki .markItUpEditor,
.dotclear .markItUpEditor {
background-image:url(images/bg-editor-wiki.png);
}
\ No newline at end of file
/* -------------------------------------------------------------------
// markItUp! Universal MarkUp Engine, JQuery plugin
// By Jay Salvat - http://markitup.jaysalvat.com/
// ------------------------------------------------------------------*/
.markItUp * {
margin:0px; padding:0px;
outline:none;
}
.markItUp a:link,
.markItUp a:visited {
color:#000;
text-decoration:none;
}
.markItUp {
width:700px;
margin:5px 0 5px 0;
}
.markItUpContainer {
font:11px Verdana, Arial, Helvetica, sans-serif;
}
.markItUpEditor {
font:12px 'Courier New', Courier, monospace;
padding:5px;
width:690px;
height:320px;
clear:both;
line-height:18px;
overflow:auto;
}
.markItUpPreviewFrame {
overflow:auto;
background-color:#FFF;
width:99.9%;
height:300px;
margin:5px 0;
}
.markItUpFooter {
width:100%;
}
.markItUpResizeHandle {
overflow:hidden;
width:22px; height:5px;
margin-left:auto;
margin-right:auto;
background-image:url(images/handle.png);
cursor:n-resize;
}
/***************************************************************************************/
/* first row of buttons */
.markItUpHeader ul li {
list-style:none;
float:left;
position:relative;
}
.markItUpHeader ul li:hover > ul{
display:block;
}
.markItUpHeader ul .markItUpDropMenu {
background:transparent url(images/menu.png) no-repeat 115% 50%;
margin-right:5px;
}
.markItUpHeader ul .markItUpDropMenu li {
margin-right:0px;
}
/* next rows of buttons */
.markItUpHeader ul ul {
display:none;
position:absolute;
top:18px; left:0px;
background:#FFF;
border:1px solid #000;
}
.markItUpHeader ul ul li {
float:none;
border-bottom:1px solid #000;
}
.markItUpHeader ul ul .markItUpDropMenu {
background:#FFF url(images/submenu.png) no-repeat 100% 50%;
}
.markItUpHeader ul .markItUpSeparator {
margin:0 10px;
width:1px;
height:16px;
overflow:hidden;
background-color:#CCC;
}
.markItUpHeader ul ul .markItUpSeparator {
width:auto; height:1px;
margin:0px;
}
/* next rows of buttons */
.markItUpHeader ul ul ul {
position:absolute;
top:-1px; left:150px;
}
.markItUpHeader ul ul ul li {
float:none;
}
.markItUpHeader ul a {
display:block;
width:16px; height:16px;
text-indent:-10000px;
background-repeat:no-repeat;
padding:3px;
margin:0px;
}
.markItUpHeader ul ul a {
display:block;
padding-left:0px;
text-indent:0;
width:120px;
padding:5px 5px 5px 25px;
background-position:2px 50%;
}
.markItUpHeader ul ul a:hover {
color:#FFF;
background-color:#000;
}
/* preview style examples */
body {
background-color:#EFEFEF;
font:70% Verdana, Arial, Helvetica, sans-serif;
}
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>markItUp! preview template</title>
<link rel="stylesheet" type="text/css" href="~/templates/preview.css" />
</head>
<body>
<!-- content -->
</body>
</html>
......@@ -8,7 +8,7 @@
{% block head %}
{{ super() }}
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.css') }}" rel="stylesheet">
{% endblock %}
{% block body %}
......@@ -29,6 +29,6 @@
{% block tail %}
{{ super() }}
<script src="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='admin/js/form.js') }}"></script>
{% endblock %}
......@@ -8,7 +8,7 @@
{% block head %}
{{ super() }}
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.css') }}" rel="stylesheet">
{% endblock %}
{% block body %}
......@@ -20,6 +20,6 @@
{% block tail %}
{{ super() }}
<script src="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='admin/js/form.js') }}"></script>
{% endblock %}
......@@ -6,7 +6,7 @@
{% block head %}
{{ super() }}
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.css') }}" rel="stylesheet">
{% endblock %}
{% block body %}
......@@ -139,7 +139,7 @@
{% block tail %}
{{ super() }}
<script src="{{ url_for('admin.static', filename='datepicker/bootstrap-datepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='datetimepicker/bootstrap-datetimepicker.js') }}"></script>
<script src="{{ url_for('admin.static', filename='admin/js/form.js') }}"></script>
<script src="{{ url_for('admin.static', filename='admin/js/filters.js') }}"></script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment