Project moved to github as 7.0beta ¶
Motivated by earlier suggestions, a lot of improvements made on the library.
- What's new compared to 6.x?
- huge refactor
- one-file code splitted to parts
- completely new css processing part: processing @import-s, url-s
- composer support
- demo app
- moved to github
Visit https://github.com/nlac ***
NLSClientScript prevents duplicated linking of javascript files when updating a view by ajax, when eg. paging or sorting a gridview, ajax-submitting a form or any custom ajax-updating a part of a view.
The extension does not prevent the multiple loading of CSS files. I simply couldn't find a way to manage it clearly (too long to explain here).
The issue what this extenson fights is for example when you render Jui widgets by CHtml::ajax, the js files used by the widget will be loaded as many times as you render such a widget in a view. The unnecessary bandwidth usage is the smaller problem, the bigger problem is eg. loading jquery.js again may reset some js objects set by previously loaded ui-related js files. That can cause js errors and the view may stop working.
Using NLSClientScript helps to avoid it all.
From 6.0, it optionally merges/caches + minifies the registered js and css files.
History ¶
- 6.7
- fixed toAbsUrl() and optimized init() methods (reported + fix by le_top)
- 6.6
- fixed regexp in normUrl (reported by le_top)
- 6.5
- fixed buggy behavior when more xhr "script"-dataType requests started for the same script
- eliminated deprecated jQuery.browser reference
- 6.4
- followed the change of the registerScriptFile() arguments in yii 1.1.14
- removed/added some comments
- 6.3
- serious bug fixed: filtering duplications (usually) failed when js-merging applied for the response of an xhr request
- new params: mergeIfXhr, mergeJsExcludePattern, mergeJsIncludePattern, mergeCssExcludePattern, mergeCssIncludePattern, resMap2Request (see the phpdoc comments in the source for more info)
- appended an extra ; to the js files
some other small improvements
- 6.21
fixed another bug: merged files have been re-generated on every request when the appVersion parameter was used
- 6.2 (see the updated Usage)
- fixed a serious bug broke the original functionality when merging happened (duplicates couldn't been recognized)
added a new parameter appVersion
- 6.1 (see the updated Usage)
- fixed several bugs (serverBaseUrl composing, merging css files by media correctly)
added parameters mergeAbove, curlTimeOut, curlConnectionTimeOut
- 6.0 (see the updated Usage)
- added optional merge and minify functionalities
to keep the simpleness of the single-file extension, embedded JSMin.php from https://github.com/eriknyk/jsmin-php
- 5.0 (see the updated Usage)
in 4.0RC found an issue couldn't worked around: it registered also the script tags being in html/css/js comments, input field, textarea value so i had to drop the native source analysis by regexp. Fortunately found the solution in 5.0 looks like the most perfect till now. Tested successfully in IE7+, latest FF,Chrome,Opera. Reports about testing are welcome as always.
- 4.0 RC
refactored, hopefully all bugs reported about 3.x have been eliminated
- 3.6
fixed a typo
- 3.5 (see the updated Usage)
- handling special case when updating a table by tr tag
- further IE fixes
- added 2 new parameters: ignoredPattern and processedPattern
general refactoring
- 3.4
fixed non-script-rendering bug in IE
- 3.3
- removes the occasional ...?_=3767454656434 -like timestamps from the url keys used to store/identify the loaded scripts
fixed the accidental naming NLSClientScript to EClientScript
- 3.2
- fixed accessing HEAD element for IE
compressed js code (full source is still there in the php source)
- 3.1
the extension now prevents the duplicated loading of css files also.
- 3.0
- brand new approach simplifying dramatically the extension and the usage of the extension, based the great idea of Eirik Hoem
see the Usage below!
- 2.1
- dirty fix for a rendering bug of jquery.js v1.6.1 affecting binline=true mode in Yii 1.18
- 2.0
- brand new approach: resource hash stored at the server side, in the webuser state. All these info deleted when a non-ajax request comes
- no $.ajax usage - better performance
- the extension does not require jquery.js and jquery.yii.js to be linked initially any more
- js/css files can be linked from other domain
new parameter: bInlineJs - if true, the scriptFile method will insert the js file content into the html instead of linking the file what can result even better performance
- 1.3
- added cache:true to the ajax js load
compressed core js code
- 1.2
- fixed js error when app not in YII_DEBUG mode
- 1.1
- hash key generated on server side
- two hash key mode: PATH and CONTENT
- shortened client-side code
- 1.0
- base version
If you interest the details, see the comments in the source.
Requirements ¶
Yii 1.x
Limitations ¶
The extension identifies the scripts by its paths so it does not prevent to load the same script content from different paths. So eg. if you published the same js file into different asset directories, NLSClientScript considers those to be different and won't prevent to load those several instances.
The extension doesn't watch wether a js/css file has been changed. If you set the merge functionality and some file changed, you need to delete the cached merged file manually, otherwise you'll get the old merged one.
Usage (v6.3+) ¶
1 . Set the class for the clientScript component in /protected/config/main.php, like
...
'components'=>array(
...
'clientScript' => array(
'class' => 'your.path.to.NLSClientScript',
//'excludePattern' => '/\.tpl/i', //js regexp, files with matching paths won't be filtered is set to other than 'null'
//'includePattern' => '/\.php/', //js regexp, only files with matching paths will be filtered if set to other than 'null'
'mergeJs' => true, //def:true
'compressMergedJs' => false, //def:false
'mergeCss' => true, //def:true
'compressMergedCss' => false, //def:false
'mergeJsExcludePattern' => '/edit_area/', //won't merge js files with matching names
'mergeIfXhr' => true, //def:false, if true->attempts to merge the js files even if the request was xhr (if all other merging conditions are satisfied)
'serverBaseUrl' => 'http://localhost', //can be optionally set here
'mergeAbove' => 1, //def:1, only "more than this value" files will be merged,
'curlTimeOut' => 10, //def:10, see curl_setopt() doc
'curlConnectionTimeOut' => 10, //def:10, see curl_setopt() doc
'appVersion'=>1.0 //if set, it will be appended to the urls of the merged scripts/css
)
...
)
For more information about the parameters, see the header comment of NLSClientScript.php.
2 . use Yii::app()->getClientScript() by the standard way to link js and css files/snippets
Example:
$cs = Yii::app()->getClientScript();
$systemJsPath = Yii::app()->getAssetManager()->publish( Yii::getPathOfAlias( 'system.web.js' ), false, -1, false );
$cs->registerScriptFile( $systemJsPath . '/ext/yii_ext.js');
$cs->registerScriptFile( $systemJsPath . '/ext/plugins/jquery.form.js');
3 . DOES NOT WORK FROM v5.0: If you want to do a custom ajax request with "dataType"="json" and there are some fields of the response you want to update your page with, filter that part "by hand" with $.ajaxSettings.dataFilter like eg.:
echo CHtml::ajaxLink('custom update', array('/site/testupdate'), array(
'dataType' => 'json',
'success'=>'js:function(data){ $("#cont").html($.ajaxSettings.dataFilter(data.content)); }',
));
nice one
I'll check it out for sure
What I do is to extend controller's render and renderPartial methods to accomplish the same result but your way is better
just looks wonderful
gonna take a look on this one for sure.
thanks a lot and keep up the good work!
thx
thank you guys, let me know if any issue come up with it.
Great work
I use another way for it like fullajax concept. But in jquery way.
not working for me
This extension is promising. I´m facing the mentioned troubles with my ajax-loaded gridview and its ajax events: same requests keep repeating after refreshing the grid.
I´ve just installed the extension but it doesn´t seem to be working, the same things still happens. What could I be doing wrong?
Thanks
more info needed
Hi hav3fun,
thx for the report. Can you send me (at least the relevant part) of your source code, pls check my mail address in my profile. I'll try to debug.
more info needed2
also please specify exactly what request keeps repeating: what is requested, what is the response (use Firebug)
works but sadly not usefull in my case
This extension works for me, but sadly the final "rendertime" of the page seems to be increased (sometimes dramatically). I got a application with several js files which are also used for the layout. With this extension the js excecution time is increased so the not finished (or positioned) layout is shown.
I also had some trouble with the ajax caching. Every visit to the page would let load the js file again an again because every request had a ?_=1308645861658 in the url. Don't know if this is some case of some other ajax setup's i have used. But if i add cache:true, to the script ajax call this issue is solved.
Sadly the excecution time is to high guess it comes from the ajax lazyload.
1.3 released
Thx horizons, pls check the new version 1.3.
To be honest i couldn't do too much with the speed of the ajax loading in the current version (only that way can synchronously load a remote js dynamically, eg. appending a script tag to the head/body cannot provide synchronous load). I also have to remark that i didn't experience so much speed loss with the ajax load.
Not working in _dev mode
Hey.
Nice extension.
But sadly it's not working in the _dev mode, when YII_DEBUG is defined =(
help me to fix
Hi WallTearer,
thanks for the report. Could you help me in the fixing by sending the following infos by mail (you can mail me going into my profile page)?
Thx
OK
I've send you an email with some explanations
thanks + suggestion
hi nlac,
Thank you for your great extension. I installed and used it with no problem.
In installation process,I took another approach: instead of 3rd step you mentioned(changing index file), I add just the following code:
if (!Yii::app()->request->isAjaxRequest) Yii::app()->clientScript->clearCache();
to onBeginRequest event of application. Actually, I added a class to main config file as behaviours parameter, and bind the above code to onBeginRequest in that class.
my approach has 2 main advantage over yours:
indeed
Yes arash.. a handler for the onBeginRequest event is definitely the right place for clearing the script cache instead. An additional reason is, if an action registers a script then invokes an another action by eg. forwarding, the script cache may NOT be cleared meanwhile..
I'll include it into the next version, thx man.
to WallTearer
Thanks for the mail report. Unfortunately i couldn't really get more info from it, especially i would have been interested the code in the view/controller. I haven't ever met this issue. If you like, we can change mail addresses and you can share your code for me that way.
I'm really curious btw what is the issue.
Good but..
If user open multiple pages and using ajax on individual of those pages, Yii::app()->user->setState('nlsLoadedResources', array()); will be clear for the previously opened page?
for kernel
Thanks for the comment. Yes that's true, this is a kind of limitation of this session-based caching. The perfect would be to have some kind of "view scope" like in JSF but it isn't available in PHP (and i have no clue how could it be implemented).
This limitation isn't recent in the DOM-based caching (in nlsclientscript v<2.0) but the advantage is to be able to cache js files from another domain and the performance is better.
I try to have some time in the next 1-2 weeks to create the next version keeping the last comments in mind. Unfortunately i'm recently extremely busy in work and other stuffs :(
Hi, nlac
A solution I came up with is to identify each page by generating a (unique id / 'session id' / page token .. you name it) for it, and store the ID in state() or $_SESSION, AND, this ID will be destory on browser's window.onUnload event.
So, individual ajax actions on differet pages will go with the it's page ID to help nlsclientscript to detect the ajax request context where it came from. I will paste some code here sooner or later.
about v3.0
one drawback of client-side filtering of incoming data is more network traffic, i.e. already loaded js/css will send again to client on each ajax request which is not so good, especially for slow connections.
hi
Sending the script TAGs again - NOT the script - won't cause relevant network traffic. The already loaded scripts won't be loaded again, that's the point of the extension.
As you may noticed, the extension recently doesn't care with css links, so css links are still allowed to be loaded more times. However that is not so big issue like the js case i'm still thinking about the best way to handle it.
thank you
I just want to thank you for providing such a good extension
thx
i hope you guys find it useful
I don't understand
Please, help somebody.
1 - The extension file name is NLSClientScript.php, but class in it has name EClientScript. My standart Yii autoloader don't understand this and when I'm trying to view any page of my site I see the next:
include(NLSClientScript.php) [<a href='function.include'>function.include</a>]: failed to open stream: No such file or directory
This problem have a really simple solution (I manually rename class name EClientScript to NLSClientScript), but am I the only one who faced the similar problem?
2 - All versions after version 2.1 seems do not work for me!
On user profile on my local site in the Firefox, Firebug, opened Network tab I can see that jquery file was loaded from http://example/assets/74888a90/jquery.js.
Next step I click on link to open CJuiDialog. After that in the Firebug's Network tab I see also one jquery file loaded from http://example/assets/74888a90/jquery.js?_=1318941693410. The same I see about some other files. Where I wrong?
i'll check
Hi Alexey,
issue 1 is because i've accidentally left the class renamed (i use it with that other name in a project). The class name should be NLSClientScript of course.
The issue 2 i guess is because the random url parameter appended to the js url by the framework, the extension considers it to be another file than the earlier-registered jquery.js. I'll inspect how to avoid it and will update soon.
let me know if ok
Alexey and maybe others, pls try 3.3 and let me know if there is still any issue with the extension. However i couldn't reproduce the reported issue i applied a possible fix.
to nlac
Thank you for quick update but nothing changed for me about issue 2. :(
I looked into your code in the Firebug and it seems defined what's wrong:
if (type && type != "html" && type != "text") return data;
My type is json. So this line ignore all next code and always return data.
hmm..
than explains everything. So i guess you make a custom ajax request, response a json putting the html in some field of the json (capturing the output of a partial render i guess) and update a container "by hand" in the response handler?
My goal was with it to improve the performance by adding that filtering there.
Now i'm thinking about to extend the API with a js function, calling it would be possible to set that global filtering any time + handling the filtering of the json.
about type=JSON
Yes, you are completely right!
But this is do not resolve the problem yet. :)
I changed condition to
if (type && type != "html" && type != "text" && type != "json") return data;
and had tracking step by step.
The line
$._holder[0].innerHTML = data;
filled $._holder[0] by the data, but it seems this action also escape and urlencode all HTML. So having data
"{"status":"failure","content":"<link rel=\"stylesheet\" type=\"text\/css\" href=\"\/assets\/87d8c6f6\/vertical.css\" \/>\n<link rel=\"stylesheet\" type=\"text\/css\" href=\"\/assets\/74888a90\/jui\/css\/base\/jquery-ui.css\" \/>\n<script type=\"text\/javascript\" src=\"\/assets\/74888a90\/jquery.js\"><\/script>\n<div id=\"profilePhotoTabs\">\n<ul>\n<li><a href=\"#profilePhotoTabs_tab_0\" title=\"#profilePhotoTabs_tab_0\">From URL<\/a><\/li>\n<li><a href=\"\/user\/profilePhoto\/fromComputer\" title=\"#profilePhotoTabs_tab_1\">From computer<\/a><\/li>\n<li><a href=\"\/user\/profilePhoto\/fromWebcam\" title=\"#profilePhotoTabs_tab_2\">From webcam<\/a><\/li>\n<\/ul>\n<div id=\"profilePhotoTabs_tab_0\">Would be some text field for URL<\/div>\n<\/div>\n<script type=\"text\/javascript\" src=\"\/assets\/74888a90\/jui\/js\/jquery-ui.min.js\"><\/script>\n<script type=\"text\/javascript\">\n\/*<![CDATA[*\/\njQuery('#profilePhotoTabs').tabs({'cache':true});\n\/*]]>*\/\n<\/script>\n"}"
we are getting
"{"status":"failure","content":"<link rel="\"stylesheet\"" type="\"text\/css\"" href="%5C%22%5C/assets%5C/87d8c6f6%5C/vertical.css%5C%22" \="">\n<link rel="\"stylesheet\"" type="\"text\/css\"" href="%5C%22%5C/assets%5C/74888a90%5C/jui%5C/css%5C/base%5C/jquery-ui.css%5C%22" \="">\n<script type="\"text\/javascript\"" src="%5C%22%5C/assets%5C/74888a90%5C/jquery.js%5C%22"><\/script>\n<div id=\"profilePhotoTabs\">\n<ul>\n<li><a href=\"#profilePhotoTabs_tab_0\" title=\"#profilePhotoTabs_tab_0\">From URL<\/a><\/li>\n<li><a href=\"\/user\/profilePhoto\/fromComputer\" title=\"#profilePhotoTabs_tab_1\">From computer<\/a><\/li>\n<li><a href=\"\/user\/profilePhoto\/fromWebcam\" title=\"#profilePhotoTabs_tab_2\">From webcam<\/a><\/li>\n<\/ul>\n<div id=\"profilePhotoTabs_tab_0\">Would be some text field for URL<\/div>\n<\/div>\n<script type=\"text\/javascript\" src=\"\/assets\/74888a90\/jui\/js\/jquery-ui.min.js\"><\/script>\n<script type=\"text\/javascript\">\n\/*<![CDATA[*\/\njQuery('#profilePhotoTabs').tabs({'cache':true});\n\/*]]>*\/\n<\/script>\n"}"
as result.
Next loop works not as I expect because on first loop I have
tmp = <script src="\"\/assets\/74888a90\/jquery.js\"" type="\"text\/javascript\"">
and so on... :(
Can you suggest anything?
providing a callback
the solution will be providing the chance for communicating with the global filter by setting a callback what can transform the "data" to filterable elements and can transform the filtered fragments back into the "data". I'll update soon.
dataType=json
see the updated Usage point 3
Version 3.4?
Sorry, it seems something was gone wrong? Yesterday evening I see the version 3.4 and instruction how to use it for data type=json. But now it is hide.
I don't want to be annoying, but want to say about my implementation of ajax request.
I use this code:
CHtml::ajax(array( 'url'=>array('profilePhoto/index'), 'data'=>'js:$(this).serialize()', 'type'=>'post', 'dataType'=>'json', 'success'=>...
so 'dataType'=>'json' is already defined.
But I have else one question. Even you will add a callback possibility for json responses, where will be benefit to use a new version with all required callback functions instead the version 2.1 without any callbacks?
version 3.4
Forget 3.4, i added that yesterday but some minutes after i realized that callbacks are unnecessary, so i removed that version (i was really tired..).
Latest is 3.3, no callbacks.
Alexey, just check the "success"=>... code in the Usage point 3. and apply that in you code.
Yes!
It works great now! And so simple solution!
Thank you for this work and for your attention to your customers.
Re: version 3.3
Does exactly what it promises, and with a very elegant solution. Excellent!
The only thing I don't understand is why it's called NLSClientScript, was there no more descriptive name available? (like EAjaxClientScript) :) And by the way, the changelog currently says it's called EClientScript..
table row problem
hi, i've switched from 2.1 to 3.3 today and found the following bug:
in a form which is organized in a table, the user can add new rows via ajax. the server is sending only a new table row (tr-element) with some columns in it.
the javascript-filter takes this row and puts it via innerHTML into a div-element which kills all tr- and td-elements from the original code. it then filters the dom and returns the broken code.
quick-fix:
insert above line 74:
data = jQuery.trim(data); if(data.slice(0,3) == "<tr") { $._holder = $(document.createElement("tbody")); } else { $._holder = $(document.createElement("div")); } $._holder[0].innerHTML = data; //<<< original line
to marcovtwout
Hi, thanks.
"NLS" points to "NLacSoft" what is my domain name actually. (i'll release some valuable content there in a few days!:))
The "EClientScript" is a kinda standard extension name format, i use my extension with that name at the company i work for.
to stereochrome
Thanks, excellent catch and solution.
I'll include it in the next release, also have to fight other cases (dt,dd,li,caption,thead etc)
for stereochrome
Hi, i tested the bug, actually i experienced such issue only in IE (not exactly the same issue but can be related) and added a fix in 3.4.
i'm curious if it has been fixed at your case
problem persists
Hi,
unfortunately this new version does not fix the problem. I'm encountering this problem in chrome 15 on kubuntu and in other browsers. I've got a lot of work to do at the moment because it is the last workday for this year (yay), but i'm going to create a testcase for this problem in the new year.
for stereochrome
check 3.5 and also the demo on nlacsoft.net (it does exactly your case:))
works!
yep, 3.5 works like expected. thanks for your work and a happy new year!
Warning: "head" is not defined.
Here is returning an error warning that "head" is not defined.
This piece of code:
// iterate over new scripts and remove if source is already in DOM: for(i=0,res=holder.find($._nlsc.selector); i<res.length; i++) { tmp = res[i]; ind = tmp.src ? tmp.src : tmp.href; ind = ind.replace($._nlsc.urlGarbageRg,""); if (resMap[ind]) $(tmp).remove(); else { if (tmp.href) head.appendChild(tmp); else tmp.removeAttribute("defer"); resMap[ind] = 1; } }
should be?
// iterate over new scripts and remove if source is already in DOM: for(i=0,res=holder.find($._nlsc.selector); i<res.length; i++) { tmp = res[i]; ind = tmp.src ? tmp.src : tmp.href; ind = ind.replace($._nlsc.urlGarbageRg,""); if (resMap[ind]) $(tmp).remove(); else { if (tmp.href) $._nlsc.head.appendChild(tmp); else tmp.removeAttribute("defer"); resMap[ind] = 1; } }
thx thimt8-yii
fixed in 3.6
Issue with the parser in Internet Explorer 7
Hello,
I am using version 3.6 of your extension in my Yii project.
It seems that the selection of script tags in the HTML source fails for some reason in Internet Explorer 7. The looping through the SCRIPT or LINK elements is the place where we have now added an extra test case, to be sure that there is at least a not empty SRC or HREF attribute defined. (see added code below)
//fetching scripts from the DOM for(i=0,res=$(document).find($._nlsc.selector); i<res.length; i++) { tmp = res[i]; // CODE ADDED: // ie7 sometimes gets accidental script tags and selector returns undefined objects if (tmp.src == "" && typeof(tmp.href) === "undefined") { continue; } ind = tmp.src ? tmp.src : tmp.href; ind = ind.replace($._nlsc.urlGarbageRg,""); if (tmp.href && tmp.parentNode!=$._nlsc.head) $._nlsc.head.appendChild(tmp); $._nlsc.resMap[ind] = 1; }
And I had to add the code again in the other loop :
// iterate over new scripts and remove if source is already in DOM: for(i=0,res=holder.find($._nlsc.selector); i<res.length; i++) { tmp = res[i]; // CODE ADDED: // ie7 sometimes gets accidental script tags and selector returns undefined objects if (tmp.src == "" && typeof(tmp.href) === "undefined") { continue; } ind = tmp.src ? tmp.src : tmp.href; ind = ind.replace($._nlsc.urlGarbageRg,""); if (resMap[ind]) $(tmp).remove(); else { if (tmp.href) $._nlsc.head.appendChild(tmp); else tmp.removeAttribute("defer"); resMap[ind] = 1; } }
Is it possible that the jquery selector is not precise enough ?
selector : "script[src],link[rel=\"stylesheet\"]",
Please let me know if there would be a fix for that issue in your next revision.
Yann
thx
hoplayann thanks for the report, i'll check and will release a new version in a few days, there's also an other issue needs to be fixed.
HTML content is being duplicated.
I have problems. When the extension is enabled the HTML content is being duplicated in ajax requests.
Detail: the problem does not occur in IE, only in Firefox and Chrome. And only occurs when the return of Ajax is the complete page, including the HTML tag.
The javascript code behaves completely different in IE vs Firefox and Chrome.
The developer needs to fix the default behavior on all browsers.
A workaround for Firefox and Chrome (but certainly not the ultimate solution):
(...) firstTagRg : /<([a-z1-6]+)[^>]*>/i, (...) holders : { "default" : $(document.createElement("div")), "tr" : $(document.createElement("tbody")), "html" : $(document.createElement("html")) },
Duplicate html content rendering
is #7098 fixed in 3.6 version? I am still facing the problem in filtering in the cgridview
IE7 bug
IE7 has a problem with the "src" attribute of the script tag, as can be seen in http://bugs.jquery.com/ticket/11404
So the update of the grid returns the alert "Parser error".
The solution to the problem would be to change the script to:
(...) selector : "script:not([src=\"\"]),link[rel=\"stylesheet\"]", (...)
guys please test 5.0
test results about usages of the latest version are welcome
Script error jquery undefined
I have install version 5.0.
It works on all my pages where jquery is included.
But on my static pages (e.g. impressum page) where I need no jquery there I get the error 'jquery undefined'.
What can I do. Must I include on all my pages jquery or can I do this with exclude pattern ?
for klaus66
I guess that is not a static page where the issue occurs. On the pages where no script file registered, the component renders nothing. On your "static page" some script is registered requires no jquery, that's when the issue occurs.
So yes, for now all pages need jquery registered since the component uses it. I'll fix in the next release to register jquery automatically in every case.
Not really static page
You are right. My 'static' pages register a small js script.
But how you said they don't need jquery.
I register now jquery for all my sites in my main layout view.
I use the google lib and I think it is no problem for performance.
Version 5
Using version 5 seems to work as expected in IE7/8 and Chrome.
I upgraded after IE7/8-issues in version 3.3.
Only thing I would like to see is proper DocBlock commenting on variables and functions in your extension.
And actually, maybe a better name because "NLSClientScript" doesn't say anthing about what it does, but something like "AjaxCompatibleClientScript" or maybe just "EClientScript" or "XClientScript" is better.
5.0 not ok with 'dataFilter'
Hi
I just tried version 5.0 after previously using v3.6.
I use it as in the example: $("#cont").html($.ajaxSettings.dataFilter(data.content)); .
Apparently this does not work anymore ad 'dataFilter' is unknown in Chrome (for example) when using 5.0. It appears that 'dataFilter' is defined only when using 'IE'.
=/
Even with the extension when using AJAX, the Bootstrap CSS files are reloaded the page.
A problem & a suggested fix
Hello nlac,
Thanks so much for such work, was totally a savior for me.
I'm reporting that there's a conflict between nlsclientscript & Minscript extension
http://www.yiiframework.com/extension/minscript/
The js file is loaded again & duplicated after the first ajax request.. thats because the normUrl function of nlsclientscript takes the minscript url in the form of:
& returns
> http://localhost/soedu/min/serve?g=7668aa4b832f39e552dd77ac5e156c5c&lm=1353462851&
Notice the '&' at the end
The suggested fix would be to modify normUrl function, replacing
return url.replace(/\?*(_=\d+)?$/g,"");
With
return url.replace(/(\?|&)*(_=\d+)?$/g,"");
Fatal error in 6.0
$_SERVER['REQUEST_SCHEME'] is not always available, and will throw undefined index:
if (!$this->serverBaseUrl) $this->serverBaseUrl = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
Omitting it is safe in most browsers, but I haven't checked how it affects other parts of your code:
if (!$this->serverBaseUrl) $this->serverBaseUrl = '//' . $_SERVER['HTTP_HOST'];
serverBaseUrl issue
yes i'm aware, will fix soon. Till then set that param explicitly in config.php
import in css not work
Thanks, nice extension, but import function of css not work after minify.
May be you should use full css minifier (e.g http://code.google.com/p/cssmin/) not simple css minifier?
@Nafania
Hi,
i'm not sure the problem relates to the minification. When the extension merges the files, it publishes the merged one into the /assets dir. That way, if you use relative url in your @import (like "dir/xy.css" or "../dir/xy.css"), that will usually break.
Have you tried to use url like "/dir/xy.css" in the @import rule (relative to the server root) or perhaps full absolute url?
About cssmin, i try to keep my extension lightweight, without merging 3rd parties into being 10x large than the extension itself, unless it is really necessary.
@Nafania
Well, i've just have seen that http://code.google.com/p/cssmin/ is able to merge the @import-ed css files into the parent one by its documentation.
That's indeed a feature what makes me consider to use it in a later version some way.
Thanks for the tip...
Misfunction of NLSClientScript
i've problem. I plugged in NLSClientScript and it worked well for my Yii app.
Yet, when i've moved the code to the new host it doesn't work right, it issues smth. like:
<link rel="stylesheet" type="text/css" href="/application/assets/nls2027373635.css" /> <script type="text/javascript" src="0"></script>
instead of
<link rel="stylesheet" type="text/css" href="/application/assets/nls4067536120.css" /> <script type="text/javascript" src="/application/assets/nls1913355335.js"></script>
What's wrong? How to resolve it?
@Igor
i'm not sure what causes that right now.
First make sure that
and test again.
If no success, go to my forum profile page and send me the following info (local menu "nlac"/Messenger/Compose new):
@Igor Savinkin
It's because CClientScript's
scriptFiles
property signature changed in 1.1.14. (I'm sure you've made upgrage yii version when moved to new host). Authors have to change a few line of code. In_mergeJs
protected method it's need to changeif ($this->mergeJsExcludePattern && preg_match($this->mergeJsExcludePattern, $absUrl)) { $finalScriptFiles[] = $scriptFile; continue; } if ($this->mergeJsIncludePattern && !preg_match($this->mergeJsIncludePattern, $absUrl)) { $finalScriptFiles[] = $scriptFile; continue; }
to
if ($this->mergeJsExcludePattern && preg_match($this->mergeJsExcludePattern, $absUrl)) { $finalScriptFiles[$scriptFile] = $scriptFile; continue; } if ($this->mergeJsIncludePattern && !preg_match($this->mergeJsIncludePattern, $absUrl)) { $finalScriptFiles[$scriptFile] = $scriptFile; continue; }
THANKS
Thanks! This really saved me ;)
Multiple gridview
In my code i render, through ajax, 3 times (ajax1, ajax2, ajax3) the same widget(cgridview) with different parameters.
Most of the time it works good, but sometimes i get the error "jQuery(...).yiiGridView is not a function"
ERROR IMAGE
NO ERROR IMAGE
sourceMappingURL bug
Not found sourceMappingURL
when use compress css
@Bianchi
So if i understand correctly, more partials have been requested asynchronously, containing the same type widget (?). If this is the case, i have an idea about the issue, will test it and possibly fix in some days as i'll have time.
@nlac
You understood correctly, i'll wait for your fix :)
sourceMappingURL bug
example /css/bootstrap.css:
/# sourceMappingURL=bootstrap.css.map /
bootsrap.css.map in same path as bootstrap.css
but after compressing it search bootsrap.css.map in /assets/ folder
@fad
first, there is no "compress" option in nlsclientscript, only mergeCss or compressMergedCss. I guess the problem caused by using the mergeCss. Just don't use the option in that specific case with mapping.
Problem about "mergeCss" option
Thanks for your great job, nlsc!
You save my time. While I just stranded by the duplicated "jquery-ui.min.js".
It works fine with JS. There is a small problem about "mergeCss" option.
If set "mergeCss" to TRUE, some jquery-ui assets files may got a wrong uri (404 in browser).
For example:
VALID: http://localhost/app/assets/4a2e203a/jui/css/base/images/ui-bg_flat_75_ffffff_40x100.png
INVALID: http://localhost/app/assets/images/ui-bg_flat_75_ffffff_40x100.png
@yanhui + @fad
yes, i'm aware of that problem, there is no url transformation in the content implemented when merging css. Since many people miss that feature I'll try to work out a solution soon.
Till that time, pls do not use the css merging.
@nlac Maybe compatibility problem work with Linux?
Your reply is appreciated, thanks for your attention, nlac.
nlsclientscript works fine in my develop pc (win8.1/xampp1.8.3),
today I found it doesn't works properly in my server environment (centos6.4/lampp1.8.3).
The error messages in browser like follow:
-Uncaught ReferenceError: $ is not defined nls1858337492.js:79
-Uncaught ReferenceError: jQuery is not defined index.php:28
After some googling, I found someone may meets the same problem.
-http://stackoverflow.com/questions/21679474/nlsclientscript-errors
-https://github.com/yiisoft/yii/issues/604
@yanhui
I didn't experienced yet op. system incompatibility regarding nlsclientscript. I contacted you for details through your forum profile.
GitHub
Would you consider moving the source code to GitHub and adding Composer support? :)
moving to github
good point, it would have several advantages. i registered it on my todo list:)
Issues - some solutions
I was still using 5.0, but for some reason my jQuery gets loaded two times when fetching a CJuiDialog through Ajax. So I was digging into that issue and decided to upgrade to the latest version to see if things were fixed.
Actually things are worse. My page layout and javascript were completely "scrambled".
First, the function to combine files is on by default and some "urls" were not found.
Second, my production server serves compressed files and they remain compressed after combining - they should be combined uncompressed!
The missing urls issue could be fixed by fixing the way the absUrl is computed.
The following code works for me:
protected function toAbsUrl($relUrl) { if(substr($relUrl,0,2)==='//') return (Yii::app()->getRequest()->getIsSecureConnection()?'https:':'http:').$relUrl; else return preg_match('&^(http(s?):)?//&',$relUrl) ? $relUrl : rtrim($this->serverBaseUrl,'/') . '/' . (substr($relUrl,0,1)==='/'?'':Yii::app()->getRequest()->getBaseUrl().'/').ltrim($relUrl,'/'); }
Changes are that if the url starts with '//' that only the scheme is prefixed.
Also, when the url starts with '/', the path is absolute from the host, but when the '/' is missing, the url is relative, so 'baseUrl' has to be added, which is also done above.
I prefer using Yii methods if they exist, so in 'init()', I changed a few lines:
if (!$this->serverBaseUrl) { $this->serverBaseUrl=Yii::app()->getRequest()->getHostInfo();
So that works on my dev machine, but not on the server where compressed content is combined. I haven't checked that issue yet. I have now disabled combining again.
I still have the dual jQuery loading, so I continue to look into that core issue for me.
Duplicate library load fixed...
The core mystery has been solved: my url had a trailing '&' after removing the '='.
That is because I added a timestamp to the assets which postfixes the urls with '?' which becomes '?&='.
So the normUrl function had to be updated with:
~~~
[javascript]
return url.replace(/\?*\&?(_=\d+)?$/g,"");
[javascript]
$.ajaxSettings.dataFilter(data)
~~~
?
@le_top
Thanks for the bug hunt, i added the fix.
About the old trick you pointed ($.ajaxSettings.dataFilter(data)), there's no need for that at all. From 5.0, the extension is rewritten in a totally different way, so you can work with any json ajax response without any neccessary post-processing.
Fix(es)
Ok for dataFilter - I suppose that is why my JSON calls do not seem to give any trouble. Some of the logic is done behind the scenes so I thought it did not apply.
I also reported about the 'toAbsUrl' method which is equally important. Otherwise combining(merging) scripts/css is not functional for 'localhost/workspace/index.php' or '//blabla.google.com/blabla'. A resource like 'themes/mytheme/js/script.js' would not work without one of the fixes for toAbsUrl.
Anyway, I also had some kind of compression issue where the combined file had compressed content - but only on the production server, so I suppose it has to do with compression from the content served by the production server and not with content served from third parties.
@le_top
Ok, somehow i skipped the toAbsUrl issue last time, focused only the second comment.. the fixes seem to be fine, have been added now.
About the compression issue, the compression is done by the embedded JSMin.php, that project is unfortunately abandoned, no further buxfixes provided. Possible minification issues should be work-arounded, eg. deal with originally minified files and just concat them by NLSClientScript.
Compression issue
Well, the absUrl fix is integrated ;-).
The compression issue is that the resulting file contains gzip compressed content, and is not related to content minimized (or compacted) by JsMin.
problem in mergeJs to false
Thanks for your work
I have this code in widget:
public function init() { $assetsPath = Yii::getPathOfAlias('application.widgets.gallery.assets'); $assetsUrl = Yii::app()->assetManager->publish($assetsPath); Yii::app()->clientScript->registerCssFile($assetsUrl.'/gallery.css'); Yii::app()->clientScript->registerScriptFile($assetsUrl.'/gallery.js'); // fancybox Yii::app()->clientScript->registerCssFile($assetsUrl.'/fancybox/source/jquery.fancybox.css?v=2.1.5'); Yii::app()->clientScript->registerScriptFile($assetsUrl.'/fancybox/lib/jquery.mousewheel-3.0.6.pack.js'); Yii::app()->clientScript->registerScriptFile($assetsUrl.'/fancybox/source/jquery.fancybox.pack.js?v=2.1.5'); }
But when i set mergeJs to false:
'mergeJs' => false, //def:true
I get this error:
TypeError: $(...).fancybox is not a function $(".fancybox").fancybox();
How i can resolve it?
Fix for compression bug
Hi
I found the solution for the compression bug.
Just add the following line to the initCurlHandler method:
curl_setopt($this->ch, CURLOPT_ENCODING, "");
@moa, @le_top
@moa: when the error comes, when the page is loaded or at the first partial update? I guess the second case, i suspect the fancybox plugin has broken due to loading again a js file (maybe fancybox.pack or other). Please check with Firebug what js file is loaded twice - remember if you refer a js once xxx.js?v=2.14, later xxx.js or xxx.js?v=2.15, NLSClientScript will consider those files to be different and won't prevent to load again. Please normalize the url's, to be the same for the same js content.
@le_top: nice, i'll test it and add to the next version, thx.
CSS merging and relative resources
Hi
Now that merging is working, I'v done a few tests.
Css merging has an important issue: relative resources are not rebased.
Example:
~~~
[css]
.grid-view table.items th {
color: white; background: url("bg.gif") repeat-x scroll left top white; text-align: center
}
~~~
After merging, the navigators looks in the assets folder for 'bg.gif', but it is not there.
Other issues with combining CSS files can be expected, and it might be a good idea to rely on an existing open source to do the job.
@le_top
Yep, i'm aware that url issue in the merged css, that was a topic in some earlier commments (btw not sure why only the top 20 comments are shown, near 90 comments are here). It's a plan to allow configuring a 3rd pary service to do the proper merging (or handle it properly without 3rd party, still not sure how much work it is).
Anyway it requires effort, i can't say will be done in some weeks, but it is in my list (as other things...:( ).
CSS urls
Hi
I suggest that you mention the limitation for the CSS at least in the notes above, and also in the comments of the source code (e.g., as a comment to the variable enabling the merge).
Also, while the comments say that Js and CSS merging are disabled by default, they are actually active by default in the extension. I recommend to keep buggy/limited options inactive - so CSS merging should really be false because relative Urls are essential (to the framework CSS for starters). If things do not work "immediately", many developers try and abandon the extension.
I understand the limitation of time completely - you'll likely add proper Css merging when you are in need of it yourself, which is fully understandable. That's why I generally fix bugs myself, the difficulty is often to get them into the official release.
Very Cool
Very Good extension, Its solve my issue as well as it boost my application speed
CGridView/CListView
NLSClientScript is an excellent extension but it does not work very well for the content of CGridView and CListView.
I had to face that issue once more and I decided to have a deeper look and I found a solution.
First, we can rely on the 'afterAjaxUpdate' parameter of the CListView/CGridView like this:
$this->widget('zii.widgets.CListView', array( //... 'afterAjaxUpdate' => "function(id,data){jQuery('body').append(jQuery(data).filter('script:not(\"[src]\")'));}", ));
That works but the second time you will try the Ajax reload will happen twice, the third time three times, etc. The "issue" is with the core library but was not accepted as a bug three years ago so here are the changes I apply after each Yii update for that (I just discovered the change needed for yiilistview.js as I have not been using that until recently).
CButtonColumn:
To remove the 'on' event on a grid before setting it.
if(true) { $class=preg_replace('/\s+/','.',$button['options']['class']); $js[]="if(typeof(_gridf)==='undefined'){_gridf={};}" ."if(typeof(_gridf['on-{$this->grid->id}-{$class}'])!=='undefined') {jQuery(document).off('click','#{$this->grid->id} a.{$class}',_gridf['on-{$this->grid->id}-{$class}']);}" ."_gridf['on-{$this->grid->id}-{$class}']=$function;" ."jQuery(document).on('click','#{$this->grid->id} a.{$class}',_gridf['on-{$this->grid->id}-{$class}']);"; } else { // Original code. $class=preg_replace('/\s+/','.',$button['options']['class']); $js[]="jQuery('#{$this->grid->id} a.{$class}').live('click',$function);"; }
jquery.yiigridview.js:
Add lines to switch off event listeners before defining them.
-> There is a potential issue that there are other listeners using the same selector that might be deleted.
-> However, the risk is low because the selector is specific and likely to be used by the yiiGridView only.
[javascript] $(document).off('click.yiiGridView', '#' + id + ' .' + settings.tableClass + ' > tbody > tr'); $(document).on('click.yiiGridView', '#' + id + ' .' + settings.tableClass + ' > tbody > tr', function (e) {
[javascript] $(document).off('click.yiiGridView', '#' + id + ' .select-on-check-all'); $(document).on('click.yiiGridView', '#' + id + ' .select-on-check-all', function () {
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector); $(document).on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
jquery.yiilistview.js:
~~~
[javascript]
$(document).off('click.yiiListView', settings.updateSelector);
$(document).on('click.yiiListView', settings.updateSelector,function(){
~~~
Have fun with it!
le_top
Hmm hardcore stuffs:) Interesting, as i remember i definitely tested the 7.0 with CGridView (not sure i did it with CListView) and didn't noticed any trouble...
Could you pls descibe the original issue you experienced, regarding the conflict of NLSClientScript and CGridView/CListView? It is still not clear for me and to be honest i stopped digging into the further details from that point. I got confused from the "afterAjaxUpdate" thing - it was already an attempt to solve an issue or it was the case when the issue happened? Sorry maybe i'm too tired right now and missed something in the description:)
Gist to demonstrate issue
Hi
I created a GIST that you can use as a view ('$this->render('viewname');' in a controller will do it).
This example has two grids with a CJuiButton that I inserted in the filter.
The CJuiButton is fully functionnal if the jquery-ui is executed on it.
For the purpose of the test:
EDIT: I just tested by dropping my gist inside your demo 'site/pages'. Bad behavior is as expected ;-).
@le_top
Ok, i just updated the 7.0beta, due to fix another issue - i suggest to use always the latest version, won't backport any fix to 6.x (and i'd prefer to have new issues reported to git, consequently;-). I tried your gist in the demo's environment with yii 1.16 and i can see the issue. I'm afraid there's nothing nlsclientscript could do with it, the issue is not related about to prevent re-loading some already loaded scripts, but related how Yii's grid/jQuery handles the grid update. Exactly the same happens there with or without using nlsclientscript.
A trivial workaround i would apply for that specific issue is, set 'htmlOptions'=>array('onclick'=>'$("#mygridid").yiiGridView("update")') for the CJuiButton instead of 'onclick' as it is in the gist. It fixes the case.
Fix for CJuiButton - which is just a "simple" example
Thanks for having a look. With my post I am mainly sharing a solution and hoping for some "idea" to integrate something in NLSClientScript.
CJuiButton is quite easy as an example and your susggestion does not make the button Jquery-ui'fy itself. It is more complex with jquery-ui dropdowns, date filter fields, ... .
One of the options that could be implemented in NLSClientScript is that it automatically applies the 'scripts' on the page at least only once at the end of each ajax call.
In other words, the scripts ('') that were already "added" during the ajax call are not added again, and the other ones are "executed"/added/. Anyway this is what I do with the code I add for 'afterAjaxUpdate' .
So if you do not see another solution, "we" just have to apply what I explained in my comment.
@le_top
Well, the first versions of NLSClientScript filtered the received html data (removed the script tags already recent, looking at its "src"). This is similar to your suggestion, just now it should be applied to script tags with no src, considering their content. There were several issues with that technique, therefore i switched to a more clean approach from version 6. Anyway i will think about some general solution but this problem seems to be hard.
Cache-control: no-transform is required!
I just spent a long time debugging a particular case.
To make a long story short, "Cache-control: no-transform" is required and this can be set in the extension by adding the following code:
private static $headerSet=false; public function registerCoreScript($name) { if(!self::$headerSet) { self::$headerSet=true; header('Cache-Control: no-transform',false); } return parent::registerCoreScript($name); } public function registerScriptFile($url,$position=null,array $htmlOptions=array()) { if(!self::$headerSet) { self::$headerSet=true; header('Cache-Control: no-transform',false); } return parent::registerScriptFile($url,$position,$htmlOptions); }
What went wrong?
Some proxy (probably the antivirus) of the end-user replaced the 'script' and 'link' tags with the actual content of the URLs that it cached.
As a result, nor jQuery nor NLSClientScript can identify the duplicates and 'jQuery' as well as the other code was loaded more than once.
This was never observed earlier as all sites use 'https' preventing proxies from modifying the content. However this is a new setup without 'https' available.
I determined that 'no-transform' could do the trick and it does. It tells the proxy that it should not change the content - and it respects that.
Note:
When calling 'header' elsewhere without setting the second parameter to false, potentially removes this directive from the response, so make sure that you include 'no-transform' in the Cache-Control directive when you need it.
blank page
hi team, when i m running this extension , i m getting white blank page without any error?
Avoiding ajax timestamp
Hi
I've ran in a few other issues:
a. The timestamp added by jQuery/ajax at the end of the URL breaks the use of the navigator's cache.
b. [More annoying]: the scripts are loaded "asynchronously" and the order of execution is not guaranteed - not even with regards to the embedded script.
Solution for a:
$this->registerScript('fixDuplicateResources', ';$.ajaxSetup({cache:true});'. // Avoid appending "_" to script file requests. ';(function($){var ieVer=navigator.userAgent.match(...' , CClientScript::POS_HEAD);
Workaround for b:
static private $D3id=0; public function registerD3Script($id,$script,$position=null,array $htmlOptions=array()) { self::$D3id++; $sid="d3_".self::$D3id; $js="var {$sid}=function(){if(typeof(d3)==='undefined'){window.setTimeout({$sid},5);}else{{$script}};};{$sid}();"; $cs=Yii::app()->clientScript; $cs->registerScript($id,$js,$position,$htmlOptions); }
So basically I replace the call to 'registerScript' by 'registerD3Script'.
This adds wrapper aroud the code which checks if D3 is loaded and if not it continues waiting for it.
For b, a better workaround/solution would consist of:
This all may explain some other issues I experienced in the past...
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.