All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gwt.material.design.addins.client.timepicker.resources.js.timepicker.js Maven / Gradle / Ivy

There is a newer version: 2.8.3
Show newest version
/*!
 * Lolliclock v0.1.0
 * Matthew Krick 2015
 * Inspired by Google's material design & ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/)
 */

;
(function () {
    var $ = window.jQuery;

    // Default options
    LolliClock.DEFAULTS = {
        startTime: '',	      // default time, '' or 'now' or 'H:MM AM'
        autoclose: false,    	// show Cancel/OK buttons
        vibrate: true,        // vibrate the device when dragging clock hand
        hour24:false,
        orientation:"portrait"
    };

    // Listen touch events in touch screen device, instead of mouse events in desktop.
    var touchSupported = 'ontouchstart' in window;
    var mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : '');
    var mousemoveEvent = 'mousemove.lolliclock' + ( touchSupported ? ' touchmove.lolliclock' : '');
    var mouseupEvent = 'mouseup.lolliclock' + ( touchSupported ? ' touchend.lolliclock' : '');

    // Vibrate the device if supported
    var vibrate = navigator.vibravarte ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null;

    var svgNS = 'http://www.w3.org/2000/svg';

    function createSvgElement(name) {
        return document.createElementNS(svgNS, name);
    }

    function leadingZero(num) {
        return (num < 10 ? '0' : '') + num;
    }

    // Get a unique id
    var idCounter = 0;

    function uniqueId(prefix) {
        var id = ++idCounter + '';
        return prefix ? prefix + id : id;
    }

    // Clock size
    var dialRadius = 84;
    var radius = 50;
    var outSizeRadius = 70;
    var tickRadius = 12;
    var diameter = dialRadius * 2;
    var duration = 350;

    // Popover template
    var tpl = [
        '
', '
', '
', '
', '
', '
', '
', '
', ':', '
', '
', '
', '
', '
', '', '
', '
', '
', '
', '
', '
', '
', '
', '
', '
', '
AM
', '
', '
', '
', '
', '
PM
', '
', '
', '
', '
', '
' ].join(''); // LolliClock function LolliClock(element, options) { var popover = $(tpl); var main = popover.find('.lolliclock-popover'); var plate = popover.find('.lolliclock-plate'); var hoursView = popover.find('.lolliclock-dial-hours'); var minutesView = popover.find('.lolliclock-dial-minutes'); var isInput = element.prop('tagName') === 'INPUT'; var input = isInput ? element : element.find('input'); var self = this; this.id = uniqueId('lolli'); this.element = element; this.options = options; this.isAppended = false; this.isShown = false; this.currentView = 'hours'; this.isInput = isInput; this.input = input; this.popover = popover; this.plate = plate; this.hoursView = hoursView; this.minutesView = minutesView; this.header = popover.find('.lolliclock-header'); this.spanHours = popover.find('.lolliclock-hours'); this.spanMinutes = popover.find('.lolliclock-minutes'); this.spanNewTime = popover.find('.lolliclock-time-new'); this.spanOldTime = popover.find('.lolliclock-time-old'); this.spanAmPm = popover.find('.lolliclock-am-pm'); this.amOrPm = "PM"; this.AmPmButtons = popover.find('.lolliclock-ampm-btn'); this.amButton = popover.find('#lolliclock-btn-am'); this.pmButton = popover.find('#lolliclock-btn-pm'); if(this.options.hour24) { this.AmPmButtons.hide(); this.spanAmPm.hide(); } popover.addClass(this.options.orientation); //var exportName = (this.input[0].name || this.input[0].id) + '-export'; //this.dateTimeVal = $('').insertAfter(input); // If autoclose is not setted, append a button if (!options.autoclose) { this.popover.css('height', '380px'); var $closeButtons = $('
').appendTo(main); $('
Cancel
') .click($.proxy(this.hide, this)) .appendTo($closeButtons); $('
OK
') .click($.proxy(this.done, this)) .appendTo($closeButtons); this.closeButtons = popover.find('.lolliclock-button'); } // Show or toggle input.on('focus.lolliclock click.lolliclock', $.proxy(this.show, this)); // Build ticks var tickTpl = $('
'); var i, tick, radian; // Hours view if(options.hour24) { for (i = 1; i < 13; i++) { tick = tickTpl.clone(); radian = i / 6 * Math.PI; tick.css({ left: dialRadius + Math.sin(radian) * radius - tickRadius, top: dialRadius - Math.cos(radian) * radius - tickRadius }); tick.html(i); hoursView.append(tick); } for (i = 13; i <= 24; i++) { tick = tickTpl.clone(); radian = (i / 6) * Math.PI; tick.css({ left: dialRadius + Math.sin(radian) * outSizeRadius - tickRadius, top: dialRadius - Math.cos(radian) * outSizeRadius - tickRadius }); if(i === 24) { tick.html("00"); } else { tick.html(i); } hoursView.append(tick); } } else { for (i = 1; i < 13; i++) { tick = tickTpl.clone(); radian = i / 6 * Math.PI; tick.css({ left: dialRadius + Math.sin(radian) * outSizeRadius - tickRadius, top: dialRadius - Math.cos(radian) * outSizeRadius - tickRadius }); tick.html(i); hoursView.append(tick); } } // Minutes view for (i = 0; i < 60; i += 5) { tick = tickTpl.clone(); radian = i / 30 * Math.PI; tick.css({ left: dialRadius + Math.sin(radian) * outSizeRadius - tickRadius, top: dialRadius - Math.cos(radian) * outSizeRadius - tickRadius }); tick.html(leadingZero(i)); minutesView.append(tick); } //Move click to nearest tick plate.on(mousedownEvent, mousedown); // Mousedown or touchstart function mousedown(e) { var offset = plate.offset(), isTouch = /^touch/.test(e.type), x0 = offset.left + dialRadius, y0 = offset.top + dialRadius, dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0, z = Math.sqrt(dx * dx + dy * dy), moved = false; outsideMode = true; // Ignore plate clicks that aren't even close if (z< outSizeRadius + tickRadius && z> outSizeRadius - tickRadius) { outsideMode = true } else if (z > radius - tickRadius && z < radius + tickRadius && options.hour24 && self.currentView === 'hours') { outsideMode = false } else { return } e.preventDefault(); $(document.body).addClass('lolliclock-moving'); // Place the canvas to top plate.append(self.canvas); // Clock self.setHand(dx, dy, outsideMode); // Mousemove on document $(document).off(mousemoveEvent).on(mousemoveEvent, function (e) { e.preventDefault(); var isTouch = /^touch/.test(e.type), x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0; if (!moved && x === dx && y === dy) { // Clicking in chrome on windows will trigger a mousemove event return; } moved = true; self.setHand(x, y, outsideMode); }); // Mouseup on document $(document).off(mouseupEvent).on(mouseupEvent, function (e) { e.preventDefault(); var isTouch = /^touch/.test(e.type), x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0, y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0; if (x === dx && y === dy) { self.setHand(x, y, outsideMode); } if (self.currentView === 'hours') { self.toggleView('minutes', duration / 2); } else if (options.autoclose) { self.done(); } plate.prepend(canvas); // Reset mouse cursor $(document.body).removeClass('lolliclock-moving'); // Unbind mousemove event $(document).off(mousemoveEvent); $(document).off(mouseupEvent); }); } // Draw clock SVG var canvas = popover.find('.lolliclock-canvas'); var svg = createSvgElement('svg'); svg.setAttribute('class', 'lolliclock-svg'); svg.setAttribute('width', diameter); svg.setAttribute('height', diameter); var g = createSvgElement('g'); g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); var bearing = createSvgElement('circle'); bearing.setAttribute('class', 'lolliclock-bearing'); bearing.setAttribute('cx', 0); bearing.setAttribute('cy', 0); bearing.setAttribute('r', 1.25); var hand = createSvgElement('line'); hand.setAttribute('x1', 0); hand.setAttribute('y1', 0); var bg = createSvgElement('circle'); bg.setAttribute('class', 'lolliclock-canvas-bg'); bg.setAttribute('r', tickRadius); var fg = createSvgElement('circle'); fg.setAttribute('class', 'lolliclock-canvas-fg'); fg.setAttribute('r', 3.5); g.appendChild(hand); g.appendChild(bg); g.appendChild(fg); g.appendChild(bearing); svg.appendChild(g); canvas.append(svg); this.hand = hand; this.bg = bg; this.fg = fg; this.bearing = bearing; this.g = g; this.canvas = canvas; raiseCallback(this.options.init); } function raiseCallback(callbackFunction) { if (callbackFunction && typeof callbackFunction === "function") { callbackFunction(); } } // Show or hide popover LolliClock.prototype.toggle = function () { this[this.isShown ? 'hide' : 'show'](); }; // Show or hide popover LolliClock.prototype.setOrientation = function (orientation) { this.popover.removeClass(this.options.orientation); this.options.orientation = orientation; this.popover.addClass(orientation); }; LolliClock.prototype.changeAmPm = function (isAmOrPm) { if (!!isAmOrPm && isAmOrPm === this.amOrPm && this.options.hour24) return; this.amOrPm = this.amOrPm === 'AM' ? 'PM' : 'AM'; this.spanAmPm.html(this.amOrPm); $(this.amButton[0].childNodes[0]).toggleClass('lolliclock-active-button-background', (this.amOrPm === 'AM')); $(this.pmButton[0].childNodes[0]).toggleClass('lolliclock-active-button-background', (this.amOrPm === 'PM')); $(this.amButton[0].childNodes[1]).toggleClass('lolliclock-active-button-text', (this.amOrPm === 'AM')); $(this.pmButton[0].childNodes[1]).toggleClass('lolliclock-active-button-text', (this.amOrPm === 'PM')); }; // Set popover position, keep it on screen no matter how it's scrolled LolliClock.prototype.locate = function () { var element = this.element; var popover = this.popover; var popoverMargin = 8; var leftOffset = element.offset().left + (element.outerWidth() - popover.width()) / 2; var maxLeft = $(window).width() - popover.width() - popoverMargin; var minLeft = popoverMargin; var maxTop = $(window).height() + $(window).scrollTop() - popoverMargin - popover.height(); var minTop = popoverMargin + $(window).scrollTop(); var topOffset = element.offset().top; var styles = {}; styles.top = topOffset < minTop ? minTop : topOffset > maxTop ? maxTop : topOffset; styles.left = leftOffset < minLeft ? minLeft : leftOffset > maxLeft ? maxLeft : leftOffset; popover.css(styles); popover.show(); }; // Show popover LolliClock.prototype.show = function () { //this.input.trigger('blur'); if (this.isShown) { return; } raiseCallback(this.options.beforeShow); var self = this; this.popover.addClass(this.options.orientation); // Initialize if (!this.isAppended) { // Append popover to body $(document.body).append(this.popover); this.isAppended = true; // Reset position when resize $(window).on('resize.lolliclock' + this.id, function () { if (self.isShown) { self.locate(); } }); // Reset position on scroll $(window).on('scroll.lolliclock', function () { if (self.isShown) { self.locate(); } }); //Add listeners this.AmPmButtons.on('click', function (e) { self.changeAmPm(e.currentTarget.children[1].innerHTML); }); this.spanMinutes.on('click', function () { self.toggleView('minutes'); }); this.spanHours.on('click', function () { self.toggleView('hours'); }); this.spanAmPm.on('click', function () { self.changeAmPm(); }); } // Set position self.locate(); //animate show this.plate.addClass('animate'); this.header.addClass('animate'); this.popover.addClass('animate'); this.AmPmButtons.addClass('animate'); this.spanNewTime.addClass('animate'); this.spanOldTime.addClass('animate'); !this.options.autoclose && this.closeButtons.addClass('animate'); this.plate.on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function () { self.plate.removeClass("animate"); self.header.removeClass("animate"); self.popover.removeClass("animate"); self.AmPmButtons.removeClass("animate"); self.spanNewTime.removeClass("animate"); self.spanOldTime.removeClass("animate"); !self.options.autoclose && self.closeButtons.removeClass("animate"); self.plate.off('webkitAnimationEnd animationend MSAnimationEnd oanimationend'); }); //Get the time function timeToDate(time) { var parts = time.split(':'); if (parts.length === 2){ var hours = +parts[0]; var minAM = parts[1].split(' '); if (minAM.length === 2) { var mins = minAM[0]; if (minAM[1] === 'PM') hours += 12; return new Date(1970, 1, 1, hours, mins); } } return new Date('x'); } function isValidTime(time) { return !isNaN(timeToDate(time).getTime()); } var value; var inputValue = this.input.prop('value'); var defaultValue = this.options.startTime; var placeholderValue = this.input.prop('placeholder'); if (inputValue && isValidTime(inputValue)) { value = timeToDate(inputValue); } else if (defaultValue === 'now') { value = new Date(); } else if (defaultValue && isValidTime(defaultValue)) { value = timeToDate(defaultValue); } else if (placeholderValue && isValidTime(placeholderValue)) { value = timeToDate(placeholderValue); } else { value = new Date(); } if(this.options.hour24) { this.hours = value.getHours() } else { this.hours = value.getHours()%12; this.amOrPm = value.getHours() > 11 ? "AM" : "PM"; } this.minutes = value.getMinutes(); //purposefully wrong because we change it next line this.changeAmPm(); // Set time self.toggleView('minutes'); self.toggleView('hours'); self.isShown = true; // Hide when clicking or tabbing on any element except the clock, input $(document).on('click.lolliclock.' + this.id + ' focusin.lolliclock.' + this.id, function (e) { var target = $(e.target); if (target.closest(self.popover).length === 0 && target.closest(self.input).length === 0) { self.done(); } }); // Hide when ESC is pressed $(document).on('keyup.lolliclock.' + this.id, function (e) { if (e.keyCode === 27) { self.hide(); } }); raiseCallback(this.options.afterShow); }; // Hide popover LolliClock.prototype.hide = function () { raiseCallback(this.options.beforeHide); //animate out var self = this; self.popover.addClass('animate-out'); self.plate.addClass("animate-out"); self.header.addClass("animate-out"); self.AmPmButtons.addClass("animate-out"); !self.options.autoclose && self.closeButtons.addClass('animate-out'); this.popover.on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function () { $(self.spanHours[0].childNodes[0]).html(''); $(self.spanMinutes[0].childNodes[0]).html(''); self.popover.removeClass("animate-out"); self.plate.removeClass("animate-out"); self.header.removeClass("animate-out"); self.AmPmButtons.removeClass("animate-out"); !self.options.autoclose && self.closeButtons.removeClass("animate-out"); self.popover.off('webkitAnimationEnd animationend MSAnimationEnd oanimationend'); // Unbinding events on document $(document).off('click.lolliclock.' + self.id + ' focusin.lolliclock.' + self.id); $(document).off('keyup.lolliclock.' + self.id); self.popover.hide(); raiseCallback(self.options.afterHide); } ); self.isShown = false; }; // Toggle to hours or minutes view LolliClock.prototype.toggleView = function (view, delay) { var isHours = view === 'hours'; var nextView = isHours ? this.hoursView : this.minutesView; var hideView = isHours ? this.minutesView : this.hoursView; this.currentView = view; this.spanHours.toggleClass('lolliclock-primary-text', isHours); this.spanMinutes.toggleClass('lolliclock-primary-text', !isHours); // Let's make transitions hideView.addClass('lolliclock-dial-out'); nextView.css('visibility', 'visible').removeClass('lolliclock-dial-out'); // Reset clock hand this.resetClock(delay); // After transitions ended clearTimeout(this.toggleViewTimer); this.toggleViewTimer = setTimeout(function () { hideView.css('visibility', 'hidden'); }, duration); //Add pointer mouse cursor to show you can click between ticks if (isHours) { this.plate.off(mousemoveEvent); } else { var self = this; this.plate.on(mousemoveEvent, function (e) { var offset = self.plate.offset(), x0 = offset.left + dialRadius, y0 = offset.top + dialRadius, dx = e.pageX - x0, dy = e.pageY - y0, z = Math.sqrt(dx * dx + dy * dy); if (z > outSizeRadius - tickRadius && z < outSizeRadius + tickRadius) { $(document.body).addClass('lolliclock-clickable'); } else { $(document.body).removeClass('lolliclock-clickable'); } }); } }; // Reset clock hand LolliClock.prototype.resetClock = function (delay) { var view = this.currentView, outSizeMode = true, value = this[view], isHours = view === 'hours'; if(isHours) { unit = Math.PI / 6; if(value !== 0 && value <=12 && this.options.hour24) { outSizeMode = false; } } else { unit = Math.PI / 30 } var radian = value * unit, x = Math.sin(radian) * radius, y = -Math.cos(radian) * radius, self = this; if (delay) { self.canvas.addClass('lolliclock-canvas-out'); setTimeout(function () { self.canvas.removeClass('lolliclock-canvas-out'); self.setHand(x, y, outSizeMode); }, delay); } else { this.setHand(x, y, outSizeMode); } }; // Set clock hand to (x, y) LolliClock.prototype.setHand = function (x, y, outSizeMode) { //Keep radians postive from 1 to 2pi var radian = Math.atan2(-x, y) + Math.PI; var isHours = this.currentView === 'hours'; var unit = Math.PI / (isHours ? 6 : 30); var value; // Get the round value if(outSizeMode && this.options.hour24 && isHours) { value = Math.round(radian / unit); if(value === 12 || value ===0) { value = 0; } else { value += 12; } } else { value = Math.round(radian / unit); } // Get the round radian radian = value * unit; // Correct the hours or minutes if (isHours) { if (value === 0 && !(this.options.hour24 && outSizeMode)) { value = 12; } this.fg.style.visibility = 'hidden'; } else { var isOnNum = (value % 5 === 0); if (isOnNum) { this.fg.style.visibility = 'hidden'; } else { this.fg.style.visibility = 'visible'; } if (value === 60) { value = 0; } } // Once hours or minutes changed, vibrate the device if (this[this.currentView] !== value) { if (vibrate && this.options.vibrate) { // Do not vibrate too frequently if (!this.vibrateTimer) { navigator[vibrate](10); this.vibrateTimer = setTimeout($.proxy(function () { this.vibrateTimer = null; }, this), 100); } } } //TODO: Keep tens digit static for changing hours this[this.currentView] = value; function cleanupAnimation($obj) { $obj.on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function () { $oldTime.html(value); //only needed for -up transitions $oldTime.removeClass("old-down old-up"); $newTime.removeClass("new-down new-up"); $oldTime.off('webkitAnimationEnd animationend MSAnimationEnd oanimationend'); }); } var $oldTime; var $newTime; if (isHours) { $oldTime = $(this.spanHours[0].childNodes[0]); $newTime = $(this.spanHours[0].childNodes[1]); if(this.options.hour24) { value = leadingZero(value); } } else { $oldTime = $(this.spanMinutes[0].childNodes[0]); $newTime = $(this.spanMinutes[0].childNodes[1]); value = leadingZero(value); } cleanupAnimation($oldTime); if (value < (+$oldTime.html())) { $newTime.html($oldTime.html()); $oldTime.html(value); $newTime.addClass('new-down'); $oldTime.addClass('old-down'); } else if (value > (+$oldTime.html()) || !$oldTime.html()) { $newTime.html(value); $oldTime.addClass('old-up'); $newTime.addClass('new-up'); } this.g.insertBefore(this.hand, this.bearing); this.g.insertBefore(this.bg, this.fg); this.bg.setAttribute('class', 'lolliclock-canvas-bg'); // Set clock hand and others' position var r = radius; if (outSizeMode) { r = outSizeRadius } var cx = Math.sin(radian) * r, cy = -Math.cos(radian) * r; this.hand.setAttribute('x2', Math.sin(radian) * (r - tickRadius)); this.hand.setAttribute('y2', -Math.cos(radian) * (r - tickRadius)); this.bg.setAttribute('cx', cx); this.bg.setAttribute('cy', cy); this.fg.setAttribute('cx', cx); this.fg.setAttribute('cy', cy); }; // Hours and minutes are selected LolliClock.prototype.done = function () { raiseCallback(this.options.beforeDone); var last = this.input.prop('value'); var value = ""; if(!this.options.hour24) { value = this.hours + ':' + leadingZero(this.minutes) + " " + this.amOrPm; } else { value = leadingZero(this.hours) + ':' + leadingZero(this.minutes) ; } if (value !== last) { this.input.prop('value', value); this.input.trigger('input'); this.input.trigger('change'); } this.hide(); }; // Remove lolliclock from input LolliClock.prototype.remove = function () { this.element.removeData('lolliclock'); this.input.off('focus.lolliclock click.lolliclock'); if (this.isShown) { this.hide(); } if (this.isAppended) { $(window).off('resize.lolliclock' + this.id); $(window).off('scroll.lolliclock' + this.id); this.popover.remove(); } }; // Extends $.fn.lolliclock $.fn.lolliclock = function (option) { var args = Array.prototype.slice.call(arguments, 1); return this.each(function () { var $this = $(this), data = $this.data('lolliclock'); if (!data) { var options = $.extend({}, LolliClock.DEFAULTS, $this.data(), typeof option == 'object' && option); $this.data('lolliclock', new LolliClock($this, options)); } else { // Manual operatsions. show, hide, remove, e.g. if (typeof data[option] === 'function') { data[option].apply(data, args); } } }); }; }());




© 2015 - 2024 Weber Informatics LLC | Privacy Policy