/*
* Copyright 2017 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This class provides a widget to select a image. The image can be file or a glyph.
*
* This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_FILE.<br>
*
* This widget is configurable:<br>
* - Use {@link #cfg-allowExtensions} to restrict files by extensions such as 'pdf', 'xml', 'png'.... <br>
* - Use {@link #cfg-allowSources} to specify the authorized file sources (eg: 'external' for local resource, 'resource' for shared resource). Separated by comma.<br>
* See the subclasses of {@link Ametys.form.widget.File.FileSource} and {@link Ametys.form.widget.Illustration.GlyphSource} for the available sources.<br>
*/
Ext.define('Ametys.form.widget.Illustration', {
extend: 'Ametys.form.widget.File',
/**
* @cfg {String[]} _cssLinkElmtIds The id of CSS link elements inserted dynamically.
*/
_cssLinkElmtIds: [],
/**
* @cfg {String|String[]} [allowGlyphSources] The allowed sources for glyphes in a Array or separated by coma.
*/
statics: {
/**
* @property {Object} _glyphSources The glyph sources
* @private
*/
_glyphSources: [],
/**
* Register a new glyph source
* @param {String} source The glyph sources
* @param {Ametys.form.widget.Illustration.GlyphSource} className The object class associated with this source
*/
registerGlyphSource: function (source, className)
{
this._glyphSources[source] = className;
},
/**
* Get the object class associated with the given glyph source type
* @param {String} source The glyph source
* @return {Ametys.form.widget.Illustration.GlyphSource} The glyph source class
*/
getGlyphSource: function (source)
{
return this._glyphSources[source];
}
},
constructor: function (config)
{
config.filter = 'image'; // force image filter
this.glyphSources = [];
if (!Ext.isEmpty(config['allowGlyphSources']))
{
this.glyphSources = Ext.isArray(config['allowGlyphSources']) ? config['allowGlyphSources'] : config['allowGlyphSources'].split(',');
}
this.callParent(arguments);
delete config.allowGlyphSources;
},
initComponent: function (config)
{
// Preview Glyph
this.glyph = Ext.create('Ext.Component', {
cls: this.imgWithBorderCls + ' ' + this.glyphCls,
hidden: true,
width: 48 + 6, // image width + padding
height: 48 + 6, // image height + padding
style: {
fontSize: this.imagePreviewMaxWidth - 10 + 'px'
}
});
this.items = [];
this.items.push(this.glyph);
this.callParent(arguments);
this.on('hide', this._removeStylesheets, this);
this.on('destroy', this._removeStylesheets, this);
},
// Override to allow only glyph sources
_prepareFileSources: function(config)
{
if (Ext.isEmpty(config['allowSources']) && Ext.isEmpty(config['allowGlyphSources']))
{
/**
* @protected
* @cfg {String[]} [defaultSources=[Ametys.form.widget.File.External.SOURCE]] The sources to use when {#cfg-allowSources} is null or empty
*/
this.fileSources = config.defaultSources || [Ametys.form.widget.File.External.SOURCE];
}
else if (Ext.isEmpty(config['allowSources']))
{
this.fileSources = [];
}
else
{
this.fileSources = Ext.isArray(config['allowSources']) ? config['allowSources'] : config['allowSources'].split(',');
}
delete config.allowSources;
},
getBtnConfig: function ()
{
// Menu
if ((this.fileSources.length + this.glyphSources.length) > 1)
{
var menuItems = this._getMenuItemsForFileSources();
menuItems = Ext.Array.merge(menuItems, this._getMenuItemsForGlyphSources());
return {
text: this.getInitialConfig('buttonText') || Ametys.form.widget.File.filters[this.fileFilter].buttonMenuText,
tooltip: this.getInitialConfig('buttonTooltip') || Ametys.form.widget.File.filters[this.fileFilter].buttonMenuTooltip,
iconCls: this.getInitialConfig('buttonIconCls') || Ametys.form.widget.File.filters[this.fileFilter].buttonMenuIconCls,
menu: menuItems,
disabled: this.disabled
}
}
// Only a file
else if (this.fileSources.length == 1)
{
var source = Ametys.form.widget.File.getFileSource(this.fileSources[0]);
var btnCfg = source.getBtnConfig (this.getInitialConfig(), this.fileFilter);
return Ext.apply(btnCfg, {
handler: this._selectFile,
scope: this,
disabled: this.disabled
});
}
// Only a glyph
else
{
var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[0]);
var btnCfg = source.getBtnConfig (this.getInitialConfig());
return Ext.apply(btnCfg, {
handler: this._selectGlyph,
scope: this,
disabled: this.disabled
});
}
},
/**
* @private
* Get the configuration for menu items for the available glyph sources
* @return {Object} The menu items
*/
_getMenuItemsForGlyphSources: function()
{
var items = [];
for (var i=0; i < this.glyphSources.length; i++)
{
var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[i]);
var itemCfg = source.getMenuItemConfig (this.getInitialConfig());
items.push(Ext.apply(itemCfg, {
xtype: 'menuitem',
itemId: 'menuitem-glyph-source-' + source.getId(),
handler: this._selectGlyph,
scope: this,
hidden: true
}));
}
return items;
},
/**
* Get CSS files
*/
afterRender: function()
{
this.callParent(arguments);
this._cssLinkElmtIds = [];
// Iterate over glyph sources
for (var i=0; i < this.glyphSources.length; i++)
{
var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[i]);
source.isAvailable(Ext.bind(this._isSourceAvailable, this, [source], 1))
}
},
/**
*
* @param {Boolean} available True if the source is availble
* @param {Ametys.form.widget.Illustration.GlyphSource} source The source
*/
_isSourceAvailable: function(available, source)
{
if (available)
{
source.getCSSFiles(Ext.bind(this._createStyleSheet, this));
var menuitem = this.down("#menuitem-glyph-source-" + source.getId())
if (menuitem)
{
menuitem.setVisible(true);
}
}
},
/**
* @private
* Remove css in a link tag according to _cssLinkElmtIds array of ids
*/
_removeStylesheets: function()
{
Ext.Array.forEach(this._cssLinkElmtIds, function (elmtId) {
var styleEl = document.getElementById(elmtId);
if (styleEl)
{
styleEl.parentNode.removeChild(styleEl);
}
});
this._cssLinkElmtIds = [];
},
/**
* @private
* Insert a <link> element into the <head> element for each CSS files for glyphes
* @param {Object} response CSS urls to load
*/
_createStyleSheet: function (response)
{
var head = document.getElementsByTagName('head')[0];
var me = this;
Ext.Array.forEach(response.cssFiles, function (href) {
me._cssLinkElmtIds.push(cssId);
var cssId = me.getId() + '-css-glyph-' + i;
var styleEl = document.createElement('link');
styleEl.setAttribute('type', 'text/css');
styleEl.setAttribute('rel', 'stylesheet');
styleEl.setAttribute('id', cssId);
styleEl.setAttribute('href', href);
head.appendChild(styleEl);
});
},
/**
* @private
* Select a glyph.
* @param {Ext.Button} btn The button calling this function
*/
_selectGlyph: function (btn)
{
var source = Ametys.form.widget.Illustration.getGlyphSource(btn.source);
source.handler(this.getInitialConfig(), Ext.bind(this._insertGlyphCb, this));
},
/**
* @private
* Callback function, called when a glyph is selected in the dialog.
*/
_insertGlyphCb: function (glyph)
{
if (glyph == null)
{
return;
}
this.setValue({
id: glyph,
type: 'glyph'
});
},
_updateUI: function()
{
var value = this.value;
if (value && value.type == 'glyph')
{
if (!this.readOnly)
{
this.deleteButton.show();
this.button.hide();
}
this._updateGlyphUI(value.id);
}
else
{
this.glyph.hide();
this.callParent(arguments);
}
},
/**
* @private
* Construct the glyph and update the display field
* @param {String} glyph The CSS class of glyph
*/
_updateGlyphUI: function(glyph)
{
if (this.img)
{
this.img.setVisible(false);
}
this.glyph.update('<span class="' + glyph + '"></span>');
this.glyph.setVisible(true);
this.displayField.setHeight(21);
this.displayField.update(glyph);
}
});