Giter Site home page Giter Site logo

weareoutman / clockpicker Goto Github PK

View Code? Open in Web Editor NEW
2.0K 2.0K 536.0 1.01 MB

A clock-style timepicker for Bootstrap (or jQuery). Sorry but no longer maintained.

Home Page: http://weareoutman.github.io/clockpicker/

License: MIT License

JavaScript 82.46% CSS 17.54%

clockpicker's Introduction

Hi there 👋

About me

  • 🏠 Living & working in Shenzhen, China.
  • 👨‍💻 Things for making a living: JS/CSS/HTML, React, NodeJS.
  • ❤️ Love sports like 🏀 🏸 🏓 ⛰ ⛺️ 🚵‍♂️.
  • 😝 Fun fact: I fly drones 🚁 and make vlogs 🎬 sometimes!

clockpicker's People

Contributors

ericop avatar hermanya avatar weareoutman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clockpicker's Issues

Add "now" button in popup

Is it possible the add a property like "enableNowButton" and when is true, it will be visible in the tooltip?

Furthermore the AM/PM buttons could be using Bootstraps button group and the AM/PM button acts as a toggle buttons.

Here is two previews of how it could look:

image image

if twelvehour is false the AM/PM buttons are hidden, but still you could choose to use the "now" button.

Need seconds

Hello,

I tested your clock picker and it's really great !
Is it possible to add seconds, same display than minutes ???

Thanks a lot !

Bower

It'd be so great to have this plugin managed by bower ;)

Picker cannot be opened with touch screen devises second time if focus on it

Use some tablet or smartphone with touchscreen
Open picker first time, use drug and drop functionality to choose the time
After choosing minutes it is automatically closed
Open picker one more time
Expected result: it is opened
Actual result: It is opened for a second but then closed without any reason

Disable Hours

How can I disable hours ? (ex from(18:00) To (08:00) )

Setting minutes increment?

Hello. Is there any way to set / restrict the minutes to a certain increment? For example, to set an increment of "5" would only allow the minutes selection to be 0, 5, 10, 15.... As it is now, one can click and drag around the clock face for the minutes and select any minute.

Min Hours and Min Time

How can we add min hours and min time between two time pickers , like start time and end time. The end time should not before of the start time

15 Minute Increment

Hi, sorry if this is the wrong place to ask this but is it possible to set the minutes to display 0 15 30 45 only? I've found where I can set this for the display but when dragging it still goes up by 1 minute as you drag, would like it to snap to 0 15 30 45.

Hope that makes sense :)

Rich

'onclick' does not open a dialog when an input is focused

For example, if autoclose is on, when you selected a time, a focus is left in the input. If you click the input again, nothing happens. You have to remove focus manually (click somewhere out of the input) to make it work.
Seems like onclick does not toggle popup at all. Only onfocus works.

How to compare two times

Hello,

The plugin is very nice and easy to us it

i want to compare two times (range) and i dont found the solution for this

for example : the restaurant manager put two times : open and close , i must verify if time close is bigger then time open

thank's

Need function to get time value

The current output of the time presentation and the way to retrieve it ($('input.clockpicker').val()), is not always useful. Especially when using 12-hour notation, it forces me to write complex functions to convert it.

A way to get the time as an offset (e.g. seconds from midnite) would be useful. So, '10:00' would give us '36000' (or even in millisecs like '36000000'). This way, it can be easily used in calculations.

$('.clockcpicker').clockpicker('getTime') could produce a Date object (alike datepicker), so $('.clockcpicker').clockpicker('getTime').getTime() gives the required integer.

How can I limit minutes options?

Hello there, and thank you for this nice script.

We want to use it into one of our projects, but we really need to limit minutes selection to "00" and "30", and disallow any other selection.

Can this be achieved with your code? If not, any advice of where should we take a look?

Thank you in advanced for your help.

Please release this package on npm

Would be nice if I could just do npm install bootstrap-clockpicker.

