Rails 3 Best Prototype + JQuery Solution - ruby-on-rails-3

I have a website that is rendering a prototype based calender on 90% of the pages. I'm also looking at using the Uploadify module for handling multiple uploads with Paperclip. As you know, Paperclip and JQuery don't play nicely and a lot of the solutions I've tried such as NoConflict hasn't worked for me I still get the "not defined" errors in firebug all over the place. I'm wondering what the best way for me to approach adding this JQuery module that will be very localized in a largely Prototype-based application. I've considered switching my Prototype code with JQuery but I've yet to see a better JQuery solution for this particular calendar plugin that I'm using.

Use a proper structure for noConflict.
<script src="prototype.js"></script>
<script src="someprototypeplugin.js"></script>
<script src="jQuery.js"></script>
<script src="uploadify.jquery.js"></script>
<script>
$.noConflict();
jQuery(document).ready(function($){
$("#someelement").uploadify();
});
</script>
If this doesn't answer your question, please provide more(some) code.
Edit for comments:
Just run the $.noConflict() immediately following your jQuery plugins, and then use jQuery instead of the $ variable throughout your JS files.
<script src="prototype.js"></script>
<script src="someprototypeplugin.js"></script>
<script src="jQuery.js"></script>
<script src="uploadify.jquery.js"></script>
<script>
$.noConflict();
</script>
sample js file:
(function($){
// since we passed a reference to jQuery to this anonymous
// function and accepted it as a parameter named "$", we can
// safely use "$"
$("#target").uploadify();
})(jQuery);
If you need a document ready, you can do it this way:
jQuery(document).ready(function($) {
$("#target").uploadify();
});

Related

Using vue.js without NPM or CLI

I'd like to use Vue.js within one page of a large legacy application. The idea is to replace the old JS+jQuery hodge-podge within a single page -- but leave the rest of the app (many other pages) untouched. So, not interested in using NPM, Node, Vue CLI, Webpack, Babel, etc., just yet.
This is a proof-of-concept before we invest in refactoring the entire frontend of the application.
The approach we followed was to include vue.js via as explained here: https://v2.vuejs.org/v2/guide/installation.html#Direct-lt-script-gt-Include in that one page, and the use Vue only within that one page. This is the general page layout:
<html>
<head>
...
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
...
</head>
<body>
<div id="el">
... vue template ...
</div>
<script>
...
var vm = new Vue({
el : '#el',
data : {
config : <% config.json %> // this is server-rendered, using server templating
...
},
...
});
...
</script>
</body>
</html>
The page does work. However, I get the following error/warning within the Vue console:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.
Although I'd rather not, I can certainly move the page-specific JS to its own separate file (and that does eliminate the warning/error). However, I wouldn't be able to set vm.config with server-provided data along with the loaded page by using server-side template, e.g. config : <% config.json %>. I know I could GET it using JS separately, after pageload, via an AJAX call directly from the server, but for practical reasons I'd like to avoid doing that here.
I'd greatly appreciate any suggestions on how to get this to work nicely. I'm also open to other suggestions with regard to this general pattern, that don't involve retooling the front-end just yet.
And perhaps the answer is to ignore the warning, or somehow disable it, given the page does work as intended...
Thank you!
One simple solution here is to write it to the global window object. IIRC SSR frameworks like Angular universal/Nuxt/Next/... all use this approach.
window.__STATE__ = <% config.json %>
In your JS file you can then refer to the window.__STATE__ object.
var vm = new Vue({
el: '#el',
data: {
config: window.__STATE__
}
})
Ofcourse the order is important here:
<body>
<script>
window.__STATE__ = <% config.json %>
</script>
<script src="app.js"></script>
</body>
Grrr, after several days after enduring this error, I discovered this:
<fieldset id="el">
...
<div id="el">
...
</div>
...
</fieldset>
So the issue was repeating #el within same page.
My mistake.
Just wish the error message emitted by Vue had been a bit more useful!
Bottom line: The pattern described in the origional question works just fine without NPM/CLI.

IBM Worklight - How to bypass WP's " Unable to add dynamic content" warning?

