diff --git a/.gitignore b/.gitignore index eb79dd5..c727bb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .idea +.DS_Store diff --git a/bs-config.js b/bs-config.js new file mode 100644 index 0000000..afa79eb --- /dev/null +++ b/bs-config.js @@ -0,0 +1,31 @@ + +/* + |-------------------------------------------------------------------------- + | Browser-sync config file + |-------------------------------------------------------------------------- + | + | For up-to-date information about the options: + | http://www.browsersync.io/docs/options/ + | + | There are more options than you see here, these are just the ones that are + | set internally. See the website for more info. + | + | + */ +module.exports = { + "ui": { + "port": 8080 + }, + "files": [ + "./js/*.js", + "./css/*.css" + ], + "startPath": "/test/index.html", + "server": true, + // "proxy": { + // target: "modalvideo.dev", + // ws: true + // }, + "port": 80, + "open": "external" +}; diff --git a/js/jquery-modal-video.js b/js/jquery-modal-video.js index 59568ad..2da84de 100644 --- a/js/jquery-modal-video.js +++ b/js/jquery-modal-video.js @@ -14,11 +14,10 @@ * homepage: https://github.com/krambuhl/custom-event-polyfill#readme * version: 0.3.0 * - * es6-object-assign: + * deepmerge: * license: MIT (http://opensource.org/licenses/MIT) - * author: Rubén Norte - * homepage: https://github.com/rubennorte/es6-object-assign - * version: 1.1.0 + * homepage: https://github.com/TehShrike/deepmerge + * version: 4.3.1 * * This header is generated by licensify (https://github.com/twada/licensify) */ @@ -69,53 +68,140 @@ try { } },{}],2:[function(require,module,exports){ -/** - * Code refactored from Mozilla Developer Network: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - */ - 'use strict'; -function assign(target, firstSource) { - if (target === undefined || target === null) { - throw new TypeError('Cannot convert first argument to object'); - } +var isMergeableObject = function isMergeableObject(value) { + return isNonNullObject(value) + && !isSpecial(value) +}; - var to = Object(target); - for (var i = 1; i < arguments.length; i++) { - var nextSource = arguments[i]; - if (nextSource === undefined || nextSource === null) { - continue; - } +function isNonNullObject(value) { + return !!value && typeof value === 'object' +} - var keysArray = Object.keys(Object(nextSource)); - for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { - var nextKey = keysArray[nextIndex]; - var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); - if (desc !== undefined && desc.enumerable) { - to[nextKey] = nextSource[nextKey]; - } - } - } - return to; +function isSpecial(value) { + var stringValue = Object.prototype.toString.call(value); + + return stringValue === '[object RegExp]' + || stringValue === '[object Date]' + || isReactElement(value) } -function polyfill() { - if (!Object.assign) { - Object.defineProperty(Object, 'assign', { - enumerable: false, - configurable: true, - writable: true, - value: assign - }); - } +// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 +var canUseSymbol = typeof Symbol === 'function' && Symbol.for; +var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7; + +function isReactElement(value) { + return value.$$typeof === REACT_ELEMENT_TYPE +} + +function emptyTarget(val) { + return Array.isArray(val) ? [] : {} +} + +function cloneUnlessOtherwiseSpecified(value, options) { + return (options.clone !== false && options.isMergeableObject(value)) + ? deepmerge(emptyTarget(value), value, options) + : value +} + +function defaultArrayMerge(target, source, options) { + return target.concat(source).map(function(element) { + return cloneUnlessOtherwiseSpecified(element, options) + }) +} + +function getMergeFunction(key, options) { + if (!options.customMerge) { + return deepmerge + } + var customMerge = options.customMerge(key); + return typeof customMerge === 'function' ? customMerge : deepmerge +} + +function getEnumerableOwnPropertySymbols(target) { + return Object.getOwnPropertySymbols + ? Object.getOwnPropertySymbols(target).filter(function(symbol) { + return Object.propertyIsEnumerable.call(target, symbol) + }) + : [] +} + +function getKeys(target) { + return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target)) +} + +function propertyIsOnObject(object, property) { + try { + return property in object + } catch(_) { + return false + } +} + +// Protects from prototype poisoning and unexpected merging up the prototype chain. +function propertyIsUnsafe(target, key) { + return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet, + && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain, + && Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable. +} + +function mergeObject(target, source, options) { + var destination = {}; + if (options.isMergeableObject(target)) { + getKeys(target).forEach(function(key) { + destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); + }); + } + getKeys(source).forEach(function(key) { + if (propertyIsUnsafe(target, key)) { + return + } + + if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) { + destination[key] = getMergeFunction(key, options)(target[key], source[key], options); + } else { + destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); + } + }); + return destination +} + +function deepmerge(target, source, options) { + options = options || {}; + options.arrayMerge = options.arrayMerge || defaultArrayMerge; + options.isMergeableObject = options.isMergeableObject || isMergeableObject; + // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge() + // implementations can use it. The caller may not replace it. + options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; + + var sourceIsArray = Array.isArray(source); + var targetIsArray = Array.isArray(target); + var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; + + if (!sourceAndTargetTypesMatch) { + return cloneUnlessOtherwiseSpecified(source, options) + } else if (sourceIsArray) { + return options.arrayMerge(target, source, options) + } else { + return mergeObject(target, source, options) + } } -module.exports = { - assign: assign, - polyfill: polyfill +deepmerge.all = function deepmergeAll(array, options) { + if (!Array.isArray(array)) { + throw new Error('first argument should be an array') + } + + return array.reduce(function(prev, next) { + return deepmerge(prev, next, options) + }, {}) }; +var deepmerge_1 = deepmerge; + +module.exports = deepmerge_1; + },{}],3:[function(require,module,exports){ 'use strict'; @@ -152,11 +238,17 @@ var _createClass = function () { function defineProperties(target, props) { for require('custom-event-polyfill'); +var _deepmerge = require('deepmerge'); + +var _deepmerge2 = _interopRequireDefault(_deepmerge); + var _util = require('../lib/util'); +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"); } } -var assign = require('es6-object-assign').assign; +// const assign = require('es6-object-assign').assign; var defaults = { channel: 'youtube', @@ -215,6 +307,9 @@ var defaults = { modalVideoIframeWrap: 'modal-video-movie-wrap', modalVideoCloseBtn: 'modal-video-close-btn' }, + handleClassName: { + modalVideoDismissBtn: 'js-modal-video-dismiss-btn' + }, aria: { openMessage: 'You just openned the modal video', dismissBtnMessage: 'Close the modal by clicking here' @@ -223,90 +318,92 @@ var defaults = { var ModalVideo = function () { function ModalVideo(ele, option) { - var _this = this; - _classCallCheck(this, ModalVideo); - var opt = assign({}, defaults, option); - var selectors = typeof ele === 'string' ? document.querySelectorAll(ele) : ele; - var body = document.querySelector('body'); - var classNames = opt.classNames; - var speed = opt.animationSpeed; - [].forEach.call(selectors, function (selector) { - selector.addEventListener('click', function (event) { - if (selector.tagName === 'A') { - event.preventDefault(); - } - var videoId = selector.dataset.videoId; - var channel = selector.dataset.channel || opt.channel; - var id = (0, _util.getUniqId)(); - var videoUrl = selector.dataset.videoUrl || _this.getVideoUrl(opt, channel, videoId); - var html = _this.getHtml(opt, videoUrl, id); - (0, _util.append)(body, html); - var modal = document.getElementById(id); - var btn = modal.querySelector('.js-modal-video-dismiss-btn'); - var timeout = void 0; // used for resize - var resizeModalVideoWhenHeightGreaterThanWindowHeight = function resizeModalVideoWhenHeightGreaterThanWindowHeight() { - clearTimeout(timeout); - // Resize modal-video-iframe-wrap when window size changed when the height of the video is greater than the height of the window. - timeout = setTimeout(function () { - var width = _this.getWidthFulfillAspectRatio(opt.ratio, window.innerHeight, window.innerWidth); - - var modalVideoInner = document.getElementById('modal-video-inner-' + id); - if (modalVideoInner.style.maxWidth !== width) { - modalVideoInner.style.maxWidth = width; - } - }, 10); - }; - modal.focus(); - modal.addEventListener('click', function () { - (0, _util.addClass)(modal, classNames.modalVideoClose); - window.removeEventListener('resize', resizeModalVideoWhenHeightGreaterThanWindowHeight); - setTimeout(function () { - (0, _util.remove)(modal); - selector.focus(); - }, speed); - }); - modal.addEventListener('keydown', function (e) { - if (e.which === 9) { - e.preventDefault(); - if (document.activeElement === modal) { - btn.focus(); - } else { - modal.setAttribute('aria-label', ''); - modal.focus(); - } - } - }); - window.addEventListener('resize', resizeModalVideoWhenHeightGreaterThanWindowHeight); - btn.addEventListener('click', function () { - (0, _util.triggerEvent)(modal, 'click'); - }); - }); - }); + // Member variable + this.opt = (0, _deepmerge2.default)(defaults, option); + this.id = (0, _util.getUniqId)(); + this.modal = this.onClick.bind(this); + this.selectors = typeof ele === 'string' ? document.querySelectorAll(ele) : ele; + + // Main methods + this.add(); } _createClass(ModalVideo, [{ - key: 'getPadding', - value: function getPadding(ratio) { - var arr = ratio.split(':'); - var width = Number(arr[0]); - var height = Number(arr[1]); - var padding = height * 100 / width; - return padding + '%'; + key: 'onClick', + value: function onClick(event) { + var _this = this; + + var selector = event.target; + if (selector.tagName === 'A') { + event.preventDefault(); + } + + // modal append + var videoId = event.target.dataset.videoId; + var channel = selector.dataset.channel || this.opt.channel; + var videoUrl = selector.dataset.videoUrl || this.getVideoUrl(this.opt, channel, videoId); + var body = document.querySelector('body'); + var html = this.getHtml(videoUrl); + (0, _util.append)(body, html); + + // modal Handling + var modal = document.getElementById(this.id); + var btn = modal.querySelector('.' + this.opt.handleClassName.modalVideoDismissBtn); + modal.focus(); + + var timeout = void 0; // used for resize + var resizeModalVideoWhenHeightGreaterThanWindowHeight = function resizeModalVideoWhenHeightGreaterThanWindowHeight() { + clearTimeout(timeout); + // Resize modal-video-iframe-wrap when window size changed when the height of the video is greater than the height of the window. + timeout = setTimeout(function () { + var width = _this.getWidthFulfillAspectRatio(_this.opt.ratio, window.innerHeight, window.innerWidth); + var modalVideoInner = document.getElementById('modal-video-inner-' + _this.id); + if (modalVideoInner.style.maxWidth !== width) { + modalVideoInner.style.maxWidth = width; + } + }, 10); + }; + modal.addEventListener('click', function () { + (0, _util.addClass)(modal, _this.opt.classNames.modalVideoClose); + window.removeEventListener('resize', resizeModalVideoWhenHeightGreaterThanWindowHeight()); + setTimeout(function () { + (0, _util.remove)(modal); + selector.focus(); + }, _this.opt.animationSpeed); + }); + modal.addEventListener('keydown', function (e) { + if (e.which === 9) { + e.preventDefault(); + if (document.activeElement === modal) { + btn.focus(); + } else { + modal.setAttribute('aria-label', ''); + modal.focus(); + } + } + if (e.key === 'Escape') { + (0, _util.triggerEvent)(modal, 'click'); + } + }); + window.addEventListener('resize', resizeModalVideoWhenHeightGreaterThanWindowHeight()); + btn.addEventListener('click', function () { + (0, _util.triggerEvent)(modal, 'click'); + }); } /** - * Calculate the width of the video fulfill aspect ratio. - * When the height of the video is greater than the height of the window, - * this function return the width that fulfill the aspect ratio for the height of the window. - * In other cases, this function return '100%'(the height relative to the width is determined by css). - * - * @param string ratio - * @param number maxHeight - * @param number maxWidth - * @returns string - */ + * Calculate the width of the video fulfill aspect ratio. + * When the height of the video is greater than the height of the window, + * this function return the width that fulfill the aspect ratio for the height of the window. + * In other cases, this function return '100%'(the height relative to the width is determined by css). + * + * @param string ratio + * @param number maxHeight + * @param number maxWidth + * @returns string + */ }, { key: 'getWidthFulfillAspectRatio', @@ -337,7 +434,6 @@ var ModalVideo = function () { Object.keys(obj).forEach(function (key) { url += key + '=' + obj[key] + '&'; }); - console.log(url); return url.substr(0, url.length - 1); } }, { @@ -367,7 +463,6 @@ var ModalVideo = function () { if (youtube.nocookie === true) { return '//www.youtube-nocookie.com/embed/' + videoId + '?' + query; } - return '//www.youtube.com/embed/' + videoId + '?' + query; } }, { @@ -375,12 +470,44 @@ var ModalVideo = function () { value: function getFacebookUrl(facebook, videoId) { return '//www.facebook.com/v2.10/plugins/video.php?href=https://www.facebook.com/facebook/videos/' + videoId + '&' + this.getQueryString(facebook); } + }, { + key: 'add', + value: function add() { + var _this2 = this; + + var isUpdateSelectors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (isUpdateSelectors) { + this.selectors = typeof this.selectors === 'string' ? document.querySelectorAll(this.selectors) : this.selectors; + } + Array.from(this.selectors).forEach(function (selector) { + selector.addEventListener('click', _this2.modal); + }); + } + }, { + key: 'destroy', + value: function destroy() { + var _this3 = this; + + Array.from(this.selectors).forEach(function (selector) { + selector.removeEventListener('click', _this3.modal); + }); + } + }, { + key: 'getPadding', + value: function getPadding(ratio) { + var arr = ratio.split(':'); + var width = Number(arr[0]); + var height = Number(arr[1]); + var padding = height * 100 / width; + return padding + '%'; + } }, { key: 'getHtml', - value: function getHtml(opt, videoUrl, id) { - var padding = this.getPadding(opt.ratio); - var classNames = opt.classNames; - return '\n