You need to add a "main" entry to the package.json that points to the bootstrap-clockpicker source, and then use npm publish to push it to npm

reset time

hi, i made the input as read only but when a user want to rest the time to blank or none it's not possible so i suggest a reset button beside the validation button
thank you

Military time clock is confusing

Military time is not confusing, but this clock's implementation is.

The inner circle (morning) goes from 1-12. The outer circle (eveining) goes from 00 to 23.

Where would you logically click to select 12:30 in the afternoon? Try it.

Clicking the 12 sets the clock to AM. This is wrong. In military time, 12 is noon. Always.

The inner circle should start with 00 at the top, and go up to 11. The OUTER circle should start at 12 at the top and go to 23.

Where should one click for 'Midnight' is a logical question. Do you click on the top of the OUTER circle (the end of the day), or do you click on the top of the INNER circle (the start of the day)? I'm modifying the clock so that 00 is on the inside, and that is where you would click for midnight.

Change one: Move 12 to the outer circle, and 00 to the inner circle:

// Near line 185 of jquery-clickpicker.js
var inner = i > 0 && i < 13;  // Old line
var inner = i >= 0 && i < 12;  // New line

Change two: Correct the 'Radius =' line for inner/outer.

// Near line 548 of jquery-clockpicker.js
radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius, // old
radius = isHours && value >= 0 && value < 12 ? innerRadius : outerRadius, // new

Change three: Correct the detection of the swap of 00 and 12.

// Near line 600 of jquery-clockpicker.js
// ----- "if (isHours)" section. --------
// Replace the three IF statements, with the below statements.
            if (! options.twelvehour ) {

                if (inner && value === 12 ) {
                    value = 0;
                }
                if (! inner && value === 0 ) {
                    value = 12;
                }
                if (! inner && value < 12 ) {
                    value += 12;
                }
            }
            if (options.twelvehour && value === 0) {
                value = 12;
            }
            if (value === 24) {
                value = 0;
            }

Offers

Please implement more events with options extending.
For example:
I need an function after function done, I extended, but now I need to merge with you.
As for me it would be great to has functions like:

init, beforeShow, afterShow, beforeDone, afterDone, beforeHourSelect, afterHourSelect

then your plugin will be more flexible. thanks.

inline clock component

I tested your picker and find it very nice.
Is it planned to use the clockpicker inline in a form, and not in a bootstrap popover. I would like to use it directly in a bootstrap modal.

Thank you in advance !

Bower Package differs from zip file

Hey,

I installed the clockpicker via bower and the version is not the same as the one in the zip file. I.e. I can't use events with the bower version. Is this planned to be updated?

Thanks

Readonly property

You could add a readonly property as a clockpicker option like this;:

Options
Name Default Description
readonly false (true, flase)

and then the plugin add automatically this property in input tag:

How minute step fixed on 5

Hi, i would fixed a step 5 by 5 min , like the minute on the display not between like 16min or 54 just 05-00-05-10-15-20-25-30-35-40-45-50-55-. I search in jquery.clockpicker-min.js but its hard; If anybody know how//

i have check he other post on 30 minute step and doesb't run for me

Thanks

When using two clockPicker in the same form, the second one does not function!

I'm a newbie and using this in an MVC project. In a "Create" view I have used two fields as clockPicker (start and end time). First one works like a charm but the second one does not function.
I do not know if this is the right place to bring this up. Here's my code in Create view:

@Html.EditorFor(model => model.StringStartTime, new { htmlAttributes = new { @Class = "form-control clockPicker", id = "single-input", value = "", placeholder = "اکنون" } })

@Html.EditorFor(model => model.StringEndTime, new { htmlAttributes = new { @Class = "form-control clockPicker", id = "single-input", value = "", placeholder = "اکنون" } })

Can't have autoclose && "done" button

Seems one can only have autoclose OR the "done" button, but not both, I'd love to have both.

When using the "Done" button, clicking out of the clockpicker closes it without setting the time selected

