Yahoo.extend in alfresco for extending dnd-upload component - javascript

I would like to customize the dnd-upload.js file. For example I want to override _adjustGuiIfFinished method. I've tried several times to do it, but all of them failed (I was using some tutorials/examples:
http://blogs.alfresco.com/wp/wabson/2011/08/12/custom-admin-console-components-in-share/
https://forums.alfresco.com/forum/developer-discussions/alfresco-share-development/javascrip-autocompete-yahoo-library-03152012)
Here are my steps:
create .js file, let's say dnd-upload-ep.js with following contents:
(function ()
{
Alfresco.EpDNDUpload = function Alfresco_EpDNDUpload(htmlId)
{
Alfresco.EpDNDUpload.superclass.constructor.call(this, htmlId);
return this;
};
YAHOO.extend(Alfresco.EpDNDUpload, Alfresco.DNDUpload,{
_adjustGuiIfFinished: function EpDNDUpload_adjustGuiIfFinished()
{
...
// function body with some modifications
...
})
});
include just created file in .ftl. Override dnd-upload.get.html.ftl and include file in js dependencies:
...
<#markup id="js">
<#-- JavaScript Dependencies -->
<#script type="text/javascript" src="${url.context}/res/components/upload/dnd-upload.js" group="upload"/>
<#script type="text/javascript" src="${url.context}/res/components/upload/dnd-upload-ep.js" group="upload"/>
</#>
...
instead of original DNDUpload instantiate recently created EpDNDUpload. To do it override dnd-upload.get.js changing 'Widget instantiation metadata':
...
//Widget instantiation metadata...
var dndUpload = {
id : "EpDNDUpload",
name : "Alfresco.EpDNDUpload",
assignTo : "dndUpload"
};
model.widgets = [dndUpload];
...
Seems that it should work, but it doesn't. When I upload document I got error that Alfresco.EpDNDUpload not created and could't be instantiated.
Is there is something I do wrong?

Related

How to keep script in partial view from loading more than once and causing errors when partial is used more than once in the same page

Working in ASP.NET MVC, I created a partial view which is rendered on the same page 2 times. My problem is the JavaScript is included as many times as the partial view is and JavaScript does not like classes to be redefined.
My question is: How do I include the JavaScript in the partial view so it remains modular, but only have it included in the page once? I am not interested in solutions which require including the .js file separately from the content of the partial view, like
<script src="some.js"></script>
#Html.Partial("some/partial.cshtml")
#Html.Partial("some/partial.cshtml")
but I am okay with a separate .js file that is included inside the partial view. The partial view should include within it everything that is needed to make it work.
My code is structured something like this:
<div id=#ViewBag.id></div>
<script>
class MyClass{
constructor(divName){
this._divId = divId;
}
doSomething(){
/* do stuff with element that has id of divId */
}
}
</script>
Then, in the calling file, I have
<body>
#Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
#Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
</body>
<script>
$().ready(function(){
id1Functionality = new MyClass("id_1"); // please forgive the poor naming :-)
id2Functionality = new MyClass("id_2");
id1Functionality.doSomething();
id2Functionality.doSomething();
})
</script>
One solution is to implement an Html helper extension function which will only load a script once. See below. (this can work for CSS and other included files, too).
Implement an extension for the HtmlHelper class and a private backing class as a singleton per HttpContext.
public static class YourHtmlHelperExtensionClass
{
private class TagSrcAttrTracker
{
private TagSrcAttrTracker() { }
public Dictionary<string, string> sources { get; } = new Dictionary<string, string>();
public static TagSrcAttrTrackerInstance {
get {
IDictionary items = HttpContext.Current.Items;
const string instanceName = "YourClassInstanceNameMakeSureItIsUniqueInThisDictionary";
if(!items.Contains(instanceName))
items[instanceName] = new TagSrcAttrTracker();
return items[instanceName] as TagSrcAttrTracker;
}
}
}
public static MvcHtmlString IncludeScriptOnlyOnce(this HtmlHelper helper, string urlOfScript)
{
if(TagSrcAttrTracker.Instance.sources.ContainsKey(urlOfScript))
return null;
TagSrcAttrTracker.Instance.sources[urlOfScript] = urlOfScript;
TagBuilder script = new TagBuilder("script");
scriptTag.MergeAttribute("src", urlOfScript);
return MvcHtmlString.Create(script.ToString());
}
}
Then, separate the JavaScript and other code into separate files.
Example .js file contents
class MyClass{
myFunction() {
constructor(divId){
this._divId = divId
}
doSomething() {
// do something with a div with id == divId
}
}
}
Example .cshtml file contents for partial view
<link rel="stylesheet" type="text/css" href="~/Content/CustomCSS/MyPartialView.css"/>
<div id="#ViewBag.id">
Some content! Yay!
</div>
#Html.IncludeScriptOnlyOnce("/Scripts/CustomScripts/MyPartialView.js")
Example .cshtml file that consumes the partial view
...
<body>
<h1>Here is some content!</h1>
#Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
#Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
#Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_3"} })
</body>
<script>
$().ready(
const id1Functionality = new MyClass("id_1") // forgive the poor naming :-)
const id2Functionality = new MyClass("id_3")
const id3Functionality = new MyClass("id_2")
id1Functionality.doSomething();
id2Functionality.doSomething();
id3Functionality.doSomething();
)
</script>
The partial view may have been included more than once and the JavaScript is packaged with the partial view, but the .js file is only included in the page once, hence no complaining by the browser that MyClass was declared more than once.

Odoo-12: I created a widget. How do I use it?

I created a custom module that defines a widget. here are the .js file as well as the QWeb template:
bh_sidebar.js
odoo.define('sidebar_widget.bh_sidebar', function (require) {
'use strict';
var Widget = require('web.Widget');
var widgetRegistry = require('web.widget_registry');
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
var bh_sidebar = Widget.extend({
init: function () {
var self = this;
this._super(parent);
console.log('Widget initialized!');
},
events: {},
start: function () {
this.$el.append(QWeb.render('bh_sidebar_template'));
console.log('Widget started!');
}
});
widgetRegistry.add(
'bh_sidebar', bh_sidebar
)
})
bh_sidebar.xml
<?xml version="1.0"?>
<templates id="template" xml:space="preserve">
<t t-name="bh_sidebar_template">
<div style="background-color:red;" class="myClass">
Button 1
Button 2
</div>
</t>
</templates>
I've added both to the backend assets using:
<odoo>
<data>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="script[last()]" position="after">
<script type="text/javascript" src="/sidebar_widget/static/src/js/bh_sidebar.js"></script>
<!-- <script type="text/javascript" src="/sidebar_widget/static/src/js/renderer.js"></script> -->
<link rel="stylesheet" type="text/scss" href="/sidebar_widget/static/src/scss/widget.scss"></link>
</xpath>
</template>
</data>
</odoo>
I've also added the templates to the manifest file.
This widget is supposed to display a red rectangle with two links, button 1 and button 2. I want this widget to be independent of any type of view, and just show up at the top of the screen beneath Odoo's navigation bar. How do I that? if I try to run my code as is, nothing happens. I've been at this for a week. Nothing I found on the internet helped. The documentation is criminally outdated, the ressources scarce.
I would appreciate any help.
Thank you.
Your widget will not be instantiated and inserted into the DOM automatically. To do this, you can hook into any of the already existing high-level widgets. For example, using the show_application method on the WebClient:
var WebClient = require('web.WebClient');
WebClient.include({
show_application: function () {
var sup = this._super.apply(this, arguments);
// Instantiate
var sidebar = new bh_sidebar();
// Insert in DOM
sidebar.insertAfter(this.$('.o_main'));
return sup;
},
});
I think u should render this view by using controller mechanism this will render this view independent from others view.

Tapestry properties in jQuery

I have two files: "Index.properties", "Index_es.properties" for multilenguage in Tapestry.
I want to read literals from those files in a *.js file, for example:
**Index.properties:**
menu=Main menu
menu-welcome=Welcome to my webpage
**Index_es.properties:**
menu=Menú principal
menu-welcome=Bienvenido a mi página web
**Index.tml:**
...
<script type="text/javascript" language="JavaScript"
src="${context:/javaScript/menu.js}"></script>
...
**menu.js:**
...
var currentOption=$('#activemenu').attr('name');
if (currentOption=="menu"){
$("#button1txt").text("${message:option1}");
}
...
How can I read the files since "menu.js"?
Thank you
About expansions
Expansions only work in your templates (.tml files) or in the component classes if you are using the #Component annotation, for example.
Component parameter documentation:
https://tapestry.apache.org/component-parameters.html
You cannot access files in JavaScript that are stored on the server. But you could pass them along with your script’s init script.
How to add custom scripts to your pages
Don’t do this to your template:
<script type="text/javascript" language="JavaScript" src="${context:/javaScript/menu.js}"></script>
Do this instead to your page class:
#Import(library = { "context:javaScript/menu.js" })
public class Index {
}
Read the documentation about this feature to learn more: http://tapestry.apache.org/javascript.html
Solution to your problem
With all that knowledge you’ll now rather want to pass the translations for your menu script like this:
#Import(library = { "context:javaScript/menu.js" })
public class Index {
#Inject
private Messages messages;
#Inject
private JavaScriptSupport javaScriptSupport;
void afterRender() {
javaScriptSupport.addInitializerCall("initMenu", new JSONObject()
put("option1", messages.get("option1"))
);
}
}
menu.js
(function( $, window ) {
'use scrict';
$.extend(Tapestry.Initializer, {
initMenu: function (spec) {
var currentOption=$('#activemenu').attr('name');
if (currentOption=="menu"){
$("#button1txt").text(spec.option1);
}
}
}
})(jQuery, window);

Error when trying to load custom Client Editor

I've followed the steps in this article to create a basic custom editor but I'm getting a 404 error when trying to enter Forms Edit mode from
/EPiServer/CMS/1.0.456/ClientResources/dtk/app/editors/EmailTextbox.js
The document linked article states that EPiServer automatically adds a mapping from /ClinetResources/Scripts to the app namespace. I took a punt and added a module.config to the root of my site, like so:
<?xml version="1.0" encoding="utf-8"?>
<module>
<assemblies>
<!-- This adds the Alloy template assembly to the "default module" -->
<add assembly="PropertyTest" />
</assemblies>
<dojoModules>
<!-- Add a mapping from alloy to ~/ClientResources/Scripts to the dojo loader configuration -->
<add name="app" path="Scripts" />
</dojoModules>
</module>
This fixed the 404 but now I get a type error in the console when I try to enter forms mode
TypeError {} dojo.js:15
(anonymous function) dojo.js:15
dojo.Deferred.reject.errback dojo.js:15
_174 dojo.js:15
dojo.Deferred._171.then.then dojo.js:15
dojo.Deferred.when.dojo.when dojo.js:15
dojo.declare._createInternal widgets.js:2
(anonymous function) widgets.js:2
_388 dojo.js:15
map dojo.js:15
dojo.declare._createWidgets widgets.js:2
(anonymous function) widgets.js:2
_388 dojo.js:15
_c6 dojo.js:15
_36 dojo.js:15
_7a dojo.js:15
_ee dojo.js:15
req.injectUrl._109 dojo.js:15
Why is this erroring?
The source of my JS file is as per the linked article but I've included below for completeness.
define([
// Inherited mixins
"dojo",
"dojo/_base/declare",
"dijit/_Widget",
"dijit/_TemplatedMixin"
], function (
dojo,
declare,
_Widget,
_TemplatedMixin) {
declare("app.editors.EmailTextbox", [_Widget, _TemplatedMixin], {
// templateString: [protected] String
// A string that represents the default widget template.
templateString: '<div> \
<input type="email" data-dojo-attach-point="email" data-dojo-attach-event="onchange:_onChange" /> \
</div>',
postCreate: function () {
// summary:
// Set the value to the textbox after the DOM fragment is created.
// tags:
// protected
this.set('value', this.value);
if (this.intermediateChanges) {
this.connect(this.email, 'onkeydown', this._onIntermediateChange);
this.connect(this.email, 'onkeyup', this._onIntermediateChange);
}
},
focus: function () {
// summary:
// Put focus on this widget.
// tags:
// public
dijit.focus(this.email);
},
isValid: function () {
// summary:
// Indicates whether the current value is valid.
// tags:
// public
var emailRegex = '[a-zA-Z0-9_.-]+#[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+';
if (!this.required) {
emailRegex = '(' + emailRegex + ')?';
}
var regex = new RegExp('^' + emailRegex + '$');
return regex.test(this.value);
},
onChange: function (value) {
// summary:
// Called when the value in the widget changes.
// tags:
// public callback
},
_onIntermediateChange: function (event) {
// summary:
// Handles the textbox key press events event and populates this to the onChange method.
// tags:
// private
if (this.intermediateChanges) {
this._set('value', event.target.value);
this.onChange(this.value);
}
},
_onChange: function (event) {
// summary:
// Handles the textbox change event and populates this to the onChange method.
// tags:
// private
this._set('value', event.target.value);
this.onChange(this.value);
},
_setValueAttr: function (value) {
// summary:
// Sets the value of the widget to "value" and updates the value displayed in the textbox.
// tags:
// private
this._set('value', value);
this.email.value = this.value || '';
}
});
});
If you've gotten your script to load properly then it's a good idea to deploy the debug versions of the script files. Head over to Debugging EPiServer CMS client side files for the download and instructions on how to deploy them.
With the compressed and minified versions it's very hard to figure out what's going wrong.
Are you aware that you can just use the RegularExpression attribute if you want email validation ?
[RegularExpression(EPiServer.Framework.Validator.EmailRegexString)]
public virtual string Email { get; set; }
If this occurs on a development box the solution is to disable the Broswer Link in Visual Studio.
http://www.herlitz.nu/2016/09/19/cant-load-the-episerver-edit-gui-in-development-environment/

separate views in different files while structuring jquery binds for large websites

I am trying to implement this way to structure my jquery binds, it worked perfect.
I just have one question:
In the sample in the article he put all the views in one namespace called SITENAME, and like that all views should exist in one .js file, how can I put the views in different .js files?
for example:
To put common view in common.js file and users view in users.js
Namespace SITENAME is just a JavaScript object.
If you have code like this:
SITENAME = {
common: { ... },
example1: { ... },
example2: { ... }
}
You can change it to:
SITENAME = {
common: { ... }
};
SITENAME.example1 = { ... };
SITENAME.example2 = { ... };
As you can see now the example1 and example2 objects are still defined inside SITENAME, but they are separated from the definition of SITENAME object itself.
So in your case you need to create your "namespace" object first (e.g. create app.js which will contain also some configuration stuff) and then you create separate .js files that will define own properties on already existing SITENAME object.
Example:
HTML:
...
<head>
...
<script src="js/app.js" />
<script src="js/example1.js" />
<script src="js/example2.js" />
</head>
...
app.js (insert here common functionality, configuration, etc):
App = { ... };
example1.js:
App.example1 = { ... };
example2.js:
App.example2 = { ... };

Categories