How to properly set contents in a gitbook-plugin's block? - block

Get the path of a file in gitbook head
This question touch the possibility to get a path of a specific file.
For example, to get some content, before page loads in a gitbook, is possible to add in "head:end" some customizations. This work fine when we need jquery loaded in `.
module.exports = {
book: {
...
/* Load files */
html: {
'head:end': function(current){
console.log()
var p = current.basePath+"/"+current.staticBase+"/plugins/myplugin/jquery-latest.min.js";
...
}
...
Get the path of a file in gitbook block
But in a custom block, how i do this?
blocks: {
myblock: {
process: function(current) {
//current isnt same... :(
// h
console.log(current);
var p = current.basePath+"/"+current.staticBase+"/plugins/myplugin/"+current.args[0];

Related

How to download file from Sanity via HTTP?

I would like to know if there is possibility to download file from Sanity with HTTP request?
I only have reference ID:
{
file: {
asset: {
_ref: "file-fxxxxxxxxxxxxxxxxxxxx-xlsx"
_type: "reference"
}
}
}
I would like to do this is this scenario:
<a href="https://cdn.sanity.io/assets/clientID/dataset/file-xxxxxxxxxxx-xlsx">
Download File
</a>
You can, indeed 🎉 With a bit of custom code you can do it just from the _ref, which is the file document's _id
Creating the URL from the _ref/_id of the file
The _ref/_id structure is something like this: file-{ID}-{EXTENSION} (example: file-207fd9951e759130053d37cf0a558ffe84ddd1c9-mp3).
With this, you can generate the downloadable URL, which has the following structure: https://cdn.sanity.io/files/{PROJECT_ID}/{DATASET}/{ID_OF_FILE}.{EXTENSION}. Here's some pseudo Javascript code for the operation:
const getUrlFromId = ref => {
// Example ref: file-207fd9951e759130053d37cf0a558ffe84ddd1c9-mp3
// We don't need the first part, unless we're using the same function for files and images
const [_file, id, extension] = ref.split('-');
return `https://cdn.sanity.io/files/${PROJECT_ID}/${DATASET}/${id}.${extension}`
}
Querying the URL directly
However, if you can query for the file's document with GROQ that'd be easier:
*[(YOUR FILTER HERE)] {
file->{ url } // gets the URL from the referenced file
}
You can do the same with images, too.

Get the loaded LESS file and compile it on demand

I'm trying to compile a small LESS portion of code and mixing it with a bigger one already compiled in the page.
I thought there was some way to reuse the compiled less or maybe load it again, mix it with the newer code and then compile it mixed in the page.
I thought to load it in some way like the example below:
var runtime_less = '#bg:red; .selector { background-color:#bg; }';
var library_less = '#var:bla bla bla...';
var library_parser = new(less.Parser)({
paths: ['.', './lib'], // Specify search paths for #import directives
filename: 'css/full_library.less' // Specify a filename, for better error messages
});
frontsize_parser.parse('', function (e, tree) {
library_less = tree;
});
var runtime_parser = new(less.Parser)({});
runtime_parser.parse(library_less, function (e, tree) {
// this should be inside some load event
$("#container-style").text(library_less.toCSS() + ' ' + tree.toCSS());
});
Does exist some way to get the current page loaded LESS file and treat it in some way?
Or does exist some way to load LESS files and then mix the LESS data with a string with additional LESS code?
with t.less containing:
#color: lightgreen;
You can use the following code:
<link type="text/css" href="t.less" rel="stylesheet/less">
<script>
less = {
env: "development"
};
</script>
<script src="/less.js/dist/less.js"></script>
<script>
var tmp = less.parse;
less.parse = function(input,option,callback) {
tmp(input + ' h1 {color:#color;}',option,callback);
}
less.refreshStyles();
</script>

usemin revved filenames and requirejs dependencies