I have tried to run a Windows Phone 8 App written in Sencha Touch in Worklight. I used sencha in the following way:
<script src="//Microsoft.WinJS.1.0/js/base.js"></script><script src="//Microsoft.WinJS.1.0/js/ui.js"></script><script>
// Define WL namespace.
var WL = WL ? WL : {};
/**
* WLClient configuration variables.
* Values are injected by the deployer that packs the gadget.
*/
WL.StaticAppProps = {
"APP_DISPLAY_NAME": "Cockpit",
"APP_ID": "Cockpit",
"APP_SERVICES_URL": "http:\/\/192.168.99.11:10080\/CockpitProj\/apps\/services\/",
"APP_VERSION": "1.2.1",
"ENVIRONMENT": "windows8",
"LOGIN_DISPLAY_TYPE": "embedded",
"WORKLIGHT_PLATFORM_VERSION": "6.1.0.00.20131219-1900",
"WORKLIGHT_ROOT_URL": "http:\/\/192.168.99.11:10080\/CockpitProj\/apps\/services\/api\/Cockpit\/windows8\/"
};</script>
<script src="worklight/cordova.js"></script>
<script src="worklight/wljq.js"></script>
<script src="worklight/worklight.js"></script>
</head>
<body>
<div class="loadingSpinner bigLoad" id="appLoadingIndicator"></div>
<script src="js/initOptions.js" type="text/javascript"></script>
<script src="js/sencha-touch-all.js" type="text/javascript"></script>
<script src="js/app.js" type="text/javascript"></script>
<script src="js/messages.js" type="text/javascript"></script>
</body>
</html>
If I run this code, I get an exception:
Unable to add dynamic content. A script attempted to inject dynamic
content, or elements previously modified dynamically, that might be
unsafe. For example, using the innerHTML property to add script or
malformed HTML will generate this exception. Use the toStaticHTML
method to filter dynamic content, or explicitly create elements and
attributes with a method such as createElement. For more information,
see http://go.microsoft.com/fwlink/?LinkID=247104.
This can be solved by every sencha call inside the sencha-touch-all into a
MSApp.execUnsafeLocalFunction(function () {}
This can only be a workaround, as there are too many of these sencha calls.
What is the general concept of using Sencha for Windows Phone, like
these steps from Phonegap:
IMO there is no good way around it in Windows Phone development. Doesn't matter if it is a pure Cordova app, or a Worklight-based app.
See the second option in the following discussion. Perhaps you could set it in a way that it will work for all code parts required by your app:
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/e35017b4-e21b-4807-8668-fc3c332c6b32/javascript-runtime-error
Copy-paste:
The host enforcement code will throw an access denied exception in the
event that you try to set the innerHTML (and outerHTML and a couple of
others) of an element to HTML which doesn't conform to a whitelist of
known safe HTML. You can get around this in a couple of ways:
call toStaticHTML() on your string first which should strip out everything which is disallowed
use WinJS.Utilities.setInnerHTMLUnsafe(element, text), this allows you to set innerHTML to anything you like
use msWWA.execUnsafeLocalFunction, for instance:
msWWA.execUnsafeLocalFunction(function () { element.innerHTML = text; })
Option 2 is implemented in terms of 3. Be aware that if you set
innerHTML of an element to html that you don't control (e.g. something
you downloaded off the web like an RSS feed) it may contain script
which will be able to access the WinRT and do bad things which is why
the names of the functions in 2) and 3) are purposefully a little
scary.

$(...).tabs is not a function

