Commit: 23609c81b59a1c6168d94a034e91b6f16d0ef2c5

Author: Nate Abele | Date: 2010-01-21 15:27:37 -0500
Implemented dynamic field editing, collection reloading, and added button bar.
diff --git a/config/routes.php b/config/routes.php index a3d5448..675c332 100644 --- a/config/routes.php +++ b/config/routes.php @@ -37,6 +37,6 @@ Router::connect('/test', array('controller' => '\lithium\test\Controller')); */ Router::connect('/{:controller}/{:action}/{:id}.{:type}', array('id' => null)); Router::connect('/{:controller}/{:action}/{:id}'); -Router::connect('/{:controller}/{:action}/{:args}'); +Router::connect('/{:controller}/{:action}/{:id}/{:args}'); ?> \ No newline at end of file diff --git a/controllers/CollectionsController.php b/controllers/CollectionsController.php index d032945..4df414d 100644 --- a/controllers/CollectionsController.php +++ b/controllers/CollectionsController.php @@ -23,6 +23,13 @@ class CollectionsController extends \lithium\action\Controller { public function index() { $collections = Connections::get('default')->entities(); + + if ($this->request->is('ajax')) { + $this->render(array( + 'template' => '../elements/collections', 'data' => compact('collections') + )); + return; + } return compact('collections'); } @@ -30,6 +37,41 @@ class CollectionsController extends \lithium\action\Controller { $data = Collection::all(array('source' => $this->request->id)); return compact('data'); } + + public function edit() { + $path = $this->request->args; + $_id = array_shift($path); + + $item = $document = Collection::first(array( + 'source' => $this->request->id, + 'conditions' => compact('_id') + )); + + foreach (array_slice($path, 0, -1) as $key) { + $item =& $item[$key]; + } + $key = end($this->request->args); + + if ($item->{$key} == $this->request->data['old']) { + $item->{$key} = $this->request->data['data']; + $document->save(); + $this->render(array('text' => $this->request->data['data'])); + return; + } + $this->render(array('text' => $this->request->data['old'])); + } + + protected function _coerceType($data) { + switch ($data) { + case 'null': + return null; + case 'true': + return true; + case 'false': + return false; + } + return is_numeric($data) ? floatval($data) : $data; + } } ?> \ No newline at end of file diff --git a/views/collections/index.html.php b/views/collections/index.html.php index c00acef..3a967b4 100644 --- a/views/collections/index.html.php +++ b/views/collections/index.html.php @@ -2,14 +2,5 @@ </div> <div id="groups"> - <ul> - <li class="title">Collections</li> - <?php foreach ($collections as $collection) { ?> - <li class="collection"> - <?=$this->html->link($collection, array( - 'controller' => 'collections', 'action' => 'view', 'id' => $collection - )); ?> - </li> - <?php } ?> - </ul> + <?=$this->view()->render(array('element' => 'collections'), compact('collections')); ?> </div> diff --git a/views/collections/view.html.php b/views/collections/view.html.php index ebe2861..9140d76 100644 --- a/views/collections/view.html.php +++ b/views/collections/view.html.php @@ -2,10 +2,11 @@ use \lithium\data\model\Document; -$list = function($data) use (&$list, $h) { +$list = function($data, $topLevel = false) use (&$list, $h) { echo "<ul>"; foreach ($data as $key => $value) { - echo '<li><div class="key">' . $h($key) . '</div>: '; + echo '<li' . ($topLevel ? ' class="document"' : '') . '>'; + echo '<div class="key' . ($key === '_id' ? ' id' : '') . '">' . $h($key) . '</div>: '; echo '<div class="value">'; switch (true) { @@ -19,13 +20,13 @@ $list = function($data) use (&$list, $h) { echo 'null'; break; default: - $list($value); + $list($value, false); break; } echo '</div></li>'; } echo "</ul>"; }; -$list($data); +$list($data, true); ?> diff --git a/views/elements/collections.html.php b/views/elements/collections.html.php new file mode 100644 index 0000000..e1e9a4d --- /dev/null +++ b/views/elements/collections.html.php @@ -0,0 +1,10 @@ +<ul> + <li class="title">Collections</li> + <?php foreach ($collections as $collection) { ?> + <li class="collection"> + <?=$this->html->link($collection, array( + 'controller' => 'collections', 'action' => 'view', 'id' => $collection + )); ?> + </li> + <?php } ?> +</ul> diff --git a/views/layouts/default.html.php b/views/layouts/default.html.php index 7fe984d..f31066a 100644 --- a/views/layouts/default.html.php +++ b/views/layouts/default.html.php @@ -5,6 +5,17 @@ * @copyright Copyright 2009, Union of RAD (http://union-of-rad.org) * @license http://opensource.org/licenses/bsd-license.php The BSD License */ + +use \lithium\http\Router; + +$urls = array( + 'index' => Router::match(array('controller' => 'collections'), $this->request()), + 'edit' => Router::match( + array('controller' => 'collections', 'action' => 'edit', 'id' => ':col', 'args' => ':args'), + $this->request() + ), +); + ?> <!doctype html> <html> @@ -13,6 +24,9 @@ <title>MongoDB > <?=$this->title; ?></title> <?=$this->html->style(array('base', 'detail', 'jquery.treeview')); ?> <?=$this->html->script(array('jquery', 'app')); ?> + <script type="text/javascript"> + urls = <?php echo json_encode($urls); ?>; + </script> </head> <body class="app"> <div id="container"> @@ -22,7 +36,14 @@ <div id="layout"> <?=$this->content; ?> </div> - <div id="footer"></div> + <div id="footer"> + <div class="button-bar"> + <button id="AddCollection" title="Add collection"></button> + <button id="RefreshCollections" title="Refresh collections"></button> + <button id="SelectDatabase" title="Select database"></button> + </div> + <span class="status"></span> + </div> </div> </body> </html> diff --git a/webroot/css/base.css b/webroot/css/base.css index b1243fa..e479d9e 100644 --- a/webroot/css/base.css +++ b/webroot/css/base.css @@ -13,6 +13,10 @@ a:link, a:visited, a:active { color: blue; } +*:focus { + outline: none; +} + pre { font-size: 80%; color: #000; @@ -144,28 +148,57 @@ pre { position: absolute; float: left; width: 100%; - height: 22px; + height: 24px; bottom: 0; font-size: 11px; + padding-top: 4px; margin-top: -32px; - padding-top: 8px; text-align: center; background: #C0C0C0 url(../img/footer-gradient.png); font-family: Lucida Grande, Lucida, sans-serif; } -#footer ul { +#footer .status { + display: block; + margin-top: 4px; +} + +.button-bar { + padding: 1px 0 0 40px; + float: left; +} + +.button-bar button { + height: 19px; + width: 39px; padding: 0; - margin: 1px; + border: 0; + margin: 0 -3px 0 0; + border-style: none; } -#footer li { - font-size: 70%; - color: #000; - text-align: center; - padding: 3px; - display: block; +#AddCollection { + background: url(../img/add.png) no-repeat 0 0; + width: 40px; } -#footer li.bold { - font-weight: bold; + +#AddCollection.pressed { + background-image: url(../img/add-click.png); } + +#RefreshCollections { + background: url(../img/refresh.png) no-repeat 0 0; +} + +#RefreshCollections.pressed { + background-image: url(../img/refresh-click.png); +} + +#SelectDatabase { + background: url(../img/select.png) no-repeat 0 0; +} + +#SelectDatabase.pressed { + background-image: url(../img/select-click.png); +} + diff --git a/webroot/css/detail.css b/webroot/css/detail.css index 7950a86..cd3ffac 100644 --- a/webroot/css/detail.css +++ b/webroot/css/detail.css @@ -20,15 +20,20 @@ width: 150px; color: purple; overflow: hidden; - padding-left: 15px; + padding: 0 0 3px 25px; background-repeat: no-repeat; - background-position: 50% left; + background-position: 8px 50%; cursor: pointer; } .tree .value { display: inline; clear: right; + cursor: pointer; +} + +.tree .value ul { + cursor: default; } .tree .key.open { diff --git a/webroot/img/add-click.png b/webroot/img/add-click.png new file mode 100644 index 0000000..bcf0d76 Binary files /dev/null and b/webroot/img/add-click.png differ diff --git a/webroot/img/add.png b/webroot/img/add.png new file mode 100644 index 0000000..2ebc24e Binary files /dev/null and b/webroot/img/add.png differ diff --git a/webroot/img/arrow.png b/webroot/img/arrow.png new file mode 100644 index 0000000..7275b5a Binary files /dev/null and b/webroot/img/arrow.png differ diff --git a/webroot/img/refresh-click.png b/webroot/img/refresh-click.png new file mode 100644 index 0000000..71d9558 Binary files /dev/null and b/webroot/img/refresh-click.png differ diff --git a/webroot/img/refresh.png b/webroot/img/refresh.png new file mode 100644 index 0000000..32d7c34 Binary files /dev/null and b/webroot/img/refresh.png differ diff --git a/webroot/img/select-click.png b/webroot/img/select-click.png new file mode 100644 index 0000000..24fe166 Binary files /dev/null and b/webroot/img/select-click.png differ diff --git a/webroot/img/select.png b/webroot/img/select.png new file mode 100644 index 0000000..009a028 Binary files /dev/null and b/webroot/img/select.png differ diff --git a/webroot/js/app.js b/webroot/js/app.js index a587074..7ce4d49 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -1,30 +1,93 @@ -$(document).ready(function() { - $collections = $('.collection a'); +App = { + start: function() { + $collections = $('.collection a'); - $collections.bind('click', function() { - $('.collection').removeClass('selected'); - $self = $(this); + $collections.bind('click', function() { + $('.collection').removeClass('selected'); + $self = $(this); - $('#main').load(this.href, null, function() { - $self.parent().addClass('selected'); - $('#main > ul').tree(); + $('#main').load(this.href, null, function() { + $self.parent().addClass('selected'); + $('#main > ul').tree(); + }); + return false; }); - return false; + }, + status: function() { + $collections = $('.collection a'); + text = " collection" + ($collections.length == 1 ? "" : "s") + " in database"; + $('#footer .status').text($collections.length + text); + }, + collections: { + refresh: function() { + $('#groups').load(location.toString(), {}, function() { + App.start(); + App.status(); + }); + }, + add: function() { + '<li class="collection"><input type="text" id="ColName" /></li>'; + $('#groups > ul').append() + } + } +}; + +$(document).ready(function() { + + $('.button-bar button').bind('mousedown', function() { + $(this).toggleClass('pressed'); + }).bind('mouseup', function() { + $(this).toggleClass('pressed'); + }); + + $('#RefreshCollections').bind('click', function() { + App.collections.refresh(); }); - text = " collection" + ($collections.length == 1 ? "" : "s") + " in database"; - $('#footer').text($collections.length + text); + App.start(); + App.status(); }); jQuery.fn.tree = function(config) { $keys = jQuery(this).addClass('tree').find(".value ul").hide().parent().prev(".key"); $keys.addClass("closed").bind('click', function() { - if ($(this).hasClass('closed')) { - $(this).next('.value').find('> ul').show(); - } else { - $(this).next('.value').find('> ul').hide(); + $self = jQuery(this); + $self.next('.value').find('> ul')[$self.hasClass('closed') ? 'show' : 'hide'](); + $self.toggleClass('closed').toggleClass('open'); + }); + + jQuery(this).find('.value:not(:has(ul))').bind('click', function() { + if ($(this).find('input').length > 0) { + return true; } - $(this).toggleClass('closed').toggleClass('open'); + old = jQuery(this).text(); + $in = jQuery(this).html('<input type="text" class="edit" value="" />').find('input'); + + $in.val(old).focus().bind('blur', function(e) { + val = $(this).val(); + $node = $(this).parent(); + $(this).parent().text(); + + mapper = function() { return encodeURIComponent($(this).text()); }; + path = $node.parents('ul').parent().prev('.key').map(mapper).toArray(); + path.push(encodeURIComponent($node.prev('.key').text())); + path.shift(); + path = '/' + path.join('/'); + + _id = $node.parents('.document').find('.key.id:first').next('.value').text(); + url = urls.edit.replace(':col', jQuery("#groups .selected a").text()); + url = url.replace(':args', encodeURIComponent(_id) + path); + data = { data: val, old: old }; + + $.post(url, data, function(text) { + $node.html(text); + }); + }).bind('keyDown', function(e) { + if (e.keyCode == 32) { + $(this).blur(); + } + return true; + }) }); };