I am using Kickstrap 1.3.0 and want to add an App in my PHP-View with a method like <?php $this->enableKickstrapApp('myapp'); ?>. This method would put the app name into an apps array and the layout template could generate any code anywhere in the page to active the app.
But I don't know how to load the app. The docs say that I should add a page specific less file. But I don't want to autogenerate such an extra less file (I will do this it there is no better solution). Also an API method loadApp() is mentioned in the API docs. But there seems to be no loadApp in the source code. Also it is not documented how to get the API object (maybe this should be a global method--I couldn't find it). In an maybe outdated doc at GitHub I found the tip to write a pageApps array. But scanning the source code for "pageApps" also had no results.
Is there any way to activate an app dynamically (or in the global ks variable) without an extra less file?
That works:
var ks = {
apps: ['myapp']
}
Must be defined before loading kickstrap.js of course.
Related
My Shopify app replaces the product pages 'Add To Cart' form / product form, with it's own form of sorts. It is Liquid logic that decides whether or not to render the entire <form> element.
This works great, but on some themes (like Jumpstart by Shopify), the product page bugs out completely, throwing me an error saying:
option_selection.js - can't access its "parentNode" property
Which I believe is the option_selection.js function where it is looking for the select box / variant ID somewhere on the page.
Of course, this variant ID / select box does not exist because it is not being rendered.
How can I replace the add to cart form while satisfying the option_selection.js functions?
Usually this wouldn't be a big deal, but Shopify's app review team will give me problems with this, and on the Jumpstart theme specifically, this error causes the product photos to not render; breaking the page completely.
Any ideas here? Much appreciated!
Axing the entire product form seems a bit extreme - there's no way to do what you need to do in a less invasive way?
Assuming not, you'll want to expand your install so that you can update any code in a theme that initializes the product form to take into account the possibility that you've defied the theme's simplistic assumptions.
For the option_selection.js compatibility, you'll be looking for where new Shopify.OptionSelectors is being invoked. If your code has set a variable through Javascript, that may be the easiest check to make. Example of an inline install that assumes your code creates a function named MyAppNamespace.isProdHidden:
Original:
new Shopify.OptionSelectors( ...
Updated:
!(window.MyAppNamespace && MyAppNamespace.isProdHidden({{ product.id | json }}) ) && new Shopify.OptionSelectors( ...
The added piece of code will evaluate to false if and only if your app has loaded properly and your isProdHidden function returns a truthy value. This scenario would prevent the new Shopify.OptionSelectors part from running, since we're using the && as a sort of short-circuit/emergency-stop operation.
If your app failed to load (or was uninstalled from the store without the liquid code being updated), or if MyAppNamespace.isProdHidden returns false, then the added block of code evaluates as true and the new Shopify.OptionSelectors happens as normal.
The above is equivalent to wrapping the entire new Shopify.OptionSelectors call in an if statement, with the install benefit that the party installing your app doesn't need to read the theme code to figure out where the OptionSelectors call ends. In most themes the OptionSelectors code is spread out over multiple lines and occasionally theme developers declare their onVariantChange function as an inline anonymous function - neither of which are big obstacles for experienced developers, but a huge complication for novices and store owners without this kind of expertise.
Making the status of your app available somehow through Javascript is probably the best thing for you to do as far as theme-install-compatibility goes. Some themes have their OptionSelectors call right in the product page, which can be affected by dynamic Liquid variables, but many have this code tucked away in a .js file in the assets folder instead. Still other themes don't use Shopify's OptionSelectors code at all and instead run their own thing, and thus your app could interfere in completely unexpected ways or places. Creating tools to make it easier to integrate your app into somebody else's code is therefore one of the best things you can do.
You'll also want to make sure that your code is able to handle multiple products, as many stores have quick-shops all through the site which can load arbitrary product forms. By making sure you have made the tools available, it's possible for you, your support team (if any) and theme devs can make the required updates to (almost!) any arbitrary theme.
Hope that helps!
I have just upgraded to Grails 2.4 and am using the Asset-Pipeline1.8.7 plugin. I am wondering how to access the images from Javascript. I am using the Google Maps Javascript V3 API and need to set some marker icons in Javascript. Is there a way to create some Javascript vars on a GSP using the tag and then access the file in my app.js code? If that is not possible, how do a reference the compiled images in assets?
You could define a globally available object that holds the root-path to your assets dir and use this to build-up URLs to your assets.
Add this snippet to your layouts head-section
<g:javascript>
window.grailsSupport = {
assetsRoot : '${ raw(asset.assetPath(src: '')) }'
};
</g:javascript>
Then use it elsewhere like this:
<g:javascript>
var pathToMyImg = window.grailsSupport.assetsRoot + 'images/google_maps_marker.png';
</g:javascript>
Update 2015-08-06
While checking the release notes of the asset-pipeline plugin I noticed that non-digest versions of assets are no longer stored in the WAR-file. This would mean that my proposed solution breaks when the application is deployed as a WAR:
May 31, 2015
2.2.3 Release - No longer storing non digest versions in war file, cutting overhead in half. Also removed Commons i/o dependency. Faster byte stream.
This means that you have to explicitly define all your images beforehand and are no longer able to construct the path dynamically in your scripts:
<g:javascript>
window.grailsSupport = {
myImage1 : '${assetPath(src: 'myImage1.jpg')}',
myImage2 : '${assetPath(src: 'myImage2.jpg')}'
};
</g:javascript>
Update 2016-05-25
It is now possible to configure if non-digest versions of the assets are included in the built war-file by setting grails.assets.skipNonDigests (default is false):
It is normally not necessary to turn off 'skipNonDigests'. Tomcat will automatically still serve files by non digest name and will copy them out using storagePath via the manifest.properties alias map. This simply cuts storage in half. However, if you are attempting to do things like upload to a cdn outside of the cdn-asset-pipeline plugin and via the contents of 'target/assets'. This may still be useful.
Note that you still might use the proposed solution to define all required images beforehand to work around caching issues in the browser (as the digest-version of the asset has its content-hash in the filename).
Yes you can by putting a ${assetPath(src: 'img.png')} in your gsp
I don't know what the ideal solution is in your case but a solution might be:
Use relative paths like '../assets/use-control.png' in your js code.
Add the img in your dom and reference it from your js code.
Add a data-imgpath="${asset.assetPath(src: 'use-control.png')}" attribute on an appropriate element in your dom and use this link.
As an alternative you can use HTML5's data-* Attribute.
I've explained a bit further here:
load images from javascript
Is there any way I can include an external JS library in my pebble code?
Conventionally on a webpage I would do this in my head tags:
<script type='text/javascript' src='https://cdn.firebase.com/js/client/1.0.11/firebase.js'></script>
But in pebble, I am unable to do that since I am only using JS. So how can I include an external library for a JavaScript file.
At present, you cannot include external JS files.
If you're using CloudPebble, then the only way to do this is to copy and paste the content of the JS library files into your JS file.
If you're doing native development, you can modify the wscript file to combine multiple JS files into one at build time.
I think there's some confusion over Pebble.js vs PebbleKit JS (v3.8.1). Pebble.js is a fledgling SDK where eventually the programmer will be able to write pure JavaScript. It's still cooking so there's some functionality missing like the ability to draw a line or obtain the screen dimensions. The repo is a mix of C and JS sources where you can add C code to augment missing functionality but otherwise all your code lives in src/js/app.js or src/js/app/. Anyway, Pebble.js does support require.
I don't use CloudPebble but I got the impression that it either supports Pebble.js (and hence require) or is planning to. I think all this SDK boilerplate code would be hidden.
PebbleKit JS does not support require out of the box AFAIK. I've made a demo that ports require support from Pebble.js to PKJS. The summary of changes is:
Move your project's src/js/pebble-js-app.js to src/js/app/index.js.
Remove any ready event listener from src/js/app/index.js. index.js will
be loaded when the ready event is emitted.
Add src/js/loader.js from Pebble.js.
Add a src/js/main.js that calls require('src/js/app') on the ready event.
Update your wscript with the following
deltas.
When adding new modules, place them under src/js/app/ and require('./name') will work.
I've tried to cover this all in the demo's readme.
BTW, here's the official breakdown of all the different SDKs but it's a little confusing.
I am not sure if there have been changes since the above answer, but it looks like there is in fact a way to include additional resources while keeping things tidy. On the pebbleJS page, there is the following section with an some information on the subject.
GLOBAL NAMESPACE - require(path)
Loads another JavaScript file allowing you to write a multi-file project. Package loading loosely follows the CommonJS format. path is the path to the dependency.
You can then use the following code to "require" a JS library in your pebble project. This should be usable on both Cloud Pebble as well as native development.
// src/js/dependency.js
var dep = require('dependency');
You can then use this as shown below:
dep.myFunction(); // run a function from the dependency
dep.myVar = 2; // access or change variables
Update:
After some digging into this for my own, I have successfully gotten CloudPebble to work with this functionality. It is a bit convoluted, but follows the ECMAScript 6 standards. Below I am posting a simple example of getting things set up. Additionally, I would suggest looking at this code from PebbleJS for a better reference of a complex setup.
myApp.js
var resource = require('myExtraFile'); // require additional library
console.log(resource.value); // logs 42
resource.functionA(); // logs "This is working now"
myExtraFile.js
var myExtraFile = { // create a JSON object to export
"value" : 42, // variable
functionA : function() { // function
console.log("This is working now!");
}
};
this.exports = myExtraFile; // export this function for
// later use
I am developing an extension for Mediawiki which is based on another extension (developed in-house) that will not work above with a Mediawiki installation with a version superior 1.16.5 . I need to include javascript in pages belonging to a specific namespace and I cannot use the ResourceLoader http://www.mediawiki.org/wiki/ResourceLoader .
Does someone know if there's a simple to do this? I need to include JQuery and Datatables for a custom rendering of the pages belonging to the namespace.
There are at least three ways to go about this.
The 1st approach is to edit the magic page MediaWiki:Common.js and add something like this:
if(wgNamespaceNumber == 0) { // NS_MAIN
importScript('MediaWiki:MyScript.js');
}
You can place arbitrary javascript in the block, the importScript bit there is for executing JavaScript stored in a Wiki page but there are other ways to include JS on the fly as well (see eg. this question). See Manual:Interface/JavaScript for details of the MediaWiki side of things.
The 2nd approach would be to hack the PHP that produces the MediaWiki page to inject <script> tags depending on the current namespace, but that's a bit more involved: you'd need to build a custom extension and hook it in at some appropriate point. The ParserAfterTidy hook looks suitable, see Hooks.
The 3rd approach would be to simply edit the skin and load the JS for every page in the wiki -- is there a reason you don't want to do this for every page? They're cached anyway, so it's only a one-time hit.
When building webapps with MVC web framworks like Django, Kohana, Rails and the like, I put together the application without JS-driven components initially, and then add them afterwards as "improvements" to the UI.
This approach leads to non-intrusive JS, but I don't have a good "standard" way of how to go about organizing the JS work. Most of the JS I write in apps like these are 10-30 line JQuery snippets that hook into some very specific part of the UI.
So far I often end up inlining these things together with the part of the UI they manage. This makes me feel dirty, I'd like to keep the JS code as organized as the python / php / ruby code, I'd like for it to be testable and I'd like for it to be reusable.
What is the best way to go about organizing JS code in a setup like this, where we're not building a full-blown JS client app, and the main meat is still server side?
I am also very interested in what other people have to say about this. The approach I've taken is to use object literal notation to store the bulk of the function, and store these in one file included on all pages (the library)
uiHelper = {
inputDefault:function(defaulttext){
// function to swap default text into input elements
},
loadSubSection:function(url){
// loads new page using ajax instead of refreshing page
},
makeSortable:function(){
// apply jQuery UI sortable properties to list and remove non javascript controls
}
}
Then I include a .js file on any page that needs to use the library that ties the elements on that page to the function in the library. I've tried to make each function as reuseable as possible and sometimes the event binding function on the page calls several of my library functions.
$(document).ready(function(){
$('#mybutton').live('click',uiHelper.loadSubSection);
//more complicated helper
$('#myotherbutton').live('click',function(){
uiHelper.doThisThing;
uiHelper.andThisThing;
});
});
edit: using jsDoc http://jsdoc.sourceforge.net/ notation for commenting for these functions can produce documentation for the 'library' and helps keep your code easy to read (functions split by comments).
The following question is along similar lines to your own - you should check it out...
Commonly accepted best practices around code organization in JavaScript
When dealing with JS code, you should first analyze whether it will be used right away when the page loads. If it's not used right away (meaning the user must do something to invoke it) you should package this into a JS file and include it later so the load time is perceived faster for the user. This means that anything that the user will sees should go first and JS related to the functionality should be imported near the end of the file.
Download this tool to analyze your website: http://getfirebug.com/
If the JS code is small enough, it should just be inline with the HTML.
Hope that helps a bit.
For quick little user interface things like that I put everything into a single javascript file that I include on every page. Then in the javascript file I check what exists on the page and run code accordingly. I might have this in UIMagic.js for example. I have jQuery, so excuse those jQuery-isms if they aren't familiar to you.
function setupMenuHover() {
if ($("li.menu").length) { // The page has a menu
$("li.menu").hover(function() { ... }, function() { ... });
}
}
$(setupMenuHover);
function setupFacebookWizbang() {
if (typeof FB != "undefined") { // The page has Facebook's Javascript API
...
}
}
$(setupFacebookWizbang);
I've found this to be a sane enough approach.
My preferred method is to store inline javascript in it's own file (so that I can edit it easily with syntax highlighting etc.), and then include it on the page by loading the contents directly:
'<script type="text/javascript">'+open('~/js/page-inline.js').read()+'</script>'
This may not perform well though, unless your templating library can cache this sort of thing.
With Django you might be able to just include the js file:
<script type="text/javascript">
{% include "js/page-inline.js" %}
</script>
Not sure if that caches the output.
If you are still worried about being 'dirty', then you could check out the following projects, which try to bridge the server/client side language mismatch:
http://pyjs.org/ (Python generating JavaScript)
http://code.google.com/webtoolkit/ (Java generating JavaScript)
http://nodejs.org/ (JavaScript all the way!)