I'm running into the following problem with requirejs and usemin:
I want to setup a multipage application, where I dynamically load modules that only contain page specific functionality (e.g. about -> about.js, home -> home.js). I could go ahead and pack everything in a single file, but that just leads to a bigger file size and overhead on functionality that isn't necessary on each site! (e.g. why would I need to load a carousel plugin on a page that doesn't have a carousel!)
I checked out the example https://github.com/requirejs/example-multipage-shim
That is in fact a great way to deal with it, until I bring usemin into the game. After revving the filenames the src path of each script tag is updated, but what about the dependencies?
<script src="scripts/vendor/1cdhj2.require.js"></script>
<script type="text/javascript">
require(['scripts/common'], function (common) {
require(['app'], function(App) {
App.initialize();
});
});
</script>
In that case, require.js got replaced by the revved file 1cdhj2.require.js. Great!
But the required modules "common" and "app" no longer work since common became 4jsh3b.common.js and app became 23jda3.app.js!
What can I do about this? Thanks for your help!
(Also using Yeoman, btw)
It's a tricky problem and I'm sure somebody else fixed in in a more elegant way, but the following works for me.
I might publish this as a grunt plugin once it's a little more robust.
Taken from my Gruntfile:
"regex-replace": {
rjsmodules: { // we'll build on this configuration later, inside the 'userevd-rjsmodules' task
src: ['build/**/*.js'],
actions: []
}
},
grunt.registerTask('userevd-rjsmodules', 'Make sure RequireJS modules are loaded by their revved module name', function() {
// scheduled search n replace actions
var actions = grunt.config("regex-replace").rjsmodules.actions;
// action object
var o = {
search: '',
replace: '', //<%= grunt.filerev.summary["build/js/app/detailsController.js"] %>
flags: 'g'
};
// read the requirejs config and look for optimized modules
var modules = grunt.config("requirejs.compile.options.modules");
var baseDir = grunt.config("requirejs.compile.options.dir");
var i, mod;
for (i in modules) {
mod = modules[i].name;
revvedMod = grunt.filerev.summary[baseDir + "/" + mod + ".js"];
revvedMod = revvedMod.replace('.js', '').replace(baseDir+'/','');
o.name = mod;
o.search = "'"+mod+"'";
// use the moduleid, and the grunt.filerev.summary object to find the revved file on disk
o.replace = "'"+revvedMod+"'";
// update the require(["xxx/yyy"]) declarations by scheduling a search/replace action
actions.push(o);
}
grunt.config.set('regex-replace.rjsmodules.actions', actions);
grunt.log.writeln('%j', grunt.config("regex-replace.rjsmodules"));
grunt.task.run("regex-replace:rjsmodules");
}),
You can also use requirejs' map config to specify a mapping between your original module and your revved one.
Filerev outputs a summary object containing a mapping of all the modules that were versioned and their original names. Use grunt file write feature to write a file in AMD way with the contents being the summary object:
// Default task(s).
grunt.registerTask('default', ['uglify', 'filerev', 'writeSummary']);
grunt.registerTask('writeSummary', 'Writes the summary output of filerev task to a file', function() {
grunt.file.write('filerevSummary.js', 'define([], function(){ return ' + JSON.stringify(grunt.filerev.summary) + '; })');
})
and use this file in your require config so that the new revved modules are used instead of old ones:
require(['../filerevSummary'], function(fileRev) {
var filerevMap = {};
for (var key in fileRev) {
var moduleID = key.split('/').pop().replace('.js', '');
var revvedModule = '../' + fileRev[key].replace('.js', '');
filerevMap[moduleID] = revvedModule;
}
require.config({
map: {
'*': filerevMap
}
});
The filerevMap object that I created above is specific to my folder structure. You can tweak it as per yours. It just loops through the filerev summary and makes sure the keys are modified as per your module names and values as per your folder structure.

Windows 8 Javascript reading html into data.js

I'm using the sample grid javascript template to build a win8 application.
I'm also using the data.js file to load data. However this uses :
var content = "test content";
var sampleItems = [
{group: sampleGroups[0], title: "Title", description: "DESC", content: content},
However, my content text is getting longer and I would also like to put in html syntax like IMG and P etc.
Whats the simplest way to load a local html file into the content variable above?
Thanks!
To read an HTML file in the local storage of the application you would use the readText method of the WinJS.Application.local object.
var loc = WinJS.Application.local;
loc.readText("fileName", "failed").done( /* Your success and error handlers */ );
For reading a file stored in the app package you would execute something more like this:
var myText;
var url = new Windows.Foundation.Uri("ms-appx:///html/filename.html");
Windows.Storage.StorageFile.getFileFromApplicationUriAsync(url).then(function (file) {
Windows.Storage.FileIO.readTextAsync(file).then(function (text) {
myText=text;
});
});

Yii renderpartial (proccessoutput = true) Avoid Duplicate js request

Im creating a site who works with ajaxRequest, when I click a link, it will load using ajaxRequest. When I load for example user/login UserController actionLogin, I renderPartial the view with processOUtput to true so the js needed inside that view will be generated, however if I have clientScriptRegister inside that view with events, how can I avoid to generate the scriptRegistered twice or multiple depending on the ajaxRequest? I have tried Yii::app()->clientScript->isSCriptRegistered('scriptId') to check if the script is already registered but it seems that if you used ajaxRequest, the result is always false because it will only be true after the render is finished.
Controller code
if (Yii::app()->request->isAjaxRequest)
{
$this->renderPartial('view',array('model'=>$model),false,true);
}
View Code
if (!Yii::app()->clientScript->isScriptregistered("view-script"))
Yii::app()->clientScript->registerScript("view-script","
$('.link').live('click',function(){
alert('test');
})
");
If I request for the controller for the first time, it works perfectly (alert 1 time) but if I request again for that same controller without refreshing my page and just using ajaxRequest, the alert will output twice if you click it (because it keeps on generating eventhough you already registered it once)
This is the same if you have CActiveForm inside the view with jquery functionality.. the corescript yiiactiveform will be called everytime you renderPartial.
To avoid including core scripts twice
If your scripts have already been included through an earlier request, use this to avoid including them again:
// For jQuery core, Yii switches between the human-readable and minified
// versions based on DEBUG status; so make sure to catch both of them
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;
If you have views that are being rendered both independently and as HTML fragments to be included with AJAX, you can wrap this inside if (Yii::app()->request->isAjaxRequest) to cover all bases.
To avoid including jQuery scripts twice (JS solution)
There's also the possibility of preventing scripts from being included twice on the client side. This is not directly supported and slightly more cumbersome, but in practice it works fine and it does not require you to know on the server side what's going on at the client side (i.e. which scripts have been already included).
The idea is to get the HTML from the server and simply strip out the <script> tags with regular expression replace. The important point is you can detect if jQuery core scripts and plugins have already been loaded (because they create $ or properties on it) and do this conditionally:
function stripExistingScripts(html) {
var map = {
"jquery.js": "$",
"jquery.min.js": "$",
"jquery-ui.min.js": "$.ui",
"jquery.yiiactiveform.js": "$.fn.yiiactiveform",
"jquery.yiigridview.js": "$.fn.yiiGridView",
"jquery.ba-bbq.js": "$.bbq"
};
for (var scriptName in map) {
var target = map[scriptName];
if (isDefined(target)) {
var regexp = new RegExp('<script.*src=".*' +
scriptName.replace('.', '\\.') +
'".*</script>', 'i');
html = html.replace(regexp, '');
}
}
return html;
}
There's a map of filenames and objects that will have been defined if the corresponding script has already been included; pass your incoming HTML through this function and it will check for and remove <script> tags that correspond to previously loaded scripts.
The helper function isDefined is this:
function isDefined(path) {
var target = window;
var parts = path.split('.');
while(parts.length) {
var branch = parts.shift();
if (typeof target[branch] === 'undefined') {
return false;
}
target = target[branch];
}
return true;
}
To avoid attaching event handlers twice
You can simply use a Javascript object to remember if you have already attached the handler; if yes, do not attach it again. For example (view code):
Yii::app()->clientScript->registerScript("view-script","
window.myCustomState = window.myCustomState || {}; // initialize if not exists
if (!window.myCustomState.liveClickHandlerAttached) {
window.myCustomState.liveClickHandlerAttached = true;
$('.link').live('click',function(){
alert('test');
})
}
");
The cleanest way is to override beforeAction(), to avoid any duplicated core script:
class Controller extends CController {
protected function beforeAction($action) {
if( Yii::app()->request->isAjaxRequest ) {
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery-2.0.0.js'] = false;
Yii::app()->clientScript->scriptMap['anything.js'] = false;
}
return parent::beforeAction($action);
}
}
Note that you have to put the exact js file name, without the path.
To avoid including script files twice, try this extension: http://www.yiiframework.com/extension/nlsclientscript/
To avoid attaching event handlers twice, see Jons answer: https://stackoverflow.com/a/10188538/729324