JSFiddle - React, Tailwind, and code Playground
by khamer
HTML
<div id="cidr">
<input type="text" v-model="shorthand" placeholder="xxx.xxx.xxx.xxx">
<div class="bits">
<span class="byte" v-for="byte, j in bytes">
<span class="bit" v-for="bit, i in byte" v-text="bit" :class="{inMask: (i + j*8) < mask}">
</span>
</span>
</div>
<ul class="explanation">
<octet-mask-explanation v-if="mask < 8" :mask="mask" :bits="octet1" adj="first"></octet-mask-explanation>
<li v-if="mask >= 8">
Since the subnet mask is 8 or more, we know the first 8 bits must be exactly the same. In this case, that's
<binary-number :bits="octet1"></binary-number>.
</li>
<octet-mask-explanation v-if="mask > 8 && mask < 16" :mask="mask - 8" :bits="octet2" adj="second"></octet-mask-explanation>
<li v-if="mask >= 16">
Since the subnet mask is 16 or more, we know the second 8 bits must be exactly the same. In this case, that's
<binary-number :bits="octet2"></binary-number>.
</li>
<octet-mask-explanation v-if="mask > 16 && mask < 24" :mask="mask - 16" :bits="octet3" adj="third"></octet-mask-explanation>
<li v-if="mask >= 24">
Since the subnet mask is 24 or more, we know the third 8 bits must be exactly the same. In this case, that's
<binary-number :bits="octet3"></binary-number>.
</li>
<octet-mask-explanation v-if="mask > 24 && mask < 32" :mask="mask - 24" :bits="octet4" adj="fourth"></octet-mask-explanation>
<li v-if="mask == 32">
With a 32 bit mask, all 32 bits must be the same, and we know that the only matching IP is <strong v-text="ip"></strong>.
</li>
</ul>
</div>
<script type="text/tmpl" id="octet-mask">
<li>
Only the first {{ niceBits }} of the {{ adj }} octet are masked, which means the {{ adj }} octet can go
from <binary-number :bits="min"></binary-number> to <binary-number :bits="max"></binary-number>.
</li>
</script>
SCSS
html, body {
background-color: #fff;
}
.bits {
padding: 1em;
}
.byte {
border: 1px solid #ddd;
padding: .25em;
font-family: monospace;
font-size: 2em;
}
.inMask {
color: green;
}
.number {
background-color: #f4f4f4;
padding-left: .25em;
padding-right: .25em;
}
.binary {
font-family: monospace;
}
JavaScript
(function() {
let toBits = function(n) {
let digits = (n >>> 0).toString(2);
return ("00000000".substr(digits.length) + digits);
};
Vue.component('binary-number', {
template: `<span class="number"><span class="binary" v-text="bits" /> (<span v-text="decimal" />)</span>`,
props: ['bits'],
computed: {
decimal() {
return parseInt(this.bits, 2);
},
},
});
Vue.component('octet-mask-explanation', {
template: '#octet-mask',
props: ['mask', 'bits', 'adj'],
computed: {
niceBits() {
return this.mask + " " + (this.bits.length == 1 ? "bit" : "bits");
},
min() {
var minbits = this.bits.slice(0, this.mask);
return minbits + "00000000".slice(minbits.length);
},
max() {
var maxbits = this.bits.slice(0, this.mask);
return maxbits + "11111111".slice(maxbits.length);
},
}
});
new Vue({
el: "#cidr",
data: {
shorthand: "192.168.10.1/22",
},
computed: {
ip() {
return this.shorthand.replace(/\/.*$/, "");
},
mask() {
return this.shorthand.replace(/^.*\//, "");
},
bytes() {
return this.ip.split(".").map(toBits);
},
octet1() {
return this.bytes[0];
},
octet2() {
return this.bytes[1];
},
octet3() {
return this.bytes[2];
},
octet4() {
return this.bytes[3];
},
},
});
})();