diff --git a/bower.json b/bower.json index c2ccbe130..7a70fa7e2 100644 --- a/bower.json +++ b/bower.json @@ -25,7 +25,7 @@ "devDependencies": { "jquery": null, "jquery-1.9.1": "jquery#1.9.1", - "qunit": "~1.14.0", + "qunit": "1.x", "requirejs-text": "2.x", "underscore": "1.x", "blanket": "1.x" diff --git a/grunt/config/concat.js b/grunt/config/concat.js index 7b62f5d63..868ced441 100644 --- a/grunt/config/concat.js +++ b/grunt/config/concat.js @@ -19,7 +19,8 @@ module.exports = function (grunt) { 'js/repeater.js', 'js/repeater-list.js', 'js/repeater-thumbnail.js', - 'js/scheduler.js' + 'js/scheduler.js', + 'js/picker.js' ], dest: 'dist/js/' + '<%= pkg.name %>' + '.js' }, @@ -34,5 +35,5 @@ module.exports = function (grunt) { } } } - + }; \ No newline at end of file diff --git a/index.html b/index.html index d3634e7c7..7bec998e0 100644 --- a/index.html +++ b/index.html @@ -2437,6 +2437,61 @@

Spinbox

+
+

Picker

+
+
+
+
+ +
+ +
+
+
+
+
Choose Folder Location
+
+ +
+
    + + +
+
+ + +
+ +
+ +
+
+ + + +
+
+

Tree

