JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
const divider = '------------------------------';
let turk = {
queue: [],
styleTarget: '#css',
presentationTarget: '#code pre code',
htmlTarget: '#email',
els: {},
wait(delay) {
this.queue.push({
delay
});
},
space(lines = 1) {
this.queue.push({
type: 'space',
contents: Array(lines + 1).join('\n')
});
},
progressBar(delay) {
const spaces = 20;
const otherChars = '/* */'.length;
this.addComment({
contents: Array(spaces).join('='),
speed: delay / (spaces + otherChars)
});
},
addHTML({
action = 'append', contents = '
', target = this.htmlTarget, delay = 750
}) {
this.queue.push({
type: 'html',
action,
contents,
target,
delay
});
},
addCSS({
contents = '', delay, speed
}) {
this.queue.push({
type: 'css',
contents,
delay,
speed
});
},
addComment({
contents = '', delay, speed
}) {
this.queue.push({
type: 'comment',
contents,
delay,
speed
});
},
run() {
this.els = {
style: $(this.styleTarget),
presentation: $(this.presentationTarget),
css: $(`${this.styleTarget}, ${this.presentationTarget}`),
html: $(this.htmlTarget)
};
this.next();
},
next() {
if (this.queue.length === 0) {
return console.log('done');
}
let typingPromise = Promise.resolve();
const item = this.queue.shift();
switch (item.type) {
case 'space':
typingPromise = write(this.els.css, item.contents);
break;
case 'comment':
let comment = item.contents.split('\n').length > 1 ?
`/* ${item.contents.replace(/\n/gm, '\n * ')}\n */\n\n` :
`/* ${item.contents} */\n`;
typingPromise = write(this.els.css, comment, item.speed);
break;
case 'css':
typingPromise = write(this.els.css, `${this.htmlTarget} ${item.contents}\n\n`, item.speed);
break;
case 'html':
if (item.action === 'append') {
$(item.contents).appendTo(item.target);
}
if (item.action === 'wrap') {
$(item.target).wrapAll(item.contents);
}
if (item.action === 'prepend') {
$(item.target).prepend(item.contents);
}
break;
}
typingPromise
.then(() => wait(item.delay || 300))
.then(() => {
this.next();
});
}
};
function wait(time = 0) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, time);
});
}
function scrollToBottom() {
// turk.els.presentation.animate({ scrollTop: turk.els.presentation[0].scrollHeight });
}
function write($target, str, speed = 40) {
if (str.length === 0) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
$target.append(str.charAt(0));
scrollToBottom($target);
setTimeout(() => {
write($target, str.substr(1), speed).then(resolve);
}, speed);
})
}
// building the queue
turk.addComment({
contents: `Hey there!
Lets learn about interactive email.
Interactive email
> An interactive email has the functionality for users
> to take an action within the email that triggers an
> event within the same email.`
});
turk.addComment({
contents: `How does that work?
Email clients like gmail strip out JavaScript to protect
us from dangerous senders. But there are some pretty cool
CSS hacks out there to still make emails interactive.
We use some checkbox magic!
We need a client that supports 3 things
1. the \`\` tag
2. the \`:checked\` selector
3. the \`+\` and \`~\` selectors to target siblings`
});
turk.space();
turk.wait(300);
turk.addComment({
contents: `Lets get started
${divider}`
});
turk.addComment({
contents: `We'll start with a label....`
});
turk.space();
turk.addHTML({
contents: 'Click me!'
});
turk.addComment({
contents: `a checkbox....`
});
turk.space();
turk.addHTML({
contents: ''
});
turk.addComment({
contents: `and content we want to show after we click the 'button'....`
});
turk.space();
turk.addHTML({
contents: '
});
turk.addComment({
contents: `Lets make our label look like a button.`
});
turk.addCSS({
contents: `#button {
background: coral;
color: white;
padding: 0.67em 1em;
display: inline-block;
cursor: pointer;
}`
});
turk.addComment({
contents: `Hmm, lets make that easier to see.`
});
turk.addCSS({
contents: `* {
font-size: 16px;
}`
});
turk.space();
turk.addComment({
contents: `Next we'll hide the #magic-content.`
});
turk.addCSS({
contents: `#magic-content {
display: none;
}`
})
turk.addComment({
contents: `Now lets show the \`#magic-content\` when the checkbox is checked.`
});
turk.addCSS({
contents: `#button-hook:checked ~ #magic-content {
display: inline-block;
}`
});
turk.space();
turk.addComment({
contents: `Give it a try!`
});
turk.progressBar(8000);
turk.space(3);
turk.addComment({
contents: `Ok, but this doesn't work everywhere.
We need to create a fallback for those poor souls that won't get our
awesome super advanced email.`
});
turk.addComment({
contents: `We'll wrap our interactive content in a div
with the id \`#interactive\`...`
})
turk.addHTML({
contents: `
action: 'wrap',
target: `${turk.htmlTarget} *`
});
turk.space();
turk.addComment({
contents: `add a checked checkbox right before \`#interactive\`...`
});
turk.addHTML({
contents: ``,
action: 'prepend',
target: turk.htmlTarget
});
turk.space();
turk.addComment({
contents: `and we'll hide the interactive content by default.`
});
turk.addCSS({
contents: `#interactive {
display: none;
}`
});
turk.addComment({
contents: `Next, we'll override that when its next to a checked checkbox...which it is!`
});
turk.addCSS({
contents: `#interactive-hook:checked ~ #interactive {
display: block;
}`
});
turk.addComment({
contents: `Now if the client support the css we need it will work but
if it doesn't our interactive content won't show.`
});
turk.addComment({
contents: `Lastly, we need some fallback content.`
});
turk.addHTML({
contents: `Dude, get a better email client.`
});
turk.space();
turk.addComment({
contents: `Lets apply the same idea as before and flip the styles.
We'll show \`#fallback\` by default and hide it if its next to a checked checkbox.`
});
turk.addCSS({
contents: `#interactive-hook:checked ~ #fallback {
display: none;
}`
});
turk.addComment({
contents: `Lets clean it all up...`
});
turk.addCSS({
contents: `#button-hook, #interactive-hook {
display: none !important;
}`
});
turk.addComment({
contents: `Wooo! We successfully made an interactive email with a safe fallback`
});
// turk.addHTML({ contents: `
turk.run();