We're trying to use Stackoverflow's excellent WMD / Markdown editor (http://blog.stackoverflow.com/2009/01/updated-wmd-editor/, http://github.com/derobins/wmd/tree/master) on a Symfony project.
This works excellent on textareas without any AJAX involved. But when we have to include wmd.js first, and then later on user interaction (i.e. "click on link") have the textarea loaded via AJAX we utterly fail to make WMD work, Firebug is giving us
elem is null
addEvent()()wmd.js (Linie 110)
setupEvents()()wmd.js (Linie 1790)
init()()wmd.js (Linie 1970)
previewManager()()wmd.js (Linie 1987)
loadListener()()wmd.js (Linie 1763)
[Break on this error] if (elem.attachEvent) {
on loading the page (i.e. before textarea loading).
Symfony's AJAX Loader seems to eval() everything between tags. We tried including the whole script directly between those tags, we tried escaping this and that, but had no success with differnt errors coming up.
At this point we think we have to include the script in the normal page and after the AJAX call we have to initiate WMD manually - what functions do we have to call? Are we completely off track and need to use a different approach?
Thank you!
You can use my version. Simply put the constructor call, config values and the call to the start() method in the callback function that handles the results you get from the AJAX request. My version of mooWMD.
drobins fork of wmd on github is solving the AJAX issues as well.
I had this same issue and I initialize WMD once my textarea has been added to the page asynchronously.
Heres my code:
function loadTextEditor()
{
var instances = [];
if (!Attacklab || !Attacklab.wmd) {
alert("WMD hasn't finished loading!");
return;
}
/***** build the preview manager *****/
var textArea = document.getElementById('postcontent');
var previewPane = document.getElementById('postPreview');
var panes = {input:textArea, preview:previewPane, output:null};
var previewManager = new Attacklab.wmd.previewManager(panes);
/***** build the editor and tell it to refresh the preview after commands *****/
var editor = new Attacklab.wmd.editor(textArea,previewManager.refresh);
// save everything so we can destroy it all later
instances.push({ta:textarea, div:previewDiv, ed:editor, pm:previewManager});
}
Related
I am using the following directive to create a ckEditor view. There are other lines to the directive to save the data but these are not included as saving always works for me.
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = ck = CKEDITOR.replace(elm[0]);
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
}; }
};
}])
The window appears but almost always the first time around it is empty. Then after clicking the [SOURCE] button to show the source and clicking it again the window is populated with data.
I'm very sure that the ck.setData works as I tried a ck.getData and then logged the output to the console. However it seems like ck.setData does not make the data visible at the start.
Is there some way to force the view window contents to appear?
You can call render on the model at any time and it will simply do whatever you've told it to do. In your case, calling ngModel.$render() will grab the $modelValue and pass it to ck.setData(). Angular will automatically call $render whenever it needs to during its digest cycle (i.e. whenever it notices that the model has been updated). However, I have noticed that there are times when Angular doesn't update properly, especially in instances where the $modelValue is set prior to the directive being compiled.
So, you can simply call ngModel.$render() when your modal object is set. The only problem with that is you have to have access to the ngModel object to do that, which you don't have in your controller. My suggestion would be to do the following:
In your controller:
$scope.editRow = function (row, entityType) {
$scope.modal.data = row;
$scope.modal.visible = true;
...
...
// trigger event after $scope.modal is set
$scope.$emit('modalObjectSet', $scope.modal); //passing $scope.modal is optional
}
In your directive:
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
scope.$on('modalObjectSet', function(e, modalData){
// force a call to render
ngModel.$render();
});
Its not a particularly clean solution, but it should allow you to call $render whenever you need to. I hope that helps.
UPDATE: (after your update)
I wasn't aware that your controllers were nested. This can get really icky in Angular, but I'll try to provide a few possible solutions (given that I'm not able to see all your code and project layout). Scope events (as noted here) are specific to the nesting of the scope and only emit events to child scopes. Because of that, I would suggest trying one of the three following solutions (listed in order of my personal preference):
1) Reorganize your code to have a cleaner layout (less nesting of controllers) so that your scopes are direct decendants (rather than sibling controllers).
2) I'm going to assume that 1) wasn't possible. Next I would try to use the $scope.$broadcast() function. The specs for that are listed here as well. The difference between $emit and $broadcast is that $emit only sends event to child $scopes, while $broadcast will send events to both parent and child scopes.
3) Forget using $scope events in angular and just use generic javascript events (using a framework such as jQuery or even just roll your own as in the example here)
There's a fairly simple answer to the question. I checked the DOM and found out the data was getting loaded in fact all of the time. However it was not displaying in the Chrome browser. So the problem is more of a display issue with ckEditor. Strange solution seems to be to do a resize of the ckEditor window which then makes the text visible.
This is a strange issue with ckeditor when your ckeditor is hidden by default. Trying to show the editor has a 30% chance of the editor being uneditable and the editor data is cleared. If you are trying to hide/show your editor, use a css trick like position:absolute;left-9999px; to hide the editor and just return it back by css. This way, the ckeditor is not being removed in the DOM but is just positioned elsewhere.
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
Second way In controller ,when your query is fetch data from database then use th
is code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});
I know, that this thread is dead for a year, but I got the same problem and I found another (still ugly) solution to this problem:
instance.setData(html, function(){
instance.setData(html);
});
In MVC4 applications, I would like to update a panel using AJAX but using jQuery methods instead using AjaxExtensions from MVC.
But my problem is the updatePanelId.
I've seen several people use this to update it when has success:
success: function (response) {
var $target = $("#target");
var $newHtml = response;
$target.replaceWith($newHtml);
}
But when I do this, it forces me to use in every partial view that includes the id="target" at the root level of my razor view, and I guess that's not a good practice; I said this because I've realized when I use AjaxExtensions it doesn't happens, replace the update and it does not remove the panelId. But using jQuery it does.
Any idea to port the AjaxExtensions feature to jQuery?
You can use just:
$("#target").html(response); // it will just update content of the $("#target") container
Use jQuery's .load function. This will load the contents of the URL you specify into the target element. You can optionally specify a selector after the URL in load to only grab part of the target page.
$(function() {
$("#target").load("/MyURL");
});
JavaScript same origin policy applies to this.
I am trying to fetch data from a site by simulating events using CasperJS with phantomJS 1.7.0.
I am able to simulate normal click events and select events. But my code fails in following scenario:
When I click on button / anchor etc on remote page, the click on remote page initiates an AJAX call / JS call(depending on how that page is implemented by programmer.).
In case of JS call, my code works and I get changed data. But for clicks where is AJAX call is initiated, I do not get updated data.
For debugging, I tried to get the page source of the element container(before and after), but I see no change in code.
I tried to set wait time from 10 sec to 1 ms range, but that to does not reflect any changes in behavior.
Below is my piece of code for clicking. I am using an array of CSS Paths, which represents which element(s) to click.
/*Click on array of clickable elements using CSS Paths.*/
fn_click = function(){
casper.each(G_TAGS,function(casper, cssPath, count1)
{
casper.then ( function() {
casper.click(cssPath);
this.echo('DEBUG AFTER CLICKING -START HTML ');
//this.echo(this.getHTML("CONTAINER WHERE DETAILS CHANGE"));
this.echo('DEBUG AFTER CLICKING -START HTML');
casper.wait(5000, function()
{
casper.then(fn_getData);
}
);
});
});
};
UPDATE:
I tried to use remote-debug option from phantomJS, to debug above script.
It is not working. I am on windows. I will try to run remote debugging on Ubuntu as well.
Please help me. I would appreciate any help on this.
UPDATE:
Please have a look at following code as a sample.
https://gist.github.com/4441570
Content before click and after click are same.
I am clicking on sorting options provided under tag (votes / activity etc.).
I had the same problem today. I found this post, which put me in the direction of jQuery.
After some testing I found out that there was already a jQuery loaded on that webpage. (A pretty old version though)
Loading another jQuery on top of that broke any js calls made, so also the link that does an Ajax call.
To solve this I found http://api.jquery.com/jQuery.noConflict/
and I added the following to my code:
this.evaluate(function () { jq = $.noConflict(true) } );
Anything that was formerly assigned to $ will be restored that way. And the jQuery that you injected is now available under 'jq'.
Hope this helps you guys.
I have a task to change envelope icons on the main Activities view page (Work Place, My Work -> Activities) for every row in the grid, depending on the custom status of the row in crm 4.0. I need to do it using JavaScript. Does anybody know if there is a way to do that and where should the JavaScript code be placed? I am assuming that I need to intercept grid onLoad event, go through the grid, check the condition and flip the url of the icon. But I cannot figure out how to hook into that event...
Thanks very much!
I got several very useful advices and here is what I got so far.
1. I added SiteMap to load a custom page, instead of default one (/workplace/home_activities.aspx)
2. Here is the code of the custom page, placing onreadystatechange in the html was the only way I could get this function to run. Do not know why.
HTML>
HEAD>
TITLE>
script language="javascript" type="text/javascript">
function Run()
{
var objIframe = getIframe();
if(objIframe.readyState == "complete")
{
var docFrame = objIframe.contentWindow.document;
var grid = docFrame.getElementById("crmGrid");
var allRecords = grid.InnerGrid.AllRecords;
for(var i=0; i
function getIframe()
{
return document.getElementById("wraperActivitiesFrame");
}
/script>
/HEAD>
body >
iframe id="wraperActivitiesFrame" src="/workplace/home_activities.aspx" WIDTH="100%" HEIGHT="100%" onreadystatechange="Run()">
/HTML>
The issue I am having now is that the function does not run again when I try to page the grid. I have 2 pages of Activities; when the page loads for the first time - I have my alert boxes, but when I click on "page 2" arrow - nothing happens. Why??? What I am doing wrong?
You kinda can hook into that event. You create a "wrapper" HTML page that you load in CRM instead of the default activities grid via Sitemap. This wrapper contains a full-size IFrame in which you load the actual grid, and in the IFrame's onreadystatechange handler (for readyState == 4), you traverse the grid's DOM (jQuery might make this a little easier, but I haven't used jQuery much myself) and do whatever changes you need to do (that means the JavaScript goes within the wrapper HTML page). If you call this via setInterval and put a try-catch around it, this will even be safe against grid refreshes and browsing through the pages.
How to "bookmark" page or content fetched using AJAX?
It looks like it can be easy if we just add the details to the "anchor", and then, use the routing or even in PHP code or Ruby on Rails's route.rb, to catch that part, and then show the content or page accordingly? (show the whole page or partial content)
Then it can be very simple? It looks like that's how facebook does it. What are other good ways to do it?
Update: There is now the HTML5 History API (pushState, popState) which deprecates the HTML4 hashchange functionality. History.js provides cross-browser compatibility and an optional hashchange fallback for HTML4 browsers.
To store the history of a page, the most popular and full featured/supported way is using hashchanges. This means that say you go from yoursite/page.html#page1 to yoursite/page.html#page2 you can track that change, and because we are using hashes it can be picked up by bookmarks and back and forward buttons.
You can find a great way to bind to hash changes using the jQuery History project
http://www.balupton.com/projects/jquery-history
There is also a full featured AJAX extension for it, allowing you to easily integrate Ajax requests to your states/hashes to transform your website into a full featured Web 2.0 Application:
http://www.balupton.com/projects/jquery-ajaxy
They both provide great documentation on their demo pages to explain what is happening and what is going on.
Here is an example of using jQuery History (as taken from the demo site):
// Bind a handler for ALL hash/state changes
$.History.bind(function(state){
// Update the current element to indicate which state we are now on
$current.text('Our current state is: ['+state+']');
// Update the page"s title with our current state on the end
document.title = document_title + ' | ' + state;
});
// Bind a handler for state: apricots
$.History.bind('/apricots',function(state){
// Update Menu
updateMenu(state);
// Show apricots tab, hide the other tabs
$tabs.hide();
$apricots.stop(true,true).fadeIn(200);
});
And an example of jQuery Ajaxy (as taken from the demo site):
'page': {
selector: '.ajaxy-page',
matches: /^\/pages\/?/,
request: function(){
// Log what is happening
window.console.debug('$.Ajaxy.configure.Controllers.page.request', [this,arguments]);
// Adjust Menu
$menu.children('.active').removeClass('active');
// Hide Content
$content.stop(true,true).fadeOut(400);
// Return true
return true;
},
response: function(){
// Prepare
var Ajaxy = $.Ajaxy; var data = this.State.Response.data; var state = this.state;
// Log what is happening
window.console.debug('$.Ajaxy.configure.Controllers.page.response', [this,arguments], data, state);
// Adjust Menu
$menu.children(':has(a[href*="'+state+'"])').addClass('active').siblings('.active').removeClass('active');
// Show Content
var Action = this;
$content.html(data.content).fadeIn(400,function(){
Action.documentReady($content);
});
// Return true
return true;
And if you ever want to get the querystring params (so yoursite/page.html#page1?a.b=1&a.c=2) you can just use:
$.History.bind(function(state){
var params = state.queryStringToJSON(); // would give you back {a:{b:1,c:2}}
}
So check out those demo links to see them in action, and for all installation and usage details.
If you use jquery, you can do that in a simple manner. just use ajaxify plugin. it can manage bookmarking of ajax pages and many other things.
Check this, something may help you:
How to change URL from javascript: http://doet.habrahabr.ru/blog/15736/
How to pack the app state into url: http://habrahabr.ru/blogs/javascript/92505/
An approach description: http://habrahabr.ru/blogs/webstandards/92300/
Note: all articles are in Russian, so either Google Translate them, or just review the code and guess the details.
Take a look to the Single Page Interface Manifesto
I tried many packages. The jQuery History plugin seems to be most complete:
http://github.com/tkyk/jquery-history-plugin