4c32af3c69e8" alt=""/>  luyanan 0054f738af 资源图片压缩变形问题 8 ans auparavant   luyanan ce66aec30c 解决资源图片变形问题 8 ans auparavant   jack b083d65e60 搜索列表中,若为本人或本人发布的资源,则隐藏咨询按钮,点击进入后隐藏点赞按钮、咨询按钮。 8 ans auparavant   jiapeng c5d9752792 --init 8 ans auparavant jiapeng/portal-front - Gogs: Go Git Service

6 次代碼提交 (8bfe150fa1a9412d50673b7a1e2edfdd39d953c7)

作者 SHA1 備註 提交日期
  xuchunyang 0583012266 新文章功能 7 年之前
  xuchunyang bc5ca014b7 编辑器修改 7 年之前
  xuchunyang bc9c6d594e 修改图片上传,和编辑器上传图片慢的问题, 7 年之前
  xuchunyang 241a6ee47a 编辑器修改 7 年之前
  xuchunyang 476bfccec0 编辑器修改 7 年之前
  xuchunyang bdf84638b6 编辑器组件 8 年之前
jiapeng/portal-front - Gogs: Go Git Service

26 Commits (8b401c7a905a426fd6a9bed0946355218ba135ed)

Autor SHA1 Mensaje Fecha
  xuchunyang 1e1857d6d0 文章修改 %!s(int64=7) %!d(string=hace) años
  happy 566023346d 文章和资源去掉权限 %!s(int64=7) %!d(string=hace) años
  luyanan 677b77e0d3 更换工作台菜单链接地址及菜单样式 %!s(int64=7) %!d(string=hace) años
  xuchunyang e7638939d8 工作台新闻链接修改 %!s(int64=7) %!d(string=hace) años
  luyanan 0cbddd4b66 Merge branch 'dev' of http://121.42.53.174:3000/jiapeng/portal-front.git %!s(int64=7) %!d(string=hace) años
  luyanan 5f56cf19f8 首页添加热门专家模块、修改关注模块的相关 %!s(int64=7) %!d(string=hace) años
  luyanan 70efc5c3e9 修改判断标识以及专家头像与企业logo的区别 %!s(int64=7) %!d(string=hace) años
  jack b0e1c7b5a5 关注文章在工作台浏览 %!s(int64=7) %!d(string=hace) años
  luyanan 67d3a44a2a 修改静态页面网页title显示的内容; %!s(int64=7) %!d(string=hace) años
  jack 0f1a32c83a 专家及非专家显示 %!s(int64=7) %!d(string=hace) años
  jack b39de95f66 工作台 %!s(int64=7) %!d(string=hace) años
  xuchunyang f3469dd0b7 工作台最新咨询和最新回复头像加链接,去掉内容 %!s(int64=7) %!d(string=hace) años
  luyanan 39404d5d76 更改普通版头部导航 %!s(int64=7) %!d(string=hace) años
  jack 78c5980c70 工作台需求数量 %!s(int64=7) %!d(string=hace) años
  jack 69bbdfb0a7 需求 %!s(int64=7) %!d(string=hace) años
  xuchunyang a8edb25ae2 咨询修改,工作平台修改 %!s(int64=7) %!d(string=hace) años
  xuchunyang 5a1257194a 工作台分离 %!s(int64=7) %!d(string=hace) años
  luyanan 7e5400df9f 1、增加【需求发布】功、【需求确认】 %!s(int64=7) %!d(string=hace) años
  xuchunyang 4f94b047af 用户权限修改个人预览页面,个人修改页面,工作台,新增我的关注功能 %!s(int64=7) %!d(string=hace) años
  luyanan 4fcd64a97e 【我的工作台】上加入我的文章模块 %!s(int64=7) %!d(string=hace) años
  luyanan 0d2e13d8f6 【我的工作台】添加关注模块 %!s(int64=7) %!d(string=hace) años
  xuchunyang 7d807b851e 新增研究文章添加功能,修改功能,删除功能,列表显示功能。 %!s(int64=7) %!d(string=hace) años
  luyanan 1d2ed04e8b 更换默认头像图片(带不带?) %!s(int64=7) %!d(string=hace) años
  luyanan 28ccfa2d31 增加点击【客服邮箱】链接后,自动打开邮箱客户端 %!s(int64=7) %!d(string=hace) años
  xuchunyang 38f4f52aee 资源发布,修改添加编辑器 %!s(int64=8) %!d(string=hace) años
  jiapeng c5d9752792 --init %!s(int64=8) %!d(string=hace) años
bulomakaka/ekexiu.app - Gogs: Go Git Service

7 Commits (6d626f8a9a4f19f06b49f3ca382710fbf42927a8)

Autor SHA1 Mensagem Data
  lipengtao 91c523019b 我的关注加上身份标示,点赞长度样式,账户页个人信息去掉逗号,未认证位置 8 anos atrás
  lipengtao 3c4fd4d120 添加学生,企业专家,专家的模块,加上认证标示 8 anos atrás
  lipengtao 4bc2825fb4 加上时间和城市控件 8 anos atrás
  luyanan 772ddc7e13 朋涛专家信息修改 8 anos atrás
  xiaoai_123 dbb3a786de 鹏涛:专家修改已经填充ok 8 anos atrás
  luyanan e3e4f43f89 1、新增专家详细信息修改子页面; 8 anos atrás
  luyanan 8fffca8842 ekexiu.app页面首次上传 8 anos atrás
