Durandal Weyland/Requirejs optimizer with kendo ui dataviz - kendo-ui

I'm building an app with Durandal to bundle with PhoneGap. When I'm trying to run the weyland optimizer I'm running into some issues.
The build and optimization runs fine without any errors (I'm using requirejs as optimizer), but when I run the application my kendo ui chart throws an error saying "Uncaught TypeError: Object [object Object] has no method 'kendoChart'".
If I pause in debug mode in chrome where the kendoChart binding is taking place and type "kendo" in the console I get the kendoobject and can view its properties and so on, so it's definitely in the DOM.
Iv'e google around quite a bit and found some threads here on SO but none of them seem to sort my issue out. For instance this thread or this one.
I have a custom knockout binding for the chart, which is provided below.
My weyland.config looks like this:
exports.config = function (weyland) {
weyland.build('main')
.task.jshint({
include: 'App/**/*.js'
})
.task.uglifyjs({
// not uglyfying anything now...
//include: ['App/**/*.js', 'Scripts/durandal/**/*.js', 'Scripts/custom/**/*.js']
})
.task.rjs({
include: ['App/**/*.{js,html}', 'Scripts/custom/**/*.js', 'Scripts/jquery/*.js', 'Scripts/durandal/**/*.js'],
exclude: ['Scripts/jquery/jquery-2.0.3.intellisense.js', 'App/main.js'],
loaderPluginExtensionMaps: {
'.html': 'text'
},
rjs: {
name: 'main',
baseUrl: 'App',
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions',
'knockout': '../Scripts/knockout/knockout-2.3.0',
'kendo': 'empty:', <-- tried refering kendo.all.min, or dataviz.chart or the path
'jquery': '../Scripts/jquery/jquery-2.0.3.min',
'Helpers': '../Scripts/custom/helpers',
........ other scripts ......
},
deps: ['knockout', 'ko_mapping', 'command'],
callback: function (ko, mapping, command) {
ko.mapping = mapping;
}
//findNestedDependencies: true, **<-- tried both true and false here**
inlineText: true,
optimize: 'none',
pragmas: {
build: true
},
stubModules: ['text'],
keepBuildDir: false,
out: 'App/main-built.js'
}
});
};
// The custom binding for the kendo chart
define([
'knockout',
'jquery',
'Helpers',
'kendo/kendo.dataviz.chart.min'
], function (
ko,
$,
helpers,
kendoui
) {
function drawChart(element, values, options) {
$(element).kendoChart({ **<-- this is where I get an error**
... options for chart ...
});
}
// kendoUi data viz chart
ko.bindingHandlers.moodChart = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
//set the default rendering mode to svg
kendo.dataviz.ui.Chart.fn.options.renderAs = "svg"; **<-- this renders no errors**
// if this is a mobile device
if (kendo.support.mobileOS) {
// canvas for chart for you!
kendo.dataviz.ui.Chart.fn.options.renderAs = "canvas";
}
var values = ko.unwrap(valueAccessor());
setTimeout(function () {
drawChart(element, values);
}, 125);
}
};
});
I might add that everything works fine running the not optimized code in a web browser (or a phone for that matter).
I've also tried to shim the kendo path in the config file and add a dependency to jquery, which doesn't really seem to do any difference.
Any help would be appreciated!

For large frameworks like kendo that have their own set of dependencies e.g. jquery version, I tend not to bundle them with my own AMD modules. Personal preference, I know.
Take a look at how you could load jquery , knockout and kendo via normal script tags in the .NET example
<body>
<div id="applicationHost"></div>
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.js"></script>
<script type="text/javascript" src="~/Scripts/whateverKendoVersionGoesHere.js"></script>
<script type="text/javascript" src="~/Scripts/knockout-2.3.0.js"></script>
<script type="text/javascript" src="~/Scripts/bootstrap.js"></script>
<script type="text/javascript" src="~/Scripts/require.js" data-main="/App/main"></script>
</body>
That way jquery and knockout will be loaded as globals. In main.js you'd have to define jquery and knockout in order to make them available to Durandal (see main.js) as Durandal internally is still using them as AMD modules.
requirejs.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions'
}
});
define('jquery', function () { return jQuery; });
define('knockout', ko);
define(['durandal/system', 'durandal/app', 'durandal/viewLocator'], function (system, app, viewLocator) {
...
});