How to have to visible clockpickers at the same time?

Hi.

I would like to have two visible clockpickers concurrently.

inputa.clockpicker().clockpicker("show");
inputb.clockpicker().clockpicker("show");

The problem is that when you click on one, the other one dissapears.

Allowing submission on clicking am/pm rather than minute pickers/items

Hi,

I needed a feature where I wanted to let the timepicker submit on clicking on AM/PM rather than the minute hands. Since it seems like the owner of the project has been inactive for quite some time I thought I would fork the project myself and implement the feature. It didn't take much time really (just a couple of minutes).

I thought it might help someone else who is in search of similar functionality. You'll find the functionality on my fork - https://github.com/rishabhp/clockpicker

My fork is a fork of https://github.com/JordyMoos/clockpicker which has several other interesting features like hours and minute steps (really needed that in my project). I've even opened a PR on that project for this same functionality that I implemented JordyMoos#2

Hope that'll help someone else in search of true enlightenment!

Difference btw tag 0.0.7 and main branch.

Hi, after drive me crazy trying to understand why afterShow does not trigger on the options. I checked the code on master vs release 0.0.7, and this tag, does not have this option.

Idk if is missing other options, plz, re release the tag 0.0.7 to match the current documentation with the api.

How to use BeforeDone/AfterDone events?

You have appended meridiem(AM/PM) with the time without a separator. So, I want to add space between time and meridiem. Can I use BeforeDone/AfterDone events and if yes, how to use? if not, how can I add separator?

Thanks

Bower version: No RaiseCallback

Very nice plugin! Just encountered a problem with the bower version (0.0.7). The raiseCallback calls are nowhere to be found in that version. Is that intended?

12 hour clock option

Is it currently possible to use a 12 hour clock instead of 24 hour?

If it isnt already implemented, perhaps it could be added? Possibly could show an AM / PM next t select time which could be clicked on to toggle between the 2 which in the backend would then convert the PM time to a time great than 12.

For example if you select 2 and PM it would then save the time as 14 but would show 2 PM to the user on the clock UI

Below shows the 24 hours clock

2015-08-13_14-52-03

A fix for AM/PM issues

I noticed when setting the default value to a time with AM or PM, with twelvehour=true, it wouldn't get reflected in the popup title or button focus. So I added that functionality.

I don't know how to post that in Github, so I'm just going to post it here if you want to add it or if anyone needs it.

