I am updating some legacy code to support CKEditor up from FCKEditor, in classic asp. I am not a classic asp designer by trade so I am flying by the seat of my pants here. We previously used Javascriptspellcheck to to the spell checking. The problem I am having relates to this old code:
function doSpellCheck() {
var oSpell = new JavaScriptSpellCheck();
oSpell.callBack = function() {
oEditor.SetHTML($('POST_MESSAGE').value);
}
oEditor.UpdateLinkedField();
oSpell.spellCheckWindow('POST_MESSAGE');
}
oEditor is an instance of FCKEditor defined in a fckeditor_oncomplete() function. The new code I am trying to use is as follows:
function doSpellCheck() {
oSpellEditor = CKEDITOR.instances['POST_MESSAGE'].getData();
var oSpell = new JavaScriptSpellCheck();
oSpell.callBack = function() {
CKEDITOR.instances['POST_MESSAGE'].Setdata(oSpellEditor);
}
oSpell.spellCheckWindow('POST_MESSAGE');
}
The problem I seem to be facing is that JavaScriptSpellCheck(); needs the textarea id of the ckeditor instance. I attempted to follow the directions in This Post and nemisj's answer but I am having trouble with the code. I am not really understanding the DOM or how to manipulate it in this case. I know that this is not asp, to create the ckeditor instance I am using a custom asp sub to create it, but this is the area that I am having trouble with.
*EDIT: Found the answer. Where I am creating new CKEditor I needed to add text area attributes like so:
Set pageEditorTop = New CKEditor
' Change default textarea attributes
set textareaAttributes = CreateObject("Scripting.Dictionary")
textareaAttributes.Add "id", "POST_MESSAGE"
Set pageEditorTop.textareaAttributes = textareaAttributes
That code that you are trying to use doesn't make sense.
This is a straight port of the original code to CKEditor:
function doSpellCheck() {
var oEditor = CKEDITOR.instances['POST_MESSAGE'];
var oSpell = new JavaScriptSpellCheck();
oSpell.callBack = function() {
oEditor.setData($('POST_MESSAGE').value);
}
oEditor.updateElement();
oSpell.spellCheckWindow('POST_MESSAGE');
}
Related
Ok so i am not looking for an example more of help with an approach i am primarily a java developer so please excuse (and correct) the terminology if it need be. This is also why i need help as i am still early on into my journey into angular.
So i am using angular 5, along with ui-router. I am trying to design a three tabbed page [view, html, css] where the html and css will be text areas where a user will enter said thing, then , the view will be the rendering of that. There will be data (can be fetched prior to or at the time of rendering the view) that will bind to that html. The user will basically be putting in angular templates.
I have been reading this example but not sure if that is the proper approach.
this article had the solution
https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e
basically it looks like this
#ViewChild("ancc", { read: ViewContainerRef }) container;
#Input() property:Property = new Property();
constructor(private resolver: ComponentFactoryResolver,private _compiler: Compiler){
console.log("hit layout constructor");
}
view(){
// create the template
const template = '<span>generated on the fly: {{property.label}}</span>';
//clear out the old instance
this.container.clear();
const tmpCmp = Component({template: template})(class {
});
const tmpModule = NgModule({declarations: [tmpCmp]})(class {
});
this._compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
//attach the component to the view
const cmpRef = this.container.createComponent(f);
//bind the data
cmpRef.instance.property = this.property;
})
}
hope this helps someone!
Well, I've been reading the documentation and I believe that I'm calling functions and passing parameters correctly, but for the life of me I can't get this simple UI code to work.
I'm generating a UI for a Spreadsheet using the following code:
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
// Absolute panel for setting specific locations for elements
var panel = gui.createAbsolutePanel();
// Equipment ID#s Label
var equipmentIDLabel = gui.createLabel("Equipment ID#s");
equipmentIDLabel.setHorizontalAlignment(UiApp.HorizontalAlignment.CENTER);
equipmentIDLabel.setSize("20px", "125px");
equipmentIDLabel.setStyleAttributes({background: "SteelBlue", color: "white"});
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
gui.add(panel);
return gui;
}
function getUIdata(eventInfo) {
// I know how to get the data from each element based on ID
}
It generates the Absolute Panel correctly when checkOut() is called, but the EquipmentIDLabel is never added to the panel. I am basing the code on the simplistic design I created in the GUI builder (that will be deprecated in a few days, which is why I am writing the code so that I can change it later):
So what exactly is going wrong here? If I can figure out how to add one element, I can infer the rest by looking at the docs. I've never been any good at GUI development!
You could maybe use grid as an interesting alternative... here is an example :
// define styles
var labelStyle = {background: "SteelBlue", color: "white",'textAlign':'center','line-height':'20px','vertical-align':'middle','font-family':"Arial, sans-serif",'fontSize':'10pt'};// define a common label style
var fieldStyle = {background: "white", color: "SteelBlue",'font-family':"Courrier, serif",'fontSize':'11pt'};// define a common label style
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
var panel = gui.createAbsolutePanel().setStyleAttribute('padding','10px');
var grid = gui.createGrid(4,2).setWidth('300').setCellPadding(10);//define grid size in number of row & cols
var equipmentID = ['equipmentIDLabel','equipmentIDLabel1','equipmentIDLabel2','equipmentIDLabel3'];// define labels in an array of strings
for(var n=0 ;n<equipmentID.length ; n++){;// iterate
var equipmentIDLabel = gui.createLabel(equipmentID[n]).setWidth('125').setStyleAttributes(labelStyle);
var equipmentIDField = gui.createTextBox().setText('Enter value here').setName(equipmentID[n]).setSize("125", "20").setStyleAttributes(fieldStyle);
grid.setWidget(n,0,equipmentIDLabel).setWidget(n,1,equipmentIDField);
}
gui.add(panel.add(grid));
return gui;
}
It looks like the absolute panel offset method is a little capricious and take control of your positioning, in my tests I have been able to position panels that are visible in the following way:
panel.add(equipmentIDLabel);
panel.add(equipmentIDField,150,0);
panel.add(otherLabel);
panel.add(otherField, 150, 20);
Try it out with trial and error, you may get the UI you need, if not I would move to an alternate layout, verticalPanel is a little better behaved and of course you can use forms as well.
Another small bug is that you inverted the length and hight in equipmentIDLabel.setSize("20px", "125px");
Let me know if I can be of more assitance
The specific problem in your code is the following line :
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
Simply change it to : panel.add(equipmentIDLabel);
..and you will see the field (at position 0,0).
As patt0 observes, you can then add OTHER components and use positioning. It seems to be a limitation of adding the first field to an absolutePanel.
Of course, the Google Script gui is now deprecated (since December 2014) but I was interested to try your code and see that it still basically executes (as at Feb 2016).
var currentDialog = CKEDITOR.dialog.getCurrent();
currentDialog._.editor.insertHtml("<customTag myAttr='var'></customTag>");
Throws an error, TypeError: Cannot read property 'isBlock' of undefined
If I try .insertHtml("<span>hello</span>") it works just fine.
How can I change ckeditor to allow me to specify my own custom html tags via .insertHtml()? I'd love to just change it to be something like <span class='custom'... or something like that, but I'm having to deal with legacy CMS articles. Using latest ckeditor. Thanks.
You need to modify CKEDITOR.dtd object so editor will know this tag and correctly parse HTML and process DOM:
CKEDITOR.dtd.customtag = { em:1 }; // List of tag names it can contain.
CKEDITOR.dtd.$block.customtag = 1; // Choose $block or $inline.
CKEDITOR.dtd.body.customtag = 1; // Body may contain customtag.
You need to allow for this tag and its styles/attrs/classes in Advanced Content Filter:
editor.filter.allow( 'customtag[myattr]', 'myfeature' );
Unfortunately, due to some caching, in certain situations you cannot modify DTD object after CKEditor is loaded - you need to modify it when it is created. So to do that:
Clone the CKEditor repository or CKEditor presets repository.
Modify core/dtd.js code.
And build your minified package following instructions in README.md - the only requirements are Java (sorry - Google Closure Compiler :P) and Bash.
PS. That error should not be thrown when unknown element is inserted, so I reported http://dev.ckeditor.com/ticket/10339 and to solve this inconvenience http://dev.ckeditor.com/ticket/10340.
I worked around this issue with a combination of createFromHtml() and insertElement()
CKEDITOR.replace('summary', { ... });
var editor = CKEDITOR.instances.summary;
editor.on('key', function(ev) {
if (ev.data.keyCode == 9) { // TAB
var tabHtml = '<span style="white-space:pre"> </span>';
var tabElement = CKEDITOR.dom.element.createFromHtml(tabHtml, editor.document);
editor.insertElement(tabElement);
}
}
As far as I can tell, Backbone.js view represents DOM element. I take it from existing DOM or create it on the fly in el attribute.
In my case, I want to take it from server with AJAX request because I'm using Django templates and don't want to rewrite everything to JavaScript templates.
So I define el function that performs AJAX request.
el: function() {
model.fetch().success(function(response) {
return response.template
})
}
Of course, it does NOT work because AJAX request is executed asynchronous.
This means that I don't have el attribute and events does NOT work neither. Can I fix it?
Maybe the Backbone.js framework isn't the right tool for my needs? The reason I want to use that was to have some structure for the code.
P.S. I'm new to Backbone.js.
Do your ajax request from another view, or directly after the page load using jquery directly, and after you've downloaded your template, THEN instantiate your backbone view class with the proper id/el or whatever (depending on where you stored your ajax fetched template). Depending on your use-case, this may or may not be a sensible approach.
Another, perhaps more typical approach, would be to set up your view with some placeholder element (saying "loading" or whatever), then fire off the ajax, and after the updated template has been retrieved, then update your view accordingly (replace the placeholder with the actual template you requested).
When/if you update your view with new/other DOM elements, you need to call the view's delegateEvents method to rebind your events to the new elements, see:
http://backbonejs.org/#View-delegateEvents
I came across a similar requirement. In my instance, I was running asp.net and wanted to pull my templates from user controls. The first thing I would recommend is looking into Marionette because it will save you from writing a lot of boiler plate code in Backbone. The next step is to override how your templates are loaded. In this case I created a function that uses Ajax to retrieve the HTML from the server. I found an example of this function where they were using it to pull down html pages so I did a little modification so I can make MVC type requests. I can't remember where I found the idea from; otherwise, I would give the link here.
function JackTemplateLoader(params) {
if (typeof params === 'undefined') params = {};
var TEMPLATE_DIR = params.dir || '';
var file_cache = {};
function get_filename(name) {
if (name.indexOf('-') > -1) name = name.substring(0, name.indexOf('-'));
return TEMPLATE_DIR + name;
}
this.get_template = function (name) {
var template;
var file = get_filename(name);
var file_content;
var result;
if (!(file_content = file_cache[name])) {
$.ajax({
url: file,
async: false,
success: function (data) {
file_content = data; // wrap top-level templates for selection
file_cache[name] = file_content;
}
});
}
//return file_content.find('#' + name).html();
return file_content;
}
this.clear_cache = function () {
template_cache = {};
};
}
The third step would be to override Marionette's method to load templates. I did this in the app.addInitializer method. Here I am initializing my template loader and setting it's directory to a route handler. So when I want to load a template, I just set the template: "templatename" in my view and Backbone will load the template from api/ApplicationScreens/templatename. I am also overriding my template compiling to use Handlebars because ASP.net is not impressed with the <%= %> syntax.
app.JackTemplateLoader = new JackTemplateLoader({ dir: "/api/ApplicationScreens/", ext: '' });
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function (name) {
if (name == undefined) {
return "";
} else {
var template = app.JackTemplateLoader.get_template(name);
return template;
}
};
// compiling
Backbone.Marionette.TemplateCache.prototype.compileTemplate = function (rawTemplate) {
var compiled = Handlebars.compile(rawTemplate);
return compiled;
};
// rendering
Backbone.Marionette.Renderer.render = function (template, data) {
var template = Marionette.TemplateCache.get(template);
return template(data);
}
Hopefully this helps. I've been working on a large dynamic website and it is coming along very nicely. I am constantly being surprised by the overall functionality and flow of using Marionette and Backbone.js.
Hi I am trying to make some changes to our implementation of CKEDITOR 3.6.2
by removing all but 2 options in the link target type dropdown that appears in the link dialog's target tab.
I tried to achieve this using the API but I am getting an error in the minified core ckeditor.js file in the dialog() method on this line X=S.lang.dir; where S is the editor.
The .lang property of the editor instance is undefined when doing CKEDITOR.dialog(editor, 'link'), when viewing debugging the "editor" object I don't see a lang object anywhere, so I'm not sure why this is missing? I didn't work on our original implementation but as far as I know we have only added 2 plugins and not changed the ckeditor core.
Here is my code:
for (var i in CKEDITOR.instances) {
var editor = CKEDITOR.instances[i];
var dialogObj = CKEDITOR.dialog(editor, 'link');
var linkDialogTargetField = dialogObj.getContentElement('target', 'linkTargetType');
// API didn't seem to have a more efficient approach than clearing all and re-adding the one we want
linkDialogTargetField.clear();
linkDialogTargetField.add('notSet', '<not set>');
linkDialogTargetField.add('_blank', 'New Window (_blank)');
}
I have managed to make my change without using the API properly by doing the below:
CKEDITOR.on('dialogDefinition', function (ev) {
// Take the dialog name and its definition from the event
// data.
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
// Check if the definition is from the dialog we're
// interested on (the "Link" dialog).
if (dialogName == 'link') {
// Get a reference to the "Link target" tab.
var targetTab = dialogDefinition.getContents('target');
var targetField = targetTab.get('linkTargetType');
// removing everything except the 1st (none set) & 3rd (new window) options from the dropdown
targetField['items'].splice(1, 2);
targetField['items'].splice(2, 3); // the array is reduced by splice, so we have to splice from [2] onwards not from [4]
}
});
but I don't like this approach, does anyone have any ideas? or other ways to achieve the same result using the API?
Using second approach and overwritten the dropdown items instead of splicing.