Related

polymer 1.0 event firing among nested components

I have a problem in Polymer 1.0 related to event propagation within a nested structure of web components. In particular, I am trying to dynamically configure a web component named wc-split by means of a collection of other components named wc-split-rule located within its local DOM. The following snippet of code shows a correct form of use:
<wc-split-test>
<wc-split>
<wc-split-rule key="{{k1}}" ...></wc-split-rule>
<wc-split-rule key="{{k2}}" ...></wc-split-rule>
<wc-split-rule key="{{k3}}" ...></wc-split-rule>
</wc-split>
</wc-split-test>
As it can be seen in the previous example, the aim is to provide to the wc-split component the values on key attributes within each wc-split-rule component. As we need dynamic reconfiguration capabilities, the architectural strategy starts by firing an event each time a change in key attributes is met and those changes are promoted by bubbling up to reach the wc-split component, which process them.
The followed approach works properly when [1] it is both tested in a pure HTML context with literal values and [2] within a component template with data-bound values. Nevertheless, [3] when it is tested within a component template using literal values, changes are not promoted. It seems that event propagation are ignored or listener defined in wc-split does not catch the event:
<wc-split-test>
<wc-split> <!-- does not work -->
<wc-split-rule key="k1" ...></wc-split-rule>
<wc-split-rule key="k2" ...></wc-split-rule>
<wc-split-rule key="k3" ...></wc-split-rule>
</wc-split>
</wc-split-test>
The following listing shows implementation of both components [https://goo.gl/OkU9jQ]:
<dom-module id="wc-split-rule">
<script>
Polymer({
is: 'wc-split-rule',
properties: {
key : {
type: String,
reflectToAttribute: true,
notify: true,
value: '',
observer: '_changed'
},
},
_changed: function (){
this.fire('wc-split-rule', {
key : this.key,
});
}
});
</script>
</dom-module>
<dom-module id="wc-split">
<template>
<content></content>
</template>
<script>
Polymer( {
is: 'wc-split',
listeners: {
'wc-split-rule': 'onRule'
},
ready: function(){
...
},
onRule: function (event, context){
... // this is executed in test [1] and [2] NOT in [3]
}
});
</script>
</dom-module>
<dom-module id="wc-split-test">
<template>
<wc-split id="split">
<wc-split-rule key="e1"/>
</wc-split>
</template>
<script>
...
</script>
</dom-module>
Surprisingly, the same code on Polymer 0.5 works properly for each test scenario [https://goo.gl/CHV3JE]:
<polymer-element name="wc-split-rule">
<script>
Polymer('wc-split-rule', {
publish : {
key : '',
},
observe: {
key : '_changed',
},
_changed: function (){
this.fire('wc-split-rule', {
key : this.key,
});
}
});
</script>
</polymer-element>
<polymer-element name="wc-split">
<template>
<div on-wc-split-rule="{{onRule}}">
<content select="wc-split-rule"></content>
</div>
<content></content>
</template>
<script>
Polymer('wc-split', {
ready: function(){
...
},
onRule: function (event, context){
... // this is always executed
}
});
</script>
</polymer-element>
<polymer-element name="wc-split-test">
<template>
<wc-split id="split">
<wc-split-rule key="e1"/>
</wc-split>
</template>
<script>
...
</script>
</polymer-element>
This boils down to a timing issue. The wc-split-rule event is firing before your wc-split element is registered. Therefore, the event is being missed. It's only an issue when the elements are first booted up b/c you have a parent element that's also a custom element. One way around this is to ensure the event fires after the wc-split-rule is attached:
attached: function() {
this._changed();
},
This works: http://jsbin.com/yixinuhahu/edit?html,output

Kendo-UI components when using Durandaljs

I'm spent days trying to work out how to use the kendo-ui component with Durandal but to no avail.
I've managed to add a kendo-ui component declaratively on the page i.e. . This has no problems.
However, I would like to do some animations based on page events. Coding directly in the javascript viewmodel makes it easier to manipulate afterwards.
I've added my code below (which doesn't work), and I'm not sure that I'm taking the right approach. Actually, I'm sure I'm not. Anyone who can point me in the right direction I would appreciate it.
Any help or suggestions are welcome
Main.js
requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins': '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'jquery': '../lib/jquery/jquery-1.9.1',
'kendo': '../lib/kendo/kendo.ui.core.min',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'toastr': '../lib/toastr/toastr',
'lib': '../lib'
},
shim: {
'kendo': { deps: ['jquery'], exports: 'kendo' },
'bootstrap': {deps: ['jquery'],exports: 'jQuery'}
}
});
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'durandal/binder', 'kendo'], function (system, app, viewLocator, binder, kendo) {
app.title = 'My Jumpstart';
//specify which plugins to install and their configuration
app.configurePlugins({
router:true,
dialog: true,
widget: {
kinds: ['expander']
}
});
kendo.ns = "kendo-";
binder.binding = function (obj, view) {
kendo.bind(view, obj.viewModel || obj);
};
app.start().then(function () {
viewLocator.useConvention();
app.setRoot('shell');
});
});
index.js
define(['durandal/app', 'durandal/system', 'knockout', 'toastr', 'kendo'],
function (app, system, ko, toastr, kendo) {
var myButton = function () {
var kbutton = $("#myButton").kendoButton();
};
var vm = {
myButton: myButton
};
return vm;
});
index.html
<section>
<div id="myButton">My Kendo Button</div>
</section>
Instead of shimming, add the Kendo libraries via the <script> tag on your index.html page. Be sure to add it after jQuery.
Also, are you using the knockout-kendo library from Ryan Niemeyer? That would affect my answer.

