diff options
| author | Alon Levy <alon@pobox.com> | 2015-04-06 11:43:16 +0300 |
|---|---|---|
| committer | Alon Levy <alon@pobox.com> | 2015-04-06 11:43:16 +0300 |
| commit | 3ae06034b88e7a9887a1c9fb2f5e623cd9469669 (patch) | |
| tree | f4fcf31e491ded0f747538af683322bdad0730ba /src/client/view/item_info.js | |
| parent | cadfc79763a9c5c7473ca8ab764a0f9c56b125c1 (diff) | |
client: property tab cleanup; resolve #396
Diffstat (limited to 'src/client/view/item_info.js')
| -rw-r--r-- | src/client/view/item_info.js | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/src/client/view/item_info.js b/src/client/view/item_info.js new file mode 100644 index 00000000..1f187ce0 --- /dev/null +++ b/src/client/view/item_info.js @@ -0,0 +1,276 @@ +define(['jquery', 'jquery-ui', 'util', 'consts', 'view/helpers', 'model/diff', 'model/types'], +function($, _unused_jquery_ui, util, consts, view_helpers, model_diff, model_types) { + +var DEBOUNCE_TIME = 500; // milliseconds + +var item = null, + msg_node = $('.info-card-message'), + graph, + setup_done = false, + info = $('#info'), + info_container = $('.info-container'), + form_element = $('#editbox'), + delete_button = $('#edit-dialog__delete'), + form = _.object(model_types.all_attributes.map(function (attr) { + var element = edit_element_for_attribute(attr); + + if (element.length == 0) { + element = form_add_element(attr, 'textarea'); + } + return [attr, element]; + })), + change_handlers = [], + status_display = info.find('#displaystatus'), + status = info.find('#editstatus'); + +/** + * Adds the div with the label, return the edit child + */ +function form_add_element(attr, value_element_type) +{ + var div = $('<div></div>'), + label = $('<label></label>'), + value = $('<' + value_element_type + '></' + value_element_type + '>'), + delete_button = form_element.find('#info-container__bottom-btn-bar'); + + div.attr('id', attr); + label.addClass('info-card-attr'); + label.text(model_types.attribute_titles[attr] + ':'); + value.addClass('info-card-attr-val'); + value.attr('id', 'edit' + attr); + div.append(label); + div.append(value); + div.insertBefore(delete_button); + return value; +} + +function clean_url(candidate_url) +{ + if (candidate_url.length == 0) { + return ''; + } + if (candidate_url.search('://') != -1) { + return candidate_url; + } + return 'https://' + candidate_url; +} + +function _get_form_data() { + var ret = _.object(_.keys(form),_.values(form).map(function (x) { return x.val(); })); + + ret.url = clean_url(ret.url); + return ret; +} + +function is_node(item) +{ + return item.__src === undefined; +} + +function update_item(item, new_data) +{ + if (is_node(item)) { + graph.update_node(item, new_data); + } else { + graph.update_link(item, new_data); + } +} + +function commit() +{ + if (item === null) { + return; + } + update_item(item, _get_form_data()); +} + +function textarea_resize(text, max) +{ + var height; + text.style.height = 'auto'; + height = text.scrollHeight; + if (max) { + height = Math.min(max, height); + } + text.style.height = height + 'px'; +} + +function setup_change_handlers() +{ + disable_change_handlers(); + // auto save after DEBOUNCE_TIME inactivity + var streams = _.map(_.values(form), function (element) { + return element.asEventStream('change input keyup'); + }); + var single = _.reduce(streams, function (stream_a, stream_b) { return stream_a.merge(stream_b); }); + change_handlers = [single.debounce(DEBOUNCE_TIME).onValue(function () { + commit(); + })]; +} + +function disable_change_handlers() +{ + _.each(change_handlers, function (unsub) { unsub(); }); + change_handlers = []; +} + +function delete_item() +{ + if (is_node(item)) { + graph.nodes__delete([item.id]); + } else { + graph.links__delete([item.id]); + } +} + +/** + * XXX + * need to update fields iff there have been no new input events associated with them since commit. + * do not look at contents because that will exist in the past too. + * + * see Bacon.awaiting. + * + * For now we just show a warning instead telling the user the dialog is not up to date. + */ +function setup_click_handlers() +{ + setup_change_handlers(); + if (setup_done) { + return; + } + setup_done = true; + form_element.on('keydown', function (e) { + if (e.which == consts.VK_ENTER && e.target !== delete_button[0]) { + e.preventDefault(); + } + }); + delete_button.on('click', function (e) { + var msg = is_node(item) ? 'delete node?' : 'delete link?'; + + e.preventDefault(); + hide(); + if (confirm(msg)) { + delete_item(item); + } + }); + $('#edit-dialog__save').on('click', function (e) { + e.preventDefault(); + hide(); + commit(); + }); + + // warn user if the item has been changed while open + diffBusUnsubscribe = graph.diffBus.onValue(function (diff) { + var removed_set = is_node(item) ? diff.node_id_set_rm : diff.link_id_set_rm, + changed_set = is_node(item) ? diff.id_to_node_map : diff.id_to_link_map; + + if (model_diff.is_topo_diff(diff) && _.contains(removed_set, item.id)) { + warning('!! item has been deleted !!'); + return; + } + if (model_diff.is_attr_diff(diff) || _.contains(_.keys(changed_set), item.id)) { + warning('!! item has been changed !!'); + return; + } + }); +} + +function warning(string) +{ + msg_node.text(string); +} + +function base_element_for_attribute(attr) +{ + return info.find('#' + attr); +} + +function edit_element_for_attribute(attr) +{ + return info.find('#edit' + attr); +} + +function update_textarea(textarea, value) +{ + textarea.val(value); + textarea_resize(textarea[0], 150); +} + +function show(_graph, new_item, visible_attributes) +{ + var visible_attributes, + hidden_attributes, + visible_elements, + hidden_elements, + max_height; + + visible_attributes = visible_attributes || model_types.type_attributes(new_item.type).slice(0); + hidden_attributes = _.difference(model_types.all_attributes, visible_attributes), + visible_elements = visible_attributes.map(base_element_for_attribute); + hidden_elements = hidden_attributes.map(base_element_for_attribute); + warning(''); // reset warning + graph = _graph; + item = new_item; + util.assert((is_node(item) ? graph.find_node__by_id : graph.find_link__by_id)(item.id) != null); + + setup_click_handlers(); + + _.each(hidden_elements, function (element) { element.hide(); }); + _.each(visible_elements, function (element) { element.show(); }); + + info.attr('class', 'info'); + info.addClass('type-' + item.type); // Add a class to distinguish types for css + + // hack - should be able to set max-height via css percentage, no? + max_height = $(document.body).innerHeight() - $('.info')[0].getBoundingClientRect().top * 2; + info_container[0].style['max-height'] = String(max_height) + 'px'; + + info_container.show(); + console.log(visible_attributes); + console.log(hidden_attributes); + _.each(visible_attributes, function (attr) { + var element = edit_element_for_attribute(attr); + value = item[attr]; + + switch (attr) { + case 'enddate': + case 'startdate': + element.datepicker({ + inline: true, + showOtherMonths: true, + dayNamesMin: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + }); + break; + case 'name': + case 'description': + update_textarea(element, value); + break; + case 'status': + if (_.contains(rz_config.role_set, 'admin')) { + status.val(item.status); + status.show(); + status_display.hide(); + } else { + status_display.text(item.status); + status.hide(); + status_display.show(); + } + break; + } + if (element.val !== undefined) { + element.val(value); + } + }); +} + +function hide() { + item = null; + info_container.hide(); +} + +return { + show: show, + hide: hide, +}; + +}); |
