CKEditor New Instance always unloaded - javascript

I'm using CKEditor in my Angular app and have a view that reloads my CKEditor instance every time users access a new model.
I'm using the following JS to initialize the editor:
var initEditor = function() {
$('.js-editor-wrap').html("<textarea id='editor'></textarea>");
var editor = CKEDITOR.replace('editor', {});
editor.on('loaded', function() {
console.log('editor loaded');
});
editor.on('instanceReady', function() {
console.log('instance ready')
});
}
And the following to destroy the editor:
var destroyEditor = function() {
if (CKEDITOR.instances['editor']) {
CKEDITOR.instances['editor'].destroy(true);
$('#editor').off().remove();
}
}
The first editor initialization works just as expected, but subsequent initializations create an editor instance with a status of "unloaded" that never triggers the "loaded" or "instanceReady" events. I'm not seeing any errors in the console.
Any ideas what might be causing this?
This is definitely a similar issue to the following, but different enough that I think it warrants its own question: CKEditor instance already exists

After a LOT more digging and thanks to the jsfiddle from Jey Dwork, I figured out where the issue is here. My CKEditor config file adds a couple of plugins that referenced lang files that were improperly named. For some reason, when these plugins were included together they caused the editor to not fully load during a second initialization.
Removing the lang files and reference to them in the plugin definitions resolved the issue. It's too bad that there wasn't some error that was triggered around this. All's well that ends well though.

Related

How can I access the DOM of a <webview> in Electron?