diff --git a/index.js b/index.js index fbb7a3bdc..ed871679c 100644 --- a/index.js +++ b/index.js @@ -12,8 +12,8 @@ define(function (require) { }; // programmatically injecting this is so much easier than writing the html by hand 376 times... - $('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id], dt[id]').each(function (i) { - $(this).prepend([' '].join('')); + $('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id], dt[id], section[id]').each(function (i) { + $(this).children('h2:first').prepend([' '].join('')); }); // load fuel controls @@ -945,13 +945,11 @@ define(function (require) { $('#mySpinbox1').spinbox(); }); - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TREE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - $('#myTree1').tree({ - dataSource: function (parentData, callback) { + var treeDataSource = function (parentData, callback) { log("Opening branch data: ", parentData); setTimeout(function () { @@ -1018,7 +1016,10 @@ define(function (require) { ] }); }, 400); - }, + } + + $('#myTree1').tree({ + dataSource: treeDataSource, cacheItems: true, folderSelect: true, multiSelect: true @@ -1226,6 +1227,51 @@ define(function (require) { log('Disclosed All, this many recursions: ', data.disclosures); }); + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + SUPERPICKER + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + $('#btnPickerEnable').click(function () { + $('#mypicker').picker('enable'); + }); + $('#btnPickerDisable').click(function () { + $('#mypicker').picker('disable'); + }); + $('#btnPickerDestroy').click(function () { + var $container = $('#mypicker').parent(); + var markup = $('#mypicker').picker('destroy'); + log(markup); + $container.append(markup); + $('#mypicker').picker({ + edit: true + }); + }); + + $('#mypicker').on('accepted.fu.picker', function() { + console.log('accepted.fu.picker'); + }); + $('#mypicker').on('cancelled.fu.picker', function() { + console.log('cancelled.fu.picker'); + }); + $('#mypicker').on('exited.fu.picker', function() { + console.log('exited.fu.picker'); + }); + $('#mypicker').on('shown.fu.picker', function() { + console.log('shown.fu.picker'); + }); + + $('#myPickerTree1').tree({ + dataSource: treeDataSource, + cacheItems: true, + folderSelect: true, + multiSelect: true + }); + + // requires https://github.com/exacttarget/get-list-item-path + // $('#mypicker2').on('accepted.fu.picker', function(o){ + // var selected = $('#myPickerTree1').find('.tree-selected'); + // var selectedPaths = getListItemPaths('#myPickerTree1', selected, '.tree-label', '/', ', '); + // $('#mypicker2').picker('setValue', selectedPaths); + // }); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WIZARD diff --git a/js/all.js b/js/all.js index 70a760f92..665b9e6d3 100644 --- a/js/all.js +++ b/js/all.js @@ -39,6 +39,7 @@ require('fuelux/search'); require('fuelux/spinbox'); require('fuelux/selectlist'); + require('fuelux/picker'); require('fuelux/tree'); require('fuelux/wizard'); diff --git a/js/picker.js b/js/picker.js new file mode 100644 index 000000000..e3274ef52 --- /dev/null +++ b/js/picker.js @@ -0,0 +1,293 @@ +/* + * Fuel UX Picker + * https://github.com/ExactTarget/fuelux + * + * Copyright (c) 2014 ExactTarget + * Licensed under the BSD New license. + */ + +// -- BEGIN UMD WRAPPER PREFACE -- + +// For more information on UMD visit: +// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // if AMD loader is available, register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // OR use browser globals if AMD is not present + factory(jQuery); + } +}(function ($) { + // -- END UMD WRAPPER PREFACE -- + + // -- BEGIN MODULE CODE HERE -- + + var old = $.fn.picker; + + // PLACARD CONSTRUCTOR AND PROTOTYPE + + var Picker = function Picker(element, options) { + var self = this; + this.$element = $(element); + this.options = $.extend({}, $.fn.picker.defaults, options); + + this.$accept = this.$element.find('.picker-accept'); + this.$cancel = this.$element.find('.picker-cancel'); + this.$trigger = this.$element.find('.picker-trigger'); + this.$footer = this.$element.find('.picker-footer'); + this.$header = this.$element.find('.picker-header'); + this.$popup = this.$element.find('.picker-popup'); + this.$body = this.$element.find('.picker-body'); + + this.clickStamp = '_'; + + this.isInput = this.$trigger.is('input'); + + this.$trigger.on('keydown.fu.picker', $.proxy(this.keyComplete, this)); + this.$trigger.on('focus.fu.picker', $.proxy(function inputFocus(e){ + if(typeof e === "undefined" || $(e.target).is('input[type=text]')){ + $.proxy(this.show(), this); + } + }, this)); + this.$trigger.on('click.fu.picker', $.proxy(function triggerClick(e){ + if(!$(e.target).is('input[type=text]')){ + $.proxy(this.toggle(), this); + }else{ + $.proxy(this.show(), this); + } + }, this)); + this.$accept.on('click.fu.picker', $.proxy(this.complete, this, 'accepted')); + this.$cancel.on('click.fu.picker', function (e) { + e.preventDefault(); self.complete('cancelled'); + }); + + + }; + + var _isOffscreen = function _isOffscreen(picker) { + var windowHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + var scrollTop = $(document).scrollTop(); + var popupTop = picker.$popup.offset(); + var popupBottom = popupTop.top + picker.$popup.outerHeight(true); + + //if the bottom of the popup goes off the page, but the top does not, dropup. + if (popupBottom > windowHeight + scrollTop || popupTop.top < scrollTop){ + return true; + }else{//otherwise, prefer showing the top of the popup only vs the bottom + return false; + } + }; + + var _display = function _display(picker) { + picker.$popup.css('visibility', 'hidden'); + + _showBelow(picker); + + //if part of the popup is offscreen try to show it above + if(_isOffscreen(picker)){ + _showAbove(picker); + + //if part of the popup is still offscreen, prefer cutting off the bottom + if(_isOffscreen(picker)){ + _showBelow(picker); + } + } + + picker.$popup.css('visibility', 'visible'); + }; + + var _showAbove = function _showAbove(picker) { + picker.$popup.css('top', - picker.$popup.outerHeight(true) + 'px'); + }; + + var _showBelow = function _showBelow(picker) { + picker.$popup.css('top', picker.$trigger.outerHeight(true) + 'px'); + }; + + Picker.prototype = { + constructor: Picker, + + complete: function complete(action) { + var EVENT_CALLBACK_MAP = { + 'accepted': 'onAccept', + 'cancelled': 'onCancel', + 'exited': 'onExit' + }; + var func = this.options[ EVENT_CALLBACK_MAP[action] ]; + + var obj = { + contents: this.$body + }; + + if (func) { + func(obj); + this.$element.trigger(action + '.fu.picker', obj); + } else { + this.$element.trigger(action + '.fu.picker', obj); + this.hide(); + } + }, + + keyComplete: function keyComplete(e) { + if (this.isInput && e.keyCode === 13) { + this.complete('accepted'); + this.$trigger.blur(); + } else if (e.keyCode === 27) { + this.complete('exited'); + this.$trigger.blur(); + } + }, + + destroy: function destroy() { + this.$element.remove(); + // remove any external bindings + $(document).off('click.fu.picker.externalClick.' + this.clickStamp); + // empty elements to return to original markup + // [none] + // return string of markup + return this.$element[0].outerHTML; + }, + + disable: function disable() { + this.$element.addClass('disabled'); + this.$trigger.attr('disabled', 'disabled'); + }, + + enable: function enable() { + this.$element.removeClass('disabled'); + this.$trigger.removeAttr('disabled'); + }, + + toggle: function toggle() { + if (this.$element.hasClass('showing')) { + this.hide(); + }else{ + this.show(); + } + }, + + hide: function hide() { + if (!this.$element.hasClass('showing')) { + return; + } + + this.$element.removeClass('showing'); + $(document).off('click.fu.picker.externalClick.' + this.clickStamp); + this.$element.trigger('hidden.fu.picker'); + }, + + externalClickListener: function externalClickListener(e, force) { + if (force === true || this.isExternalClick(e)) { + this.complete('exited'); + } + }, + + isExternalClick: function isExternalClick(e) { + var el = this.$element.get(0); + var exceptions = this.options.externalClickExceptions || []; + var $originEl = $(e.target); + var i, l; + + if (e.target === el || $originEl.parents('.picker:first').get(0) === el) { + return false; + } else { + for (i = 0, l = exceptions.length; i < l; i++) { + if ($originEl.is(exceptions[i]) || $originEl.parents(exceptions[i]).length > 0) { + return false; + } + + } + } + + return true; + }, + + show: function show() { + var other; + + other = $(document).find('.picker.showing'); + if (other.length > 0) { + if (other.data('fu.picker') && other.data('fu.picker').options.explicit) { + return; + } + + other.picker('externalClickListener', {}, true); + } + + this.$element.addClass('showing'); + + _display(this); + + this.$element.trigger('shown.fu.picker'); + + this.clickStamp = new Date().getTime() + (Math.floor(Math.random() * 100) + 1); + if (!this.options.explicit) { + $(document).on('click.fu.picker.externalClick.' + this.clickStamp, $.proxy(this.externalClickListener, this)); + } + } + }; + + // PLACARD PLUGIN DEFINITION + + $.fn.picker = function picker(option) { + var args = Array.prototype.slice.call(arguments, 1); + var methodReturn; + + var $set = this.each(function () { + var $this = $(this); + var data = $this.data('fu.picker'); + var options = typeof option === 'object' && option; + + if (!data) { + $this.data('fu.picker', (data = new Picker(this, options))); + } + + if (typeof option === 'string') { + methodReturn = data[option].apply(data, args); + } + }); + + return (methodReturn === undefined) ? $set : methodReturn; + }; + + $.fn.picker.defaults = { + onAccept: undefined, + onCancel: undefined, + onExit: undefined, + externalClickExceptions: [], + explicit: false + }; + + $.fn.picker.Constructor = Picker; + + $.fn.picker.noConflict = function noConflict() { + $.fn.picker = old; + return this; + }; + + // DATA-API + + $(document).on('focus.fu.picker.data-api', '[data-initialize=picker]', function (e) { + var $control = $(e.target).closest('.picker'); + if (!$control.data('fu.picker')) { + $control.picker($control.data()); + } + }); + + // Must be domReady for AMD compatibility + $(function () { + $('[data-initialize=picker]').each(function () { + var $this = $(this); + if ($this.data('fu.picker')) return; + $this.picker($this.data()); + }); + }); + + // -- BEGIN UMD WRAPPER AFTERWORD -- +})); +// -- END UMD WRAPPER AFTERWORD -- diff --git a/js/placard.js b/js/placard.js index 6e67451be..605f5c7fa 100644 --- a/js/placard.js +++ b/js/placard.js @@ -242,7 +242,7 @@ this.$field.val(val); - if (!suppressEllipsis && !_isShown) { + if (!suppressEllipsis && !_isShown(this)) { this.applyEllipsis(); } diff --git a/less/fuelux.less b/less/fuelux.less index ea152566b..1e6d781de 100644 --- a/less/fuelux.less +++ b/less/fuelux.less @@ -26,6 +26,7 @@ @import "scheduler.less"; @import "search.less"; @import "selectlist.less"; +@import "picker.less"; @import "tree.less"; @import "wizard.less"; @import "utility.less"; diff --git a/less/picker.less b/less/picker.less new file mode 100644 index 000000000..807b6c6c5 --- /dev/null +++ b/less/picker.less @@ -0,0 +1,166 @@ +.fuelux { + + .picker { + display: inline-block; + position: relative; + + &[data-ellipsis="true"] { + &.showing { + input.picker-field { + overflow: visible; + text-overflow: clip; + white-space: normal; + } + } + + input.picker-field { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &::-ms-clear { + display:none; + } + } + + textarea.picker-field { + &[readonly] { + overflow: hidden; + } + } + } + + &.showing { + .picker-footer, + .picker-header, + .picker-popup { + display: block; + z-index: 1; + } + + input.picker-field, textarea.picker-field { + background: @true-white; + border: 1px solid @gray80; + box-shadow: none; + position: relative; + z-index: 1; + } + } + + input.picker-field, textarea.picker-field { + resize: none; + + &[readonly] { + background: @true-white; + cursor: auto; + + &.glass { + background: none; + + &:hover { + background: @infoBackground; + cursor: pointer; + } + } + } + + &:focus { + border: 1px solid @gray80; + box-shadow: none; + } + } + + &-cancel { + font-size: 12px; + margin-right: 4px; + vertical-align: middle; + } + + &-footer, + &-header { + display: none; + left: 0; + line-height: 1; + right: 0; + } + + &-footer { + padding: 8px 10px 8px 0; + text-align: right; + bottom: 0; + position: absolute; + } + + &-header { + height: 31px; + padding: 8px 0 0px 10px; + + h1, h2, h3, h4, h5, h6 { + margin: 0; + } + } + + &-popup { + background: @infoBackground; + background-clip: padding-box; + border: 1px solid @gray80; + border-radius: 4px; + box-shadow: 0 0 0 1px @true-white inset; + display: none; + position: absolute; + padding-left: 6px; + padding-right: 6px; + height: 234px; + width: 350px; + margin: 4px 0; + + } + + .picker-body.well { + background-color: #fff; + overflow: scroll; + padding: 0; + height: 165px; + } + + .tree { + border: none; + } + + .glass { + background: transparent; + border: 1px solid @true-white; + box-shadow: none; + + &:hover { + background: @infoBackground; + border-color: @focusColor; + cursor: pointer; + + &[disabled] { + background: transparent; + border-color: @true-white; + cursor: not-allowed; + } + } + + &:focus { + background: @true-white; + border-color: @focusColor; + box-shadow: inset 0 1px 1px fade(@true-black, 75%), 0 0 8px fade(@focusColor, 60%); + cursor: auto; + + &[disabled] { + background: transparent; + border-color: @true-white; + cursor: not-allowed; + } + } + + &[disabled] { + cursor: not-allowed; + } + } + } + +} \ No newline at end of file diff --git a/test/markup/picker-markup.html b/test/markup/picker-markup.html new file mode 100644 index 000000000..fdf4654ba --- /dev/null +++ b/test/markup/picker-markup.html @@ -0,0 +1,51 @@ + + +Sample Markup + +
+ +
+
+
+ + +
+
+
+
+
Header
+
+ +
+ + +
+
+ +
+
+
+ + +
+
+
+
+
Header
+
+ +
+ + +
+
+ +
+ + \ No newline at end of file diff --git a/test/picker-test.js b/test/picker-test.js new file mode 100644 index 000000000..308b581d3 --- /dev/null +++ b/test/picker-test.js @@ -0,0 +1,306 @@ +/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/ +/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/ +/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/ + +define(function(require){ + var $ = require('jquery'); + var html = require('text!test/markup/picker-markup.html!strip'); + + require('bootstrap'); + require('fuelux/picker'); + + module('Fuel UX Picker'); + + test('should be defined on jquery object', function () { + ok($().find('#picker1').picker(), 'picker method is defined'); + }); + + test('should return element', function () { + var $picker = $(html).find('#picker1'); + ok($picker.picker() === $picker, 'picker should be initialized'); + }); + + test('should show and hide as expected - input', function(assert){ + var $picker = $(html).find('#picker1'); + + $('body').append($picker); + $picker.picker(); + + var cancelledDone = assert.async(); + var allDone = assert.async(); + + var $textInputTrigger = $($picker.find('.picker-trigger')[0]); + var $otherTrigger = $($picker.find('.picker-trigger')[1]); + $textInputTrigger.focus().focus(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + + $picker.one('exited.fu.picker', function(e, helpers){ + ok(1===1, 'default action event (exited) triggered upon external click'); + cancelledDone(); + }); + + $('body').click(); + + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + + $textInputTrigger.click(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + + $textInputTrigger.click(); + equal($picker.hasClass('showing'), true, 'picker continues showing when text input clicked and picker is already showing'); + + $otherTrigger.click(); + equal($picker.hasClass('showing'), false, 'picker hides when non-text input clicked and picker is already showing'); + + $picker.remove(); + allDone(); + }); + + test('should behave as expected - button', function(assert){ + var $picker = $(html).find('#picker2'); + $('body').append($picker); + $picker.picker(); + + var cancelledDone = assert.async(); + var allDone = assert.async(); + $picker.one('exited.fu.picker', function(e, helpers){ + ok(1===1, 'default action event (exited) triggered upon external click'); + cancelledDone(); + }); + + $($picker.find('.picker-trigger')[1]).click(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + + $('body').click(); + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + $picker.remove(); + + allDone(); + }); + + test('show/hide functions should behave as expected', function(assert){ + var $picker = $(html).find('#picker1'); + $('body').append($picker); + $picker.picker(); + + var shownDone = assert.async(); + var hiddenDone = assert.async(); + var allDone = assert.async(); + + $picker.one('shown.fu.picker', function(e){ + ok(1===1, 'shown event triggers on show'); + equal(typeof e, 'object', 'event object passed in shown event'); + shownDone(); + }); + $picker.one('hidden.fu.picker', function(e, helpers){ + ok(1===1, 'hidden event triggers on hide'); + equal(typeof e, 'object', 'event object passed in hidden event'); + hiddenDone(); + }); + + $picker.picker('show'); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + + $picker.picker('hide'); + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + + allDone(); + + $picker.remove(); + }); + + test('trigger events should fire as expected', function(assert){ + var $picker = $(html).find('#picker1'); + + $('body').append($picker); + $picker.picker(); + + + var acceptedDone = assert.async(); + var cancelledDone = assert.async(); + var exitedDone = assert.async(); + var allDone = assert.async(); + + $picker.one('accepted.fu.picker', function(e, helpers){ + ok(1===1, 'accept event triggers on accept'); + equal(typeof e, 'object', 'event object passed in accept event'); + equal(typeof helpers, 'object', 'helpers object passed in accept event'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + acceptedDone(); + }); + $picker.one('cancelled.fu.picker', function(e, helpers){ + ok(1===1, 'cancel event triggers on cancel'); + equal(typeof e, 'object', 'event object passed in cancel event'); + equal(typeof helpers, 'object', 'helpers object passed in cancel event'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + cancelledDone(); + }); + $picker.on('exited.fu.picker', function(e, helpers){ + ok(1===1, 'exit event triggers on exit'); + equal(typeof e, 'object', 'event object passed in exit event'); + equal(typeof helpers, 'object', 'helpers object passed in exit event'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + exitedDone(); + }); + + + $picker.find('.picker-trigger')[0].click(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + $picker.find('.picker-cancel').click(); + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + $picker.find('.picker-trigger')[0].click(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + $picker.find('.picker-accept').click(); + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + $picker.find('.picker-trigger')[0].click(); + equal($picker.hasClass('showing'), true, 'picker shows when appropriate'); + $('body').click(); + equal($picker.hasClass('showing'), false, 'picker hides when appropriate'); + allDone(); + + $picker.remove(); + }); + + test('onAccept function should be called as expected', function(assert){ + var $picker = $(html).find('#picker1'); + + var acceptedDone = assert.async(); + $picker.picker({ + onAccept: function(helpers){ + ok(1===1, 'onAccept function called on accept'); + equal(typeof helpers, 'object', 'helpers object passed to onAccept function'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + $picker.picker('hide'); + acceptedDone(); + } + }); + + $picker.find('.picker-trigger')[0].click(); + $picker.find('.picker-accept').click(); + }); + + test('onCancel function should be called as expected', function(assert){ + var $picker = $(html).find('#picker1'); + + var cancelledDone = assert.async(); + $picker.picker({ + onCancel: function(helpers){ + ok(1===1, 'onCancel function called on cancel'); + equal(typeof helpers, 'object', 'helpers object passed to onCancel function'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + $picker.picker('hide'); + cancelledDone(); + } + }); + + $picker.find('.picker-trigger')[0].click(); + $picker.find('.picker-cancel').click(); + }); + + test('onExit function should be called as expected', function(assert){ + var $picker = $(html).find('#picker1'); + $('body').append($picker); + + var exitedDone = assert.async(); + $picker.picker({ + onExit: function(helpers){ + ok(1===1, 'onExit function called on exit'); + equal(typeof helpers, 'object', 'helpers object passed to onExit function'); + equal((helpers.contents!==undefined), true, 'helpers object contains correct attributes'); + $picker.picker('hide'); + exitedDone(); + } + }); + + $picker.find('.picker-trigger')[0].click(); + $('body').click(); + }); + + test('Enter and exit keys should trigger appropriate response', function(assert){ + var $picker = $(html).find('#picker1'); + $('body').append($picker); + + var $input = $($picker.find('input')[0]); + var e = $.Event("keydown"); + + var acceptedDone = assert.async(); + var exitedDone = assert.async(); + $picker.picker({ + onAccept: function(e){ + ok(1===1, 'onAccept function called when enter keypress'); + acceptedDone(); + }, + onExit: function(){ + ok(1===1, 'onExit function called when exit keypress'); + exitedDone(); + } + }); + + e.keyCode = 13; + $input.trigger(e); + e.keyCode = 27; + $input.trigger(e); + + $picker.remove(); + }); + + + test('externalClickExceptions option should work as expected', function(){ + var $picker = $(html).find('#picker1'); + + $('body').append('
'); + $('body').append($picker); + $picker.picker({ + externalClickExceptions: ['.test', '#test'] + }); + + $picker.find('.picker-trigger')[0].click(); + $('#test').click(); + equal($picker.hasClass('showing'), true, 'externalClick ignored for specified id'); + $('.test').click(); + equal($picker.hasClass('showing'), true, 'externalClick ignored for specified class'); + $('.innerTest').click(); + equal($picker.hasClass('showing'), true, 'externalClick ignored for child of specified selector'); + + $picker.remove(); + $('.test,#test').remove(); + }); + + test('explicit option should work as expected', function(){ + var $picker = $(html).find('#picker1'); + + $('body').append($picker); + $picker.picker({ + explicit: true + }); + + $picker.find('.picker-trigger')[0].click(); + $('body').click(); + equal($picker.hasClass('showing'), true, 'externalClick ignored due to not being an explicit accept/cancel action'); + $picker.find('.picker-accept').click(); + equal($picker.hasClass('showing'), false, 'picker not showing after explicit action'); + + $picker.remove(); + }); + + test('should disable/enable as expected', function(){ + var $picker = $(html).find('#picker1'); + var $trigger = $picker.find('.picker-trigger'); + + $picker.picker('disable'); + equal($picker.hasClass('disabled'), true, 'disabled class properly added to element'); + equal($trigger.attr('disabled'), 'disabled', 'disabled attribute properly added to trigger'); + + $picker.picker('enable'); + equal($picker.hasClass('disabled'), false, 'disabled class properly removed from element'); + equal($trigger.attr('disabled'), undefined, 'disabled attribute properly removed from trigger'); + }); + + test("should destroy control", function () { + var $el = $(html).find('#picker1'); + + equal(typeof( $el.picker('destroy')) , 'string', 'returns string (markup)'); + equal( $el.parent().length, false, 'control has been removed from DOM'); + }); + +}); diff --git a/test/tests.html b/test/tests.html index 1ebda4a85..35ee2b179 100644 --- a/test/tests.html +++ b/test/tests.html @@ -96,6 +96,7 @@ 'fuelux/search': 'dist/js/fuelux', 'fuelux/selectlist': 'dist/js/fuelux', 'fuelux/spinbox': 'dist/js/fuelux', + 'fuelux/picker': 'dist/js/fuelux', 'fuelux/tree': 'dist/js/fuelux', 'fuelux/wizard': 'dist/js/fuelux' } diff --git a/test/tests.js b/test/tests.js index 3b96e441e..d311c26dd 100644 --- a/test/tests.js +++ b/test/tests.js @@ -6,7 +6,7 @@ define(function(require){ var $ = require('jquery'); QUnit.start(); // starting qunit, or phantom js will have a problem - + // Needed for saucelab testing var log = []; var testName; @@ -58,6 +58,7 @@ define(function(require){ require('./test/search-test'); require('./test/selectlist-test'); require('./test/spinbox-test'); + require('./test/picker-test'); require('./test/tree-test'); require('./test/wizard-test');