portal-front - Gogs: Go Git Service

portal html css js resource

bootstrap-datetimepicker.js 65KB

    /* //! version : 4.0.0 ========================================================= bootstrap-datetimejs https://github.com/Eonasdan/bootstrap-datetimepicker ========================================================= The MIT License (MIT) Copyright (c) 2015 Jonathan Peterson 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 (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // AMD is used - Register as an anonymous module. define(['jquery', 'moment'], factory); } else if (typeof exports === 'object') { factory(require('jquery'), require('moment')); } else { // Neither AMD nor CommonJS used. Use global variables. if (!jQuery) { throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; } if (!moment) { throw 'bootstrap-datetimepicker requires Moment.js to be loaded first'; } factory(jQuery, moment); } }(function ($, moment) { 'use strict'; if (!moment) { throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first'); } var dateTimePicker = function (element, options) { var picker = {}, date = moment(), viewDate = date.clone(), unset = true, input, component = false, widget = false, use24Hours, minViewModeNumber = 0, actualFormat, parseFormats, currentViewMode, datePickerModes = [ { clsName: 'days', navFnc: 'M', navStep: 1 }, { clsName: 'months', navFnc: 'y', navStep: 1 }, { clsName: 'years', navFnc: 'y', navStep: 10 } ], viewModes = ['days', 'months', 'years'], verticalModes = ['top', 'bottom', 'auto'], horizontalModes = ['left', 'right', 'auto'], toolbarPlacements = ['default', 'top', 'bottom'], /******************************************************************************** * * Private functions * ********************************************************************************/ isEnabled = function (granularity) { if (typeof granularity !== 'string' || granularity.length > 1) { throw new TypeError('isEnabled expects a single character string parameter'); } switch (granularity) { case 'y': return actualFormat.indexOf('Y') !== -1; case 'M': return actualFormat.indexOf('M') !== -1; case 'd': return actualFormat.toLowerCase().indexOf('d') !== -1; case 'h': case 'H': return actualFormat.toLowerCase().indexOf('h') !== -1; case 'm': return actualFormat.indexOf('m') !== -1; case 's': return actualFormat.indexOf('s') !== -1; default: return false; } }, hasTime = function () { return (isEnabled('h') || isEnabled('m') || isEnabled('s')); }, hasDate = function () { return (isEnabled('y') || isEnabled('M') || isEnabled('d')); }, getDatePickerTemplate = function () { var headTemplate = $('<thead>') .append($('<tr>') .append($('<th>').addClass('prev').attr('data-action', 'previous') .append($('<span>').addClass(options.icons.previous)) ) .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5'))) .append($('<th>').addClass('next').attr('data-action', 'next') .append($('<span>').addClass(options.icons.next)) ) ), contTemplate = $('<tbody>') .append($('<tr>') .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7'))) ); return [ $('<div>').addClass('datepicker-days') .append($('<table>').addClass('table-condensed') .append(headTemplate) .append($('<tbody>')) ), $('<div>').addClass('datepicker-months') .append($('<table>').addClass('table-condensed') .append(headTemplate.clone()) .append(contTemplate.clone()) ), $('<div>').addClass('datepicker-years') .append($('<table>').addClass('table-condensed') .append(headTemplate.clone()) .append(contTemplate.clone()) ) ]; }, getTimePickerMainTemplate = function () { var topRow = $('<tr>'), middleRow = $('<tr>'), bottomRow = $('<tr>'); if (isEnabled('h')) { topRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours') .append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') .append($('<span>').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours'))); bottomRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours') .append($('<span>').addClass(options.icons.down)))); } if (isEnabled('m')) { if (isEnabled('h')) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>').addClass('separator').html(':')); bottomRow.append($('<td>').addClass('separator')); } topRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes') .append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') .append($('<span>').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes'))); bottomRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes') .append($('<span>').addClass(options.icons.down)))); } if (isEnabled('s')) { if (isEnabled('m')) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>').addClass('separator').html(':')); bottomRow.append($('<td>').addClass('separator')); } topRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds') .append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') .append($('<span>').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds'))); bottomRow.append($('<td>') .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds') .append($('<span>').addClass(options.icons.down)))); } if (!use24Hours) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>') .append($('<button>').addClass('btn btn-primary').attr('data-action', 'togglePeriod'))); bottomRow.append($('<td>').addClass('separator')); } return $('<div>').addClass('timepicker-picker') .append($('<table>').addClass('table-condensed') .append([topRow, middleRow, bottomRow])); }, getTimePickerTemplate = function () { var hoursView = $('<div>').addClass('timepicker-hours') .append($('<table>').addClass('table-condensed')), minutesView = $('<div>').addClass('timepicker-minutes') .append($('<table>').addClass('table-condensed')), secondsView = $('<div>').addClass('timepicker-seconds') .append($('<table>').addClass('table-condensed')), ret = [getTimePickerMainTemplate()]; if (isEnabled('h')) { ret.push(hoursView); } if (isEnabled('m')) { ret.push(minutesView); } if (isEnabled('s')) { ret.push(secondsView); } return ret; }, getToolbar = function () { var row = []; if (options.showTodayButton) { row.push($('<td>').append($('<a>').attr('data-action', 'today').append($('<span>').addClass(options.icons.today)))); } if (!options.sideBySide && hasDate() && hasTime()) { row.push($('<td>').append($('<a>').attr('data-action', 'togglePicker').append($('<span>').addClass(options.icons.time)))); } if (options.showClear) { row.push($('<td>').append($('<a>').attr('data-action', 'clear').append($('<span>').addClass(options.icons.clear)))); } return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row))); }, getTemplate = function () { var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'), dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()), timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()), content = $('<ul>').addClass('list-unstyled'), toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar()); if (use24Hours) { template.addClass('usetwentyfour'); } if (options.sideBySide && hasDate() && hasTime()) { template.addClass('timepicker-sbs'); template.append( $('<div>').addClass('row') .append(dateView.addClass('col-sm-6')) .append(timeView.addClass('col-sm-6')) ); template.append(toolbar); return template; } if (options.toolbarPlacement === 'top') { content.append(toolbar); } if (hasDate()) { content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView)); } if (options.toolbarPlacement === 'default') { content.append(toolbar); } if (hasTime()) { content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView)); } if (options.toolbarPlacement === 'bottom') { content.append(toolbar); } return template.append(content); }, dataToOptions = function () { var eData = element.data(), dataOptions = {}; if (eData.dateOptions && eData.dateOptions instanceof Object) { dataOptions = $.extend(true, dataOptions, eData.dateOptions); } $.each(options, function (key) { var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1); if (eData[attributeName] !== undefined) { dataOptions[key] = eData[attributeName]; } }); return dataOptions; }, place = function () { var offset = (component || element).position(), vertical = options.widgetPositioning.vertical, horizontal = options.widgetPositioning.horizontal, parent; if (options.widgetParent) { parent = options.widgetParent.append(widget); } else if (element.is('input')) { parent = element.parent().append(widget); } else { parent = element; element.children().first().after(widget); } // Top and bottom logic if (vertical === 'auto') { if ((component || element).offset().top + widget.height() > $(window).height() + $(window).scrollTop() && widget.height() + element.outerHeight() < (component || element).offset().top) { vertical = 'top'; } else { vertical = 'bottom'; } } // Left and right logic if (horizontal === 'auto') { if (parent.width() < offset.left + widget.outerWidth()) { horizontal = 'right'; } else { horizontal = 'left'; } } if (vertical === 'top') { widget.addClass('top').removeClass('bottom'); } else { widget.addClass('bottom').removeClass('top'); } if (horizontal === 'right') { widget.addClass('pull-right'); } else { widget.removeClass('pull-right'); } // find the first parent element that has a relative css positioning if (parent.css('position') !== 'relative') { parent = parent.parents().filter(function () { return $(this).css('position') === 'relative'; }).first(); } if (parent.length === 0) { throw new Error('datetimepicker component should be placed within a relative positioned container'); } widget.css({ top: vertical === 'top' ? 'auto' : offset.top + element.outerHeight(), bottom: vertical === 'top' ? offset.top + element.outerHeight() : 'auto', left: horizontal === 'left' ? parent.css('padding-left') : 'auto', right: horizontal === 'left' ? 'auto' : parent.css('padding-right') }); }, notifyEvent = function (e) { if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) { return; } element.trigger(e); }, showMode = function (dir) { if (!widget) { return; } if (dir) { currentViewMode = Math.max(minViewModeNumber, Math.min(2, currentViewMode + dir)); } widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show(); }, fillDow = function () { var row = $('<tr>'), currentDate = viewDate.clone().startOf('w'); if (options.calendarWeeks === true) { row.append($('<th>').addClass('cw').text('#')); } while (currentDate.isBefore(viewDate.clone().endOf('w'))) { row.append($('<th>').addClass('dow').text(currentDate.format('dd'))); currentDate.add(1, 'd'); } widget.find('.datepicker-days thead').append(row); }, isInDisabledDates = function (date) { if (!options.disabledDates) { return false; } return options.disabledDates[date.format('YYYY-MM-DD')] === true; }, isInEnabledDates = function (date) { if (!options.enabledDates) { return false; } return options.enabledDates[date.format('YYYY-MM-DD')] === true; }, isValid = function (targetMoment, granularity) { if (!targetMoment.isValid()) { return false; } if (options.disabledDates && isInDisabledDates(targetMoment)) { return false; } if (options.enabledDates && isInEnabledDates(targetMoment)) { return true; } if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) { return false; } if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) { return false; } if (granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) { return false; } return true; }, fillMonths = function () { var spans = [], monthsShort = viewDate.clone().startOf('y').hour(12); // hour is changed to avoid DST issues in some browsers while (monthsShort.isSame(viewDate, 'y')) { spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM'))); monthsShort.add(1, 'M'); } widget.find('.datepicker-months td').empty().append(spans); }, updateMonths = function () { var monthsView = widget.find('.datepicker-months'), monthsViewHeader = monthsView.find('th'), months = monthsView.find('tbody').find('span'); monthsView.find('.disabled').removeClass('disabled'); if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) { monthsViewHeader.eq(0).addClass('disabled'); } monthsViewHeader.eq(1).text(viewDate.year()); if (!isValid(viewDate.clone().add(1, 'y'), 'y')) { monthsViewHeader.eq(2).addClass('disabled'); } months.removeClass('active'); if (date.isSame(viewDate, 'y')) { months.eq(date.month()).addClass('active'); } months.each(function (index) { if (!isValid(viewDate.clone().month(index), 'M')) { $(this).addClass('disabled'); } }); }, updateYears = function () { var yearsView = widget.find('.datepicker-years'), yearsViewHeader = yearsView.find('th'), startYear = viewDate.clone().subtract(5, 'y'), endYear = viewDate.clone().add(6, 'y'), html = ''; yearsView.find('.disabled').removeClass('disabled'); if (options.minDate && options.minDate.isAfter(startYear, 'y')) { yearsViewHeader.eq(0).addClass('disabled'); } yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year()); if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) { yearsViewHeader.eq(2).addClass('disabled'); } while (!startYear.isAfter(endYear, 'y')) { html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>'; startYear.add(1, 'y'); } yearsView.find('td').html(html); }, fillDate = function () { var daysView = widget.find('.datepicker-days'), daysViewHeader = daysView.find('th'), currentDate, html = [], row, clsName; if (!hasDate()) { return; } daysView.find('.disabled').removeClass('disabled'); daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat)); if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) { daysViewHeader.eq(0).addClass('disabled'); } if (!isValid(viewDate.clone().add(1, 'M'), 'M')) { daysViewHeader.eq(2).addClass('disabled'); } currentDate = viewDate.clone().startOf('M').startOf('week'); while (!viewDate.clone().endOf('M').endOf('w').isBefore(currentDate, 'd')) { if (currentDate.weekday() === 0) { row = $('<tr>'); if (options.calendarWeeks) { row.append('<td class="cw">' + currentDate.week() + '</td>'); } html.push(row); } clsName = ''; if (currentDate.isBefore(viewDate, 'M')) { clsName += ' old'; } if (currentDate.isAfter(viewDate, 'M')) { clsName += ' new'; } if (currentDate.isSame(date, 'd') && !unset) { clsName += ' active'; } if (!isValid(currentDate, 'd')) { clsName += ' disabled'; } if (currentDate.isSame(moment(), 'd')) { clsName += ' today'; } if (currentDate.day() === 0 || currentDate.day() === 6) { clsName += ' weekend'; } row.append('<td data-action="selectDay" class="day' + clsName + '">' + currentDate.date() + '</td>'); currentDate.add(1, 'd'); } daysView.find('tbody').empty().append(html); updateMonths(); updateYears(); }, fillHours = function () { var table = widget.find('.timepicker-hours table'), currentHour = viewDate.clone().startOf('d'), html = [], row = $('<tr>'); if (viewDate.hour() > 11 && !use24Hours) { currentHour.hour(12); } while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) { if (currentHour.hour() % 4 === 0) { row = $('<tr>'); html.push(row); } row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>'); currentHour.add(1, 'h'); } table.empty().append(html); }, fillMinutes = function () { var table = widget.find('.timepicker-minutes table'), currentMinute = viewDate.clone().startOf('h'), html = [], row = $('<tr>'), step = options.stepping === 1 ? 5 : options.stepping; while (viewDate.isSame(currentMinute, 'h')) { if (currentMinute.minute() % (step * 4) === 0) { row = $('<tr>'); html.push(row); } row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>'); currentMinute.add(step, 'm'); } table.empty().append(html); }, fillSeconds = function () { var table = widget.find('.timepicker-seconds table'), currentSecond = viewDate.clone().startOf('m'), html = [], row = $('<tr>'); while (viewDate.isSame(currentSecond, 'm')) { if (currentSecond.second() % 20 === 0) { row = $('<tr>'); html.push(row); } row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>'); currentSecond.add(5, 's'); } table.empty().append(html); }, fillTime = function () { var timeComponents = widget.find('.timepicker span[data-time-component]'); if (!use24Hours) { widget.find('.timepicker [data-action=togglePeriod]').text(date.format('A')); } timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh')); timeComponents.filter('[data-time-component=minutes]').text(date.format('mm')); timeComponents.filter('[data-time-component=seconds]').text(date.format('ss')); fillHours(); fillMinutes(); fillSeconds(); }, update = function () { if (!widget) { return; } fillDate(); fillTime(); }, setValue = function (targetMoment) { var oldDate = unset ? null : date; // case of calling setValue(null or false) if (!targetMoment) { unset = true; input.val(''); element.data('date', ''); notifyEvent({ type: 'dp.change', date: null, oldDate: oldDate }); update(); return; } targetMoment = targetMoment.clone().locale(options.locale); if (options.stepping !== 1) { targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0); } if (isValid(targetMoment)) { date = targetMoment; viewDate = date.clone(); input.val(date.format(actualFormat)); element.data('date', date.format(actualFormat)); update(); unset = false; notifyEvent({ type: 'dp.change', date: date.clone(), oldDate: oldDate }); } else { input.val(unset ? '' : date.format(actualFormat)); notifyEvent({ type: 'dp.error', date: targetMoment }); } }, hide = function () { var transitioning = false; if (!widget) { return picker; } // Ignore event if in the middle of a picker transition widget.find('.collapse').each(function () { var collapseData = $(this).data('collapse'); if (collapseData && collapseData.transitioning) { transitioning = true; return false; } }); if (transitioning) { return picker; } if (component && component.hasClass('btn')) { component.toggleClass('active'); } widget.hide(); $(window).off('resize', place); widget.off('click', '[data-action]'); widget.off('mousedown', false); widget.remove(); widget = false; notifyEvent({ type: 'dp.hide', date: date.clone() }); return picker; }, /******************************************************************************** * * Widget UI interaction functions * ********************************************************************************/ actions = { next: function () { viewDate.add(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc); fillDate(); }, previous: function () { viewDate.subtract(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc); fillDate(); }, pickerSwitch: function () { showMode(1); }, selectMonth: function (e) { var month = $(e.target).closest('tbody').find('span').index($(e.target)); viewDate.month(month); if (currentViewMode === minViewModeNumber) { setValue(date.clone().year(viewDate.year()).month(viewDate.month())); hide(); } showMode(-1); fillDate(); }, selectYear: function (e) { var year = parseInt($(e.target).text(), 10) || 0; viewDate.year(year); if (currentViewMode === minViewModeNumber) { setValue(date.clone().year(viewDate.year())); hide(); } showMode(-1); fillDate(); }, selectDay: function (e) { var day = viewDate.clone(); if ($(e.target).is('.old')) { day.subtract(1, 'M'); } if ($(e.target).is('.new')) { day.add(1, 'M'); } setValue(day.date(parseInt($(e.target).text(), 10))); if (!hasTime() && !options.keepOpen) { hide(); } }, incrementHours: function () { setValue(date.clone().add(1, 'h')); }, incrementMinutes: function () { setValue(date.clone().add(options.stepping, 'm')); }, incrementSeconds: function () { setValue(date.clone().add(1, 's')); }, decrementHours: function () { setValue(date.clone().subtract(1, 'h')); }, decrementMinutes: function () { setValue(date.clone().subtract(options.stepping, 'm')); }, decrementSeconds: function () { setValue(date.clone().subtract(1, 's')); }, togglePeriod: function () { setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h')); }, togglePicker: function (e) { var $this = $(e.target), $parent = $this.closest('ul'), expanded = $parent.find('.in'), closed = $parent.find('.collapse:not(.in)'), collapseData; if (expanded && expanded.length) { collapseData = expanded.data('collapse'); if (collapseData && collapseData.transitioning) { return; } expanded.collapse('hide'); closed.collapse('show'); if ($this.is('span')) { $this.toggleClass(options.icons.time + ' ' + options.icons.date); } else { $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date); } // NOTE: uncomment if toggled state will be restored in show() //if (component) { // component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date); //} } }, showPicker: function () { widget.find('.timepicker > div:not(.timepicker-picker)').hide(); widget.find('.timepicker .timepicker-picker').show(); }, showHours: function () { widget.find('.timepicker .timepicker-picker').hide(); widget.find('.timepicker .timepicker-hours').show(); }, showMinutes: function () { widget.find('.timepicker .timepicker-picker').hide(); widget.find('.timepicker .timepicker-minutes').show(); }, showSeconds: function () { widget.find('.timepicker .timepicker-picker').hide(); widget.find('.timepicker .timepicker-seconds').show(); }, selectHour: function (e) { var hour = parseInt($(e.target).text(), 10); if (!use24Hours) { if (date.hours() >= 12) { if (hour !== 12) { hour += 12; } } else { if (hour === 12) { hour = 0; } } } setValue(date.clone().hours(hour)); actions.showPicker.call(picker); }, selectMinute: function (e) { setValue(date.clone().minutes(parseInt($(e.target).text(), 10))); actions.showPicker.call(picker); }, selectSecond: function (e) { setValue(date.clone().seconds(parseInt($(e.target).text(), 10))); actions.showPicker.call(picker); }, clear: function () { setValue(null); }, today: function () { setValue(moment()); } }, doAction = function (e) { if ($(e.currentTarget).is('.disabled')) { return false; } actions[$(e.currentTarget).data('action')].apply(picker, arguments); return false; }, show = function () { var currentMoment, useCurrentGranularity = { 'year': function (m) { return m.month(0).date(1).hours(0).seconds(0).minutes(0); }, 'month': function (m) { return m.date(1).hours(0).seconds(0).minutes(0); }, 'day': function (m) { return m.hours(0).seconds(0).minutes(0); }, 'hour': function (m) { return m.seconds(0).minutes(0); }, 'minute': function (m) { return m.seconds(0); } }; if (input.prop('disabled') || input.prop('readonly') || widget) { return picker; } if (options.useCurrent && unset) { // && input.val().trim().length !== 0) { this broke the jasmine test currentMoment = moment(); if (typeof options.useCurrent === 'string') { currentMoment = useCurrentGranularity[options.useCurrent](currentMoment); } setValue(currentMoment); } widget = getTemplate(); fillDow(); fillMonths(); widget.find('.timepicker-hours').hide(); widget.find('.timepicker-minutes').hide(); widget.find('.timepicker-seconds').hide(); update(); showMode(); $(window).on('resize', place); widget.on('click', '[data-action]', doAction); // this handles clicks on the widget widget.on('mousedown', false); if (component && component.hasClass('btn')) { component.toggleClass('active'); } widget.show(); place(); if (!input.is(':focus')) { input.focus(); } notifyEvent({ type: 'dp.show' }); return picker; }, toggle = function () { return (widget ? hide() : show()); }, parseInputDate = function (date) { if (moment.isMoment(date) || date instanceof Date) { date = moment(date); } else { date = moment(date, parseFormats, options.useStrict); } date.locale(options.locale); return date; }, keydown = function (e) { if (e.keyCode === 27) { // allow escape to hide picker hide(); } }, change = function (e) { var val = $(e.target).val().trim(), parsedDate = val ? parseInputDate(val) : null; setValue(parsedDate); e.stopImmediatePropagation(); return false; }, attachDatePickerElementEvents = function () { input.on({ 'change': change, 'blur': hide, 'keydown': keydown }); if (element.is('input')) { input.on({ 'focus': show }); } else if (component) { component.on('click', toggle); component.on('mousedown', false); } }, detachDatePickerElementEvents = function () { input.off({ 'change': change, 'blur': hide, 'keydown': keydown }); if (element.is('input')) { input.off({ 'focus': show }); } else if (component) { component.off('click', toggle); component.off('mousedown', false); } }, indexGivenDates = function (givenDatesArray) { // Store given enabledDates and disabledDates as keys. // This way we can check their existence in O(1) time instead of looping through whole array. // (for example: options.enabledDates['2014-02-27'] === true) var givenDatesIndexed = {}; $.each(givenDatesArray, function () { var dDate = parseInputDate(this); if (dDate.isValid()) { givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true; } }); return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false; }, initFormatting = function () { var format = options.format || 'L LT'; actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (input) { return date.localeData().longDateFormat(input) || input; }); parseFormats = options.extraFormats ? options.extraFormats.slice() : []; if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) { parseFormats.push(actualFormat); } use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.indexOf('h') < 1); if (isEnabled('y')) { minViewModeNumber = 2; } if (isEnabled('M')) { minViewModeNumber = 1; } if (isEnabled('d')) { minViewModeNumber = 0; } currentViewMode = Math.max(minViewModeNumber, currentViewMode); if (!unset) { setValue(date); } }; /******************************************************************************** * * Public API functions * ===================== * * Important: Do not expose direct references to private objects or the options * object to the outer world. Always return a clone when returning values or make * a clone when setting a private variable. * ********************************************************************************/ picker.destroy = function () { hide(); detachDatePickerElementEvents(); element.removeData('DateTimePicker'); element.removeData('date'); }; picker.toggle = toggle; picker.show = show; picker.hide = hide; picker.disable = function () { hide(); if (component && component.hasClass('btn')) { component.addClass('disabled'); } input.prop('disabled', true); return picker; }; picker.enable = function () { if (component && component.hasClass('btn')) { component.removeClass('disabled'); } input.prop('disabled', false); return picker; }; picker.options = function (newOptions) { if (arguments.length === 0) { return $.extend(true, {}, options); } if (!(newOptions instanceof Object)) { throw new TypeError('options() options parameter should be an object'); } $.extend(true, options, newOptions); $.each(options, function (key, value) { if (picker[key] !== undefined) { picker[key](value); } else { throw new TypeError('option ' + key + ' is not recognized!'); } }); return picker; }; picker.date = function (newDate) { if (arguments.length === 0) { if (unset) { return null; } return date.clone(); } if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) { throw new TypeError('date() parameter must be one of [null, string, moment or Date]'); } setValue(newDate === null ? null : parseInputDate(newDate)); return picker; }; picker.format = function (newFormat) { if (arguments.length === 0) { return options.format; } if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) { throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat); } options.format = newFormat; if (actualFormat) { initFormatting(); // reinit formatting } return picker; }; picker.dayViewHeaderFormat = function (newFormat) { if (arguments.length === 0) { return options.dayViewHeaderFormat; } if (typeof newFormat !== 'string') { throw new TypeError('dayViewHeaderFormat() expects a string parameter'); } options.dayViewHeaderFormat = newFormat; return picker; }; picker.extraFormats = function (formats) { if (arguments.length === 0) { return options.extraFormats; } if (formats !== false && !(formats instanceof Array)) { throw new TypeError('extraFormats() expects an array or false parameter'); } options.extraFormats = formats; if (parseFormats) { initFormatting(); // reinit formatting } return picker; }; picker.disabledDates = function (dates) { if (arguments.length === 0) { return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates); } if (!dates) { options.disabledDates = false; update(); return picker; } if (!(dates instanceof Array)) { throw new TypeError('disabledDates() expects an array parameter'); } options.disabledDates = indexGivenDates(dates); options.enabledDates = false; update(); return picker; }; picker.enabledDates = function (dates) { if (arguments.length === 0) { return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates); } if (!dates) { options.enabledDates = false; update(); return picker; } if (!(dates instanceof Array)) { throw new TypeError('enabledDates() expects an array parameter'); } options.enabledDates = indexGivenDates(dates); options.disabledDates = false; update(); return picker; }; picker.daysOfWeekDisabled = function (daysOfWeekDisabled) { if (arguments.length === 0) { return options.daysOfWeekDisabled.splice(0); } if (!(daysOfWeekDisabled instanceof Array)) { throw new TypeError('daysOfWeekDisabled() expects an array parameter'); } options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) { currentValue = parseInt(currentValue, 10); if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) { return previousValue; } if (previousValue.indexOf(currentValue) === -1) { previousValue.push(currentValue); } return previousValue; }, []).sort(); update(); return picker; }; picker.maxDate = function (date) { if (arguments.length === 0) { return options.maxDate ? options.maxDate.clone() : options.maxDate; } if ((typeof date === 'boolean') && date === false) { options.maxDate = false; update(); return picker; } var parsedDate = parseInputDate(date); if (!parsedDate.isValid()) { throw new TypeError('maxDate() Could not parse date parameter: ' + date); } if (options.minDate && parsedDate.isBefore(options.minDate)) { throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat)); } options.maxDate = parsedDate; if (options.maxDate.isBefore(date)) { setValue(options.maxDate); } update(); return picker; }; picker.minDate = function (date) { if (arguments.length === 0) { return options.minDate ? options.minDate.clone() : options.minDate; } if ((typeof date === 'boolean') && date === false) { options.minDate = false; update(); return picker; } var parsedDate = parseInputDate(date); if (!parsedDate.isValid()) { throw new TypeError('minDate() Could not parse date parameter: ' + date); } if (options.maxDate && parsedDate.isAfter(options.maxDate)) { throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat)); } options.minDate = parsedDate; if (options.minDate.isAfter(date)) { setValue(options.minDate); } update(); return picker; }; picker.defaultDate = function (defaultDate) { if (arguments.length === 0) { return options.defaultDate ? options.defaultDate.clone() : options.defaultDate; } if (!defaultDate) { options.defaultDate = false; return picker; } var parsedDate = parseInputDate(defaultDate); if (!parsedDate.isValid()) { throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate); } if (!isValid(parsedDate)) { throw new TypeError('defaultDate() date passed is invalid according to component setup validations'); } options.defaultDate = parsedDate; if (options.defaultDate && input.val().trim() === '') { setValue(options.defaultDate); } return picker; }; picker.locale = function (locale) { if (arguments.length === 0) { return options.locale; } if (!moment.localeData(locale)) { throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!'); } options.locale = locale; date.locale(options.locale); viewDate.locale(options.locale); if (actualFormat) { initFormatting(); // reinit formatting } if (widget) { hide(); show(); } return picker; }; picker.stepping = function (stepping) { if (arguments.length === 0) { return options.stepping; } stepping = parseInt(stepping, 10); if (isNaN(stepping) || stepping < 1) { stepping = 1; } options.stepping = stepping; return picker; }; picker.useCurrent = function (useCurrent) { var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute']; if (arguments.length === 0) { return options.useCurrent; } if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) { throw new TypeError('useCurrent() expects a boolean or string parameter'); } if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) { throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', ')); } options.useCurrent = useCurrent; return picker; }; picker.collapse = function (collapse) { if (arguments.length === 0) { return options.collapse; } if (typeof collapse !== 'boolean') { throw new TypeError('collapse() expects a boolean parameter'); } if (options.collapse === collapse) { return picker; } options.collapse = collapse; if (widget) { hide(); show(); } return picker; }; picker.icons = function (icons) { if (arguments.length === 0) { return $.extend({}, options.icons); } if (!(icons instanceof Object)) { throw new TypeError('icons() expects parameter to be an Object'); } $.extend(options.icons, icons); if (widget) { hide(); show(); } return picker; }; picker.useStrict = function (useStrict) { if (arguments.length === 0) { return options.useStrict; } if (typeof useStrict !== 'boolean') { throw new TypeError('useStrict() expects a boolean parameter'); } options.useStrict = useStrict; return picker; }; picker.sideBySide = function (sideBySide) { if (arguments.length === 0) { return options.sideBySide; } if (typeof sideBySide !== 'boolean') { throw new TypeError('sideBySide() expects a boolean parameter'); } options.sideBySide = sideBySide; if (widget) { hide(); show(); } return picker; }; picker.viewMode = function (newViewMode) { if (arguments.length === 0) { return options.viewMode; } if (typeof newViewMode !== 'string') { throw new TypeError('viewMode() expects a string parameter'); } if (viewModes.indexOf(newViewMode) === -1) { throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value'); } options.viewMode = newViewMode; currentViewMode = Math.max(viewModes.indexOf(newViewMode), minViewModeNumber); showMode(); return picker; }; picker.toolbarPlacement = function (toolbarPlacement) { if (arguments.length === 0) { return options.toolbarPlacement; } if (typeof toolbarPlacement !== 'string') { throw new TypeError('toolbarPlacement() expects a string parameter'); } if (toolbarPlacements.indexOf(toolbarPlacement) === -1) { throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value'); } options.toolbarPlacement = toolbarPlacement; if (widget) { hide(); show(); } return picker; }; picker.widgetPositioning = function (widgetPositioning) { if (arguments.length === 0) { return $.extend({}, options.widgetPositioning); } if (({}).toString.call(widgetPositioning) !== '[object Object]') { throw new TypeError('widgetPositioning() expects an object variable'); } if (widgetPositioning.horizontal) { if (typeof widgetPositioning.horizontal !== 'string') { throw new TypeError('widgetPositioning() horizontal variable must be a string'); } widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase(); if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) { throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')'); } options.widgetPositioning.horizontal = widgetPositioning.horizontal; } if (widgetPositioning.vertical) { if (typeof widgetPositioning.vertical !== 'string') { throw new TypeError('widgetPositioning() vertical variable must be a string'); } widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase(); if (verticalModes.indexOf(widgetPositioning.vertical) === -1) { throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')'); } options.widgetPositioning.vertical = widgetPositioning.vertical; } update(); return picker; }; picker.calendarWeeks = function (showCalendarWeeks) { if (arguments.length === 0) { return options.calendarWeeks; } if (typeof showCalendarWeeks !== 'boolean') { throw new TypeError('calendarWeeks() expects parameter to be a boolean value'); } options.calendarWeeks = showCalendarWeeks; update(); return picker; }; picker.showTodayButton = function (showTodayButton) { if (arguments.length === 0) { return options.showTodayButton; } if (typeof showTodayButton !== 'boolean') { throw new TypeError('showTodayButton() expects a boolean parameter'); } options.showTodayButton = showTodayButton; if (widget) { hide(); show(); } return picker; }; picker.showClear = function (showClear) { if (arguments.length === 0) { return options.showClear; } if (typeof showClear !== 'boolean') { throw new TypeError('showClear() expects a boolean parameter'); } options.showClear = showClear; if (widget) { hide(); show(); } return picker; }; picker.widgetParent = function (widgetParent) { if (arguments.length === 0) { return options.widgetParent; } if (typeof widgetParent === 'string') { widgetParent = $(widgetParent); } if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof jQuery))) { throw new TypeError('widgetParent() expects a string or a jQuery object parameter'); } options.widgetParent = widgetParent; if (widget) { hide(); show(); } return picker; }; picker.keepOpen = function (keepOpen) { if (arguments.length === 0) { return options.format; } if (typeof keepOpen !== 'boolean') { throw new TypeError('keepOpen() expects a boolean parameter'); } options.keepOpen = keepOpen; return picker; }; // initializing element and component attributes if (element.is('input')) { input = element; } else { input = element.find('.datepickerinput'); if (input.size() === 0) { input = element.find('input'); } else if (!input.is('input')) { throw new Error('CSS class "datepickerinput" cannot be applied to non input element'); } } if (element.hasClass('input-group')) { // in case there is more then one 'input-group-addon' Issue #48 if (element.find('.datepickerbutton').size() === 0) { component = element.find('[class^="input-group-"]'); } else { component = element.find('.datepickerbutton'); } } if (!input.is('input')) { throw new Error('Could not initialize DateTimePicker without an input element'); } $.extend(true, options, dataToOptions()); picker.options(options); initFormatting(); attachDatePickerElementEvents(); if (input.prop('disabled')) { picker.disable(); } if (input.val().trim().length !== 0) { setValue(parseInputDate(input.val().trim())); } else if (options.defaultDate) { setValue(options.defaultDate); } return picker; }; /******************************************************************************** * * jQuery plugin constructor and defaults object * ********************************************************************************/ $.fn.datetimepicker = function (options) { return this.each(function () { var $this = $(this); if (!$this.data('DateTimePicker')) { // create a private copy of the defaults object options = $.extend(true, {}, $.fn.datetimepicker.defaults, options); $this.data('DateTimePicker', dateTimePicker($this, options)); } }); }; $.fn.datetimepicker.defaults = { format: false, dayViewHeaderFormat: 'MMMM YYYY', extraFormats: false, stepping: 1, minDate: false, maxDate: false, useCurrent: true, collapse: true, locale: moment.locale(), defaultDate: false, disabledDates: false, enabledDates: false, icons: { time: 'glyphicon glyphicon-time', date: 'glyphicon glyphicon-calendar', up: 'glyphicon glyphicon-chevron-up', down: 'glyphicon glyphicon-chevron-down', previous: 'glyphicon glyphicon-chevron-left', next: 'glyphicon glyphicon-chevron-right', today: 'glyphicon glyphicon-screenshot', clear: 'glyphicon glyphicon-trash' }, useStrict: false, sideBySide: false, daysOfWeekDisabled: [], calendarWeeks: false, viewMode: 'days', toolbarPlacement: 'default', showTodayButton: false, showClear: false, widgetPositioning: { horizontal: 'auto', vertical: 'auto' }, widgetParent: null, keepOpen: false }; }));