-
-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added first ES6/ES7 code draft to `lib/src` folder, the following changes apply * all components have `destroy()` method * recent fixes to allow re-init are included (on re-init we trigger `destroy()` before anything else) * more clear init objects ( in essence we're talking `{chaos,options,methods}` -> `{element,target,options,methods}` ) * removed manual tokenization, resulting in easier long term maintenance, the min files will be larger while gzip files should be 7-10% smaller, now @mustafa0x should be happy #269 * replaced `getClosest()` utility with native `element.closest(selector)` * Popover and Tooltip now both use `options.template` and make use of attributes like `data-title` to fill in the template markup * Popover and Tooltip can work simultaneously with other `data-toggle` components via `data-tip="tooltip"` and `data-tip="popover"` attributes (Modal,Dropdown,Tab,Collapse) TO DO (priority ordered): * debug and fix all issues resulted in removal of manual tokenization or other module import/link related issues * evaluate and discuss code structure to find opportunities for new features and code quality improvements (constructor, private & public methods, etc) * Toast component: aren't `destroy()` and `dispose()` methods supposed to do the same? * we need a new ES6/ES7 friendly `initCallback`, we might also need an ES6/ES7 friendly `removeDataAPI` for all components, the opposite of `initCallback`, a possible draft at `src/util/callbacks.js` * we need a new bundle builder (lib/bundle.js) to do ES6/ES7 `index.js` -> ES5 `bootstrap-native.js` compilation + uglify work, that's where YOU come in (rollup, babel, promise, whatever you need, bring it) * we need a full documentation for V4 page, the future main page of the project * wiki updates @cvaize and everyone interested in this thread please join discussion here #306 Happy New Year!
- Loading branch information
Showing
25 changed files
with
2,303 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
var bundle = require('./src/index'); | ||
// var Alert = require('./src/alert-native'); | ||
|
||
console.log(bundle) | ||
// console.log(Alert) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
|
||
/* Native JavaScript for Bootstrap 4 | Alert | ||
-------------------------------------------*/ | ||
|
||
// IMPORTS | ||
import { supports } from './util/callbacks.js'; | ||
import { hasClass, removeClass } from './util/class.js'; | ||
import { bootstrapCustomEvent, on, off } from './util/event.js'; | ||
import { queryElement } from './util/selector.js'; | ||
import { emulateTransitionEnd } from './util/transition.js'; | ||
|
||
// ALERT DEFINITION | ||
// ================ | ||
export default class Alert { | ||
|
||
constructor (element) { | ||
|
||
// initialization element | ||
element = queryElement(element); | ||
|
||
// reset on re-init | ||
element.Alert && element.Alert.destroy(); | ||
|
||
// bind, target alert, duration and stuff | ||
const self = this, | ||
|
||
// custom events | ||
closeCustomEvent = bootstrapCustomEvent('close','alert'), | ||
closedCustomEvent = bootstrapCustomEvent('closed','alert'), | ||
|
||
// handlers | ||
triggerHandler = () => { | ||
hasClass(alert,'fade') ? emulateTransitionEnd(alert,transitionEndHandler) : transitionEndHandler(); | ||
}, | ||
clickHandler = e => { | ||
alert = e.target.closest(`.alert`); | ||
element = queryElement(`[data-dismiss="alert"]`,alert); | ||
element && alert && (element === e.target || element.contains(e.target)) && self.close(); | ||
}, | ||
transitionEndHandler = () => { | ||
off(element, 'click', clickHandler); // detach it's listener | ||
alert.parentNode.removeChild(alert); | ||
dispatchCustomEvent.call(alert,closedCustomEvent); | ||
}; | ||
|
||
// public method | ||
self.close = () => { | ||
if ( alert && element && hasClass(alert,'show') ) { | ||
dispatchCustomEvent.call(alert,closeCustomEvent); | ||
if ( closeCustomEvent.defaultPrevented ) return; | ||
self.destroy(); | ||
} | ||
} | ||
|
||
self.destroy = () => { | ||
removeClass(alert,'show'); | ||
alert && triggerHandler(); | ||
off(element, 'click', clickHandler); | ||
delete element.Alert; | ||
} | ||
|
||
// init | ||
if ( !element.Alert ) { // prevent adding event handlers twice | ||
on(element, 'click', clickHandler); | ||
} | ||
|
||
// find the parent alert | ||
let alert = element.closest(`.alert`); | ||
|
||
// store init object within target element | ||
self.element = element; | ||
element.Alert = self; | ||
} | ||
} | ||
|
||
// ALERT DATA API | ||
// ============== | ||
supports.push(['Alert', Alert, '[data-dismiss="alert"]']); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
|
||
/* Native JavaScript for Bootstrap 4 | Button | ||
---------------------------------------------*/ | ||
|
||
// IMPORTS | ||
import { supports } from './util/callbacks.js'; | ||
import { hasClass, addClass, removeClass } from './util/class.js'; | ||
import { bootstrapCustomEvent, on, off } from './util/event.js'; | ||
import { queryElement, getElementsByClassName } from './util/selector.js'; | ||
|
||
// BUTTON DEFINITION | ||
// =================== | ||
export default class Button { | ||
|
||
constructor(element){ | ||
|
||
// initialization element | ||
element = queryElement(element); | ||
|
||
// reset on re-init | ||
element.Button && element.Button.destroy(); | ||
|
||
// constant | ||
let toggled = false; // toggled makes sure to prevent triggering twice the change.bs.button events | ||
|
||
// bind | ||
const self = this, | ||
|
||
// changeEvent | ||
changeCustomEvent = bootstrapCustomEvent('change', 'button'), | ||
|
||
// private methods | ||
keyHandler = e => { | ||
const key = e.which || e.keyCode; | ||
key === 32 && e.target === document.activeElement && toggle(e); | ||
}, | ||
|
||
preventScroll = e => { | ||
const key = e.which || e.keyCode; | ||
key === 32 && e.preventDefault(); | ||
}, | ||
|
||
toggle = e => { | ||
const label = e.target.tagName === 'LABEL' ? e.target : e.target.parentNode.tagName === 'LABEL' ? e.target.parentNode : null; // the .btn label | ||
|
||
if ( !label ) return; //react if a label or its immediate child is clicked | ||
|
||
const // all the button group buttons | ||
labels = getElementsByClassName(label.parentNode,'btn'), | ||
input = label.getElementsByTagName('INPUT')[0]; | ||
|
||
if ( !input ) return; // return if no input found | ||
|
||
dispatchCustomEvent.call(input, changeCustomEvent); // trigger the change for the input | ||
dispatchCustomEvent.call(element, changeCustomEvent); // trigger the change for the btn-group | ||
|
||
// manage the dom manipulation | ||
if ( input.type === 'checkbox' ) { //checkboxes | ||
if ( changeCustomEvent.defaultPrevented ) return; // discontinue when defaultPrevented is true | ||
|
||
if ( !input.checked ) { | ||
addClass(label,'active'); | ||
input.getAttribute('checked'); | ||
input.setAttribute('checked','checked'); | ||
input.checked = true; | ||
} else { | ||
removeClass(label,'active'); | ||
input.getAttribute('checked'); | ||
input.removeAttribute('checked'); | ||
input.checked = false; | ||
} | ||
|
||
if (!toggled) { // prevent triggering the event twice | ||
toggled = true; | ||
} | ||
} | ||
|
||
if ( input.type === 'radio' && !toggled ) { // radio buttons | ||
if ( changeCustomEvent.defaultPrevented ) return; | ||
// don't trigger if already active (the OR condition is a hack to check if the buttons were selected with key press and NOT mouse click) | ||
if ( !input.checked || (e.screenX === 0 && e.screenY == 0) ) { | ||
addClass(label,'active'); | ||
addClass(label,'focus'); | ||
input.setAttribute('checked','checked'); | ||
input.checked = true; | ||
|
||
toggled = true; | ||
for (let i = 0, ll = labels.length; i<ll; i++) { | ||
const otherLabel = labels[i], otherInput = otherLabel.getElementsByTagName('INPUT')[0]; | ||
if ( otherLabel !== label && hasClass(otherLabel,'active') ) { | ||
dispatchCustomEvent.call(otherInput, changeCustomEvent); // trigger the change | ||
removeClass(otherLabel,'active'); | ||
otherInput.removeAttribute('checked'); | ||
otherInput.checked = false; | ||
} | ||
} | ||
} | ||
} | ||
setTimeout( () => { toggled = false; }, 50 ); | ||
}, | ||
focusHandler = e => { | ||
addClass(e.target.parentNode,'focus'); | ||
}, | ||
blurHandler = e => { | ||
removeClass(e.target.parentNode,'focus'); | ||
}, | ||
toggleEvents = action => { | ||
action( element, 'click', toggle ); | ||
action( element, 'keyup', keyHandler ), action( element, 'keydown', preventScroll ); | ||
|
||
const allBtns = getElementsByClassName(element, 'btn'); | ||
for (let i=0; i<allBtns.length; i++) { | ||
const input = allBtns[i].getElementsByTagName('INPUT')[0]; | ||
action( input, 'focus', focusHandler), action( input, 'blur', blurHandler); | ||
} | ||
}; | ||
|
||
// public method | ||
self.destroy = () => { | ||
toggleEvents(off); | ||
delete element.Button; | ||
} | ||
|
||
// init | ||
if ( !element.Button ) { // prevent adding event handlers twice | ||
toggleEvents(on); | ||
} | ||
|
||
// activate items on load | ||
const labelsToACtivate = getElementsByClassName(element, 'btn'), lbll = labelsToACtivate.length; | ||
for (let i=0; i<lbll; i++) { | ||
!hasClass(labelsToACtivate[i],'active') | ||
&& queryElement('input:checked',labelsToACtivate[i]) | ||
&& addClass(labelsToACtivate[i],'active'); | ||
} | ||
|
||
// associate target with init object | ||
self.element = element; | ||
element.Button = self; | ||
} | ||
} | ||
|
||
// BUTTON DATA API | ||
// ================= | ||
supports.push( [ 'Button', Button, '[data-toggle="buttons"]' ] ); | ||
|
Oops, something went wrong.