1

I'm making an online advent calendar where you can only open the door of the day. All the doors use JavaScript onclick to display offer eg, 'door10'...

<a href="javascript:void(0)" onclick = "document.getElementById('door10').style.display='block';document.getElementById('fade10').style.display='block'" id="door-10-link">

They're all created with this onclick and then at the end of the HTML the following JavaScript function runs which removes the href and onclick attributes of the doors that aren't today, thus removing the ability to open them.

function disableDoor(num) {
var today = new Date();
var day = today.getDate();
var calendar_day = num;
if (calendar_day == day) {          
} else {
    var string = "door-" + num + "-link";
    var d = document.getElementById(string);
    d.removeAttribute("href");
    d.removeAttribute("onclick");
}

This all works fine in everything but Internet Explorer where the doors are still clickable even though they shouldn't be. The cursor doesn't change to the hover cursor and if you inspect the element the href and onclick values have been correctly removed, yet you can still 'open the door' even though no href is stated. The HTML now looks like this with the attributes correctly removed...

<a id="door-10-link">

In the IE inspector, if I 'Edit as HTML', don't change anything, click outside to finish editing and refresh the page it all works fine and I can't click the doors I'm not supposed to. The href element has been properly removed from the page.

It seems like the elements on the page need to refresh or something after the JavaScript has run. My guess is it's something to do with the DOM maybe but I'm pretty new to that area.

Any help would be brilliant as it's got me properly stumped.

Thanks in advance

Simeon Rowsell
  • 303
  • 1
  • 3
  • 9

3 Answers3

1

This appears to be a regression in Internet Explorer 11; I checked both Internet Explorer 9 and 10, and neither of the two would repro the issue. I've filed a bug internally to have our team look at resolving the issue as soon as we are able. You can check http://remote.modern.ie moving forward if you like. I constructed a small fiddle that demonstrates issue.

With this particular project, I would actually encourage you to take an alternate route and stand up a single event listener rather than conditionally tearing down dozens of pre-existing listeners. As a quick example of what I mean, consider the following:

(function () {

    "use strict";

    var day = (new Date).getDate(),
        doors = document.querySelectorAll( "div" );

    doors.item( --day ).addEventListener( "click", function openDoor () {
        this.classList.toggle( "open" );
    });

}());

In the above, only today's door will be unlocked — all other doors will remain locked. You can view the actual demo online at http://jsfiddle.net/jonathansampson/n4ed6uw5/.

I hope this work-around helps; in the meantime, I will be working with my team to resolve the regression.

Sampson
  • 265,109
  • 74
  • 539
  • 565
0

Try setting d.onclick = null to disable the onclick handler.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
0

You could do this with jQuery. You can attach a click handler to the element and every click handler checks if it is allowed to open.

For the time I'm using a JSON time server because if you use the client time it can be easily modified and every door could be opened.

Please check the following code. If you prefer jsFiddle you can find the same code here. It's doing what you are planning to do. Just add a popover instead of the alert to show the offer and apply your styling.

I have used MetroUI CSS just to do the tile styling.

To add your offers you have to modify the following JSON

var offers = [
    {
        'day': 1,
        'offer': 'something for day'
    },
    {
        'day': 2,
        'offer': 'A 2GB USB Stick'
    }, 
    ...
];

and add all 24 days and remove the three lines after the comment 'deep copy of offer'. Then you can use the index of your offers JSON to attach the data to the DOM elements.

There is another point that needs to be improved. If the time servers takes too long you can click at another element and both will popup. Blocking of other clicks and / or a loading progress bar would help.

var adventCalendar = (function () {
    var MONTH = 10; //10 = November / 11 = December --> set to November for testing
    var LAST_DAY = 30; // later 24 --> 30 just for testing
    
    function Calendar() {
        //console.log('constructor called');
        this.init();
    };
    var offers = [{
        'day': 1,
            'offer': 'something for day'
    }];
    // later you would have for each day a different offer.

    Calendar.prototype.init = function () {
        var offers24days;
        var $calendar = $('#adventCalendar');

        for (var i = 1; i <= LAST_DAY; i++) {
            // console.log(i);
            // deep copy of offer
            var newObject = jQuery.extend(true, {}, offers[0]);
            newObject.day = i;
            newObject.offer += ' ' + i;
            
            $door = $('<div class="tile rounded"/>')
                .text(i)
                .data(newObject)
                .appendTo($calendar);

            var that = this; // store reference to this Calendar
            $door.on('click', function () {
                var today = new Date();
                var $this = $(this);
                that.getTime('GMT', function (date) {
                    // This is where you do whatever you want with the time:
                    //console.log(date.getDate());
                    var data = $this.data(); // today from time server
                    
                    if ((data.day <= date.getDate()) && (date.getMonth() == MONTH)) {
                        // Attention! Date month starts at 0 --> 0 = Januar & 10 = November
                        // open allowed
                        alert(data.offer); // later you can use a popover instead of an alert. This is just for the demo.
                    } else {
                        //alert('not allowed'); // just for testing
                    }
                });
            });
        }
    }

    // get time from this SO question http://stackoverflow.com/questions/9486293/does-anyone-know-of-a-good-json-time-server
    // zone not used because time server doesn't support it
    Calendar.prototype.getTime = function (zone, success) {
        //var url = 'http://json-time.appspot.com/time.json?tz=' + zone,
        var url = 'http://time.jsontest.com/?', // no zone support other link is broken
            ud = 'json' + (+new Date());
        window[ud] = function (o) {
            success && success(new Date(o.milliseconds_since_epoch)); //o.datetime));
        };
        document.getElementsByTagName('head')[0].appendChild((function () {
            var s = document.createElement('script');
            s.type = 'text/javascript';
            s.src = url + 'callback=' + ud;
            return s;
        })());
    }

    return {
        Calendar: Calendar
    };
})();

$(function () {
    var advent = new adventCalendar.Calendar();
});
.tile {
    font-family: sans-serif;
    font-size: 4em;
    color: #E2E1E6;
}
<script src="http://cdn.jsdelivr.net/metro-ui-css/2.0.23/min/metro.min.js"></script>
<link href="http://cdn.jsdelivr.net/metro-ui-css/2.0.23/min/metro-responsive.min.css" rel="stylesheet"/>
<link href="http://cdn.jsdelivr.net/metro-ui-css/2.0.23/min/metro-bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
    <div id="adventCalendar" class="metro grid fluid"></div>
</div>
AWolf
  • 8,770
  • 5
  • 33
  • 39