CKEditor toolbar close button right align

I want to add a close a button in CK Editor (v4.4) and want to align it right, below screen shot shows the end product.
With the help of documentation from CKEditor website I was able to create a simple close plugin. With the help of little jQuery hack I am able align it right but if possible I would like to align it using standard toolbar creation approach rather then below hack.
Current working hack
<script>
$(document).ready(function () {
var rteComment = CKEDITOR.replace("txtPluginDemo", {
toolbar: [
['NumberedList', '-', 'Image'],
['Save'],
['CKClose'],
],
toolbarCanCollapse: false,
allowedContent: 'p img ol br',
disallowedContent: 'script',
extraAllowedContent: 'img[*]{*}(*)',
extraPlugins: 'ckclose',
image_previewText: "Image preview will be displayed here.",
disableNativeSpellChecker: false,
//If true <p></p> will be converted to <p>&nbsp,</p>
fillEmptyBlocks: true,
removePlugins: 'contextmenu,liststyle,tabletools',
skin: 'moonocolor',
});
rteComment.on("close", function (evt) {
alert("Ok time to close it.");
return true;
});
rteComment.on("instanceReady", function (evt) {
//THIS IS HACK
$(".cke_button__ckclose").closest(".cke_toolbar").css({ "float": "right" });
});
})
</script>
I am hoping that there will be some option in the below code which will let me specify the my css class here.
CKEDITOR.plugins.add('ckclose', {
// Register the icons. They must match command names.
icons: 'ckclose',
// The plugin initialization logic goes inside this method.
init: function (editor) {
// Define an editor command that inserts a timestamp.
editor.addCommand('closeEditor', {
// Define the function that will be fired when the command is executed.
exec: function (editor) {
if (editor.fire("close")) {
editor.destroy();
}
}
});
// Create the toolbar button that executes the above command.
editor.ui.addButton('CKClose', {
label: 'Discard changes and close the editor',
command: 'closeEditor',
toolbar: 'insert'
});
}
});
Below image is the Inspect Element View from Firefox.
I got help from the above answer slightly change the code its worked for me
CKEDITOR.on("instanceReady", function (evt) {
$(".cke_button__custom").closest(".cke_toolbar").css({ "float": "right" });
});
"custom" is my button name. Thank you,
You can put this piece
rteComment.on("instanceReady", function (evt) {
$(".cke_button__ckclose").closest(".cke_toolbar").css({ "float": "right" });
});
rignt inside
init: function( editor ) {
(e.g., before its closing bracket). That should be enough.
Also, you don't need to put initialization info in a SCRIPT tag of your main file. It can be cleaner to use config.js
http://docs.ckeditor.com/#!/guide/dev_configuration
Also, see an interesting example of a plugin here:
How to add an ajax save button with loading gif to CKeditor 4.2.1. [Working Sample Plugin]

Kartograph map won't display

I can't get Kartograph.js to display my .svg map. Here's what I've done:
I've successfully made a .svg map from a .shp using the most basic json file I could with kartograph.py, according to Kartograph's docs, doing the basic world.json -o world.svg. Here's the json:
{
"layers": [{
"src": "ne_50m_admin_0_countries.shp",
"simplify": 3
}]
}
I've set up a simple http host with python and directed chrome to the host, since I understand you can't do this locally.
I've written the code below. I don't get any errors, so I don't what I've done wrong. Could it be that I haven't put in any layers? I wanted to make as simple an example as possible for my first try.
<div id="map"></div>
<script>
function loadMap() {
var map = kartograph.map('#map');
map.loadMap('world.svg', function() {
});
};
</script>
<script src="jquery-1.11.0.min.js"></script>
<script src="kartograph.js-master/dist/kartograph.js"></script>
<script src="raphael-master/raphael-min.js"></script>`
Thanks guys.
You must add the layer of the svg file.
In this case: map.addLayer('layer_0');
All the code:
$(function() {
var map = kartograph.map('#map',800,600)
map.loadMap('world.svg', function() {
map.addLayer('layer_0');
});
});
To see the name of the layer i open the svg file with Inkspace, and then press Shift+Control+X.

Loading "knockout.mapping" plugin using require.js

I am creating an MVC3 application, with requireJS. In my views I need to convert the Model object into a knockout viewmodel object. So I need to use knockout and knockout.mapping libraries.
My application is designed in the following way,
1). All the script files are categorized into folders
Scripts/app/home/ - contains the scripts for the views in Home controller.
Scripts/lib/ - contains the scripts like jQuery, knockout,knockout.mapping, requirejs etc
2). In the "_Layout.cshtml" I am referencing "require.js" like this.
<script src="#Url.Content("~/Scripts/lib/require.js")" type="text/javascript"></script>
3). To configure the require.js settings I am using a different script file called "common.js" (Scripts/lib/common.js)
require.config(
{
baseUrl: "/Scripts/",
paths:{
jquery: "lib/jquery-2.0.3",
ko: "lib/knockout-2.3.0",
komapping: "lib/knockout.mapping"
}
});
4). This is my index.js file which is in 'Scripts/app/home/"
define(['ko', 'komapping'], function (ko, komapping) {
var person = function () {
var self = this;
self.getPersonViewModel = function (data) {
return ko.mapping.fromJS(data); ;
};
};
return { Person: person };
});
5). This is my "Index" action method in the "Home" controller
public ActionResult Index()
{
var person = new Person
{
Id = 1,
Name = "John",
Addresses = new List<Address>(new[]{new Address{Country = "Country 1", City = "City 1"}})
};
return View(person);
}
6). Finally this is my "Index" view
#model MMS.Web.Models.Person
<script type="text/javascript">
require(["/Scripts/common/common.js"], function () {
require(["app/home/index"], function (indexJS) {
var person = new indexJS.Person();
var vm = person.getPersonViewModel(#Html.Raw(Json.Encode(Model)));
});
});
</script>
The problem which I am facing is when loading the index.js file, I get a script error that the knockout.js cannot be loaded.
Failed to load resource: the server responded with a status of 404 (Not Found) - http:///Scripts/knockout.js
But if I remove the dependency of "komapping" inside the "index.js" file it loads correctly, but then I cannot use the mapping functionality.
I had a look inside these links, but couldn't find a solution,
Knockout.js mapping plugin with require.js and
https://github.com/SteveSanderson/knockout.mapping/issues/57
Your help, suggestions are much appreciated. Thanks!
I had the same issue. The problem is that the knockout.mapping defines a knockout dependency, so you need to satisfy this one when you load the script.
Here is how you should load your mapping stuff
require.config(
{
baseUrl: "/Scripts/",
paths:{
jquery: "lib/jquery-2.0.3",
knockout: "lib/knockout-2.3.0",
komapping: "lib/knockout.mapping"
},
shim: {
komapping: {
deps: ['knockout'],
exports: 'komapping'
}
}
});
Then in my case, I use an index.js file with a requirejs call like the following
requirejs(['jquery', 'knockout', 'komapping'], function($, ko, komapping){
ko.mapping = komapping;
//Do other stuff here
});

Resources