@ -1,159 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
(function($) { |
|||
'use strict'; |
|||
|
|||
window.Toc = { |
|||
helpers: { |
|||
// return all matching elements in the set, or their descendants
|
|||
findOrFilter: function($el, selector) { |
|||
// http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
|
|||
// http://stackoverflow.com/a/12731439/358804
|
|||
var $descendants = $el.find(selector); |
|||
return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); |
|||
}, |
|||
|
|||
generateUniqueIdBase: function(el) { |
|||
var text = $(el).text(); |
|||
var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); |
|||
return anchor || el.tagName.toLowerCase(); |
|||
}, |
|||
|
|||
generateUniqueId: function(el) { |
|||
var anchorBase = this.generateUniqueIdBase(el); |
|||
for (var i = 0; ; i++) { |
|||
var anchor = anchorBase; |
|||
if (i > 0) { |
|||
// add suffix
|
|||
anchor += '-' + i; |
|||
} |
|||
// check if ID already exists
|
|||
if (!document.getElementById(anchor)) { |
|||
return anchor; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
generateAnchor: function(el) { |
|||
if (el.id) { |
|||
return el.id; |
|||
} else { |
|||
var anchor = this.generateUniqueId(el); |
|||
el.id = anchor; |
|||
return anchor; |
|||
} |
|||
}, |
|||
|
|||
createNavList: function() { |
|||
return $('<ul class="nav navbar-nav"></ul>'); |
|||
}, |
|||
|
|||
createChildNavList: function($parent) { |
|||
var $childList = this.createNavList(); |
|||
$parent.append($childList); |
|||
return $childList; |
|||
}, |
|||
|
|||
generateNavEl: function(anchor, text) { |
|||
var $a = $('<a class="nav-link"></a>'); |
|||
$a.attr('href', '#' + anchor); |
|||
$a.text(text); |
|||
var $li = $('<li></li>'); |
|||
$li.append($a); |
|||
return $li; |
|||
}, |
|||
|
|||
generateNavItem: function(headingEl) { |
|||
var anchor = this.generateAnchor(headingEl); |
|||
var $heading = $(headingEl); |
|||
var text = $heading.data('toc-text') || $heading.text(); |
|||
return this.generateNavEl(anchor, text); |
|||
}, |
|||
|
|||
// Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
|
|||
getTopLevel: function($scope) { |
|||
for (var i = 1; i <= 6; i++) { |
|||
var $headings = this.findOrFilter($scope, 'h' + i); |
|||
if ($headings.length > 1) { |
|||
return i; |
|||
} |
|||
} |
|||
|
|||
return 1; |
|||
}, |
|||
|
|||
// returns the elements for the top level, and the next below it
|
|||
getHeadings: function($scope, topLevel) { |
|||
var topSelector = 'h' + topLevel; |
|||
|
|||
var secondaryLevel = topLevel + 1; |
|||
var secondarySelector = 'h' + secondaryLevel; |
|||
|
|||
return this.findOrFilter($scope, topSelector + ',' + secondarySelector); |
|||
}, |
|||
|
|||
getNavLevel: function(el) { |
|||
return parseInt(el.tagName.charAt(1), 10); |
|||
}, |
|||
|
|||
populateNav: function($topContext, topLevel, $headings) { |
|||
var $context = $topContext; |
|||
var $prevNav; |
|||
|
|||
var helpers = this; |
|||
$headings.each(function(i, el) { |
|||
var $newNav = helpers.generateNavItem(el); |
|||
var navLevel = helpers.getNavLevel(el); |
|||
|
|||
// determine the proper $context
|
|||
if (navLevel === topLevel) { |
|||
// use top level
|
|||
$context = $topContext; |
|||
} else if ($prevNav && $context === $topContext) { |
|||
// create a new level of the tree and switch to it
|
|||
$context = helpers.createChildNavList($prevNav); |
|||
} // else use the current $context
|
|||
|
|||
$context.append($newNav); |
|||
|
|||
$prevNav = $newNav; |
|||
}); |
|||
}, |
|||
|
|||
parseOps: function(arg) { |
|||
var opts; |
|||
if (arg.jquery) { |
|||
opts = { |
|||
$nav: arg |
|||
}; |
|||
} else { |
|||
opts = arg; |
|||
} |
|||
opts.$scope = opts.$scope || $(document.body); |
|||
return opts; |
|||
} |
|||
}, |
|||
|
|||
// accepts a jQuery object, or an options object
|
|||
init: function(opts) { |
|||
opts = this.helpers.parseOps(opts); |
|||
|
|||
// ensure that the data attribute is in place for styling
|
|||
opts.$nav.attr('data-toggle', 'toc'); |
|||
|
|||
var $topContext = this.helpers.createChildNavList(opts.$nav); |
|||
var topLevel = this.helpers.getTopLevel(opts.$scope); |
|||
var $headings = this.helpers.getHeadings(opts.$scope, topLevel); |
|||
this.helpers.populateNav($topContext, topLevel, $headings); |
|||
} |
|||
}; |
|||
|
|||
$(function() { |
|||
$('nav[data-toggle="toc"]').each(function(i, el) { |
|||
var $nav = $(el); |
|||
Toc.init($nav); |
|||
}); |
|||
}); |
|||
})(jQuery); |
|||
@ -1,4 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/) |
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */nav[data-toggle=toc] .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}nav[data-toggle=toc] .nav>li>a:focus,nav[data-toggle=toc] .nav>li>a:hover{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}nav[data-toggle=toc] .nav-link.active,nav[data-toggle=toc] .nav-link.active:focus,nav[data-toggle=toc] .nav-link.active:hover{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}nav[data-toggle=toc] .nav-link+ul{display:none;padding-bottom:10px}nav[data-toggle=toc] .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}nav[data-toggle=toc] .nav .nav>li>a:focus,nav[data-toggle=toc] .nav .nav>li>a:hover{padding-left:29px}nav[data-toggle=toc] .nav .nav>li>.active,nav[data-toggle=toc] .nav .nav>li>.active:focus,nav[data-toggle=toc] .nav .nav>li>.active:hover{padding-left:28px;font-weight:500}nav[data-toggle=toc] .nav-link.active+ul{display:block} |
|||
@ -1,5 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
!function(e){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(t){var n=e(t).text(),r=n.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g,"-");return r||t.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(n>0&&(r+="-"+n),!document.getElementById(r))return r}},generateAnchor:function(e){if(e.id)return e.id;var t=this.generateUniqueId(e);return e.id=t,t},createNavList:function(){return e('<ul class="nav navbar-nav"></ul>')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(t,n){var r=e('<a class="nav-link"></a>');r.attr("href","#"+t),r.text(n);var a=e("<li></li>");return a.append(r),a},generateNavItem:function(t){var n=this.generateAnchor(t),r=e(t),a=r.data("toc-text")||r.text();return this.generateNavEl(n,a)},getTopLevel:function(e){for(var t=1;t<=6;t++){var n=this.findOrFilter(e,"h"+t);if(n.length>1)return t}return 1},getHeadings:function(e,t){var n="h"+t,r=t+1,a="h"+r;return this.findOrFilter(e,n+","+a)},getNavLevel:function(e){return parseInt(e.tagName.charAt(1),10)},populateNav:function(e,t,n){var r,a=e,i=this;n.each(function(n,o){var s=i.generateNavItem(o),u=i.getNavLevel(o);u===t?a=e:r&&a===e&&(a=i.createChildNavList(r)),a.append(s),r=s})},parseOps:function(t){var n;return n=t.jquery?{$nav:t}:t,n.$scope=n.$scope||e(document.body),n}},init:function(e){e=this.helpers.parseOps(e),e.$nav.attr("data-toggle","toc");var t=this.helpers.createChildNavList(e.$nav),n=this.helpers.getTopLevel(e.$scope),r=this.helpers.getHeadings(e.$scope,n);this.helpers.populateNav(t,n,r)}},e(function(){e('nav[data-toggle="toc"]').each(function(t,n){var r=e(n);Toc.init(r)})})}(jQuery); |
|||
@ -0,0 +1,978 @@ |
|||
/*! |
|||
* clipboard.js v2.0.4 |
|||
* https://zenorocha.github.io/clipboard.js
|
|||
* |
|||
* Licensed MIT © Zeno Rocha |
|||
*/ |
|||
(function webpackUniversalModuleDefinition(root, factory) { |
|||
if(typeof exports === 'object' && typeof module === 'object') |
|||
module.exports = factory(); |
|||
else if(typeof define === 'function' && define.amd) |
|||
define([], factory); |
|||
else if(typeof exports === 'object') |
|||
exports["ClipboardJS"] = factory(); |
|||
else |
|||
root["ClipboardJS"] = factory(); |
|||
})(this, function() { |
|||
return /******/ (function(modules) { // webpackBootstrap
|
|||
/******/ // The module cache
|
|||
/******/ var installedModules = {}; |
|||
/******/ |
|||
/******/ // The require function
|
|||
/******/ function __webpack_require__(moduleId) { |
|||
/******/ |
|||
/******/ // Check if module is in cache
|
|||
/******/ if(installedModules[moduleId]) { |
|||
/******/ return installedModules[moduleId].exports; |
|||
/******/ } |
|||
/******/ // Create a new module (and put it into the cache)
|
|||
/******/ var module = installedModules[moduleId] = { |
|||
/******/ i: moduleId, |
|||
/******/ l: false, |
|||
/******/ exports: {} |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Execute the module function
|
|||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
|||
/******/ |
|||
/******/ // Flag the module as loaded
|
|||
/******/ module.l = true; |
|||
/******/ |
|||
/******/ // Return the exports of the module
|
|||
/******/ return module.exports; |
|||
/******/ } |
|||
/******/ |
|||
/******/ |
|||
/******/ // expose the modules object (__webpack_modules__)
|
|||
/******/ __webpack_require__.m = modules; |
|||
/******/ |
|||
/******/ // expose the module cache
|
|||
/******/ __webpack_require__.c = installedModules; |
|||
/******/ |
|||
/******/ // define getter function for harmony exports
|
|||
/******/ __webpack_require__.d = function(exports, name, getter) { |
|||
/******/ if(!__webpack_require__.o(exports, name)) { |
|||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); |
|||
/******/ } |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // define __esModule on exports
|
|||
/******/ __webpack_require__.r = function(exports) { |
|||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
|||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
|||
/******/ } |
|||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // create a fake namespace object
|
|||
/******/ // mode & 1: value is a module id, require it
|
|||
/******/ // mode & 2: merge all properties of value into the ns
|
|||
/******/ // mode & 4: return value when already ns object
|
|||
/******/ // mode & 8|1: behave like require
|
|||
/******/ __webpack_require__.t = function(value, mode) { |
|||
/******/ if(mode & 1) value = __webpack_require__(value); |
|||
/******/ if(mode & 8) return value; |
|||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; |
|||
/******/ var ns = Object.create(null); |
|||
/******/ __webpack_require__.r(ns); |
|||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); |
|||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); |
|||
/******/ return ns; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|||
/******/ __webpack_require__.n = function(module) { |
|||
/******/ var getter = module && module.__esModule ? |
|||
/******/ function getDefault() { return module['default']; } : |
|||
/******/ function getModuleExports() { return module; }; |
|||
/******/ __webpack_require__.d(getter, 'a', getter); |
|||
/******/ return getter; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Object.prototype.hasOwnProperty.call
|
|||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
|||
/******/ |
|||
/******/ // __webpack_public_path__
|
|||
/******/ __webpack_require__.p = ""; |
|||
/******/ |
|||
/******/ |
|||
/******/ // Load entry module and return exports
|
|||
/******/ return __webpack_require__(__webpack_require__.s = 0); |
|||
/******/ }) |
|||
/************************************************************************/ |
|||
/******/ ([ |
|||
/* 0 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
|
|||
|
|||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; |
|||
|
|||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); |
|||
|
|||
var _clipboardAction = __webpack_require__(1); |
|||
|
|||
var _clipboardAction2 = _interopRequireDefault(_clipboardAction); |
|||
|
|||
var _tinyEmitter = __webpack_require__(3); |
|||
|
|||
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter); |
|||
|
|||
var _goodListener = __webpack_require__(4); |
|||
|
|||
var _goodListener2 = _interopRequireDefault(_goodListener); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
|||
|
|||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } |
|||
|
|||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } |
|||
|
|||
/** |
|||
* Base class which takes one or more elements, adds event listeners to them, |
|||
* and instantiates a new `ClipboardAction` on each click. |
|||
*/ |
|||
var Clipboard = function (_Emitter) { |
|||
_inherits(Clipboard, _Emitter); |
|||
|
|||
/** |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger |
|||
* @param {Object} options |
|||
*/ |
|||
function Clipboard(trigger, options) { |
|||
_classCallCheck(this, Clipboard); |
|||
|
|||
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); |
|||
|
|||
_this.resolveOptions(options); |
|||
_this.listenClick(trigger); |
|||
return _this; |
|||
} |
|||
|
|||
/** |
|||
* Defines if attributes would be resolved using internal setter functions |
|||
* or custom functions that were passed in the constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
_createClass(Clipboard, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = typeof options.action === 'function' ? options.action : this.defaultAction; |
|||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; |
|||
this.text = typeof options.text === 'function' ? options.text : this.defaultText; |
|||
this.container = _typeof(options.container) === 'object' ? options.container : document.body; |
|||
} |
|||
|
|||
/** |
|||
* Adds a click event listener to the passed trigger. |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'listenClick', |
|||
value: function listenClick(trigger) { |
|||
var _this2 = this; |
|||
|
|||
this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) { |
|||
return _this2.onClick(e); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Defines a new `ClipboardAction` on each click event. |
|||
* @param {Event} e |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'onClick', |
|||
value: function onClick(e) { |
|||
var trigger = e.delegateTarget || e.currentTarget; |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction = null; |
|||
} |
|||
|
|||
this.clipboardAction = new _clipboardAction2.default({ |
|||
action: this.action(trigger), |
|||
target: this.target(trigger), |
|||
text: this.text(trigger), |
|||
container: this.container, |
|||
trigger: trigger, |
|||
emitter: this |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Default `action` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultAction', |
|||
value: function defaultAction(trigger) { |
|||
return getAttributeValue('action', trigger); |
|||
} |
|||
|
|||
/** |
|||
* Default `target` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultTarget', |
|||
value: function defaultTarget(trigger) { |
|||
var selector = getAttributeValue('target', trigger); |
|||
|
|||
if (selector) { |
|||
return document.querySelector(selector); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Returns the support of the given action, or all actions if no action is |
|||
* given. |
|||
* @param {String} [action] |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultText', |
|||
|
|||
|
|||
/** |
|||
* Default `text` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
value: function defaultText(trigger) { |
|||
return getAttributeValue('text', trigger); |
|||
} |
|||
|
|||
/** |
|||
* Destroy lifecycle. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'destroy', |
|||
value: function destroy() { |
|||
this.listener.destroy(); |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction.destroy(); |
|||
this.clipboardAction = null; |
|||
} |
|||
} |
|||
}], [{ |
|||
key: 'isSupported', |
|||
value: function isSupported() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; |
|||
|
|||
var actions = typeof action === 'string' ? [action] : action; |
|||
var support = !!document.queryCommandSupported; |
|||
|
|||
actions.forEach(function (action) { |
|||
support = support && !!document.queryCommandSupported(action); |
|||
}); |
|||
|
|||
return support; |
|||
} |
|||
}]); |
|||
|
|||
return Clipboard; |
|||
}(_tinyEmitter2.default); |
|||
|
|||
/** |
|||
* Helper function to retrieve attribute value. |
|||
* @param {String} suffix |
|||
* @param {Element} element |
|||
*/ |
|||
|
|||
|
|||
function getAttributeValue(suffix, element) { |
|||
var attribute = 'data-clipboard-' + suffix; |
|||
|
|||
if (!element.hasAttribute(attribute)) { |
|||
return; |
|||
} |
|||
|
|||
return element.getAttribute(attribute); |
|||
} |
|||
|
|||
module.exports = Clipboard; |
|||
|
|||
/***/ }), |
|||
/* 1 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
|
|||
|
|||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; |
|||
|
|||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); |
|||
|
|||
var _select = __webpack_require__(2); |
|||
|
|||
var _select2 = _interopRequireDefault(_select); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
|||
|
|||
/** |
|||
* Inner class which performs selection from either `text` or `target` |
|||
* properties and then executes copy or cut operations. |
|||
*/ |
|||
var ClipboardAction = function () { |
|||
/** |
|||
* @param {Object} options |
|||
*/ |
|||
function ClipboardAction(options) { |
|||
_classCallCheck(this, ClipboardAction); |
|||
|
|||
this.resolveOptions(options); |
|||
this.initSelection(); |
|||
} |
|||
|
|||
/** |
|||
* Defines base properties passed from constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
_createClass(ClipboardAction, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = options.action; |
|||
this.container = options.container; |
|||
this.emitter = options.emitter; |
|||
this.target = options.target; |
|||
this.text = options.text; |
|||
this.trigger = options.trigger; |
|||
|
|||
this.selectedText = ''; |
|||
} |
|||
|
|||
/** |
|||
* Decides which selection strategy is going to be applied based |
|||
* on the existence of `text` and `target` properties. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'initSelection', |
|||
value: function initSelection() { |
|||
if (this.text) { |
|||
this.selectFake(); |
|||
} else if (this.target) { |
|||
this.selectTarget(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Creates a fake textarea element, sets its value from `text` property, |
|||
* and makes a selection on it. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'selectFake', |
|||
value: function selectFake() { |
|||
var _this = this; |
|||
|
|||
var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; |
|||
|
|||
this.removeFake(); |
|||
|
|||
this.fakeHandlerCallback = function () { |
|||
return _this.removeFake(); |
|||
}; |
|||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; |
|||
|
|||
this.fakeElem = document.createElement('textarea'); |
|||
// Prevent zooming on iOS
|
|||
this.fakeElem.style.fontSize = '12pt'; |
|||
// Reset box model
|
|||
this.fakeElem.style.border = '0'; |
|||
this.fakeElem.style.padding = '0'; |
|||
this.fakeElem.style.margin = '0'; |
|||
// Move element out of screen horizontally
|
|||
this.fakeElem.style.position = 'absolute'; |
|||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; |
|||
// Move element to the same position vertically
|
|||
var yPosition = window.pageYOffset || document.documentElement.scrollTop; |
|||
this.fakeElem.style.top = yPosition + 'px'; |
|||
|
|||
this.fakeElem.setAttribute('readonly', ''); |
|||
this.fakeElem.value = this.text; |
|||
|
|||
this.container.appendChild(this.fakeElem); |
|||
|
|||
this.selectedText = (0, _select2.default)(this.fakeElem); |
|||
this.copyText(); |
|||
} |
|||
|
|||
/** |
|||
* Only removes the fake element after another click event, that way |
|||
* a user can hit `Ctrl+C` to copy because selection still exists. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'removeFake', |
|||
value: function removeFake() { |
|||
if (this.fakeHandler) { |
|||
this.container.removeEventListener('click', this.fakeHandlerCallback); |
|||
this.fakeHandler = null; |
|||
this.fakeHandlerCallback = null; |
|||
} |
|||
|
|||
if (this.fakeElem) { |
|||
this.container.removeChild(this.fakeElem); |
|||
this.fakeElem = null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Selects the content from element passed on `target` property. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'selectTarget', |
|||
value: function selectTarget() { |
|||
this.selectedText = (0, _select2.default)(this.target); |
|||
this.copyText(); |
|||
} |
|||
|
|||
/** |
|||
* Executes the copy operation based on the current selection. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'copyText', |
|||
value: function copyText() { |
|||
var succeeded = void 0; |
|||
|
|||
try { |
|||
succeeded = document.execCommand(this.action); |
|||
} catch (err) { |
|||
succeeded = false; |
|||
} |
|||
|
|||
this.handleResult(succeeded); |
|||
} |
|||
|
|||
/** |
|||
* Fires an event based on the copy operation result. |
|||
* @param {Boolean} succeeded |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'handleResult', |
|||
value: function handleResult(succeeded) { |
|||
this.emitter.emit(succeeded ? 'success' : 'error', { |
|||
action: this.action, |
|||
text: this.selectedText, |
|||
trigger: this.trigger, |
|||
clearSelection: this.clearSelection.bind(this) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Moves focus away from `target` and back to the trigger, removes current selection. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'clearSelection', |
|||
value: function clearSelection() { |
|||
if (this.trigger) { |
|||
this.trigger.focus(); |
|||
} |
|||
|
|||
window.getSelection().removeAllRanges(); |
|||
} |
|||
|
|||
/** |
|||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. |
|||
* @param {String} action |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'destroy', |
|||
|
|||
|
|||
/** |
|||
* Destroy lifecycle. |
|||
*/ |
|||
value: function destroy() { |
|||
this.removeFake(); |
|||
} |
|||
}, { |
|||
key: 'action', |
|||
set: function set() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; |
|||
|
|||
this._action = action; |
|||
|
|||
if (this._action !== 'copy' && this._action !== 'cut') { |
|||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Gets the `action` property. |
|||
* @return {String} |
|||
*/ |
|||
, |
|||
get: function get() { |
|||
return this._action; |
|||
} |
|||
|
|||
/** |
|||
* Sets the `target` property using an element |
|||
* that will be have its content copied. |
|||
* @param {Element} target |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'target', |
|||
set: function set(target) { |
|||
if (target !== undefined) { |
|||
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { |
|||
if (this.action === 'copy' && target.hasAttribute('disabled')) { |
|||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); |
|||
} |
|||
|
|||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { |
|||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); |
|||
} |
|||
|
|||
this._target = target; |
|||
} else { |
|||
throw new Error('Invalid "target" value, use a valid Element'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Gets the `target` property. |
|||
* @return {String|HTMLElement} |
|||
*/ |
|||
, |
|||
get: function get() { |
|||
return this._target; |
|||
} |
|||
}]); |
|||
|
|||
return ClipboardAction; |
|||
}(); |
|||
|
|||
module.exports = ClipboardAction; |
|||
|
|||
/***/ }), |
|||
/* 2 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function select(element) { |
|||
var selectedText; |
|||
|
|||
if (element.nodeName === 'SELECT') { |
|||
element.focus(); |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { |
|||
var isReadOnly = element.hasAttribute('readonly'); |
|||
|
|||
if (!isReadOnly) { |
|||
element.setAttribute('readonly', ''); |
|||
} |
|||
|
|||
element.select(); |
|||
element.setSelectionRange(0, element.value.length); |
|||
|
|||
if (!isReadOnly) { |
|||
element.removeAttribute('readonly'); |
|||
} |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else { |
|||
if (element.hasAttribute('contenteditable')) { |
|||
element.focus(); |
|||
} |
|||
|
|||
var selection = window.getSelection(); |
|||
var range = document.createRange(); |
|||
|
|||
range.selectNodeContents(element); |
|||
selection.removeAllRanges(); |
|||
selection.addRange(range); |
|||
|
|||
selectedText = selection.toString(); |
|||
} |
|||
|
|||
return selectedText; |
|||
} |
|||
|
|||
module.exports = select; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 3 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function E () { |
|||
// Keep this empty so it's easier to inherit from
|
|||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
|||
} |
|||
|
|||
E.prototype = { |
|||
on: function (name, callback, ctx) { |
|||
var e = this.e || (this.e = {}); |
|||
|
|||
(e[name] || (e[name] = [])).push({ |
|||
fn: callback, |
|||
ctx: ctx |
|||
}); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
once: function (name, callback, ctx) { |
|||
var self = this; |
|||
function listener () { |
|||
self.off(name, listener); |
|||
callback.apply(ctx, arguments); |
|||
}; |
|||
|
|||
listener._ = callback |
|||
return this.on(name, listener, ctx); |
|||
}, |
|||
|
|||
emit: function (name) { |
|||
var data = [].slice.call(arguments, 1); |
|||
var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); |
|||
var i = 0; |
|||
var len = evtArr.length; |
|||
|
|||
for (i; i < len; i++) { |
|||
evtArr[i].fn.apply(evtArr[i].ctx, data); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
off: function (name, callback) { |
|||
var e = this.e || (this.e = {}); |
|||
var evts = e[name]; |
|||
var liveEvents = []; |
|||
|
|||
if (evts && callback) { |
|||
for (var i = 0, len = evts.length; i < len; i++) { |
|||
if (evts[i].fn !== callback && evts[i].fn._ !== callback) |
|||
liveEvents.push(evts[i]); |
|||
} |
|||
} |
|||
|
|||
// Remove event from queue to prevent memory leak
|
|||
// Suggested by https://github.com/lazd
|
|||
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
|
|||
|
|||
(liveEvents.length) |
|||
? e[name] = liveEvents |
|||
: delete e[name]; |
|||
|
|||
return this; |
|||
} |
|||
}; |
|||
|
|||
module.exports = E; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 4 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var is = __webpack_require__(5); |
|||
var delegate = __webpack_require__(6); |
|||
|
|||
/** |
|||
* Validates all params and calls the right |
|||
* listener function based on its target type. |
|||
* |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} target |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listen(target, type, callback) { |
|||
if (!target && !type && !callback) { |
|||
throw new Error('Missing required arguments'); |
|||
} |
|||
|
|||
if (!is.string(type)) { |
|||
throw new TypeError('Second argument must be a String'); |
|||
} |
|||
|
|||
if (!is.fn(callback)) { |
|||
throw new TypeError('Third argument must be a Function'); |
|||
} |
|||
|
|||
if (is.node(target)) { |
|||
return listenNode(target, type, callback); |
|||
} |
|||
else if (is.nodeList(target)) { |
|||
return listenNodeList(target, type, callback); |
|||
} |
|||
else if (is.string(target)) { |
|||
return listenSelector(target, type, callback); |
|||
} |
|||
else { |
|||
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Adds an event listener to a HTML element |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {HTMLElement} node |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNode(node, type, callback) { |
|||
node.addEventListener(type, callback); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
node.removeEventListener(type, callback); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a list of HTML elements |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {NodeList|HTMLCollection} nodeList |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNodeList(nodeList, type, callback) { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.addEventListener(type, callback); |
|||
}); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.removeEventListener(type, callback); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a selector |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenSelector(selector, type, callback) { |
|||
return delegate(document.body, selector, type, callback); |
|||
} |
|||
|
|||
module.exports = listen; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 5 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
/** |
|||
* Check if argument is a HTML element. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.node = function(value) { |
|||
return value !== undefined |
|||
&& value instanceof HTMLElement |
|||
&& value.nodeType === 1; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a list of HTML elements. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.nodeList = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return value !== undefined |
|||
&& (type === '[object NodeList]' || type === '[object HTMLCollection]') |
|||
&& ('length' in value) |
|||
&& (value.length === 0 || exports.node(value[0])); |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a string. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.string = function(value) { |
|||
return typeof value === 'string' |
|||
|| value instanceof String; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a function. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.fn = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return type === '[object Function]'; |
|||
}; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 6 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var closest = __webpack_require__(7); |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function _delegate(element, selector, type, callback, useCapture) { |
|||
var listenerFn = listener.apply(this, arguments); |
|||
|
|||
element.addEventListener(type, listenerFn, useCapture); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
element.removeEventListener(type, listenerFn, useCapture); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element|String|Array} [elements] |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function delegate(elements, selector, type, callback, useCapture) { |
|||
// Handle the regular Element usage
|
|||
if (typeof elements.addEventListener === 'function') { |
|||
return _delegate.apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Element-less usage, it defaults to global delegation
|
|||
if (typeof type === 'function') { |
|||
// Use `document` as the first parameter, then apply arguments
|
|||
// This is a short way to .unshift `arguments` without running into deoptimizations
|
|||
return _delegate.bind(null, document).apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Selector-based usage
|
|||
if (typeof elements === 'string') { |
|||
elements = document.querySelectorAll(elements); |
|||
} |
|||
|
|||
// Handle Array-like based usage
|
|||
return Array.prototype.map.call(elements, function (element) { |
|||
return _delegate(element, selector, type, callback, useCapture); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Finds closest match and invokes callback. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Function} |
|||
*/ |
|||
function listener(element, selector, type, callback) { |
|||
return function(e) { |
|||
e.delegateTarget = closest(e.target, selector); |
|||
|
|||
if (e.delegateTarget) { |
|||
callback.call(element, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = delegate; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 7 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
var DOCUMENT_NODE_TYPE = 9; |
|||
|
|||
/** |
|||
* A polyfill for Element.matches() |
|||
*/ |
|||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { |
|||
var proto = Element.prototype; |
|||
|
|||
proto.matches = proto.matchesSelector || |
|||
proto.mozMatchesSelector || |
|||
proto.msMatchesSelector || |
|||
proto.oMatchesSelector || |
|||
proto.webkitMatchesSelector; |
|||
} |
|||
|
|||
/** |
|||
* Finds the closest parent that matches a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @return {Function} |
|||
*/ |
|||
function closest (element, selector) { |
|||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { |
|||
if (typeof element.matches === 'function' && |
|||
element.matches(selector)) { |
|||
return element; |
|||
} |
|||
element = element.parentNode; |
|||
} |
|||
} |
|||
|
|||
module.exports = closest; |
|||
|
|||
|
|||
/***/ }) |
|||
/******/ ]); |
|||
}); |
|||
@ -0,0 +1,159 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
(function ($) { |
|||
'use strict'; |
|||
|
|||
window.Toc = { |
|||
helpers: { |
|||
// return all matching elements in the set, or their descendants
|
|||
findOrFilter: function ($el, selector) { |
|||
// http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
|
|||
// http://stackoverflow.com/a/12731439/358804
|
|||
var $descendants = $el.find(selector); |
|||
return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); |
|||
}, |
|||
|
|||
generateUniqueIdBase: function (el) { |
|||
var text = $(el).text(); |
|||
var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); |
|||
return anchor || el.tagName.toLowerCase(); |
|||
}, |
|||
|
|||
generateUniqueId: function (el) { |
|||
var anchorBase = this.generateUniqueIdBase(el); |
|||
for (var i = 0; ; i++) { |
|||
var anchor = anchorBase; |
|||
if (i > 0) { |
|||
// add suffix
|
|||
anchor += '-' + i; |
|||
} |
|||
// check if ID already exists
|
|||
if (!document.getElementById(anchor)) { |
|||
return anchor; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
generateAnchor: function (el) { |
|||
if (el.id) { |
|||
return el.id; |
|||
} else { |
|||
var anchor = this.generateUniqueId(el); |
|||
el.id = anchor; |
|||
return anchor; |
|||
} |
|||
}, |
|||
|
|||
createNavList: function () { |
|||
return $('<ul class="nav navbar-nav"></ul>'); |
|||
}, |
|||
|
|||
createChildNavList: function ($parent) { |
|||
var $childList = this.createNavList(); |
|||
$parent.append($childList); |
|||
return $childList; |
|||
}, |
|||
|
|||
generateNavEl: function (anchor, text) { |
|||
var $a = $('<a class="nav-link"></a>'); |
|||
$a.attr('href', '#' + anchor); |
|||
$a.text(text); |
|||
var $li = $('<li></li>'); |
|||
$li.append($a); |
|||
return $li; |
|||
}, |
|||
|
|||
generateNavItem: function (headingEl) { |
|||
var anchor = this.generateAnchor(headingEl); |
|||
var $heading = $(headingEl); |
|||
var text = $heading.data('toc-text') || $heading.text(); |
|||
return this.generateNavEl(anchor, text); |
|||
}, |
|||
|
|||
// Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
|
|||
getTopLevel: function ($scope) { |
|||
for (var i = 1; i <= 6; i++) { |
|||
var $headings = this.findOrFilter($scope, 'h' + i); |
|||
if ($headings.length > 1) { |
|||
return i; |
|||
} |
|||
} |
|||
|
|||
return 1; |
|||
}, |
|||
|
|||
// returns the elements for the top level, and the next below it
|
|||
getHeadings: function ($scope, topLevel) { |
|||
var topSelector = 'h' + topLevel; |
|||
|
|||
var secondaryLevel = topLevel + 1; |
|||
var secondarySelector = 'h' + secondaryLevel; |
|||
|
|||
return this.findOrFilter($scope, topSelector + ',' + secondarySelector); |
|||
}, |
|||
|
|||
getNavLevel: function (el) { |
|||
return parseInt(el.tagName.charAt(1), 10); |
|||
}, |
|||
|
|||
populateNav: function ($topContext, topLevel, $headings) { |
|||
var $context = $topContext; |
|||
var $prevNav; |
|||
|
|||
var helpers = this; |
|||
$headings.each(function (i, el) { |
|||
var $newNav = helpers.generateNavItem(el); |
|||
var navLevel = helpers.getNavLevel(el); |
|||
|
|||
// determine the proper $context
|
|||
if (navLevel === topLevel) { |
|||
// use top level
|
|||
$context = $topContext; |
|||
} else if ($prevNav && $context === $topContext) { |
|||
// create a new level of the tree and switch to it
|
|||
$context = helpers.createChildNavList($prevNav); |
|||
} // else use the current $context
|
|||
|
|||
$context.append($newNav); |
|||
|
|||
$prevNav = $newNav; |
|||
}); |
|||
}, |
|||
|
|||
parseOps: function (arg) { |
|||
var opts; |
|||
if (arg.jquery) { |
|||
opts = { |
|||
$nav: arg |
|||
}; |
|||
} else { |
|||
opts = arg; |
|||
} |
|||
opts.$scope = opts.$scope || $(document.body); |
|||
return opts; |
|||
} |
|||
}, |
|||
|
|||
// accepts a jQuery object, or an options object
|
|||
init: function (opts) { |
|||
opts = this.helpers.parseOps(opts); |
|||
|
|||
// ensure that the data attribute is in place for styling
|
|||
opts.$nav.attr('data-toggle', 'toc'); |
|||
|
|||
var $topContext = this.helpers.createChildNavList(opts.$nav); |
|||
var topLevel = this.helpers.getTopLevel(opts.$scope); |
|||
var $headings = this.helpers.getHeadings(opts.$scope, topLevel); |
|||
this.helpers.populateNav($topContext, topLevel, $headings); |
|||
} |
|||
}; |
|||
|
|||
$(function () { |
|||
$('nav[data-toggle="toc"]').each(function (i, el) { |
|||
var $nav = $(el); |
|||
Toc.init($nav); |
|||
}); |
|||
}); |
|||
})(jQuery); |
|||
@ -0,0 +1,110 @@ |
|||
@color_1: #767676; |
|||
@color_2: #563d7c; |
|||
@background_color_1: transparent; |
|||
|
|||
/*! |
|||
* Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/) |
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ |
|||
/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ |
|||
/* All levels of nav */ |
|||
/* Nav: second level (shown on .active) */ |
|||
nav[data-toggle='toc'] { |
|||
.nav { |
|||
> li { |
|||
> a { |
|||
display: block; |
|||
padding: 4px 20px; |
|||
font-size: 13px; |
|||
font-weight: 500; |
|||
color: @color_1; |
|||
|
|||
&:hover { |
|||
padding-left: 19px; |
|||
color: @color_2; |
|||
text-decoration: none; |
|||
background-color: @background_color_1; |
|||
border-left: 1px solid #563d7c; |
|||
} |
|||
|
|||
&:focus { |
|||
padding-left: 19px; |
|||
color: @color_2; |
|||
text-decoration: none; |
|||
background-color: @background_color_1; |
|||
border-left: 1px solid #563d7c; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.nav { |
|||
> li { |
|||
> a { |
|||
padding-top: 1px; |
|||
padding-bottom: 1px; |
|||
padding-left: 30px; |
|||
font-size: 12px; |
|||
font-weight: normal; |
|||
|
|||
&:hover { |
|||
padding-left: 29px; |
|||
} |
|||
|
|||
&:focus { |
|||
padding-left: 29px; |
|||
} |
|||
} |
|||
|
|||
> .active { |
|||
padding-left: 28px; |
|||
font-weight: 500; |
|||
|
|||
&:hover { |
|||
padding-left: 28px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
&:focus { |
|||
padding-left: 28px; |
|||
font-weight: 500; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.nav-link.active { |
|||
padding-left: 18px; |
|||
font-weight: bold; |
|||
color: @color_2; |
|||
background-color: @background_color_1; |
|||
border-left: 2px solid #563d7c; |
|||
|
|||
&:hover { |
|||
padding-left: 18px; |
|||
font-weight: bold; |
|||
color: @color_2; |
|||
background-color: @background_color_1; |
|||
border-left: 2px solid #563d7c; |
|||
} |
|||
|
|||
&:focus { |
|||
padding-left: 18px; |
|||
font-weight: bold; |
|||
color: @color_2; |
|||
background-color: @background_color_1; |
|||
border-left: 2px solid #563d7c; |
|||
} |
|||
|
|||
& + ul { |
|||
display: block; |
|||
} |
|||
} |
|||
|
|||
.nav-link { |
|||
& + ul { |
|||
display: none; |
|||
padding-bottom: 10px; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
nav[data-toggle=toc] .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}nav[data-toggle=toc] .nav>li>a:focus,nav[data-toggle=toc] .nav>li>a:hover{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}nav[data-toggle=toc] .nav-link.active,nav[data-toggle=toc] .nav-link.active:focus,nav[data-toggle=toc] .nav-link.active:hover{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}nav[data-toggle=toc] .nav-link+ul{display:none;padding-bottom:10px}nav[data-toggle=toc] .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}nav[data-toggle=toc] .nav .nav>li>a:focus,nav[data-toggle=toc] .nav .nav>li>a:hover{padding-left:29px}nav[data-toggle=toc] .nav .nav>li>.active,nav[data-toggle=toc] .nav .nav>li>.active:focus,nav[data-toggle=toc] .nav .nav>li>.active:hover{padding-left:28px;font-weight:500}nav[data-toggle=toc] .nav-link.active+ul{display:block} |
|||
@ -1,29 +0,0 @@ |
|||
{ |
|||
"name": "anchor-js", |
|||
"version": "4.1.0", |
|||
"authors": [ |
|||
"Bryan Braun" |
|||
], |
|||
"description": "A Javascript utility for adding deep anchor links to online docs.", |
|||
"main": "anchor.js", |
|||
"license": "MIT", |
|||
"homepage": "https://github.com/bryanbraun/anchorjs", |
|||
"ignore": [ |
|||
"**/.*", |
|||
"node_modules", |
|||
"bower_components", |
|||
"test", |
|||
"tests", |
|||
"package.json" |
|||
], |
|||
"_release": "4.1.0", |
|||
"_resolution": { |
|||
"type": "version", |
|||
"tag": "4.1.0", |
|||
"commit": "848ef8ca7e8bbd5edb032b6c3623f05aefb5ef0b" |
|||
}, |
|||
"_source": "https://github.com/bryanbraun/anchorjs.git", |
|||
"_target": "^4.1.0", |
|||
"_originalSource": "anchor-js", |
|||
"_direct": true |
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
# AnchorJS [](https://travis-ci.org/bryanbraun/anchorjs) |
|||
|
|||
A JavaScript utility for adding deep anchor links ([like these](http://ux.stackexchange.com/q/36304/33248)) to existing page content. AnchorJS is lightweight, accessible, and has no dependencies. |
|||
|
|||
**[See Live Examples in the Documentation](http://bryanbraun.github.io/anchorjs#examples).** |
|||
|
|||
 |
|||
|
|||
## Installation |
|||
|
|||
Download AnchorJS using npm, |
|||
|
|||
```bash |
|||
npm install anchor-js |
|||
``` |
|||
|
|||
or bower: |
|||
|
|||
```bash |
|||
bower install anchor-js --save-dev |
|||
``` |
|||
|
|||
(or just [download it from github](https://github.com/bryanbraun/anchorjs/releases)). |
|||
|
|||
Then include the anchor.js file (or anchor.min.js) in your webpage. |
|||
|
|||
```html |
|||
<script src="anchor.js"></script> |
|||
``` |
|||
|
|||
You could also include it via a CDN like [CDNJS](https://cdnjs.com/libraries/anchor-js) or [jsDelivr](http://www.jsdelivr.com/projects/anchorjs). |
|||
|
|||
## Usage |
|||
See **[the Documentation](http://bryanbraun.github.io/anchorjs#basic-usage)** for detailed instructions. |
|||
|
|||
## Compatibility |
|||
Currently Supports: IE9+ and modern browsers |
|||
|
|||
## Contributing [](https://david-dm.org/bryanbraun/anchorjs#info=devDependencies) |
|||
To contribute: |
|||
|
|||
1. Fork/Clone the repo. |
|||
2. Make your changes. |
|||
3. Write tests as needed. |
|||
4. Run tests locally to confirm everything is working: |
|||
- Install phantomjs: `brew install phantomjs` |
|||
- Install test modules: Run `npm install` |
|||
- Run all tests: `npm test` |
|||
5. Minify the code: `npm run release` |
|||
6. Submit a Pull Request. |
|||
|
|||
## License |
|||
Licensed with the [MIT License](http://opensource.org/licenses/MIT). |
|||
@ -1,17 +0,0 @@ |
|||
const fs = require('fs'); |
|||
const pkg = require('./package.json'); |
|||
const filename = 'anchor.min.js'; |
|||
const script = fs.readFileSync(filename); |
|||
const padStart = str => ('0' + str).slice(-2) |
|||
const dateObj = new Date; |
|||
const date = `${dateObj.getFullYear()}-${padStart(dateObj.getMonth() + 1)}-${padStart(dateObj.getDate())}`; |
|||
const banner = `/**
|
|||
* AnchorJS - v${pkg.version} - ${date} |
|||
* ${pkg.homepage} |
|||
* Copyright (c) ${dateObj.getFullYear()} Bryan Braun; Licensed ${pkg.license} |
|||
*/ |
|||
`;
|
|||
|
|||
if (script.slice(0, 3) != '/**') { |
|||
fs.writeFileSync(filename, banner + script); |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
{ |
|||
"name": "anchor-js", |
|||
"version": "4.1.0", |
|||
"authors": [ |
|||
"Bryan Braun" |
|||
], |
|||
"description": "A Javascript utility for adding deep anchor links to online docs.", |
|||
"main": "anchor.js", |
|||
"license": "MIT", |
|||
"homepage": "https://github.com/bryanbraun/anchorjs", |
|||
"ignore": [ |
|||
"**/.*", |
|||
"node_modules", |
|||
"bower_components", |
|||
"test", |
|||
"tests", |
|||
"package.json" |
|||
] |
|||
} |
|||
@ -1,335 +0,0 @@ |
|||
/* eslint-env amd, node */ |
|||
|
|||
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
|
|||
(function (root, factory) { |
|||
'use strict'; |
|||
|
|||
if (typeof define === 'function' && define.amd) { |
|||
// AMD. Register as an anonymous module.
|
|||
define([], factory); |
|||
} else if (typeof module === 'object' && module.exports) { |
|||
// Node. Does not work with strict CommonJS, but
|
|||
// only CommonJS-like environments that support module.exports,
|
|||
// like Node.
|
|||
module.exports = factory(); |
|||
} else { |
|||
// Browser globals (root is window)
|
|||
root.AnchorJS = factory(); |
|||
root.anchors = new root.AnchorJS(); |
|||
} |
|||
}(this, function () { |
|||
'use strict'; |
|||
|
|||
function AnchorJS(options) { |
|||
this.options = options || {}; |
|||
this.elements = []; |
|||
|
|||
/** |
|||
* Assigns options to the internal options object, and provides defaults. |
|||
* @param {Object} opts - Options object |
|||
*/ |
|||
function _applyRemainingDefaultOptions(opts) { |
|||
opts.icon = opts.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'.
|
|||
opts.visible = opts.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' & 'touch'
|
|||
opts.placement = opts.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left'
|
|||
opts.ariaLabel = opts.hasOwnProperty('ariaLabel') ? opts.ariaLabel : 'Anchor'; // Accepts any text.
|
|||
opts.class = opts.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
|
|||
// Using Math.floor here will ensure the value is Number-cast and an integer.
|
|||
opts.truncate = opts.hasOwnProperty('truncate') ? Math.floor(opts.truncate) : 64; // Accepts any value that can be typecast to a number.
|
|||
} |
|||
|
|||
_applyRemainingDefaultOptions(this.options); |
|||
|
|||
/** |
|||
* Checks to see if this device supports touch. Uses criteria pulled from Modernizr: |
|||
* https://github.com/Modernizr/Modernizr/blob/da22eb27631fc4957f67607fe6042e85c0a84656/feature-detects/touchevents.js#L40
|
|||
* @return {Boolean} - true if the current device supports touch. |
|||
*/ |
|||
this.isTouchDevice = function() { |
|||
return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch); |
|||
}; |
|||
|
|||
/** |
|||
* Add anchor links to page elements. |
|||
* @param {String|Array|Nodelist} selector - A CSS selector for targeting the elements you wish to add anchor links |
|||
* to. Also accepts an array or nodeList containing the relavant elements. |
|||
* @return {this} - The AnchorJS object |
|||
*/ |
|||
this.add = function(selector) { |
|||
var elements, |
|||
elsWithIds, |
|||
idList, |
|||
elementID, |
|||
i, |
|||
index, |
|||
count, |
|||
tidyText, |
|||
newTidyText, |
|||
readableID, |
|||
anchor, |
|||
visibleOptionToUse, |
|||
indexesToDrop = []; |
|||
|
|||
// We reapply options here because somebody may have overwritten the default options object when setting options.
|
|||
// For example, this overwrites all options but visible:
|
|||
//
|
|||
// anchors.options = { visible: 'always'; }
|
|||
_applyRemainingDefaultOptions(this.options); |
|||
|
|||
visibleOptionToUse = this.options.visible; |
|||
if (visibleOptionToUse === 'touch') { |
|||
visibleOptionToUse = this.isTouchDevice() ? 'always' : 'hover'; |
|||
} |
|||
|
|||
// Provide a sensible default selector, if none is given.
|
|||
if (!selector) { |
|||
selector = 'h2, h3, h4, h5, h6'; |
|||
} |
|||
|
|||
elements = _getElements(selector); |
|||
|
|||
if (elements.length === 0) { |
|||
return this; |
|||
} |
|||
|
|||
_addBaselineStyles(); |
|||
|
|||
// We produce a list of existing IDs so we don't generate a duplicate.
|
|||
elsWithIds = document.querySelectorAll('[id]'); |
|||
idList = [].map.call(elsWithIds, function assign(el) { |
|||
return el.id; |
|||
}); |
|||
|
|||
for (i = 0; i < elements.length; i++) { |
|||
if (this.hasAnchorJSLink(elements[i])) { |
|||
indexesToDrop.push(i); |
|||
continue; |
|||
} |
|||
|
|||
if (elements[i].hasAttribute('id')) { |
|||
elementID = elements[i].getAttribute('id'); |
|||
} else if (elements[i].hasAttribute('data-anchor-id')) { |
|||
elementID = elements[i].getAttribute('data-anchor-id'); |
|||
} else { |
|||
tidyText = this.urlify(elements[i].textContent); |
|||
|
|||
// Compare our generated ID to existing IDs (and increment it if needed)
|
|||
// before we add it to the page.
|
|||
newTidyText = tidyText; |
|||
count = 0; |
|||
do { |
|||
if (index !== undefined) { |
|||
newTidyText = tidyText + '-' + count; |
|||
} |
|||
|
|||
index = idList.indexOf(newTidyText); |
|||
count += 1; |
|||
} while (index !== -1); |
|||
index = undefined; |
|||
idList.push(newTidyText); |
|||
|
|||
elements[i].setAttribute('id', newTidyText); |
|||
elementID = newTidyText; |
|||
} |
|||
|
|||
readableID = elementID.replace(/-/g, ' '); |
|||
|
|||
// The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
|
|||
// '<a class="anchorjs-link ' + this.options.class + '" href="#' + elementID + '" aria-label="Anchor" data-anchorjs-icon="' + this.options.icon + '"></a>';
|
|||
anchor = document.createElement('a'); |
|||
anchor.className = 'anchorjs-link ' + this.options.class; |
|||
anchor.href = '#' + elementID; |
|||
anchor.setAttribute('aria-label', this.options.ariaLabel); |
|||
anchor.setAttribute('data-anchorjs-icon', this.options.icon); |
|||
|
|||
if (visibleOptionToUse === 'always') { |
|||
anchor.style.opacity = '1'; |
|||
} |
|||
|
|||
if (this.options.icon === '\ue9cb') { |
|||
anchor.style.font = '1em/1 anchorjs-icons'; |
|||
|
|||
// We set lineHeight = 1 here because the `anchorjs-icons` font family could otherwise affect the
|
|||
// height of the heading. This isn't the case for icons with `placement: left`, so we restore
|
|||
// line-height: inherit in that case, ensuring they remain positioned correctly. For more info,
|
|||
// see https://github.com/bryanbraun/anchorjs/issues/39.
|
|||
if (this.options.placement === 'left') { |
|||
anchor.style.lineHeight = 'inherit'; |
|||
} |
|||
} |
|||
|
|||
if (this.options.placement === 'left') { |
|||
anchor.style.position = 'absolute'; |
|||
anchor.style.marginLeft = '-1em'; |
|||
anchor.style.paddingRight = '0.5em'; |
|||
elements[i].insertBefore(anchor, elements[i].firstChild); |
|||
} else { // if the option provided is `right` (or anything else).
|
|||
anchor.style.paddingLeft = '0.375em'; |
|||
elements[i].appendChild(anchor); |
|||
} |
|||
} |
|||
|
|||
for (i = 0; i < indexesToDrop.length; i++) { |
|||
elements.splice(indexesToDrop[i] - i, 1); |
|||
} |
|||
this.elements = this.elements.concat(elements); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
/** |
|||
* Removes all anchorjs-links from elements targed by the selector. |
|||
* @param {String|Array|Nodelist} selector - A CSS selector string targeting elements with anchor links, |
|||
* OR a nodeList / array containing the DOM elements. |
|||
* @return {this} - The AnchorJS object |
|||
*/ |
|||
this.remove = function(selector) { |
|||
var index, |
|||
domAnchor, |
|||
elements = _getElements(selector); |
|||
|
|||
for (var i = 0; i < elements.length; i++) { |
|||
domAnchor = elements[i].querySelector('.anchorjs-link'); |
|||
if (domAnchor) { |
|||
// Drop the element from our main list, if it's in there.
|
|||
index = this.elements.indexOf(elements[i]); |
|||
if (index !== -1) { |
|||
this.elements.splice(index, 1); |
|||
} |
|||
// Remove the anchor from the DOM.
|
|||
elements[i].removeChild(domAnchor); |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
/** |
|||
* Removes all anchorjs links. Mostly used for tests. |
|||
*/ |
|||
this.removeAll = function() { |
|||
this.remove(this.elements); |
|||
}; |
|||
|
|||
/** |
|||
* Urlify - Refine text so it makes a good ID. |
|||
* |
|||
* To do this, we remove apostrophes, replace nonsafe characters with hyphens, |
|||
* remove extra hyphens, truncate, trim hyphens, and make lowercase. |
|||
* |
|||
* @param {String} text - Any text. Usually pulled from the webpage element we are linking to. |
|||
* @return {String} - hyphen-delimited text for use in IDs and URLs. |
|||
*/ |
|||
this.urlify = function(text) { |
|||
// Regex for finding the nonsafe URL characters (many need escaping): & +$,:;=?@"#{}|^~[`%!'<>]./()*\
|
|||
var nonsafeChars = /[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\]/g, |
|||
urlText; |
|||
|
|||
// The reason we include this _applyRemainingDefaultOptions is so urlify can be called independently,
|
|||
// even after setting options. This can be useful for tests or other applications.
|
|||
if (!this.options.truncate) { |
|||
_applyRemainingDefaultOptions(this.options); |
|||
} |
|||
|
|||
// Note: we trim hyphens after truncating because truncating can cause dangling hyphens.
|
|||
// Example string: // " ⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
|||
urlText = text.trim() // "⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
|||
.replace(/\'/gi, '') // "⚡⚡ Dont forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
|||
.replace(nonsafeChars, '-') // "⚡⚡-Dont-forget--URL-fragments-should-be-i18n-friendly--hyphenated--short--and-clean-"
|
|||
.replace(/-{2,}/g, '-') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-short-and-clean-"
|
|||
.substring(0, this.options.truncate) // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-"
|
|||
.replace(/^-+|-+$/gm, '') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated"
|
|||
.toLowerCase(); // "⚡⚡-dont-forget-url-fragments-should-be-i18n-friendly-hyphenated"
|
|||
|
|||
return urlText; |
|||
}; |
|||
|
|||
/** |
|||
* Determines if this element already has an AnchorJS link on it. |
|||
* Uses this technique: http://stackoverflow.com/a/5898748/1154642
|
|||
* @param {HTMLElemnt} el - a DOM node |
|||
* @return {Boolean} true/false |
|||
*/ |
|||
this.hasAnchorJSLink = function(el) { |
|||
var hasLeftAnchor = el.firstChild && ((' ' + el.firstChild.className + ' ').indexOf(' anchorjs-link ') > -1), |
|||
hasRightAnchor = el.lastChild && ((' ' + el.lastChild.className + ' ').indexOf(' anchorjs-link ') > -1); |
|||
|
|||
return hasLeftAnchor || hasRightAnchor || false; |
|||
}; |
|||
|
|||
/** |
|||
* Turns a selector, nodeList, or array of elements into an array of elements (so we can use array methods). |
|||
* It also throws errors on any other inputs. Used to handle inputs to .add and .remove. |
|||
* @param {String|Array|Nodelist} input - A CSS selector string targeting elements with anchor links, |
|||
* OR a nodeList / array containing the DOM elements. |
|||
* @return {Array} - An array containing the elements we want. |
|||
*/ |
|||
function _getElements(input) { |
|||
var elements; |
|||
if (typeof input === 'string' || input instanceof String) { |
|||
// See https://davidwalsh.name/nodelist-array for the technique transforming nodeList -> Array.
|
|||
elements = [].slice.call(document.querySelectorAll(input)); |
|||
// I checked the 'input instanceof NodeList' test in IE9 and modern browsers and it worked for me.
|
|||
} else if (Array.isArray(input) || input instanceof NodeList) { |
|||
elements = [].slice.call(input); |
|||
} else { |
|||
throw new Error('The selector provided to AnchorJS was invalid.'); |
|||
} |
|||
return elements; |
|||
} |
|||
|
|||
/** |
|||
* _addBaselineStyles |
|||
* Adds baseline styles to the page, used by all AnchorJS links irregardless of configuration. |
|||
*/ |
|||
function _addBaselineStyles() { |
|||
// We don't want to add global baseline styles if they've been added before.
|
|||
if (document.head.querySelector('style.anchorjs') !== null) { |
|||
return; |
|||
} |
|||
|
|||
var style = document.createElement('style'), |
|||
linkRule = |
|||
' .anchorjs-link {' + |
|||
' opacity: 0;' + |
|||
' text-decoration: none;' + |
|||
' -webkit-font-smoothing: antialiased;' + |
|||
' -moz-osx-font-smoothing: grayscale;' + |
|||
' }', |
|||
hoverRule = |
|||
' *:hover > .anchorjs-link,' + |
|||
' .anchorjs-link:focus {' + |
|||
' opacity: 1;' + |
|||
' }', |
|||
anchorjsLinkFontFace = |
|||
' @font-face {' + |
|||
' font-family: "anchorjs-icons";' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
|
|||
' src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype");' + |
|||
' }', |
|||
pseudoElContent = |
|||
' [data-anchorjs-icon]::after {' + |
|||
' content: attr(data-anchorjs-icon);' + |
|||
' }', |
|||
firstStyleEl; |
|||
|
|||
style.className = 'anchorjs'; |
|||
style.appendChild(document.createTextNode('')); // Necessary for Webkit.
|
|||
|
|||
// We place it in the head with the other style tags, if possible, so as to
|
|||
// not look out of place. We insert before the others so these styles can be
|
|||
// overridden if necessary.
|
|||
firstStyleEl = document.head.querySelector('[rel="stylesheet"], style'); |
|||
if (firstStyleEl === undefined) { |
|||
document.head.appendChild(style); |
|||
} else { |
|||
document.head.insertBefore(style, firstStyleEl); |
|||
} |
|||
|
|||
style.sheet.insertRule(linkRule, style.sheet.cssRules.length); |
|||
style.sheet.insertRule(hoverRule, style.sheet.cssRules.length); |
|||
style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length); |
|||
style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length); |
|||
} |
|||
} |
|||
|
|||
return AnchorJS; |
|||
})); |
|||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
@ -1,24 +0,0 @@ |
|||
@font-face { |
|||
font-family: 'anchorjs-extras'; |
|||
src:url('anchorjs-extras.eot?-qcq09q'); |
|||
src:url('anchorjs-extras.eot?#iefix-qcq09q') format('embedded-opentype'), |
|||
url('anchorjs-extras.woff?-qcq09q') format('woff'), |
|||
url('anchorjs-extras.ttf?-qcq09q') format('truetype'), |
|||
url('anchorjs-extras.svg?-qcq09q#anchorjs-extras') format('svg'); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
|
|||
[class^="ajs-"], [class*=" ajs-"] { |
|||
font-family: 'anchorjs-extras'; |
|||
speak: none; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-variant: normal; |
|||
text-transform: none; |
|||
line-height: 1; |
|||
|
|||
/* Better Font Rendering =========== */ |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
@ -1,3 +0,0 @@ |
|||
/*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */ |
|||
|
|||
(function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this); |
|||
@ -1,5 +0,0 @@ |
|||
|
|||
.icon-grunticon-link { |
|||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABuklEQVQ4T52U4VnCMBiE71hAnECcgLCBblBYAJxANgAmEDfABWg3kA2IE6ATWBbo+XwplLaWguZnm765fncX4h9LkesC6DHxvv45/8JT5CIQLyB74TspBbFChgUTn9qjq4EauhXIMYA9pBWIFKId0IfkITwa9CpgARM+ID0c1QSRIzcHOIP0ythPLwLbYMdxaTjwgO4Y+9uLwKAicjaztKysPPtCZab7VqAi9wBSkPZNjp4UuiXIZ2RqVqiRm0KYgbR45Csf/FMdHCJE7EDuud72fiksufkFaIkMnyBM6QSSDm6G/B1g7yAdMg2Z+KQCbHUzcg4dbiwy5mYFJr0x9pNKDptgGrolgHFZ1S9lJVgBDA3oMEYtZzqpEogEQgLCQZiEttRgJ+Bo8Amgi0zWz1ChwguDktaMfunxHtCca29/UFkMs+jw+5j0c90Oau1Q62viN+f2GdCGvQW04NrPmzYebpcuE29/0rqCyxoNUkg7xn5Q333OzbMKA9DctKTnc1mU5mehzXPWYEATNFcY0s5NcRWZozav3M3utbBqDvMKzUMjgJvD6V/INLUGXJrd8X3j5XDpdmmD/wAyTxBSftthKwAAAABJRU5ErkJggg=='); |
|||
background-repeat: no-repeat; |
|||
} |
|||
@ -1,5 +0,0 @@ |
|||
|
|||
.icon-grunticon-link { |
|||
background-image: url('data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%3C%21--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%20768%20768%22%3E%0A%20%20%3Cg%20fill%3D%22%23FF5231%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M544%2032q37.75%200%2072.875%2014.25t62.875%2042%2042%2062.875%2014.25%2072.875q0%2037.5-14.375%2072.875t-41.875%2062.875l-96%2096q-2.75%202.75-8.25%207.75-26.75%2023.75-59.75%2036.125t-67.75%2012.375q-43.75%200-82.75-18.75-29.25-13.75-53-37.5t-37.5-53q18.75-18.75%2045.25-18.75%209.25%200%2018.75%202.75%2016.25%2026.25%2042.5%2042.5%2030.75%2018.75%2066.75%2018.75%2025%200%2048.5-9.5t42-28l96-96q18.5-18.5%2028-42t9.5-48.5-9.5-48.5-28-42-42-28-48.5-9.5-48.5%209.5-42%2028l-67.25%2067.25q-32-8.75-66.25-8.75-5.5%200-15.5%200.5%205-5.5%207.75-8.25l96-96q27.5-27.5%2062.875-41.875t72.875-14.375zM320%20256q43.75%200%2082.75%2018.75%2029.25%2013.75%2053%2037.5t37.5%2053q-18.75%2018.75-45.25%2018.75-9.25%200-18.75-2.75-16.25-26.25-42.5-42.5-30.75-18.75-66.75-18.75-25%200-48.5%209.5t-42%2028l-96%2096q-18.5%2018.5-28%2042t-9.5%2048.5%209.5%2048.5%2028%2042%2042%2028%2048.5%209.5%2048.5-9.5%2042-28l67.25-67.25q32%208.75%2066.25%208.75%205.5%200%2015.5-0.5-5%205.5-7.75%208.25l-96%2096q-27.75%2027.75-62.875%2042t-72.875%2014.25q-37.5%200-72.875-14.375t-62.875-41.875q-27.75-27.75-42-62.875t-14.25-72.875%2014.25-72.875%2042-62.875l96-96q2.75-2.75%208.25-7.75%2026.75-23.75%2059.75-36.125t67.75-12.375z%22%3E%3C/path%3E%0A%20%20%3C/g%3E%0A%3C/svg%3E%0A'); |
|||
background-repeat: no-repeat; |
|||
} |
|||
@ -1,5 +0,0 @@ |
|||
|
|||
.icon-grunticon-link { |
|||
background-image: url('png/grunticon-link.png'); |
|||
background-repeat: no-repeat; |
|||
} |
|||
|
Before Width: | Height: | Size: 499 B |
@ -1,33 +0,0 @@ |
|||
<!doctype HTML> |
|||
<html> |
|||
<head> |
|||
<title>Icons Preview!</title> |
|||
<meta charset="utf-8"> |
|||
<style> |
|||
body { |
|||
background-image: linear-gradient(#eee 25%, transparent 25%, transparent), linear-gradient(#eee 25%, transparent 25%, transparent), linear-gradient(transparent 75%, #eee 75%), linear-gradient(transparent 75%, #eee 75%); |
|||
width: auto; |
|||
background-size: 10px 10px; |
|||
} |
|||
</style> |
|||
<script> |
|||
|
|||
/*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */ |
|||
|
|||
(function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this); |
|||
|
|||
grunticon(["icons.data.svg.css", "icons.data.png.css", "icons.fallback.css"]); |
|||
</script> |
|||
<noscript><link href="icons.fallback.css" rel="stylesheet"></noscript> |
|||
|
|||
</head> |
|||
<body> |
|||
|
|||
<h1>PREVIEW - you can change this in the previewTemplate option</h1> |
|||
|
|||
|
|||
<pre><code>.icon-grunticon-link:</code></pre><div class="icon-grunticon-link" style="width: 20px; height: 20px;" ></div><hr/> |
|||
|
|||
|
|||
</body> |
|||
</html> |
|||
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 763 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@ -1,822 +0,0 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>AnchorJS - Add deep anchor links to your docs</title> |
|||
<link rel="icon" type="image/x-icon" href="favicon.ico"> |
|||
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,700' rel='stylesheet' type='text/css'> |
|||
<link rel="stylesheet" href="styles.css"> |
|||
<link rel="stylesheet" href="fonts/fonts.css"> |
|||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/prism/1.5.1/themes/prism-twilight.css"> |
|||
<script src="grunticon/grunticon.loader.js"></script> |
|||
<script> |
|||
grunticon(["grunticon/icons.data.svg.css", "grunticon/icons.data.png.css", "grunticon/icons.fallback.css"]); |
|||
</script> |
|||
<noscript> |
|||
<link href="grunticon/icons.fallback.css" rel="stylesheet"> |
|||
</noscript> |
|||
</head> |
|||
<body> |
|||
<header class="header"> |
|||
<h1 class="page-title">AnchorJS</h1> |
|||
<img class="logo" src="img/anchorjs_logo.png" /> |
|||
<div class="desc"> |
|||
<p class="maindesc">Add deep anchor links to your docs.</p> |
|||
<p class="subdesc">What are "deep anchor links"? Here are a few examples:</p> |
|||
</div> |
|||
<div class="preview-examples"> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3 id="basic-link-preview">Basic Link</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options.visible = 'always'; |
|||
anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Paragraph Link</h3> |
|||
<p id="paragraph-link-preview">Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '¶' |
|||
}; |
|||
anchors.add('p');</code></pre> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<p class="more-examples"><a href="#examples">See more examples</a></p> |
|||
<div class="used-by"> |
|||
<h2 class="used-by-label">Used by</h2> |
|||
<!-- <a href="http://primercss.io/about/"><img src="https://avatars.githubusercontent.com/u/7143434?v=3&s=120" alt="Primer CSS Logo" title="PrimerCSS"/></a> --> |
|||
<a href="http://getbootstrap.com/getting-started/"><img src="https://avatars.githubusercontent.com/u/2918581?v=3&s=120" alt="Bootstrap Logo" title="Bootstrap" /></a> |
|||
<a href="http://eslint.org/docs/rules/"><img src="https://avatars.githubusercontent.com/u/6019716?v=3&s=120" alt="ESLint logo" title="ESLint"/></a> |
|||
<a href="https://frontend.18f.gov/"><img src="https://avatars.githubusercontent.com/u/6233994?v=3&s=120" alt="18F Logo" title="18F" /></a> |
|||
<a href="http://bundler.io/v1.15/guides/deploying.html"><img src="https://avatars.githubusercontent.com/u/1137638?v=3&s=120" alt="Bundler Logo" title="Bundler" /></a> |
|||
<a href="https://mochajs.org"><img src="https://avatars.githubusercontent.com/u/8770005?v=3&s=120" alt="Mocha Logo" title="Mocha" /></a> |
|||
<a href="https://middlemanapp.com/basics/install/"><img src="https://avatars.githubusercontent.com/u/1280820?v=3&s=120" alt="Middleman logo" title="Middleman"/></a> |
|||
<!-- <a href="http://learn.getgrav.org/"><img src="https://avatars.githubusercontent.com/u/8237355?v=3&s=120" alt="Grav Logo" title="Grav" /></a> --> |
|||
</div> |
|||
</header> |
|||
<section class="main"> |
|||
<h2>Overview</h2> |
|||
<img class="anchorlink-examples" src="img/anchorlinks2.png" alt="Examples of deep anchor links from across the web." /> |
|||
<p>AnchorJS lets you drop deep anchor links (<a href="http://ux.stackexchange.com/q/36304/33248">like these</a>) onto any webpage, and be on your way.</p> |
|||
<p>You don't need to set up IDs or worry about urls. AnchorJS will respect your IDs if you have them, and generate them if you don't.</p> |
|||
<p>It uses an attractive link icon by default, but you can customize the display via <a href="#options">options</a> and CSS syling. The <a href="#examples">examples</a> demonstrate a few customization ideas.</p> |
|||
<p>Finally, AnchorJS is <strong>lightweight</strong>, <strong>accessible</strong>, and has <strong>no dependencies</strong>.</p> |
|||
|
|||
<h2>Installation</h2> |
|||
|
|||
<p>Download AnchorJS using npm,</p> |
|||
<pre><code>npm install anchor-js</code></pre> |
|||
<p>or bower:</p> |
|||
<pre><code>bower install anchor-js</code></pre> |
|||
<p>(or just <a href="https://github.com/bryanbraun/anchorjs/releases">download it from github</a>).</p> |
|||
<p>Then include the anchor.js file (or anchor.min.js) in your webpage.</p> |
|||
<pre><code class="language-markup"><script src="anchor.js"></script></code></pre> |
|||
<p>You could also include it via a CDN like <a href="https://cdnjs.com/libraries/anchor-js">CDNJS</a> or <a href="http://www.jsdelivr.com/projects/anchorjs">jsDelivr</a>.</p> |
|||
<p>If you're using it from Node/CommonJS, include it via:</p> |
|||
<pre class="src-js"><code>var anchorJS = require('anchor-js'); |
|||
var anchors = new anchorJS();</code></pre> |
|||
|
|||
<h2>Basic usage</h2> |
|||
<p>AnchorJS provides the <code>anchors.add()</code> method which takes a CSS selector (similar to jQuery) for targeting elements you want to deep-link. Here are some usage examples.</p> |
|||
<pre class="src-js"><code>/** |
|||
* Example 1 |
|||
* Add anchors to all h1's on the page |
|||
*/ |
|||
anchors.add('h1'); |
|||
|
|||
/** |
|||
* Example 2 |
|||
* Adds anchors to elements that have been assigned the class '.anchored' |
|||
*/ |
|||
anchors.add('.anchored'); |
|||
|
|||
/** |
|||
* Example 3 |
|||
* If no selector is provided, it falls back to a default selector of: |
|||
* 'h2, h3, h4, h5, h6' |
|||
*/ |
|||
anchors.add();</code></pre> |
|||
|
|||
<h3>Don't run it too late!</h3> |
|||
<p>You need to add anchors to the page early in the page load process if you want browsers to jump to the ID properly.</p> |
|||
<p>We recommend you call <code>anchors.add()</code> before the DOM finishes loading...</p> |
|||
|
|||
<pre><code class="language-markup"><!-- Add anchors before the closing body tag. --> |
|||
<script> |
|||
anchors.add(); |
|||
</script> |
|||
</body></code></pre> |
|||
<p>...or on DOMContentLoaded:</p> |
|||
<pre class="src-js"><code>// Add anchors on DOMContentLoaded |
|||
document.addEventListener("DOMContentLoaded", function(event) { |
|||
anchors.add(); |
|||
});</code></pre> |
|||
|
|||
<p>Don't add anchors on later events, like <code>$(document).ready()</code> or <code>window.onload</code> as some browsers will attempt to jump to your ID before AnchorJS can add it to the page. For more details, see <a href="https://github.com/bryanbraun/anchorjs/issues/69#issuecomment-255503575">github issue #69</a>).</p> |
|||
|
|||
<h2>Options</h2> |
|||
<p>You can set a number of options to customize how your anchors look:</p> |
|||
<table class='options-table'> |
|||
<thead> |
|||
<tr> |
|||
<th>Option</th> |
|||
<th class="minicol">Accepted Values</th> |
|||
<th class="minicol">Default Value</th> |
|||
<th>Description</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr> |
|||
<td><code>placement</code></td> |
|||
<td><code>right</code> <br> <code>left</code></td> |
|||
<td><code>right</code></td> |
|||
<td><code>right</code> appends the anchor to the end of the element.<br> <code>left</code> places it to the left, in the margin.</td> |
|||
</tr> |
|||
<tr> |
|||
<td><code>visible</code></td> |
|||
<td><code>hover</code> <br> <code>always</code> <br> <code>touch</code></td></td> |
|||
<td><code>hover</code></td> |
|||
<td><code>hover</code> displays the anchor when hovering over the element.<br> <code>always</code> will always display the anchor link. <br> <code>touch</code> will <em>always</em> display anchors for devices that support touch events, and only display them via <em>hover</em> for devices that do not support touch events. This approximates touchscreen detection (but <a href="http://www.stucox.com/blog/you-cant-detect-a-touchscreen/">isn't 100% accurate</a>).</td> |
|||
</tr> |
|||
<tr> |
|||
<td><code>icon</code></td> |
|||
<td>(any unicode character)</td> |
|||
<td><code style="font-family: 'anchorjs-icons'; font-size: 24px; -webkit-font-smoothing: antialiased;"></code></td> |
|||
<td>Replace the default link icon with the character(s) provided. These are a few good options: <code>#</code>, <code>¶</code>, <code>❡</code>, and <code>§</code>.</td> |
|||
</tr> |
|||
<tr> |
|||
<td><code>class</code></td> |
|||
<td>(any string)</td> |
|||
<td>(none)</td> |
|||
<td>Adds the provided class(es) to the anchor html.</td> |
|||
</tr> |
|||
<tr> |
|||
<td><code>truncate</code></td> |
|||
<td>(any positive number)</td> |
|||
<td><code>64</code></td> |
|||
<td>Truncates the generated ID to the specified character length. <small>Note: the length may not be exactly the same, if there are dangling spaces or hyphens to be trimmed.</small></td> |
|||
</tr> |
|||
<tr> |
|||
<td><code>ariaLabel</code></td> |
|||
<td>(any text)</td> |
|||
<td><code>Anchor</code></td> |
|||
<td>Allows you to customize or translate the default aria-label ("Anchor"), for screenreaders that encounter the link.</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
<p>For example:</p> |
|||
<pre class="src-js"><code>/** |
|||
* Example 1 |
|||
* Add anchors to all h1s, h2s and h3s inside of #post. |
|||
* Anchors will be always visible. |
|||
*/ |
|||
anchors.options.visible = 'always'; |
|||
anchors.add('#post h1, #post h2, #post h3'); |
|||
|
|||
/** |
|||
* Example 2 |
|||
* Provide options as an object before adding anchors to the page. |
|||
* Adds always-visible ¶ anchors in the left margin of each p tag inside .story |
|||
*/ |
|||
anchors.options = { |
|||
placement: 'left', |
|||
visible: 'always', |
|||
icon: '¶' |
|||
}; |
|||
anchors.add('.story > p');</code></pre> |
|||
|
|||
<h2>Advanced usage</h2> |
|||
|
|||
<section id="section-ids"> |
|||
<h3 data-anchor-id="section-ids">Section IDs</h3> |
|||
<p>In some cases, you might want to link to existing section IDs instead of the heading element itself. You can instruct AnchorJS to do this with the <code>data-anchor-id</code> attribute:</p> |
|||
<pre><code class="language-markup"><section id="section-1"> |
|||
<h3 data-anchor-id="section-1">Section 1</h3> |
|||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed...</p> |
|||
</section> |
|||
|
|||
<!-- ... --> |
|||
|
|||
<script> |
|||
anchors.add('h3'); |
|||
</script></code></pre> |
|||
<p>This allows you to do things like <a href="https://css-tricks.com/on-target/#article-header-id-3">highlight sections when your users jump to them</a>.</p> |
|||
</section> |
|||
|
|||
<h3>Removing anchors</h3> |
|||
<p>You can remove anchors with the <code>anchors.remove()</code> or <code>anchors.removeAll()</code> methods:</p> |
|||
<pre class="src-js"><code>/** |
|||
* Example 1 |
|||
* Remove anchors from all h1s on the page. |
|||
*/ |
|||
anchors.remove('h1'); |
|||
|
|||
/** |
|||
* Example 2 |
|||
* Remove all anchors from the page. |
|||
*/ |
|||
anchors.removeAll();</pre></code> |
|||
<p>Removing anchors with <code>.remove()</code> should be uncommon. If you simply want anchors on a more selective group, consider using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:not">the CSS <em>:not()</em> pseudo-class</a> when you add them, like so:</p> |
|||
<pre class="src-js"><code>/** |
|||
* Example 2 |
|||
* Add anchors to all h2s, except for those with a class of "no-anchor". |
|||
*/ |
|||
anchors.add('h2:not(.no-anchor)');</pre></code> |
|||
|
|||
<h3>Chaining commands</h3> |
|||
<p>You can chain commands of <code>add()</code> and <code>remove()</code> (since they return a copy of <code>anchors</code>), but it's usually more performant to lean on CSS when targeting elements: |
|||
|
|||
<pre class="src-js"><code>/** |
|||
* Example 1 |
|||
* Adds anchors to `.my-anchors` and `.my-other-anchors` except for those |
|||
* with a class of `no-anchor`. |
|||
*/ |
|||
anchors.add('.my-anchors').add('.my-other-anchors').remove('.no-anchor'); |
|||
|
|||
/** |
|||
* Example 2 |
|||
* A more performant way to add anchors to the same classes in Example 1 above. |
|||
*/ |
|||
anchors.add('.my-anchors:not(.no-anchor), .my-other-anchors:not(.no-anchor)');</code></pre> |
|||
|
|||
<h3>Multiple sets of anchors</h3> |
|||
<p>You can have multiple sets of anchors on one page, each with their own design. To do so, just create your own instances of the AnchorJS object:</p> |
|||
<pre class="src-js"><code>var sidebarAnchors = new AnchorJS(); |
|||
anchors.add('.main h2'); // The default instance. |
|||
sidebarAnchors.add('.sidebar h2'); // The new instance.</code></pre> |
|||
<p>You can preset your instance with whatever options you like:</p> |
|||
<pre class="src-js"><code>var sidebarAnchors = new AnchorJS({ |
|||
placement: 'left', |
|||
icon: '¶' |
|||
}); |
|||
sidebarAnchors.add('.sidebar h2');</code></pre> |
|||
|
|||
<h3>Generating navigations</h3> |
|||
<p>AnchorJS doesn't include methods for dynamically generating navigations (like a table of contents or jump nav). This is to keep AnchorJS lightweight and simple for the most common usecases.</p> |
|||
<p>However, AnchorJS <em>does</em> expose a list of all anchored elements at <code>anchors.elements</code>. This way, external code can look up the elements and use them to generate navigations (as shown in <a href="https://jsfiddle.net/bryanbraun/nc6rL9hk/">this example</a>).</p> |
|||
<p>You can also use AnchorJS alongside a static navigation with pre-defined IDs (as is done in <a href="https://jsfiddle.net/bryanbraun/x85hfvbk/">this example</a>).</p> |
|||
|
|||
<h2>Examples</h2> |
|||
<div class="examples"> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Basic Link</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options.visible = 'always'; |
|||
anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Basic Link - Left</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Paragraph Link</h3> |
|||
<p id="paragraph-link">Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '¶' |
|||
}; |
|||
anchors.add('p');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Octothorp</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
icon: '#' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Unicode Icon 1</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '§' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Unicode Icon 2</h3> |
|||
<p id="unicode-icon-2">Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
icon: '❡' |
|||
}; |
|||
anchors.add('p');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Custom Text</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
icon: '# LINK' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
font-weight: 200; |
|||
margin-left: 1em; |
|||
padding-right: 0.375em; |
|||
font-size: 0.5em; |
|||
border: 1px dashed #FFBAAC; |
|||
vertical-align: middle; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Custom Image</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>// Use an empty string ('') for the icon when styling the background with CSS. |
|||
anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
width: 14px; |
|||
height: 32px; |
|||
margin-top: 6px; |
|||
margin-left: -1.25em !important; |
|||
background: url('img/mini-logo.png') no-repeat; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Link w/CSS Styling</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
display: inline-block; |
|||
height: 32px; |
|||
width: 18px; |
|||
border-radius: 50%; |
|||
background-color: #FF5231; |
|||
color: white; |
|||
margin-top: 4px; |
|||
margin-left: -1.4em !important; |
|||
} |
|||
.anchorjs-link:before { |
|||
margin-left: 7px; |
|||
margin-top: -4px; |
|||
display: block; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Icon Font</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>// Just pass in the octal code for your icon-font character. |
|||
anchors.options = { |
|||
visible: 'always', |
|||
icon: '\uf0c1' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
font-family: 'your-icon-font'; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>SVG Icon</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
icon: '' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
display: inline-block; |
|||
background: url('img/hyperlink.svg') no-repeat; |
|||
margin-left: 8px; |
|||
width: 14px; |
|||
height: 24px; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Base64 Icon</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjIwcHgiIGhlaWdodD0iMTBweCIgdmlld0JveD0iMCAwIDIwIDEwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9ImxpbmsiIGZpbGw9IiNGRjUyMzEiPgogICAgICAgICAgICA8cGF0aCBkPSJNMTUsMCBMMTIuMzA0Njg3NSwwIEMxMy4yNDIxODc1LDAuNjI1IDE0LjEyMTA5MzgsMS43MzgyODEyNSAxNC4zOTQ1MzEyLDIuNSBMMTQuOTgwNDY4OCwyLjUgQzE2LjI1LDIuNSAxNy40ODA0Njg4LDMuNzUgMTcuNDgwNDY4OCw1IEMxNy40ODA0Njg4LDYuMjUgMTYuMjEwOTM3NSw3LjUgMTQuOTgwNDY4OCw3LjUgTDExLjIzMDQ2ODgsNy41IEMxMCw3LjUgOC43MzA0Njg3NSw2LjI1IDguNzMwNDY4NzUsNSBDOC43MzA0Njg3NSw0LjU1MDc4MTI1IDguODY3MTg3NSw0LjEyMTA5Mzc1IDkuMDgyMDMxMjUsMy43NSBMNi40MDYyNSwzLjc1IEM2LjMwODU5Mzc1LDQuMTYwMTU2MjUgNi4yNSw0LjU3MDMxMjUgNi4yNSw1IEM2LjI1LDcuNSA4LjczMDQ2ODc1LDEwIDExLjIzMDQ2ODgsMTAgTDE1LDEwIEMxNy41LDEwIDIwLDcuNSAyMCw1IEMyMCwyLjUgMTcuNSwwIDE1LDAgTDE1LDAgWiBNNS42MDU0Njg3NSw3LjUgTDUuMDE5NTMxMjUsNy41IEMzLjc1LDcuNSAyLjUxOTUzMTI1LDYuMjUgMi41MTk1MzEyNSw1IEMyLjUxOTUzMTI1LDMuNzUgMy43ODkwNjI1LDIuNSA1LjAxOTUzMTI1LDIuNSBMOC43Njk1MzEyNSwyLjUgQzEwLDIuNSAxMS4yNjk1MzEyLDMuNzUgMTEuMjY5NTMxMiw1IEMxMS4yNjk1MzEyLDUuNDQ5MjE4NzUgMTEuMTMyODEyNSw1Ljg3ODkwNjI1IDEwLjkxNzk2ODgsNi4yNSBMMTMuNTkzNzUsNi4yNSBDMTMuNjkxNDA2Miw1LjgzOTg0Mzc1IDEzLjc1LDUuNDI5Njg3NSAxMy43NSw1IEMxMy43NSwyLjUgMTEuMjY5NTMxMiwwIDguNzY5NTMxMjUsMCBMNSwwIEMyLjUsMCAwLDIuNSAwLDUgQzAsNy41IDIuNSwxMCA1LDEwIEw3LjY5NTMxMjUsMTAgQzYuNzU3ODEyNSw5LjM3NSA1Ljg3ODkwNjI1LDguMjYxNzE4NzUgNS42MDU0Njg3NSw3LjUgTDUuNjA1NDY4NzUsNy41IFoiIGlkPSJTaGFwZSI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+") no-repeat; |
|||
margin-top: 15px; |
|||
height: 16px; |
|||
width: 20px; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>CSS Icon</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>/* See also: nicolasgallagher.com/pure-css-gui-icons */ |
|||
.anchorjs-link { |
|||
border-color: #FF5231 #FF5231 transparent; |
|||
border-width: 15px 7px 6px; |
|||
border-style: solid; |
|||
margin-top: 10px; |
|||
font-size: 22px; |
|||
padding-right: 0 !important; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Emoji</h3> |
|||
<p id="emoji">Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '⚓' |
|||
}; |
|||
anchors.add('p');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
margin-left: -1.8em !important; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Grunticon</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>// Assuming you have set up |
|||
// grunticon and you have a |
|||
// grunticon class named |
|||
// 'icon-grunticon-link'... |
|||
anchors.options = { |
|||
visible: 'always', |
|||
class: 'icon-grunticon-link' |
|||
icon: '' |
|||
}; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
display: inline-block; |
|||
margin-left: 0.375em; |
|||
width: 0.375em; |
|||
height: 20px; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<h2 id="hover-examples" class="title">Hover examples</h2> |
|||
<div class="hover-examples"> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Basic Hover</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.add('h3');</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Color Transition</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link:hover { |
|||
color: #2500AD; |
|||
} |
|||
*:hover > .anchorjs-link { |
|||
transition: color .25s linear; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Shift Out</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options.placement = 'left'; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>.anchorjs-link { |
|||
transition: all .25s linear; |
|||
} |
|||
*:hover > .anchorjs-link { |
|||
margin-left: -1.125em !important; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Arrow</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options.icon = '# LINK'; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>/* Based on http://codepen.io/corysimmons/pen/NPBXbe */ |
|||
/* Vendor prefixes not included */ |
|||
.anchorjs-link { |
|||
position: relative; |
|||
top: 4px; |
|||
height: 36px; |
|||
flex: 1; |
|||
background: #FF5231; |
|||
color: white; |
|||
font-family: Helvetica, Arial, sans-serif; |
|||
font-weight: 200; |
|||
font-size: 1rem; |
|||
margin-right: -6%; |
|||
padding-right: 6%; |
|||
padding-left: 42px !important; |
|||
line-height: 38px; |
|||
transition: all 0.5s ease; |
|||
transform: translateX(100%); |
|||
} |
|||
.anchorjs-link::before { |
|||
position: absolute; |
|||
display: block; |
|||
left: 0; |
|||
width: 0; |
|||
height: 0; |
|||
content: ''; |
|||
border: 18px solid #fdfdfd; /* Background color */ |
|||
border-right-color: #FF5231; |
|||
transition: all 0.5s ease; |
|||
} |
|||
h2 { |
|||
display: flex; |
|||
} |
|||
*:hover > .anchorjs-link { |
|||
transform: translateX(0); |
|||
} |
|||
*:hover > .anchorjs-link:hover { |
|||
background: #FF806A; |
|||
} |
|||
*:hover > .anchorjs-link:hover::before { |
|||
border-right-color: #FF806A; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="example"> |
|||
<div class="example-content"> |
|||
<h3>Tooltip</h3> |
|||
<p>Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.</p> |
|||
<a href="#" class="example-code-link">{}</a> |
|||
</div> |
|||
<div class="example-code"> |
|||
<pre class="js"><code>anchors.options = { icon: 'Permalink' }; |
|||
anchors.add('h3');</code></pre> |
|||
<pre class="css"><code>/* tooltip box */ |
|||
.anchorjs-link:after { |
|||
display: inline-block; |
|||
transition: opacity .25s linear; |
|||
font-family: Verdana, sans-serif; |
|||
font-size: 0.75ex; |
|||
font-weight: 100; |
|||
padding: 0.5ex 1.5ex; |
|||
background: #444; |
|||
color: #fff; |
|||
border-radius: 0.6ex; |
|||
vertical-align: 0.8ex; |
|||
} |
|||
/* tooltip arrow */ |
|||
.anchorjs-link:before { |
|||
content: ''; |
|||
display: inline-block; |
|||
border-top: 0.3ex solid transparent; |
|||
border-right: 0.5ex solid #444; |
|||
border-bottom: 0.3ex solid transparent; |
|||
vertical-align: 0.35ex; |
|||
} |
|||
.anchorjs-link:hover:after { |
|||
background-color: #666; |
|||
} |
|||
.anchorjs-link:hover:before { |
|||
border-right-color: #666; |
|||
}</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
<footer class="footer"><p><small>Made by <a href="http://www.bryanbraun.com">Bryan</a>. You should <a href="https://twitter.com/intent/tweet?text=Hi%20%40BryanEBraun%2C%20">say hi</a> sometime. 👋</small></p></footer> |
|||
<a href="https://github.com/bryanbraun/anchorjs"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://github-camo.global.ssl.fastly.net/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"></a> |
|||
</section> |
|||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> |
|||
<script src="anchor.js"></script> |
|||
<script src="scripts.js"></script> |
|||
<script> |
|||
anchors.add('.main > h2, .main > h3, .main > section > h2, .main > section > h3').remove('.used-by-label'); |
|||
|
|||
var ex1 = new AnchorJS({ visible: 'always' }); |
|||
ex1.add('.examples .example:nth-child(1) h3, .preview-examples .example:nth-child(1) h3'); |
|||
|
|||
var ex2 = new AnchorJS({ |
|||
placement: 'left', |
|||
visible: 'always' |
|||
}); |
|||
ex2.add('.examples .example:nth-child(2) h3'); |
|||
|
|||
var ex3 = new AnchorJS({ |
|||
icon: '¶', |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}); |
|||
ex3.add('.examples .example:nth-child(3) p, .preview-examples .example:nth-child(2) p'); |
|||
|
|||
var ex4 = new AnchorJS({ |
|||
icon: '#', |
|||
visible: 'always' |
|||
}); |
|||
ex4.add('.examples .example:nth-child(4) h3'); |
|||
|
|||
var ex5 = new AnchorJS({ |
|||
icon: '§', |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}); |
|||
ex5.add('.examples .example:nth-child(5) h3'); |
|||
|
|||
var ex6 = new AnchorJS({ |
|||
icon: '❡', |
|||
visible: 'always' |
|||
}); |
|||
ex6.add('.examples .example:nth-child(6) p'); |
|||
|
|||
var ex7 = new AnchorJS({ |
|||
icon: '# LINK', |
|||
visible: 'always' |
|||
}); |
|||
ex7.add('.examples .example:nth-child(7) h3'); |
|||
|
|||
var ex8 = new AnchorJS({ |
|||
icon: '', |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}); |
|||
ex8.add('.examples .example:nth-child(8) h3'); |
|||
|
|||
var ex9 = new AnchorJS({ |
|||
visible: 'always', |
|||
placement: 'left' |
|||
}); |
|||
ex9.add('.examples .example:nth-child(9) h3'); |
|||
|
|||
var ex10 = new AnchorJS({ |
|||
visible: 'always', |
|||
class: 'ajs-10', |
|||
icon: '\uf0c1' |
|||
}); |
|||
ex10.add('.examples .example:nth-child(10) h3'); |
|||
|
|||
var ex11 = new AnchorJS({ |
|||
visible: 'always', |
|||
icon: '' |
|||
}); |
|||
ex11.add('.examples .example:nth-child(11) h3'); |
|||
|
|||
var ex12 = new AnchorJS({ |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '' |
|||
}); |
|||
ex12.add('.examples .example:nth-child(12) h3'); |
|||
|
|||
var ex13 = new AnchorJS({ |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '' |
|||
}); |
|||
ex13.add('.examples .example:nth-child(13) h3'); |
|||
|
|||
var ex14 = new AnchorJS({ |
|||
visible: 'always', |
|||
placement: 'left', |
|||
icon: '⚓' |
|||
}); |
|||
ex14.add('.examples .example:nth-child(14) p'); |
|||
|
|||
var ex15 = new AnchorJS({ |
|||
visible: 'always', |
|||
class: 'icon-grunticon-link', |
|||
icon: '' |
|||
}); |
|||
ex15.add('.examples .example:nth-child(15) h3'); |
|||
|
|||
var hovEx1 = new AnchorJS(); |
|||
hovEx1.add('.hover-examples .example:nth-child(1) h3'); |
|||
|
|||
var hovEx2 = new AnchorJS(); |
|||
hovEx2.add('.hover-examples .example:nth-child(2) h3'); |
|||
|
|||
var hovEx3 = new AnchorJS({ placement: 'left' }); |
|||
hovEx3.add('.hover-examples .example:nth-child(3) h3'); |
|||
|
|||
var hovEx4 = new AnchorJS({ icon: '# LINK' }); |
|||
hovEx4.add('.hover-examples .example:nth-child(4) h3'); |
|||
|
|||
var hovEx5 = new AnchorJS({ icon: 'Permalink' }); |
|||
hovEx5.add('.hover-examples .example:nth-child(5) h3'); |
|||
</script> |
|||
<script src="https://cdn.jsdelivr.net/prism/1.5.1/prism.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -1,12 +0,0 @@ |
|||
$(document).ready(function() { |
|||
var preEls = $('pre'); |
|||
|
|||
$('.example-code-link').click(function(e) { |
|||
e.preventDefault(); |
|||
$(this).parent().next().slideToggle(); |
|||
}); |
|||
|
|||
// Dynamically add PrismJS class for syntax highlight
|
|||
preEls.filter('[class*="js"]').find('code').addClass('language-javascript'); |
|||
preEls.filter('.css').find('code').addClass('language-css'); |
|||
}); |
|||
@ -1,494 +0,0 @@ |
|||
/*//// Base Styles ////*/ |
|||
|
|||
div, |
|||
article, |
|||
section, |
|||
main, |
|||
footer, |
|||
header, |
|||
form, |
|||
fieldset, |
|||
pre, |
|||
code, |
|||
p, |
|||
input[type="text"], |
|||
input[type="tel"], |
|||
input[type="email"], |
|||
input[type="url"], |
|||
input[type="password"] { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
body { |
|||
font-family: 'Source Sans Pro', sans-serif; |
|||
background-color: rgb(162, 255, 224); |
|||
color: #262626; |
|||
margin: 0 1.5em; |
|||
} |
|||
|
|||
h1 { |
|||
font-size: 2.2em; |
|||
} |
|||
h2 { |
|||
font-size: 2.0em; |
|||
margin-top: 1.5em; |
|||
} |
|||
h3 { |
|||
font-size: 1.8em; |
|||
} |
|||
|
|||
table { |
|||
border-collapse: collapse; |
|||
background: white; |
|||
box-shadow: 0px 0px 10px -4px #666; |
|||
border: 1px solid white; |
|||
} |
|||
|
|||
table td, |
|||
table th { |
|||
padding: 0.5em; |
|||
border: 1px solid #ddd; |
|||
} |
|||
|
|||
img { |
|||
max-width: 100%; |
|||
} |
|||
|
|||
a { |
|||
color: black; |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
/*//// Code Snippet Styles ////*/ |
|||
|
|||
code, |
|||
samp, |
|||
kbd { |
|||
background-color: #141414; |
|||
color: #f7f7f7; |
|||
font-family: "Inconsolata", "Menlo", "Consolas", monospace; |
|||
font-size: 0.9em; |
|||
padding: 2px 6px; |
|||
text-align: left; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
pre { |
|||
background-color: #141414; |
|||
color: #f7f7f7; |
|||
font-family: "Inconsolata", "Menlo", "Consolas", monospace; |
|||
font-size: 0.9em; |
|||
line-height: 1.2em; |
|||
margin: 0; |
|||
overflow: auto; |
|||
padding: 1em; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
.examples pre, |
|||
.hover-examples pre, |
|||
.preview-examples pre { |
|||
padding-left: 2.75em; |
|||
border-radius: 0; |
|||
} |
|||
|
|||
/* Override 'code' css rules if using 'pre > code' markup. */ |
|||
pre > code { |
|||
font-size: 1em; |
|||
padding: 0px; |
|||
} |
|||
|
|||
/* for IE7 and IE6 */ |
|||
*:first-child+html pre { |
|||
overflow: visible; |
|||
overflow-x: auto; |
|||
overflow-y: hidden; |
|||
padding-bottom: 2em; |
|||
} |
|||
|
|||
* html pre { |
|||
overflow: visible; |
|||
overflow-x: auto; |
|||
padding-bottom: 2em; |
|||
} |
|||
|
|||
/* Reset PrismJS' border styles */ |
|||
.main pre[class*="language-"], |
|||
.example pre[class*="language-"] { |
|||
border: 0; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
/*//// Page Styles ////*/ |
|||
.header { |
|||
max-width: 720px; |
|||
margin: 0 auto; |
|||
padding-top: 1.5em; |
|||
} |
|||
|
|||
.page-title { |
|||
text-align: center; |
|||
} |
|||
|
|||
.logo { |
|||
display: block; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.desc { |
|||
padding: 1em 0; |
|||
text-align: center; |
|||
} |
|||
.maindesc { |
|||
font-size: 30px; |
|||
margin-bottom: 1em; |
|||
} |
|||
.subdesc { |
|||
font-size: 15px; |
|||
} |
|||
|
|||
.more-examples { |
|||
text-align: right; |
|||
font-size: 12px; |
|||
margin: 0 5px 0 0; |
|||
} |
|||
|
|||
.main { |
|||
line-height: 1.4; |
|||
margin: 0 auto; |
|||
max-width: 720px; |
|||
} |
|||
.used-by { |
|||
text-align: center; |
|||
position: relative; |
|||
padding: 1em 0; |
|||
} |
|||
.used-by-label { |
|||
font-size: 20px; |
|||
text-align: center; |
|||
font-weight: normal; |
|||
} |
|||
.used-by img { |
|||
border-radius: 8px; |
|||
opacity: 1; |
|||
margin: 0px 10px; |
|||
width: 96px; |
|||
} |
|||
|
|||
.anchorlink-examples { |
|||
float: right; |
|||
margin: 0 0 1em 1em; |
|||
box-shadow: 0px 0px 10px -3px #666; |
|||
} |
|||
|
|||
.options-table { |
|||
width: 100%; |
|||
margin: 1em 0; |
|||
} |
|||
|
|||
.minicol { |
|||
width: 62px; |
|||
} |
|||
|
|||
.footer { |
|||
text-align: center; |
|||
color: #777; |
|||
} |
|||
.footer a { |
|||
color: #777; |
|||
} |
|||
|
|||
/*///////////// Examples /////////////*/ |
|||
|
|||
.examples, |
|||
.hover-examples, |
|||
.preview-examples { |
|||
max-width: 720px; |
|||
margin: 0 auto; |
|||
display: -webkit-flex; |
|||
display: flex; |
|||
-webkit-flex-direction: row; |
|||
flex-direction: row; |
|||
-webkit-justify-content: center; |
|||
justify-content: center; |
|||
-webkit-flex-wrap: wrap; |
|||
flex-wrap: wrap; |
|||
-webkit-align-content: flex-end; |
|||
align-content: flex-end; |
|||
} |
|||
|
|||
.example { |
|||
max-width: 350px; |
|||
min-height: 160px; |
|||
margin: 5px; |
|||
} |
|||
.example-label { |
|||
font-size: 12px; |
|||
color: #777; |
|||
display: none; |
|||
} |
|||
.example-content { |
|||
padding: 0 0 0 3.5em; |
|||
overflow: hidden; |
|||
position: relative; |
|||
background: #fff; |
|||
box-shadow: 0px 0px 10px -3px #666; |
|||
} |
|||
|
|||
.example-code-link { |
|||
width: 16px; |
|||
position: absolute; |
|||
top: 8px; |
|||
right: 8px; |
|||
font-family: Courier monospace; |
|||
color: #aaa; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
.example-code-link:hover:after, |
|||
.example-code-link:focus:after { |
|||
left: -50px; |
|||
opacity: 1; |
|||
-webkit-transition: all 0.25s ease-in; |
|||
transition: all 0.25s ease-in; |
|||
} |
|||
|
|||
.example-code-link:after { |
|||
content: "SOURCE"; |
|||
font-family: Helvetica, Arial, sans-serif; |
|||
font-size: 10px; |
|||
line-height: 1; |
|||
display: block; |
|||
position: absolute; |
|||
text-transform: uppercase; |
|||
top: 7px; |
|||
left: -45px; |
|||
opacity: 0; |
|||
-webkit-transition: all 0.25s ease-in; |
|||
transition: all 0.25s ease-in; |
|||
} |
|||
|
|||
.example-code { |
|||
display: none; |
|||
} |
|||
|
|||
.css { |
|||
border-top: 1px solid #666; |
|||
} |
|||
|
|||
.css, |
|||
.js { |
|||
position: relative; |
|||
} |
|||
|
|||
.css::before, |
|||
.js::before { |
|||
left: 0; |
|||
top: 0; |
|||
padding: 1px 4px; |
|||
color: white; |
|||
background: #FF5231; |
|||
position: absolute; |
|||
font-size: 11px; |
|||
text-transform: uppercase; |
|||
} |
|||
|
|||
.css::before { |
|||
content: 'css'; |
|||
} |
|||
.js::before { |
|||
content: 'js'; |
|||
} |
|||
|
|||
.example-content > p { |
|||
width: 310px; |
|||
} |
|||
|
|||
.anchorjs-link { |
|||
color: #FF5231; |
|||
} |
|||
|
|||
/*///// Styles within Examples /////*/ |
|||
.examples .example:nth-child(3) .anchorjs-link, |
|||
.preview-examples .example:nth-child(2) .anchorjs-link { |
|||
font-family: Helvetica, Arial, sans-serif; |
|||
} |
|||
|
|||
.examples .example:nth-child(7) .anchorjs-link { |
|||
font-weight: 200; |
|||
margin-left: 1em; |
|||
padding-right: 0.375em; |
|||
font-size: 0.5em; |
|||
border: 1px dashed #FFBAAC; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
.examples .example:nth-child(8) .anchorjs-link { |
|||
width: 14px; |
|||
height: 32px; |
|||
margin-top: 6px; |
|||
background: url('img/mini-logo.png') no-repeat; |
|||
margin-left: -1.25em !important; |
|||
} |
|||
|
|||
.examples .example:nth-child(9) .anchorjs-link:after { |
|||
margin-left: 7px; |
|||
margin-top: -4px; |
|||
display: block; |
|||
} |
|||
|
|||
.examples .example:nth-child(9) .anchorjs-link { |
|||
background-color: #FF5231; |
|||
height: 32px; |
|||
width: 18px; |
|||
border-radius: 50%; |
|||
display: inline-block; |
|||
color: white; |
|||
margin-top: 4px; |
|||
margin-left: -1.4em !important; |
|||
} |
|||
|
|||
.examples .example:nth-child(11) .anchorjs-link { |
|||
display: inline-block; |
|||
background: url('img/hyperlink.svg') no-repeat; |
|||
margin-left: 8px; |
|||
width: 14px; |
|||
height: 24px; |
|||
} |
|||
|
|||
.examples .example:nth-child(12) .anchorjs-link { |
|||
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjIwcHgiIGhlaWdodD0iMTBweCIgdmlld0JveD0iMCAwIDIwIDEwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9ImxpbmsiIGZpbGw9IiNGRjUyMzEiPgogICAgICAgICAgICA8cGF0aCBkPSJNMTUsMCBMMTIuMzA0Njg3NSwwIEMxMy4yNDIxODc1LDAuNjI1IDE0LjEyMTA5MzgsMS43MzgyODEyNSAxNC4zOTQ1MzEyLDIuNSBMMTQuOTgwNDY4OCwyLjUgQzE2LjI1LDIuNSAxNy40ODA0Njg4LDMuNzUgMTcuNDgwNDY4OCw1IEMxNy40ODA0Njg4LDYuMjUgMTYuMjEwOTM3NSw3LjUgMTQuOTgwNDY4OCw3LjUgTDExLjIzMDQ2ODgsNy41IEMxMCw3LjUgOC43MzA0Njg3NSw2LjI1IDguNzMwNDY4NzUsNSBDOC43MzA0Njg3NSw0LjU1MDc4MTI1IDguODY3MTg3NSw0LjEyMTA5Mzc1IDkuMDgyMDMxMjUsMy43NSBMNi40MDYyNSwzLjc1IEM2LjMwODU5Mzc1LDQuMTYwMTU2MjUgNi4yNSw0LjU3MDMxMjUgNi4yNSw1IEM2LjI1LDcuNSA4LjczMDQ2ODc1LDEwIDExLjIzMDQ2ODgsMTAgTDE1LDEwIEMxNy41LDEwIDIwLDcuNSAyMCw1IEMyMCwyLjUgMTcuNSwwIDE1LDAgTDE1LDAgWiBNNS42MDU0Njg3NSw3LjUgTDUuMDE5NTMxMjUsNy41IEMzLjc1LDcuNSAyLjUxOTUzMTI1LDYuMjUgMi41MTk1MzEyNSw1IEMyLjUxOTUzMTI1LDMuNzUgMy43ODkwNjI1LDIuNSA1LjAxOTUzMTI1LDIuNSBMOC43Njk1MzEyNSwyLjUgQzEwLDIuNSAxMS4yNjk1MzEyLDMuNzUgMTEuMjY5NTMxMiw1IEMxMS4yNjk1MzEyLDUuNDQ5MjE4NzUgMTEuMTMyODEyNSw1Ljg3ODkwNjI1IDEwLjkxNzk2ODgsNi4yNSBMMTMuNTkzNzUsNi4yNSBDMTMuNjkxNDA2Miw1LjgzOTg0Mzc1IDEzLjc1LDUuNDI5Njg3NSAxMy43NSw1IEMxMy43NSwyLjUgMTEuMjY5NTMxMiwwIDguNzY5NTMxMjUsMCBMNSwwIEMyLjUsMCAwLDIuNSAwLDUgQzAsNy41IDIuNSwxMCA1LDEwIEw3LjY5NTMxMjUsMTAgQzYuNzU3ODEyNSw5LjM3NSA1Ljg3ODkwNjI1LDguMjYxNzE4NzUgNS42MDU0Njg3NSw3LjUgTDUuNjA1NDY4NzUsNy41IFoiIGlkPSJTaGFwZSI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+") no-repeat; |
|||
margin-top: 15px; |
|||
height: 16px; |
|||
width: 20px; |
|||
} |
|||
|
|||
.examples .example:nth-child(13) .anchorjs-link { |
|||
border-color: #FF5231 #FF5231 transparent; |
|||
border-width: 15px 7px 6px; |
|||
border-style: solid; |
|||
margin-top: 10px; |
|||
font-size: 22px; |
|||
padding-right: 0 !important; |
|||
} |
|||
|
|||
.examples .example:nth-child(14) .anchorjs-link { |
|||
margin-left: -1.8em !important; |
|||
} |
|||
|
|||
.examples .example:nth-child(15) .anchorjs-link { |
|||
display: inline-block; |
|||
width: 0.375em; |
|||
height: 20px; |
|||
margin-left: 0.375em; |
|||
} |
|||
|
|||
/* Hover Examples */ |
|||
|
|||
.hover-examples .example:nth-child(2) *:hover > .anchorjs-link, |
|||
.hover-examples .example:nth-child(2) .anchorjs-link:focus { |
|||
transition: color .25s linear; |
|||
} |
|||
.hover-examples .example:nth-child(2) .anchorjs-link:hover { |
|||
color: #2500AD; |
|||
} |
|||
|
|||
.hover-examples .example:nth-child(3) .anchorjs-link { |
|||
transition: all .25s linear; |
|||
} |
|||
.hover-examples .example:nth-child(3) *:hover > .anchorjs-link, |
|||
.hover-examples .example:nth-child(3) .anchorjs-link:focus { |
|||
margin-left: -1.125em !important; |
|||
} |
|||
|
|||
|
|||
.hover-examples .example:nth-child(4) h3 { |
|||
display: -webkit-box; |
|||
display: -webkit-flex; |
|||
display: -ms-flexbox; |
|||
display: flex; |
|||
} |
|||
.hover-examples .example:nth-child(4) .anchorjs-link { |
|||
background: #FF5231; |
|||
color: white; |
|||
font-family: Helvetica, Arial, sans-serif; |
|||
font-weight: 200; |
|||
font-size: 1rem; |
|||
position: relative; |
|||
top: 2px; |
|||
-webkit-box-flex: 1; |
|||
-webkit-flex: 1; |
|||
-ms-flex: 1; |
|||
flex: 1; |
|||
margin-right: -6%; |
|||
padding-right: 6%; |
|||
padding-left: 42px !important; |
|||
height: 36px; |
|||
line-height: 38px; |
|||
-webkit-transition: all 0.5s ease; |
|||
transition: all 0.5s ease; |
|||
-webkit-transform: translateX(100%); |
|||
-ms-transform: translateX(100%); |
|||
transform: translateX(100%); |
|||
} |
|||
.hover-examples .example:nth-child(4) .anchorjs-link::before { |
|||
position: absolute; |
|||
left: 0; |
|||
display: block; |
|||
width: 0; |
|||
height: 0; |
|||
border: 18px solid #fff; |
|||
border-right-color: #FF5231; |
|||
content: ''; |
|||
transition: all 0.5s ease; |
|||
} |
|||
.hover-examples .example:nth-child(4) *:hover > .anchorjs-link, |
|||
.hover-examples .example:nth-child(4) .anchorjs-link:focus { |
|||
-webkit-transform: translateX(0); |
|||
-ms-transform: translateX(0); |
|||
|
|||
transform: translateX(0); |
|||
} |
|||
.hover-examples .example:nth-child(4) *:hover > .anchorjs-link:hover, |
|||
.hover-examples .example:nth-child(4) .anchorjs-link:focus { |
|||
background: #FF806A; |
|||
} |
|||
.hover-examples .example:nth-child(4) *:hover > .anchorjs-link:hover::before, |
|||
.hover-examples .example:nth-child(4) .anchorjs-link:focus { |
|||
border-right-color: #FF806A; |
|||
} |
|||
|
|||
.hover-examples .example:nth-child(5) .anchorjs-link:after { |
|||
display: inline-block; |
|||
transition: opacity .25s linear; |
|||
font-family: Verdana, sans-serif; |
|||
font-size: 0.75ex; |
|||
font-weight: 100; |
|||
padding: 0.5ex 1.5ex; |
|||
background: #444; |
|||
color: #fff; |
|||
border-radius: 0.6ex; |
|||
vertical-align: 0.8ex; |
|||
} |
|||
.hover-examples .example:nth-child(5) .anchorjs-link:before { |
|||
content: ''; |
|||
display: inline-block; |
|||
border-top: 0.3ex solid transparent; |
|||
border-right: 0.5ex solid #444; |
|||
border-bottom: 0.3ex solid transparent; |
|||
vertical-align: 0.35ex; |
|||
} |
|||
.hover-examples .example:nth-child(5) .anchorjs-link:hover:after { |
|||
background-color: #666; |
|||
} |
|||
.hover-examples .example:nth-child(5) .anchorjs-link:hover:before { |
|||
border-right-color: #666; |
|||
} |
|||
|
|||
/*////// Utilities ////////*/ |
|||
/* Clearfix */ |
|||
.group:after { |
|||
content: ""; |
|||
display: table; |
|||
clear: both; |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
{ |
|||
"name": "bootstrap-toc", |
|||
"homepage": "https://github.com/afeld/bootstrap-toc", |
|||
"version": "0.4.1", |
|||
"_release": "0.4.1", |
|||
"_resolution": { |
|||
"type": "version", |
|||
"tag": "v0.4.1", |
|||
"commit": "a46628385301df48d2a0d813b2a7f529a074662b" |
|||
}, |
|||
"_source": "https://github.com/afeld/bootstrap-toc.git", |
|||
"_target": "0.4.1", |
|||
"_originalSource": "bootstrap-toc" |
|||
} |
|||
@ -1,4 +0,0 @@ |
|||
_site/ |
|||
node_modules/ |
|||
Gemfile.lock |
|||
*.sw? |
|||
@ -1,10 +0,0 @@ |
|||
sudo: false |
|||
language: node_js |
|||
node_js: |
|||
- "5.1" |
|||
branches: |
|||
only: |
|||
- /.*/ |
|||
cache: |
|||
directories: |
|||
- node_modules |
|||
@ -1,3 +0,0 @@ |
|||
source 'https://rubygems.org' |
|||
|
|||
gem 'github-pages', group: :jekyll_plugins |
|||
@ -1,25 +0,0 @@ |
|||
The MIT License (MIT) |
|||
===================== |
|||
|
|||
Copyright © 2015 Aidan Feldman |
|||
|
|||
Permission is hereby granted, free of charge, to any person |
|||
obtaining a copy of this software and associated documentation |
|||
files (the “Software”), to deal in the Software without |
|||
restriction, including without limitation the rights to use, |
|||
copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following |
|||
conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be |
|||
included in all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, |
|||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|||
OTHER DEALINGS IN THE SOFTWARE. |
|||
@ -1,6 +0,0 @@ |
|||
baseurl: /bootstrap-toc |
|||
markdown: kramdown |
|||
kramdown: |
|||
input: GFM |
|||
exclude: |
|||
- node_modules/ |
|||
@ -1,56 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<title>Table of Contents plugin for Bootstrap</title> |
|||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.1.1/gh-fork-ribbon.min.css" /> |
|||
<!--[if lt IE 9]> |
|||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.1.1/gh-fork-ribbon.ie.min.css" /> |
|||
<![endif]--> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous"> |
|||
<link rel="stylesheet" href="{{ site.baseurl }}/bootstrap-toc.css" media="screen" charset="utf-8"> |
|||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/github.min.css"> |
|||
<link rel="stylesheet" href="{{ site.baseurl }}/assets/screen.css" media="screen" charset="utf-8"> |
|||
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> |
|||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script> |
|||
<script src="{{ site.baseurl }}/bootstrap-toc.js" charset="utf-8"></script> |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"></script> |
|||
<script type="text/javascript"> |
|||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
|||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
|||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
|||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); |
|||
|
|||
ga('create', 'UA-19048260-11', 'auto'); |
|||
ga('send', 'pageview'); |
|||
|
|||
hljs.initHighlightingOnLoad(); |
|||
|
|||
$(function() { |
|||
$('#toc').append('<div class="hint">(creates this)</div>'); |
|||
}); |
|||
</script> |
|||
</head> |
|||
<body data-spy="scroll" data-target="#toc"> |
|||
<div class="github-fork-ribbon-wrapper right"> |
|||
<div class="github-fork-ribbon"> |
|||
<a href="https://github.com/afeld/bootstrap-toc">Fork me on GitHub</a> |
|||
</div> |
|||
</div> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-sm-3"> |
|||
<nav id="toc" data-spy="affix" data-toggle="toc"></nav> |
|||
</div> |
|||
<div class="col-sm-9"> |
|||
{{ content }} |
|||
<footer> |
|||
<a href="https://twitter.com/aidanfeldman" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @aidanfeldman</a> |
|||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script> |
|||
</footer> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</body> |
|||
</html> |
|||
@ -1,10 +0,0 @@ |
|||
--- |
|||
layout: default |
|||
--- |
|||
|
|||
<style media="screen"> |
|||
h1, h2, h3, h4 { |
|||
margin-bottom: 150px; |
|||
} |
|||
</style> |
|||
{{ content }} |
|||
@ -1,54 +0,0 @@ |
|||
.right .github-fork-ribbon { |
|||
background-color: #563d7c; |
|||
} |
|||
|
|||
.container { |
|||
max-width: 800px; |
|||
padding-top: 40px; |
|||
padding-bottom: 40px; |
|||
} |
|||
|
|||
.hint { |
|||
color: #563d7c; |
|||
display: inline-block; |
|||
font-weight: bold; |
|||
left: 20px; /* match the left margin of the top-level nav items */ |
|||
position: relative; |
|||
top: 0.5em; |
|||
} |
|||
.hint:before { |
|||
content: '↑'; |
|||
display: block; |
|||
font-size: 3em; |
|||
margin-bottom: 5px; |
|||
text-align: center; |
|||
} |
|||
|
|||
footer { |
|||
margin-top: 50px; |
|||
text-align: center; |
|||
} |
|||
|
|||
/* small screens */ |
|||
@media (max-width: 768px) { |
|||
/* override the Affix plugin so that the navigation isn't sticky */ |
|||
nav.affix[data-toggle='toc'] { |
|||
position: static; |
|||
} |
|||
|
|||
/* display the second-level nav */ |
|||
nav[data-toggle='toc'] .nav .nav { |
|||
display: block; |
|||
} |
|||
|
|||
.hint { |
|||
top: 0; |
|||
} |
|||
} |
|||
|
|||
/* large screens */ |
|||
@media (min-width: 768px) { |
|||
h1:first-child { |
|||
margin-top: 0; |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/) |
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ |
|||
|
|||
/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ |
|||
|
|||
/* All levels of nav */ |
|||
nav[data-toggle='toc'] .nav > li > a { |
|||
display: block; |
|||
padding: 4px 20px; |
|||
font-size: 13px; |
|||
font-weight: 500; |
|||
color: #767676; |
|||
} |
|||
nav[data-toggle='toc'] .nav > li > a:hover, |
|||
nav[data-toggle='toc'] .nav > li > a:focus { |
|||
padding-left: 19px; |
|||
color: #563d7c; |
|||
text-decoration: none; |
|||
background-color: transparent; |
|||
border-left: 1px solid #563d7c; |
|||
} |
|||
nav[data-toggle='toc'] .nav > .active > a, |
|||
nav[data-toggle='toc'] .nav > .active:hover > a, |
|||
nav[data-toggle='toc'] .nav > .active:focus > a { |
|||
padding-left: 18px; |
|||
font-weight: bold; |
|||
color: #563d7c; |
|||
background-color: transparent; |
|||
border-left: 2px solid #563d7c; |
|||
} |
|||
|
|||
/* Nav: second level (shown on .active) */ |
|||
nav[data-toggle='toc'] .nav .nav { |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > li > a { |
|||
padding-top: 4px; |
|||
padding-bottom: 4px; |
|||
padding-left: 40px; |
|||
font-size: 11px; |
|||
font-weight: normal; |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > li > a:hover, |
|||
nav[data-toggle='toc'] .nav .nav > li > a:focus { |
|||
padding-left: 39px; |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > .active > a, |
|||
nav[data-toggle='toc'] .nav .nav > .active:hover > a, |
|||
nav[data-toggle='toc'] .nav .nav > .active:focus > a { |
|||
padding-left: 28px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ |
|||
nav[data-toggle='toc'] .nav > .active > ul { |
|||
display: block; |
|||
} |
|||
@ -1,159 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
(function() { |
|||
'use strict'; |
|||
|
|||
window.Toc = { |
|||
helpers: { |
|||
// return all matching elements in the set, or their descendants
|
|||
findOrFilter: function($el, selector) { |
|||
// http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
|
|||
// http://stackoverflow.com/a/12731439/358804
|
|||
var $descendants = $el.find(selector); |
|||
return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); |
|||
}, |
|||
|
|||
generateUniqueIdBase: function(el) { |
|||
var text = $(el).text(); |
|||
var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); |
|||
return anchor || el.tagName.toLowerCase(); |
|||
}, |
|||
|
|||
generateUniqueId: function(el) { |
|||
var anchorBase = this.generateUniqueIdBase(el); |
|||
for (var i = 0; ; i++) { |
|||
var anchor = anchorBase; |
|||
if (i > 0) { |
|||
// add suffix
|
|||
anchor += '-' + i; |
|||
} |
|||
// check if ID already exists
|
|||
if (!document.getElementById(anchor)) { |
|||
return anchor; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
generateAnchor: function(el) { |
|||
if (el.id) { |
|||
return el.id; |
|||
} else { |
|||
var anchor = this.generateUniqueId(el); |
|||
el.id = anchor; |
|||
return anchor; |
|||
} |
|||
}, |
|||
|
|||
createNavList: function() { |
|||
return $('<ul class="nav"></ul>'); |
|||
}, |
|||
|
|||
createChildNavList: function($parent) { |
|||
var $childList = this.createNavList(); |
|||
$parent.append($childList); |
|||
return $childList; |
|||
}, |
|||
|
|||
generateNavEl: function(anchor, text) { |
|||
var $a = $('<a></a>'); |
|||
$a.attr('href', '#' + anchor); |
|||
$a.text(text); |
|||
var $li = $('<li></li>'); |
|||
$li.append($a); |
|||
return $li; |
|||
}, |
|||
|
|||
generateNavItem: function(headingEl) { |
|||
var anchor = this.generateAnchor(headingEl); |
|||
var $heading = $(headingEl); |
|||
var text = $heading.data('toc-text') || $heading.text(); |
|||
return this.generateNavEl(anchor, text); |
|||
}, |
|||
|
|||
// Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
|
|||
getTopLevel: function($scope) { |
|||
for (var i = 1; i <= 6; i++) { |
|||
var $headings = this.findOrFilter($scope, 'h' + i); |
|||
if ($headings.length > 1) { |
|||
return i; |
|||
} |
|||
} |
|||
|
|||
return 1; |
|||
}, |
|||
|
|||
// returns the elements for the top level, and the next below it
|
|||
getHeadings: function($scope, topLevel) { |
|||
var topSelector = 'h' + topLevel; |
|||
|
|||
var secondaryLevel = topLevel + 1; |
|||
var secondarySelector = 'h' + secondaryLevel; |
|||
|
|||
return this.findOrFilter($scope, topSelector + ',' + secondarySelector); |
|||
}, |
|||
|
|||
getNavLevel: function(el) { |
|||
return parseInt(el.tagName.charAt(1), 10); |
|||
}, |
|||
|
|||
populateNav: function($topContext, topLevel, $headings) { |
|||
var $context = $topContext; |
|||
var $prevNav; |
|||
|
|||
var helpers = this; |
|||
$headings.each(function(i, el) { |
|||
var $newNav = helpers.generateNavItem(el); |
|||
var navLevel = helpers.getNavLevel(el); |
|||
|
|||
// determine the proper $context
|
|||
if (navLevel === topLevel) { |
|||
// use top level
|
|||
$context = $topContext; |
|||
} else if ($prevNav && $context === $topContext) { |
|||
// create a new level of the tree and switch to it
|
|||
$context = helpers.createChildNavList($prevNav); |
|||
} // else use the current $context
|
|||
|
|||
$context.append($newNav); |
|||
|
|||
$prevNav = $newNav; |
|||
}); |
|||
}, |
|||
|
|||
parseOps: function(arg) { |
|||
var opts; |
|||
if (arg.jquery) { |
|||
opts = { |
|||
$nav: arg |
|||
}; |
|||
} else { |
|||
opts = arg; |
|||
} |
|||
opts.$scope = opts.$scope || $(document.body); |
|||
return opts; |
|||
} |
|||
}, |
|||
|
|||
// accepts a jQuery object, or an options object
|
|||
init: function(opts) { |
|||
opts = this.helpers.parseOps(opts); |
|||
|
|||
// ensure that the data attribute is in place for styling
|
|||
opts.$nav.attr('data-toggle', 'toc'); |
|||
|
|||
var $topContext = this.helpers.createChildNavList(opts.$nav); |
|||
var topLevel = this.helpers.getTopLevel(opts.$scope); |
|||
var $headings = this.helpers.getHeadings(opts.$scope, topLevel); |
|||
this.helpers.populateNav($topContext, topLevel, $headings); |
|||
} |
|||
}; |
|||
|
|||
$(function() { |
|||
$('nav[data-toggle="toc"]').each(function(i, el) { |
|||
var $nav = $(el); |
|||
Toc.init($nav); |
|||
}); |
|||
}); |
|||
})(); |
|||
@ -1,60 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) |
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ |
|||
|
|||
/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ |
|||
|
|||
/* All levels of nav */ |
|||
nav[data-toggle='toc'] .nav > li > a { |
|||
display: block; |
|||
padding: 4px 20px; |
|||
font-size: 13px; |
|||
font-weight: 500; |
|||
color: #767676; |
|||
} |
|||
nav[data-toggle='toc'] .nav > li > a:hover, |
|||
nav[data-toggle='toc'] .nav > li > a:focus { |
|||
padding-left: 19px; |
|||
color: #563d7c; |
|||
text-decoration: none; |
|||
background-color: transparent; |
|||
border-left: 1px solid #563d7c; |
|||
} |
|||
nav[data-toggle='toc'] .nav > .active > a, |
|||
nav[data-toggle='toc'] .nav > .active:hover > a, |
|||
nav[data-toggle='toc'] .nav > .active:focus > a { |
|||
padding-left: 18px; |
|||
font-weight: bold; |
|||
color: #563d7c; |
|||
background-color: transparent; |
|||
border-left: 2px solid #563d7c; |
|||
} |
|||
|
|||
/* Nav: second level (shown on .active) */ |
|||
nav[data-toggle='toc'] .nav .nav { |
|||
display: none; /* Hide by default, but at >768px, show it */ |
|||
padding-bottom: 10px; |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > li > a { |
|||
padding-top: 1px; |
|||
padding-bottom: 1px; |
|||
padding-left: 30px; |
|||
font-size: 12px; |
|||
font-weight: normal; |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > li > a:hover, |
|||
nav[data-toggle='toc'] .nav .nav > li > a:focus { |
|||
padding-left: 29px; |
|||
} |
|||
nav[data-toggle='toc'] .nav .nav > .active > a, |
|||
nav[data-toggle='toc'] .nav .nav > .active:hover > a, |
|||
nav[data-toggle='toc'] .nav .nav > .active:focus > a { |
|||
padding-left: 28px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ |
|||
nav[data-toggle='toc'] .nav > .active > ul { |
|||
display: block; |
|||
} |
|||
@ -1,159 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
(function() { |
|||
'use strict'; |
|||
|
|||
window.Toc = { |
|||
helpers: { |
|||
// return all matching elements in the set, or their descendants
|
|||
findOrFilter: function($el, selector) { |
|||
// http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
|
|||
// http://stackoverflow.com/a/12731439/358804
|
|||
var $descendants = $el.find(selector); |
|||
return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); |
|||
}, |
|||
|
|||
generateUniqueIdBase: function(el) { |
|||
var text = $(el).text(); |
|||
var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); |
|||
return anchor || el.tagName.toLowerCase(); |
|||
}, |
|||
|
|||
generateUniqueId: function(el) { |
|||
var anchorBase = this.generateUniqueIdBase(el); |
|||
for (var i = 0; ; i++) { |
|||
var anchor = anchorBase; |
|||
if (i > 0) { |
|||
// add suffix
|
|||
anchor += '-' + i; |
|||
} |
|||
// check if ID already exists
|
|||
if (!document.getElementById(anchor)) { |
|||
return anchor; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
generateAnchor: function(el) { |
|||
if (el.id) { |
|||
return el.id; |
|||
} else { |
|||
var anchor = this.generateUniqueId(el); |
|||
el.id = anchor; |
|||
return anchor; |
|||
} |
|||
}, |
|||
|
|||
createNavList: function() { |
|||
return $('<ul class="nav"></ul>'); |
|||
}, |
|||
|
|||
createChildNavList: function($parent) { |
|||
var $childList = this.createNavList(); |
|||
$parent.append($childList); |
|||
return $childList; |
|||
}, |
|||
|
|||
generateNavEl: function(anchor, text) { |
|||
var $a = $('<a></a>'); |
|||
$a.attr('href', '#' + anchor); |
|||
$a.text(text); |
|||
var $li = $('<li></li>'); |
|||
$li.append($a); |
|||
return $li; |
|||
}, |
|||
|
|||
generateNavItem: function(headingEl) { |
|||
var anchor = this.generateAnchor(headingEl); |
|||
var $heading = $(headingEl); |
|||
var text = $heading.data('toc-text') || $heading.text(); |
|||
return this.generateNavEl(anchor, text); |
|||
}, |
|||
|
|||
// Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
|
|||
getTopLevel: function($scope) { |
|||
for (var i = 1; i <= 6; i++) { |
|||
var $headings = this.findOrFilter($scope, 'h' + i); |
|||
if ($headings.length > 1) { |
|||
return i; |
|||
} |
|||
} |
|||
|
|||
return 1; |
|||
}, |
|||
|
|||
// returns the elements for the top level, and the next below it
|
|||
getHeadings: function($scope, topLevel) { |
|||
var topSelector = 'h' + topLevel; |
|||
|
|||
var secondaryLevel = topLevel + 1; |
|||
var secondarySelector = 'h' + secondaryLevel; |
|||
|
|||
return this.findOrFilter($scope, topSelector + ',' + secondarySelector); |
|||
}, |
|||
|
|||
getNavLevel: function(el) { |
|||
return parseInt(el.tagName.charAt(1), 10); |
|||
}, |
|||
|
|||
populateNav: function($topContext, topLevel, $headings) { |
|||
var $context = $topContext; |
|||
var $prevNav; |
|||
|
|||
var helpers = this; |
|||
$headings.each(function(i, el) { |
|||
var $newNav = helpers.generateNavItem(el); |
|||
var navLevel = helpers.getNavLevel(el); |
|||
|
|||
// determine the proper $context
|
|||
if (navLevel === topLevel) { |
|||
// use top level
|
|||
$context = $topContext; |
|||
} else if ($prevNav && $context === $topContext) { |
|||
// create a new level of the tree and switch to it
|
|||
$context = helpers.createChildNavList($prevNav); |
|||
} // else use the current $context
|
|||
|
|||
$context.append($newNav); |
|||
|
|||
$prevNav = $newNav; |
|||
}); |
|||
}, |
|||
|
|||
parseOps: function(arg) { |
|||
var opts; |
|||
if (arg.jquery) { |
|||
opts = { |
|||
$nav: arg |
|||
}; |
|||
} else { |
|||
opts = arg; |
|||
} |
|||
opts.$scope = opts.$scope || $(document.body); |
|||
return opts; |
|||
} |
|||
}, |
|||
|
|||
// accepts a jQuery object, or an options object
|
|||
init: function(opts) { |
|||
opts = this.helpers.parseOps(opts); |
|||
|
|||
// ensure that the data attribute is in place for styling
|
|||
opts.$nav.attr('data-toggle', 'toc'); |
|||
|
|||
var $topContext = this.helpers.createChildNavList(opts.$nav); |
|||
var topLevel = this.helpers.getTopLevel(opts.$scope); |
|||
var $headings = this.helpers.getHeadings(opts.$scope, topLevel); |
|||
this.helpers.populateNav($topContext, topLevel, $headings); |
|||
} |
|||
}; |
|||
|
|||
$(function() { |
|||
$('nav[data-toggle="toc"]').each(function(i, el) { |
|||
var $nav = $(el); |
|||
Toc.init($nav); |
|||
}); |
|||
}); |
|||
})(); |
|||
@ -1,4 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) |
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */nav[data-toggle=toc] .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}nav[data-toggle=toc] .nav>li>a:focus,nav[data-toggle=toc] .nav>li>a:hover{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}nav[data-toggle=toc] .nav>.active:focus>a,nav[data-toggle=toc] .nav>.active:hover>a,nav[data-toggle=toc] .nav>.active>a{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}nav[data-toggle=toc] .nav .nav{display:none;padding-bottom:10px}nav[data-toggle=toc] .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}nav[data-toggle=toc] .nav .nav>li>a:focus,nav[data-toggle=toc] .nav .nav>li>a:hover{padding-left:29px}nav[data-toggle=toc] .nav .nav>.active:focus>a,nav[data-toggle=toc] .nav .nav>.active:hover>a,nav[data-toggle=toc] .nav .nav>.active>a{padding-left:28px;font-weight:500}nav[data-toggle=toc] .nav>.active>ul{display:block} |
|||
@ -1,5 +0,0 @@ |
|||
/*! |
|||
* Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
|
|||
* Copyright 2015 Aidan Feldman |
|||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
|||
!function(){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var r=e.find(t);return e.filter(t).add(r).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){var t=$(e).text(),r=t.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g,"-");return r||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),r=0;;r++){var n=t;if(r>0&&(n+="-"+r),!document.getElementById(n))return n}},generateAnchor:function(e){if(e.id)return e.id;var t=this.generateUniqueId(e);return e.id=t,t},createNavList:function(){return $('<ul class="nav"></ul>')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var r=$("<a></a>");r.attr("href","#"+e),r.text(t);var n=$("<li></li>");return n.append(r),n},generateNavItem:function(e){var t=this.generateAnchor(e),r=$(e),n=r.data("toc-text")||r.text();return this.generateNavEl(t,n)},getTopLevel:function(e){for(var t=1;t<=6;t++){var r=this.findOrFilter(e,"h"+t);if(r.length>1)return t}return 1},getHeadings:function(e,t){var r="h"+t,n=t+1,a="h"+n;return this.findOrFilter(e,r+","+a)},getNavLevel:function(e){return parseInt(e.tagName.charAt(1),10)},populateNav:function(e,t,r){var n,a=e,i=this;r.each(function(r,o){var s=i.generateNavItem(o),u=i.getNavLevel(o);u===t?a=e:n&&a===e&&(a=i.createChildNavList(n)),a.append(s),n=s})},parseOps:function(e){var t;return t=e.jquery?{$nav:e}:e,t.$scope=t.$scope||$(document.body),t}},init:function(e){e=this.helpers.parseOps(e),e.$nav.attr("data-toggle","toc");var t=this.helpers.createChildNavList(e.$nav),r=this.helpers.getTopLevel(e.$scope),n=this.helpers.getHeadings(e.$scope,r);this.helpers.populateNav(t,r,n)}},$(function(){$('nav[data-toggle="toc"]').each(function(e,t){var r=$(t);Toc.init(r)})})}(); |
|||
@ -1,58 +0,0 @@ |
|||
var gulp = require('gulp'); |
|||
var del = require('del'); |
|||
var template = require('gulp-template'); |
|||
var minifyCss = require('gulp-minify-css'); |
|||
var rename = require('gulp-rename'); |
|||
var uglify = require('gulp-uglify'); |
|||
var jshint = require('gulp-jshint'); |
|||
var mochaPhantomJS = require('gulp-mocha-phantomjs'); |
|||
var pkg = require('./package.json'); |
|||
|
|||
gulp.task('clean', function () { |
|||
return del(['dist/*']); |
|||
}); |
|||
|
|||
gulp.task('build-css', ['clean'], function() { |
|||
return gulp.src('bootstrap-toc.css') |
|||
.pipe(template(pkg)) |
|||
.pipe(gulp.dest('dist')) |
|||
.pipe(minifyCss({compatibility: 'ie8'})) |
|||
.pipe(rename({ |
|||
extname: '.min.css' |
|||
})) |
|||
.pipe(gulp.dest('dist')); |
|||
}); |
|||
|
|||
gulp.task('build-js', ['clean'], function() { |
|||
return gulp.src('bootstrap-toc.js') |
|||
.pipe(template(pkg)) |
|||
.pipe(gulp.dest('dist')) |
|||
.pipe(uglify({ |
|||
preserveComments: 'license' |
|||
})) |
|||
.pipe(rename({ |
|||
extname: '.min.js' |
|||
})) |
|||
.pipe(gulp.dest('dist')); |
|||
}); |
|||
|
|||
gulp.task('js-lint', function () { |
|||
return gulp.src('bootstrap-toc.js') |
|||
.pipe(jshint()) |
|||
.pipe(jshint.reporter('default')) |
|||
.pipe(jshint.reporter('fail')); |
|||
}); |
|||
|
|||
gulp.task('test', function () { |
|||
return gulp.src('test/index.html') |
|||
.pipe(mochaPhantomJS()); |
|||
}); |
|||
|
|||
gulp.task('watch', function() { |
|||
gulp.watch('bootstrap-toc.js', ['js-lint', 'test']); |
|||
gulp.watch('test/*', ['test']); |
|||
}); |
|||
|
|||
gulp.task('build', ['build-css', 'build-js']); |
|||
|
|||
gulp.task('default', ['build', 'js-lint', 'test']); |
|||
@ -1,183 +0,0 @@ |
|||
--- |
|||
layout: default |
|||
permalink: / |
|||
--- |
|||
|
|||
# Table of Contents plugin for Bootstrap |
|||
{: .page-header} |
|||
|
|||
[](https://travis-ci.org/afeld/bootstrap-toc) |
|||
|
|||
This [Bootstrap](http://getbootstrap.com/) plugin allows you to generate a table of contents for any page, based on the heading elements (`<h1>`, `<h2>`, etc.). It is meant to emulate the sidebar you see on [the Bootstrap documentation site](http://getbootstrap.com/css/). |
|||
|
|||
This page is an example of the plugin in action – the table of contents you see on the left (or top, on mobile) was automatically generated, without having to manually keep all of the navigation items in sync with the headings. |
|||
|
|||
## Usage |
|||
|
|||
On top of the normal Bootstrap setup (see their [Getting Started](http://getbootstrap.com/getting-started/) guide), you will need to include the Bootstrap Table of Contents stylesheet and JavaScript file. |
|||
|
|||
```html |
|||
<!-- add after bootstrap.min.css --> |
|||
<link rel="stylesheet" href="https://cdn.rawgit.com/afeld/bootstrap-toc/v0.4.1/dist/bootstrap-toc.min.css"> |
|||
<!-- add after bootstrap.min.js --> |
|||
<script src="https://cdn.rawgit.com/afeld/bootstrap-toc/v0.4.1/dist/bootstrap-toc.min.js"></script> |
|||
``` |
|||
|
|||
[Unminified versions](https://github.com/afeld/bootstrap-toc/tree/gh-pages/dist) are also available. |
|||
|
|||
Next, pick one of the two options below. |
|||
|
|||
### Via data attributes |
|||
|
|||
*Simplest.* |
|||
|
|||
Create a `<nav>` element with a `data-toggle="toc"` attribute. |
|||
|
|||
```html |
|||
<nav id="toc" data-toggle="toc"></nav> |
|||
``` |
|||
|
|||
You can put this wherever on the page you like. Since this plugin leverages Bootstrap's [Scrollspy](http://getbootstrap.com/javascript/#scrollspy) plugin, you will also need to add a couple attributes to the `<body>`: |
|||
|
|||
```html |
|||
<body data-spy="scroll" data-target="#toc"> |
|||
``` |
|||
|
|||
### Via JavaScript |
|||
|
|||
*If you need customization.* |
|||
|
|||
If you prefer to create your navigation element another way (e.g. within single-page apps), you can pass a jQuery object into `Toc.init()`. |
|||
|
|||
```html |
|||
<nav id="toc"></nav> |
|||
``` |
|||
|
|||
```javascript |
|||
$(function() { |
|||
var navSelector = '#toc'; |
|||
var $myNav = $(navSelector); |
|||
Toc.init($myNav); |
|||
$('body').scrollspy({ |
|||
target: navSelector |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
See the [Scrollspy](http://getbootstrap.com/javascript/#scrollspy) documentation for more information about initializing that plugin. |
|||
|
|||
#### Options |
|||
|
|||
When calling `Toc.init()`, you can either pass in the jQuery object for the `<nav>` element (as seen above), or an options object: |
|||
|
|||
```javascript |
|||
Toc.init({ |
|||
$nav: $('#myNav'), |
|||
// ... |
|||
}); |
|||
``` |
|||
|
|||
All options are optional, unless otherwise indicated. |
|||
|
|||
option | type | notes |
|||
--- | --- | --- |
|||
`$nav` | jQuery Object | (required) The element that the navigation will be created in. |
|||
`$scope` | jQuery Object | The element where the search for headings will be limited to, or the list of headings that will be used in the navigation. Defaults to `$(document.body)`. |
|||
{: .table } |
|||
|
|||
## Customization |
|||
|
|||
The following options can be specified at the heading level via `data-toc-*` attributes. |
|||
|
|||
### Displayed text |
|||
|
|||
By default, Bootstrap TOC will use the text from the heading element in the table of contents. If you want to customize what is displayed, add a `data-toc-text` attribute with the desired text. For example: |
|||
|
|||
```html |
|||
<h2 data-toc-text="Short text">Longer text</h2> |
|||
``` |
|||
|
|||
displays "Longer text" as the heading, but "Short text" in the sidebar. |
|||
|
|||
### Skipping |
|||
|
|||
To prevent a particular heading from being added to the table of contents, add a `data-toc-skip` [boolean attribute](https://www.w3.org/TR/2008/WD-html5-20080610/semantics.html#boolean). |
|||
|
|||
```html |
|||
<h2 data-toc-skip>Some heading you don't want in the nav</h2> |
|||
``` |
|||
|
|||
## Layout |
|||
|
|||
This plugin isn't opinionated about where it should be placed on the page, but a common use case is to have the table of contents created as a "sticky" sidebar. We will leverage the [Affix](http://getbootstrap.com/javascript/#affix) plugin for this, and wrap the `<nav>` element in a `<div>` with a Bootstrap column class (see information about the [Grid](http://getbootstrap.com/css/#grid)). As an example putting it all together (similar to this page): |
|||
|
|||
```html |
|||
<body data-spy="scroll" data-target="#toc"> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<!-- sidebar, which will move to the top on a small screen --> |
|||
<div class="col-sm-3"> |
|||
<nav id="toc" data-spy="affix" data-toggle="toc"></nav> |
|||
</div> |
|||
<!-- main content area --> |
|||
<div class="col-sm-9"> |
|||
... |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</body> |
|||
``` |
|||
|
|||
You may also want to include this in your stylesheet: |
|||
|
|||
```css |
|||
nav[data-toggle='toc'] { |
|||
margin-top: 30px; |
|||
} |
|||
|
|||
/* small screens */ |
|||
@media (max-width: 768px) { |
|||
/* override the Affix plugin so that the navigation isn't sticky */ |
|||
nav.affix[data-toggle='toc'] { |
|||
position: static; |
|||
} |
|||
|
|||
/* PICK ONE */ |
|||
/* don't expand nested items, which pushes down the rest of the page when navigating */ |
|||
nav[data-toggle='toc'] .nav .active .nav { |
|||
display: none; |
|||
} |
|||
/* alternatively, if you *do* want the second-level navigation to be shown (as seen on this page on mobile), use this */ |
|||
nav[data-toggle='toc'] .nav .nav { |
|||
display: block; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## See also |
|||
|
|||
This plugin was heavily inspired by: |
|||
|
|||
* [Bootstrap Docs Sidebar example](https://jsfiddle.net/gableroux/S2SMK/) |
|||
* [Tocify plugin](http://gregfranko.com/jquery.tocify.js/) |
|||
* [TOC plugin](http://projects.jga.me/toc/) |
|||
|
|||
## Contributing |
|||
|
|||
Questions, feature suggestions, and bug reports/fixes welcome! |
|||
|
|||
### Manual testing |
|||
|
|||
1. Run `bundle`. |
|||
1. Run `bundle exec jekyll serve`. |
|||
1. Open the various test templates: |
|||
* [H2's](http://localhost:4000/bootstrap-toc/test/templates/h2s.html) |
|||
* [Markdown](http://localhost:4000/bootstrap-toc/test/templates/markdown.html) |
|||
* [No IDs](http://localhost:4000/bootstrap-toc/test/templates/no-ids.html) |
|||
|
|||
### Automated testing |
|||
|
|||
1. Run `npm install`. |
|||
1. Run `gulp test`/`gulp watch` (command-line), or `open test/index.html` (browser). |
|||
|
|||
You can find the tests in [`test/toc-test.js`](test/toc-test.js). |
|||
@ -1,22 +0,0 @@ |
|||
{ |
|||
"name": "bootstrap-toc", |
|||
"version": "0.4.1", |
|||
"private": true, |
|||
"scripts": { |
|||
"test": "gulp test" |
|||
}, |
|||
"dependencies": { |
|||
"del": "^2.1.0", |
|||
"expect.js": "^0.3.1", |
|||
"gulp": "^3.9.0", |
|||
"gulp-jshint": "^2.0.0", |
|||
"gulp-minify-css": "^1.2.1", |
|||
"gulp-mocha-phantomjs": "^0.10.1", |
|||
"gulp-rename": "^1.2.2", |
|||
"gulp-template": "^3.1.0", |
|||
"gulp-uglify": "^1.5.1", |
|||
"jquery": "^2.1.4", |
|||
"jshint": "^2.9.1-rc1", |
|||
"mocha": "^2.3.4" |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<title>Mocha Tests</title> |
|||
<link href="../node_modules/mocha/mocha.css" rel="stylesheet" /> |
|||
</head> |
|||
<body> |
|||
<div id="mocha"></div> |
|||
<div id="mocha-fixture">foo</div> |
|||
|
|||
<script src="../node_modules/jquery/dist/jquery.min.js"></script> |
|||
<script src="../node_modules/expect.js/index.js"></script> |
|||
<script src="../node_modules/mocha/mocha.js"></script> |
|||
|
|||
<script>mocha.setup('bdd')</script> |
|||
<script src="../bootstrap-toc.js"></script> |
|||
<script src="toc-test.js"></script> |
|||
<script> |
|||
mocha.checkLeaks(); |
|||
mocha.globals(['jQuery']); |
|||
mocha.run(); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,17 +0,0 @@ |
|||
--- |
|||
layout: test |
|||
--- |
|||
|
|||
# H1 |
|||
|
|||
## H2 |
|||
|
|||
### H3 |
|||
|
|||
#### H4 |
|||
|
|||
## H2 |
|||
|
|||
### H3 |
|||
|
|||
## H2 |
|||
@ -1,21 +0,0 @@ |
|||
--- |
|||
layout: test |
|||
--- |
|||
|
|||
# H1 |
|||
|
|||
## H2 |
|||
|
|||
### H3 |
|||
|
|||
#### H4 |
|||
|
|||
## H2 |
|||
|
|||
### H3 |
|||
|
|||
# H1 |
|||
|
|||
## H2 |
|||
|
|||
# H1 |
|||
@ -1,12 +0,0 @@ |
|||
--- |
|||
layout: test |
|||
--- |
|||
|
|||
<h1>H1</h1> |
|||
<h2>H2</h2> |
|||
<h3>H3</h3> |
|||
<h4>H4</h4> |
|||
<h2>H2</h2> |
|||
<h3>H3</h3> |
|||
<h1>H1</h1> |
|||
<h2>H2</h2> |
|||
@ -1,210 +0,0 @@ |
|||
var $fixture = $('#mocha-fixture'); |
|||
|
|||
afterEach(function() { |
|||
$fixture.empty(); |
|||
}); |
|||
|
|||
describe('Toc', function() { |
|||
describe('.helpers', function() { |
|||
describe('.generateNavItem()', function() { |
|||
it("uses text within the element by default", function() { |
|||
var heading = $('<h1>foo</h1>')[0]; |
|||
var $navItem = Toc.helpers.generateNavItem(heading); |
|||
expect($navItem.text()).to.eql('foo'); |
|||
}); |
|||
|
|||
it("uses text specified as a data-toc-text attribute", function() { |
|||
var heading = $('<h1 data-toc-text="foo">bar</h1>')[0]; |
|||
var $navItem = Toc.helpers.generateNavItem(heading); |
|||
expect($navItem.text()).to.eql('foo'); |
|||
}); |
|||
|
|||
it("keeps the text from within the element escaped", function() { |
|||
var heading = document.createElement('h1'); |
|||
heading.innerText = '<script>foo</script>'; |
|||
var navItem = Toc.helpers.generateNavItem(heading)[0]; |
|||
expect(navItem.textContent).to.eql('<script>foo</script>'); |
|||
}); |
|||
|
|||
it("keeps the data-toc-text escaped", function() { |
|||
var heading = document.createElement('h1'); |
|||
heading.setAttribute('data-toc-text', '<script>foo</script>') |
|||
heading.innerText = 'bar'; |
|||
var $navItem = Toc.helpers.generateNavItem(heading); |
|||
expect($navItem.text()).to.eql('<script>foo</script>'); |
|||
}); |
|||
}); |
|||
|
|||
describe('.generateUniqueIdBase()', function() { |
|||
it("uses the text from the element", function() { |
|||
var el = document.createElement('h1'); |
|||
el.innerHTML = "Some tExt- with aidan's /. stuff " |
|||
var base = Toc.helpers.generateUniqueIdBase(el); |
|||
expect(base).to.eql('some-text-with-aidan-s-stuff'); |
|||
}); |
|||
|
|||
it("uses the tag name of the element if there's no text", function() { |
|||
var el = document.createElement('h1'); |
|||
var base = Toc.helpers.generateUniqueIdBase(el); |
|||
expect(base).to.eql('h1'); |
|||
}); |
|||
}); |
|||
|
|||
describe('.generateUniqueId()', function() { |
|||
it("uses the tag name", function() { |
|||
var el = document.createElement('h1'); |
|||
var base = Toc.helpers.generateUniqueId(el); |
|||
expect(base).to.eql('h1'); |
|||
}); |
|||
|
|||
it("adds a suffix when there's an existing element with that tag", function() { |
|||
$fixture.append('<h1 id="h1"></h1>'); |
|||
|
|||
var el = document.createElement('h1'); |
|||
var base = Toc.helpers.generateUniqueId(el); |
|||
expect(base).to.eql('h1-1'); |
|||
}); |
|||
}); |
|||
|
|||
describe('.getTopLevel()', function() { |
|||
it("returns 1 by default", function() { |
|||
var $scope = $('<div></div>'); |
|||
var level = Toc.helpers.getTopLevel($scope); |
|||
expect(level).to.eql(1); |
|||
}); |
|||
|
|||
it("returns the first level with more than one element", function() { |
|||
var $scope = $( |
|||
'<div>' + |
|||
'<h1></h1>' + |
|||
'<h2></h2>' + |
|||
'<h3></h3>' + |
|||
'<h4></h4>' + |
|||
'<h5></h5>' + |
|||
'<h6></h6>' + |
|||
'<h6></h6>' + |
|||
'</div>' |
|||
); |
|||
var level = Toc.helpers.getTopLevel($scope); |
|||
expect(level).to.eql(6); |
|||
}); |
|||
}); |
|||
|
|||
describe('.getNavLevel()', function() { |
|||
it("returns the value from the tag", function() { |
|||
var el = document.createElement('h5'); |
|||
var level = Toc.helpers.getNavLevel(el); |
|||
expect(level).to.eql(5); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
describe('.init()', function() { |
|||
var $nav; |
|||
beforeEach(function() { |
|||
$nav = $('<nav>'); |
|||
$fixture.append($nav); |
|||
}); |
|||
|
|||
it("handles single-level headings", function() { |
|||
$fixture.append( |
|||
'<h1>H1</h1>' + |
|||
'<h1>H1</h1>' + |
|||
'<h1>H1</h1>' |
|||
); |
|||
|
|||
Toc.init({ |
|||
$nav: $nav, |
|||
$scope: $fixture |
|||
}); |
|||
|
|||
expect($nav.html()).to.eql( |
|||
'<ul class="nav">' + |
|||
'<li>' + |
|||
'<a href="#h1">H1</a>' + |
|||
'</li>' + |
|||
'<li>' + |
|||
'<a href="#h1-1">H1</a>' + |
|||
'</li>' + |
|||
'<li>' + |
|||
'<a href="#h1-2">H1</a>' + |
|||
'</li>' + |
|||
'</ul>' |
|||
); |
|||
}); |
|||
|
|||
it("ignores headings with a data-toc-skip attribute", function() { |
|||
$fixture.append( |
|||
'<h1>H1</h1>' + |
|||
'<h1 data-toc-skip>H1</h1>' + |
|||
'<h1>H1</h1>' |
|||
); |
|||
|
|||
Toc.init({ |
|||
$nav: $nav, |
|||
$scope: $fixture |
|||
}); |
|||
|
|||
expect($nav.html()).to.eql( |
|||
'<ul class="nav">' + |
|||
'<li>' + |
|||
'<a href="#h1">H1</a>' + |
|||
'</li>' + |
|||
'<li>' + |
|||
'<a href="#h1-1">H1</a>' + |
|||
'</li>' + |
|||
'</ul>' |
|||
); |
|||
}); |
|||
|
|||
it("handles nested headings", function() { |
|||
$fixture.append( |
|||
'<h1>H1</h1>' + |
|||
'<h2>H2</h2>' + |
|||
'<h3>H3</h3>' + |
|||
'<h4>H4</h4>' + |
|||
'<h2>H2-1</h2>' |
|||
); |
|||
|
|||
Toc.init({ |
|||
$nav: $nav, |
|||
$scope: $fixture |
|||
}); |
|||
|
|||
expect($nav.html()).to.eql( |
|||
'<ul class="nav">' + |
|||
'<li>' + |
|||
'<a href="#h2">H2</a>' + |
|||
'<ul class="nav">' + |
|||
'<li>' + |
|||
'<a href="#h3">H3</a>' + |
|||
'</li>' + |
|||
'</ul>' + |
|||
'</li>' + |
|||
'<li>' + |
|||
'<a href="#h2-1">H2-1</a>' + |
|||
'</li>' + |
|||
'</ul>' |
|||
); |
|||
}); |
|||
|
|||
it("accepts a list of headings as the $scope", function() { |
|||
var $h1 = $('<h1>H1</h1>'); |
|||
var $h2 = $('<h2>H2</h2>'); |
|||
$fixture.append($h1, $h2); |
|||
|
|||
Toc.init({ |
|||
$nav: $nav, |
|||
$scope: $h1 |
|||
}); |
|||
|
|||
expect($nav.html()).to.eql( |
|||
'<ul class="nav">' + |
|||
'<li>' + |
|||
'<a href="#h1">H1</a>' + |
|||
'</li>' + |
|||
'</ul>' |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,33 +0,0 @@ |
|||
{ |
|||
"name": "clipboard", |
|||
"version": "1.7.1", |
|||
"description": "Modern copy to clipboard. No Flash. Just 2kb", |
|||
"license": "MIT", |
|||
"main": "dist/clipboard.js", |
|||
"ignore": [ |
|||
"/.*/", |
|||
"/demo/", |
|||
"/test/", |
|||
"/.*", |
|||
"/bower.json", |
|||
"/karma.conf.js", |
|||
"/src", |
|||
"/lib" |
|||
], |
|||
"keywords": [ |
|||
"clipboard", |
|||
"copy", |
|||
"cut" |
|||
], |
|||
"homepage": "https://github.com/zenorocha/clipboard.js", |
|||
"_release": "1.7.1", |
|||
"_resolution": { |
|||
"type": "version", |
|||
"tag": "v1.7.1", |
|||
"commit": "b6e6b80ab07eab03ce0d277515b3ed540773a330" |
|||
}, |
|||
"_source": "https://github.com/zenorocha/clipboard.js.git", |
|||
"_target": "^1.7.1", |
|||
"_originalSource": "clipboard", |
|||
"_direct": true |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
{ |
|||
"name": "clipboard", |
|||
"version": "1.7.1", |
|||
"description": "Modern copy to clipboard. No Flash. Just 2kb", |
|||
"license": "MIT", |
|||
"main": "dist/clipboard.js", |
|||
"ignore": [ |
|||
"/.*/", |
|||
"/demo/", |
|||
"/test/", |
|||
"/.*", |
|||
"/bower.json", |
|||
"/karma.conf.js", |
|||
"/src", |
|||
"/lib" |
|||
], |
|||
"keywords": [ |
|||
"clipboard", |
|||
"copy", |
|||
"cut" |
|||
] |
|||
} |
|||
@ -1,25 +0,0 @@ |
|||
{ |
|||
"name": "zenorocha/clipboardjs", |
|||
"description": "Modern copy to clipboard. No Flash. Just 3kb gzipped https://clipboardjs.com", |
|||
"type": "component", |
|||
"homepage": "https://clipboardjs.com/", |
|||
"authors": [ |
|||
{ |
|||
"name": "Zeno Rocha", |
|||
"url": "http://zenorocha.com/" |
|||
} |
|||
], |
|||
"require": { |
|||
"robloach/component-installer": "*" |
|||
}, |
|||
"extra": { |
|||
"component": { |
|||
"scripts": [ |
|||
"dist/clipboard.js" |
|||
], |
|||
"files": [ |
|||
"dist/clipboard.min.js" |
|||
] |
|||
} |
|||
} |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
# Contributing guide |
|||
|
|||
Want to contribute to Clipboard.js? Awesome! |
|||
There are many ways you can contribute, see below. |
|||
|
|||
## Opening issues |
|||
|
|||
Open an issue to report bugs or to propose new features. |
|||
|
|||
- Reporting bugs: describe the bug as clearly as you can, including steps to reproduce, what happened and what you were expecting to happen. Also include browser version, OS and other related software's (npm, Node.js, etc) versions when applicable. |
|||
|
|||
- Proposing features: explain the proposed feature, what it should do, why it is useful, how users should use it. Give us as much info as possible so it will be easier to discuss, access and implement the proposed feature. When you're unsure about a certain aspect of the feature, feel free to leave it open for others to discuss and find an appropriate solution. |
|||
|
|||
## Proposing pull requests |
|||
|
|||
Pull requests are very welcome. Note that if you are going to propose drastic changes, be sure to open an issue for discussion first, to make sure that your PR will be accepted before you spend effort coding it. |
|||
|
|||
Fork the Clipboard.js repository, clone it locally and create a branch for your proposed bug fix or new feature. Avoid working directly on the master branch. |
|||
|
|||
Implement your bug fix or feature, write tests to cover it and make sure all tests are passing (run a final `npm test` to make sure everything is correct). Then commit your changes, push your bug fix/feature branch to the origin (your forked repo) and open a pull request to the upstream (the repository you originally forked)'s master branch. |
|||
|
|||
## Documentation |
|||
|
|||
Documentation is extremely important and takes a fair deal of time and effort to write and keep updated. Please submit any and all improvements you can make to the repository's docs. |
|||
|
|||
## Known issues |
|||
If you're using npm@3 you'll probably face some issues related to peerDependencies. |
|||
https://github.com/npm/npm/issues/9204 |
|||
@ -1,939 +0,0 @@ |
|||
/*! |
|||
* clipboard.js v2.0.1 |
|||
* https://zenorocha.github.io/clipboard.js
|
|||
* |
|||
* Licensed MIT © Zeno Rocha |
|||
*/ |
|||
(function webpackUniversalModuleDefinition(root, factory) { |
|||
if(typeof exports === 'object' && typeof module === 'object') |
|||
module.exports = factory(); |
|||
else if(typeof define === 'function' && define.amd) |
|||
define([], factory); |
|||
else if(typeof exports === 'object') |
|||
exports["ClipboardJS"] = factory(); |
|||
else |
|||
root["ClipboardJS"] = factory(); |
|||
})(this, function() { |
|||
return /******/ (function(modules) { // webpackBootstrap
|
|||
/******/ // The module cache
|
|||
/******/ var installedModules = {}; |
|||
/******/ |
|||
/******/ // The require function
|
|||
/******/ function __webpack_require__(moduleId) { |
|||
/******/ |
|||
/******/ // Check if module is in cache
|
|||
/******/ if(installedModules[moduleId]) { |
|||
/******/ return installedModules[moduleId].exports; |
|||
/******/ } |
|||
/******/ // Create a new module (and put it into the cache)
|
|||
/******/ var module = installedModules[moduleId] = { |
|||
/******/ i: moduleId, |
|||
/******/ l: false, |
|||
/******/ exports: {} |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Execute the module function
|
|||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
|||
/******/ |
|||
/******/ // Flag the module as loaded
|
|||
/******/ module.l = true; |
|||
/******/ |
|||
/******/ // Return the exports of the module
|
|||
/******/ return module.exports; |
|||
/******/ } |
|||
/******/ |
|||
/******/ |
|||
/******/ // expose the modules object (__webpack_modules__)
|
|||
/******/ __webpack_require__.m = modules; |
|||
/******/ |
|||
/******/ // expose the module cache
|
|||
/******/ __webpack_require__.c = installedModules; |
|||
/******/ |
|||
/******/ // identity function for calling harmony imports with the correct context
|
|||
/******/ __webpack_require__.i = function(value) { return value; }; |
|||
/******/ |
|||
/******/ // define getter function for harmony exports
|
|||
/******/ __webpack_require__.d = function(exports, name, getter) { |
|||
/******/ if(!__webpack_require__.o(exports, name)) { |
|||
/******/ Object.defineProperty(exports, name, { |
|||
/******/ configurable: false, |
|||
/******/ enumerable: true, |
|||
/******/ get: getter |
|||
/******/ }); |
|||
/******/ } |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|||
/******/ __webpack_require__.n = function(module) { |
|||
/******/ var getter = module && module.__esModule ? |
|||
/******/ function getDefault() { return module['default']; } : |
|||
/******/ function getModuleExports() { return module; }; |
|||
/******/ __webpack_require__.d(getter, 'a', getter); |
|||
/******/ return getter; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Object.prototype.hasOwnProperty.call
|
|||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
|||
/******/ |
|||
/******/ // __webpack_public_path__
|
|||
/******/ __webpack_require__.p = ""; |
|||
/******/ |
|||
/******/ // Load entry module and return exports
|
|||
/******/ return __webpack_require__(__webpack_require__.s = 3); |
|||
/******/ }) |
|||
/************************************************************************/ |
|||
/******/ ([ |
|||
/* 0 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { |
|||
if (true) { |
|||
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [module, __webpack_require__(7)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? |
|||
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); |
|||
} else if (typeof exports !== "undefined") { |
|||
factory(module, require('select')); |
|||
} else { |
|||
var mod = { |
|||
exports: {} |
|||
}; |
|||
factory(mod, global.select); |
|||
global.clipboardAction = mod.exports; |
|||
} |
|||
})(this, function (module, _select) { |
|||
'use strict'; |
|||
|
|||
var _select2 = _interopRequireDefault(_select); |
|||
|
|||
function _interopRequireDefault(obj) { |
|||
return obj && obj.__esModule ? obj : { |
|||
default: obj |
|||
}; |
|||
} |
|||
|
|||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { |
|||
return typeof obj; |
|||
} : function (obj) { |
|||
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; |
|||
}; |
|||
|
|||
function _classCallCheck(instance, Constructor) { |
|||
if (!(instance instanceof Constructor)) { |
|||
throw new TypeError("Cannot call a class as a function"); |
|||
} |
|||
} |
|||
|
|||
var _createClass = function () { |
|||
function defineProperties(target, props) { |
|||
for (var i = 0; i < props.length; i++) { |
|||
var descriptor = props[i]; |
|||
descriptor.enumerable = descriptor.enumerable || false; |
|||
descriptor.configurable = true; |
|||
if ("value" in descriptor) descriptor.writable = true; |
|||
Object.defineProperty(target, descriptor.key, descriptor); |
|||
} |
|||
} |
|||
|
|||
return function (Constructor, protoProps, staticProps) { |
|||
if (protoProps) defineProperties(Constructor.prototype, protoProps); |
|||
if (staticProps) defineProperties(Constructor, staticProps); |
|||
return Constructor; |
|||
}; |
|||
}(); |
|||
|
|||
var ClipboardAction = function () { |
|||
/** |
|||
* @param {Object} options |
|||
*/ |
|||
function ClipboardAction(options) { |
|||
_classCallCheck(this, ClipboardAction); |
|||
|
|||
this.resolveOptions(options); |
|||
this.initSelection(); |
|||
} |
|||
|
|||
/** |
|||
* Defines base properties passed from constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
_createClass(ClipboardAction, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = options.action; |
|||
this.container = options.container; |
|||
this.emitter = options.emitter; |
|||
this.target = options.target; |
|||
this.text = options.text; |
|||
this.trigger = options.trigger; |
|||
|
|||
this.selectedText = ''; |
|||
} |
|||
}, { |
|||
key: 'initSelection', |
|||
value: function initSelection() { |
|||
if (this.text) { |
|||
this.selectFake(); |
|||
} else if (this.target) { |
|||
this.selectTarget(); |
|||
} |
|||
} |
|||
}, { |
|||
key: 'selectFake', |
|||
value: function selectFake() { |
|||
var _this = this; |
|||
|
|||
var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; |
|||
|
|||
this.removeFake(); |
|||
|
|||
this.fakeHandlerCallback = function () { |
|||
return _this.removeFake(); |
|||
}; |
|||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; |
|||
|
|||
this.fakeElem = document.createElement('textarea'); |
|||
// Prevent zooming on iOS
|
|||
this.fakeElem.style.fontSize = '12pt'; |
|||
// Reset box model
|
|||
this.fakeElem.style.border = '0'; |
|||
this.fakeElem.style.padding = '0'; |
|||
this.fakeElem.style.margin = '0'; |
|||
// Move element out of screen horizontally
|
|||
this.fakeElem.style.position = 'absolute'; |
|||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; |
|||
// Move element to the same position vertically
|
|||
var yPosition = window.pageYOffset || document.documentElement.scrollTop; |
|||
this.fakeElem.style.top = yPosition + 'px'; |
|||
|
|||
this.fakeElem.setAttribute('readonly', ''); |
|||
this.fakeElem.value = this.text; |
|||
|
|||
this.container.appendChild(this.fakeElem); |
|||
|
|||
this.selectedText = (0, _select2.default)(this.fakeElem); |
|||
this.copyText(); |
|||
} |
|||
}, { |
|||
key: 'removeFake', |
|||
value: function removeFake() { |
|||
if (this.fakeHandler) { |
|||
this.container.removeEventListener('click', this.fakeHandlerCallback); |
|||
this.fakeHandler = null; |
|||
this.fakeHandlerCallback = null; |
|||
} |
|||
|
|||
if (this.fakeElem) { |
|||
this.container.removeChild(this.fakeElem); |
|||
this.fakeElem = null; |
|||
} |
|||
} |
|||
}, { |
|||
key: 'selectTarget', |
|||
value: function selectTarget() { |
|||
this.selectedText = (0, _select2.default)(this.target); |
|||
this.copyText(); |
|||
} |
|||
}, { |
|||
key: 'copyText', |
|||
value: function copyText() { |
|||
var succeeded = void 0; |
|||
|
|||
try { |
|||
succeeded = document.execCommand(this.action); |
|||
} catch (err) { |
|||
succeeded = false; |
|||
} |
|||
|
|||
this.handleResult(succeeded); |
|||
} |
|||
}, { |
|||
key: 'handleResult', |
|||
value: function handleResult(succeeded) { |
|||
this.emitter.emit(succeeded ? 'success' : 'error', { |
|||
action: this.action, |
|||
text: this.selectedText, |
|||
trigger: this.trigger, |
|||
clearSelection: this.clearSelection.bind(this) |
|||
}); |
|||
} |
|||
}, { |
|||
key: 'clearSelection', |
|||
value: function clearSelection() { |
|||
if (this.trigger) { |
|||
this.trigger.focus(); |
|||
} |
|||
|
|||
window.getSelection().removeAllRanges(); |
|||
} |
|||
}, { |
|||
key: 'destroy', |
|||
value: function destroy() { |
|||
this.removeFake(); |
|||
} |
|||
}, { |
|||
key: 'action', |
|||
set: function set() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; |
|||
|
|||
this._action = action; |
|||
|
|||
if (this._action !== 'copy' && this._action !== 'cut') { |
|||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); |
|||
} |
|||
}, |
|||
get: function get() { |
|||
return this._action; |
|||
} |
|||
}, { |
|||
key: 'target', |
|||
set: function set(target) { |
|||
if (target !== undefined) { |
|||
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { |
|||
if (this.action === 'copy' && target.hasAttribute('disabled')) { |
|||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); |
|||
} |
|||
|
|||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { |
|||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); |
|||
} |
|||
|
|||
this._target = target; |
|||
} else { |
|||
throw new Error('Invalid "target" value, use a valid Element'); |
|||
} |
|||
} |
|||
}, |
|||
get: function get() { |
|||
return this._target; |
|||
} |
|||
}]); |
|||
|
|||
return ClipboardAction; |
|||
}(); |
|||
|
|||
module.exports = ClipboardAction; |
|||
}); |
|||
|
|||
/***/ }), |
|||
/* 1 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var is = __webpack_require__(6); |
|||
var delegate = __webpack_require__(5); |
|||
|
|||
/** |
|||
* Validates all params and calls the right |
|||
* listener function based on its target type. |
|||
* |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} target |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listen(target, type, callback) { |
|||
if (!target && !type && !callback) { |
|||
throw new Error('Missing required arguments'); |
|||
} |
|||
|
|||
if (!is.string(type)) { |
|||
throw new TypeError('Second argument must be a String'); |
|||
} |
|||
|
|||
if (!is.fn(callback)) { |
|||
throw new TypeError('Third argument must be a Function'); |
|||
} |
|||
|
|||
if (is.node(target)) { |
|||
return listenNode(target, type, callback); |
|||
} |
|||
else if (is.nodeList(target)) { |
|||
return listenNodeList(target, type, callback); |
|||
} |
|||
else if (is.string(target)) { |
|||
return listenSelector(target, type, callback); |
|||
} |
|||
else { |
|||
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Adds an event listener to a HTML element |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {HTMLElement} node |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNode(node, type, callback) { |
|||
node.addEventListener(type, callback); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
node.removeEventListener(type, callback); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a list of HTML elements |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {NodeList|HTMLCollection} nodeList |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNodeList(nodeList, type, callback) { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.addEventListener(type, callback); |
|||
}); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.removeEventListener(type, callback); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a selector |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenSelector(selector, type, callback) { |
|||
return delegate(document.body, selector, type, callback); |
|||
} |
|||
|
|||
module.exports = listen; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 2 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function E () { |
|||
// Keep this empty so it's easier to inherit from
|
|||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
|||
} |
|||
|
|||
E.prototype = { |
|||
on: function (name, callback, ctx) { |
|||
var e = this.e || (this.e = {}); |
|||
|
|||
(e[name] || (e[name] = [])).push({ |
|||
fn: callback, |
|||
ctx: ctx |
|||
}); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
once: function (name, callback, ctx) { |
|||
var self = this; |
|||
function listener () { |
|||
self.off(name, listener); |
|||
callback.apply(ctx, arguments); |
|||
}; |
|||
|
|||
listener._ = callback |
|||
return this.on(name, listener, ctx); |
|||
}, |
|||
|
|||
emit: function (name) { |
|||
var data = [].slice.call(arguments, 1); |
|||
var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); |
|||
var i = 0; |
|||
var len = evtArr.length; |
|||
|
|||
for (i; i < len; i++) { |
|||
evtArr[i].fn.apply(evtArr[i].ctx, data); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
off: function (name, callback) { |
|||
var e = this.e || (this.e = {}); |
|||
var evts = e[name]; |
|||
var liveEvents = []; |
|||
|
|||
if (evts && callback) { |
|||
for (var i = 0, len = evts.length; i < len; i++) { |
|||
if (evts[i].fn !== callback && evts[i].fn._ !== callback) |
|||
liveEvents.push(evts[i]); |
|||
} |
|||
} |
|||
|
|||
// Remove event from queue to prevent memory leak
|
|||
// Suggested by https://github.com/lazd
|
|||
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
|
|||
|
|||
(liveEvents.length) |
|||
? e[name] = liveEvents |
|||
: delete e[name]; |
|||
|
|||
return this; |
|||
} |
|||
}; |
|||
|
|||
module.exports = E; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 3 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { |
|||
if (true) { |
|||
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [module, __webpack_require__(0), __webpack_require__(2), __webpack_require__(1)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? |
|||
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); |
|||
} else if (typeof exports !== "undefined") { |
|||
factory(module, require('./clipboard-action'), require('tiny-emitter'), require('good-listener')); |
|||
} else { |
|||
var mod = { |
|||
exports: {} |
|||
}; |
|||
factory(mod, global.clipboardAction, global.tinyEmitter, global.goodListener); |
|||
global.clipboard = mod.exports; |
|||
} |
|||
})(this, function (module, _clipboardAction, _tinyEmitter, _goodListener) { |
|||
'use strict'; |
|||
|
|||
var _clipboardAction2 = _interopRequireDefault(_clipboardAction); |
|||
|
|||
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter); |
|||
|
|||
var _goodListener2 = _interopRequireDefault(_goodListener); |
|||
|
|||
function _interopRequireDefault(obj) { |
|||
return obj && obj.__esModule ? obj : { |
|||
default: obj |
|||
}; |
|||
} |
|||
|
|||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { |
|||
return typeof obj; |
|||
} : function (obj) { |
|||
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; |
|||
}; |
|||
|
|||
function _classCallCheck(instance, Constructor) { |
|||
if (!(instance instanceof Constructor)) { |
|||
throw new TypeError("Cannot call a class as a function"); |
|||
} |
|||
} |
|||
|
|||
var _createClass = function () { |
|||
function defineProperties(target, props) { |
|||
for (var i = 0; i < props.length; i++) { |
|||
var descriptor = props[i]; |
|||
descriptor.enumerable = descriptor.enumerable || false; |
|||
descriptor.configurable = true; |
|||
if ("value" in descriptor) descriptor.writable = true; |
|||
Object.defineProperty(target, descriptor.key, descriptor); |
|||
} |
|||
} |
|||
|
|||
return function (Constructor, protoProps, staticProps) { |
|||
if (protoProps) defineProperties(Constructor.prototype, protoProps); |
|||
if (staticProps) defineProperties(Constructor, staticProps); |
|||
return Constructor; |
|||
}; |
|||
}(); |
|||
|
|||
function _possibleConstructorReturn(self, call) { |
|||
if (!self) { |
|||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); |
|||
} |
|||
|
|||
return call && (typeof call === "object" || typeof call === "function") ? call : self; |
|||
} |
|||
|
|||
function _inherits(subClass, superClass) { |
|||
if (typeof superClass !== "function" && superClass !== null) { |
|||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); |
|||
} |
|||
|
|||
subClass.prototype = Object.create(superClass && superClass.prototype, { |
|||
constructor: { |
|||
value: subClass, |
|||
enumerable: false, |
|||
writable: true, |
|||
configurable: true |
|||
} |
|||
}); |
|||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; |
|||
} |
|||
|
|||
var Clipboard = function (_Emitter) { |
|||
_inherits(Clipboard, _Emitter); |
|||
|
|||
/** |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger |
|||
* @param {Object} options |
|||
*/ |
|||
function Clipboard(trigger, options) { |
|||
_classCallCheck(this, Clipboard); |
|||
|
|||
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); |
|||
|
|||
_this.resolveOptions(options); |
|||
_this.listenClick(trigger); |
|||
return _this; |
|||
} |
|||
|
|||
/** |
|||
* Defines if attributes would be resolved using internal setter functions |
|||
* or custom functions that were passed in the constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
_createClass(Clipboard, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = typeof options.action === 'function' ? options.action : this.defaultAction; |
|||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; |
|||
this.text = typeof options.text === 'function' ? options.text : this.defaultText; |
|||
this.container = _typeof(options.container) === 'object' ? options.container : document.body; |
|||
} |
|||
}, { |
|||
key: 'listenClick', |
|||
value: function listenClick(trigger) { |
|||
var _this2 = this; |
|||
|
|||
this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) { |
|||
return _this2.onClick(e); |
|||
}); |
|||
} |
|||
}, { |
|||
key: 'onClick', |
|||
value: function onClick(e) { |
|||
var trigger = e.delegateTarget || e.currentTarget; |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction = null; |
|||
} |
|||
|
|||
this.clipboardAction = new _clipboardAction2.default({ |
|||
action: this.action(trigger), |
|||
target: this.target(trigger), |
|||
text: this.text(trigger), |
|||
container: this.container, |
|||
trigger: trigger, |
|||
emitter: this |
|||
}); |
|||
} |
|||
}, { |
|||
key: 'defaultAction', |
|||
value: function defaultAction(trigger) { |
|||
return getAttributeValue('action', trigger); |
|||
} |
|||
}, { |
|||
key: 'defaultTarget', |
|||
value: function defaultTarget(trigger) { |
|||
var selector = getAttributeValue('target', trigger); |
|||
|
|||
if (selector) { |
|||
return document.querySelector(selector); |
|||
} |
|||
} |
|||
}, { |
|||
key: 'defaultText', |
|||
value: function defaultText(trigger) { |
|||
return getAttributeValue('text', trigger); |
|||
} |
|||
}, { |
|||
key: 'destroy', |
|||
value: function destroy() { |
|||
this.listener.destroy(); |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction.destroy(); |
|||
this.clipboardAction = null; |
|||
} |
|||
} |
|||
}], [{ |
|||
key: 'isSupported', |
|||
value: function isSupported() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; |
|||
|
|||
var actions = typeof action === 'string' ? [action] : action; |
|||
var support = !!document.queryCommandSupported; |
|||
|
|||
actions.forEach(function (action) { |
|||
support = support && !!document.queryCommandSupported(action); |
|||
}); |
|||
|
|||
return support; |
|||
} |
|||
}]); |
|||
|
|||
return Clipboard; |
|||
}(_tinyEmitter2.default); |
|||
|
|||
/** |
|||
* Helper function to retrieve attribute value. |
|||
* @param {String} suffix |
|||
* @param {Element} element |
|||
*/ |
|||
function getAttributeValue(suffix, element) { |
|||
var attribute = 'data-clipboard-' + suffix; |
|||
|
|||
if (!element.hasAttribute(attribute)) { |
|||
return; |
|||
} |
|||
|
|||
return element.getAttribute(attribute); |
|||
} |
|||
|
|||
module.exports = Clipboard; |
|||
}); |
|||
|
|||
/***/ }), |
|||
/* 4 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
var DOCUMENT_NODE_TYPE = 9; |
|||
|
|||
/** |
|||
* A polyfill for Element.matches() |
|||
*/ |
|||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { |
|||
var proto = Element.prototype; |
|||
|
|||
proto.matches = proto.matchesSelector || |
|||
proto.mozMatchesSelector || |
|||
proto.msMatchesSelector || |
|||
proto.oMatchesSelector || |
|||
proto.webkitMatchesSelector; |
|||
} |
|||
|
|||
/** |
|||
* Finds the closest parent that matches a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @return {Function} |
|||
*/ |
|||
function closest (element, selector) { |
|||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { |
|||
if (typeof element.matches === 'function' && |
|||
element.matches(selector)) { |
|||
return element; |
|||
} |
|||
element = element.parentNode; |
|||
} |
|||
} |
|||
|
|||
module.exports = closest; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 5 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var closest = __webpack_require__(4); |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function _delegate(element, selector, type, callback, useCapture) { |
|||
var listenerFn = listener.apply(this, arguments); |
|||
|
|||
element.addEventListener(type, listenerFn, useCapture); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
element.removeEventListener(type, listenerFn, useCapture); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element|String|Array} [elements] |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function delegate(elements, selector, type, callback, useCapture) { |
|||
// Handle the regular Element usage
|
|||
if (typeof elements.addEventListener === 'function') { |
|||
return _delegate.apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Element-less usage, it defaults to global delegation
|
|||
if (typeof type === 'function') { |
|||
// Use `document` as the first parameter, then apply arguments
|
|||
// This is a short way to .unshift `arguments` without running into deoptimizations
|
|||
return _delegate.bind(null, document).apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Selector-based usage
|
|||
if (typeof elements === 'string') { |
|||
elements = document.querySelectorAll(elements); |
|||
} |
|||
|
|||
// Handle Array-like based usage
|
|||
return Array.prototype.map.call(elements, function (element) { |
|||
return _delegate(element, selector, type, callback, useCapture); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Finds closest match and invokes callback. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Function} |
|||
*/ |
|||
function listener(element, selector, type, callback) { |
|||
return function(e) { |
|||
e.delegateTarget = closest(e.target, selector); |
|||
|
|||
if (e.delegateTarget) { |
|||
callback.call(element, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = delegate; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 6 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
/** |
|||
* Check if argument is a HTML element. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.node = function(value) { |
|||
return value !== undefined |
|||
&& value instanceof HTMLElement |
|||
&& value.nodeType === 1; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a list of HTML elements. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.nodeList = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return value !== undefined |
|||
&& (type === '[object NodeList]' || type === '[object HTMLCollection]') |
|||
&& ('length' in value) |
|||
&& (value.length === 0 || exports.node(value[0])); |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a string. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.string = function(value) { |
|||
return typeof value === 'string' |
|||
|| value instanceof String; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a function. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.fn = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return type === '[object Function]'; |
|||
}; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 7 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function select(element) { |
|||
var selectedText; |
|||
|
|||
if (element.nodeName === 'SELECT') { |
|||
element.focus(); |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { |
|||
var isReadOnly = element.hasAttribute('readonly'); |
|||
|
|||
if (!isReadOnly) { |
|||
element.setAttribute('readonly', ''); |
|||
} |
|||
|
|||
element.select(); |
|||
element.setSelectionRange(0, element.value.length); |
|||
|
|||
if (!isReadOnly) { |
|||
element.removeAttribute('readonly'); |
|||
} |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else { |
|||
if (element.hasAttribute('contenteditable')) { |
|||
element.focus(); |
|||
} |
|||
|
|||
var selection = window.getSelection(); |
|||
var range = document.createRange(); |
|||
|
|||
range.selectNodeContents(element); |
|||
selection.removeAllRanges(); |
|||
selection.addRange(range); |
|||
|
|||
selectedText = selection.toString(); |
|||
} |
|||
|
|||
return selectedText; |
|||
} |
|||
|
|||
module.exports = select; |
|||
|
|||
|
|||
/***/ }) |
|||
/******/ ]); |
|||
}); |
|||
@ -1,12 +0,0 @@ |
|||
// Package metadata for Meteor.js.
|
|||
|
|||
Package.describe({ |
|||
name: "zenorocha:clipboard", |
|||
summary: "Modern copy to clipboard. No Flash. Just 3kb.", |
|||
version: "2.0.0", |
|||
git: "https://github.com/zenorocha/clipboard.js" |
|||
}); |
|||
|
|||
Package.onUse(function(api) { |
|||
api.addFiles("dist/clipboard.js", "client"); |
|||
}); |
|||
@ -1,78 +0,0 @@ |
|||
{ |
|||
"_from": "clipboard@^2.0.0", |
|||
"_id": "clipboard@2.0.1", |
|||
"_inBundle": false, |
|||
"_integrity": "sha512-7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==", |
|||
"_location": "/clipboard", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"type": "range", |
|||
"registry": true, |
|||
"raw": "clipboard@^2.0.0", |
|||
"name": "clipboard", |
|||
"escapedName": "clipboard", |
|||
"rawSpec": "^2.0.0", |
|||
"saveSpec": null, |
|||
"fetchSpec": "^2.0.0" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/prismjs" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.1.tgz", |
|||
"_shasum": "a12481e1c13d8a50f5f036b0560fe5d16d74e46a", |
|||
"_spec": "clipboard@^2.0.0", |
|||
"_where": "C:\\Users\\alper\\Downloads\\node_modules\\prismjs", |
|||
"bugs": { |
|||
"url": "https://github.com/zenorocha/clipboard.js/issues" |
|||
}, |
|||
"bundleDependencies": false, |
|||
"dependencies": { |
|||
"good-listener": "^1.2.2", |
|||
"select": "^1.1.2", |
|||
"tiny-emitter": "^2.0.0" |
|||
}, |
|||
"deprecated": false, |
|||
"description": "Modern copy to clipboard. No Flash. Just 2kb", |
|||
"devDependencies": { |
|||
"babel-cli": "^6.5.1", |
|||
"babel-core": "^6.5.2", |
|||
"babel-loader": "^6.2.10", |
|||
"babel-plugin-transform-es2015-modules-umd": "^6.5.0", |
|||
"babel-preset-es2015": "^6.5.0", |
|||
"chai": "^3.4.1", |
|||
"cross-env": "^3.1.4", |
|||
"karma": "^1.3.0", |
|||
"karma-chai": "^0.1.0", |
|||
"karma-mocha": "^1.2.0", |
|||
"karma-phantomjs-launcher": "^1.0.0", |
|||
"karma-sinon": "^1.0.4", |
|||
"karma-webpack": "^2.0.2", |
|||
"mocha": "^3.1.2", |
|||
"phantomjs-prebuilt": "^2.1.4", |
|||
"sinon": "^1.17.2", |
|||
"webpack": "^2.2.1" |
|||
}, |
|||
"homepage": "https://github.com/zenorocha/clipboard.js#readme", |
|||
"keywords": [ |
|||
"clipboard", |
|||
"copy", |
|||
"cut" |
|||
], |
|||
"license": "MIT", |
|||
"main": "dist/clipboard.js", |
|||
"module": "dist/clipboard.js", |
|||
"name": "clipboard", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/zenorocha/clipboard.js.git" |
|||
}, |
|||
"scripts": { |
|||
"build": "npm run build-debug && npm run build-min", |
|||
"build-debug": "webpack", |
|||
"build-min": "cross-env NODE_ENV=production webpack --optimize-minimize", |
|||
"build-watch": "webpack --watch", |
|||
"prepublish": "npm run build", |
|||
"test": "karma start --single-run" |
|||
}, |
|||
"version": "2.0.1" |
|||
} |
|||
@ -1,189 +0,0 @@ |
|||
# clipboard.js |
|||
|
|||
[](https://travis-ci.org/zenorocha/clipboard.js) |
|||
 |
|||
|
|||
> Modern copy to clipboard. No Flash. Just 3kb gzipped. |
|||
|
|||
<a href="https://clipboardjs.com/"><img width="728" src="https://cloud.githubusercontent.com/assets/398893/16165747/a0f6fc46-349a-11e6-8c9b-c5fd58d9099c.png" alt="Demo"></a> |
|||
|
|||
## Why |
|||
|
|||
Copying text to the clipboard shouldn't be hard. It shouldn't require dozens of steps to configure or hundreds of KBs to load. But most of all, it shouldn't depend on Flash or any bloated framework. |
|||
|
|||
That's why clipboard.js exists. |
|||
|
|||
## Install |
|||
|
|||
You can get it on npm. |
|||
|
|||
``` |
|||
npm install clipboard --save |
|||
``` |
|||
|
|||
Or if you're not into package management, just [download a ZIP](https://github.com/zenorocha/clipboard.js/archive/master.zip) file. |
|||
|
|||
## Setup |
|||
|
|||
First, include the script located on the `dist` folder or load it from [a third-party CDN provider](https://github.com/zenorocha/clipboard.js/wiki/CDN-Providers). |
|||
|
|||
```html |
|||
<script src="dist/clipboard.min.js"></script> |
|||
``` |
|||
|
|||
Now, you need to instantiate it by [passing a DOM selector](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-selector.html#L18), [HTML element](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-node.html#L16-L17), or [list of HTML elements](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-nodelist.html#L18-L19). |
|||
|
|||
```js |
|||
new ClipboardJS('.btn'); |
|||
``` |
|||
|
|||
Internally, we need to fetch all elements that matches with your selector and attach event listeners for each one. But guess what? If you have hundreds of matches, this operation can consume a lot of memory. |
|||
|
|||
For this reason we use [event delegation](http://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) which replaces multiple event listeners with just a single listener. After all, [#perfmatters](https://twitter.com/hashtag/perfmatters). |
|||
|
|||
# Usage |
|||
|
|||
We're living a _declarative renaissance_, that's why we decided to take advantage of [HTML5 data attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes) for better usability. |
|||
|
|||
### Copy text from another element |
|||
|
|||
A pretty common use case is to copy content from another element. You can do that by adding a `data-clipboard-target` attribute in your trigger element. |
|||
|
|||
The value you include on this attribute needs to match another's element selector. |
|||
|
|||
<a href="https://clipboardjs.com/#example-target"><img width="473" alt="example-2" src="https://cloud.githubusercontent.com/assets/398893/9983467/a4946aaa-5fb1-11e5-9780-f09fcd7ca6c8.png"></a> |
|||
|
|||
```html |
|||
<!-- Target --> |
|||
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git"> |
|||
|
|||
<!-- Trigger --> |
|||
<button class="btn" data-clipboard-target="#foo"> |
|||
<img src="assets/clippy.svg" alt="Copy to clipboard"> |
|||
</button> |
|||
``` |
|||
|
|||
### Cut text from another element |
|||
|
|||
Additionally, you can define a `data-clipboard-action` attribute to specify if you want to either `copy` or `cut` content. |
|||
|
|||
If you omit this attribute, `copy` will be used by default. |
|||
|
|||
<a href="https://clipboardjs.com/#example-action"><img width="473" alt="example-3" src="https://cloud.githubusercontent.com/assets/398893/10000358/7df57b9c-6050-11e5-9cd1-fbc51d2fd0a7.png"></a> |
|||
|
|||
```html |
|||
<!-- Target --> |
|||
<textarea id="bar">Mussum ipsum cacilds...</textarea> |
|||
|
|||
<!-- Trigger --> |
|||
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar"> |
|||
Cut to clipboard |
|||
</button> |
|||
``` |
|||
|
|||
As you may expect, the `cut` action only works on `<input>` or `<textarea>` elements. |
|||
|
|||
### Copy text from attribute |
|||
|
|||
Truth is, you don't even need another element to copy its content from. You can just include a `data-clipboard-text` attribute in your trigger element. |
|||
|
|||
<a href="https://clipboardjs.com/#example-text"><img width="147" alt="example-1" src="https://cloud.githubusercontent.com/assets/398893/10000347/6e16cf8c-6050-11e5-9883-1c5681f9ec45.png"></a> |
|||
|
|||
```html |
|||
<!-- Trigger --> |
|||
<button class="btn" data-clipboard-text="Just because you can doesn't mean you should — clipboard.js"> |
|||
Copy to clipboard |
|||
</button> |
|||
``` |
|||
|
|||
## Events |
|||
|
|||
There are cases where you'd like to show some user feedback or capture what has been selected after a copy/cut operation. |
|||
|
|||
That's why we fire custom events such as `success` and `error` for you to listen and implement your custom logic. |
|||
|
|||
```js |
|||
var clipboard = new ClipboardJS('.btn'); |
|||
|
|||
clipboard.on('success', function(e) { |
|||
console.info('Action:', e.action); |
|||
console.info('Text:', e.text); |
|||
console.info('Trigger:', e.trigger); |
|||
|
|||
e.clearSelection(); |
|||
}); |
|||
|
|||
clipboard.on('error', function(e) { |
|||
console.error('Action:', e.action); |
|||
console.error('Trigger:', e.trigger); |
|||
}); |
|||
``` |
|||
|
|||
For a live demonstration, go to this [site](https://clipboardjs.com/) and open your console. |
|||
|
|||
## Tooltips |
|||
|
|||
Each application has different design needs, that's why clipboard.js does not include any CSS or built-in tooltip solution. |
|||
|
|||
The tooltips you see on the [demo site](https://clipboardjs.com/) were built using [GitHub's Primer](https://github.com/primer/primer-css/tree/master/modules/primer-tooltips). You may want to check that out if you're looking for a similar look and feel. |
|||
|
|||
## Advanced Options |
|||
|
|||
If you don't want to modify your HTML, there's a pretty handy imperative API for you to use. All you need to do is declare a function, do your thing, and return a value. |
|||
|
|||
For instance, if you want to dynamically set a `target`, you'll need to return a Node. |
|||
|
|||
```js |
|||
new ClipboardJS('.btn', { |
|||
target: function(trigger) { |
|||
return trigger.nextElementSibling; |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
If you want to dynamically set a `text`, you'll return a String. |
|||
|
|||
```js |
|||
new ClipboardJS('.btn', { |
|||
text: function(trigger) { |
|||
return trigger.getAttribute('aria-label'); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
For use in Bootstrap Modals or with any other library that changes the focus you'll want to set the focused element as the `container` value. |
|||
|
|||
```js |
|||
new ClipboardJS('.btn', { |
|||
container: document.getElementById('modal') |
|||
}); |
|||
``` |
|||
|
|||
Also, if you are working with single page apps, you may want to manage the lifecycle of the DOM more precisely. Here's how you clean up the events and objects that we create. |
|||
|
|||
```js |
|||
var clipboard = new ClipboardJS('.btn'); |
|||
clipboard.destroy(); |
|||
``` |
|||
|
|||
## Browser Support |
|||
|
|||
This library relies on both [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) and [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) APIs. The first one is [supported by all browsers](http://caniuse.com/#search=selection) while the second one is supported in the following browsers. |
|||
|
|||
| <img src="https://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="https://clipboardjs.com/assets/images/edge.png" width="48px" height="48px" alt="Edge logo"> | <img src="https://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="https://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="https://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="https://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> | |
|||
|:---:|:---:|:---:|:---:|:---:|:---:| |
|||
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ | |
|||
|
|||
The good news is that clipboard.js gracefully degrades if you need to support older browsers. All you have to do is show a tooltip saying `Copied!` when `success` event is called and `Press Ctrl+C to copy` when `error` event is called because the text is already selected. |
|||
|
|||
You can also check if clipboard.js is supported or not by running `ClipboardJS.isSupported()`, that way you can hide copy/cut buttons from the UI. |
|||
|
|||
## Bonus |
|||
|
|||
A browser extension that adds a "copy to clipboard" button to every code block on *GitHub, MDN, Gist, StackOverflow, StackExchange, npm, and even Medium.* |
|||
|
|||
Install for [Chrome](https://chrome.google.com/webstore/detail/codecopy/fkbfebkcoelajmhanocgppanfoojcdmg) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/codecopy/). |
|||
|
|||
## License |
|||
|
|||
[MIT License](http://zenorocha.mit-license.org/) © Zeno Rocha |
|||
@ -1,41 +0,0 @@ |
|||
const pkg = require('./package.json'); |
|||
const path = require('path'); |
|||
const webpack = require('webpack'); |
|||
|
|||
const production = process.env.NODE_ENV === 'production' || false; |
|||
|
|||
const banner = `clipboard.js v${pkg.version} |
|||
https://zenorocha.github.io/clipboard.js
|
|||
|
|||
Licensed MIT © Zeno Rocha`;
|
|||
|
|||
module.exports = { |
|||
entry: './src/clipboard.js', |
|||
output: { |
|||
filename: production ? 'clipboard.min.js' : 'clipboard.js', |
|||
path: path.resolve(__dirname, 'dist'), |
|||
library: 'ClipboardJS', |
|||
libraryTarget: 'umd' |
|||
}, |
|||
module: { |
|||
rules: [ |
|||
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'} |
|||
] |
|||
}, |
|||
plugins: production ? [ |
|||
new webpack.optimize.UglifyJsPlugin({ |
|||
beautify: false, |
|||
mangle: { |
|||
screw_ie8: true, |
|||
keep_fnames: true |
|||
}, |
|||
compress: { |
|||
screw_ie8: true |
|||
}, |
|||
comments: false |
|||
}), |
|||
new webpack.BannerPlugin({banner}) |
|||
] : [ |
|||
new webpack.BannerPlugin({banner}) |
|||
] |
|||
}; |
|||
@ -1,22 +0,0 @@ |
|||
# EditorConfig helps developers define and maintain consistent |
|||
# coding styles between different editors and IDEs |
|||
# http://editorconfig.org |
|||
|
|||
root = true |
|||
|
|||
[*] |
|||
# Change these settings to your own preference |
|||
indent_style = space |
|||
indent_size = 4 |
|||
|
|||
# We recommend you to keep these unchanged |
|||
end_of_line = lf |
|||
charset = utf-8 |
|||
trim_trailing_whitespace = true |
|||
insert_final_newline = true |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
|
|||
[{package.json,bower.json}] |
|||
indent_size = 2 |
|||
@ -1,3 +0,0 @@ |
|||
language: node_js |
|||
node_js: |
|||
- stable |
|||
@ -1,29 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>Delegate</title> |
|||
</head> |
|||
<body> |
|||
<!-- 1. Write some markup --> |
|||
<ul> |
|||
<li><button>Item 1</button></li> |
|||
<li><button>Item 2</button></li> |
|||
<li><button>Item 3</button></li> |
|||
<li><button>Item 4</button></li> |
|||
<li><button>Item 5</button></li> |
|||
</ul> |
|||
|
|||
<!-- 2. Include library --> |
|||
<script src="../dist/delegate.js"></script> |
|||
|
|||
<!-- 3. Add event delegation --> |
|||
<script> |
|||
var ul = document.querySelector('ul'); |
|||
|
|||
delegate(ul, 'button', 'click', function(e) { |
|||
console.log(e.target); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,37 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>Delegate</title> |
|||
</head> |
|||
<body> |
|||
<!-- 1. Write some markup --> |
|||
<ul> |
|||
<li><button>Item 1</button></li> |
|||
<li><button>Item 2</button></li> |
|||
<li><button>Item 3</button></li> |
|||
<li><button>Item 4</button></li> |
|||
<li><button>Item 5</button></li> |
|||
</ul> |
|||
<ul> |
|||
<li><span>Item 6</span></li> |
|||
<li><span>Item 7</span></li> |
|||
</ul> |
|||
|
|||
<!-- 2. Include library --> |
|||
<script src="../dist/delegate.js"></script> |
|||
|
|||
<!-- 3. Add event delegation --> |
|||
<script> |
|||
var ul = document.querySelector('ul'); |
|||
|
|||
delegate(ul, 'button', 'click', function(e) { |
|||
console.log(e.target); |
|||
}); |
|||
|
|||
delegate(document.body, 'span', 'click', function(e) { |
|||
console.log(e.target); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,31 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>Undelegate</title> |
|||
</head> |
|||
<body> |
|||
<!-- 1. Write some markup --> |
|||
<ul> |
|||
<li><button>Item 1</button></li> |
|||
<li><button>Item 2</button></li> |
|||
<li><button>Item 3</button></li> |
|||
<li><button>Item 4</button></li> |
|||
<li><button>Item 5</button></li> |
|||
</ul> |
|||
|
|||
<!-- 2. Include library --> |
|||
<script src="../dist/delegate.js"></script> |
|||
|
|||
<!-- 3. Remove event delegation --> |
|||
<script> |
|||
var ul = document.querySelector('ul'); |
|||
|
|||
var delegation = delegate(ul, 'li button', 'click', function(e) { |
|||
console.log(e.target); |
|||
}); |
|||
|
|||
delegation.destroy(); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,80 +0,0 @@ |
|||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.delegate = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
|||
var DOCUMENT_NODE_TYPE = 9; |
|||
|
|||
/** |
|||
* A polyfill for Element.matches() |
|||
*/ |
|||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { |
|||
var proto = Element.prototype; |
|||
|
|||
proto.matches = proto.matchesSelector || |
|||
proto.mozMatchesSelector || |
|||
proto.msMatchesSelector || |
|||
proto.oMatchesSelector || |
|||
proto.webkitMatchesSelector; |
|||
} |
|||
|
|||
/** |
|||
* Finds the closest parent that matches a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @return {Function} |
|||
*/ |
|||
function closest (element, selector) { |
|||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { |
|||
if (element.matches(selector)) return element; |
|||
element = element.parentNode; |
|||
} |
|||
} |
|||
|
|||
module.exports = closest; |
|||
|
|||
},{}],2:[function(require,module,exports){ |
|||
var closest = require('./closest'); |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function delegate(element, selector, type, callback, useCapture) { |
|||
var listenerFn = listener.apply(this, arguments); |
|||
|
|||
element.addEventListener(type, listenerFn, useCapture); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
element.removeEventListener(type, listenerFn, useCapture); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Finds closest match and invokes callback. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Function} |
|||
*/ |
|||
function listener(element, selector, type, callback) { |
|||
return function(e) { |
|||
e.delegateTarget = closest(e.target, selector); |
|||
|
|||
if (e.delegateTarget) { |
|||
callback.call(element, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = delegate; |
|||
|
|||
},{"./closest":1}]},{},[2])(2) |
|||
}); |
|||
@ -1,24 +0,0 @@ |
|||
module.exports = function(karma) { |
|||
karma.set({ |
|||
plugins: ['karma-browserify', 'karma-chai', 'karma-sinon', 'karma-mocha', 'karma-phantomjs-launcher'], |
|||
|
|||
frameworks: ['browserify', 'chai', 'sinon', 'mocha'], |
|||
|
|||
files: [ |
|||
'src/**/*.js', |
|||
'test/**/*.js', |
|||
'./node_modules/phantomjs-polyfill/bind-polyfill.js' |
|||
], |
|||
|
|||
preprocessors: { |
|||
'src/**/*.js' : ['browserify'], |
|||
'test/**/*.js': ['browserify'] |
|||
}, |
|||
|
|||
browserify: { |
|||
debug: true |
|||
}, |
|||
|
|||
browsers: ['PhantomJS'] |
|||
}); |
|||
} |
|||
@ -1,63 +0,0 @@ |
|||
{ |
|||
"_from": "delegate@^3.1.2", |
|||
"_id": "delegate@3.2.0", |
|||
"_inBundle": false, |
|||
"_integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", |
|||
"_location": "/delegate", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"type": "range", |
|||
"registry": true, |
|||
"raw": "delegate@^3.1.2", |
|||
"name": "delegate", |
|||
"escapedName": "delegate", |
|||
"rawSpec": "^3.1.2", |
|||
"saveSpec": null, |
|||
"fetchSpec": "^3.1.2" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/good-listener" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", |
|||
"_shasum": "b66b71c3158522e8ab5744f720d8ca0c2af59166", |
|||
"_spec": "delegate@^3.1.2", |
|||
"_where": "C:\\Users\\alper\\Downloads\\node_modules\\good-listener", |
|||
"bugs": { |
|||
"url": "https://github.com/zenorocha/delegate/issues" |
|||
}, |
|||
"bundleDependencies": false, |
|||
"deprecated": false, |
|||
"description": "Lightweight event delegation", |
|||
"devDependencies": { |
|||
"browserify": "^13.1.0", |
|||
"chai": "^3.5.0", |
|||
"karma": "^1.3.0", |
|||
"karma-browserify": "^5.1.0", |
|||
"karma-chai": "^0.1.0", |
|||
"karma-mocha": "^1.2.0", |
|||
"karma-phantomjs-launcher": "^1.0.2", |
|||
"karma-sinon": "^1.0.4", |
|||
"mocha": "^3.1.2", |
|||
"phantomjs-polyfill": "0.0.2", |
|||
"simulant": "^0.2.2", |
|||
"sinon": "^1.17.6" |
|||
}, |
|||
"homepage": "https://github.com/zenorocha/delegate#readme", |
|||
"keywords": [ |
|||
"event", |
|||
"delegate", |
|||
"delegation" |
|||
], |
|||
"license": "MIT", |
|||
"main": "src/delegate.js", |
|||
"name": "delegate", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/zenorocha/delegate.git" |
|||
}, |
|||
"scripts": { |
|||
"build": "browserify src/delegate.js -s delegate -o dist/delegate.js", |
|||
"test": "karma start --single-run" |
|||
}, |
|||
"version": "3.2.0" |
|||
} |
|||
@ -1,99 +0,0 @@ |
|||
# delegate |
|||
|
|||
Lightweight event delegation. |
|||
|
|||
## Install |
|||
|
|||
You can get it on npm. |
|||
|
|||
``` |
|||
npm install delegate --save |
|||
``` |
|||
|
|||
If you're not into package management, just [download a ZIP](https://github.com/zenorocha/delegate/archive/master.zip) file. |
|||
|
|||
## Setup |
|||
|
|||
###### Node (Browserify) |
|||
|
|||
```js |
|||
var delegate = require('delegate'); |
|||
``` |
|||
|
|||
###### Browser (Standalone) |
|||
|
|||
```html |
|||
<script src="dist/delegate.js"></script> |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
### Add event delegation |
|||
|
|||
#### With the default base (`document`) |
|||
|
|||
```js |
|||
delegate('.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
``` |
|||
|
|||
#### With an element as base |
|||
|
|||
```js |
|||
delegate(document.body, '.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
``` |
|||
|
|||
#### With a selector (of existing elements) as base |
|||
|
|||
```js |
|||
delegate('.container', '.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
``` |
|||
|
|||
#### With an array/array-like of elements as base |
|||
|
|||
```js |
|||
delegate(document.querySelectorAll('.container'), '.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
``` |
|||
|
|||
### Remove event delegation |
|||
|
|||
#### With a single base element (default or specified) |
|||
|
|||
```js |
|||
var delegation = delegate(document.body, '.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
|
|||
delegation.destroy(); |
|||
``` |
|||
|
|||
#### With multiple elements (via selector or array) |
|||
|
|||
Note: selectors are always treated as multiple elements, even if one or none are matched. `delegate()` will return an array. |
|||
|
|||
```js |
|||
var delegations = delegate('.container', '.btn', 'click', function(e) { |
|||
console.log(e.delegateTarget); |
|||
}, false); |
|||
|
|||
delegations.forEach(function (delegation) { |
|||
delegation.destroy(); |
|||
}); |
|||
``` |
|||
|
|||
## Browser Support |
|||
|
|||
| <img src="https://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="https://clipboardjs.com/assets/images/edge.png" width="48px" height="48px" alt="Edge logo"> | <img src="https://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="https://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="https://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="https://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> | |
|||
|:---:|:---:|:---:|:---:|:---:|:---:| |
|||
| Latest ✔ | Latest ✔ | Latest ✔ | 9+ ✔ | Latest ✔ | Latest ✔ | |
|||
|
|||
## License |
|||
|
|||
[MIT License](http://zenorocha.mit-license.org/) © Zeno Rocha |
|||