Initial commit

This commit is contained in:
lawgicau
2020-08-10 17:13:28 +10:00
parent 3c8b787cbb
commit c77c064943
12 changed files with 14533 additions and 2 deletions

158
css/featherlight.css Normal file
View File

@ -0,0 +1,158 @@
/**
* Featherlight ultra slim jQuery lightbox
* Version 1.7.14 - http://noelboss.github.io/featherlight/
*
* Copyright 2019, Noël Raoul Bossart (http://www.noelboss.com)
* MIT Licensed.
**/
html.with-featherlight {
/* disable global scrolling when featherlights are visible */
overflow: hidden;
}
.featherlight {
display: none;
/* dimensions: spanning the background from edge to edge */
position:fixed;
top: 0; right: 0; bottom: 0; left: 0;
z-index: 2147483647; /* z-index needs to be >= elements on the site. */
/* position: centering content */
text-align: center;
/* insures that the ::before pseudo element doesn't force wrap with fixed width content; */
white-space: nowrap;
/* styling */
cursor: pointer;
background: #333;
/* IE8 "hack" for nested featherlights */
background: rgba(0, 0, 0, 0);
}
/* support for nested featherlights. Does not work in IE8 (use JS to fix) */
.featherlight:last-of-type {
background: rgba(0, 0, 0, 0.8);
}
.featherlight:before {
/* position: trick to center content vertically */
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.featherlight .featherlight-content {
/* make content container for positioned elements (close button) */
position: relative;
/* position: centering vertical and horizontal */
text-align: left;
vertical-align: middle;
display: inline-block;
/* dimensions: cut off images */
overflow: auto;
padding: 25px 25px 0;
border-bottom: 25px solid transparent;
/* dimensions: handling large content */
margin-left: 5%;
margin-right: 5%;
max-height: 95%;
/* styling */
background: #fff;
cursor: auto;
/* reset white-space wrapping */
white-space: normal;
}
/* contains the content */
.featherlight .featherlight-inner {
/* make sure its visible */
display: block;
}
/* don't show these though */
.featherlight script.featherlight-inner,
.featherlight link.featherlight-inner,
.featherlight style.featherlight-inner {
display: none;
}
.featherlight .featherlight-close-icon {
/* position: centering vertical and horizontal */
position: absolute;
z-index: 9999;
top: 0;
right: 0;
/* dimensions: 25px x 25px */
line-height: 25px;
width: 25px;
/* styling */
cursor: pointer;
text-align: center;
font-family: Arial, sans-serif;
background: #fff; /* Set the background in case it overlaps the content */
background: rgba(255, 255, 255, 0.3);
color: #000;
border: none;
padding: 0;
}
/* See http://stackoverflow.com/questions/16077341/how-to-reset-all-default-styles-of-the-html5-button-element */
.featherlight .featherlight-close-icon::-moz-focus-inner {
border: 0;
padding: 0;
}
.featherlight .featherlight-image {
/* styling */
width: 100%;
}
.featherlight-iframe .featherlight-content {
/* removed the border for image croping since iframe is edge to edge */
border-bottom: 0;
padding: 0;
-webkit-overflow-scrolling: touch;
}
.featherlight iframe {
/* styling */
border: none;
}
.featherlight * { /* See https://github.com/noelboss/featherlight/issues/42 */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* handling phones and small screens */
@media only screen and (max-width: 1024px) {
.featherlight .featherlight-content {
/* dimensions: maximize lightbox with for small screens */
margin-left: 0;
margin-right: 0;
max-height: 98%;
padding: 10px 10px 0;
border-bottom: 10px solid transparent;
}
}
/* hide non featherlight items when printing */
@media print {
html.with-featherlight > * > :not(.featherlight) {
display: none;
}
}

34
css/responsive-tabs.css Normal file
View File

@ -0,0 +1,34 @@
.r-tabs .r-tabs-nav {
margin: 0;
padding: 0;
}
.r-tabs .r-tabs-tab {
display: inline-block;
margin: 0;
list-style: none;
}
.r-tabs .r-tabs-panel {
padding: 15px;
display: none;
}
.r-tabs .r-tabs-accordion-title {
display: none;
}
.r-tabs .r-tabs-panel.r-tabs-state-active {
display: block;
}
/* Accordion responsive breakpoint */
@media only screen and (max-width: 768px) {
.r-tabs .r-tabs-nav {
display: none;
}
.r-tabs .r-tabs-accordion-title {
display: block;
}
}

208
css/styles.css Normal file
View File

@ -0,0 +1,208 @@
body {
font-family: 'Roboto', sans-serif;
background-color: #f9f9f9;
max-width: 1400px;
margin: auto;
}
h1 {
margin: 20px 20px;
}
h2 {
margin: 10px 20px;
}
h3 {
margin: 5px 20px;
}
h4 {
font-size: 1.2em;
font-weight: bolder;
margin: 20px 20px 5px;
padding: 5px 10px;
color:white;
background-color: #00c5ad;
}
p {
margin: 10px 20px 20px;
line-height: 1.5em;
}
input {
margin: 20px 0;
font-size: 1.2em;
}
select {
font-size: 1.2em;
}
label {
margin: 20px 20px;
font-size: 1.2em;
}
a {
color: #00c5ad;
font-weight: bolder;
text-decoration: none;;
}
.thumb {
max-height: 240px;
max-width: 600px;
margin-bottom: 20px;
}
#tabs {
margin: 20px 0;
}
.videoThumb {
margin: 0 20px 20px;
}
.warning {
color: red;
font-weight: bolder;
}
li {
margin: 10px 0;
}
/* Tabs container */
.r-tabs {
position: relative;
background-color: #00c5ad;
border-top: 1px solid #00c5ad;
border-right: 1px solid #00c5ad;
border-left: 1px solid #00c5ad;
border-bottom: 4px solid #00c5ad;
border-radius: 4px;
}
/* Tab element */
.r-tabs .r-tabs-nav .r-tabs-tab {
position: relative;
background-color: #00c5ad;
}
/* Tab anchor */
.r-tabs .r-tabs-nav .r-tabs-anchor {
display: inline-block;
padding: 10px 12px;
text-decoration: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.4);
font-size: 14px;
font-weight: bold;
color: #fff;
}
/* Disabled tab */
.r-tabs .r-tabs-nav .r-tabs-state-disabled {
opacity: 0.5;
}
/* Active state tab anchor */
.r-tabs .r-tabs-nav .r-tabs-state-active .r-tabs-anchor {
color: #00c5ad;
text-shadow: none;
background-color: white;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
/* Tab panel */
.r-tabs .r-tabs-panel {
background-color: white;
border-bottom: 4px solid white;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
/* Accordion anchor */
.r-tabs .r-tabs-accordion-title .r-tabs-anchor {
display: block;
padding: 10px;
background-color: #00c5ad;
color: #fff;
font-weight: bold;
text-decoration: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.4);
font-size: 14px;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
/* Active accordion anchor */
.r-tabs .r-tabs-accordion-title.r-tabs-state-active .r-tabs-anchor {
background-color: #fff;
color: #00c5ad;
text-shadow: none;
}
/* Disabled accordion button */
.r-tabs .r-tabs-accordion-title.r-tabs-state-disabled {
opacity: 0.5;
}
/* Buttons */
button {
display:inline-block;
margin-top: 10px;
margin-right: 10px;
padding: 10px 20px;
line-height: 100%;
color: #fff;
font-size: 14px;
text-align: center;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
vertical-align: middle;
font-weight: bold;
border: 0;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background-color: #00c5ad;
box-shadow: 0px 3px 0px 0px #00ab94;
cursor: pointer;
}
/* Info bar */
.info {
display:inline-block;
margin-top: 10px;
margin-right: 10px;
padding: 10px 20px;
width: 300px;
line-height: 100%;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 14px;
color: #00c5ad;
border: 2px solid #00ab94;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background-color: #fff;
cursor: pointer;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

View File

@ -1,7 +1,147 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<title>Teaching Tech 3D Printer Calibration</title>
<link type="text/css" rel="stylesheet" href="css/styles.css">
<link type="text/css" rel="stylesheet" href="css/responsive-tabs.css">
<link type="text/css" rel="stylesheet" href="css/featherlight.css">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
<script src="js/jquery-3.5.1.js"></script>
<script src="js/jquery.responsiveTabs.js"></script>
<script src="js/videobox.js"></script>
<script src="js/featherlight.js"></script>
<script src="js/baseline.js"></script>
<script src="js/encoding-indexes.js"></script>
<script src="js/encoding.js"></script>
<script src="js/gcodeprocessing.js"></script>
</head>
<body> <body>
<h1>Hello World</h1> <h1>Teaching Tech 3D Printer Calibration</h1>
<p>I'm hosted with GitHub Pages.</p> <p>This page serves as a companion for the following video: <a href="https://www.youtube.com/watch?v=" target="_blank"></a></p>
<p>It aims to make calibrating your 3D printer as easy as possible. If you find it helps you and you would like to say thank you, here is a donation link: <a href="paypal.me/testlawgicau" target="blank">PayPal.me</a></p>
<p>Special thanks to my <a href="http://www.patreon.com/teachingtech" target="_blank">Patrons</a> for suggesting this video and helping define the contents.</p>
<p>Watch the video and then work through each tab. I have created a custom gcode generator to assist in testing towers. Every attempt has been made to ensure this is safe but ultimately there always is risk in running presliced gcode from the internet. Preview the gcode in your slicer or <a href="http://gcode.ws/" target="_blank">Gcode.ws</a> and <span class="warning">print at your own risk.</span></p>
<div id="tabs">
<ul>
<li><a href="#frame">Frame Check</a></li>
<li><a href="#pid">PID Autotune</a></li>
<li><a href="#baseline">Baseline Print</a></li>
<li><a href="#esteps">E-steps Calibration</a></li>
<li><a href="#steppers">Driver Current</a></li>
<li><a href="#retraction">Retraction Tuning</a></li>
<li><a href="#temp">Temperature Tuning</a></li>
<li><a href="#accel">Acceleration Tuning</a></li>
<li><a href="#linadv">Linear Advance</a></li>
</ul>
<div id="frame">
<h2>Frame Check</h2>
<p>Before we do anything else, we need to ensure there are no underlying problems with the frame. It would be easy to use the techniques elsewhere on this page to try and fix problems that were actually caused by a problem with the physical components, so we will eliminate this first.</p>
<p>Many of these procedures are covered in this video: <a href="https://youtu.be/T-Z3GmM20JM" target="_blank">Complete beginner's guide to 3D printing - Assembly, tour, slicing, levelling and first prints</a></p>
<div class="videoThumb" data-youtube="https://youtu.be/T-Z3GmM20JM"></div>
<h4>Loose nuts and bolts</h4>
<p>Move around the machine and check all fasteners. Crucial ones include those on the print head gantry such as those that hold the hot end on.</p>
<h4>V-roller tension</h4>
<p>If your printer has a motion system based on V-roller wheels riding on V-slot extrusions, check they are properly tensioned. Each location will have one eccentric nut. This can be twisted to either add or remove tension on the wheels.</p>
<p><b>If the wheels are too loose:</b> Wobble will be present in the assembly, which will show in the print as surface artefacts.</p>
<p><b>If the wheels are too tight:</b> The assembly is will be too tense, which will wear the V-rollers prematurely.</p>
<h4>Bed Levelling</h4>
<p>Probably the most essential part of setting up your 3D printer. Most new users will trip up on this. My method is included in the above video and this diagram is a handy reference:</p>
<a href="#" data-featherlight="img/_bed-levelling-guide.jpg"><img class="thumb" src="img/_bed-levelling-guide.jpg" /></a>
<h4>PTFE Tube</h4>
<p>If your printer has PTFE tube, such as a bowden tube setup for the extruder/hot end, it is essential to make the tube is fully inserted and seated in the coupler. Also ensure the coupler is properly tightened. You may wish to use a small retaining clip on the coupler to prevent the tube working loose: <a href="https://www.thingiverse.com/thing:4268489" target="_blank">Creality PTFE clip by morfidesign</a>.</p>
</div>
<div id="pid">
<h2>PID Autotune</h2>
<p></p>
</div>
<div id="baseline">
<h2>Baseline Print</h2>
<p>The aim of this print is to establish a baseline for comparison with later tests.</p>
<form name="baselineForm" id="baselineForm" onsubmit="return:false;">
<h4>Bed dimensions</h4>
<p>Inputting the correct number will attempt to move the print into the centre of the bed.</p>
<label>Bed X dimension (mm): <input type="number" name="bedx" value="100" min="100" max="600" step="1"></label>
<label>Bed Y dimension (mm): <input type="number" name="bedy" value="100" min="100" max="600" step="2"></label><br />
<h4>Temperatures</h4>
<p>For the hot end and bed respectively, typical PLA temperatures are 200 and 60, PETG 235 and 80, ABS 250 and 100, TPU 230 and 5 (effectively off).</p>
<label>Hot end temperature (deg C): <input type="number" name="hotendtemp" value="200" min="160" max="450"></label>
<label>Bed temperature (deg C): <input type="number" name="bedtemp" value="60" min="5" max="150"></label><br />
<h4>Retraction</h4>
<p>For intial tests, you can leave the retraction speed at 40 mm/sec. For a bowden tube printer, 6mm is a likely retraction distance. For direct drive, a starting value of 1mm may be suitable.</p>
<label>Retraction distance (mm): <input type="number" name="retdist" value="5" min="0" max="20"></label>
<label>Retraction speed (mm/sec): <input type="number" name="retspeed" value="40" min="5" max="150"></label><br />
<h4>Auto Bed Levelling</h4>
<label for="abl">Select which method of ABL is in place.</label>
<select name="abl" id="abl">
<option value="0">No ABL</option>
<option value="1">Probe new mesh at the start of print - G29</option>
<option value="2">Restore saved mesh - M420 S1</option>
</select>
<p><input type="button" onclick="processBaseline()" value="Download Gcode"></p>
</form>
</div>
<div id="esteps">
<h2>E-steps Calibration</h2>
<p></p>
</div>
<div id="steppers">
<h2>Stepper Motor Driver Current Tuning</h2>
<p></p>
</div>
<div id="retraction">
<h2>Retraction Tuning</h2>
<p></p>
</div>
<div id="temp">
<h2>Temperature Tuning</h2>
<p></p>
</div>
<div id="accel">
<h2>Acceleration Tuning</h2>
<p></p>
</div>
<div id="linadv">
<h2>Linear Advance</h2>
<p></p>
</div>
</div>
<div id="footer">
<h3>This page was created using:</h3>
<ul>
<li><a href="https://jquery.com/" target="_blank">jQuery</a></li>
<li><a href="https://github.com/jellekralt/Responsive-Tabs" target="_blank">Responsive Tabs by jellekraut</a></li>
<li><a href="https://fonts.google.com/specimen/Roboto" target="_blank">Roboto font</a></li>
<li><a href="https://github.com/tedktedk/videobox" target="_blank">Videobox by tedktedk</a></li>
<li><a href="https://github.com/noelboss/featherlight" target="_blank">Featherlight by noelboss</a></li>
</ul>
</div>
</body> </body>
<script>
$('#tabs').responsiveTabs({
startCollapsed: 'accordion'
});
$(".videoThumb").videoBox({
width: '480',
height: '360',
loop: false,
autoplay: false,
byline: false,
color: "00adef",
maxheight: '',
maxwidth: '',
portrait: true,
title: '',
controls: 1
});
</script>
</html> </html>

9027
js/baseline.js Normal file

File diff suppressed because it is too large Load Diff

47
js/encoding-indexes.js Normal file

File diff suppressed because one or more lines are too long

3313
js/encoding.js Normal file

File diff suppressed because it is too large Load Diff

668
js/featherlight.js Normal file
View File

@ -0,0 +1,668 @@
/**
* Featherlight - ultra slim jQuery lightbox
* Version 1.7.14-UMD - http://noelboss.github.io/featherlight/
*
* Copyright 2019, Noël Raoul Bossart (http://www.noelboss.com)
* MIT Licensed.
**/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = function (root, jQuery) {
if (jQuery === undefined) {
// require('jQuery') returns a factory that requires window to
// build a jQuery instance, we normalize how we use modules
// that require this pattern but the window provided is a noop
// if it's defined (how jquery works)
if (typeof window !== 'undefined') {
jQuery = require('jquery');
} else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
if('undefined' === typeof $) {
if('console' in window){ window.console.info('Too much lightness, Featherlight needs jQuery.'); }
return;
}
if($.fn.jquery.match(/-ajax/)) {
if('console' in window){ window.console.info('Featherlight needs regular jQuery, not the slim version.'); }
return;
}
/* Featherlight is exported as $.featherlight.
It is a function used to open a featherlight lightbox.
[tech]
Featherlight uses prototype inheritance.
Each opened lightbox will have a corresponding object.
That object may have some attributes that override the
prototype's.
Extensions created with Featherlight.extend will have their
own prototype that inherits from Featherlight's prototype,
thus attributes can be overriden either at the object level,
or at the extension level.
To create callbacks that chain themselves instead of overriding,
use chainCallbacks.
For those familiar with CoffeeScript, this correspond to
Featherlight being a class and the Gallery being a class
extending Featherlight.
The chainCallbacks is used since we don't have access to
CoffeeScript's `super`.
*/
function Featherlight($content, config) {
if(this instanceof Featherlight) { /* called with new */
this.id = Featherlight.id++;
this.setup($content, config);
this.chainCallbacks(Featherlight._callbackChain);
} else {
var fl = new Featherlight($content, config);
fl.open();
return fl;
}
}
var opened = [],
pruneOpened = function(remove) {
opened = $.grep(opened, function(fl) {
return fl !== remove && fl.$instance.closest('body').length > 0;
} );
return opened;
};
// Removes keys of `set` from `obj` and returns the removed key/values.
function slice(obj, set) {
var r = {};
for (var key in obj) {
if (key in set) {
r[key] = obj[key];
delete obj[key];
}
}
return r;
}
// NOTE: List of available [iframe attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).
var iFrameAttributeSet = {
allow: 1, allowfullscreen: 1, frameborder: 1, height: 1, longdesc: 1, marginheight: 1, marginwidth: 1,
mozallowfullscreen: 1, name: 1, referrerpolicy: 1, sandbox: 1, scrolling: 1, src: 1, srcdoc: 1, style: 1,
webkitallowfullscreen: 1, width: 1
};
// Converts camelCased attributes to dasherized versions for given prefix:
// parseAttrs({hello: 1, hellFrozeOver: 2}, 'hell') => {froze-over: 2}
function parseAttrs(obj, prefix) {
var attrs = {},
regex = new RegExp('^' + prefix + '([A-Z])(.*)');
for (var key in obj) {
var match = key.match(regex);
if (match) {
var dasherized = (match[1] + match[2].replace(/([A-Z])/g, '-$1')).toLowerCase();
attrs[dasherized] = obj[key];
}
}
return attrs;
}
/* document wide key handler */
var eventMap = { keyup: 'onKeyUp', resize: 'onResize' };
var globalEventHandler = function(event) {
$.each(Featherlight.opened().reverse(), function() {
if (!event.isDefaultPrevented()) {
if (false === this[eventMap[event.type]](event)) {
event.preventDefault(); event.stopPropagation(); return false;
}
}
});
};
var toggleGlobalEvents = function(set) {
if(set !== Featherlight._globalHandlerInstalled) {
Featherlight._globalHandlerInstalled = set;
var events = $.map(eventMap, function(_, name) { return name+'.'+Featherlight.prototype.namespace; } ).join(' ');
$(window)[set ? 'on' : 'off'](events, globalEventHandler);
}
};
Featherlight.prototype = {
constructor: Featherlight,
/*** defaults ***/
/* extend featherlight with defaults and methods */
namespace: 'featherlight', /* Name of the events and css class prefix */
targetAttr: 'data-featherlight', /* Attribute of the triggered element that contains the selector to the lightbox content */
variant: null, /* Class that will be added to change look of the lightbox */
resetCss: false, /* Reset all css */
background: null, /* Custom DOM for the background, wrapper and the closebutton */
openTrigger: 'click', /* Event that triggers the lightbox */
closeTrigger: 'click', /* Event that triggers the closing of the lightbox */
filter: null, /* Selector to filter events. Think $(...).on('click', filter, eventHandler) */
root: 'body', /* Where to append featherlights */
openSpeed: 250, /* Duration of opening animation */
closeSpeed: 250, /* Duration of closing animation */
closeOnClick: 'background', /* Close lightbox on click ('background', 'anywhere' or false) */
closeOnEsc: true, /* Close lightbox when pressing esc */
closeIcon: '&#10005;', /* Close icon */
loading: '', /* Content to show while initial content is loading */
persist: false, /* If set, the content will persist and will be shown again when opened again. 'shared' is a special value when binding multiple elements for them to share the same content */
otherClose: null, /* Selector for alternate close buttons (e.g. "a.close") */
beforeOpen: $.noop, /* Called before open. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
beforeContent: $.noop, /* Called when content is loaded. Gets event as parameter, this contains all data */
beforeClose: $.noop, /* Called before close. can return false to prevent closing of lightbox. Gets event as parameter, this contains all data */
afterOpen: $.noop, /* Called after open. Gets event as parameter, this contains all data */
afterContent: $.noop, /* Called after content is ready and has been set. Gets event as parameter, this contains all data */
afterClose: $.noop, /* Called after close. Gets event as parameter, this contains all data */
onKeyUp: $.noop, /* Called on key up for the frontmost featherlight */
onResize: $.noop, /* Called after new content and when a window is resized */
type: null, /* Specify type of lightbox. If unset, it will check for the targetAttrs value. */
contentFilters: ['jquery', 'image', 'html', 'ajax', 'iframe', 'text'], /* List of content filters to use to determine the content */
/*** methods ***/
/* setup iterates over a single instance of featherlight and prepares the background and binds the events */
setup: function(target, config){
/* all arguments are optional */
if (typeof target === 'object' && target instanceof $ === false && !config) {
config = target;
target = undefined;
}
var self = $.extend(this, config, {target: target}),
css = !self.resetCss ? self.namespace : self.namespace+'-reset', /* by adding -reset to the classname, we reset all the default css */
$background = $(self.background || [
'<div class="'+css+'-loading '+css+'">',
'<div class="'+css+'-content">',
'<button class="'+css+'-close-icon '+ self.namespace + '-close" aria-label="Close">',
self.closeIcon,
'</button>',
'<div class="'+self.namespace+'-inner">' + self.loading + '</div>',
'</div>',
'</div>'].join('')),
closeButtonSelector = '.'+self.namespace+'-close' + (self.otherClose ? ',' + self.otherClose : '');
self.$instance = $background.clone().addClass(self.variant); /* clone DOM for the background, wrapper and the close button */
/* close when click on background/anywhere/null or closebox */
self.$instance.on(self.closeTrigger+'.'+self.namespace, function(event) {
if(event.isDefaultPrevented()) {
return;
}
var $target = $(event.target);
if( ('background' === self.closeOnClick && $target.is('.'+self.namespace))
|| 'anywhere' === self.closeOnClick
|| $target.closest(closeButtonSelector).length ){
self.close(event);
event.preventDefault();
}
});
return this;
},
/* this method prepares the content and converts it into a jQuery object or a promise */
getContent: function(){
if(this.persist !== false && this.$content) {
return this.$content;
}
var self = this,
filters = this.constructor.contentFilters,
readTargetAttr = function(name){ return self.$currentTarget && self.$currentTarget.attr(name); },
targetValue = readTargetAttr(self.targetAttr),
data = self.target || targetValue || '';
/* Find which filter applies */
var filter = filters[self.type]; /* check explicit type like {type: 'image'} */
/* check explicit type like data-featherlight="image" */
if(!filter && data in filters) {
filter = filters[data];
data = self.target && targetValue;
}
data = data || readTargetAttr('href') || '';
/* check explicity type & content like {image: 'photo.jpg'} */
if(!filter) {
for(var filterName in filters) {
if(self[filterName]) {
filter = filters[filterName];
data = self[filterName];
}
}
}
/* otherwise it's implicit, run checks */
if(!filter) {
var target = data;
data = null;
$.each(self.contentFilters, function() {
filter = filters[this];
if(filter.test) {
data = filter.test(target);
}
if(!data && filter.regex && target.match && target.match(filter.regex)) {
data = target;
}
return !data;
});
if(!data) {
if('console' in window){ window.console.error('Featherlight: no content filter found ' + (target ? ' for "' + target + '"' : ' (no target specified)')); }
return false;
}
}
/* Process it */
return filter.process.call(self, data);
},
/* sets the content of $instance to $content */
setContent: function($content){
this.$instance.removeClass(this.namespace+'-loading');
/* we need a special class for the iframe */
this.$instance.toggleClass(this.namespace+'-iframe', $content.is('iframe'));
/* replace content by appending to existing one before it is removed
this insures that featherlight-inner remain at the same relative
position to any other items added to featherlight-content */
this.$instance.find('.'+this.namespace+'-inner')
.not($content) /* excluded new content, important if persisted */
.slice(1).remove().end() /* In the unexpected event where there are many inner elements, remove all but the first one */
.replaceWith($.contains(this.$instance[0], $content[0]) ? '' : $content);
this.$content = $content.addClass(this.namespace+'-inner');
return this;
},
/* opens the lightbox. "this" contains $instance with the lightbox, and with the config.
Returns a promise that is resolved after is successfully opened. */
open: function(event){
var self = this;
self.$instance.hide().appendTo(self.root);
if((!event || !event.isDefaultPrevented())
&& self.beforeOpen(event) !== false) {
if(event){
event.preventDefault();
}
var $content = self.getContent();
if($content) {
opened.push(self);
toggleGlobalEvents(true);
self.$instance.fadeIn(self.openSpeed);
self.beforeContent(event);
/* Set content and show */
return $.when($content)
.always(function($openendContent){
if($openendContent) {
self.setContent($openendContent);
self.afterContent(event);
}
})
.then(self.$instance.promise())
/* Call afterOpen after fadeIn is done */
.done(function(){ self.afterOpen(event); });
}
}
self.$instance.detach();
return $.Deferred().reject().promise();
},
/* closes the lightbox. "this" contains $instance with the lightbox, and with the config
returns a promise, resolved after the lightbox is successfully closed. */
close: function(event){
var self = this,
deferred = $.Deferred();
if(self.beforeClose(event) === false) {
deferred.reject();
} else {
if (0 === pruneOpened(self).length) {
toggleGlobalEvents(false);
}
self.$instance.fadeOut(self.closeSpeed,function(){
self.$instance.detach();
self.afterClose(event);
deferred.resolve();
});
}
return deferred.promise();
},
/* resizes the content so it fits in visible area and keeps the same aspect ratio.
Does nothing if either the width or the height is not specified.
Called automatically on window resize.
Override if you want different behavior. */
resize: function(w, h) {
if (w && h) {
/* Reset apparent image size first so container grows */
this.$content.css('width', '').css('height', '');
/* Calculate the worst ratio so that dimensions fit */
/* Note: -1 to avoid rounding errors */
var ratio = Math.max(
w / (this.$content.parent().width()-1),
h / (this.$content.parent().height()-1));
/* Resize content */
if (ratio > 1) {
ratio = h / Math.floor(h / ratio); /* Round ratio down so height calc works */
this.$content.css('width', '' + w / ratio + 'px').css('height', '' + h / ratio + 'px');
}
}
},
/* Utility function to chain callbacks
[Warning: guru-level]
Used be extensions that want to let users specify callbacks but
also need themselves to use the callbacks.
The argument 'chain' has callback names as keys and function(super, event)
as values. That function is meant to call `super` at some point.
*/
chainCallbacks: function(chain) {
for (var name in chain) {
this[name] = $.proxy(chain[name], this, $.proxy(this[name], this));
}
}
};
$.extend(Featherlight, {
id: 0, /* Used to id single featherlight instances */
autoBind: '[data-featherlight]', /* Will automatically bind elements matching this selector. Clear or set before onReady */
defaults: Featherlight.prototype, /* You can access and override all defaults using $.featherlight.defaults, which is just a synonym for $.featherlight.prototype */
/* Contains the logic to determine content */
contentFilters: {
jquery: {
regex: /^[#.]\w/, /* Anything that starts with a class name or identifiers */
test: function(elem) { return elem instanceof $ && elem; },
process: function(elem) { return this.persist !== false ? $(elem) : $(elem).clone(true); }
},
image: {
regex: /\.(png|jpg|jpeg|gif|tiff?|bmp|svg)(\?\S*)?$/i,
process: function(url) {
var self = this,
deferred = $.Deferred(),
img = new Image(),
$img = $('<img src="'+url+'" alt="" class="'+self.namespace+'-image" />');
img.onload = function() {
/* Store naturalWidth & height for IE8 */
$img.naturalWidth = img.width; $img.naturalHeight = img.height;
deferred.resolve( $img );
};
img.onerror = function() { deferred.reject($img); };
img.src = url;
return deferred.promise();
}
},
html: {
regex: /^\s*<[\w!][^<]*>/, /* Anything that starts with some kind of valid tag */
process: function(html) { return $(html); }
},
ajax: {
regex: /./, /* At this point, any content is assumed to be an URL */
process: function(url) {
var self = this,
deferred = $.Deferred();
/* we are using load so one can specify a target with: url.html #targetelement */
var $container = $('<div></div>').load(url, function(response, status){
if ( status !== "error" ) {
deferred.resolve($container.contents());
}
deferred.reject();
});
return deferred.promise();
}
},
iframe: {
process: function(url) {
var deferred = new $.Deferred();
var $content = $('<iframe/>');
var css = parseAttrs(this, 'iframe');
var attrs = slice(css, iFrameAttributeSet);
$content.hide()
.attr('src', url)
.attr(attrs)
.css(css)
.on('load', function() { deferred.resolve($content.show()); })
// We can't move an <iframe> and avoid reloading it,
// so let's put it in place ourselves right now:
.appendTo(this.$instance.find('.' + this.namespace + '-content'));
return deferred.promise();
}
},
text: {
process: function(text) { return $('<div>', {text: text}); }
}
},
functionAttributes: ['beforeOpen', 'afterOpen', 'beforeContent', 'afterContent', 'beforeClose', 'afterClose'],
/*** class methods ***/
/* read element's attributes starting with data-featherlight- */
readElementConfig: function(element, namespace) {
var Klass = this,
regexp = new RegExp('^data-' + namespace + '-(.*)'),
config = {};
if (element && element.attributes) {
$.each(element.attributes, function(){
var match = this.name.match(regexp);
if (match) {
var val = this.value,
name = $.camelCase(match[1]);
if ($.inArray(name, Klass.functionAttributes) >= 0) { /* jshint -W054 */
val = new Function(val); /* jshint +W054 */
} else {
try { val = JSON.parse(val); }
catch(e) {}
}
config[name] = val;
}
});
}
return config;
},
/* Used to create a Featherlight extension
[Warning: guru-level]
Creates the extension's prototype that in turn
inherits Featherlight's prototype.
Could be used to extend an extension too...
This is pretty high level wizardy, it comes pretty much straight
from CoffeeScript and won't teach you anything about Featherlight
as it's not really specific to this library.
My suggestion: move along and keep your sanity.
*/
extend: function(child, defaults) {
/* Setup class hierarchy, adapted from CoffeeScript */
var Ctor = function(){ this.constructor = child; };
Ctor.prototype = this.prototype;
child.prototype = new Ctor();
child.__super__ = this.prototype;
/* Copy class methods & attributes */
$.extend(child, this, defaults);
child.defaults = child.prototype;
return child;
},
attach: function($source, $content, config) {
var Klass = this;
if (typeof $content === 'object' && $content instanceof $ === false && !config) {
config = $content;
$content = undefined;
}
/* make a copy */
config = $.extend({}, config);
/* Only for openTrigger, filter & namespace... */
var namespace = config.namespace || Klass.defaults.namespace,
tempConfig = $.extend({}, Klass.defaults, Klass.readElementConfig($source[0], namespace), config),
sharedPersist;
var handler = function(event) {
var $target = $(event.currentTarget);
/* ... since we might as well compute the config on the actual target */
var elemConfig = $.extend(
{$source: $source, $currentTarget: $target},
Klass.readElementConfig($source[0], tempConfig.namespace),
Klass.readElementConfig(event.currentTarget, tempConfig.namespace),
config);
var fl = sharedPersist || $target.data('featherlight-persisted') || new Klass($content, elemConfig);
if(fl.persist === 'shared') {
sharedPersist = fl;
} else if(fl.persist !== false) {
$target.data('featherlight-persisted', fl);
}
if (elemConfig.$currentTarget.blur) {
elemConfig.$currentTarget.blur(); // Otherwise 'enter' key might trigger the dialog again
}
fl.open(event);
};
$source.on(tempConfig.openTrigger+'.'+tempConfig.namespace, tempConfig.filter, handler);
return {filter: tempConfig.filter, handler: handler};
},
current: function() {
var all = this.opened();
return all[all.length - 1] || null;
},
opened: function() {
var klass = this;
pruneOpened();
return $.grep(opened, function(fl) { return fl instanceof klass; } );
},
close: function(event) {
var cur = this.current();
if(cur) { return cur.close(event); }
},
/* Does the auto binding on startup.
Meant only to be used by Featherlight and its extensions
*/
_onReady: function() {
var Klass = this;
if(Klass.autoBind){
var $autobound = $(Klass.autoBind);
/* Bind existing elements */
$autobound.each(function(){
Klass.attach($(this));
});
/* If a click propagates to the document level, then we have an item that was added later on */
$(document).on('click', Klass.autoBind, function(evt) {
if (evt.isDefaultPrevented()) {
return;
}
var $cur = $(evt.currentTarget);
var len = $autobound.length;
$autobound = $autobound.add($cur);
if(len === $autobound.length) {
return; /* already bound */
}
/* Bind featherlight */
var data = Klass.attach($cur);
/* Dispatch event directly */
if (!data.filter || $(evt.target).parentsUntil($cur, data.filter).length > 0) {
data.handler(evt);
}
});
}
},
/* Featherlight uses the onKeyUp callback to intercept the escape key.
Private to Featherlight.
*/
_callbackChain: {
onKeyUp: function(_super, event){
if(27 === event.keyCode) {
if (this.closeOnEsc) {
$.featherlight.close(event);
}
return false;
} else {
return _super(event);
}
},
beforeOpen: function(_super, event) {
// Used to disable scrolling
$(document.documentElement).addClass('with-featherlight');
// Remember focus:
this._previouslyActive = document.activeElement;
// Disable tabbing:
// See http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus
this._$previouslyTabbable = $("a, input, select, textarea, iframe, button, iframe, [contentEditable=true]")
.not('[tabindex]')
.not(this.$instance.find('button'));
this._$previouslyWithTabIndex = $('[tabindex]').not('[tabindex="-1"]');
this._previousWithTabIndices = this._$previouslyWithTabIndex.map(function(_i, elem) {
return $(elem).attr('tabindex');
});
this._$previouslyWithTabIndex.add(this._$previouslyTabbable).attr('tabindex', -1);
if (document.activeElement.blur) {
document.activeElement.blur();
}
return _super(event);
},
afterClose: function(_super, event) {
var r = _super(event);
// Restore focus
var self = this;
this._$previouslyTabbable.removeAttr('tabindex');
this._$previouslyWithTabIndex.each(function(i, elem) {
$(elem).attr('tabindex', self._previousWithTabIndices[i]);
});
this._previouslyActive.focus();
// Restore scroll
if(Featherlight.opened().length === 0) {
$(document.documentElement).removeClass('with-featherlight');
}
return r;
},
onResize: function(_super, event){
this.resize(this.$content.naturalWidth, this.$content.naturalHeight);
return _super(event);
},
afterContent: function(_super, event){
var r = _super(event);
this.$instance.find('[autofocus]:not([disabled])').focus();
this.onResize(event);
return r;
}
}
});
$.featherlight = Featherlight;
/* bind jQuery elements to trigger featherlight */
$.fn.featherlight = function($content, config) {
Featherlight.attach(this, $content, config);
return this;
};
/* bind featherlight on ready if config autoBind is set */
$(document).ready(function(){ Featherlight._onReady(); });
});

60
js/gcodeprocessing.js Normal file
View File

@ -0,0 +1,60 @@
function downloadFile(filename, contents) {
var blob = new Blob([contents], {type: 'text/plain'});
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, filename);
} else{
var e = document.createEvent('MouseEvents'),
a = document.createElement('a');
a.download = filename;
a.href = window.URL.createObjectURL(blob);
a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':');
e.initEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
}
}
function processBaseline(){
var hotendTemp = document.baselineForm.hotendtemp.value;
var bedTemp = document.baselineForm.bedtemp.value;
var bedX = Math.round((document.baselineForm.bedx.value-100)/2);
var bedY = Math.round((document.baselineForm.bedy.value-100)/2);
var retDist = document.baselineForm.retdist.value;
var retSpeed = document.baselineForm.retspeed.value*60;
var abl = document.baselineForm.abl.value;
var baseline = originalBaseline;
if(abl == 1){
baseline = baseline.replace(/;G29 ; probe ABL/, "G29 ; probe ABL");
}
if(abl == 2){
baseline = baseline.replace(/;M420 S1 ; restore ABL mesh/, "M420 S1 ; restore ABL mesh");
}
baseline = baseline.replace(/M140 S60/g, "M140 S"+bedTemp);
baseline = baseline.replace(/M190 S60/g, "M140 S"+bedTemp);
baseline = baseline.replace(/M104 S210/g, "M104 S"+hotendTemp);
baseline = baseline.replace(/M109 S210/g, "M109 S"+hotendTemp);
baseline = baseline.replace(/G1 E-5.0000 F2400/g, "G1 E-"+retDist+" F"+retSpeed);
baseline = baseline.replace(/G1 E0.0000 F2400/g, "G1 E0.0000 F"+retSpeed);
if(bedX > 0){
var baselineArray = baseline.split(/\n/g);
baselineArray.forEach(function(index, item){
if(baselineArray[item].search(/X/) > -1){
var value = parseInt(baselineArray[item].match(/X\d+/)[0].substring(1)) + bedX
baselineArray[item] = baselineArray[item].replace(/X\d+/, "X"+String(value));
}
});
baseline = baselineArray.join("\n");
}
if(bedY > 0){
var baselineArray = baseline.split(/\n/g);
baselineArray.forEach(function(index, item){
if(baselineArray[item].search(/Y/) > -1){
var value = parseInt(baselineArray[item].match(/Y\d+/)[0].substring(1)) + bedY
baselineArray[item] = baselineArray[item].replace(/Y\d+/, "Y"+String(value))
}
});
baseline = baselineArray.join("\n");
}
downloadFile('baseline.gcode', baseline);
}

704
js/jquery.responsiveTabs.js Normal file
View File

@ -0,0 +1,704 @@
;(function ( $, window, undefined ) {
/** Default settings */
var defaults = {
active: null,
event: 'click',
disabled: [],
collapsible: 'accordion',
startCollapsed: false,
rotate: false,
setHash: false,
animation: 'default',
animationQueue: false,
duration: 500,
fluidHeight: true,
scrollToAccordion: false,
scrollToAccordionOnLoad: true,
scrollToAccordionOffset: 0,
accordionTabElement: '<div></div>',
navigationContainer: '',
click: function(){},
activate: function(){},
deactivate: function(){},
load: function(){},
activateState: function(){},
classes: {
stateDefault: 'r-tabs-state-default',
stateActive: 'r-tabs-state-active',
stateDisabled: 'r-tabs-state-disabled',
stateExcluded: 'r-tabs-state-excluded',
container: 'r-tabs',
ul: 'r-tabs-nav',
tab: 'r-tabs-tab',
anchor: 'r-tabs-anchor',
panel: 'r-tabs-panel',
accordionTitle: 'r-tabs-accordion-title'
}
};
/**
* Responsive Tabs
* @constructor
* @param {object} element - The HTML element the validator should be bound to
* @param {object} options - An option map
*/
function ResponsiveTabs(element, options) {
this.element = element; // Selected DOM element
this.$element = $(element); // Selected jQuery element
this.tabs = []; // Create tabs array
this.state = ''; // Define the plugin state (tabs/accordion)
this.rotateInterval = 0; // Define rotate interval
this.$queue = $({});
// Extend the defaults with the passed options
this.options = $.extend( {}, defaults, options);
this.init();
}
/**
* This function initializes the tab plugin
*/
ResponsiveTabs.prototype.init = function () {
var _this = this;
// Load all the elements
this.tabs = this._loadElements();
this._loadClasses();
this._loadEvents();
// Window resize bind to check state
$(window).on('resize', function(e) {
_this._setState(e);
if(_this.options.fluidHeight !== true) {
_this._equaliseHeights();
}
});
// Hashchange event
$(window).on('hashchange', function(e) {
var tabRef = _this._getTabRefBySelector(window.location.hash);
var oTab = _this._getTab(tabRef);
// Check if a tab is found that matches the hash
if(tabRef >= 0 && !oTab._ignoreHashChange && !oTab.disabled) {
// If so, open the tab and auto close the current one
_this._openTab(e, _this._getTab(tabRef), true);
}
});
// Start rotate event if rotate option is defined
if(this.options.rotate !== false) {
this.startRotation();
}
// Set fluid height
if(this.options.fluidHeight !== true) {
_this._equaliseHeights();
}
// --------------------
// Define plugin events
//
// Activate: this event is called when a tab is selected
this.$element.bind('tabs-click', function(e, oTab) {
_this.options.click.call(this, e, oTab);
});
// Activate: this event is called when a tab is selected
this.$element.bind('tabs-activate', function(e, oTab) {
_this.options.activate.call(this, e, oTab);
});
// Deactivate: this event is called when a tab is closed
this.$element.bind('tabs-deactivate', function(e, oTab) {
_this.options.deactivate.call(this, e, oTab);
});
// Activate State: this event is called when the plugin switches states
this.$element.bind('tabs-activate-state', function(e, state) {
_this.options.activateState.call(this, e, state);
});
// Load: this event is called when the plugin has been loaded
this.$element.bind('tabs-load', function(e) {
var startTab;
_this._setState(e); // Set state
// Check if the panel should be collaped on load
if(_this.options.startCollapsed !== true && !(_this.options.startCollapsed === 'accordion' && _this.state === 'accordion')) {
startTab = _this._getStartTab();
// Open the initial tab
_this._openTab(e, startTab); // Open first tab
// Call the callback function
_this.options.load.call(this, e, startTab); // Call the load callback
}
});
// Trigger loaded event
this.$element.trigger('tabs-load');
};
//
// PRIVATE FUNCTIONS
//
/**
* This function loads the tab elements and stores them in an array
* @returns {Array} Array of tab elements
*/
ResponsiveTabs.prototype._loadElements = function() {
var _this = this;
var $ul = (_this.options.navigationContainer === '') ? this.$element.children('ul:first') : this.$element.find(_this.options.navigationContainer).children('ul:first');
var tabs = [];
var id = 0;
// Add the classes to the basic html elements
this.$element.addClass(_this.options.classes.container); // Tab container
$ul.addClass(_this.options.classes.ul); // List container
// Get tab buttons and store their data in an array
$('li', $ul).each(function() {
var $tab = $(this);
var isExcluded = $tab.hasClass(_this.options.classes.stateExcluded);
var $anchor, $panel, $accordionTab, $accordionAnchor, panelSelector;
// Check if the tab should be excluded
if(!isExcluded) {
$anchor = $('a', $tab);
panelSelector = $anchor.attr('href');
$panel = $(panelSelector);
$accordionTab = $(_this.options.accordionTabElement).insertBefore($panel);
$accordionAnchor = $('<a></a>').attr('href', panelSelector).html($anchor.html()).appendTo($accordionTab);
var oTab = {
_ignoreHashChange: false,
id: id,
disabled: ($.inArray(id, _this.options.disabled) !== -1),
tab: $(this),
anchor: $('a', $tab),
panel: $panel,
selector: panelSelector,
accordionTab: $accordionTab,
accordionAnchor: $accordionAnchor,
active: false
};
// 1up the ID
id++;
// Add to tab array
tabs.push(oTab);
}
});
return tabs;
};
/**
* This function adds classes to the tab elements based on the options
*/
ResponsiveTabs.prototype._loadClasses = function() {
for (var i=0; i<this.tabs.length; i++) {
this.tabs[i].tab.addClass(this.options.classes.stateDefault).addClass(this.options.classes.tab);
this.tabs[i].anchor.addClass(this.options.classes.anchor);
this.tabs[i].panel.addClass(this.options.classes.stateDefault).addClass(this.options.classes.panel);
this.tabs[i].accordionTab.addClass(this.options.classes.accordionTitle);
this.tabs[i].accordionAnchor.addClass(this.options.classes.anchor);
if(this.tabs[i].disabled) {
this.tabs[i].tab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
this.tabs[i].accordionTab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
}
}
};
/**
* This function adds events to the tab elements
*/
ResponsiveTabs.prototype._loadEvents = function() {
var _this = this;
// Define activate event on a tab element
var fActivate = function(e) {
var current = _this._getCurrentTab(); // Fetch current tab
var activatedTab = e.data.tab;
e.preventDefault();
// Trigger click event for whenever a tab is clicked/touched even if the tab is disabled
activatedTab.tab.trigger('tabs-click', activatedTab);
// Make sure this tab isn't disabled
if(!activatedTab.disabled) {
// Check if hash has to be set in the URL location
if(_this.options.setHash) {
// Set the hash using the history api if available to tackle Chromes repaint bug on hash change
if(history.pushState) {
// Fix for missing window.location.origin in IE
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
history.pushState(null, null, window.location.origin + window.location.pathname + window.location.search + activatedTab.selector);
} else {
// Otherwise fallback to the hash update for sites that don't support the history api
window.location.hash = activatedTab.selector;
}
}
e.data.tab._ignoreHashChange = true;
// Check if the activated tab isnt the current one or if its collapsible. If not, do nothing
if(current !== activatedTab || _this._isCollapisble()) {
// The activated tab is either another tab of the current one. If it's the current tab it is collapsible
// Either way, the current tab can be closed
_this._closeTab(e, current);
// Check if the activated tab isnt the current one or if it isnt collapsible
if(current !== activatedTab || !_this._isCollapisble()) {
_this._openTab(e, activatedTab, false, true);
}
}
}
};
// Loop tabs
for (var i=0; i<this.tabs.length; i++) {
// Add activate function to the tab and accordion selection element
this.tabs[i].anchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate);
this.tabs[i].accordionAnchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate);
}
};
/**
* This function gets the tab that should be opened at start
* @returns {Object} Tab object
*/
ResponsiveTabs.prototype._getStartTab = function() {
var tabRef = this._getTabRefBySelector(window.location.hash);
var startTab;
// Check if the page has a hash set that is linked to a tab
if(tabRef >= 0 && !this._getTab(tabRef).disabled) {
// If so, set the current tab to the linked tab
startTab = this._getTab(tabRef);
} else if(this.options.active > 0 && !this._getTab(this.options.active).disabled) {
startTab = this._getTab(this.options.active);
} else {
// If not, just get the first one
startTab = this._getTab(0);
}
return startTab;
};
/**
* This function sets the current state of the plugin
* @param {Event} e - The event that triggers the state change
*/
ResponsiveTabs.prototype._setState = function(e) {
var $ul = $('ul:first', this.$element);
var oldState = this.state;
var startCollapsedIsState = (typeof this.options.startCollapsed === 'string');
var startTab;
// The state is based on the visibility of the tabs list
if($ul.is(':visible')){
// Tab list is visible, so the state is 'tabs'
this.state = 'tabs';
} else {
// Tab list is invisible, so the state is 'accordion'
this.state = 'accordion';
}
// If the new state is different from the old state
if(this.state !== oldState) {
// If so, the state activate trigger must be called
this.$element.trigger('tabs-activate-state', {oldState: oldState, newState: this.state});
// Check if the state switch should open a tab
if(oldState && startCollapsedIsState && this.options.startCollapsed !== this.state && this._getCurrentTab() === undefined) {
// Get initial tab
startTab = this._getStartTab(e);
// Open the initial tab
this._openTab(e, startTab); // Open first tab
}
}
};
/**
* This function opens a tab
* @param {Event} e - The event that triggers the tab opening
* @param {Object} oTab - The tab object that should be opened
* @param {Boolean} closeCurrent - Defines if the current tab should be closed
* @param {Boolean} stopRotation - Defines if the tab rotation loop should be stopped
*/
ResponsiveTabs.prototype._openTab = function(e, oTab, closeCurrent, stopRotation) {
var _this = this;
var scrollOffset;
// Check if the current tab has to be closed
if(closeCurrent) {
this._closeTab(e, this._getCurrentTab());
}
// Check if the rotation has to be stopped when activated
if(stopRotation && this.rotateInterval > 0) {
this.stopRotation();
}
// Set this tab to active
oTab.active = true;
// Set active classes to the tab button and accordion tab button
oTab.tab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
oTab.accordionTab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
// Run panel transiton
_this._doTransition(oTab.panel, _this.options.animation, 'open', function() {
var scrollOnLoad = (e.type !== 'tabs-load' || _this.options.scrollToAccordionOnLoad);
// When finished, set active class to the panel
oTab.panel.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
// And if enabled and state is accordion, scroll to the accordion tab
if(_this.getState() === 'accordion' && _this.options.scrollToAccordion && (!_this._isInView(oTab.accordionTab) || _this.options.animation !== 'default') && scrollOnLoad) {
// Add offset element's height to scroll position
scrollOffset = oTab.accordionTab.offset().top - _this.options.scrollToAccordionOffset;
// Check if the animation option is enabled, and if the duration isn't 0
if(_this.options.animation !== 'default' && _this.options.duration > 0) {
// If so, set scrollTop with animate and use the 'animation' duration
$('html, body').animate({
scrollTop: scrollOffset
}, _this.options.duration);
} else {
// If not, just set scrollTop
$('html, body').scrollTop(scrollOffset);
}
}
});
this.$element.trigger('tabs-activate', oTab);
};
/**
* This function closes a tab
* @param {Event} e - The event that is triggered when a tab is closed
* @param {Object} oTab - The tab object that should be closed
*/
ResponsiveTabs.prototype._closeTab = function(e, oTab) {
var _this = this;
var doQueueOnState = typeof _this.options.animationQueue === 'string';
var doQueue;
if(oTab !== undefined) {
if(doQueueOnState && _this.getState() === _this.options.animationQueue) {
doQueue = true;
} else if(doQueueOnState) {
doQueue = false;
} else {
doQueue = _this.options.animationQueue;
}
// Deactivate tab
oTab.active = false;
// Set default class to the tab button
oTab.tab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
// Run panel transition
_this._doTransition(oTab.panel, _this.options.animation, 'close', function() {
// Set default class to the accordion tab button and tab panel
oTab.accordionTab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
oTab.panel.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
}, !doQueue);
this.$element.trigger('tabs-deactivate', oTab);
}
};
/**
* This function runs an effect on a panel
* @param {Element} panel - The HTML element of the tab panel
* @param {String} method - The transition method reference
* @param {String} state - The state (open/closed) that the panel should transition to
* @param {Function} callback - The callback function that is called after the transition
* @param {Boolean} dequeue - Defines if the event queue should be dequeued after the transition
*/
ResponsiveTabs.prototype._doTransition = function(panel, method, state, callback, dequeue) {
var effect;
var _this = this;
// Get effect based on method
switch(method) {
case 'slide':
effect = (state === 'open') ? 'slideDown' : 'slideUp';
break;
case 'fade':
effect = (state === 'open') ? 'fadeIn' : 'fadeOut';
break;
default:
effect = (state === 'open') ? 'show' : 'hide';
// When default is used, set the duration to 0
_this.options.duration = 0;
break;
}
// Add the transition to a custom queue
this.$queue.queue('responsive-tabs',function(next){
// Run the transition on the panel
panel[effect]({
duration: _this.options.duration,
complete: function() {
// Call the callback function
callback.call(panel, method, state);
// Run the next function in the queue
next();
}
});
});
// When the panel is openend, dequeue everything so the animation starts
if(state === 'open' || dequeue) {
this.$queue.dequeue('responsive-tabs');
}
};
/**
* This function returns the collapsibility of the tab in this state
* @returns {Boolean} The collapsibility of the tab
*/
ResponsiveTabs.prototype._isCollapisble = function() {
return (typeof this.options.collapsible === 'boolean' && this.options.collapsible) || (typeof this.options.collapsible === 'string' && this.options.collapsible === this.getState());
};
/**
* This function returns a tab by numeric reference
* @param {Integer} numRef - Numeric tab reference
* @returns {Object} Tab object
*/
ResponsiveTabs.prototype._getTab = function(numRef) {
return this.tabs[numRef];
};
/**
* This function returns the numeric tab reference based on a hash selector
* @param {String} selector - Hash selector
* @returns {Integer} Numeric tab reference
*/
ResponsiveTabs.prototype._getTabRefBySelector = function(selector) {
// Loop all tabs
for (var i=0; i<this.tabs.length; i++) {
// Check if the hash selector is equal to the tab selector
if(this.tabs[i].selector === selector) {
return i;
}
}
// If none is found return a negative index
return -1;
};
/**
* This function returns the current tab element
* @returns {Object} Current tab element
*/
ResponsiveTabs.prototype._getCurrentTab = function() {
return this._getTab(this._getCurrentTabRef());
};
/**
* This function returns the next tab's numeric reference
* @param {Integer} currentTabRef - Current numeric tab reference
* @returns {Integer} Numeric tab reference
*/
ResponsiveTabs.prototype._getNextTabRef = function(currentTabRef) {
var tabRef = (currentTabRef || this._getCurrentTabRef());
var nextTabRef = (tabRef === this.tabs.length - 1) ? 0 : tabRef + 1;
return (this._getTab(nextTabRef).disabled) ? this._getNextTabRef(nextTabRef) : nextTabRef;
};
/**
* This function returns the previous tab's numeric reference
* @returns {Integer} Numeric tab reference
*/
ResponsiveTabs.prototype._getPreviousTabRef = function() {
return (this._getCurrentTabRef() === 0) ? this.tabs.length - 1 : this._getCurrentTabRef() - 1;
};
/**
* This function returns the current tab's numeric reference
* @returns {Integer} Numeric tab reference
*/
ResponsiveTabs.prototype._getCurrentTabRef = function() {
// Loop all tabs
for (var i=0; i<this.tabs.length; i++) {
// If this tab is active, return it
if(this.tabs[i].active) {
return i;
}
}
// No tabs have been found, return negative index
return -1;
};
/**
* This function gets the tallest tab and applied the height to all tabs
*/
ResponsiveTabs.prototype._equaliseHeights = function() {
var maxHeight = 0;
$.each($.map(this.tabs, function(tab) {
maxHeight = Math.max(maxHeight, tab.panel.css('minHeight', '').height());
return tab.panel;
}), function() {
this.css('minHeight', maxHeight);
});
};
//
// HELPER FUNCTIONS
//
ResponsiveTabs.prototype._isInView = function($element) {
var docViewTop = $(window).scrollTop(),
docViewBottom = docViewTop + $(window).height(),
elemTop = $element.offset().top,
elemBottom = elemTop + $element.height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
};
//
// PUBLIC FUNCTIONS
//
/**
* This function activates a tab
* @param {Integer} tabRef - Numeric tab reference
* @param {Boolean} stopRotation - Defines if the tab rotation should stop after activation
*/
ResponsiveTabs.prototype.activate = function(tabRef, stopRotation) {
var e = jQuery.Event('tabs-activate');
var oTab = this._getTab(tabRef);
if(!oTab.disabled) {
this._openTab(e, oTab, true, stopRotation || true);
}
};
/**
* This function deactivates a tab
* @param {Integer} tabRef - Numeric tab reference
*/
ResponsiveTabs.prototype.deactivate = function(tabRef) {
var e = jQuery.Event('tabs-dectivate');
var oTab = this._getTab(tabRef);
if(!oTab.disabled) {
this._closeTab(e, oTab);
}
};
/**
* This function enables a tab
* @param {Integer} tabRef - Numeric tab reference
*/
ResponsiveTabs.prototype.enable = function(tabRef) {
var oTab = this._getTab(tabRef);
if(oTab){
oTab.disabled = false;
oTab.tab.addClass(this.options.classes.stateDefault).removeClass(this.options.classes.stateDisabled);
oTab.accordionTab.addClass(this.options.classes.stateDefault).removeClass(this.options.classes.stateDisabled);
}
};
/**
* This function disable a tab
* @param {Integer} tabRef - Numeric tab reference
*/
ResponsiveTabs.prototype.disable = function(tabRef) {
var oTab = this._getTab(tabRef);
if(oTab){
oTab.disabled = true;
oTab.tab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
oTab.accordionTab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
}
};
/**
* This function gets the current state of the plugin
* @returns {String} State of the plugin
*/
ResponsiveTabs.prototype.getState = function() {
return this.state;
};
/**
* This function starts the rotation of the tabs
* @param {Integer} speed - The speed of the rotation
*/
ResponsiveTabs.prototype.startRotation = function(speed) {
var _this = this;
// Make sure not all tabs are disabled
if(this.tabs.length > this.options.disabled.length) {
this.rotateInterval = setInterval(function(){
var e = jQuery.Event('rotate');
_this._openTab(e, _this._getTab(_this._getNextTabRef()), true);
}, speed || (($.isNumeric(_this.options.rotate)) ? _this.options.rotate : 4000) );
} else {
throw new Error("Rotation is not possible if all tabs are disabled");
}
};
/**
* This function stops the rotation of the tabs
*/
ResponsiveTabs.prototype.stopRotation = function() {
window.clearInterval(this.rotateInterval);
this.rotateInterval = 0;
};
/**
* This function can be used to get/set options
* @return {any} Option value
*/
ResponsiveTabs.prototype.option = function(key, value) {
if(value) {
this.options[key] = value;
}
return this.options[key];
};
/** jQuery wrapper */
$.fn.responsiveTabs = function ( options ) {
var args = arguments;
var instance;
if (options === undefined || typeof options === 'object') {
return this.each(function () {
if (!$.data(this, 'responsivetabs')) {
$.data(this, 'responsivetabs', new ResponsiveTabs( this, options ));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
instance = $.data(this[0], 'responsivetabs');
// Allow instances to be destroyed via the 'destroy' method
if (options === 'destroy') {
// TODO: destroy instance classes, etc
$.data(this, 'responsivetabs', null);
}
if (instance instanceof ResponsiveTabs && typeof instance[options] === 'function') {
return instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
} else {
return this;
}
}
};
}(jQuery, window));

172
js/videobox.js Normal file
View File

@ -0,0 +1,172 @@
/*
* VideoBox
* Example and Documentation: https://github.com/tedktedk/videobox/blob/master/README.md
*
* Version: 1.1
*
* Copyright (c) 2016 Ted k'
* http://tedk.com.br/
*
* Dual licensed under the MIT or GPL Version 2 licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function($){
$.fn.extend({
videoBox: function(options){
var obj = $(this);
var tag_v = document.createElement("script");
var firstScriptTag = document.getElementsByTagName("script")[0];
var defaults_yt = {
autohide: 2,
autoplay: 0,
cc_load_policy: 1,
color: "",
controls: 1,
disablekb: 0,
enablejsapi: 0,
fs: 1,
hl: "",
iv_load_policy: 1,
loop: 0,
modestbranding: 1,
showinfo: 1,
height: 390,
width: 640
};
var defaults_vm = {
width: 640,
height: 360,
loop: false,
autoplay: false,
byline: true,
color: "00adef",
maxheight: "",
maxwidth: "",
portrait: true,
title: ""
};
var defaults_k = {
partner_id: "243342",
uiconf_id: "12905712",
entry_id: "0_uka1msg4",
width: 640,
height: 360,
switchOnResize: false,
simpleFormat: true,
displayMode: "sizebitrate",
inlineScript: false,
hideSource: null,
autoPlay: false
};
var options_yt = $.extend(defaults_yt, options);
var options_vm = $.extend(defaults_vm, options);
var options_k = $.extend(defaults_k, options);
$.each( obj, function( key, value ){
var _this = $(value);
if (_this.attr("data-youtube")){
tag_v.id = "VIDEOBOX_createTag_y";
if (!document.getElementById("VIDEOBOX_createTag_y")){
tag_v.src = "https://www.youtube.com/iframe_api";
firstScriptTag.parentNode.insertBefore(tag_v, firstScriptTag);
}
}
else if (_this.attr("data-vimeo")){
var randomID = "VIDEOBOX_" + Math.floor(Math.random() * 100) + key;
var returnID = _this.attr("data-vimeo").match(/https?:\/\/(?:www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|)(\d+)(?:$|\/|\?)/);
tag_v.id = "VIDEOBOX_createTag_v";
_this.attr("id", randomID);
if (!document.getElementById("VIDEOBOX_createTag_v")){
tag_v.src = "https://player.vimeo.com/api/player.js";
firstScriptTag.parentNode.insertBefore(tag_v, firstScriptTag);
}
tag_v.addEventListener("load", function(e){
options_vm.id = returnID[3];
return new Vimeo.Player(document.getElementById(randomID), options_vm);
}, false);
}
else if (_this.attr("data-kaltura")){
var randomID = "VIDEOBOX_k_" + Math.floor(Math.random() * 100) + key;
tag_v.id = "VIDEOBOX_createTag_k";
_this.attr("id", randomID);
_this.attr("itemprop", "video");
_this.attr("itemscope", true);
_this.attr("itemtype", "http://schema.org/VideoObject");
_this.css({ "width": options_k.width + "px", "height": options_k.height + "px" });
if (!document.getElementById("VIDEOBOX_createTag_k")){
tag_v.src = "https://cdnapisec.kaltura.com/p/" + options_k.partner_id + "/sp/" + options_k.partner_id + "00/embedIframeJs/uiconf_id/" + options_k.uiconf_id + "/partner_id/" + options_k.partner_id + "";
firstScriptTag.parentNode.insertBefore(tag_v, firstScriptTag);
}
tag_v.addEventListener("load", function(e){
kWidget.embed({
targetId: randomID,
wid: "_" + options_k.partner_id,
uiconf_id: options_k.uiconf_id,
entry_id: options_k.entry_id,
flashvars: {
"sourceSelector": {
"plugin": true,
"switchOnResize": options_k.switchOnResize,
"simpleFormat": options_k.simpleFormat,
"displayMode": options_k.displayMode,
"hideSource": options_k.hideSource
},
"mediaProxy.preferedFlavorBR": "1600",
"autoPlay": options_k.autoPlay,
"inlineScript": options_k.inlineScript
}
});
}, false);
}
});
window.onYouTubeIframeAPIReady = function(){
$.each( obj, function( key, value ){
var _this = $(value);
var randomID = "VIDEOBOX_" + Math.floor(Math.random() * 100) + key;
if (_this.attr("data-youtube")){
_this.attr("id", randomID);
var returnID = _this.attr("data-youtube").match(/(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/);
return new YT.Player(randomID, {
height: options_yt.height,
width: options_yt.width,
videoId: returnID[1],
playerVars: {
"autohide": options_yt.autohide,
"autoplay": options_yt.autoplay,
"cc_load_policy": options_yt.cc_load_policy,
"color": options_yt.color,
"controls": options_yt.controls,
"disablekb": options_yt.disablekb,
"enablejsapi": options_yt.enablejsapi,
"fs": options_yt.fs,
"hl": options_yt.hl,
"iv_load_policy": options_yt.iv_load_policy,
"loop": options_yt.loop,
"modestbranding": options_yt.modestbranding,
"showinfo": options_yt.showinfo,
"height": options_yt.height,
"width": options_yt.width
}
});
}
});
};
}
});
})(jQuery);