; (function () {
    var $ = window.jQuery,
        $win = $(window),
        $doc = $(document),
        $body;

    // Can I use inline svg ?
    var svgNS = 'http://www.w3.org/2000/svg',
        svgSupported = 'SVGAngle' in window && (function () {
            var supported,
                el = document.createElement('div');
            el.innerHTML = '<svg/>';
            supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS;
            el.innerHTML = '';
            return supported;
        })();

    // Can I use transition ?
    var transitionSupported = (function () {
        var style = document.createElement('div').style;
        return 'transition' in style ||
            'WebkitTransition' in style ||
            'MozTransition' in style ||
            'msTransition' in style ||
            'OTransition' in style;
    })();

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

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

    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 = 100,
        outerRadius = 80,
        // innerRadius = 80 on 12 hour clock
        innerRadius = 54,
        tickRadius = 13,
        diameter = dialRadius * 2,
        duration = transitionSupported ? 350 : 1;

    // Popover template
    var tpl = [
        '<div class="popover clockpicker-popover">',
            '<div class="arrow"></div>',
            '<div class="popover-title">',
                '<span class="clockpicker-span-hours text-primary"></span>',
                ' : ',
                '<span class="clockpicker-span-minutes"></span>',
                '<span class="clockpicker-span-am-pm"></span>',
            '</div>',
            '<div class="popover-content">',
                '<div class="clockpicker-plate">',
                    '<div class="clockpicker-canvas"></div>',
                    '<div class="clockpicker-dial clockpicker-hours"></div>',
                    '<div class="clockpicker-dial clockpicker-minutes clockpicker-dial-out"></div>',
                '</div>',
                '<span class="clockpicker-am-pm-block">',
                '</span>',
            '</div>',
        '</div>'
    ].join('');

    function AmOrPm(v) {
        if (!v)
            return "PM";

        if (v.toUpperCase().indexOf("AM") != -1)
            return "AM";

        if (v.toUpperCase().indexOf("PM") != -1)
            return "PM";

        return "PM";
    }

    // ClockPicker
    function ClockPicker(element, options) {
        var popover = $(tpl),
            plate = popover.find('.clockpicker-plate'),
            hoursView = popover.find('.clockpicker-hours'),
            minutesView = popover.find('.clockpicker-minutes'),
            amPmBlock = popover.find('.clockpicker-am-pm-block'),
            isInput = element.prop('tagName') === 'INPUT',
            input = isInput ? element : element.find('input'),
            addon = element.find('.input-group-addon'),
            self = this,
            timer;

        this.id = uniqueId('cp');
        this.element = element;
        this.options = options;
        this.isAppended = false;
        this.isShown = false;
        this.currentView = 'hours';
        this.isInput = isInput;
        this.input = input;
        this.addon = addon;
        this.popover = popover;
        this.plate = plate;
        this.hoursView = hoursView;
        this.minutesView = minutesView;
        this.amPmBlock = amPmBlock;
        this.spanHours = popover.find('.clockpicker-span-hours');
        this.spanMinutes = popover.find('.clockpicker-span-minutes');
        this.spanAmPm = popover.find('.clockpicker-span-am-pm');
        this.amOrPm = "PM";

        // Setup for for 12 hour clock if option is selected
        if (options.twelvehour) {

            var amPmButtonsTemplate = ['<div class="clockpicker-am-pm-block">',
                '<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-am-button">',
                'AM</button>',
                '<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-pm-button">',
                'PM</button>',
                '</div>'].join('');

            var amPmButtons = $(amPmButtonsTemplate);
            //amPmButtons.appendTo(plate);

            ////Not working b/c they are not shown when this runs
            //$('clockpicker-am-button')
            //    .on("click", function() {
            //        self.amOrPm = "AM";
            //        $('.clockpicker-span-am-pm').empty().append('AM');
            //    });
            //    
            //$('clockpicker-pm-button')
            //    .on("click", function() {
            //         self.amOrPm = "PM";
            //        $('.clockpicker-span-am-pm').empty().append('PM');
            //    });

            $('<button type="button" class="btn btn-sm btn-default clockpicker-button am-button">' + "AM" + '</button>')
                .on("click", function () {
                    self.amOrPm = "AM";
                    $('.clockpicker-span-am-pm').empty().append('AM');
                }).appendTo(this.amPmBlock);


            $('<button type="button" class="btn btn-sm btn-default clockpicker-button pm-button">' + "PM" + '</button>')
                .on("click", function () {
                    self.amOrPm = 'PM';
                    $('.clockpicker-span-am-pm').empty().append('PM');
                }).appendTo(this.amPmBlock);

        }

        if (!options.autoclose) {
            // If autoclose is not setted, append a button
            $('<button type="button" class="btn btn-sm btn-default btn-block clockpicker-button">' + options.donetext + '</button>')
                .click($.proxy(this.done, this))
                .appendTo(popover);
        }

        // Placement and arrow align - make sure they make sense.
        if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left';
        if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top';

        popover.addClass(options.placement);
        popover.addClass('clockpicker-align-' + options.align);

        this.spanHours.click($.proxy(this.toggleView, this, 'hours'));
        this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes'));

        // Show or toggle
        input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this));
        addon.on('click.clockpicker', $.proxy(this.toggle, this));

        // Build ticks
        var tickTpl = $('<div class="clockpicker-tick"></div>'),
            i, tick, radian, radius;

        // Hours view
        if (options.twelvehour) {
            for (i = 1; i < 13; i += 1) {
                tick = tickTpl.clone();
                radian = i / 6 * Math.PI;
                radius = outerRadius;
                tick.css('font-size', '120%');
                tick.css({
                    left: dialRadius + Math.sin(radian) * radius - tickRadius,
                    top: dialRadius - Math.cos(radian) * radius - tickRadius
                });
                tick.html(i === 0 ? '00' : i);
                hoursView.append(tick);
                tick.on(mousedownEvent, mousedown);
            }
        } else {
            for (i = 0; i < 24; i += 1) {
                tick = tickTpl.clone();
                radian = i / 6 * Math.PI;
                var inner = i > 0 && i < 13;
                radius = inner ? innerRadius : outerRadius;
                tick.css({
                    left: dialRadius + Math.sin(radian) * radius - tickRadius,
                    top: dialRadius - Math.cos(radian) * radius - tickRadius
                });
                if (inner) {
                    tick.css('font-size', '120%');
                }
                tick.html(i === 0 ? '00' : i);
                hoursView.append(tick);
                tick.on(mousedownEvent, mousedown);
            }
        }

        // Minutes view
        for (i = 0; i < 60; i += 5) {
            tick = tickTpl.clone();
            radian = i / 30 * Math.PI;
            tick.css({
                left: dialRadius + Math.sin(radian) * outerRadius - tickRadius,
                top: dialRadius - Math.cos(radian) * outerRadius - tickRadius
            });
            tick.css('font-size', '120%');
            tick.html(leadingZero(i));
            minutesView.append(tick);
            tick.on(mousedownEvent, mousedown);
        }

        // Clicking on minutes view space
        plate.on(mousedownEvent, function (e) {
            if ($(e.target).closest('.clockpicker-tick').length === 0) {
                mousedown(e, true);
            }
        });

        // Mousedown or touchstart
        function mousedown(e, space) {
            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;

            // When clicking on minutes view space, check the mouse position
            if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) {
                return;
            }
            e.preventDefault();

            // Set cursor style of body after 200ms
            var movingTimer = setTimeout(function () {
                $body.addClass('clockpicker-moving');
            }, 200);

            // Place the canvas to top
            if (svgSupported) {
                plate.append(self.canvas);
            }

            // Clock
            self.setHand(dx, dy, !space, true);

            // Mousemove on document
            $doc.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, false, true);
            });

            // Mouseup on document
            $doc.off(mouseupEvent).on(mouseupEvent, function (e) {
                $doc.off(mouseupEvent);
                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 ((space || moved) && x === dx && y === dy) {
                    self.setHand(x, y);
                }
                if (self.currentView === 'hours') {
                    self.toggleView('minutes', duration / 2);
                } else {
                    if (options.autoclose) {
                        self.minutesView.addClass('clockpicker-dial-out');
                        setTimeout(function () {
                            self.done();
                        }, duration / 2);
                    }
                }
                plate.prepend(canvas);

                // Reset cursor style of body
                clearTimeout(movingTimer);
                $body.removeClass('clockpicker-moving');

                // Unbind mousemove event
                $doc.off(mousemoveEvent);
            });
        }

        if (svgSupported) {
            // Draw clock hands and others
            var canvas = popover.find('.clockpicker-canvas'),
                svg = createSvgElement('svg');
            svg.setAttribute('class', 'clockpicker-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', 'clockpicker-canvas-bearing');
            bearing.setAttribute('cx', 0);
            bearing.setAttribute('cy', 0);
            bearing.setAttribute('r', 2);
            var hand = createSvgElement('line');
            hand.setAttribute('x1', 0);
            hand.setAttribute('y1', 0);
            var bg = createSvgElement('circle');
            bg.setAttribute('class', 'clockpicker-canvas-bg');
            bg.setAttribute('r', tickRadius);
            var fg = createSvgElement('circle');
            fg.setAttribute('class', 'clockpicker-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();
        }
    }

    // Default options
    ClockPicker.DEFAULTS = {
        'default': '',       // default time, 'now' or '13:14' e.g.
        fromnow: 0,          // set default time to * milliseconds from now (using with default = 'now')
        placement: 'bottom', // clock popover placement
        align: 'left',       // popover arrow align
        donetext: '完成',    // done button text
        autoclose: false,    // auto close when minute is selected
        twelvehour: false, // change to 12 hour AM/PM clock from 24 hour
        vibrate: true        // vibrate the device when dragging clock hand
    };

    // Show or hide popover
    ClockPicker.prototype.toggle = function () {
        this[this.isShown ? 'hide' : 'show']();
    };

    // Set popover position
    ClockPicker.prototype.locate = function () {
        var element = this.element,
            popover = this.popover,
            offset = element.offset(),
            width = element.outerWidth(),
            height = element.outerHeight(),
            placement = this.options.placement,
            align = this.options.align,
            styles = {},
            self = this;

        popover.show();

        // Place the popover
        switch (placement) {
            case 'bottom':
                styles.top = offset.top + height;
                break;
            case 'right':
                styles.left = offset.left + width;
                break;
            case 'top':
                styles.top = offset.top - popover.outerHeight();
                break;
            case 'left':
                styles.left = offset.left - popover.outerWidth();
                break;
        }

        // Align the popover arrow
        switch (align) {
            case 'left':
                styles.left = offset.left;
                break;
            case 'right':
                styles.left = offset.left + width - popover.outerWidth();
                break;
            case 'top':
                styles.top = offset.top;
                break;
            case 'bottom':
                styles.top = offset.top + height - popover.outerHeight();
                break;
        }

        popover.css(styles);
    };

    // Show popover
    ClockPicker.prototype.show = function (e) {
        // Not show again
        if (this.isShown) {
            return;
        }

        raiseCallback(this.options.beforeShow);

        var self = this;

        // Initialize
        if (!this.isAppended) {
            // Append popover to body
            $body = $(document.body).append(this.popover);

            // Reset position when resize
            $win.on('resize.clockpicker' + this.id, function () {
                if (self.isShown) {
                    self.locate();
                }
            });

            this.isAppended = true;
        }

        // Get the time
        var value = ((this.input.prop('value') || this.options['default'] || '') + '');
        this.amOrPm = AmOrPm(value);
        value = value.split(':');

        if (value[0] === 'now') {
            var now = new Date(+new Date() + this.options.fromnow);
            value = [
                now.getHours(),
                now.getMinutes()
            ];
        }
        this.hours = +value[0] || 0;
        this.minutes = +value[1] || 0;
        this.spanHours.html(leadingZero(this.hours));
        this.spanMinutes.html(leadingZero(this.minutes));

        if (this.options.twelvehour)
            this.spanAmPm.html(this.amOrPm);


        // Toggle to hours view
        this.toggleView('hours');

        // Set position
        this.locate();

        this.isShown = true;

        // Hide when clicking or tabbing on any element except the clock, input and addon
        $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function (e) {
            var target = $(e.target);
            if (target.closest(self.popover).length === 0 &&
                    target.closest(self.addon).length === 0 &&
                    target.closest(self.input).length === 0) {
                self.hide();
            }
        });

        // Hide when ESC is pressed
        $doc.on('keyup.clockpicker.' + this.id, function (e) {
            if (e.keyCode === 27) {
                self.hide();
            }
        });

        raiseCallback(this.options.afterShow);
    };

    // Hide popover
    ClockPicker.prototype.hide = function () {
        raiseCallback(this.options.beforeHide);

        this.isShown = false;

        // Unbinding events on document
        $doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id);
        $doc.off('keyup.clockpicker.' + this.id);

        this.popover.hide();

        raiseCallback(this.options.afterHide);
    };

    // Toggle to hours or minutes view
    ClockPicker.prototype.toggleView = function (view, delay) {

        var _this = this;
        var raiseAfterHourSelect = false;
        if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") {
            raiseCallback(this.options.beforeHourSelect);
            raiseAfterHourSelect = true;
        }
        var isHours = view === 'hours',
            nextView = isHours ? this.hoursView : this.minutesView,
            hideView = isHours ? this.minutesView : this.hoursView;

        this.currentView = view;

        this.spanHours.toggleClass('text-primary', isHours);
        this.spanMinutes.toggleClass('text-primary', !isHours);

        // Let's make transitions
        hideView.addClass('clockpicker-dial-out');
        nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out');

        // Reset clock hand
        this.resetClock(delay);

        // After transitions ended
        clearTimeout(this.toggleViewTimer);
        this.toggleViewTimer = setTimeout(function () {

            if (_this.options.twelvehour)
                nextView.parents(".popover-content").find("." + _this.amOrPm.toLowerCase() + "-button").focus();

            hideView.css('visibility', 'hidden');
        }, duration);

        if (raiseAfterHourSelect) {
            raiseCallback(this.options.afterHourSelect);
        }
    };

    // Reset clock hand
    ClockPicker.prototype.resetClock = function (delay) {
        var view = this.currentView,
            value = this[view],
            isHours = view === 'hours',
            unit = Math.PI / (isHours ? 6 : 30),
            radian = value * unit,
            radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius,
            x = Math.sin(radian) * radius,
            y = -Math.cos(radian) * radius,
            self = this;
        if (svgSupported && delay) {
            self.canvas.addClass('clockpicker-canvas-out');
            setTimeout(function () {
                self.canvas.removeClass('clockpicker-canvas-out');
                self.setHand(x, y);
            }, delay);
        } else {
            this.setHand(x, y);
        }
    };

    // Set clock hand to (x, y)
    ClockPicker.prototype.setHand = function (x, y, roundBy5, dragging) {
        var radian = Math.atan2(x, -y),
            isHours = this.currentView === 'hours',
            unit = Math.PI / (isHours || roundBy5 ? 6 : 30),
            z = Math.sqrt(x * x + y * y),
            options = this.options,
            inner = isHours && z < (outerRadius + innerRadius) / 2,
            radius = inner ? innerRadius : outerRadius,
            value;

        if (options.twelvehour) {
            radius = outerRadius;
        }

        // Radian should in range [0, 2PI]
        if (radian < 0) {
            radian = Math.PI * 2 + radian;
        }

        // Get the round value
        value = Math.round(radian / unit);

        // Get the round radian
        radian = value * unit;

        // Correct the hours or minutes
        if (options.twelvehour) {
            if (isHours) {
                if (value === 0) {
                    value = 12;
                }
            } else {
                if (roundBy5) {
                    value *= 5;
                }
                if (value === 60) {
                    value = 0;
                }
            }
        } else {
            if (isHours) {
                if (value === 12) {
                    value = 0;
                }
                value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12;
            } else {
                if (roundBy5) {
                    value *= 5;
                }
                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);
                }
            }
        }

        this[this.currentView] = value;
        this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value));

        // If svg is not supported, just add an active class to the tick
        if (!svgSupported) {
            this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function () {
                var tick = $(this);
                tick.toggleClass('active', value === +tick.html());
            });
            return;
        }

        // Place clock hand at the top when dragging
        if (dragging || (!isHours && value % 5)) {
            this.g.insertBefore(this.hand, this.bearing);
            this.g.insertBefore(this.bg, this.fg);
            this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans');
        } else {
            // Or place it at the bottom
            this.g.insertBefore(this.hand, this.bg);
            this.g.insertBefore(this.fg, this.bg);
            this.bg.setAttribute('class', 'clockpicker-canvas-bg');
        }

        // Set clock hand and others' position
        var cx = Math.sin(radian) * radius,
            cy = -Math.cos(radian) * radius;
        this.hand.setAttribute('x2', cx);
        this.hand.setAttribute('y2', cy);
        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
    ClockPicker.prototype.done = function () {
        raiseCallback(this.options.beforeDone);
        this.hide();
        var last = this.input.prop('value'),
            value = leadingZero(this.hours) + ':' + leadingZero(this.minutes);
        if (this.options.twelvehour) {
            value = value + this.amOrPm;
        }

        this.input.prop('value', value);
        if (value !== last) {
            this.input.triggerHandler('change');
            if (!this.isInput) {
                this.element.trigger('change');
            }
        }

        if (this.options.autoclose) {
            this.input.trigger('blur');
        }

        raiseCallback(this.options.afterDone);
    };

    // Remove clockpicker from input
    ClockPicker.prototype.remove = function () {
        this.element.removeData('clockpicker');
        this.input.off('focus.clockpicker click.clockpicker');
        this.addon.off('click.clockpicker');
        if (this.isShown) {
            this.hide();
        }
        if (this.isAppended) {
            $win.off('resize.clockpicker' + this.id);
            this.popover.remove();
        }
    };

    // Extends $.fn.clockpicker
    $.fn.clockpicker = function (option) {
        var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function () {
            var $this = $(this),
                data = $this.data('clockpicker');
            if (!data) {
                var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option);
                $this.data('clockpicker', new ClockPicker($this, options));
            } else {
                // Manual operations. show, hide, remove, e.g.
                if (typeof data[option] === 'function') {
                    data[option].apply(data, args);
                }
            }
        });
    };
}());

