Skip to content

Instantly share code, notes, and snippets.

@brianjmiller
Created December 30, 2011 17:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianjmiller/1540779 to your computer and use it in GitHub Desktop.
Save brianjmiller/1540779 to your computer and use it in GitHub Desktop.
YUI: Single Template
YUI.add(
"ep-w-work_entry-base",
function (Y) {
var UI = Y.Widget.UI_SRC;
var MODE = "Mode";
var STATUS = "Status";
var WC_AC_SOURCE = "WorkChart/ac?";
var Clazz = Y.namespace("EP.W.WorkEntry").Base = Y.Base.create(
"ep-w-work_entry-base",
Y.Widget,
[ Y.MakeNode, Y.EP.ModelConsumer ],
{
_onBlurWCRestore: null,
_durationsTable: null,
initializer: function (config) {
Y.log(Clazz.NAME + "::initializer");
this._onBlurWCRestore = false;
var modelList = this.get("model").get("durations");
Y.log(Clazz.NAME + "::initializer - modelList: " + modelList);
this._durationsTable = new Y.EP.W.WorkEntry.Durations.Base (
{
modelList: modelList
}
);
},
renderUI: function () {
Y.log(Clazz.NAME + "::renderUI");
this._autoRenderUI();
var i;
var today = new Date ();
var datePerformed = this.get("model").get("date_performed");
for (i = (today.getFullYear() + 1); i >= 2001 ; i--) {
var option = Y.Node.create('<option value="' + i + '">' + i + '</option>');
if (i === datePerformed.getFullYear()) {
option.set("selected", "selected");
}
this._datePerformedSelectYearNode.append(option);
}
for (i = 1; i <= 12; i++) {
var value = i - 1;
var label = i;
if (String(label).length === 1) {
label = '0' + label;
}
var option = Y.Node.create('<option value="' + value + '">' + label + '</option>');
if (i === datePerformed.getMonth() + 1) {
option.set("selected", "selected");
}
this._datePerformedSelectMonthNode.append(option);
}
for (i = 1; i <= 31; i++) {
var value = i;
var label = i;
if (String(label).length === 1) {
label = '0' + label;
}
var option = Y.Node.create('<option value="' + value + '">' + label + '</option>');
if (i === datePerformed.getDate()) {
option.set("selected", "selected");
}
this._datePerformedSelectDayNode.append(option);
}
this._workChartInputNode.plug(
Y.Plugin.AutoComplete,
{
scrollIntoView: true,
queryDelay: 300,
minQueryLength: 3,
resultListLocator: "results",
resultTextLocator: "display_label",
source: WC_AC_SOURCE,
requestTemplate: Y.bind(
function (query) {
Y.log(Clazz.NAME + "::renderUI - AC requestTemplate: " + query);
var config_string = encodeURIComponent(
Y.JSON.stringify(
{
is_leaf: true,
partial: query
}
)
);
return "config=" + config_string;
},
this
)
}
);
// TODO: can we handle this through the existing status class set in syncUI?
if (this.get("model").get("status").code !== "new") {
this._workChartInputNode.addClass( this._classNames.workChartInputHidden );
}
else {
this._workChartNode.addClass( this._classNames.workChartHidden );
}
this._durationsTable.render(this._durationsContainerNode);
},
bindUI: function () {
Y.log(Clazz.NAME + "::bindUI");
var eh;
var bb = this.get("boundingBox");
eh = bb.on(
"hover",
function (e) {
//Y.log(Clazz.NAME + "::bindUI - bb hover enter");
this.focus();
},
function (e) {
//Y.log(Clazz.NAME + "::bindUI - bb hover exit");
this.blur();
},
this
);
this._eventHandles.push(eh);
eh = bb.delegate(
"click",
function (e) {
Y.log(Clazz.NAME + "::bindUI - work chart clicked");
this._workChartNode.addClass( this._classNames.workChartHidden );
this._workChartInputNode.removeClass( this._classNames.workChartInputHidden );
this._workChartInputNode.focus();
},
"div.yui3-ep-w-work_entry-base-formEditMode span.yui3-ep-w-work_entry-base-workChart",
this
);
this._eventHandles.push(eh);
this._workChartInputNode.ac.on(
"query",
function (e) {
Y.log(Clazz.NAME + "::bindUI - onQuery");
this._workChartInputNode.addClass("acLoading");
},
this
);
this._eventHandles.push(eh);
this._workChartInputNode.ac.after(
"results",
function (e) {
Y.log(Clazz.NAME + "::bindUI - afterResults");
this._workChartInputNode.removeClass("acLoading");
},
this
);
this._eventHandles.push(eh);
eh = this._workChartInputNode.ac.on(
[
"activeItemChange",
"hoveredItemChange"
],
function (e) {
if (e.newVal) {
Y.log(Clazz.NAME + "::bindUI - work chart item change: " + e.newVal.getContent());
this._onBlurWCRestore = true;
this._workChartNode.setContent(e.newVal.getContent());
}
},
this
);
this._eventHandles.push(eh);
eh = this._workChartInputNode.ac.after(
"select",
function (selection) {
Y.log(Clazz.NAME + "::bindUI - work chart AC selection");
Y.log(Clazz.NAME + "::bindUI - work chart AC selection: " + Y.dump(selection.result));
this._onBlurWCRestore = false;
this.get("model").set("work_chart", selection.result.raw.id);
//
// calling this directly isn't fun, but I was having problems getting the blur
// events to happen when I tried blurring the node directly
//
this._afterWorkChartInputBlur();
},
this
);
this._eventHandles.push(eh);
eh = this.after("ep-m-work_entry:destroy", this.destroy, this);
this._eventHandles.push(eh);
eh = this.after(
"ep-m-work_entry:statusChange",
function (e) {
Y.log(Clazz.NAME + "::bindUI - work entry:status change handler");
var bb = this.get("boundingBox");
bb.removeClass( this.getClassName(e.prevVal.code + STATUS) );
bb.addClass( this.getClassName(e.newVal.code + STATUS) );
},
this
);
this._eventHandles.push(eh);
eh = this.after(
"ep-m-work_entry:flat_feeChange",
function (e) {
Y.log(Clazz.NAME + "::bindUI - work entry:flat_fee change handler");
this._syncFlatFee();
},
this
);
this._eventHandles.push(eh);
eh = this.after(
[
"ep-m-work_entry:work_chartChange",
"ep-m-work_chart:change",
],
function (e) {
Y.log(Clazz.NAME + "::bindUI - work chart changes handler");
var full_label = "";
full_label = this.get("model").get("work_chart").full_label();
if (full_label !== "") {
this._workChartNode.setContent(full_label);
}
},
this
);
this._eventHandles.push(eh);
eh = this.after(
[
"ep-ml-work_entry-durations:add",
"ep-ml-work_entry-durations:reset",
"ep-ml-work_entry-durations:remove"
],
function (e) {
if (this.get("model").get("durations").size() === 1) {
this._durationsContainerNode.addClass( this._classNames.durationsSingle );
}
else {
this._durationsContainerNode.removeClass( this._classNames.durationsSingle );
}
},
this
);
this._eventHandles.push(eh);
eh = this.after(
"ep-m-work_entry:descriptionChange",
function (e) {
this._descriptionNode.setContent(this.get("model").get("htmlDescription"));
if (e.src !== UI) {
this._descriptionInputNode.setContent(e.newVal);
}
},
this
);
this._eventHandles.push(eh);
},
syncUI: function () {
Y.log(Clazz.NAME + "::syncUI");
var bb = this.get("boundingBox");
var cb = this.get("contentBox");
var m = this.get("model");
var wc = m.get("work_chart");
bb.addClass( this.getClassName(m.get("status").code + STATUS) );
cb.addClass( this.getClassName(this.get("mode") + MODE) );
if (wc) {
this._workChartNode.setContent( wc.full_label() );
}
this._syncFlatFee();
Y.log(Clazz.NAME + "::syncUI - durations size: " + m.get("durations").size());
if (m.get("durations").size() === 1) {
this._durationsContainerNode.addClass( this._classNames.durationsSingle );
}
},
_afterThisModeChange: function (e) {
Y.log(Clazz.NAME + "::_afterThisModeChange");
this.get("contentBox").removeClass( this.getClassName( e.prevVal + MODE ) );
this.get("contentBox").addClass( this.getClassName( e.newVal + MODE ) );
},
_afterEditButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterEditButtonClick");
e.preventDefault();
this.set("mode", "formEdit");
},
_afterDeleteButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterDeleteButtonClick");
e.preventDefault();
this.set("mode", "formDelete");
},
_afterSaveButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterSaveButtonClick");
this.get("model").save();
},
_afterConfirmButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterConfirmButtonClick");
Y.log(Clazz.NAME + "::_afterConfirmButtonClick - mode: " + this.get("mode"));
if (this.get("mode") === 'formDelete') {
//
// TODO: this seems backwards, shouldn't destroy only get called if the
// server delete works?
//
this.get("model").destroy(
{
delete: true
},
Y.bind(
function (err) {
Y.log(Clazz.NAME + "::_afterConfirmButtonClick - model destroy callback: " + err);
},
this
)
);
}
},
_afterDoneButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterDoneButtonClick");
e.preventDefault();
this.set("mode", "displayLong");
},
_afterCancelButtonClick: function (e) {
Y.log(Clazz.NAME + "::_afterCancelButtonClick");
e.preventDefault();
if (this.get("model").isNew()) {
this.get("model").destroy();
}
else {
this.set("mode", "displayLong");
}
},
_afterDurationsAllToggleClick: function (e) {
Y.log(Clazz.NAME + "::_afterDurationsAllToggleClick");
e.preventDefault();
this._durationsContainerNode.toggleClass(this._classNames.durationsShowAll);
},
_afterWorkChartInputBlur: function (e) {
Y.log(Clazz.NAME + "::_afterWorkChartInputBlur");
var wc = this.get("model").get("work_chart");
if (wc) {
if (this._onBlurWCRestore) {
this._workChartNode.setContent( wc.full_label() );
this._onBlurWCRestore = false;
}
this._workChartInputNode.addClass( this._classNames.workChartInputHidden );
this._workChartNode.removeClass( this._classNames.workChartHidden );
this._workChartInputNode.set("value", "");
}
},
_afterDescriptionInputValueChange: function (e) {
//Y.log(Clazz.NAME + "::_afterDescriptionInputValueChange");
this.get("model").set("description", e.newVal, { src: UI });
},
_syncFlatFee: function () {
Y.log(Clazz.NAME + "::_syncFlatFee");
if (Y.Lang.isValue(this.get("flat_fee")) && Number(this.get("flat_fee")) !== 0) {
this._flatFeeContainerNode.removeClass(this._classNames.zeroFlatFee);
}
else {
this._flatFeeContainerNode.addClass(this._classNames.zeroFlatFee);
}
}
},
{
ATTRS: {
strings: {
value: {
editButtonLabel: "Edit",
deleteButtonLabel: "Delete",
saveButtonLabel: "Save",
confirmButtonLabel: "Confirm",
doneButtonLabel: "Done",
cancelButtonLabel: "Cancel",
workChartLabel: "Work Chart",
datePerformedLabel: "Date Performed",
flatFeeLabel: "Flat Fee",
durationsLabel: "Durations",
durationsAllToggle: "+/-",
descriptionLabel: "Description"
}
},
model: { value: null, setter: '_setM', mClass: Y.EP.M.WorkEntry.Base },
mode: { value: 'displayLong' }
},
_CLASS_NAMES: [
"headerContainer",
"workChartContainer",
"workChartLabel",
"workChart",
"workChartInput",
"workChartHidden",
"workChartInputHidden",
"datePerformedContainer",
"datePerformedLabel",
"datePerformedInput",
"datePerformedSelectYear",
"datePerformedSelectMonth",
"datePerformedSelectDay",
"flatFeeContainer",
"flatFee",
"flatFeeLabel",
"flatFeeInput",
"zeroFlatFee",
"durationsContainer",
"durationsLabel",
"durationsAllToggle",
"durationsShowAll",
"durationsSingle",
"topButtonContainer",
"editButton",
"deleteButton",
"bodyContainer",
"description",
"descriptionLabel",
"descriptionInput",
"bottomButtonContainer",
"messageContainer",
"saveButton",
"doneButton",
"confirmButton",
"cancelButton"
],
_TEMPLATE: [
'<div class="{c headerContainer} yui3-u-3-4">',
'<div class="{c workChartContainer} yui3-u-1">',
'<label class="{c workChartLabel}">{s workChartLabel}</label>',
'<span class="{c workChart}"></span>',
'<input class="{c workChartInput}" />',
'</div>',
'<div class="{c datePerformedContainer} yui3-u-1">',
'<label class="{c datePerformedLabel}">{s datePerformedLabel}</label>',
'<span class="{c datePerformedInput}">',
'<select class="{c datePerformedSelectYear}"></select>',
'<select class="{c datePerformedSelectMonth}"></select>',
'<select class="{c datePerformedSelectDay}"></select>',
'</span>',
'</div>',
'<div class="{c flatFeeContainer} yui3-u-1">',
'<label class="{c flatFeeLabel}">{s flatFeeLabel}</label>',
'$<span class="{c flatFee}">{n @ model @ flat_fee}</span>',
'<input class="{c flatFeeInput} ledger_value" type="text" value="{n @ model @ flat_fee}" />',
'</div>',
'<div class="{c durationsContainer} yui3-u-1">',
'<label class="{c durationsLabel}">{s durationsLabel}</label>',
'<a class="{c durationsAllToggle}">{s durationsAllToggle}</a>',
'</div>',
'</div>',
'<div class="{c topButtonContainer} yui3-u-1-4">',
'<div style="border: 1px solid black;">',
'Status: {n @ model @ status p display_label}<br />',
'<button class="{c editButton}">{s editButtonLabel}</button>',
'<button class="{c deleteButton}">{s deleteButtonLabel}</button>',
'</div>',
'</div>',
'<div class="{c bodyContainer} yui3-u-1">',
'<p class="{c description}">{n @ model @ htmlDescription}</p>',
'<label class="{c descriptionLabel}">{s descriptionLabel}</label>',
'<textarea class="{c descriptionInput}">{n @ model @ description}</textarea>',
'</div>',
'<div class="{c bottomButtonContainer} yui3-u-1-3">',
'<button class="{c saveButton}">{s saveButtonLabel}</button>',
'<button class="{c confirmButton}">{s confirmButtonLabel}</button>',
'<button class="{c doneButton}">{s doneButtonLabel}</button>',
'<button class="{c cancelButton}">{s cancelButtonLabel}</button>',
'</div>',
'<div class="{c messageContainer} yui3-u-2-3"></div>'
].join(''),
_EVENTS: {
THIS: "modeChange",
editButton: "click",
deleteButton: "click",
saveButton: "click",
confirmButton: "click",
doneButton: "click",
cancelButton: "click",
durationsAllToggle: "click",
workChartInput: "blur",
descriptionInput: "valueChange"
}
}
);
},
"0.0.1",
{
requires: [
"ep-w-work_entry-base-css",
"widget",
"gallery-makenode",
"autocomplete-plugin",
"autocomplete-sources",
"event-hover",
"event-valuechange",
"ic-model-consumer",
"ep-w-work_entry-durations-base"
]
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment