-
-
Save christocracy/977765 to your computer and use it in GitHub Desktop.
Some ext code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @overview FeatureForm.js | |
* Collection of components related to Feature Forms | |
* @author Dave Lazar | |
*/ | |
/** | |
* @namespace CCA.feature | |
*/ | |
Ext.namespace('CCA.feature'); | |
/** | |
* this is an Ext 2.2 override to allow us to use radio buttons with a name feature[foo] | |
* from forums: http://www.extjs.com/forum/showthread.php?p=210602#post210602 | |
*/ | |
Ext.DomQuery.matchers[2].re = /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?(?:"(.*?)"|'(.*?)'|(.*?)))?[\]\}])/; | |
Ext.override(Ext.form.Radio, { | |
getGroupValue : function(){ | |
var c = this.getParent().child('input[name="'+this.el.dom.name+'"]:checked', true); | |
return c ? c.value : null; | |
}, | |
toggleValue : function() { | |
if(!this.checked){ | |
var els = this.getParent().select('input[name="'+this.el.dom.name+'"]'); | |
els.each(function(el){ | |
if(el.dom.id == this.id){ | |
this.setValue(true); | |
}else{ | |
Ext.getCmp(el.dom.id).setValue(false); | |
} | |
}, this); | |
} | |
}, | |
setValue : function(v){ | |
if(typeof v=='boolean') { | |
Ext.form.Radio.superclass.setValue.call(this, v); | |
} else { | |
var r = this.getParent().child('input[name="'+this.el.dom.name+'"][value="'+v+'"]', true); | |
if(r && !r.checked){ | |
Ext.getCmp(r.id).toggleValue(); | |
}; | |
} | |
} | |
}); | |
Ext.form.FileUploadField = Ext.extend(Ext.form.TextField, { | |
/** | |
* @cfg {String} buttonText The button text to display on the upload button (defaults to | |
* 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text | |
* value will be used instead if available. | |
*/ | |
buttonText: 'Browse...', | |
/** | |
* @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible | |
* text field (defaults to false). If true, all inherited TextField members will still be available. | |
*/ | |
buttonOnly: false, | |
/** | |
* @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field | |
* (defaults to 3). Note that this only applies if {@link #buttonOnly} = false. | |
*/ | |
buttonOffset: 3, | |
/** | |
* @cfg {Object} buttonCfg A standard {@link Ext.Button} config object. | |
*/ | |
// private | |
readOnly: true, | |
/** | |
* @hide | |
* @method autoSize | |
*/ | |
autoSize: Ext.emptyFn, | |
// private | |
initComponent: function(){ | |
Ext.form.FileUploadField.superclass.initComponent.call(this); | |
this.addEvents( | |
/** | |
* @event fileselected | |
* Fires when the underlying file input field's value has changed from the user | |
* selecting a new file from the system file selection dialog. | |
* @param {Ext.form.FileUploadField} this | |
* @param {String} value The file value returned by the underlying file input field | |
*/ | |
'fileselected' | |
); | |
}, | |
// private | |
onRender : function(ct, position){ | |
Ext.form.FileUploadField.superclass.onRender.call(this, ct, position); | |
this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'}); | |
this.el.addClass('x-form-file-text'); | |
this.el.dom.removeAttribute('name'); | |
this.fileInput = this.wrap.createChild({ | |
id: this.getFileInputId(), | |
name: this.name||this.getId(), | |
cls: 'x-form-file', | |
tag: 'input', | |
type: 'file', | |
size: 1 | |
}); | |
var btnCfg = Ext.applyIf(this.buttonCfg || {}, { | |
text: this.buttonText | |
}); | |
this.button = new Ext.Button(Ext.apply(btnCfg, { | |
renderTo: this.wrap, | |
cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '') | |
})); | |
if(this.buttonOnly){ | |
this.el.hide(); | |
this.wrap.setWidth(this.button.getEl().getWidth()); | |
} | |
this.fileInput.on('change', function(){ | |
var v = this.fileInput.dom.value; | |
if (this.isPermittedFileType(v)) { | |
this.setValue(v); | |
this.fireEvent('fileselected', this, v); | |
} else { | |
Ext.Msg.alert(App.STATUS_NOTICE, "Not an allowed upload filetype"); | |
} | |
}, this); | |
}, | |
// private | |
getFileInputId: function(){ | |
return this.id+'-file'; | |
}, | |
// private | |
onResize : function(w, h){ | |
Ext.form.FileUploadField.superclass.onResize.call(this, w, h); | |
this.wrap.setWidth(w); | |
if(!this.buttonOnly){ | |
var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset; | |
this.el.setWidth(w); | |
} | |
}, | |
// private | |
preFocus : Ext.emptyFn, | |
// private | |
getResizeEl : function(){ | |
return this.wrap; | |
}, | |
// private | |
getPositionEl : function(){ | |
return this.wrap; | |
}, | |
// private | |
alignErrorIcon : function(){ | |
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]); | |
}, | |
isPermittedFileType : function(filename) { | |
var result = true; | |
var p = this.getPermissions(this.permittedExtensions) || []; | |
if (p.length > 0) { | |
result = p.indexOf(this.getFileExtension(filename)) != -1; | |
} | |
return result; | |
}, | |
getPermissions : function (type) { | |
switch (type) { | |
case 'video': | |
case 'videos': | |
return ['avi', 'AVI', 'mpg','MPEG', 'mpeg', 'mp4', 'MP4', 'MPEG4','mpeg4', 'flv', 'FLV', 'wmv', 'WMV']; | |
break; | |
case 'image': | |
case 'images': | |
return ['jpg', 'JPG', 'JPEG', 'jpeg', 'GIF', 'gif', 'BMP', 'bmp', 'TIFF', 'tiff', 'PNG', 'png']; | |
break; | |
case 'audio': | |
return ['mp3', 'MP3', 'MPEG3', 'mpeg3', 'FLAC', 'flac', 'OGG', 'ogg', 'THEORA', 'theora']; | |
break; | |
case 'document': | |
case 'documents': | |
return ['doc', 'DOC', 'pdf', 'PDF', 'zip', 'ZIP', 'sit', 'SIT']; | |
break; | |
} | |
}, | |
getFileExtension : function(filename) { | |
var result = null; | |
var parts = filename.split('.'); | |
if (parts.length > 1) { | |
result = parts.pop(); | |
} | |
return result; | |
} | |
}); | |
Ext.reg('fileuploadfield', Ext.form.FileUploadField); | |
// globally set validation messages to appear on side of field | |
Ext.form.Field.prototype.msgTarget = 'side'; | |
CCA.feature.TemplateHelper = function () { | |
return { | |
/** | |
* formatBody | |
* shrink the incoming string down to some reasonable size | |
* @param {String} input | |
*/ | |
formatBody : function (input, size) { | |
return Ext.util.Format.ellipsis(input, size); | |
}, | |
/** | |
* getMediaFields | |
* the incoming type here will be Audio, Video, Image, Slideshow or OtherMedia.. and this collection was prepped by the server... | |
* we also remove the file upload field since it makes no sense inside the nice template | |
* @param {Object} type | |
*/ | |
getMediaFields : function(type) { | |
var fields = CCA.feature.MediaFieldMgr.get(type); | |
var filtered = []; | |
for (var i = 0, len = fields.length; i < len; i++) { | |
if(fields[i].xtype != 'fileuploadfield') { | |
filtered.push(fields[i]) | |
} | |
} | |
return filtered; | |
}, | |
/** | |
* getEntityFields | |
* this is used to provide a form without an upload field | |
* @param {Object} type | |
*/ | |
getEntityFields : function(type) { | |
var fields = CCA.feature.EntityFieldMgr.get(type); | |
var filtered = []; | |
for (var i = 0, len = fields.length; i < len; i++) { | |
if(fields[i].xtype != 'fileuploadfield') { | |
filtered.push(fields[i]) | |
} | |
} | |
return filtered; | |
}, | |
/** | |
* getAllEntityFields | |
* this is used to list ALL the fields an entity has | |
* @param {Object} type | |
*/ | |
getAllEntityFields : function(type) { | |
return CCA.feature.EntityFieldMgr.get(type); | |
}, | |
/** | |
* formatEntityField | |
* for now return thumbs.. but we might have to just return the original link | |
* @param {Object} thumb | |
* @param {Object} original | |
*/ | |
formatEntityField : function (thumb, original) { | |
return '<img src="'+thumb+'" />'; | |
}, | |
isLink : function (value) { | |
return (value === 'Link')? true : false; | |
}, | |
isOtherMedia : function (value) { | |
return (value == 'OtherMedia')? true : false; | |
}, | |
isCopyrightCleared : function(value) { | |
return (value)? App.t("y") : App.t("n"); | |
}, | |
isRepresentative : function(value) { | |
return (value)? App.t("y") : App.t("n"); | |
}, | |
isImage : function (type) { | |
return (type == 'Image')? true : false; | |
}, | |
isAudio : function (type) { | |
return (type == 'Audio')? true : false; | |
}, | |
isVideo : function (type) { | |
return (type == 'Video')? true : false; | |
}, | |
isSlideshow : function (type) { | |
return (type == 'Slideshow')? true : false; | |
}, | |
hasVideoThumb : function (values) { | |
return ( values.type == 'Video' && values.thumb != '')? true : false; | |
} | |
} | |
}(); | |
/** | |
* CCA.feature.Form | |
* General feature form. produces form for all types of features. | |
* NOTE: Dealing with publications is a little weird... it is a serialized object, so it will not render | |
* without a little extra processing in the case where the Feature is a Publication... | |
*/ | |
CCA.feature.Form = Ext.extend(Ext.form.FormPanel, { | |
/** | |
* @cfg {String} featureType [required] | |
*/ | |
frame: false, | |
border: false, | |
autoScroll: true, | |
controller: 'feature', | |
// delete is handled through the grid at this time | |
actions: { | |
insert: 'insert', | |
update: 'update' | |
}, | |
bodyStyle: 'padding:10px', | |
labelAlign: 'right', | |
// these come in for use through the constructor | |
record: null, | |
entities: null, | |
roles: null, | |
// private | |
initComponent: function(){ | |
this.header = false; | |
// set css class (normally would place this above in @cfg props but doesn't work there??) | |
this.cls = 'cca-feature-form'; | |
// build the form for a Generic Feature | |
this.items = this.build(); | |
CCA.feature.Form.superclass.initComponent.call(this); | |
this.form.baseParams = { | |
"type": this.record.data.type | |
}; | |
}, | |
/** | |
* setValues | |
* In cases of publication, we need to strip off the publication key from data, and map it to the | |
* form fields which are not keyed off of the prefix 'feature', but 'feature_publication' | |
* Event Features send along a bunch of dates and times, which will need to be assigned carefully as well | |
* Look for key event_dates:[] to populate the Dates,Admissions, Locations | |
* @param {Object} data | |
*/ | |
setValues: function(data){ | |
/** | |
* take advantage of our utility singleton to ensure the content is displayed in the correct language | |
*/ | |
var currLang = CCA.feature.Util.getContentLanguage(); | |
//console.log('currLang for the form set values is ', currLang); | |
if (!this.controller) { | |
this.form.setValues(data); | |
return true; | |
} | |
values = {}; | |
for (var key in data) { | |
switch (key) { | |
case 'lang': | |
// 'lang' key identifies a key of an array of translated strings. | |
// Ex: lang :{'en':{'title': 'English title'}, 'subtitle': 'English sub'}, | |
// {'fr':{'title': 'Titre français'}, 'subtitle': 'Soustitre français'}} | |
for (var aLocale in data[key]) { | |
for (var aColumn in data[key][aLocale]){ | |
elname = '[lang]['+aLocale+']['+aColumn+']'; | |
values[this.controller + elname] = data['lang'][aLocale][aColumn]; | |
} | |
} | |
break; | |
case 'publication': | |
// strip off all the keys inside publication and setup the form elements | |
for ( var p in data[key][currLang]) { | |
values['feature_publication['+p+']'] = data[key][currLang][p]; | |
} | |
break; | |
case 'layout': | |
// strip off all the keys inside layout key and setup the form elements | |
for ( var p in data[key] ) { | |
// The editor in chief can add template from a different category | |
// If it's the case, we must add manually this template | |
// in the combo... | |
if (p=='template') { | |
var combo = Ext.getCmp('template_combo_' + data.id); | |
var keyFound = false; | |
Ext.each(combo.store.data.keys, function(k){ | |
if (k == data[key][p]) | |
keyFound = true; | |
}); | |
if (!keyFound) { | |
Ext.each(this.record.data.layouts, function(l){ | |
if (l[0] == data[key][p]) { | |
var TemplateRecord = Ext.data.Record.create([ | |
{name: 'id', mapping: 'id'}, | |
{name: 'name', mapping: 'name'} | |
]); | |
var newRecord = new TemplateRecord({ | |
id: l[0], | |
name: l[1] | |
}); | |
combo.store.add(newRecord); | |
} | |
}); | |
} | |
} | |
values['feature_layout['+p+']'] = data[key][p]; | |
} | |
break; | |
default: | |
values[this.controller + '[' + key + ']'] = data[key]; | |
break; | |
} | |
} | |
this.form.setValues(values); | |
if (this.record.data.type == 'Event' || this.record.data.type == 'Series') { | |
var adm = this.findById('admission_'+this.record.data.id); | |
if (adm) { | |
var dates = adm.findByType('eventdate'); // <=== as many eventdate panels as were built need to be filled | |
if (dates) { | |
for (var i = 0, len = dates.length; i< len; i++) { | |
dates[i].setValues(this.record.data.event_dates[i]); | |
} | |
} | |
} | |
} | |
}, | |
/** | |
* hasUnsavedData | |
* This method checks if any data in the form has changed since editing | |
* returns true if the data has changed. | |
* @param {Object} data | |
*/ | |
hasUnsavedData: function(){ | |
var formValues = this.form.getValues(); | |
var currLang = CCA.feature.Util.getContentLanguage(); | |
var hasChanged = false; | |
for (var key in this.record.data) { | |
switch (key) { | |
case 'lang': | |
/* | |
for (var aLocale in this.record.data[key]) { | |
for (var aColumn in this.record.data[key][aLocale]){ | |
elname = '[lang]['+aLocale+']['+aColumn+']'; | |
values[this.controller + elname] = this.record.data['lang'][aLocale][aColumn]; | |
} | |
} | |
*/ | |
break; | |
case 'publication': | |
for ( var p in this.record.data[key][currLang]) { | |
var formValue = formValues['feature_publication[' + p + ']']; | |
if (formValue != null && typeof(formValue) != 'undefined') { | |
var recValue = this.record.data[key][currLang][p]; | |
if(recValue != null && typeof(recValue) != 'undefined') { | |
if (formValue != recValue) | |
hasChanged = true; | |
} | |
} | |
} | |
break; | |
case 'layout': | |
for ( var p in this.record.data[key] ) { | |
var formValue = formValues['feature_layout[' + p + ']']; | |
if (formValue != null && typeof(formValue) != 'undefined') { | |
var recValue = this.record.data[key][p]; | |
if(recValue != null && typeof(recValue) != 'undefined') { | |
if (formValue != recValue) | |
hasChanged = true; | |
} | |
} | |
} | |
break; | |
case 'event_dates': | |
var startDate = Date.parseDate(formValues['feature[start_date]'], 'd/m/Y'); | |
if(startDate == null || typeof(startDate) == 'undefined'){ | |
startDate = ''; | |
} else { | |
startDate = startDate.format('Y-m-d'); | |
} | |
var endDate = Date.parseDate(formValues['feature[end_date]'], 'd/m/Y'); | |
if(endDate == null || typeof(endDate) == 'undefined'){ | |
endDate = ''; | |
} else { | |
endDate = endDate.format('Y-m-d'); | |
} | |
var startTime = formValues['feature[start_time]']; | |
var endTime = formValues['feature[end_time]']; | |
for ( var p in this.record.data[key] ) { | |
if(typeof(this.record.data[key][p]) == 'object'){ | |
var sd = this.record.data[key][p]['sd']; | |
var st = this.record.data[key][p]['st']; | |
var ed = this.record.data[key][p]['ed']; | |
var et = this.record.data[key][p]['et']; | |
if(sd != null && typeof(sd) != 'undefined') { | |
if (sd != startDate) | |
hasChanged = true; | |
} | |
if(ed != null && typeof(ed) != 'undefined') { | |
if (ed != endDate) | |
hasChanged = true; | |
} | |
if(st != null && typeof(st) != 'undefined' && | |
startTime != null && typeof(startTime) != 'undefined') { | |
if (st != startTime) | |
hasChanged = true; | |
} | |
if(et != null && typeof(et) != 'undefined' && | |
endTime != null && typeof(endTime) != 'undefined') { | |
if (et != endTime) | |
hasChanged = true; | |
} | |
} | |
} | |
break; | |
default: | |
// there is an array for event dates | |
if(key == 'start_date' || key == 'start_time' || | |
key == 'end_date' || key == 'end_time') | |
break; | |
var formValue = formValues['feature[' + key + ']']; | |
if(formValue != null && typeof(formValue) != 'undefined') { | |
var recValue = this.record.data[key]; | |
if(recValue != null && typeof(recValue) != 'undefined') { | |
if (formValue != recValue) | |
hasChanged = true; | |
} | |
} | |
break; | |
} | |
} | |
/* | |
if (this.record.data.type == 'Event') { | |
var adm = this.findById('admission_'+this.record.data.id); | |
if (adm) { | |
var dates = adm.findByType('eventdate'); // <=== as many eventdate panels as were built need to be filled | |
if (dates) { | |
for (var i = 0, len = dates.length; i< len; i++) { | |
dates[i].setValues(this.record.data.event_dates[i]); | |
} | |
} | |
} | |
} | |
*/ | |
return hasChanged; | |
}, | |
/** | |
* save | |
*/ | |
save: function() { | |
if (this.form.isValid()) { | |
if (this.record.data.type == 'Event' || this.record.data.type == 'Series') { | |
var adm = this.findById('admission_'+this.record.data.id); | |
if (adm) { | |
var dates = adm.findByType('eventdate'); | |
if (dates) { | |
date_data = []; | |
for (var i = 0, len = dates.length; i< len; i++) { | |
date_data.push(dates[i].getValues()); | |
dates[i].disableFields(); | |
} | |
} | |
} | |
this.form.baseParams = {eventdates: Ext.encode(date_data)}; | |
} | |
App.showSpinner('save'); | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.update + '/' + this.record.data.id, | |
success: function(form, action){ | |
/** | |
* once the form has been saved, turn on the date and time fields again | |
*/ | |
if (this.record.data.type == 'Event' || this.record.data.type == 'Series') { | |
this.enableDateTime(); | |
} | |
// update the record in the Grid, which is not re-loaded in case the panel is re-loaded after closing | |
this.record.beginEdit(); | |
Ext.apply(this.record.data,action.result.data.feature); | |
this.record.endEdit(); | |
this.record.commit(); | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
/** | |
* once the form has been saved, turn on the date and time fields again | |
*/ | |
if (this.record.data.type == 'Event' || this.record.data.type == 'Series') { | |
this.enableDateTime(); | |
} | |
App.processResponse(action); | |
}, | |
scope: this | |
}); | |
} else { | |
App.setAlert(App.t('NOTICE'), "The Basic Form has a field not validating"); | |
} | |
}, | |
/** | |
* once the form has been saved, turn on the date and time fields again | |
*/ | |
enableDateTime : function () { | |
var adm = this.findById('admission_'+this.record.data.id); | |
if (adm) { | |
var dates = adm.findByType('eventdate'); | |
if (dates) { | |
for (var i = 0, len = dates.length; i< len; i++) { | |
dates[i].enableFields(); | |
} | |
} | |
} | |
}, | |
refreshTemplateCombo: function(checkBox) { | |
var combo = Ext.getCmp('template_combo_' + this.record.data.id); | |
var templateData = this.record.data.layouts; | |
function getTemplateDataSubset(start, end) { | |
var newArray = new Array(); | |
for(i=start; i<=end; i++) | |
newArray.push(templateData[i]); | |
return newArray; | |
} | |
switch(checkBox.inputValue) { | |
case 1: | |
combo.store.loadData(getTemplateDataSubset(3, 5)); | |
break; | |
case 2: | |
combo.store.loadData(getTemplateDataSubset(0, 2)); | |
break; | |
case 3: | |
combo.store.loadData(getTemplateDataSubset(8, 9)); | |
break; | |
case 4: | |
combo.store.loadData(getTemplateDataSubset(10, 11)); | |
break; | |
case 5: | |
combo.store.loadData(getTemplateDataSubset(6, 7)); | |
break; | |
} | |
combo.clearValue(); | |
}, | |
buildCategories: function () { | |
var obj = this; | |
var cid = this.record.data.category_id; | |
var items = []; | |
if (CCA.feature.Util.getCategorizations(this.record.data.content_language).getCount()) { | |
CCA.feature.Util.getCategorizations(this.record.data.content_language).each(function(c){ | |
items.push({ | |
xtype: 'radio', | |
fieldLabel: c.name, | |
name: 'feature[category_id]', | |
inputValue: c.id, | |
checked: (cid == c.id)? true : false, | |
listeners: { | |
'check': function(cb, isChecked){ | |
if (isChecked && CCA.feature.Util.getAccountProfile() != 'profile.admin' && CCA.feature.Util.getAccountProfile() != 'profile.guest_writer') | |
obj.refreshTemplateCombo(cb); | |
}, | |
'render': function(cb){ | |
if (cb.checked && CCA.feature.Util.getAccountProfile() != 'profile.admin' && CCA.feature.Util.getAccountProfile() != 'profile.guest_writer') | |
obj.refreshTemplateCombo(cb); | |
} | |
} | |
}); | |
}, this); | |
} | |
var radios = { | |
xtype: 'radiogroup', | |
labelSeparator: '', | |
columns: 3, | |
anchor: '99%', | |
items: items | |
} | |
var fieldset = { | |
xtype: 'fieldset', | |
labelWidth: 1, | |
layout: 'form', | |
title: App.t('category'), | |
autoHeight: true, | |
items: radios | |
} | |
return fieldset; | |
}, | |
/** | |
* build | |
* provides the form where all the most general details of a Feature are displayed | |
*/ | |
build: function(){ | |
// these are all the roles that can be assigned to this puppy | |
// rolename is simply a convenience to map the type which is 'CollectionStory' to 'collection' | |
var roles = []; // store the 'id' and 'identifier' from the collection for the dropdown | |
var role_collection = CCA.feature.Util.getFeatureRoles(this.record.data.content_language).filter('prefix', this.record.data.rolename); | |
role_collection.each(function(r){ | |
roles.push([r.id, r.label]); | |
}); | |
var combo = { | |
xtype: 'rolecombo', | |
roles: roles, | |
emptyText: App.t('select_type') | |
}; | |
var content = { | |
xtype: 'feature_content', | |
id: 'feature_content_' + this.record.data.id, | |
feature_id: this.record.data.id, | |
title: App.t('feature_content'), | |
data: this.record.data.paragraphs | |
} | |
this.record.data.layouts = [['layouts/_exhibitionA1.liquid', 'Exhibition A1'], | |
['layouts/_exhibitionA2.liquid', 'Exhibition A2'], | |
['layouts/_exhibitionA5.liquid', 'Exhibition A5'], | |
['layouts/_collectionB2.liquid', 'Collection B2'], | |
['layouts/_collectionB3.liquid', 'Collection B3'], | |
['layouts/_collectionB5.liquid', 'Collection B5'], | |
['layouts/_recommendsC2.liquid', 'CCA Recommends C2'], | |
['layouts/_recommendsC3.liquid', 'CCA Recommends C3'], | |
['layouts/_educationD1.liquid', 'Education & Events D1'], | |
['layouts/_educationD4.liquid', 'Education & Events D4'], | |
['layouts/_studycentreE2.liquid', 'Study Centre E2'], | |
['layouts/_studycentreE3.liquid', 'Study Centre E3']]; | |
var tplStore = new Ext.data.SimpleStore({ | |
fields: ['id', 'name'], | |
id: 0 | |
}); | |
if (CCA.feature.Util.getAccountProfile() == 'profile.admin' || CCA.feature.Util.getAccountProfile() == 'profile.guest_writer') | |
tplStore.loadData(this.record.data.layouts); | |
var templateCombo = { | |
xtype: 'combo', | |
hiddenName: 'feature_layout[template]', | |
hiddenId: Ext.id(), | |
emptyText: App.t('select_template'), | |
fieldLabel: App.t('template'), | |
id: 'template_combo_' + this.record.data.id, | |
mode: 'local', | |
store: tplStore, | |
valueField: 'id', | |
displayField: 'name', | |
triggerAction: 'all', | |
value: '' | |
} | |
var themeStore = new Ext.data.SimpleStore({ | |
fields: ['id', 'name'], | |
data:[['blank','Default'], ['dark','Inverted'], ['accent','Accented-Green']], | |
id: 0 | |
}); | |
var themeCombo = { | |
xtype: 'combo', | |
hiddenName: 'feature_layout[theme]', | |
hiddenId: Ext.id(), | |
emptyText: App.t('select_theme'), | |
fieldLabel: App.t('theme'), | |
id: 'theme_combo_'+this.record.data.id, | |
mode: 'local', | |
store: themeStore, | |
triggerAction: 'all', | |
value: '', | |
valueField: 'id', | |
displayField: 'name', | |
autoWidth:false, | |
width:120 | |
} | |
var contentStore = new Ext.data.SimpleStore({ | |
fields: ['id', 'name'], | |
data: [['images','Images'], ['slideshow','SlideShow + anything'], ['video','Video + Images']], | |
id: 0 | |
}); | |
var contentCombo = { | |
xtype: 'combo', | |
hiddenName: 'feature_layout[content]', | |
hiddenId: Ext.id(), | |
emptyText: App.t('select_content'), | |
fieldLabel: App.t('content_kind'), | |
id: 'kind_combo_' + this.record.data.id, | |
mode: 'local', | |
store: contentStore, | |
valueField: 'id', | |
displayField: 'name', | |
triggerAction: 'all', | |
value: '' | |
} | |
var formItems = [ | |
// <=== outer panel container is a column layout ultimately holding two panels | |
{ | |
xtype: 'panel', | |
anchor: '99%', | |
border: false, | |
titleCollapse: true, | |
collapsible: true, | |
title: App.t('general'), | |
layout: 'column', | |
iconCls: 'icon-text-signature', | |
bodyStyle: 'padding: 5px', | |
items: [{ | |
layout: 'form', | |
frame: true, | |
columnWidth: 0.5, | |
style: 'margin-right: 10px', | |
items: [{xtype: 'publishedurl', record: this.record},{ | |
xtype: 'textfield', | |
fieldLabel: App.t('title'), | |
name: 'feature[title]', | |
allowBlank: false, | |
blankText: App.t('required_title'), | |
anchor: '99%' | |
}, { | |
xtype: 'textfield', | |
name: 'feature[subtitle]', | |
fieldLabel: App.t('subtitle'), | |
anchor: '99%' | |
}, { | |
xtype: 'textarea', | |
name: 'feature[synopsis]', | |
fieldLabel: App.t('synopsis'), | |
allowBlank: true, | |
grow: true, | |
growMax: 200, | |
anchor: '99%' | |
}, combo] | |
},{ | |
layout: 'form', | |
columnWidth: 0.5, | |
frame: true, | |
anchor: '90%', | |
items: [{ | |
xtype: 'fieldset', | |
title: 'Layout Settings', | |
autoHeight: true, | |
items: [templateCombo,themeCombo] | |
},this.buildCategories()] | |
}]// <== two columns closed | |
}]; | |
// Add the date selector if necessary | |
// note that we can provide translations via the constructor | |
if(this.record.data.dateable) { | |
formItems.push(new CCA.feature.AdmissionForm({ | |
id: 'admission_'+this.record.data.id, | |
title: App.t('event_dates'), | |
data: this.record.data.event_dates | |
}, this)); | |
} | |
if(this.record.data.type == 'Publication') { | |
formItems.push(new CCA.feature.PublicationForm({title: App.t('publication')})); | |
} | |
formItems.push(content); | |
return formItems; | |
}, | |
// private | |
onInsert: function(btn, ev){ | |
App.showSpinner('saving'); | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.insert | |
}); | |
this.form.on('actioncomplete', function(form, action){ | |
App.hideSpinner(); | |
}); | |
}, | |
// onCancel | |
onCancel: function(btn, ev){ | |
this.stopMonitoring(); | |
if (this.useDialog == true) { | |
//this.dialog.hide(); | |
this.dialog.close(); | |
} | |
this.fireEvent('cancel', this); | |
}, | |
/** | |
* onSave | |
* we are inside an Ext.form.FormPanel here, so we are not able to nest in a FormPanel | |
* so instead we will use Ajax to build up the Feature Content | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onSave : function (btn, ev) { | |
var text = Ext.getCmp('content_'+this.record.data.id); | |
var value = text.getValue(); | |
if (value.length) { | |
App.showSpinner('save'); | |
App.request({ | |
url: this.controller + '/' + 'insert_content' + '/' + this.record.data.id, | |
method: 'POST', | |
// perhaps we are too liberal just allowing any old text to be created :) | |
params: {body: value}, | |
success: function(res){ | |
if (res.success == true) { | |
// get the dataview... | |
// add the resulting text to it... | |
text.setValue(""); | |
} | |
}, | |
scope: this | |
}); | |
} | |
} | |
}); | |
Ext.reg('featureform', CCA.feature.Form); | |
/** | |
* CCA.feature.EntityPanel | |
* note: these entity panels know about the feature they belong to via the feature_id | |
*/ | |
CCA.feature.EntityPanel = Ext.extend(Ext.Panel, { | |
controller: 'feature', | |
actions: { | |
'reorder': 'reorder_entity', | |
'delete': 'delete_entity', | |
'load': 'load_entity' | |
}, | |
/** | |
* @cfg {String} templateId | |
* default template id to retrieve from TemplateMgr | |
*/ | |
templateId : 'feature_entity_template', | |
entity: null, | |
layout: 'form', | |
autoScroll: true, | |
frame: false, | |
// FeatureEntityType mapping to iconCls | |
iconMap: { | |
'Quote': 'icon-comments', | |
'DateAdmission': 'icon-date', | |
'Organizer': 'icon-shield', | |
'Sponsor': 'icon-money', | |
'Subject': 'icon-user', | |
'Item': 'icon-package', | |
'Credit': 'icon-award-gold', | |
'SeriesEpisode': 'icon-film-add' | |
}, | |
/** | |
* @cfg {Integer} feature_id | |
* This entity's associated Feature id | |
*/ | |
initComponent: function(){ | |
this.title = App.t(this.entity.type); | |
this.iconCls = this.iconMap[this.entity.type]; | |
// register this entity's fields with EntityFieldMgr singleton. this is to assist in XTemplate rendering. | |
CCA.feature.EntityFieldMgr.register(this.entity.type, this.entity.fields); | |
this.items = [this.buildView()]; | |
var dragdrop = new RExt.DataView.Orderable({ | |
listeners: { | |
order: function (view, startIndex,records) { | |
rs = []; | |
for (var i = 0, len = records.length; i < len; i++) { | |
rs.push({ | |
id: records[i].data.id, | |
position: i+startIndex | |
}); | |
} | |
App.request({ | |
url: this.controller + '/' + this.actions.reorder, | |
params: { | |
data: Ext.encode(rs) | |
}, | |
success: function (res) { | |
//console.log('Success', res); | |
}, | |
failure: function (res) { | |
//console.log('bummer', res); | |
} | |
}); | |
}, | |
scope: this | |
} | |
}); | |
this.plugins = dragdrop; | |
CCA.feature.EntityPanel.superclass.initComponent.call(this); | |
this.on('render', function () { | |
Ext.dd.ScrollManager.register(this.body); | |
}, this); | |
}, | |
buildView: function(){ | |
var store = new Ext.data.Store({ | |
reader: new Ext.data.ArrayReader({ | |
record: 'entity' | |
}, CCA.data.FeatureEntity), | |
data: this.entity.data || [], | |
baseParams: {}, | |
sortInfo: { | |
field: 'position', | |
direction: 'ASC' | |
} | |
}); | |
// make a ptr to fields. this is for the XTemplate function getFields | |
var fields = this.entity.fields; | |
var tools = new RExt.DataViewEditor({ | |
actions: { | |
edit: 'edit_entity', | |
"delete": 'delete_entity', | |
load: 'load_entity' | |
}, | |
listeners: { | |
'edit' : function(view, index, node, ev) { | |
this.onEdit(view, index, node, ev); | |
}, | |
'delete' : function(view, index, node, ev) { | |
this.onDelete(view, index, node, ev); | |
}, scope: this | |
} | |
}); | |
// create view | |
var view = new Ext.DataView({ | |
id: this.id + '_view', | |
controller: this.controller, | |
store: store, | |
tpl: this.getTemplate(), | |
singleSelect: true, | |
overClass: 'x-grid3-row-over', | |
itemSelector: 'div.feature-entity', | |
dropZoneCls: 'dropzone', | |
selectedClass: 'x-grid3-row-selected', | |
emptyText: '<h2>No items added</h2><h3 class="icon-information r-icon-text">You may add any number of items.</h3>', | |
plugins: tools | |
}); | |
return view; | |
}, | |
getTemplate : function() { | |
return RExt.util.TemplateMgr.get((RExt.util.TemplateMgr.exists(this.entity.type + '_entity_template')) ? this.entity.type + '_entity_template' : this.templateId); | |
}, | |
/** | |
* getView | |
* returns attached DataView | |
* @return {Ext.DataView} | |
*/ | |
getView: function(){ | |
return this.findByType(Ext.DataView).shift(); | |
}, | |
/** | |
* getValues | |
* returns array of added Entities | |
* @return {Hash} | |
*/ | |
getValues: function(){ | |
var rs = []; | |
this.getView().store.each(function(rec){ | |
rs.push(rec.data.form); | |
}); | |
return { | |
type: this.entity.type, | |
data: rs | |
}; | |
}, | |
/** | |
* onEdit | |
* 'edit' tool clicked on a row in a DataView | |
* @param {Object} view | |
* @param {Object} index | |
* @param {Object} node | |
* @param {Object} ev | |
*/ | |
onEdit : function(view, index, node, ev) { | |
var record = view.store.getAt(index); | |
var fpanel = Ext.getCmp('entity_edit_'+this.feature_id); | |
fpanel.layout.activeItem.doEdit(this, record); | |
return; | |
}, | |
/** | |
* onDelete | |
* remove a an entity from a Feature | |
* @param {Ext.DataView} view | |
* @param {Number} index | |
* @param {HTMLElement} node | |
* @param {Ext.EventObject} ev | |
*/ | |
onDelete : function(view, index, node, ev) { | |
Ext.MessageBox.confirm('Confirm', 'Delete Entity?', function(btn) { | |
if (btn == 'yes') { | |
var rec = view.store.getAt(index); | |
App.request({ | |
url: this.controller + '/' + this.actions['delete'] + '/' + rec.data.id, | |
method: 'POST', | |
success:function(res) { | |
view.store.remove(rec); | |
}, | |
failure: function(res) { | |
App.setAlert('STATUS_ERROR', res.data.msg); | |
} | |
}); | |
} | |
},this); | |
} | |
}); | |
/** | |
* CCA.data.Insitution | |
* data.Record for Institution combo | |
*/ | |
CCA.data.Institution = Ext.data.Record.create([ | |
{ name: 'id'}, | |
{ name: 'name'} | |
]); | |
/** | |
* CCA.feature.EntityEditForm | |
* allows us to edit existing entity records without uploader fields etc... | |
*/ | |
CCA.feature.EntityEditForm = Ext.extend(Ext.form.FormPanel, { | |
controller: 'feature', | |
actions: { | |
insert: 'create_entity', | |
update: 'update_entity' | |
}, | |
defaults: { | |
anchor: '96%' | |
}, | |
feature_id: null, | |
fileUpload:true, | |
labelAlign: 'right', | |
frame: true, | |
border: false, | |
header: false, | |
/** | |
* @cfg {String} fieldPrefix | |
* the Rails-style prefix to append to each fieldname. eg: field_prefix[field_name] | |
* if a field-name comes in as "field_name", it'll be turned into field_prefix[field_name] | |
*/ | |
fieldPrefix: 'feature_entity', | |
/** | |
* @cfg {String} entityType | |
* The AR STI type. will be added to form post | |
*/ | |
entityType: null, | |
monitorValid: true, | |
sender: null, | |
record: null, | |
entity: null, | |
// private initComponent, | |
initComponent: function(){ | |
// puke if no entity object was provided. | |
if (typeof(this.entity) != 'object') { | |
return alert("Error -- CCA.feature.EntityEditForm -- @cfg param 'entity' is required and must be an object"); | |
} | |
// set cfg params | |
this.title = this.entity.title; | |
this.entityType = this.entity.type; | |
/** | |
* build form-fields | |
* append "feature_entity" prefix to each field so each fields is like feature_entity[field_name] | |
* thing is, we'd also like to control the layout of the form better, so we should look for | |
* layout setting inside the entity and respect that as well??? | |
*/ | |
this.items = []; | |
for (var n = 0, len = this.entity.fields.length; n < len; n++) { | |
var field = Ext.apply({ | |
model: this.entity.type | |
}, this.entity.fields[n]); // <-- clone the field. | |
if (typeof(field.hiddenName) != 'undefined') { | |
field.hiddenName = "feature_entity[" + field.hiddenName + ']'; | |
} | |
else { | |
field.name = "feature_entity[" + field.name + ']'; | |
} | |
this.items.push(field); | |
} | |
this.buttons = [{ | |
id: this.id+'_btnSave', | |
text: 'Save', | |
handler: this.onSave, | |
formBind: (this.monitorValid) ? true : false, | |
scope: this | |
},{ | |
id: this.id+'_btnUpdate', | |
text: 'Update', | |
handler: this.onUpdate, | |
formBind: (this.monitorValid) ? true : false, | |
scope: this | |
},{ | |
id: this.id+'_btnCancel', | |
text: 'Cancel', | |
handler: this.onCancel, | |
scope: this | |
}]; | |
// super | |
CCA.feature.EntityEditForm.superclass.initComponent.call(this); | |
// add "entity_type" to BasicForm's baseParams hash. BasicForm is created *after* super | |
this.form.baseParams = { | |
entity_type: this.entity.type | |
}; | |
// remove this.entity -- we're done with it. no point keeping duplicate data and fattening the object. | |
delete this.entity; | |
this.hideButton(this.id+'_btnUpdate'); | |
}, | |
/** | |
* getEntityType | |
* returns the AR class of this FeatureEntity | |
* @return {String} entityType | |
*/ | |
getEntityType: function(){ | |
return this.entityType; | |
}, | |
setRecord : function (record) { | |
this.record = record; | |
}, | |
setSender : function (sender) { | |
this.sender = sender; | |
}, | |
getRecord : function () { | |
return this.record; | |
}, | |
getSender : function () { | |
return this.sender; | |
}, | |
/** | |
* doEdit | |
* called from the EntityEditForm this provides the form with some crucial information | |
* - the sender panel, giving us the dataview and it's store and template etc. | |
* - a data record that can be displayed for editing | |
* @param {CCA.feature.EntityPanel} sender | |
* @param {Ext.data.Record} record | |
*/ | |
doEdit : function (sender, record) { | |
this.setRecord(record); | |
this.setSender(sender); | |
this.setValues(record); | |
this.hideButton(this.id+'_btnSave'); | |
this.showButton(this.id+'_btnUpdate'); | |
}, | |
setValues : function(rec) { | |
/** | |
* Entity Forms have some exceptions where combo boxes need a record to work on | |
*/ | |
var icombo = this.form.findField(this.formName + '[institution_id]'); | |
if (icombo) { | |
icombo.store.add(new icombo.store.recordType({ | |
id: rec.data.institution_id, | |
name: rec.data.institution.name | |
})); | |
} | |
var author_combo = this.form.findField(this.formName + '[person_id]'); | |
if (author_combo) { | |
author_combo.store.add(new author_combo.store.recordType({ | |
id: rec.data.person_id, | |
name: rec.data.person.first + ' ' + rec.data.person.last | |
})); | |
} | |
if (!this.formName) { | |
this.form.setValues(rec.data); | |
return true; | |
} | |
values = {}; | |
if (this.formName) { | |
for (var key in rec.data) { | |
values[this.formName + '[' + key + ']'] = rec.data[key]; | |
} | |
} | |
this.form.setValues(values); | |
}, | |
/** | |
* onSave | |
*/ | |
onSave: function(btn, ev){ | |
if (this.form.isValid()) { | |
var entity_accordion = Ext.getCmp('entity_panel_' + this.feature_id); | |
var panel = entity_accordion.layout.activeItem; | |
App.showSpinner(App.t("saving")); | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.insert + '/' + this.feature_id, | |
success: function(form, action) { | |
var dv = panel.getView(); | |
var r = dv.store.add(new dv.store.recordType(action.result.data.feature_entity)); | |
this.form.reset(); | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}); | |
} | |
}, | |
/** | |
* onUpdate | |
* send changes to the entity record to the dataview | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onUpdate : function (btn, ev) { | |
if (this.isValid()) { | |
App.showSpinner(App.t("update")); | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.update + '/' + this.record.data.id, | |
success: function(form, action) { | |
/** | |
* get the view, the index of the record, remove it, add a new record...refesh | |
* this is due to a problem encountered with XTemplate and nested data keys | |
*/ | |
var dv = this.sender.getView(); | |
var idx = dv.store.indexOf(this.record); | |
dv.store.remove(this.record); | |
var r = dv.store.insert(idx, new dv.store.recordType(action.result.data.feature_entity)); | |
dv.refresh(); | |
/** | |
* Zero out the form for the next usage | |
*/ | |
this.sender = null; | |
this.form.reset(); | |
this.hideButton(this.id+'_btnUpdate'); | |
this.showButton(this.id+'_btnSave'); | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}); | |
} | |
}, | |
/** | |
* onCancel | |
* cancel and reset the form | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onCancel : function (btn, ev) { | |
this.form.reset(); | |
this.showButton(this.id+ '_btnSave'); | |
this.hideButton(this.id+'_btnUpdate'); | |
this.hideButton(this.id+'_cancel'); | |
}, | |
/** | |
* isValid | |
* if we do not have a record, then this form cannot possibly be submitted | |
*/ | |
isValid : function () { | |
if (typeof this.record == 'undefined') { | |
App.setStatus(App.t(App.STATUS_ERROR), App.t('select_media')); | |
return false; | |
} | |
return this.form.isValid(); | |
}, | |
/** | |
* getButtons | |
* return the buttons we assigned to this panel in the center region | |
*/ | |
getButtons : function () { | |
return this.buttons; | |
}, | |
showButton: function (id) { | |
var buttons = this.getButtons(); | |
for (var i = 0, len = buttons.length; i < len; i++) { | |
if (buttons[i].id == id) { | |
buttons[i].show(); | |
} | |
} | |
}, | |
hideButton: function (id) { | |
var buttons = this.getButtons(); | |
for(var i = 0, len = buttons.length; i< len; i++) { | |
if (buttons[i].id == id) { | |
buttons[i].hide(); | |
} | |
} | |
} | |
}); | |
/** | |
* CCA.feature.MediaPanel | |
* note: these entity panels know about the feature they belong to via the feature_id | |
*/ | |
CCA.feature.MediaPanel = Ext.extend(Ext.Panel, { | |
controller: 'feature', | |
actions: { | |
'reorder': 'reorder_media', | |
'delete': 'delete_media', | |
'load': 'load_media' | |
}, | |
/** | |
* @cfg {String} templateId | |
* default template id to retrieve from TemplateMgr | |
*/ | |
templateId : 'feature_media_template', | |
media: null, | |
layout: 'fit', | |
frame: false, | |
border: false, | |
autoScroll: true, | |
iconMap: { | |
'Image': 'icon-image', | |
'Audio': 'icon-ipod', | |
'Video': 'icon-film', | |
'Slideshow': 'icon-pictures', | |
'OtherMedia': 'icon-user', | |
'Link': 'icon-link' | |
}, | |
/** | |
* @cfg {Integer} feature_id | |
* This entity's associated Feature id | |
*/ | |
initComponent: function(){ | |
this.title = this.media.type; | |
this.iconCls = this.iconMap[this.media.type]; | |
// register this media's fields with MediaFieldMgr singleton. this is to assist in XTemplate rendering. | |
//CCA.feature.MediaFieldMgr.register(this.media.type, this.media.fields); | |
//console.info('registered the media type %s and fields %o', this.media.type, this.media.fields); | |
this.items = this.buildView(); | |
var dragdrop = new RExt.DataView.Orderable({ | |
listeners: { | |
order: function (view, startIndex,records) { | |
rs = []; | |
for (var i = 0, len = records.length; i < len; i++) { | |
rs.push({ | |
id: records[i].data.id, | |
position: i+startIndex | |
}); | |
} | |
App.request({ | |
url: this.controller + '/' + this.actions.reorder, | |
params: { | |
data: Ext.encode(rs) | |
}, | |
success: function (res) { | |
//console.log('Success', res); | |
}, | |
failure: function (res) { | |
//console.log('bummer', res); | |
} | |
}); | |
}, | |
scope: this | |
} | |
}); | |
this.plugins = dragdrop; | |
CCA.feature.MediaPanel.superclass.initComponent.call(this); | |
this.on('render', function() { | |
Ext.dd.ScrollManager.register(this.body); | |
}, this); | |
}, | |
buildView: function() { | |
var store = new Ext.data.Store({ | |
reader: new Ext.data.ArrayReader({ | |
record: 'media' | |
}, CCA.data.FeatureMedia), | |
data: this.media.data || [], | |
baseParams: {}, | |
sortInfo: { | |
field: 'position', | |
direction: 'ASC' | |
} | |
}); | |
// make a ptr to fields. this is for the XTemplate function getFields | |
var fields = this.media.fields; | |
var tools = new RExt.DataViewEditor({ | |
actions: { | |
edit: 'edit_media', | |
"delete": 'delete_media', | |
load: 'load_media' | |
}, | |
listeners: { | |
'edit' : function(view, index, node, ev) { | |
this.onEdit(view, index, node, ev); | |
}, | |
'delete' : function(view, index, node, ev) { | |
this.onDelete(view, index, node, ev); | |
}, | |
scope: this | |
} | |
}); | |
// create view | |
var view = new Ext.DataView({ | |
controller: this.controller, | |
store: store, | |
tpl: this.getTemplate(), | |
singleSelect: true, | |
overClass: 'x-grid3-row-over', | |
itemSelector: 'div.feature-media', | |
dropZoneCls: 'dropzone', | |
selectedClass: 'x-grid3-row-selected', | |
emptyText: '<h2>No items added</h2><h3 class="icon-information r-icon-text">You may add any number of items.</h3>', | |
plugins: tools | |
}); | |
return [view]; | |
}, | |
getTemplate : function() { | |
return RExt.util.TemplateMgr.get((RExt.util.TemplateMgr.exists(this.media.type + '_media_template')) ? this.media.type + '_media_template' : this.templateId); | |
}, | |
/** | |
* getView | |
* returns attached DataView | |
* @return {Ext.DataView} | |
*/ | |
getView: function(){ | |
return this.findByType(Ext.DataView).shift(); | |
}, | |
/** | |
* getValues | |
* returns array of added Entities | |
* @return {Hash} | |
*/ | |
getValues: function(){ | |
var rs = []; | |
this.getView().store.each(function(rec){ | |
rs.push(rec.data.form); | |
}); | |
return { | |
type: this.media.type, | |
data: rs | |
}; | |
}, | |
/** | |
* onEdit | |
* 'edit' tool clicked on a row in a DataView | |
* show the correct card in the editing form card layout... | |
* @param {Object} view | |
* @param {Object} index | |
* @param {Object} node | |
* @param {Object} ev | |
*/ | |
onEdit : function(view, index, node, ev) { | |
var record = view.store.getAt(index); | |
var fpanel = Ext.getCmp('media_edit_'+this.feature_id); | |
fpanel.layout.activeItem.doEdit(this, record); | |
return; | |
}, | |
/** | |
* onDelete | |
* remove a an entity from a Feature | |
* @param {Ext.DataView} view | |
* @param {Number} index | |
* @param {HTMLElement} node | |
* @param {Ext.EventObject} ev | |
*/ | |
onDelete : function(view, index, node, ev) { | |
Ext.MessageBox.confirm(App.t('confirm'), App.t('delete_media'), function(btn) { | |
if (btn == 'yes') { | |
var rec = view.store.getAt(index); | |
App.request({ | |
url: this.controller + '/' + this.actions['delete'] + '/' + rec.data.id, | |
method: 'POST', | |
success:function(res) { | |
view.store.remove(rec); | |
/** | |
* we are smart enough to reset the current panel??? Is this too jarring | |
* when you switch context from a form panel to a Dataview action like delete | |
*/ | |
//if (view.ownerCt.xtype == 'slideshow_panel') { | |
var fpanel = Ext.getCmp('media_edit_' + this.feature_id); | |
var fm = fpanel.layout.activeItem.form.reset(); | |
//} | |
}, | |
failure: function(res) { | |
App.setAlert('STATUS_ERROR', res.data.msg); | |
}, | |
scope: this | |
}); | |
} | |
},this); | |
} | |
}); | |
/** | |
* CCA.feature.MediaEditForm | |
* A base-class for all FeatureMedia forms. | |
* Form constructor must be provided with a FeatureMedia object containing title and fields array. | |
*/ | |
CCA.feature.MediaEditForm = Ext.extend(Ext.form.FormPanel, { | |
controller: 'feature', | |
actions: { | |
insert: 'create_media', | |
update: 'update_media' | |
}, | |
defaults: { | |
anchor: '95%' | |
}, | |
feature_id: null, | |
fileUpload: true, | |
labelAlign: 'right', | |
labelWidth: 150, | |
frame: true, | |
border: false, | |
header: false, | |
buttons: null, | |
autoScroll: true, | |
monitorValid: true, | |
reset: true, | |
/** | |
* @cfg {String} fieldPrefix | |
* the Rails-style prefix to append to each fieldname. eg: field_prefix[field_name] | |
* if a field-name comes in as "field_name", it'll be turned into field_prefix[field_name] | |
*/ | |
fieldPrefix: 'feature_media', | |
/** | |
* @cfg {String} mediaType | |
* The AR STI type. will be added to form post | |
*/ | |
mediaType: null, | |
media: null, | |
sender: null, | |
record: null, | |
// private initComponent, | |
initComponent: function(){ | |
// puke if no entity object was provided. | |
if (typeof(this.media) != 'object') { | |
return alert("Error -- CCA.feature.MediaEditForm -- @cfg param 'media' is required and must be an object"); | |
} | |
// set cfg params | |
this.title = this.media.title; | |
if (this.title == null) { //added so there's no blank titles | |
this.title = App.t('slideshow_details'); //this shouldn't be hard-coded but hey | |
} | |
/** | |
* build form-fields | |
* append "feature_media" prefix to each field so each fields is like feature_media[field_name] | |
* thing is, we'd also like to control the layout of the form better, so we should look for | |
* layout setting inside the entity and respect that as well??? | |
*/ | |
this.items = []; | |
for (var n = 0, len = this.media.fields.length; n < len; n++) { | |
var field = Ext.apply({ | |
model: this.media.type | |
}, this.media.fields[n]); // <-- clone the field. | |
if (typeof(field.hiddenName) != 'undefined') { | |
field.hiddenName = "feature_media[" + field.hiddenName + ']'; | |
} | |
else { | |
field.name = "feature_media[" + field.name + ']'; | |
} | |
this.items.push(field); | |
} | |
this.buttons = [{ | |
id: this.id+'_btnSave', | |
text: 'Save', | |
handler: this.onSave, | |
formBind: (this.monitorValid) ? true : false, | |
scope: this | |
},{ | |
id: this.id+'_btnUpdate', | |
text: 'Update', | |
handler: this.onUpdate, | |
formBind: (this.monitorValid) ? true : false, | |
scope: this | |
},{ | |
id: this.id+'_btnCancel', | |
text: 'Cancel', | |
handler: this.onCancel, | |
scope: this | |
}]; | |
// add a toolbar to the slideshow meta data panel for use in that form, it is special | |
if (this.media.type == 'Slideshow') { | |
this.tbar = [{ | |
xtype: 'tbtext', | |
text: 'Create Slideshow' | |
},'-',{ | |
text: 'New', | |
handler: this.onNew, | |
scope: this | |
}]; | |
} | |
CCA.feature.MediaEditForm.superclass.initComponent.call(this); | |
// add "media_type" to BasicForm's baseParams hash. BasicForm is created *after* super | |
this.form.baseParams = { | |
media_type: this.media.type | |
}; | |
// remove this.entity -- we're done with it. no point keeping duplicate data and fattening the object. | |
delete this.media; | |
this.hideButton(this.id+'_btnUpdate'); | |
this.on('render', function () { | |
var tb = this.getTopToolbar(); | |
if (tb) { | |
tb.hide(); | |
} | |
},this); | |
}, | |
setRecord : function (record) { | |
this.record = record; | |
}, | |
setSender : function (sender) { | |
this.sender = sender; | |
}, | |
getRecord : function () { | |
return this.record; | |
}, | |
getSender : function () { | |
return this.sender; | |
}, | |
// as well as cleaning up the meta data form.. we need to reset the slideshow_edit too | |
onNew : function (btn, ev) { | |
var fpanel = Ext.getCmp('media_edit_' + this.feature_id); | |
var fm = fpanel.layout.activeItem.reset(); | |
}, | |
/** | |
* doEdit | |
* called from the MediaEditForm this provides the form with some crucial information | |
* - the sender panel, giving us the dataview and it's store and template etc. | |
* - a data record that can be displayed for editing | |
* @param {CCA.feature.MediaPanel} sender | |
* @param {Ext.data.Record} record | |
*/ | |
doEdit : function (sender, record) { | |
this.setRecord(record); | |
this.setSender(sender); | |
this.setValues(record); | |
this.hideButton(this.id+'_btnSave'); | |
this.showButton(this.id+'_btnUpdate'); | |
/** okay... so the last field in the form is always the file uploader... and the Ext.BasicForm.findField() function | |
* does not seem to have much luck in finding fields like feature_media[item], so we hack the find... and for updates | |
* we set the allowBlank property to be TRUE, hence you do not HAVE to upload a new image or other media on UPDATE | |
*/ | |
var last = this.form.items.getCount(); | |
var field = this.form.findField(last-1); | |
if (field.xtype =='fileuploadfield') { | |
field.allowBlank = true; | |
} | |
}, | |
/** | |
* onUpdate | |
* pressed into service to update a media record delivered from a media panel | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onUpdate : function (btn, ev) { | |
if (this.isValid()) { | |
App.showSpinner(App.t('update')); | |
var media_accordion = Ext.getCmp('media_panel_' + this.feature_id); | |
var panel = media_accordion.layout.activeItem; | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.update + '/' + this.record.data.id, | |
success: function(form, action) { | |
/** | |
* get the view, the index of the record, remove it, add a new record...refesh | |
* this is due to a problem encountered with XTemplate and nested data keys | |
*/ | |
var dv = panel.getView(); | |
var idx = dv.store.indexOf(this.record); | |
dv.store.remove(this.record); | |
this.record = new dv.store.recordType(action.result.data); | |
dv.store.insert(idx, this.record); | |
/** | |
* Zero out the form for the next usage | |
* NOTE: This is only for the forms unlike Slideshow | |
*/ | |
if (this.reset) { | |
this.record = null; | |
this.sender = null; | |
this.form.reset(); | |
this.hideButton(this.id+'_btnUpdate'); | |
this.showButton(this.id+'_btnSave'); | |
} | |
// turn the fileuploadfield back on for validation in case a save is done next. | |
var last = this.form.items.getCount(); | |
var field = this.form.findField(last-1); | |
if(field.xtype == 'fileuploadfield') { | |
field.allowBlank = false; | |
} | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}); | |
} | |
}, | |
/** | |
* onSave | |
*/ | |
onSave: function(btn, ev){ | |
if (this.form.isValid()) { | |
var media_accordion = Ext.getCmp('media_panel_' + this.feature_id); | |
var panel = media_accordion.layout.activeItem; | |
App.showSpinner(App.t("saving")); | |
this.form.submit({ | |
url: this.controller + '/' + this.actions.insert + '/' + this.feature_id, | |
success: function(form, action) { | |
var dv = panel.getView(); | |
var record = new dv.store.recordType(action.result.data.feature_media); | |
dv.store.add(record); | |
/** | |
* SlideshowEdit is a special case. We have to deal with those a little different | |
*/ | |
if (this.form.xtype != 'slideshow_form') { | |
this.form.reset(); | |
} else { | |
this.fireEvent('created', this, record); | |
} | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}); | |
} | |
}, | |
/** | |
* onCancel | |
* cancel and reset the form but with exception for more complicated slideshow form | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onCancel : function (btn, ev) { | |
if (this.form.xtype != 'slideshow_form') { | |
this.form.reset(); | |
} else { | |
var fpanel = Ext.getCmp('media_edit_' + this.feature_id); //copied from onNew for panel toolbar | |
var fm = fpanel.layout.activeItem.reset(); | |
}; | |
this.showButton(this.id+ '_btnSave'); | |
this.hideButton(this.id+'_btnUpdate'); | |
this.hideButton(this.id+'_cancel'); | |
}, | |
/** | |
* getMediaType | |
* returns the AR class of this FeatureMedia | |
* @return {String} mediaType | |
*/ | |
getMediaType: function(){ | |
return this.mediaType; | |
}, | |
/** | |
* isValid | |
* if we do not have a record, then this form cannot possibly be submitted | |
*/ | |
isValid : function () { | |
if (typeof this.record == 'undefined') { | |
App.setStatus(App.t(App.STATUS_ERROR), App.t('select_media')); | |
return false; // <=== you did not actually click on some media to edit.... so bug off... | |
} | |
return this.form.isValid(); | |
}, | |
/** | |
* setValues | |
* handed a record, this will setup the form with the provided values | |
* @param {Ext.data.Record} rec | |
*/ | |
setValues : function(rec) { | |
// if a person combo is found on a media form, pre-populate it with the record's data | |
var author_combo = this.form.findField(this.formName + '[person_id]'); | |
if (author_combo) { | |
author_combo.store.add(new author_combo.store.recordType({ | |
id: rec.data.person_id, | |
name: rec.data.person.first + ' ' + rec.data.person.last | |
})); | |
} | |
if (!this.formName) { | |
this.form.setValues(rec.data); | |
return true; | |
} | |
values = {}; | |
if (this.formName) { | |
for (var key in rec.data) { | |
values[this.formName + '[' + key + ']'] = rec.data[key]; | |
} | |
} | |
this.form.setValues(values); | |
}, | |
/** | |
* getButtons | |
* return the buttons we assigned to this panel in the center region | |
*/ | |
getButtons : function () { | |
return this.buttons; | |
}, | |
showButton: function (id) { | |
var buttons = this.getButtons(); | |
for (var i = 0, len = buttons.length; i < len; i++) { | |
if (buttons[i].id == id) { | |
buttons[i].show(); | |
} | |
} | |
}, | |
hideButton: function (id) { | |
var buttons = this.getButtons(); | |
for(var i = 0, len = buttons.length; i< len; i++) { | |
if (buttons[i].id == id) { | |
buttons[i].hide(); | |
} | |
} | |
} | |
}); | |
/** | |
* Slideshows are slightly different from ordinary Media Panels | |
* - we hack the onAdd function to show the CCA.slideshow.Manager window instead of a | |
* regular CCA.feature.MediaPanel | |
*/ | |
CCA.feature.SlideshowPanel = Ext.extend(CCA.feature.MediaPanel, { | |
controller: 'feature', | |
actions: { | |
create: 'create_media', | |
'delete': 'delete_media', | |
deleteall: 'delete_all_media', | |
reorder: 'reorder_media' | |
}, | |
initComponent : function () { | |
CCA.feature.SlideshowPanel.superclass.initComponent.call(this); | |
/*this.tbar.push({ | |
xtype: 'button', | |
text: 'Delete All', | |
iconCls: 'icon-delete', | |
handler: this.onDeleteAll, | |
scope: this | |
}); | |
this.tbar.push('-'); | |
*/ | |
}, | |
onDeleteAll : function (btn, ev) { | |
if (this.getView().store.getCount()) { | |
Ext.MessageBox.confirm('Confirm', 'Delete ALL Slideshows?', function(btn){ | |
if (btn == 'yes') { | |
// Remove All records from this store.. and tell the server to remove | |
// all rows from FeatureMedia where the type is Slideshow and the feature_id is blah | |
this.getView().store.removeAll(); | |
App.request({ | |
url: this.controller + '/' + this.actions['deleteall'] + '/' + this.feature_id, | |
method: 'POST', | |
params: { | |
media_type: 'Slideshow' | |
}, | |
success: function(res){ | |
if (res.success == true) { | |
//console.log('Removed all Slideshows from Server!'); | |
} | |
}, | |
scope: this | |
}); | |
} | |
}, this); | |
} | |
}, | |
/** | |
* onAdd | |
* first we establish the PK of a new Slideshow in the FeatureMedia table, | |
* and once we have that PK, we can show the SlideshowManager with both the FeatureID and SlideshowID | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onAdd : function (btn, ev) { | |
//console.log('creating a new slideshow'); | |
// prompt the user to create a new slideshow, with a title | |
Ext.Msg.prompt('New Slideshow', 'Title', function(btn, text){ | |
if (btn == 'ok'){ | |
App.showSpinner('Saving'); // <-- showSpinner | |
App.request({ | |
url: this.controller + '/' + this.actions.create, | |
method: "POST", | |
params : { | |
"feature_media[title]" : text, | |
"feature_media[feature_id]" : this.feature_id, | |
"media_type" : 'Slideshow' | |
}, | |
success : function(res) { | |
// create a record for this entry, and then add it to the existing records | |
// in the store, so that it becomes visible... | |
var view = this.getView(); | |
var record = new view.store.recordType(res.data.feature_media); | |
view.store.add(record); | |
App.hideSpinner(); // <-- hideSpinner | |
}, | |
failure : function(res) { | |
App.hideSpinner(); // <-- hideSpinner | |
}, | |
scope: this | |
},this); | |
} | |
},this); | |
}, | |
/** | |
* onEdit | |
* a click on a slideshow in the panel, will swing into view the slideshow manager, provided with the record of the click | |
* @param {Ext.DataView} view | |
* @param {Number} index | |
* @param {HTMLElement} node | |
* @param {Ext.EventObject} ev | |
*/ | |
onEdit : function (view, index, node, ev) { | |
//console.log('editing an existing slideshow'); | |
var record = view.store.getAt(index); | |
var fpanel = Ext.getCmp('media_edit_'+this.feature_id); | |
//var mp = Ext.getCmp('media_panel_' + this.feature_id); | |
//mp.collapse(); | |
fpanel.layout.activeItem.doEdit(this, record); | |
} | |
}); | |
/*** | |
* CCA.feature.Roles | |
* A drop down we create that provides the roles available for a Feature | |
* @param {Object} param | |
*/ | |
CCA.feature.Roles = Ext.extend(Ext.form.ComboBox, { | |
shadow: false, | |
tabIndex: 1, | |
hiddenId: Ext.id(), | |
hiddenName: 'feature[role_id]', | |
fieldLabel: App.t('type'), | |
mode: 'local', | |
triggerAction: 'all', | |
valueField: 'id', | |
displayField: 'identifier', | |
forceSelection: true, | |
roles: null, | |
listWidth: 200, | |
initComponent: function(){ | |
this.on('select', function () { | |
}); | |
this.store = new Ext.data.SimpleStore({ | |
fields: ['id','identifier'], | |
data: this.roles, | |
id: 0 | |
}, this); | |
CCA.feature.Roles.superclass.initComponent.call(this); | |
}, | |
/*** | |
* setTypeId | |
* @param {Integer} type_id | |
*/ | |
setTypeId: function(id){ | |
this.type_id = id; | |
this.store.baseParams.type_id = id; | |
}, | |
reset: function(){ | |
CCA.feature.Roles.superclass.reset.call(this); | |
this.lastQuery = null; | |
this.store.removeAll(); | |
}, | |
getForm: function(){ | |
return Ext.getCmp(this.form_id); | |
} | |
}); | |
Ext.reg('rolecombo', CCA.feature.Roles); | |
/*** | |
* CCA.feature.Admission | |
* @param {Object} param | |
*/ | |
CCA.feature.Admission = Ext.extend(Ext.form.ComboBox, { | |
emptyText: App.t('select_admission'), | |
shadow: false, | |
tabIndex: 1, | |
hiddenId: Ext.id(), | |
hiddenName: 'feature[admission_id]', | |
allowBlank: false, | |
mode: 'local', | |
triggerAction: 'all', | |
valueField: 'id', | |
displayField: 'name', | |
forceSelection: true, | |
width: 200, | |
listWidth: 200, | |
initComponent: function(){ | |
this.store = new Ext.data.SimpleStore({ | |
fields: ['id', 'name'], | |
data: CCA.feature.Util.getAdmission(), | |
id: 0 | |
}); | |
// super | |
CCA.feature.Admission.superclass.initComponent.call(this); | |
}, | |
/*** | |
* setAdmissionId | |
* @param {Integer} admission_id | |
*/ | |
setAdmissionId: function(id){ | |
this.admission_id = id; | |
this.store.baseParams.admission_id = id; | |
}, | |
reset: function(){ | |
CCA.feature.Admission.superclass.reset.call(this); | |
this.lastQuery = null; | |
}, | |
getForm: function(){ | |
return Ext.getCmp(this.form_id); | |
} | |
}); | |
Ext.reg('admission', CCA.feature.Admission); | |
/** | |
* CCA.feature.AdmissionForm | |
* A panel dedicated to collecting startdate, enddate, price and location fields for Events | |
* We have to provide for the client to add MULTIPLE dates per event, so this is done with an | |
* Add button on the form itself, or perhaps a little tool plugin... | |
*/ | |
CCA.feature.AdmissionForm = Ext.extend(Ext.Panel, { | |
feature_id: null, | |
iconCls: 'icon-date', | |
layout: 'form', | |
title: '', | |
border: false, | |
style: 'margin-top: 10px;', | |
bodyStyle: 'padding: 5px', | |
anchor: '99%', | |
collapsible: true, | |
titleCollapse: true, | |
collapsed: true, | |
tools: [{ | |
id: 'plus', | |
qtip: 'Add more event date fields.', | |
handler: function(event, toolEl, panel) { | |
panel.insert(panel.items.length-1, {xtype: 'eventdate'}); | |
panel.doLayout(); | |
}, | |
scope: this | |
}], | |
data: null, | |
initComponent: function(){ | |
this.items = this.build(); | |
CCA.feature.AdmissionForm.superclass.initComponent.call(this); | |
}, | |
/** | |
* build | |
* will return an array of Ext.form elements and Ext.DatePicker elements as needed | |
* If we are provided with data... we should create as many eventdate panels as needed to display them all | |
*/ | |
build: function(){ | |
// first we add all the needed eventdate panels | |
var panels = []; | |
if (this.data instanceof Array) { | |
for (var i = 0, len = this.data.length; i < len; i++) { | |
panels.push({ | |
xtype: 'eventdate' | |
}); | |
} | |
} else { | |
panels.push({xtype: 'eventdate'}); | |
} | |
// next we add the admission, location and duration objects. | |
var fs = { | |
xtype: 'fieldset', | |
autoHeight: true, | |
anchor: '90%', | |
style: 'margin-bottom:5px; margin-left: 15px;', | |
items: [ | |
new CCA.feature.Admission({ | |
emptyText: App.t('select_admission'), | |
fieldLabel: App.t('admission') | |
}),{ | |
xtype: 'textfield', | |
fieldLabel: App.t('location'), | |
name: 'feature[location]', | |
allowBlank: true, | |
blankText: App.t('event_location') | |
},{ | |
xtype: 'textfield', | |
fieldLabel: App.t('duration'), | |
name: 'feature[duration]', | |
allowBlank: true, | |
blankText: App.t('event_duration') | |
}] | |
}; | |
panels.push(fs); | |
return panels; | |
} | |
}); | |
/*** | |
* CCA.feature.Institution | |
* @param {Object} param | |
*/ | |
CCA.feature.Institution = Ext.extend(RExt.form.ComboBoxAdd, { | |
domain: null, | |
// id of the CompanyForm available via Ext.getCmp | |
form_id: 'institution_form', | |
company_id: null, | |
controller: 'institution', | |
actions: { | |
load: 'search', | |
insert: 'insert' | |
}, | |
// Ext params | |
shadow: false, | |
tabIndex: 1, | |
anchor: '90%', | |
hiddenId: Ext.id(), | |
hiddenName: 'feature_entity[institution_id]', | |
allowBlank: false, | |
mode: 'remote', | |
triggerAction: 'all', | |
valueField: 'id', | |
displayField: 'name', | |
pageSize: 10, | |
forceSelection: true, | |
minChars: 3, | |
initComponent: function(){ | |
this.store = new Ext.data.Store({ | |
proxy: new Ext.data.HttpProxy({ | |
url: this.controller + '/' + this.actions.load | |
}), | |
reader: new Ext.data.JsonReader({ | |
root: 'data', | |
totalProperty: 'total', | |
id: 0 | |
}, CCA.data.Institution), | |
baseParams: { | |
institution_id: null | |
} | |
}); | |
// listen to [+] button | |
this.on('add', this.onAdd, this); | |
// when user selects an institution, get the person combo (if exists, it might not) and set the company id. this will cause an autoload on | |
// person combo. | |
this.on('select', function(){ | |
var fpanel = this.findParentBy(function(c){ | |
return c instanceof Ext.form.FormPanel | |
}); | |
var person = fpanel.form.items.find(function(f){ | |
return f.getXType() == 'person'; | |
}); | |
if (person) { | |
//person.setInstitutionId(this.getValue()); | |
} | |
}, this); | |
// super | |
CCA.feature.Institution.superclass.initComponent.call(this); | |
}, | |
/*** | |
* setInstitutionId | |
* @param {Integer} institution_id | |
*/ | |
setInstitutionId: function(id){ | |
this.institution_id = id; | |
this.store.baseParams.institution_id = id; | |
}, | |
reset: function(){ | |
CCA.feature.Institution.superclass.reset.call(this); | |
this.lastQuery = null; | |
this.store.removeAll(); | |
}, | |
onAdd: function(param){ | |
var fpanel = Ext.getCmp(this.form_id); | |
//RExt.UploadMgr.allowOnly('image'); | |
fpanel.showInsert(); | |
fpanel.on('actioncomplete', function(form, action){ | |
if (typeof(action.result) != 'undefined') { | |
var res = action.result; | |
var rec = this.insert(0, res.data[this.controller]); | |
//RExt.UploadMgr.flush(); | |
fpanel.hide(); | |
} | |
}, this); | |
}, | |
onEdit: function(rec){ | |
var fpanel = this.getForm(); | |
if (fpanel) { | |
var domain = RExt.company.Util.loadDomainById(rec.data.domain_id); | |
fpanel.setDomain(domain); | |
fpanel.load(rec.data.id); | |
fpanel.on('actioncomplete', function(form, action){ | |
if (action.type == 'submit') { | |
var res = action.result; | |
if (res.success == true) { | |
fpanel.hide(); | |
} | |
} | |
}); | |
} | |
else { | |
} | |
}, | |
getForm: function(){ | |
return Ext.getCmp(this.form_id); | |
} | |
}); | |
Ext.reg('institution', CCA.feature.Institution); | |
/** | |
* CCA.feature.EntityInstitution | |
* A special combo for selecting companies related to a feature entity. | |
*/ | |
CCA.feature.InstitutionForm = Ext.extend(RExt.sys.Form, { | |
controller: 'institution', | |
fileUpload: true, | |
actions: { | |
insert: 'insert', | |
update: 'update', | |
"delete": 'delete' | |
}, | |
layoutConfig: { | |
fill: true, | |
activeOnTop: true, | |
titleCollapse: true | |
}, | |
title: App.t('institution'), | |
useDialog: true, | |
frame: false, | |
layout: 'fit', | |
dialogConfig: { | |
height: 350, | |
width: 320 | |
}, | |
header: false, | |
labelAlign: 'right', | |
labelWidth: 70, | |
bodyStyle: 'padding: 10px', | |
/*** | |
* initComponent | |
*/ | |
initComponent: function(){ | |
this.items =[this.buildProperties()]; | |
CCA.feature.InstitutionForm.superclass.initComponent.call(this); | |
}, | |
/** | |
* buildProperties | |
* @return {Ext.Panel} | |
*/ | |
buildProperties: function(){ | |
return new Ext.Panel({ | |
title: App.t('properties'), | |
frame: false, | |
border: false, | |
header: false, | |
layout: 'form', | |
autoHeight: true, | |
bodyStyle: 'padding: 10px;', | |
items: [{ | |
fieldLabel: App.t('name'), | |
name: 'institution[name]', | |
xtype: 'textfield', | |
anchor: '90%', | |
allowBlank: false | |
},{ | |
fieldLabel: App.t('description'), | |
name: 'institution[description]', | |
xtype: 'textarea', | |
anchor: '90%', | |
allowBlank: true | |
},{ | |
fieldLabel: App.t('location'), | |
name: 'institution[location]', | |
xtype: 'textfield', | |
anchor: '90%', | |
allowBlank: true | |
}, { | |
fieldLabel: App.t('logo'), | |
permittedExtensions: 'image', | |
name: 'institution[logo]', | |
emptyText: App.t("select_logo"), | |
model: "Institution", | |
xtype: 'fileuploadfield', | |
anchor: '90%', | |
allowBlank: true, | |
buttonCfg: { | |
text: '', | |
iconCls: 'upload-icon' | |
} | |
}] | |
}); | |
}, | |
/** | |
* buildLocation | |
* @return {Ext.Panel} | |
*/ | |
buildLocation: function(){ | |
var formName = 'location'; | |
// get region manager | |
regionMgr = Ext.ComponentMgr.get('region_manager'); | |
// init the regionManager with the current form name "company" | |
regionMgr.setFormName(formName); | |
var comboCountry = regionMgr.renderCountry({ | |
anchor: '90%', | |
tabIndex: 1, | |
msgTarget: 'qtip', | |
allowBlank: true | |
}); | |
var comboRegion = regionMgr.renderRegion({ | |
width: 120, | |
tabIndex: 1, | |
msgTarget: 'qtip', | |
anchor: '90%', | |
allowBlank: true | |
}); | |
// create city combo | |
var comboCity = regionMgr.renderCity({ | |
queryDelay: 100, | |
anchor: '90%', | |
allowBlank: true | |
}); | |
// sew them all together with RegionMgr::associate | |
regionMgr.associate(comboCountry, comboRegion, comboCity); | |
return new Ext.form.FieldSet({ | |
id: this.id + '_fs_location', | |
checkboxToggle: true, | |
collapsed: true, | |
iconCls: 'icon-world', | |
layout: 'form', | |
title: 'Address', | |
defaultType: 'textfield', | |
autoWidth: true, | |
autoHeight: true, | |
bodyStyle: 'padding: 10px', | |
items: [comboCountry, comboRegion, comboCity, new Ext.form.TextField({ | |
name: 'location[addr1]', | |
fieldLabel: 'Addr1', | |
anchor: '90%' | |
}), new Ext.form.TextField({ | |
name: 'location[zip]', | |
fieldLabel: 'Postal/Zip', | |
anchor: '90%' | |
})] | |
}); | |
} | |
}); | |
/*** | |
* CCA.feature.Location | |
* Every Feature of type Event (or EventSeries) can be assigned a When, Where and How Much) | |
* which is all collected and organized through the entity called DateAdmission | |
* @param {Object} param | |
*/ | |
CCA.feature.Location = Ext.extend(RExt.form.ComboBoxAdd, { | |
domain: null, | |
form_id: 'location_form', // our hook the the correct form for this object ie) CCA.feature.LocationForm | |
controller: 'location', | |
actions: { | |
load: 'search', | |
insert: 'insert' | |
}, | |
emptyText: 'Select location...', | |
shadow: false, | |
tabIndex: 1, | |
//anchor: '90%', | |
hiddenId: Ext.id(), | |
hiddenName: 'feature_entity[location_id]', | |
fieldLabel: 'Location', | |
allowBlank: false, | |
mode: 'remote', | |
triggerAction: 'all', | |
valueField: 'id', | |
displayField: 'name', | |
pageSize: 10, | |
forceSelection: true, | |
initComponent: function(){ | |
this.store = new Ext.data.Store({ | |
proxy: new Ext.data.HttpProxy({ | |
url: this.controller + '/' + this.actions.load | |
}), | |
reader: new Ext.data.JsonReader({ | |
root: 'data', | |
totalProperty: 'total', | |
id: 0 | |
}, CCA.data.Location), | |
baseParams: { | |
location_id: null | |
} | |
}); | |
// listen to [+] button | |
this.on('add', this.onAdd, this); | |
this.on('select', function(){ | |
var fpanel = this.findParentBy(function(c){ | |
return c instanceof Ext.form.FormPanel | |
}); | |
var person = fpanel.form.items.find(function(f){ | |
return f.getXType() == 'person'; | |
}); | |
if (person) { | |
person.setInstitutionId(this.getValue()); | |
} | |
}, this); | |
// super | |
CCA.feature.Location.superclass.initComponent.call(this); | |
}, | |
/*** | |
* setLocationId | |
* @param {Integer} location_id | |
*/ | |
setLocationId: function(id){ | |
this.location_id = id; | |
this.store.baseParams.location_id = id; | |
}, | |
reset: function(){ | |
CCA.feature.Location.superclass.reset.call(this); | |
this.lastQuery = null; | |
this.store.removeAll(); | |
}, | |
onAdd: function(param){ | |
// the feature entity panel knows a lot of the feature.. so we grab it | |
var parent = this.findParentBy(function(c){ | |
return c instanceof Ext.form.FormPanel | |
}); | |
var fpanel = Ext.getCmp(this.form_id); | |
fpanel.setKey(parent.feature_id); | |
fpanel.showInsert(); | |
fpanel.on('actioncomplete', function(form, action){ | |
if (typeof(action.result) != 'undefined') { | |
var res = action.result; | |
var rec = this.insert(0, res.data[this.controller]); | |
fpanel.hide(); | |
} | |
}, this); | |
}, | |
onEdit: function(rec){ | |
var fpanel = this.getForm(); | |
if (fpanel) { | |
var domain = RExt.company.Util.loadDomainById(rec.data.domain_id); | |
fpanel.setDomain(domain); | |
fpanel.load(rec.data.id); | |
fpanel.on('actioncomplete', function(form, action){ | |
if (action.type == 'submit') { | |
var res = action.result; | |
if (res.success == true) { | |
fpanel.hide(); | |
} | |
} | |
}); | |
} | |
else { | |
} | |
}, | |
getForm: function(){ | |
return Ext.getCmp(this.form_id); | |
} | |
}); | |
Ext.reg('location', CCA.feature.Location); | |
/** | |
* CCA.feature.LocationForm | |
* A special combo for selecting locations for a feature. | |
*/ | |
CCA.feature.LocationForm = Ext.extend(RExt.sys.Form, { | |
/** | |
* controller & actions | |
*/ | |
controller: 'location', | |
actions: { | |
insert: 'insert', | |
update: 'update', | |
"delete": 'delete' | |
}, | |
layoutConfig: { | |
fill: true, | |
activeOnTop: true, | |
titleCollapse: true | |
}, | |
title: 'Event Location', | |
useDialog: true, | |
border: false, | |
frame: false, | |
layout: 'fit', | |
dialogConfig: { | |
height: 260, | |
width: 300 | |
}, | |
header: false, | |
labelAlign: 'right', | |
labelWidth: 70, | |
style: 'padding: 5px', | |
/*** | |
* initComponent | |
*/ | |
initComponent: function(){ | |
this.items = this.buildLocation(); | |
CCA.feature.LocationForm.superclass.initComponent.call(this); | |
}, | |
getParams : function () { | |
return {type: 'Feature'} | |
}, | |
/** | |
* buildLocation | |
* @return {Ext.Panel} | |
*/ | |
buildLocation: function(){ | |
var formName = 'location'; | |
// get region manager | |
regionMgr = Ext.ComponentMgr.get('region_manager'); | |
// init the regionManager with the current form name "company" | |
regionMgr.setFormName(formName); | |
var comboCountry = regionMgr.renderCountry({ | |
anchor: '92%', | |
tabIndex: 1, | |
msgTarget: 'qtip', | |
allowBlank: true | |
}); | |
var comboRegion = regionMgr.renderRegion({ | |
width: 120, | |
tabIndex: 1, | |
msgTarget: 'qtip', | |
anchor: '92%', | |
allowBlank: true | |
}); | |
// create city combo | |
var comboCity = regionMgr.renderCity({ | |
queryDelay: 100, | |
tabIndex: 1, | |
anchor: '92%', | |
allowBlank: true | |
}); | |
// sew them all together with RegionMgr::associate | |
regionMgr.associate(comboCountry, comboRegion, comboCity); | |
return new Ext.form.FieldSet({ | |
id: this.id + '_fs_location', | |
//checkboxToggle: true, | |
collapsed: false, | |
iconCls: 'icon-world', | |
layout: 'form', | |
title: 'Details', | |
defaultType: 'textfield', | |
autoWidth: true, | |
autoHeight: true, | |
bodyStyle: 'padding: 5px', | |
items: [comboCountry, comboRegion, comboCity, new Ext.form.TextField({ | |
name: 'location[name]', | |
tabIndex: 1, | |
fieldLabel: 'Name', | |
anchor: '92%' | |
}), new Ext.form.TextField({ | |
name: 'location[zip]', | |
tabIndex: 1, | |
fieldLabel: 'Postal/Zip', | |
anchor: '92%' | |
})] | |
}); | |
} | |
}); | |
/** | |
* CCA.data.Person provides a simple record definition for the Person store | |
*/ | |
CCA.data.Person = Ext.data.Record.create([ | |
{name: 'id'}, | |
{name: 'name'} | |
]); | |
/** | |
* CCA.feature.Person | |
* A special combo for selecting accounts related to a feature entity | |
* @author Chris Scott | |
*/ | |
CCA.feature.Person = Ext.extend(RExt.form.ComboBoxAdd, { | |
controller: 'institution', | |
actions: { | |
load: "search_person", | |
insert: "insert_person" | |
}, | |
form_id: 'person_form', | |
cls: 'person-combo', | |
hiddenName: 'feature_entity[person_id]', | |
valueField: 'id', | |
displayField: 'name', | |
name: 'contact', | |
shadow: false, | |
emptyText: 'Select contact...', | |
tabIndex: 1, | |
anchor: '90%', | |
hiddenId: Ext.id(), | |
fieldLabel: 'Contact', | |
allowBlank: false, | |
mode: 'remote', | |
triggerAction: 'all', | |
minChars: 3, | |
initComponent: function(){ | |
this.store = new Ext.data.Store({ | |
proxy: new Ext.data.HttpProxy({ | |
url: this.controller + '/' + this.actions.load | |
}), | |
reader: new Ext.data.JsonReader({ | |
root: 'data', | |
totalProperty: 'total', | |
id: 0 | |
}, CCA.data.Person), | |
baseParams: { | |
company_id: null | |
}, | |
listeners: { | |
// auto-select 1st record on-load | |
load: function(store, rs, options){ | |
if (rs.length > 0) { | |
this.onSelect(rs[0], 0); | |
} | |
}, | |
scope: this | |
} | |
}); | |
this.on('add', this.onAdd, this); | |
CCA.feature.Person.superclass.initComponent.call(this); | |
}, | |
reset: function(){ | |
CCA.feature.Person.superclass.reset.call(this); | |
this.lastQuery = null; | |
this.store.removeAll(); | |
}, | |
/*** | |
* setInstitutionId | |
* sets the combo's institution_id. institution_id is automatically added to query params | |
* @param {Integer} id | |
*/ | |
setInstitutionId: function(id){ | |
this.institution_id = id; | |
this.store.baseParams.institution_id = id; | |
this.reset(); | |
this.doQuery('', true); | |
}, | |
onAdd: function(param){ | |
var fpanel = Ext.getCmp(this.form_id); | |
try { | |
//fpanel.setDomain(this.domain); | |
fpanel.setInstitutionId(this.institution_id); | |
fpanel.showInsert(); | |
fpanel.on('actioncomplete', function(form, action){ | |
var res = action.result; | |
if (res.success == true) { | |
var rec = this.insert(0, res.data.person); | |
this.onSelect(rec, 0); | |
fpanel.hide(); | |
} | |
}, this); | |
} | |
catch (e) { | |
Application.handleException(this, e); | |
} | |
}, | |
/*** | |
* onAddPerson | |
* called by comboBoAdd | |
* @param {Object} ev | |
*/ | |
onAddPerson: function(ev){ | |
this.personField = ev.field; | |
var companyField = null; | |
}, | |
/*** | |
* doInsertPerson | |
* @param {Object} form | |
* @param {Object} action | |
*/ | |
doInsertPerson: function(form, action){ | |
if (typeof(action.result) != 'undefined') { | |
var fpanel = Ext.get(this.form_id); | |
fpanel.hide(); | |
var combo = this.personField; | |
var rec = combo.insert(0, action.result.data.person); | |
combo.onSelect(rec, 0); | |
} | |
} | |
}); | |
// register this field as an xtype | |
Ext.reg('person', CCA.feature.Person); | |
/** | |
* CCA.feature.PersonForm | |
*/ | |
CCA.feature.PersonForm = Ext.extend(RExt.sys.Form, { | |
controller: 'institution', | |
actions: { | |
insert: 'insert_person' | |
}, | |
header: false, | |
title: App.t('person_details'), | |
useDialog: true, | |
dialogConfig: { | |
width: 300, | |
height: 500 | |
}, | |
labelWidth: 125, | |
plain: true, | |
autoScroll: true, | |
initComponent: function(){ | |
this.items = [new CCA.feature.PersonProperties({})]; | |
CCA.feature.PersonForm.superclass.initComponent.call(this); | |
}, | |
/** | |
* setInstitutionId | |
* sets this person's related institution | |
* @param {Object} id | |
*/ | |
setInstitutionId: function(id){ | |
//console.log('set Institution ID is called inside PersonForm'); | |
return; | |
if (typeof(this.form.baseParams) != 'object') { | |
this.form.baseParams = { | |
//"person[institution_id]": null | |
} | |
} | |
//this.form.baseParams["person[institution_id]"] = id | |
} | |
}); | |
/** | |
* CCA.feature.PersonProperties | |
* fieldset for institution account properties | |
*/ | |
CCA.feature.PersonProperties = Ext.extend(Ext.Panel, { | |
header: false, | |
layout: 'form', | |
border: false, | |
initComponent: function(){ | |
this.items = [new Ext.form.TextField({ | |
name: 'person[first]', | |
fieldLabel: App.t('first'), | |
allowBlank: false, | |
anchor: '90%' | |
}), new Ext.form.TextField({ | |
name: 'person[last]', | |
fieldLabel: App.t('last'), | |
allowBlank: false, | |
anchor: '90%' | |
}), new Ext.form.TextField({ | |
name: 'person[title]', | |
fieldLabel: App.t('title'), | |
width: 50, | |
anchor: '90%' | |
}), new Ext.form.TextArea({ | |
name: 'person[description]', | |
fieldLabel: App.t('extra'), | |
allowBlank: true, | |
anchor: '90%' | |
}), | |
new CCA.feature.Biographies({ | |
hiddenName: 'person[feature_id]', | |
emptyText: App.t('select_biography'), | |
fieldLabel: App.t('biography'), | |
store: Ext.StoreMgr.get('biography_store') | |
}), | |
new CCA.feature.Institution({ | |
hiddenName: 'person[institution_id]', | |
allowBlank: true, | |
emptyText: App.t('select_institution'), | |
fieldLabel: App.t('Institution') | |
}), | |
new Ext.form.FieldSet({ | |
title: 'Roles', | |
items: CCA.feature.Util.getPersonRoles(), // <-- role checkboxes | |
autoHeight: true | |
})]; | |
CCA.feature.PersonProperties.superclass.initComponent.call(this); | |
} | |
}); | |
/*** | |
* CCA.feature.Biographies | |
* a drop down of only existing biography features, for use in assigning a person to a biography | |
* Maps a Person to a Feature of Type Biography.... so there | |
* @param {Object} param | |
*/ | |
CCA.feature.Biographies = Ext.extend(Ext.form.ComboBox, { | |
form_id: 'biography_form', | |
controller: 'feature', | |
actions: { | |
load: 'search_biography' | |
}, | |
shadow: false, | |
tabIndex: 1, | |
anchor: '90%', | |
allowBlank: true, | |
mode: 'remote', | |
triggerAction: 'all', | |
valueField: 'id', | |
displayField: 'title', | |
pageSize: 10, | |
forceSelection: true, | |
initComponent: function(){ | |
CCA.feature.Biographies.superclass.initComponent.call(this); | |
}, | |
reset: function(){ | |
CCA.feature.Biographies.superclass.reset.call(this); | |
this.lastQuery = null; | |
this.store.removeAll(); | |
}, | |
getForm: function(){ | |
return Ext.getCmp(this.form_id); | |
} | |
}); | |
Ext.reg('biographies', CCA.feature.Biographies); | |
/** | |
* CCA.feature.EntityLocation | |
* A special combo for selecting a location of an EntityCompany | |
* @author Chris Scott | |
*/ | |
CCA.feature.EntityLocation = Ext.extend(Ext.form.TextField, { | |
initComponent: function(){ | |
CCA.feature.EntityLocation.superclass.initComponent.call(this); | |
} | |
}); | |
Ext.reg('entity_location', CCA.feature.EntityLocation); | |
/** | |
* THIS IS PROBABLY USELESS AND COULD BE DELETED | |
* CCA.feature.ShowcasingsForm | |
* Features can be placed into any Showcasings and their rank can also be set | |
*/ | |
/* | |
CCA.feature.ShowcasingsForm = Ext.extend(Ext.Panel, { | |
title: 'Showcasings', | |
labelAlign: 'right', | |
labelWidth: 125, | |
autoHeight: true, | |
collapsible: true, | |
titleCollapse: true, | |
bodyStyle: 'padding: 10px', | |
layout: 'form', | |
iconCls: 'icon-application-view-tile', | |
initComponent: function(){ | |
if (CCA.feature.Util.getShowcases().getCount() > 0) { | |
this.items = this.build(); | |
} | |
CCA.feature.ShowcasingsForm.superclass.initComponent.call(this); | |
}, | |
build: function(){ | |
var items = []; | |
CCA.feature.Util.getShowcases().each(function(s){ | |
var cfg = { | |
name: 'showcase[' + s.id + ']', | |
fieldLabel: s.name, | |
value: 0, | |
checked: false, | |
sliderConfig: { | |
boxLabel: 'rank', | |
plugins: new Ext.ux.SliderTip({ | |
getText: function(slider){ | |
return String.format('<b>rank: {0}</b>', slider.getValue()); | |
} | |
}) | |
} | |
}; | |
var showcase = this.data.find(function(fs){ | |
return (fs.showcase_id == s.id) ? true : false | |
}); | |
if (showcase) { | |
cfg.checked = true; | |
cfg.value = showcase.rank; | |
} | |
items.push(new RExt.form.SliderCheckbox(cfg)); | |
}, this); | |
return items; | |
} | |
}); | |
Ext.reg('showcasings', CCA.feature.ShowcasingsForm); | |
*/ | |
/** | |
* CCA.feature.SlideshowImagesView | |
* a panel containing a DataView that provides the drag drop and other operations on images | |
* | |
*/ | |
CCA.feature.SlideshowImagesView = Ext.extend(Ext.Panel, { | |
controller: 'slideshow', | |
actions: { | |
search: 'view', | |
reorder: 'reorder', | |
'delete': 'delete' | |
}, | |
ctCls: 'r-dataview-dropzone', | |
autoScroll: true, | |
border: true, | |
frame: true, | |
initComponent : function() { | |
/** | |
* we can broadcast the event editslideshowevent to whoever is listening... | |
*/ | |
this.addEvents({ | |
'editslideshowimage' : true | |
}); | |
this.items = this.build(); | |
var dnd = new RExt.DataView.Orderable({ | |
listeners: { | |
order: function (view, startIndex,records) { | |
rs = []; | |
for (var i = 0, len = records.length; i < len; i++) { | |
rs.push({ | |
id: records[i].data.id, | |
position: i+startIndex | |
}); | |
} | |
App.request({ | |
url: this.controller + '/' + this.actions.reorder, | |
params: { | |
data: Ext.encode(rs) | |
}, | |
success: function (res) { | |
}, | |
failure: function (res) { | |
} | |
}); | |
}, | |
scope: this | |
} | |
}); | |
this.plugins = dnd; | |
CCA.feature.SlideshowImagesView.superclass.initComponent.call(this); | |
this.on('render', function () { | |
Ext.dd.ScrollManager.register(this.body); | |
}, this); | |
}, | |
setSlideshowId : function(id) { | |
this.getView().store.proxy.conn.url = this.controller + '/' + this.actions.search + '/' + id; | |
}, | |
build : function() { | |
var store = this.buildStore(); | |
var tools = new RExt.DataViewEditor({ | |
actions: { | |
"delete": 'delete_image', | |
edit: 'edit_image' | |
}, | |
listeners: { | |
'edit' : function(view, index, node, ev) { | |
this.onEdit(view, index, node, ev); | |
}, | |
'delete' : function(view, index, node, ev) { | |
this.onDelete(view, index, node, ev); | |
}, | |
scope: this | |
} | |
}); | |
var tpl = new Ext.XTemplate( | |
'<tpl for=".">', | |
' <div id="feature-media-{id}" class="slideshow-media x-unselectable">', | |
' <table class="properties">', | |
' <tbody>', | |
// ' <tr><th>Title:</th><td><em>{title}</em></td></tr>', | |
// ' <tr><th>Caption:</th><td><em>{caption}</em></td></tr>', | |
' <tr><th>Thumb:</th><td><img src="{thumb}" alt="{title}" /></td></tr>', | |
' <tr><th></th><td>{item_file_name}</td></tr>', | |
' <tr><th>Tools:</th><td><div class="tools"><a href="#" class="edit">edit</a> | <a class="delete" href="#">delete</a></div></td></tr>', | |
' </tbody>', | |
' </table>', | |
' </div>', | |
'</tpl>',{ | |
getTitle : function (title) { | |
return title; | |
//return (typeof title == 'undefined')? 'none' : title; | |
} | |
} | |
); | |
//this.bbar = this.buildBottomToolbar(store); | |
var view = new Ext.DataView({ | |
store: store, | |
tpl: tpl, | |
singleSelect: true, | |
itemSelector: 'div.slideshow-media', | |
dropZoneCls: 'dropzone', | |
selectedClass: 'x-grid3-row-selected', | |
overClass: 'x-grid3-row-over', | |
plugins: tools | |
}); | |
return view; | |
}, | |
/** | |
* onDelete | |
* remove a slideshow image | |
* @param {Ext.DataView} view | |
* @param {Number} index | |
* @param {HTMLElement} node | |
* @param {Ext.EventObject} ev | |
*/ | |
onDelete : function (view, index, node, ev) { | |
Ext.MessageBox.confirm(App.t('delete'), App.t('delete_image'), function(btn){ | |
if (btn == 'yes') { | |
var record = view.store.getAt(index); | |
App.showSpinner('delete'); // <-- showSpinner | |
App.request({ | |
url: this.controller + '/' + this.actions["delete"] + '/' + record.data.id, | |
method: 'POST', | |
success: function(res){ | |
if (res.success == true) { | |
view.store.removeAt(index); | |
} | |
}, | |
failure: function(res) { | |
}, | |
scope: this | |
}, this); | |
} | |
}, this); | |
}, | |
/** | |
* onEdit | |
* a click on the edit tool and an image in a slideshow can be edited, | |
* @param {Ext.DatView} view | |
* @param {Number} index | |
* @param {HTMLElement} node | |
* @param {Ext.EventObject} ev | |
*/ | |
onEdit : function (view, index, node, ev) { | |
var record = view.store.getAt(index); | |
this.fireEvent('editslideshowimage', this, record); | |
}, | |
// private | |
load : function(record) { | |
this.setSlideshowId(record.data.id) | |
App.showSpinner('loading'); | |
this.getView().store.load(); | |
App.hideSpinner(); | |
this.doLayout(); // <-- this is necessary for some stupid reason. | |
}, | |
buildBottomToolbar : function(store) { | |
return new Ext.PagingToolbar({ | |
store: store, | |
pageSize: this.pageSize, | |
displayInfo: false | |
}); | |
}, | |
buildStore : function(params) { | |
params = params || {}; | |
var url = this.controller + '/' + this.actions.search; | |
if (this.slideshow_id != null) { url += '/' + this.slideshow_id } | |
var cfg = Ext.apply({ | |
/*autoLoad: { | |
params : { | |
limit: this.pageSize, | |
start: 0 | |
} | |
},*/ | |
reader: new Ext.data.JsonReader({ | |
totalProperty: 'total', | |
root: 'media', | |
id: 'id' | |
}, CCA.data.FeatureMedia), | |
proxy: new Ext.data.HttpProxy({ | |
url: url, | |
method: "GET" | |
}), | |
baseParams : this.baseParams | |
},params); | |
if (this.autoLoad === false) { | |
cfg.autoLoad = false; | |
} | |
return new Ext.data.Store(cfg); | |
}, | |
/** | |
* getView | |
* @return {Ext.DataView} | |
*/ | |
getView : function() { | |
return this.items.first(); | |
}, | |
/** | |
* doEdit | |
* When a slideshow is ready to be updated this call handles the setup of the form panel and view | |
* @param {Object} data | |
*/ | |
doEdit : function (data) { | |
//console.log('Loading the Slideshow with the data ', data); | |
App.hideSpinner(); | |
}, | |
/** | |
* onClick | |
* @param {Object} v | |
* @param {Object} index | |
* @param {Object} node | |
* @param {Object} ev | |
*/ | |
onClick : function(v, index, node, ev) { | |
var btn = ev.getTarget('a', 4, true); | |
if (btn == null) { | |
this.fireEvent('select', v, index, node, ev); // <-- simply fire select event | |
return false; // <-- no tool clicked. GTFO | |
} | |
// did user click a tool? give chance for any Plugins to service this toolclick event | |
if (btn.hasClass('tool')) { | |
return this.fireEvent('toolclick', v, index, node, btn, ev); | |
} | |
// link with an href? redir regular <a href="/url"> | |
else if (btn.dom.href) { | |
document.location = btn.dom.href; | |
} | |
}, | |
onLoad : function (store, records, options) { | |
//console.log('onLoad fired store=%o, records=%o, options=%o', store, records, options); | |
}, | |
/** | |
* reset | |
* empty the store and get ready for new data | |
*/ | |
reset : function () { | |
var view = this.getView(); | |
view.store.removeAll(); | |
} | |
}); | |
Ext.reg('slideshowview', CCA.feature.SlideshowImagesView); | |
/** | |
* CCA.feature.SlideshowImageEditor | |
* The center region will contain two panels, only one of which is visible at a time. | |
* One panel contains the image, large size, with the current data rendered by an XTemplate | |
* The second panel contains an editing form where the minute details of an image can be changed | |
*/ | |
CCA.feature.SlideshowImageEditor = Ext.extend(Ext.form.FormPanel, { | |
controller: 'slideshow', | |
frame: true, | |
border: false, | |
header: false, | |
actions: { | |
update: 'update_media' | |
}, | |
record: null, | |
initComponent : function() { | |
/** | |
* when building an image editor for a slideshow, we really only need to present three fields, namely | |
* 1) title 2) caption 3) copyright cleared | |
*/ | |
var fields = CCA.feature.MediaFieldMgr.get('Image'); | |
var formItems = []; | |
for ( var i = 0, len = fields.length; i < len; i++) { | |
switch (fields[i].name) { | |
case 'title': | |
case 'caption': | |
case 'cleared': | |
var f = {}; | |
Ext.apply(f, fields[i]); | |
f.name = "feature_media[" + fields[i].name + ']'; | |
f.width = "80%"; // set width of items as percentage of container width | |
formItems.push(f); | |
break; | |
} | |
} | |
//console.log('formItems ', formItems); | |
this.items = formItems; | |
this.buttons = [{ | |
text: App.t('update'), | |
handler: this.onUpdate, | |
scope: this | |
},{ | |
text: App.t('cancel'), | |
handler: this.reset, | |
scope: this | |
}]; | |
CCA.feature.SlideshowImageEditor.superclass.initComponent.call(this); | |
}, | |
/** | |
* onUpdate | |
* update the title, caption and copyright elements for a slideshow image | |
* @param {Object} btn | |
* @param {Object} ev | |
*/ | |
onUpdate : function (btn, ev) { | |
var fm = this.getForm(); | |
if (fm.isValid()) { | |
App.showSpinner(App.t('save')); | |
fm.submit({ | |
url: this.controller + '/' + this.actions.update + '/' + this.record.data.id, | |
success: function(form, action) { | |
var record = this.getRecord(); | |
fm.reset(); | |
this.disableButtons(); | |
var data = action.result.data; | |
record.fields.each(function(f) { | |
record.set(f.name, data[f.mapping]); | |
}); | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}, this); | |
} | |
}, | |
getRecord : function () { | |
return this.record; | |
}, | |
/** | |
* load | |
* accepts a record, and presents the Media in the record in a nice way | |
* @param {Object} record | |
*/ | |
load : function(record) { | |
//PAT. Find out which code is calling this load method | |
console.info("SlideShowImageEditor#load record:", record); | |
// END PAT | |
this.record = record; | |
var fm = this.getForm(); | |
fm.setValues(this.formify(record.data)); | |
this.enableButtons(); | |
}, | |
/** | |
* getButtons | |
* return the buttons we assigned to this panel in the center region | |
*/ | |
getButtons : function () { | |
return this.buttons; | |
}, | |
disableButtons: function () { | |
var buttons = this.getButtons(); | |
for (var i = 0, len = buttons.length; i < len; i++) { | |
buttons[i].disable(); | |
} | |
}, | |
enableButtons: function () { | |
var buttons = this.getButtons(); | |
for(var i = 0, len = buttons.length; i< len; i++) { | |
buttons[i].enable(); | |
} | |
}, | |
formify : function (data) { | |
values = {}; | |
for (var key in data) { | |
values['feature_media[' + key + ']'] = data[key]; | |
} | |
return values; | |
} | |
}); | |
Ext.reg('slideshowimageeditor', CCA.feature.SlideshowImageEditor); | |
/** | |
* CCA.feature.SlideshowManager | |
* This panel contains a pretty sophisticated border layout to handle Slideshows. | |
* Outer Level: WEST == form holding the Meta Data for the slideshow | |
* CENTER == border layout for holding the actual details for the selected slideshow | |
* Inner Level: | |
* NORTH = file uploader (which is a form) | |
* CENTER = form with Image details | |
* EAST = listing of current images assigned to a slideshow | |
*/ | |
CCA.feature.SlideshowManager = Ext.extend(Ext.Panel, { | |
controller: 'slideshow', | |
actions: { | |
view: 'view', | |
update: 'update', | |
reorder: 'reorder', | |
"delete" : 'delete', | |
delete_images: 'delete_images', | |
upload: 'upload' | |
}, | |
layout: 'border', | |
media: null, | |
feature_id: null, | |
record: null, | |
initComponent : function () { | |
this.addEvents({ | |
/** | |
* @event created | |
* fires when a slideshow has been created | |
* @param {Panel} this | |
* @param {Record} record | |
*/ | |
'created' : true | |
}); | |
// we need this to make a slideshow editing form... | |
var media = { | |
type: 'Slideshow', | |
fields: CCA.feature.MediaFieldMgr.get('Slideshow') | |
} | |
this.items = [{ | |
region:'west', | |
xtype: 'slideshow_form', | |
media: media, | |
feature_id: this.feature_id, | |
formName: 'feature_media', | |
header: true, | |
border: false, | |
labelAlign: 'top', | |
split: true, | |
width: 250, | |
minWidth: 200, | |
maxWidth: 400, | |
reset: false, | |
autoHeight:true, | |
listeners : { | |
created: this.onCreated, | |
scope: this | |
} | |
}, { | |
xtype: 'panel', | |
region: 'center', | |
layout: 'border', | |
items: [{ | |
xtype: 'form', | |
fileUpload: true, | |
region: 'north', | |
disabled: true, | |
height: 40, | |
header: false, | |
frame: false, | |
border: false, | |
bodyStyle: 'padding: 5px', | |
labelAlign: 'right', | |
items: [ { | |
xtype: 'fileuploadfield', | |
ctCls: 'slideshow-north', | |
name: 'item', | |
fieldLabel: App.t('image'), | |
emptyText: App.t('select_image'), | |
allowBlank: true, | |
permittedExtensions: 'image', | |
model: 'FeatureMedia', | |
buttonCfg: { | |
text: '', | |
iconCls: 'upload-icon' | |
}, | |
listeners: { | |
'fileselected': this.onSelect, | |
scope: this | |
} | |
}] | |
},{ | |
xtype: 'slideshowimageeditor', | |
region: 'center', | |
margins: '5 5 5 5' | |
},{ | |
region:'east', | |
xtype: 'slideshowview', | |
title: 'Images', | |
frame: false, | |
split: true, | |
width: 200, | |
listeners: { | |
'editslideshowimage' : function (sender, record) { | |
this.doEditImage(record); | |
}, | |
scope: this | |
} | |
}] | |
}]; | |
CCA.feature.SlideshowManager.superclass.initComponent.call(this); | |
}, | |
setRecord : function (record) { | |
this.record = record; | |
}, | |
setSender : function (sender) { | |
this.sender = sender; | |
}, | |
getRecord : function () { | |
return this.record; | |
}, | |
getSender : function () { | |
return this.sender; | |
}, | |
/** | |
* when a slideshow is created, we need to setup the Slideshow Edit process to be update for the metadata | |
* and turn on the image uploader in the north | |
*/ | |
onCreated : function (form, record) { | |
var uploadPanel = this.getUploadPanel(); | |
uploadPanel.enable(); | |
form.hideButton(form.id+'_btnSave'); | |
form.showButton(form.id+'_btnUpdate'); | |
this.getFormPanel().setRecord(record); | |
this.getFormPanel().setSender(this.getFormPanel()); | |
this.getFormPanel().getTopToolbar().show(); | |
}, | |
/** | |
* doEditImage | |
* accept an image record for display and editing in the center region | |
* @param {Ext.data.Record} record | |
*/ | |
doEditImage : function (record) { | |
var mp = this.getMediaPanel(); | |
mp.load(record); | |
}, | |
/** | |
* doEdit | |
* called from the MediaEditForm this provides the form with some crucial information | |
* - the sender panel, giving us the dataview and it's store and template etc. | |
* - a data record that can be displayed for editing | |
* @param {CCA.feature.MediaPanel} sender | |
* @param {Ext.data.Record} record | |
*/ | |
doEdit : function (sender, record) { | |
this.setRecord(record); | |
this.setSender(sender); | |
// this will use the record from the slideshow_panel to load the images | |
var vp = this.getViewPanel(); | |
if(vp) { | |
vp.load(record); | |
} | |
// turn on the ability to upload more photos to an existing slideshow | |
var uploadPanel = this.getUploadPanel(); | |
uploadPanel.enable(); | |
// clear out the center region panel to get it ready for edits | |
var mp = this.getMediaPanel(); | |
mp.form.reset(); | |
// setup the Meta Details form, turn on the update and hide save button | |
var fp = this.getFormPanel(); | |
fp.setSender(sender); | |
fp.setRecord(record); | |
fp.setValues(record); | |
fp.hideButton(fp.id+'_btnSave'); | |
fp.showButton(fp.id+'_btnUpdate'); | |
fp.getTopToolbar().show(); | |
}, | |
/** | |
* resetSlideshowEdit | |
* there are occasions when we want to reset the whole Slideshow Editor to nil | |
*/ | |
reset : function () { | |
// this will use the record from the slideshow_panel to load the images | |
this.setRecord(null); | |
var vp = this.getViewPanel(); | |
if(vp) { | |
vp.reset(); | |
} | |
var fp = this.getFormPanel(); | |
fp.showButton(fp.id+'_btnSave'); | |
fp.hideButton(fp.id+'_btnUpdate'); | |
// this is odd... formpanel has no reset().. so we do it manually. | |
fp.getForm().items.each(function (f){ | |
f.reset(); | |
}); | |
fp.getTopToolbar().hide(); | |
// turn off the ability to upload photos to an non-editable slideshow | |
var uploadPanel = this.getUploadPanel(); | |
uploadPanel.form.reset(); | |
uploadPanel.disable(); | |
}, | |
/** | |
* getUploadPanel | |
* returns the North region which has been assigned the photo uploader element | |
*/ | |
getUploadPanel : function () { | |
var panel = this.getContentPanel(); | |
return panel.items.find(function(p) { return (p.region == 'north') ? true : false; }); | |
}, | |
/** | |
* getViewPanel | |
* returns the west region which has been assigned the DataView showing all the slideshow images | |
*/ | |
getViewPanel : function () { | |
var panel = this.getContentPanel(); | |
return panel.items.find(function(p) { return (p.region == 'east') ? true : false; }); | |
}, | |
/** | |
* getMediaPanel | |
* returns the center region which contains the slideshow image manipulation components | |
*/ | |
getMediaPanel : function() { | |
var panel = this.getContentPanel(); | |
return panel.items.find(function(p) { return (p.region == 'center') ? true : false; }); | |
}, | |
/** | |
* getMediaPanel | |
* returns the center region which contains the slideshow image manipulation components | |
*/ | |
getContentPanel : function() { | |
return this.items.find(function(p) { return (p.region == 'center') ? true : false; }); | |
}, | |
getFormPanel : function () { | |
return this.items.find(function(p) { return (p.region == 'west') ? true : false; }); | |
}, | |
/** | |
* onSelect | |
* if we selected a file, send the Feature controller a command to inform the file upload queue that a file is coming | |
* @param {Ext.form.ComboBox} combo | |
* @param {Object} file | |
*/ | |
onSelect : function (combo, file) { | |
App.showSpinner(App.t('upload')); | |
var fPanel = this.getUploadPanel(); | |
fPanel.form.submit({ | |
url: this.controller + '/' + this.actions.upload + '/' + this.getRecord().data.feature_id, | |
params: {parent_id: this.getRecord().data.id}, | |
success: function(form, action) { | |
// action.response.responseText contains all the goodies | |
fPanel.form.reset(); | |
var response = Ext.decode(action.response.responseText); | |
var vp = this.getViewPanel(); | |
var store = vp.getView().store; | |
store.add(new store.recordType(response.data)); | |
App.processResponse(action); | |
}, | |
failure: function(form, action){ | |
App.processResponse(action); | |
}, | |
scope: this | |
}) | |
} | |
}); | |
/** | |
* CCA.feature.PublishedUrl | |
* this component provides a semi-smart way of viewing the URL of a published feature | |
*/ | |
CCA.feature.PublishedUrl = Ext.extend(Ext.Panel,{ | |
controller: 'feature', | |
actions: { | |
unpublish: 'unpublish' | |
}, | |
frame: true, | |
border: false, | |
header:false, | |
record: null, | |
style: 'margin:5px', | |
tpl: null, | |
initComponent : function () { | |
CCA.feature.PublishedUrl.superclass.initComponent.call(this); | |
// This template is a handy way of stamping out the record data | |
this.tpl = new Ext.XTemplate('<tpl for=".">', | |
'<div class="published_url">', | |
' <div style="float:left;">', | |
' URL: <a href="{url}" target="_blank">{url}</a>', | |
' </div>', | |
' <tpl if="this.canUnpublish() == true">', | |
' <div style="float:right;text-align:right;">', | |
' <span><a href="#" id="unpublish_{id}">' + App.t('unpublish')+ '</a></span>', | |
' </div>', | |
' </tpl>', | |
'</div>', | |
'</tpl>', { | |
canUnpublish: function(){ | |
if(CCA.feature.Util.getAccountProfile() == 'profile.writer') | |
return false; | |
return true; | |
} | |
}); | |
this.on('render', function () { | |
if(this.record.data.published) { | |
this.tpl.overwrite(this.body, this.record.data); | |
if (CCA.feature.Util.getAccountProfile() != 'profile.writer') { | |
var link = Ext.get('unpublish_' + this.record.data.id); | |
link.on('click', this.unPublish, this, this.record.data.id); | |
} | |
} else { | |
this.body.update('<p>' + App.t('unpublished_content') + '</p>'); | |
} | |
}, this); | |
}, | |
unPublish : function (ev, el, id) { | |
Ext.MessageBox.confirm('Unpublish', 'Unpublish Feature?', function(btn){ | |
if (btn == 'yes') { | |
App.showSpinner('save'); // <-- showSpinner | |
App.request({ | |
url: this.controller + '/' + this.actions['unpublish'] + '/' + id, | |
success: function(res){ | |
//console.log('res ', res); | |
if (res.success == true) { | |
var link = Ext.get('unpublish_'+id); | |
link.un('click', this); | |
this.body.update('<p>' + App.t('unpublished_content') + '</p>'); | |
// remove the publication date from the grid too | |
// eventually just fire an event to tell grid to update itself | |
var grid = Ext.getCmp('feature_grid'); | |
var store = grid.store; | |
var range = store.getRange(); | |
for (var i = 0, len = range.length; i < len; i++) { | |
if (range[i].data.id == id) { | |
var record = range[i]; | |
} | |
} | |
if(record instanceof Ext.data.Record) { | |
record.set('published_at', null); | |
record.set('published', false); | |
} | |
} | |
}, | |
failure: function(res) { | |
var msgBody = ''; | |
if(res.data.features.length > 0 || res.data.showcases.length > 0) | |
msgBody = 'This feature cannot be unpublished because it is linked with the following items:<br /><br />'; | |
if(res.data.features.length > 0) { | |
msgBody += 'features:<br />======<br /><br /><ul>'; | |
for(var i=0; i<res.data.features.length; i++) { | |
var item = res.data.features[i]; | |
msgBody += '<li style="margin-left: 10px; list-style-type: disc !important">' + item.title + ' (id='+ item.id + ')</li>'; | |
if(i == 9){ | |
msgBody += (res.data.features.length - (i + 1)) + ' more...<br /><br />' | |
break; | |
} | |
} | |
msgBody += '</ul>'; | |
} | |
if(res.data.showcases.length > 0) { | |
msgBody += 'showcases:<br />=======<br /><br /><ul>'; | |
for(var i=0; i<res.data.showcases.length; i++) { | |
var item = res.data.showcases[i]; | |
msgBody += '<li style="margin-left: 10px; list-style-type: disc !important">' + item.title + ' (id='+ item.id + ')</li>'; | |
if(i == 9){ | |
msgBody += (res.data.showcases.length - (i + 1)) + ' more...<br /><br />' | |
break; | |
} | |
} | |
msgBody += '</ul>'; | |
} | |
if(msgBody.length > 0) | |
Ext.Msg.alert('failed to unpublish this feature', msgBody); | |
}, | |
scope: this | |
}, this); | |
} | |
}, this); | |
}, | |
update: function (data) { | |
this.tpl.overwrite(this.body, data); | |
if (CCA.feature.Util.getAccountProfile() != 'profile.writer') { | |
var link = Ext.get('unpublish_' + data.id); | |
link.on('click', this.unPublish, this, data.id); | |
} | |
var grid = Ext.getCmp('feature_grid'); | |
var store = grid.store; | |
var range = store.getRange(); | |
for (var i = 0, len = range.length; i < len; i++) { | |
if (range[i].data.id == data.id) { | |
var record = range[i]; | |
} | |
} | |
if(record instanceof Ext.data.Record) { | |
record.set('published_at',data.published_at); | |
record.set('published',data.published); | |
} | |
} | |
}); | |
Ext.reg('publishedurl', CCA.feature.PublishedUrl); | |
/** | |
* register all the Feature Entities as xtypes, making the loop to create the accordian | |
* much simpler. This way, we can just instantiate new xtypes and not embed presentation logic | |
* in the models as it is presently done. | |
*/ | |
Ext.reg('quote_panel', CCA.feature.EntityPanel); | |
Ext.reg('organizer_panel', CCA.feature.EntityPanel); | |
Ext.reg('sponsor_panel', CCA.feature.EntityPanel); | |
Ext.reg('credit_panel', CCA.feature.EntityPanel); | |
Ext.reg('publisher_panel', CCA.feature.EntityPanel); | |
Ext.reg('item_panel', CCA.feature.EntityPanel); | |
Ext.reg('subject_panel', CCA.feature.EntityPanel); | |
Ext.reg('quote_edit', CCA.feature.EntityEditForm); | |
Ext.reg('organizer_edit', CCA.feature.EntityEditForm); | |
Ext.reg('sponsor_edit', CCA.feature.EntityEditForm); | |
Ext.reg('credit_edit', CCA.feature.EntityEditForm); | |
Ext.reg('publisher_edit', CCA.feature.EntityEditForm); | |
Ext.reg('item_edit', CCA.feature.EntityEditForm); | |
Ext.reg('subject_edit', CCA.feature.EntityEditForm); | |
Ext.reg('DateAdmission', CCA.feature.AdmissionForm); | |
/** | |
* register all the Feature Media as xtypes, panels and forms | |
*/ | |
Ext.reg('image_panel', CCA.feature.MediaPanel); | |
Ext.reg('audio_panel', CCA.feature.MediaPanel); | |
Ext.reg('video_panel', CCA.feature.MediaPanel); | |
Ext.reg('slideshow_panel', CCA.feature.SlideshowPanel); | |
Ext.reg('othermedia_panel', CCA.feature.MediaPanel); | |
Ext.reg('link_panel', CCA.feature.MediaPanel); | |
/** | |
* various forms for editing existing media assigned to Features | |
*/ | |
Ext.reg('image_edit', CCA.feature.MediaEditForm); | |
Ext.reg('audio_edit', CCA.feature.MediaEditForm); | |
Ext.reg('video_edit', CCA.feature.MediaEditForm); | |
Ext.reg('slideshow_edit', CCA.feature.SlideshowManager); | |
Ext.reg('othermedia_edit', CCA.feature.MediaEditForm); | |
Ext.reg('slideshow_form', CCA.feature.MediaEditForm); | |
Ext.reg('link_edit', CCA.feature.MediaEditForm); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment