Skip to content

Instantly share code, notes, and snippets.

@apipkin
Created March 3, 2010 02:09
Show Gist options
  • Save apipkin/320226 to your computer and use it in GitHub Desktop.
Save apipkin/320226 to your computer and use it in GitHub Desktop.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Lister</title>
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.0.0/build/cssreset/reset-min.css"/>
<script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>
<script>
YUI({
filter : 'raw',
modules : {
'lister' : {
'fullpath' : './lister.js',
'requires' : ['test','node','io','json-parse','plugin','dd-constrain','dd-drop','dd-proxy','dd-plugin']
}
}
}).use('lister',function(Y){
Y.on('domready',function() {
var l = new Y.Lister()
.fetchCategories()
.fetchItems();
});
});
</script>
<style>
form {
padding: 10px;
}
dt, dd {
float:left;
padding:0 10px 10px 0;
}
dt {
clear:both;
}
fieldset {
float:left;
padding:0 20px 0 0;
}
.lister-item {
margin:4px 0;
padding: 4px;
border: 1px solid #fff;
width: 250px;
cursor:pointer;
}
.active {
background-color: lightblue;
border-color:blue;
}
.lister-filtered {
display:none;
}
fieldset div {
clear:left;
}
</style>
</head>
<body>
<div id="pageWrapper">
<div id="page">
<div id="bodyWrapper">
<div id="body">
<form>
<fieldset>
<dl>
<dt><label for="category">Category</label></dt>
<dd><select id="category"><option>All Categories</option></select></dd>
<dd><input type="button" value="fetch" id="category_btn"/></dd>
<dt><label for="filter">Filter</label></dt>
<dd><input type="text" id="filter" name="filter"/></dd>
<dd><input type="button" value="filter" id="filter_btn"/></dd>
</dl>
<div id="available"></div>
</fieldset>
<fieldset>
<ul>
<li><input type="button" value="->|" id="add_all_btn"/></li>
<li><input type="button" value="->" id="add_btn"/></li>
<li><input type="button" value="<-" id="remove_btn"/></li>
<li><input type="button" value="|<-" id="remove_all_btn"/></li>
</ul>
</fieldset>
<fieldset>
<div id="chosen"></div>
</fieldset>
</form>
</div><!-- /body -->
</div><!-- /bodyWrapper -->
</div><!-- /page -->
</div><!-- /pageWrapper -->
</body>
</html>
<?php
$items = array(
'states' => array(
array('id' => '10', 'name' => 'Georgia'),
array('id' => '11', 'name' => 'Florida'),
array('id' => '12', 'name' => 'Alabama'),
array('id' => '13', 'name' => 'Alaska'),
array('id' => '14', 'name' => 'Arizona'),
array('id' => '15', 'name' => 'New York'),
array('id' => '16', 'name' => 'New Jersey'),
array('id' => '17', 'name' => 'New Hamshire')
), 'animals' => array(
array('id' => '20', 'name' => 'dog'),
array('id' => '21', 'name' => 'cat'),
array('id' => '22', 'name' => 'horse'),
array('id' => '23', 'name' => 'rabbit'),
array('id' => '24', 'name' => 'hamster')
), 'drinks' => array(
array('id' => '30', 'name' => 'Coke'),
array('id' => '31', 'name' => 'Sprite'),
array('id' => '32', 'name' => 'Mellow Yellow'),
array('id' => '33', 'name' => 'Barq')
)
);
$categories = array_keys($items);
header('Content-type: application/json');
if(isset($_GET['category']) && array_key_exists($_GET['category'],$items)) {
echo json_encode($items[$_GET['category']]);
}elseif(isset($_GET['mode']) && $_GET['mode'] === 'c') {
echo json_encode($categories);
}else{
echo json_encode($items);
}
YUI.add('lister',function(Y){
var Lister,
CLASSES = {
filtered : 'lister-filtered'
},
setFromNode = function(node) {
var n = Y.one(node);
if (!n) {
Y.fail('Lister: Invalid Node Given: ' + node);
}
return n;
},
isArray = Y.Lang.isArray,
Lister = function(config){
Lister.superclass.constructor.apply(this, arguments);
}
;
Y.mix(Lister,{
NAME : 'lister',
NS : 'lister',
CLASSES : CLASSES,
ATTRS : {
items : {
value : {}
},
used : {
value : []
},
available : {
setter: setFromNode,
value : '#available'
},
chosen : {
setter: setFromNode,
value : '#chosen'
},
categories : {
setter: setFromNode,
value : '#category'
},
fetchButton : {
setter: setFromNode,
value : '#category_btn'
},
filterField : {
setter: setFromNode,
value : '#filter'
},
filterButton : {
setter: setFromNode,
value : '#filter_btn'
},
addAllButton : {
setter: setFromNode,
value : '#add_all_btn'
},
addButton : {
setter: setFromNode,
value : '#add_btn'
},
removeAllButton : {
setter: setFromNode,
value : '#remove_all_btn'
},
removeButton : {
setter: setFromNode,
value : '#remove_btn'
},
categoryUrl : {
value : './list-items.php?mode=c'
},
itemUrl : {
value : './list-items.php'
},
itemTemplate : {
value : '<div class="lister-item">{name}</div>'
}
}
});
Y.extend(Lister,Y.Base,{
initializer : function(config) {
Y.log('Lister::initializer','info');
var cat = this.get('categories');
Y.delegate('click',function(e){
e.currentTarget.toggleClass('active');
},Y.one('body'),'.lister-item',this);
this.get('categories').on('change',this.updateItems,this);
this.get('fetchButton').on('click',this.updateItems,this);
this.get('filterField').on('keyup',this.filterItems,this);
this.get('filterButton').on('click',this.filterItems,this);
this.get('addAllButton').on('click',this.itemAddAll,this);
this.get('addButton').on('click',this.itemAdd,this);
this.get('removeButton').on('click',this.itemRemove,this);
this.get('removeAllButton').on('click',this.itemRemoveAll,this);
return this;
},
destructor : function() {
Y.log('Lister::destructor','info');
},
itemAdd : function(e) {
Y.log('Lister::itemAdd','info');
this.get('available').all('.active').each(function(item){
if(item.hasClass(CLASSES.filtered)) {
return;
}
this.get('chosen').append(item);
item.removeClass('active');
var index = this._search(item.get('id'), this.get('used'));
Y.log(index + " : " + item.get('id'));
if(index < 0) {
this.get('used').push(item.get('id'));
}
},this);
},
itemRemove : function (e) {
Y.log('Lister::removeItem','info');
this.get('chosen').all('.active').each(function(item){
this.get('available').append(item);
item.removeClass('active');
var index = this._search(item.get('id'), this.get('used'));
Y.log(index + " : " + item.get('id'));
if(index >= 0) {
this.get('used').splice(index,1);
}
},this);
},
itemAddAll : function(e) {
Y.log('Lister::itemAddAll','info');
this.get('available').all('.lister-item').each(function(item){
if(item.hasClass(CLASSES.filtered)) {
return;
}
this.get('chosen').append(item);
var index = this._search(item.get('id'), this.get('used'));
Y.log(index + " : " + item.get('id'));
if(index < 0) {
this.get('used').push(item.get('id'));
}
},this);
},
itemRemoveAll : function(e) {
Y.log('Lister::itemRemoveAll','info');
this.get('chosen').all('.lister-item').each(function(item){
this.get('available').append(item);
var index = this._search(item.get('id'), this.get('used'));
Y.log(index + " : " + item.get('id'));
if(index >= 0) {
this.get('used').splice(index,1);
}
},this);
},
filterItems : function(e){
Y.log('Lister::filterItems','info');
this.filter(this.get('filterField').get('value'));
},
filter : function(value) {
Y.log(CLASSES.filtered);
Y.log('Lister::filter','info');
if(!value) {
this.get('available').all('.' + CLASSES.filtered).removeClass(CLASSES.filtered);
}else{
value = value.toLowerCase();
this.get('available').all('.lister-item').each(function(o){
var item = this.get('items')[o.get('id')];
if(item && item.name.toLowerCase().indexOf(value) >= 0) {
o.removeClass(CLASSES.filtered);
}else{
o.addClass(CLASSES.filtered);
}
},this);
}
},
fetchCategories : function() {
Y.log('Lister::fetchCategories','info');
var catIO = {
on : {
success : Y.bind(this._retrieveCategories, this)
}
};
Y.io(this.get('categoryUrl'),catIO);
var chosen = this.get('chosen');
return this;
},
fetchItems : function(url) {
Y.log('Lister::fetchItems','info');
return this;
},
updateItems : function(e) {
Y.log('Lister::_updateItems','info');
var itemIO = {
on : {
success : Y.bind(this._retrieveItems, this)
}
};
Y.io(this.get('itemUrl') + '?category=' + this.get('categories').get('value'), itemIO);
},
_retrieveCategories : function(id,o,args) {
Y.log('Lister::_retrieveCategories','info');
var json = Y.JSON.parse(o.responseText);
var cat = this.get('categories');
cat.set('innerHTML','').append('<option>All Categories</option>');
for(var o in json) {
cat.append('<option>' + json[o] + '</option>');
}
cat.set('selectedIndex',0);
},
_retrieveItems : function (id, o, args) {
Y.log('Lister::_retrieveItems','info');
this.get('available').set('innerHTML','');
this.set('items',{});
var json = Y.JSON.parse(o.responseText);
if(isArray(json)) {
this._itemsArrayToList(json);
}else{
for(var o in json) {
this._itemsArrayToList(json[o]);
}
}
this.filterItems();
},
_itemsArrayToList : function (items) {
Y.log('Lister::_itemsArrayToList','info');
for(var i=0,l=items.length; i < l; i++) {
var nodeString = Y.substitute(this.get('itemTemplate'),items[i]);
var node = Y.Node.create(nodeString);
var nodeId = Y.Event.generateId(node);
if(items[i].id) {
nodeId = 'lister-item-' + items[i].id;
}
Y.log(nodeId);
node.set('id', nodeId);
this.get('items')[nodeId] = items[i];
if(this._search(nodeId, this.get('used')) >= 0){
continue;
}
this.get('available').append(node);
}
Y.log(this.get('items'));
},
_setItems : function(obj) {
Y.log('Lister::_setItems','info');
},
_setFromNode : function(node) {
var n = Y.one(node);
if(!n) {
Y.fail('Lister::_setFromNode: Invalid Node Given: ' + node);
}
return n;
},
_search : function(needle, haystack) {
for(var i = 0; i < haystack.length; i++) {
if(haystack[i] === needle) {
return i;
}
}
return -1;
}
});
Y.Lister = Lister;
},'0.1',{requires:['substitue','test','node','io','json-parse','plugin','dd-constrain','dd-drop','dd-proxy','dd-plugin']});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment