We have a project with jstree 1.0-rc3. To extend basic funtionality we wrote custom extention using JQuery.jstree.plugin() function. Other words, we created custom plugin and used it as a usual plugin. Recently we decided to update jstree version to latest (3.3.8) and I met trouble because this function (JQuery.jstree.plugin) do not exist anymore and I can not find any analogue. Because of size of our custom plugin (hundreds of lines) and big count of place where we use it we do not want to move functionality to some another place from custom plugin cause it will take a really lot of time. Does anyone know how is it possible to create custom plugin in latest jstree ( 3.3.8 now)? Many thanks.
The functionality to add custom plugin is still there in the current jsTree version (3.3.8). As an example, it is already explained
// conditional select
(function ($, undefined) {
"use strict";
$.jstree.defaults.conditionalselect = function () { return true; };
$.jstree.plugins.conditionalselect = function (options, parent) {
this.activate_node = function (obj, e) {
if(this.settings.conditionalselect.call(this, this.get_node(obj))) {
parent.activate_node.call(this, obj, e);
}
};
};
})(jQuery);
$("#tree").jstree({
"conditionalselect" : function (node) {
return node.text === "Root node" ? false : true;
},
"plugins" : ["conditionalselect"]
});
Please the approach explained in https://github.com/vakata/jstree#more-plugins how to included your own plugin or any third party plugins.You must include its source on the page and list its name in the "plugins" config array.
You can have a look at jstree/src/misc.js for finding many such custom plugins already written.
Related
I try to add a new tool/function to the ContentTools but I don't want to learn Coffeescript and as it states on the website it should running fine with plain jquery.
And I can not find any further documentation how to add a simple tool to my toolbar.
I hope you can help me or is there any other opensource WYSIYG Editor with this beautiful inline editing style like ContentTools which has a better documentation?
As I know, GetmeUK/ContentTools project is an open source project which is written with coffeescript and sass technologies.
What is Coffeescript :
CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.
What is sass :
Sass is the most mature, stable, and powerful professional grade CSS extension language in the world. just like coffeescripts sass finally is converted to css.
So as I know it is possible to modify the final JS files generated by coffeescript compiler, but the easier way is to learn how to compile coffeescript, then you can modify and rebuild any other open source softwares, libs, and etc... .
How to download and build GetmeUK/ContentTools project ?
first of all you have to clone the project using GIT :
git clone https://github.com/GetmeUK/ContentTools.git
for rebuilding this project you need to have NPM and GEM installed in your operating system. follow the instructions mentioned in the link https://nodejs.org/en/download/ for NPM and https://rubygems.org/pages/download for GEM.
cd ContentTools; npm install; gem install sass;
By running grunt build you can build the project and save pure JS exports for this project. With this way you can use the pure JS which is generated by compiling Coffeescript files. this is what is suggest to you.
By the way there is another harder way to sit and read the compiled JS code of this project for weeks, finally if you have chance you can understand generated codes and then after hard working sessions you can modify it :) I hope the following codes help you :
Coffeescript code:
class ContentTools.Tools.Paragraph extends ContentTools.Tools.Heading
# Convert the current text block to a paragraph (e.g <p>foo</p>)
ContentTools.ToolShelf.stow(#, 'paragraph')
#label = 'Paragraph'
#icon = 'paragraph'
#tagName = 'p'
#canApply: (element, selection) ->
# Return true if the tool can be applied to the current
# element/selection.
if element.isFixed()
return false
return element != undefined
#apply: (element, selection, callback) ->
# Apply the tool to the current element
forceAdd = #editor().ctrlDown()
if ContentTools.Tools.Heading.canApply(element) and not forceAdd
# If the element is a top level text element and the user hasn't
# indicated they want to force add a new paragraph convert it to a
# paragraph in-place.
return super(element, selection, callback)
else
# Dispatch `apply` event
toolDetail = {
'tool': this,
'element': element,
'selection': selection
}
if not #dispatchEditorEvent('tool-apply', toolDetail)
return
# If the element isn't a text element find the nearest top level
# node and insert a new paragraph element after it.
if element.parent().type() != 'Region'
element = element.closest (node) ->
return node.parent().type() is 'Region'
region = element.parent()
paragraph = new ContentEdit.Text('p')
region.attach(paragraph, region.children.indexOf(element) + 1)
# Give the newely inserted paragraph focus
paragraph.focus()
callback(true)
# Dispatch `applied` event
#dispatchEditorEvent('tool-applied', toolDetail)
The compiled JS code:
ContentTools.Tools.Paragraph = (function(_super) {
__extends(Paragraph, _super);
function Paragraph() {
return Paragraph.__super__.constructor.apply(this, arguments);
}
ContentTools.ToolShelf.stow(Paragraph, 'paragraph');
Paragraph.label = 'Paragraph';
Paragraph.icon = 'paragraph';
Paragraph.tagName = 'p';
Paragraph.canApply = function(element, selection) {
if (element.isFixed()) {
return false;
}
return element !== void 0;
};
Paragraph.apply = function(element, selection, callback) {
var forceAdd, paragraph, region, toolDetail;
forceAdd = this.editor().ctrlDown();
if (ContentTools.Tools.Heading.canApply(element) && !forceAdd) {
return Paragraph.__super__.constructor.apply.call(this, element, selection, callback);
} else {
toolDetail = {
'tool': this,
'element': element,
'selection': selection
};
if (!this.dispatchEditorEvent('tool-apply', toolDetail)) {
return;
}
if (element.parent().type() !== 'Region') {
element = element.closest(function(node) {
return node.parent().type() === 'Region';
});
}
region = element.parent();
paragraph = new ContentEdit.Text('p');
region.attach(paragraph, region.children.indexOf(element) + 1);
paragraph.focus();
callback(true);
return this.dispatchEditorEvent('tool-applied', toolDetail);
}
};
return Paragraph;
})(ContentTools.Tools.Heading);
You can go step by step by the tutorial provided by GetContentTools website and replace the code written in Coffescript with its equivalent in JS. for this goal I have some samples for you :
Every where you see #propertyName you can replace it with PackageName.ClassName.propertyName, or for calling super(parameters ...) method, you have to use the Paragraph.__super__.constructor.apply.call(this, parameters ...) syntax.
Also there is links to row files of this project which I share with you :
Tools CoffeeScript File and Exported JS File
After all I think there is no way for doing this work with having no knowledge about Coffescript syntax or concepts, I suggest you to learn it, it would help you to have codes with more performance and clearness.
Dojo 1.10+
I want to conditionally load custom module according to this post
Dojo FAQ: How can I conditionally load AMD modules?
require([
'dojo/has'
], function (has) {
var ui;
var moduleId = 'myApp/ui/';
// Assume 'has' tests for mobile and tablet
// have been defined
if (has('mobile')) {
moduleId += 'Mobile';
}
else if (has('tablet')) {
moduleId += 'Tablet';
}
else {
moduleId += 'Desktop';
}
require([moduleId], function (UiModule) {
ui = new UiModule();
ui.placeAt(document.body);
ui.startup();
});
});
However it seems dojo/has only detects certain dojo features. If that is the case is there an alternative method to detect if a custom module exists before attempting to require and then instantiate it if its a widget?
Yes, dojo/has only detects certain dojo features. But you can add your own, i was trying something like you are trying here, maybe not the best, but this work for me.
At boot time of your app, you can add you own features to dojo, i.e.
var deviceWidth = has('device-width'), hasTouch = has('touch');
has.add('mobile', (hasTouch && deviceWidth <=736));
has.add('tablet', (hasTouch && (deviceWidth > 736 && deviceWidth <=1024)));
and so on, so, later in another widget, you can require dojo/has and use the recently added features. Or event better, you can do this
require(['dojo/has!mobile?myApp/ui/Mobile:myApp/ui/Tablet'], function (UiModule) {
ui = new UiModule();
ui.placeAt(document.body);
ui.startup();
});
I've never tried nested dojo/has validations and i can not tell you if it works, but i've tried like in the example i'm giving you and it works.
Think that you can have in your project your own has lib extending the dojo version and adding all the features you want. For example:
//myApp/has.js
define(["dojo/has"], function(has){
has.add('myApp', true);
return has;
});.
Then later in your app you can include myApp/has and us it just like if it were the dojo version.
I'm running a project where people can find doctors on the map and And book Online , ...
Previously I decided to use Angularjs and change the whole project, so I had to forget about some jQuery plugins which I've used before.
**Problem ** :
I'm using a jQuery plugin that works awesome with Google map API (Landcarte) , and I haven't find anything else to compare with this plugin in AngularJS.
So I couldn't do anything but to use both jquery and angular and this plugin in my site , But I dont know , I feel that its wrong to use both jquery and angular because I think that makes my firstload heavy.
**Questions : **
1- Is this possible to convert this plugin into a normal Javascript so I can omit the Jquery in my site ?
2- If not , What can I do ?
3- Can I use RequireJS to load jquery and this plugin later in my site ? (I dont know how to :()
I don't know about the Landcarte plugin so I can't help you with question 1.
If you want to initialize a jquery plugin but it's not working, a common cause of the problem is that the DOM is not ready yet.
To solve this, there are three options:
Method 1 Initialize the plugin inside of the link property of your directive. Within the link function, the children of the directive element have already been compiled and linked. If your plugin relies only on the children of the element being DOM ready, then this option is suitable.
app.directive('myDirective', function(){
return {
link: function(scope, element,attr){
element.plugin();
}
}
});
Method 2 Using $evalAsyc which runs after the compile and link phase but before the Render phase. Use this method if your plugin relies on the entire page being DOM ready, but it is not important that expressions have been rendered.
app.directive('myDirective', function(){
return {
link: function(scope, element,attr){
scope.$evalAsync(function(scope){
element.plugin();
});
}
}
});
Method 3 Using $timeout which runs after the render phase. Use this method if your plugin relies on the entire page being DOM ready, and all the expressions have been rendered.
app.directive('myDirective', function($timeout){
return {
link: function(scope, element,attr){
$timeout(function(){
element.plugin();
});
}
}
});
Depending on the plugin, one of these options should work for you. Prefer one that meets the need of the plugin minimally - meaning prefer option 1, over option 2, over option 3, but ultimately go with the one that works.
To turn min.js file into normal.js you can use this
but it just set tabulations and spaces and make script readable.
For example this script:
var a={log:function(){try{var e=Array.prototype.slice.call(arguments);if(typeof e[0]==="string"){if(/[\{\}]/.test(e[0])&&e.length>1){var t=e.length>2?e.slice(1):e[1];return console.log(this.text(e[0],t))}}return console.log.apply(console,e)}catch(n){}}}
will be:
var a = {
log: function () {
try {
var e = Array.prototype.slice.call(arguments);
if (typeof e[0] === "string") {
if (/[\{\}]/.test(e[0]) && e.length > 1) {
var t = e.length > 2 ? e.slice(1) : e[1];
return console.log(this.text(e[0], t))
}
}
return console.log.apply(console, e)
} catch (n) {}
}
}
Landcarte can be used in a pure JS code without jQuery as well. A map can be initialized by an explicit call of the at.geo.Map class constructor:
var container = document.getElementById("map");
var map = new at.geo.Map(container);
This class is mentioned in the reference.
In my corporate environment, we are using a lot of javascript. To simplify the management of all this script, and avoid naming collision, we adopted a javascript naming convention for namespaces, which is basically:
CompanyName.ProjectName.Area.XYZ.js
To create the namespaces, we are using the following pattern:
var Company;
(function (Company) {
(function (Project) {
(function (Area) {
(function (XYZ) {
function function1(args) {
},
function function2(args) {
}
})(Area.XYZ|| (Area.XYZ = {}));
})(Project.Area || (Project.Area = {}));
var Area = Project.Area;
})(Company.Project || (Company.Project = {}));
var Project = Company.Project;
})(Company || (Company = {}));
Which works fine (actually, this is the output of a TypeScript script).
However, I also have some scripts that use the Microsoft Ajax namespacing function, because this is required by out of control applications (javascript plugin).
I use this declaration :
Type.registerNamespace('CompanyName.ProjectName.Area');
CompanyName.ProjectName.Area.ABC = function() {
}
CompanyName.ProjectName.Area.ABC.prototype = {
function1 : function (args) {
},
function2 : function (args) {
}
}
But the call to Type.registerNamespace throws an error:
Sys.InvalidOperationException: Object Company already exists and is not a namespace
How can I properly combine both worlds? How can I solve my issue and make the warning disappears?
I cannot control the order of the script inclusion, as it's dynamically generated by the application.
I don't want to migrate the whole code to the Microsoft's pattern, as it's quite useless and hard to read. And as I migrate to typescript, I even can't control the namespacing output.
I also don't want to introduce an alternative namespace to exclude the Ajax's ones, because it will introduce some confusion to all the team.
Some months later... I finally had to create two separate namespaces. One for MS Ajax rigid model, one for self created namespaces.
CompanyName.ProjectName.Area
CompanyNameAjax.ProjectName.Area
Can you not just try/catch it?
try {
Type.registerNamespace('CompanyName.ProjectName.Area');
} catch( e ) {
//log it, or just ignore it..
}
I'm working on an app that uses Backbone and RequireJS (using the Backbone boilerplate).
What I'd like to do is detect if the user is on a mobile device (currently using Modernizr to check for touch), and if so then load jQuery Mobile's css and js, and have it applied to all modules and their templates.
I'm not sure of the best way to do this with RequireJS.
Cheers
Edit: After re-reading your question, I'm not sure this is what you're asking for. Sorry for the noise.
I'm currently in a similar situation. You can set properties on Backbone's View/Router/Model/Etc prototypes and they'll filter down the chain. So, for example:
//Assuming we're in 'mobile' mode, you'd do this in whatever code gets loaded.
Backbone.View.prototype.useMobileView = true;
Then you can do whatever is necessary if this.useMobileView == true. For example:
ResponsiveView = Backbone.View.extend({
getTemplate: function () {
if(this.useMobileView) {
return this.mobileTemplate;
} else {
return this.template;
}
}
});
SomeView = ResponsiveView.extend({
render: function () {
var template = this.getTemplate();
//do stuff
}
});