I have this code on two pages on my site, but at one page the function doesn't work. Firebug shows me " $(...).tabs is not a function ". I don't understand why, can anyone tell me what is wrong ?
this is working:
http://www.invat-online.net/variante-rezolvate
this is not working:
http://www.invat-online.net/variante-explicate-limba-romana/varianta-01
Here is the code:
<div id="tabss">
<ul>
<li>Subiect I</li>
<li>Subiect II</li>
<li>Subiect III</li>
</ul>
<div id="SubiectI">content here</div>
<div id="SubiectII">content here</div>
<div id="SubiectIII">content here</div>
</div>
$(document).ready(function() {
$("#tabss").tabs();
});
You have relative paths to javascript files:
javascript/jquery-ui-1.9.2.custom.min.js
change them to absolute paths because you're using mod_rewrite module
/javascript/jquery-ui-1.9.2.custom.min.js
In first link the server is looking to the directory
http://www.invat-online.net/javascript/my_js_file.js (which exists)
but in the second one the path will be
http://www.invat-online.net/variante-explicate-limba-romana/javascript/my_js_file.js which do not exists
In my case:
I was using
jquery-ui-1.10.3.minimal.min.js
instead of
jquery-ui-1.10.3.custom.min.js
minimal version does not include ui.tabs.js, hence no ui.tabs function. Hope this helps someone else out there
The issue is that the jQuery UI js and css is not loading.
Try changing the path in you <script> tags to either the directory above ../javascript or the website root /javascript.
<script src="/javascript/head.min.js"></script>
<script src="/javascript/jquery-ui-1.9.2.custom.min.js"></script>
<link href="/stylesheets/smoothness/jquery-ui-1.9.2.custom.min.css" rel="stylesheet" />
Your first demo loads:
http://www.invat-online.net/javascript/jquery-ui-1.9.2.custom.min.js
Your second demo attempts to load:
http://www.invat-online.net/variante-explicate-limba-romana/javascript/jquery-ui-1.9.2.custom.min.js
The last one results in a 404. You should correct the path of the later, perhaps instructing it to find jQuery UI in one directory above the current: ../jquery-ui-1.9.2.custom.min.js.
Try this:
#section scripts{
$(document).ready(function() {
$("#tabss").tabs();
});
}
Put #Scripts.Render("~/bundles/jqueryui") in the <body></body> of your layout.cshtml
The error Uncaught TypeError: $(...).tabs is not a function may also be produced when in a Django project on the Admin area and using django-tabbed-admin under the following setup:
Django = 1.10.5
django-tabbed-admin=1.0.4
DEFAULT_JQUERY_UI_JS = 'tabbed_admin/js/jquery-ui-1.11.4.min.js'
The problem is that the code in jquery-ui-1.11.4.min.js for this Django lib is as follows:
/*! jQuery UI - v1.11.4 - 2015-07-27
(...)*/
jQuery = jQuery || django.jQuery.noConflict(false);
and the code on django-tabbed-admin uses it this way (change_form.html):
<script type="text/javascript">
(function($) {
$(window).scrollTop()
$('#tabs').tabs({
{% if add %}
// when adding, don't select a tab by default, we'll do it ourselves
// by finding the first available tab.
selected: -1
{% endif %}
});
(....)
})(django.jQuery);
</script>
<!-- end admin_tabs stuff -->
To sort this out this should be what would be passed in to the IIFE instead of the (django.jQuery) as above:
<script type="text/javascript">
(function($) {
(....)
})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined')
? django.jQuery
: jQuery)
</script>
<!-- end admin_tabs stuff -->
I've reported this issue in the project and created a PR with a fix for it. Waiting on it to be approved, so in the meantime you can sort it following my simple fix.
I hope this helps someone out there.
Check your page you might have loaded multiple versions of jQuery
I had the same problem, I realized that I had jquery and bootstrap css imports that enter in conflict each other. Take a look to the ones you have imported and reduce those imports to the minimum to see which is the conflict.
Here there is an example of how to implement it, I took that example and worked, then I adapted to my application:
for jquery 1.9 (click on view source to see the code)
http://jqueryui.com/tabs/
for jquery 1.8 (check the example at the end of the page)
http://api.jqueryui.com/1.8/tabs/
Hope it helps!

How do I use Dojo inside of Worklight correctly?

