ExtJs: How to use plugin within defined component in MVC architecture? - javascript

Due to the lack of experience, I can't find how to activate an upload plugin in button component using MVC architecture.
When I used few files, this plugin works perfect.
But when I started to move to MVC direction, everything begin to fall apart.
Here is how I initialize the plugin:
Ext.Loader.setConfig( {
enabled: true,
paths: {
'Ext.ux.upload': 'ext-4.2.1.883/src/ux/upload/'
}
});
Ext.require([
....
'Ext.ux.upload.Button',
'Ext.ux.upload.plugin.Window',
.....
Here is the "old way" which worked perfect (button is situated on a panel, when you click it, the plugin upload window opens):
ObjectPhotosTab = Ext.create('Ext.Panel', {
disabled : true,
id : 'ObjectPhotosTab',
collapsible : true,
frame : true,
title : 'Photos',
items : [
//here goes button with upload plugin
Ext.create('Ext.ux.upload.Button', {
text : 'Select files',
id : 'ObjectPhotosUploadBtn',
SelectedObjectId : 0,
autoRender : true,
hidden : true,
plugins: [{
ptype : 'ux.upload.window',
title : 'Upload',
width : 320,
height : 350,
pluginId: 'pid'
}],
uploader: {
url : MainSiteUrl + 'getimages.php?a=a&Object=',
uploadpath : '/Root/files',
autoStart : true,
max_file_size : '2020mb',
statusQueuedText: 'Ready to upload',
statusUploadingText: 'Uploading ({0}%)',
statusFailedText: '<span style="color: red">Error</span>',
statusDoneText: '<span style="color: green">Complete</span>',
statusInvalidSizeText: 'File too large',
statusInvalidExtensionText: 'Invalid file type'
},
listeners: {
filesadded: function(uploader, files) {
console.log('filesadded');
return true;
},
.......,
scope: this
}
}),
Ext.getCmp('ImagesDataView') // other stuff
]
});
In my new application I have moved an upload button to the "view" directory (surely through controller) and put plugin params to initComponent like this:
Ext.define('crm.view.ObjectPhotosUploadBtn',{
extend: 'Ext.ux.upload.Button',
text : 'Select files',
id : 'ObjectPhotosUploadBtn',
alias : 'widget.ObjectPhotosUploadBtn',
SelectedObjectId : 0,
autoRender : true,
hidden : false,
initComponent: function() {
this.plugins = {
ptype : 'ux.upload.window',
title : 'Upload',
width : 320,
height : 350,
pluginId: 'pid'
};
this.uploader ={
// exactly the same stuff
};
this.listeners = {
// exactly the same stuff
};
this.callParent();
}
})
New defined button class is called from a panel like this:
ObjectPhotosTab = Ext.create('Ext.Panel', {
disabled : true,
id : 'ObjectPhotosTab',
collapsible : true,
frame : true,
title : 'Photos',
items : [
Ext.widget('ObjectPhotosUploadBtn'), // call button via widget
Ext.getCmp('ImagesDataView') // other stuff
]
});
Here is the header of file /ext-4.2.1.883/src/ux/upload/plugin/Window.js
/**#class Ext.ux.upload.plugin.Window
* #extends Ext.AbstractPlugin
* #author Harald Hanek (c) 2011-2012
* #license http://harrydeluxe.mit-license.org*/
Ext.define('Ext.ux.upload.plugin.Window', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.ux.upload.window',
requires: [ 'Ext.ux.statusbar.StatusBar',
'Ext.ux.statusbar.ValidationStatus' ],
constructor: function(config) {
var me = this;
Ext.apply(me, config);
me.callParent(arguments);
},
init: function(cmp) {
var me = this,
uploader = cmp.uploader;
cmp.on({
filesadded: {
......
Here is the header of file /ext-4.2.1.883/src/ux/upload/Button.js
/**#class Ext.ux.upload.Button
* #extends Ext.button.Button
* #author Harald Hanek (c) 2011-2012
* #license http://harrydeluxe.mit-license.org */
Ext.define('Ext.ux.upload.Button', {
extend: 'Ext.button.Button',
alias: 'widget.uploadbutton',
requires: ['Ext.ux.upload.Basic'],
disabled: true,
constructor: function(config) {
var me = this;
config = config || {};
Ext.applyIf(config.uploader, {
browse_button: config.id || Ext.id(me)
});
me.callParent([config]);
},
initComponent: function() {
var me = this,
e;
me.callParent();
me.uploader = me.createUploader();
......
The problem is that the button is created successfully but it does not do needed plugin action.
I see no errors in ff/chrome console also.
When I inspect "crm.view.ObjectPhotosUploadBtn" through the Illuminations ff plugin, I can see all needed plugin properties of this class.
Please help me to solve this question.

There is too much code for me to quote, but the problem lies in this snippet:
Ext.define('crm.view.ObjectPhotosUploadBtn',{
extend: 'Ext.ux.upload.Button',
...
initComponent: function() {
this.plugins = {
...
};
}
});
By the time initComponent is executed, the plugins have already been constructed and initialized in the constructor, and your initComponent overwrites all that.
What you need instead is to move the plugins blob into the class definition:
Ext.define('crm.view.ObjectPhotosUploadBtn', {
extend: 'Ext.ux.upload.Button',
...
plugins: [{
ptype : 'ux.upload.window',
title : 'Upload',
width : 320,
height : 350,
pluginId: 'pid'
}]
});
The same goes for uploader and listeners assignments.

Related

How to access parent component ExtJS?

For some reason, the blur event doesn't get fired when the below floating panel loses focus. However, when I listen to the 'el' of the panel for the blur event, it gets registered as shown in the listeners config. What I want to do is hide the panel when the blur event occurs. How do I get access to the parent panel ?
Ext.define('NoteKeeper.view.tabs.AttachmentPanel',{
extend : 'Ext.panel.Panel',
alias : 'widget.attachmentPanel',
itemId : 'attachmentPanel',
floating : true,
focusable : true,
width : 200,
height : 150,
layout : {
type : 'vbox'
},
items : [
{
xtype : 'grid',
store : null,
columns : [
{
text : 'File Name',
dataIndex : 'fileName'
},
{
dataIndex : 'remove'
}
]
},
{
xtype : 'button',
text : '+'
}
],
listeners : {
el: {
blur: {
fn: function()
{
console.log( this );
//how do I access the 'attachmentPanel' from here
//so I can hide it ?
}
}
}
},
noteId : null,
initComponent : function()
{
this.callParent(arguments);
}
});
Please note that there can be multiple instances of these 'attachmentPanel's.
The following appears to work fine:
listeners : {
el: {
blur: {
fn: function()
{
console.log(this);
var elId = this.id;
var attachmentPanels = Ext.ComponentQuery.query('#attachmentPanel');
Ext.Array.forEach( attachmentPanels, function(cmp){
if(cmp.id == elId)
{
cmp.hide();
return false;
}
});
}
}
}
Please let me know if there is better/more efficient solution. Thanks!
There is a reference from the element to the owning component, in form of the component property, so from the scope of the element, you can access the panel like so:
var attachmentPanel = this.component;

How to split up code for better readability?

I want to clean up my code for better readability and put some code in extra js-files but nothing I've tried has worked.
It's a SubApp and part of a larger Project (Shopware) that is still using ExtJs 4.1.
I have a "main/window.js" that extends 'Ext.window.Window'.
initComponent looks like this:
initComponent: function () {
//...
me.dockedItems = [
me.createTopToolbar(),
];
//...
}
createTopToolbar is a Method inside "main/window.js" that return a Ext.toolbar.Toolbar with some elements.
My goal is to put this method in an extra file.
I tried to create a new static/singleton class like this
Ext.define('myapp.myplugin.view.main.Toptoolbar', {
singleton: true,
createTopToolbar: function(){
// ...
return toolbar;
}
But inside "main/window.js" i cannot call it using myapp.myplugin.view.main.Toptoolbar.createTopToolbar(), or main.Toptoolbar.createTopToolbar()
In app.js i tried to include it like this
views: [
'main.Window',
'main.Toptoolbar',
],
but it doesnt work.
I have no experience with ExtJs and search for hours...hope someone can help me.
Thank you
Edit
To answer the question why i'm building the toolbar within a function.
The whole functions looks like this:
createTopToolbar: function () {
var me = this;
var shopStore = Ext.create('Shopware.apps.Base.store.Shop');
shopStore.filters.clear();
shopStore.load({
callback: function(records) {
shopCombo.setValue(records[0].get('id'));
}
});
var shopCombo = Ext.create('Ext.form.field.ComboBox', {
name: 'shop-combo',
fieldLabel: 'Shop',
store: shopStore,
labelAlign: 'right',
labelStyle: 'margin-top: 2px',
queryMode: 'local',
valueField: 'id',
editable: false,
displayField: 'name',
listeners: {
'select': function() {
if (this.store.getAt('0')) {
me.fireEvent('changeShop');
}
}
}
});
var toolbar = Ext.create('Ext.toolbar.Toolbar', {
dock: 'top',
ui: 'shopware-ui',
items: [
'->',
shopCombo
]
});
return toolbar;
}
And i dont want the whole code inside my "main/window.js".
I'm not sure using the xtype solution provided by Jaimee in this context because i dont realy extend 'Ext.toolbar.Toolbar'. I just need a "wrapper" for my "shopCombo" code and return 'Ext.toolbar.Toolbar' with shopCombo as an item.
Create the toolbar as you would any other view, and create an 'xtype' to add it to your window.
Ext.define('myapp.myplugin.view.main.Toptoolbar', {
extends: 'Ext.toolbar.Toolbar',
xtype: 'mytoptoolbar',
dock: 'top',
ui: 'shopware-ui',
items :[
'->',
{
xtype: 'combobox',
name: 'shop-combo',
fieldLabel: 'Shop',
store: 'shopStore',
labelAlign: 'right',
labelStyle: 'margin-top: 2px',
queryMode: 'local',
valueField: 'id',
editable: false,
displayField: 'name',
listeners: {
'select': function() {
if (this.store.getAt('0')) {
me.fireEvent('changeShop');
}
}
}
}]
});
And then simply add it to your window's docked items like you would any other component:
initComponent: function () {
//...
me.dockedItems = [
{
xtype: 'mytoptoolbar'
}
];
//...
}
And the load listener can be added to the store.
Ext.define('Shopware.apps.Base.store.Shop', {
// ....
listeners:
{
load: function() {
Ext.ComponentQuery.query("combobox[name='shop-combo']")[0].setValue(...)
}
}
However, I'd suggest just setting a starting value for the combobox if it's a predictable value. You'll need to add the store to your controller's stores config if you haven't already.
You could use a factory pattern like so:
Ext.define('ToolbarFactory', {
alias : 'main.ToolbarFactory',
statics : {
/**
* create the toolbar factory
*/
factory : function() {
console.log('create the toolbar');
var toolbar = ....;
return toolbar;
}
}
});
Then you can create the Toolbar this way:
initComponent: function () {
//...
me.dockedItems = [
ToolbarFactory.factory();
];
//...
}
Depending on your build process you may need to add a requires statement.

Load extra conditional in backbone js page

I have a backbone app developed externally - initially where I perform the definitions & inject jquery etc..) on the first line - the 7th param is the 'tools template')
I
P.S A lot of code has been removed from here for clarity/ease (as it is well over 800 lines with all the other code) & this is all new to me so feel free to point out any obvious mistakes
On Line 8 - I have the following line:
window.isMobileDevice ? "text!views/tools/templates/i_tools.html" : "text!views/tools/templates/tools.html",
This basically does a 'if a mobile device load mobile page OTHERWISE load the standard (desktop) page.
I want to amend this with some additional logic but unsure how...
I want to add in another conditional, which basically says the following:
if (mobile device)
Load mobile page (as is now) e.g mobile-tools.html
else
if (stampVar == true)
load desktop stamp page e.g stamp-tools.html
else
load the standard desktop page e.g tools.html
Any ideas on how to do this? The stampVar will basically be true/false and i'm trying to work out how to load that in dynamically from an existing js object
define([
"jquery",
"backbone",
"config",
"models/model",
"collections/collection",
"views/tools/toolsBase",
window.isMobileDevice ? "text!views/tools/templates/i_tools.html" : "text!views/tools/templates/stamper_tools.html",
window.isMobileDevice ? "text!views/tools/templates/i_editor.html" : "text!views/tools/templates/editor.html",
window.isMobileDevice ? "text!views/tools/templates/i_txts.html" : "text!views/tools/templates/txts.html",
window.isMobileDevice ? "text!views/tools/templates/i_txtsItem.html" : "text!views/tools/templates/txtsItem.html",
"text!views/tools/templates/fontItem.html",
"curvetext"
],
function ($, Backbone, Config, Model, Collection, ToolsBase, ToolsTmpl, EditorTmpl, TxtTmpl, TxtItemTmpl, FontItemTmpl) {
"use strict";
var View = ToolsBase.extend({
initialize: function() {
var self = this;
if (window.isMobileDevice) {
$(window).bind("resize.app", _.bind(this.resizeTools, this));
}
},
render: function() {
var self = this, tpl_data, tools_tpl_data;
$('.customtool-title .tools-tabs').show();
self.stickerSetup();
//console.log(app.ctors);
tools_tpl_data = {
tips: app.settings.tips,
isCompetition: app.settings.competition !== undefined,
allowCodes: app.ctors["toolsCtor"].getAllowCodes(),
customType: 'stamper'
};
if (app.settings.competition !== undefined) {
tools_tpl_data.competition = app.settings.competition
}
console.log(ToolsTmpl);
self.$el.find(".tools").append(_.template(ToolsTmpl, tools_tpl_data));
tpl_data = {
stickerTxtTop : self.selectedTxt.top,
stickerTxtMiddle : self.selectedTxt.middle,
stickerTxtBottom : self.selectedTxt.bottom,
selectedtitle : self.selectedTitle,
selectedtemplate : self.selectedTemplate,
stickerTemplate : Config.templates + self.selectedTemplate + Config.templateExtension,
isCompetition : app.settings.competition !== undefined,
designType: app.ctors["toolsCtor"].getDesignType(),
tips: app.settings.tips,
selectedCodes : self.selectedCodes,
selectedPoints : self.selectedPoints
};
if (app.settings.competition !== undefined) {
tpl_data.competition = app.settings.competition;
}
if (self.backgroundType === "color") {
tpl_data.stickerBgImage = null;
tpl_data.stickerFgImage = this.getFgPath(self.stickerFgImage);
self.$el.find(".editor").append(_.template(EditorTmpl, tpl_data));
$(".customtool-background").hide();
$('.customtool-fill').css({
background: self.stickerBgColor,
opacity: self.stickerBgOpacity
}).show();
} else {
tpl_data.stickerFgImage = this.getFgPath(self.stickerFgImage);
tpl_data.stickerBgImage = this.getBgPath(self.stickerBgImage);
self.$el.find(".editor").append(_.template(EditorTmpl, tpl_data));
$(".customtool-background").show();
$('.customtool-fill').hide();
}
self.applyTextFormatting();
self.refreshArcs(1,".customtool-toptext", self.selectedTxt.top.arc);
self.refreshArcs(2,".customtool-middletext", self.selectedTxt.middle.arc);
self.refreshArcs(3,".customtool-bottomtext", self.selectedTxt.bottom.arc);
self.toggleCodes();
if (app.settings.competition !== undefined && !window.isMobileDevice) {
$('#dialog-form').dialog({
autoOpen: false,
width: 600,
modal: true,
zIndex: 1001,
dialogClass: 'competition-dialog',
draggable: false,
buttons: [{
'text': "Create Another",
'class': 'pull-right createanother',
'style': 'display:none',
'click': function(e) {
self.restart(e);
return false;
}
}, {
'text': "Enter Competition",
'class': 'pull-right green enter',
'disabled': true,
'click': function(e) {
self.competitionEnter(e);
return false;
}
}, {
'text': "Order",
'class': 'pull-right continue green',
'style': 'display:none',
'click': function(e) {
self.competitionContinue(e);
return false;
}
}, {
'text': "Cancel",
'class': 'pull-left cancelcomp',
'click': function(e) {
self.competitionCancel(e);
return false;
}
}]
});
}
if (app.settings.competition !== undefined) {
_gaq.push(['_trackPageview', '/sticker-competition/editor']);
}
if (!window.isMobileDevice) {
app.trigger("tools:bg");
}
}
}, {
sticker_id: null,
toolsOpen: false
});
return View;
});

ExtJS Ext.panel.Panel tools order

I've got this panel. It shows tools icons in this order: gear, close, collapse.
I'd like to get icons is this order: gear, collapse, close. I can't figure it out.
When I put collapseFirst: true, then collapse is at the first position.
Here's an alternative link to the SenchFiddle
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('Ext.panel.Panel', {
width : 500,
height: 200,
title : 'Panel',
renderTo: Ext.getBody(),
closable : true,
collapsible : true,
collapseFirst : false,
tools: [{
type : 'gear'
}],
initTools: function() {
var me = this,
tools = me.tools,
i, tool;
me.tools = [];
for (i = tools && tools.length; i; ) {
--i;
me.tools[i] = tool = tools[i];
tool.toolOwner = me;
}
// Add a collapse tool unless configured to not show a collapse tool
// or to not even show a header.
if (me.collapsible && !(me.hideCollapseTool || me.header === false || me.preventHeader)) {
if (Ext.getVersion().major == '4') {
me.collapseDirection = me.collapseDirection || me.headerPosition || 'top';
me.collapseTool = me.expandTool = Ext.widget({
xtype: 'tool',
handler: me.toggleCollapse,
scope: me
});
me.updateCollapseTool();
// Prepend collapse tool is configured to do so.
if (me.collapseFirst) {
me.tools.unshift(me.collapseTool);
}
} else {
me.updateCollapseTool();
// Prepend collapse tool is configured to do so.
if (me.collapseFirst) {
me.tools.unshift(me.collapseTool);
}
}
}
if (me.pinnable) {
me.initPinnable();
}
// Add subclass-specific tools.
me.addTools();
// Append collapse tool if needed.
if (me.collapseTool && !me.collapseFirst) {
me.addTool(me.collapseTool);
}
// Make Panel closable.
if (me.closable) {
me.addClsWithUI('closable');
me.addTool({
xtype : 'tool',
type: 'close',
scope: me,
handler: me.close
});
}
}
});
}
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/extjs/4.2.1/resources/css/ext-all-neptune.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/extjs/4.2.1/ext-all-debug.js"></script>
Thanks anyone for help :)
EDIT: Found that overriding the initTools method is a better solutions for this
EDIT 2: Supports both ExtJS 4.2 and ExtJS 5.x
Ext.create('Ext.panel.Panel', {
width : 500,
height: 500,
title : 'Panel',
renderTo: Ext.getBody(),
closable : true,
collapsible : true,
collapseFirst : false,
tools: [{
type : 'gear'
}],
initTools: function() {
var me = this,
tools = me.tools,
i, tool;
me.tools = [];
for (i = tools && tools.length; i; ) {
--i;
me.tools[i] = tool = tools[i];
tool.toolOwner = me;
}
// Add a collapse tool unless configured to not show a collapse tool
// or to not even show a header.
if (me.collapsible && !(me.hideCollapseTool || me.header === false || me.preventHeader)) {
if (Ext.getVersion().major == '4') {
me.collapseDirection = me.collapseDirection || me.headerPosition || 'top';
me.collapseTool = me.expandTool = Ext.widget({
xtype: 'tool',
handler: me.toggleCollapse,
scope: me
});
me.updateCollapseTool();
// Prepend collapse tool is configured to do so.
if (me.collapseFirst) {
me.tools.unshift(me.collapseTool);
}
} else {
me.updateCollapseTool();
// Prepend collapse tool is configured to do so.
if (me.collapseFirst) {
me.tools.unshift(me.collapseTool);
}
}
}
if (me.pinnable) {
me.initPinnable();
}
// Add subclass-specific tools.
me.addTools();
// Append collapse tool if needed.
if (me.collapseTool && !me.collapseFirst) {
me.addTool(me.collapseTool);
}
// Make Panel closable.
if (me.closable) {
me.addClsWithUI('closable');
me.addTool({
xtype : 'tool',
type: 'close',
scope: me,
handler: me.close
});
}
}
});

CKEditor Plugin - OK Button Permission Error

Hi i have created the following ckeditor plugin to insert a youtube video:
(function() {
CKEDITOR.plugins.add('youtube', {
requires : ['iframedialog'],
init : function(editor) {
var iframeWindow = null;
CKEDITOR.dialog.add('youtube_dialog', function() {
return {
title : 'YouTube Movie Properties',
minWidth : 550,
minHeight : 200,
contents : [{
id : 'iframe',
label : 'Insert YouTube Movie',
expand : true,
elements : [{
type : 'iframe',
src : me.path + 'dialogs/youtube.html',
width : '100%',
height : '100%',
onContentLoad : function() {
iframeWindow = document.getElementById(this._.frameId).contentWindow;
}
}]
}],
onOk : function() {
this._.editor.insertHtml('<cke:youtube url="' + iframeWindow.document.getElementById('url').value + '">YouTube Video Place Marker</cke:youtube>');
}
};
});
editor.addCommand('youtube', new CKEDITOR.dialogCommand('youtube_dialog'));
editor.ui.addButton('YouTube', {
label : 'Insert YouTube Movie',
command : 'youtube',
icon : this.path + 'images/icon.gif'
});
}
});
})();
This was working fine but i recently moved my ckeditor files to a CDN. Now when i click the "OK" button i get a permission error. I was looking at the source of the existing plugins to get an idea of how they work but whatever i have tried doesn't seem to work. To get something basic working I tried changing my okOk event to:
onOk : function() {
var hr = new CKEDITOR.dom.element('hr', editor.document );
editor.insertElement(hr);
}
But this gave me a null reference exception.
I'd really appreciate it if someone could show me what i am doing wrong. Thanks
Problem fixed! The solution is to change:
CKEDITOR.dialog.add('youtube_dialog', function()
to:
CKEDITOR.dialog.add('youtube_dialog', function(editor)
and change:
this._.editor
to:
editor
Hope this helps.

Categories

Resources