Can't change time value when control inside Bootstrap's "Modal" window (IE 10)

When Clockpicker placed inside "Modal" control, user can't change time value. Dropdown with dial shows correct, user can select new hour and minute, selected values are show in dropdown, But, after click on 'Done' button - nothing changes in input text.
Error occurs only in IE10.
UPD: it's possible to change editor's value, when 'autoclose' option set to 'true'. If 'autoclose' option not set (or set to 'false' explicit), user can't change editor's value

Picker does not work with type="time" inputs when twelvehour=true

When the option "twelvehour" = true, the text "AM"/"PM" is added to the output string.

This is great for TEXT inputs, but does not work for TIME inputs. TIME inputs expect a value in the format of HH:MM:SS.

The easiest way to account for this is down in the "ClockPicker.prototype.done" function:

  1. Only do the following steps if the TYPE of the input is "time".
  2. Increment the hours+12 if this.amOrPm==="PM".
  3. Do not include the "AM"/"PM" in the final output string.
  4. Append ":00" (Zero seconds) to the output string.

clockpicker without <input>

The clockpicker is an excellent implementation to select a time value. And yes, the normal way would be to have an element. That way the current clockpicker is fine, but with my project I need a button to trigger the clockpicker but without an <input> element, example (partial html code)

         <div class="btn-group">  <!-- ON -->
            <button class="btn btn-default btn-sm dropdown-toggle clockpicker-with-callbacks" type="button"
                  id="ON"
                  data-toggle="dropdown" aria-expanded="false">
                  {{ON}} &nbsp; -- &nbsp;&nbsp;&nbsp;<span class="caret"></span>
            </button>

clockpicker_wo_input2
This works with callbacks and the clockpicker is tied to the button with the id "ON".

So the preset time value for the clockpicker has to be passed somehow.

To extend the clockpicker for that -- and not change the standard behavior -- was a very easy job with just a few lines of the clockpicker.js code and a specific calling sequence like this:

               $('#ON').clockpicker()
                  .clockpicker('show',{
                  'current': setON
               });

To get the time value selected with the clockpicker a "return time value" is passed with a modified callback like this:

     var clockInput = $('.clockpicker-with-callbacks').clockpicker({
         afterDone: function(timeValue) {
         .... code to process timeValue ...
         }
     });

The required clockpicker.js code changes can be found with a pull request with the same title.
Would be great to include it with the standard code base.
Thanks.

Ability to work with date object

Could this be added to current todos, please? :) I am used to that from Angular - one data source for both date and time picker - one date object.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.