I'm just getting started with Electron, with prior experience with node-webkit (nw.js).
In nw.js, I was able to create iframes and then access the DOM of said iframe in order to grab things like the title, favicon, &c. When I picked up Electron a few days ago to port my nw.js app to it, I saw advice to use webviews instead of iframes, simply because they were better. Now, the functionality I mentioned above was relatively easy to do in nw.js, but I don't know how to do it in Electron (and examples are slim to none). Can anyone help?
Also, I have back/forward buttons for my webview (and I intend on having more than one). I saw in the documentation that I could call functions for doing so on a webview, but nothing I have tried worked either (and, I haven't found examples of them being used in the wild).
I dunno who voted to close my question, but I'm glad it didn't go through. Other people have this question elsewhere online too. I also explained what I wanted to achieve, but w/e.
I ended up using ipc-message. The documentation could use more examples/explanations for the layperson, but hey, I figured it out. My code is here and here, but I will also post examples below should my code disappear for whatever reason.
This code is in aries.js, and this file is included in the main renderer page, which is index.html.
var ipc = require("ipc");
var webview = document.getElementsByClassName("tabs-pane active")[0];
webview.addEventListener("ipc-message", function (e) {
if (e.channel === "window-data") {
// console.log(e.args[0]);
$(".tab.active .tab-favicon").attr("src", e.args[0].favicon);
$(".tab.active .tab-title").html(e.args[0].title);
$("#url-bar").val(e.args[0].url);
$("#aries-titlebar h1").html("Aries | " + e.args[0].title);
}
// TODO
// Make this better...cancel out setTimeout?
var timer;
if (e.channel === "mouseover-href") {
// console.log(e.args[0]);
$(".linker").html(e.args[0]).stop().addClass("active");
clearTimeout(timer);
timer = setTimeout(function () {
$(".linker").stop().removeClass("active");
}, 1500);
}
});
This next bit of code is in browser.js, and this file gets injected into my <webview>.
var ipc = require("ipc");
document.addEventListener("mouseover", function (e) {
var hoveredEl = e.target;
if (hoveredEl.tagName !== "A") {
return;
}
ipc.sendToHost("mouseover-href", hoveredEl.href);
});
document.addEventListener("DOMContentLoaded", function () {
var data = {
"title": document.title,
"url": window.location.href,
// need to make my own version, can't rely on Google forever
// maybe have this URL fetcher hosted on hikar.io?
"favicon": "https://www.google.com/s2/favicons?domain=" + window.location.href
};
ipc.sendToHost("window-data", data);
});
I haven't found a reliable way to inject jQuery into <webview>s, and I probably shouldn't because the page I would be injecting might already have it (in case you're wondering why my main code is jQuery, but there's also regular JavaScript).
Besides guest to host IPC calls as NetOperatorWibby, it is also very useful to go from host to guest. The only way to do this at present is to use the <webview>.executeJavaScript(code, userGesture). This api is a bit crude but it works.
If you are working with a remote guest, like "extending" a third party web page, you can also utilize webview preload attribute which executes your custom script before any other scripts are run on the page. Just note that the preload api, for security reasons, will nuke any functions that are created in the root namespace of your custom JS file when your custom script finishes, however this custodial process will not nuke any objects you declare in the root. So if you want your custom functions to persist, bundle them into a singleton object and your custom APIs will persist after the page fully loads.
[update] Here is a simple example that I just finished writing: Electron-Webview-Host-to-Guest-RPC-Sample
This relates to previous answer (I am not allowed to comment): Important info regarding ipc module for users of Electron 1.x:
The ipc module was split into two separate modules:
ipcMain for the main process
ipcRenderer for the renderer process
So, the above examples need to be corrected, instead of
// Outdated - doesn't work in 1.x
var ipc = require("ipc");
use:
// In main process.
var ipcMain = require('electron').ipcMain
And:
// In renderer process.
var ipcRenderer = require('electron').ipcRenderer
See: http://electron.atom.io/blog/2015/11/17/electron-api-changes section on 'Splitting the ipc module'

Uncaught TypeError: $player.jPlayer is not a function

I'm helping a friend with his site and after updating his WordPress installation to address the recent security issue, the JPlayer plugin that was handling audio on his site stopped working.
Chrome's console shows the error in the title, but I don't know JS well enough to be able to debug it properly. I'm pretty sure that the plugin itself is loaded correctly, along with JQuery, in the page header. I checked it against the plugin's instructions and it all appears fine.
I've also updated the plugin itself to ensure that it's not some compatibility issue.
I did not build his site, nor am I familiar with this particular plugin at all, I'm just trying to see if it's an easy fix or if I have to restore a backup.
I assume it has something to do with how his web designer (they had a falling out) implemented it in the main.js file, but that's about as far as I've gotten.
Help?
Really condensing and removing parts of main.js, it looks like
var $player = false,
$(document).ready(function() {
if(!$player) {
$("#jPlayer").jPlayer({
ready: function() {
$player = $(this); // IT'S BEING SET HERE !
PlaylistPlay(playlistObject,trackIndex);
}
});
} else {
PlaylistPlay(playlistObject,trackIndex);
}
});
function PlaylistPlay(lePID,trackIndex) {
playTrack(trackIndex);
}
function playTrack(index) {
$player.jPlayer("setMedia", {mp3: trackObject.mp3,oga: trackObject.oga}).jPlayer("play");
}
If you look closely at that, you'll see that there is a distinct possibility that PlaylistPlay can be called without $player being set to $(this), it's actually almost a certaintity, which means that $player is false, and doing
false.jPlayer(...
doesn't really work, see the console output that confirms the variable is false
The plugin is not initializing correctly. On $(document).ready() it's trying to initialize the plugin and it's reporting a Flash error.
Here's the significant part of the code:
$("#jPlayer").jPlayer({
...
error: function(event) {
var out = "<p id=\"noSolution\">Sorry, you need an HTML5 capable browser or flash to be able to listen to music on this website.<br /> Reason: ";
switch(event.jPlayer.error.type) {
case $.jPlayer.error.FLASH:
out += "A problem with the Flash insertion on the page.";
break;
...
}
}
...
});
Digging a bit deeper, I can trace this back to the vimeo.jplayer in the specific code block:
_flash_volume: function(a) {
try {
this._getMovie().fl_volume(a)
} catch (b) {
this._flashError(b)
}
}
That function is throwing an exception because this._getMovie() does not have a property named fl_volume.
The error you actually see is a side-effect of this failure. You could try removing the line: this._flashError(b) from the above statement and see if the error can be safely ignored.

Update/Insert to Meteor collection being ignored by server

I have a collection called "Materials" defined on the client and server. In one template, I can insert and update correctly to Materials. On another template, I can insert and update but when I refresh the browser, the changes are lost.
The two views are called
view_materials (inserting/updating works)
view_orders (doesn't work)
Both templates have the materials collection binded to them like so:
//Bind viewOrders to Materials collection
Template.view_order.materials = function () {
return Materials.find();
};
// Bind materialsTemplate to Materials collection
Template.view_materials.materials = function () {
return Materials.find();
};
and both are using the function below to update.
var docid = Materials.findOne({material_number: newMaterial.material_number});
console.log(docid._id);
Materials.update({_id:docid._id},{$set: {material_qty: total}});
Please note that the ID printed out to the console matches perfectly. Like I mentioned, on view_orders it updates for a moment on the client but not in another browser window nor does it persist after being reloaded from the server. On view_materials it works perfectly. Any ideas?
I also deployed an example of the bug here:
http://upexmple.meteor.com/
and added the source to github:
https://github.com/stereochromatic/update_example
The relevant code can be found in client/views/view_materials/view_materials.js
and
client/views/view_orders/view_orders.js
To duplicate the error:
Click on inventory and under Raw Materials, type A for material number and -50 for quantity. You will see it get updated correctly. Now click on create release and under raw material type, select A and -50 for quantity. You will see the correct info get printed to the console and you may also see the changes on inventory but upon refresh those changes are gone.
- show quoted text -
You need to define your Meteor Collections outside of the client directory. I usually put mine into a /lib folder, but defining collections on just the client side can cause issues.
So just move
Materials = new Meteor.Collection("materials");
and
MaterialsLog = new Meteor.Collection("materialsLog");
into a folder outside of the client/server folders.
I can't reproduce the error. I've done as you said, but the changes do not disappear for me upon refresh. I can even close the tab and reopen it, and the changes are still there.
Finally figured this out...
I removed the autopublish package with
meteor remove autopublish
and then defined my permissions (and subscriptions) in /lib/Materials.js like so:
// Declare client materials collection
Materials = new Meteor.Collection("materials");
materials = Materials
if (Meteor.isClient) {
Meteor.subscribe('materials');
}
if (Meteor.isServer) {
Meteor.publish('materials', function() {
return materials.find();
});
materials.allow({
insert: function (document) {
return true;
},
update: function () {
return true;
},
remove: function () {
return false;
}
});
}
Thanks to everyone who helped out. I realize that for a production app this is best practice anyways so this needed really to be done at some point. I originally was going to wait until the end to remove autopublish, insecure and wrap collection in publish/subscribe, allow/deny rules but this issue helped expedite that work :)
Using your code above my with file structure:
Please take note that I remove the materials = Materials
client folder:
subscriber.js
Meteor.subscribe('materials');
server folder
publisher.js
Meteor.publish('materials', function() {
return Materials.find();
});
allow.js
Materials.allow({
insert: function (document) {
return true;
},
update: function () {
return true;
},
remove: function () {
return false;
}
});
}
collection folder. this is outside from the client and the server folders
collections.js
Materials = new Meteor.Collection("materials");
let me know if its works and though this very late at least people can see it

Backbone/jQuery mobile duplicate view

I've got some problems with my Backbone, RequireJS & jQuery mobile application.
When I use a form view 2 times the form submit event is fired twice.
Each new view is added to the body and the previous view will be removed. For that I use this code in my app.js file:
$(document).on("mobileinit", function () {
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$(document).on('pagehide', 'div[data-role="page"]', function (event, ui) {
$(event.currentTarget).remove();
});
})
Router.js
define([
'jquery',
'backbone',
'views/projects/ProjectsView',
'views/projects/AddProjectView'
], function($, Backbone, ProjectsView, AddProjectView) {
return Backbone.Router.extend({
routes: {
'addProject': 'addProject',
'editProject/:projectId': 'editProject',
'*actions': 'showProjects' // Default
},
addProject: function() {
new AddProjectView().render();
},
editProject: function(projectId) {
require([
"views/projects/EditProjectView",
"collections/ProjectsCollection",
"models/ProjectModel"
], function (EditProjectView, ProjectsCollection, ProjectModel) {
var projectsCollection = new ProjectsCollection();
projectsCollection.fetch();
var project = projectsCollection.get(projectId);
if (project) {
var view = new EditProjectView({model: project, projectsCollection: projectsCollection});
view.render();
}
});
},
showProjects: function() {
new ProjectsView().navigate();
}
});
});
I've uploaded my code to a directory on my website: http://rickdoorakkers.nl/np2
If you go through the following steps, you'll see the problem:
Add a project
Add a second project with a different name
Open a project by clicking on it and change the values and save it
As you can see the event of adding a project is launched and there's a project added instead of changed.
This same problem also occurs when you try to change 2 projects after each other. The first project is edited then.
Is there somebody who can tell me what I'm doing wrong?
Thanks!
Rido, your code is really hard to read for me because of the way it's mixing together a few things and not following any of the usual conventions for Backbone.
For your specific problem, I have a feeling the problem is that you binding both the Edit view and the New view to body (el: body), both respond to the event submit, and you are never clearly cleaning up the views, so I think that whenever you add a project and then edit it, the add view is still in memory, still bound to the submit event and still answering the call = new project with the new name, instead of editing.
It's 'easy' to fix in a dirty way, by adding a call to stopListening after adding, but the real problem is that you are binding to body, and mixing togethers the Backbone Router and manual hash control + other weird patterns, such as fetching the collection every 5 lines (you could just create one at the start of the App and always use it! here it's localstorage so it doesn't matter but if you ever move to a remote storage, you'll regret it... fetch() reset the collection and do a full reload!). May I suggest you maybe try to rewrite this without caring about jQuery mobile and just try to make it work with Backbone.Router + a single collection + not binding to body but instead, create the views on the fly and append them to body / remove when you are done? You'll see the bugs will be less weird and easier to track.

Google Closure Editor plugin

I'm trying to add behavior to a google closure editor, and I'm having trouble getting even an empty plugin to register.
(function() {
goog.provide('my.EscapeKeyPressedPlugin');
goog.require('goog.editor.Plugin');
my.EscapeKeyPressedPlugin = function() {
goog.editor.Plugin.call(this);
};
goog.inherits(my.EscapeKeyPressedPlugin, goog.editor.Plugin);
Rally.ui.richtext.EscapeKeyPressedPlugin.prototype.getTrogClassId = function() {
return 'EscapeKeyPressedPlugin';
};
})();
This is what I've conjured attempting to copy examples of built in plugins, but when I add this plugin to my editor, the editor becomes completely non-functional and no controls render. I don't get any js errors either, so I'm stuck.
What am I missing here?
The issue was namespacing. Something about how and when goog.provide or Ext.ns('') got hit caused the two to collide and destroy objects.
I moved to a new namespace and my example plugin works.

Categories

Resources