I need some help as well as some advice on how to use Dojo correctly in my project. At the moment, this is what I'm doing:
Say I setup a project named 'Test'. Test.html is the first file hit, and in that file I have the following:
<script type="text/javascript" data-dojo-config="isDebug: false, async: true, parseOnLoad: true" src="dojo/dojo.js"></script>
<script type="text/javascript" src="dojo/core-web-layer.js"></script>
<script type="text/javascript" src="dojo/mobile-ui-layer.js"></script>
<script type="text/javascript" src="dojo/mobile-compat-layer.js"></script>
<script type="text/javascript">
require(
// Set of module identifiers
[ "dojo", "dojox/mobile/parser", "dojox/mobile/SwapView", "dojox/mobile", "dojox/mobile/compat", "dojox/mobile/deviceTheme", "dojox/mobile/ScrollableView" ],
// Callback function, invoked on dependencies evaluation results
function(dojo) {
dojo.ready(function() {});
});
</script>
I also have this in Test.js:
require([ "dojo", "dojox/mobile/parser", "dojox/mobile/deviceTheme",
"dojox/mobile/ScrollableView", "dojox/mobile/compat", "dojox/mobile",
"dojox/mobile/Button", "dojox/mobile/View", "dojox/mobile/Heading",
"dojox/mobile/TabBarButton", "dojox/mobile/TabBar",
"dojox/mobile/TextBox", "dojox/mobile/RoundRectList",
"dojox/mobile/ListItem", "dojox/mobile/Button",
"dojox/mobile/SpinWheel", "dojox/mobile/SpinWheelSlot",
"dojox/mobile/IconContainer", "dojox/mobile/SwapView" ],
function(dojo, parser) {
dojo.ready(function() {
});
});
Now, when I click a on one of my buttons, it triggers the WL.Page.Load method and my pagePort div now shows my new page inside of my Test.html page (let's say this is Page2.html), however, there's a problem. The Dojo stuff works fine on page one, but now it doesn't work on page two. I'm not sure what's happening behind the scenes but I feel I'm missing a step (do I need to unload Dojo? Declare it again in the next page?).
If somebody could help me get Dojo working on this second page so I'm able to use Dojo on further pages (after learning what I'm doing wrong) I would be really grateful!
My best guess based on the info you've given is that Page2.html is not really inside Test.html and its a new page. In this case you will need to have the script references in Page2 as well.
If you're testing your code in a web browser you can view the Console and hopefully gain some insight as to what exactly is going wrong.
You can also try working with the Worklight logger to help locate the problem.
http://wpcertification.blogspot.com/2012/03/enabling-debuglog-console-in-worklight.html
Here is a general link for "Problem Determination" from IBM as well
http://publib.boulder.ibm.com/infocenter/ieduasst/v1r1m0/index.jsp?topic=/com.ibm.iea.worklight/worklight/5.0/Problem_Determination/IMFV50_ProblemDetermination/player.html
As Nick said if you load totally different HTML page you will have that page to declare the classes your are using. In dojox/mobile/tests see test_IconContainer.html for example.
That said you could proceed differently by for example having your alternate views defined in the same HTML or as your are in Worklight by using the fragment mechanism (see https://www.ibm.com/developerworks/mobile/worklight/getting-started/ modules 60.1, 2 and 3).

Newbie Dojo - Google CDN Question

I have a test jsp with:
<head>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js" type="text/javascript">
</script>
<script type="text/javascript">
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeSelector");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.widget.TreeContextMenu");
</script>
</head>
<body>
<div dojoType="TreeSelector" widgetId="treeSelector"></div>
<div dojoType="Tree" widgetId="treeWidget" selector="treeSelector"toggler="wipe">
<div dojoType="TreeNode" widgetId="1" title="First node" isFolder="false"></div>
<div dojoType="TreeNode" widgetId="2" title="Second node">
<div dojoType="TreeNode" widgetId="2.1" title="Second node First Child"></div>
<div dojoType="TreeNode" widgetId="2.2" title="Second node Second Child"></div>
</div>
<div dojoType="TreeNode" widgetId="3" title="Third node" isFolder="false"></div>
</div>
This will not work in any browser.
I thought this would be easy, it seems the dojo library is not being downloaded/found?
Do I need to do anything else?
Also, my IDE, JDeveloper, reports that the attribute "dojoType" is not defined on element div.
I have to say, this example looks like it is taken from a very old version of dojo, but you're trying to run it against Dojo 1.5. That most likely won't work. dojo.widget hasn't existed since...0.4, 0.9 maybe.
You may be right in your comment to the previous answer in that no parseOnLoad: true was necessary in the original example, but I'd also assure you that that example was not running any version of Dojo anywhere near what you're running it with.
Based on what you're looking at there, you may want to start somewhere like here: http://www.dojotoolkit.org/reference-guide/dijit/Tree.html
I'm not sure what the default behavior is when it's not present, but you probably need to define a djConfig with parseOnLoad set to true (or call the parser directly). See the following links for more information:
http://docs.dojocampus.org/djConfig
http://dojocampus.org/content/2008/03/08/the-dojo-parser/
Follow the:
Google AJAX Libraries API Dev Guide,
and the Google API Loader's Guide.
You need to:
register for an API key (or use a direct link as you did),
if not using a direct link but google.load, you need to defer the execution of your code using an onload callback.
Personally, I would just do something like:
within the <head> section of my.html:
<script type="text/javascript" src="http://www.google.com/jsapi?key=MY_API_KEY_GOES_HERE"></script>
<script type="text/javascript" src="my.js"></script>
in my.js:
google.load("dojo", "1.5", {
uncompressed: true
});
function OnLoad() {
/* do stuff here */
}
google.setOnLoadCallback(OnLoad);