google-nomulus/java/google/registry/ui/js/edit_item.js
Justine Tunney 5012893c1d mv com/google/domain/registry google/registry
This change renames directories in preparation for the great package
rename. The repository is now in a broken state because the code
itself hasn't been updated. However this should ensure that git
correctly preserves history for each file.
2016-05-13 18:55:08 -04:00

294 lines
8.7 KiB
JavaScript

// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('registry.EditItem');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('registry.Component');
goog.require('registry.soy.console');
goog.require('registry.util');
/**
* An editable item, with Edit and Save/Cancel buttons in the appbar.
* @param {!registry.Console} cons
* @param {function()} itemTmpl
* @constructor
* @extends {registry.Component}
*/
registry.EditItem = function(cons, itemTmpl) {
registry.EditItem.base(this, 'constructor', cons);
/**
* @type {!Function}
*/
this.itemTmpl = itemTmpl;
/**
* Optional current target resource id.
* @type {?string}
*/
this.id = null;
/**
* Transitional id for next resource during create.
* @type {?string}
*/
this.nextId = null;
};
goog.inherits(registry.EditItem, registry.Component);
/** @override */
registry.EditItem.prototype.bindToDom = function(id) {
registry.EditItem.base(this, 'bindToDom', id);
this.id = id;
this.nextId = null;
this.setupAppbar();
};
/** Setup appbar save/edit buttons. */
registry.EditItem.prototype.setupAppbar = function() {
goog.soy.renderElement(goog.dom.getRequiredElement('reg-appbar'),
registry.soy.console.appbarButtons);
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-add'),
goog.events.EventType.CLICK,
goog.bind(this.add, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-edit'),
goog.events.EventType.CLICK,
goog.bind(this.edit, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-save'),
goog.events.EventType.CLICK,
goog.bind(this.save, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-cancel'),
goog.events.EventType.CLICK,
goog.bind(this.cancel, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-back'),
goog.events.EventType.CLICK,
goog.bind(this.back, this));
if (this.id) {
registry.util.setVisible('reg-app-btns-edit', true);
} else {
registry.util.setVisible('reg-app-btn-add', true);
}
};
/**
* Retrieve item from server. Overrides should callback to {@code
* #handleFetchItem(string, !Object)}.
* @param {string} id item id.
*/
registry.EditItem.prototype.fetchItem = goog.abstractMethod;
/**
* Handle result decoding and display.
* @param {string} id The requested ID/name, for error message.
* @param {!Object} rsp The requested object.
*/
registry.EditItem.prototype.handleFetchItem = goog.abstractMethod;
/** Subclasses should override to continue processing after fetch. */
registry.EditItem.prototype.processItem = function() {};
/**
* Show the item.
* @param {!Object} objArgs
*/
registry.EditItem.prototype.renderItem = function(objArgs) {
goog.soy.renderElement(goog.dom.getRequiredElement('reg-content'),
this.itemTmpl,
objArgs);
};
/**
* @return {boolean} if the component is currently being edited.
*/
registry.EditItem.prototype.isEditing = function() {
return goog.dom.classlist.contains(
goog.dom.getElement('reg-app'), goog.getCssName('editing'));
};
/**
* Toggles the editing state of a component. This will first hide the
* elements of the {@code shown} class, then adds the {@code editing}
* style to the component, then shows the elements that had the {@code
* hidden} class.
*/
registry.EditItem.prototype.toggleEdit = function() {
// Toggle appbar buttons.
var addBtn = goog.dom.getRequiredElement('reg-app-btn-add');
var editBtns = goog.dom.getRequiredElement('reg-app-btns-edit');
var saveBtns = goog.dom.getRequiredElement('reg-app-btns-save');
var editing = goog.dom.classlist.contains(saveBtns,
registry.util.cssShown);
if (editing) {
registry.util.setVisible(saveBtns, false);
if (this.id) {
registry.util.setVisible(editBtns, true);
} else {
registry.util.setVisible(addBtn, true);
}
} else {
if (this.id) {
registry.util.setVisible(editBtns, false);
} else {
registry.util.setVisible(addBtn, false);
}
registry.util.setVisible(saveBtns, true);
}
// Then page contents.
var parentElt = goog.dom.getElement('reg-content');
var shownCssName = goog.getCssName('shown');
var hiddenCssName = goog.getCssName('hidden');
var shown = goog.dom.getElementsByClass(shownCssName, parentElt);
var hidden = goog.dom.getElementsByClass(hiddenCssName, parentElt);
for (var i = 0; i < shown.length; i++) {
goog.dom.classlist.addRemove(shown[i], shownCssName, hiddenCssName);
}
// Then add editing styles.
var editingCssName = goog.getCssName('editing');
var startingEdit = !goog.dom.classlist.contains(parentElt, editingCssName);
if (startingEdit) {
goog.dom.classlist.remove(parentElt, editingCssName);
} else {
goog.dom.classlist.add(parentElt, editingCssName);
}
// The show hiddens.
for (var i = 0; i < hidden.length; i++) {
goog.dom.classlist.addRemove(hidden[i], hiddenCssName, shownCssName);
}
};
/**
* Subclasses should override to enhance the default model.
* @return {!Object.<string, ?>}
*/
registry.EditItem.prototype.newModel = function() {
return {item: {}};
};
// N.B. setting these as abstract precludes their correct binding in
// setupAppbar.
/** Show add item panel. */
registry.EditItem.prototype.add = function() {};
/** Go back from item to collection view. */
registry.EditItem.prototype.back = function() {};
/** Sets up initial edit model state and then called edit(objArgs). */
registry.EditItem.prototype.edit = function() {
var objArgs = this.model;
if (objArgs == null) {
objArgs = this.newModel();
}
// XXX: This is vestigial. In the new msg format, this pollutes the
// server-model state. Should be carried elsewhere.
objArgs.readonly = false;
this.renderItem(objArgs);
this.setupEditor(objArgs);
this.toggleEdit();
};
/**
* Save the current item. Calls either create if creating a new
* object or update otherwise.
*/
registry.EditItem.prototype.save = function() {
if (this.model == null) {
this.sendCreate();
} else {
this.sendUpdate();
}
};
/**
* Resets to non-editing, readonly state, or visits home screen if the
* page was in on a create panel.
*/
registry.EditItem.prototype.cancel = function() {
this.toggleEdit();
// XXX: The presence of a model is sufficent for non-collection pages, but an
// empty id also means go to the collection in collection pages. Should
// be simplified.
if (this.model && this.id != '') {
this.model.readonly = true;
this.renderItem(this.model);
} else {
this.bindToDom('');
}
};
/**
* Called after this.renderItem(), to allow for further setup of
* editing.
* @param {!Object} objArgs
*/
registry.EditItem.prototype.setupEditor = function(objArgs) {};
// XXX: These should really take @param {object} which is the form. Alas the
// only override which doesn't work this way, ResourceComponent.sendCreate
// breaks this opportunity. Hmmm...
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendCreate = goog.abstractMethod;
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendUpdate = goog.abstractMethod;
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendDelete = goog.abstractMethod;
/**
* Sublcasses should override to populate update queryParams with form
* fields as needed. {@code queryParams.nextId} MUST be set to the
* new object's ID.
* @param {!Object} queryParams
*/
registry.EditItem.prototype.prepareUpdate = goog.abstractMethod;
/**
* Subclasses should provide a funtion to parse either XML or JSON response
* from server and return a result object as described below.
* @param {!Object} rsp Decoded XML/JSON response from the server.
* @return {!Object} a result object describing next steps. On
* success, if next is defined, visit(ret.next) is called, otherwise
* if err is set, the butterbar message is set to it.
*/
registry.EditItem.prototype.handleUpdateResponse = goog.abstractMethod;