How to use options when writing a jQuery plugin? - javascript

Here's my code ( http://jsfiddle.net/nB4Hg/ ):
JQuery:
// plugin code
(function($) {
$.fn.coloredDiv = function(options) {
// defaults
var options = {
'color' : 'black'
};
$(this).css('background', options.color);
}
})(jQuery);
// use the plugin
$(function() {
$("#foo").coloredDiv({ 'color' : 'red' });
$("#bar").coloredDiv();
});
CSS:
div { width: 100px; height: 100px; margin-bottom: 10px; }
HTML:
<div id="foo"></div>
<div id="bar"></div>
Now I am trying to learn how to use options when writing plugins. In my code what I'm trying to do is specify that the first div should be colored red and the second since it has no options should be the default black. However both are black. What am I doing wrong?

Your current approach is accepting a parameter named options, but then declaring another variable named options that "shadows" the parameter, and thus the passed-in options never get seen by the subsequent code.
Instead, you should declare your default options, then use $.extend to overwrite those defaults with the ones passed in by the user, where applicable:
$.fn.coloredDiv = function (userOptions) {
var options = $.extend({
color: "black"
}, userOptions);
// ...
};

Related

How to change styling of cells that has been edited in ag-Grid?

I want to mark cells who has been edited so the user can see which cells have been touched and altered. I know there is a cell flash option, but that just changes the background colors for a bit. What I want is a background color change when an edit has been done.
Cannot seem to find any specific documentation on accessing for example the html element or the styling of affected cell.
Anyone got any ideas?
You can use ColDef.onCellValueChanged to detect if something changes and update the cell style accordingly using GridApi.refreshCells()
const columnDefs = [{
headerName: "Athlete",
field: "athlete",
onCellValueChanged: this.markAsDirty
},...]
...
private markAsDirty(params: ICellRendererParams) {
params.colDef.cellClass = (p) =>
p.rowIndex.toString() === params.node.id ? "ag-cell-dirty" : "";
params.api.refreshCells({
columns: [params.column.getId()],
rowNodes: [params.node],
force: true // without this line, the cell style is not refreshed at the first time
});
}
In your css file
:host ::ng-deep .ag-cell-dirty {
background-color: rgba(255, 193, 7, 0.5) !important;
}
You may also want to use defaultColDef if you want this behavior applied to all columns
this.gridOptions = {
defaultColDef: {
editable: true,
onCellValueChanged: this.markAsDirty
},
};
Live Demo
I did this on a project I was working on.
There is a cellClass property that you can define in your column definitions (https://www.ag-grid.com/javascript-grid-cell-styles/) and it can take a callback function with params: CellClassParams.
So try doing:
cellClass: (params: CellClassParams) => {
// you need to have a handle on the original untouched data
// See if the original value does not equal the modified value in params
// For shortness, I will write pseudocode
if (originalValue !== modifiedValue) {
return 'ag-cell-was-modified';
}
}
If many columns are editable, you may want to use a re-usable function for cellClass for each column.
That should apply the class ag-cell-was-modified conditionally whether the cell was modified or not and in your style.scss or main stylesheet, you can add:
.ag-cell-was-modified {
background: red;
}
Of course, if you are using SASS, you can place this class definition in somewhere more appropriate.

Quill insertText producing TypeError: n.appendChild is not a function

I'm planning on implementing Quill into my website but unfortunately the insertText function is producing the following:
TypeError: n.appendChild is not a function shadow.ts:150
wrap shadow.ts:150
formatAt shadow.ts:70
format embed.ts:26
value cursor.js:25
formatAt embed.ts:30
formatAt container.ts:98
forEachAt linked-list.ts:114
formatAt container.ts:97
formatAt block.ts:42
value block.js:78
value cursor.js:35
value selection.js:110
value quill.js:157
a quill.js:437
value quill.js:149
value toolbar.js:101
I'm extending the text blot and attempting to use the documentation notes from here (copying the divider code) but the output ends up just printing true to the editor.
JS
const Text = Quill.import("blots/text");
class SchoolNameBlot extends Text {}
SchoolNameBlot.blotName = "tagName";
SchoolNameBlot.tagName = "NAME";
const toolbarOptions = [['bold', 'italic'], ['link', 'image', 'tagName']];
Quill.register(SchoolNameBlot);
const options = {
debug: 'info',
theme: 'snow',
modules: {
toolbar: toolbarOptions
}
}
const editor = new Quill("#msgText", options);
$("#tagName-Button").click(function() {
let range = editor.getSelection(true);
editor.insertText(range.index, "insertText");
});
HTML Element:
<div class="col-md-11">
<div id="msgText"></div>
</div>
Output
From what I can tell, I am using Quill correctly so I'm not to sure why this error is being produced. I'm using the CDN's provided on their page.
I'm extending the text blot and attempting to use the documentation
notes from here (copying the divider code) but the output ends up just
printing true to the editor.
In the link presented talking about how to clone Medium, there is no blot being created that extends blots/text. Divider is created using blots/block/embed. Basically, there are 3 types of blots that can be created:
Block Blot
Inline Blot
Embed Blot
To help you better understand what I'm talking about, I suggest you to read a little about Parchment and Blots.
Now, about your problem itself... As you can see from your example, you just created a blot, but didn't add any behavior to it, and you have set your created blot tag name to NAME. Of all existing tags in HTML, there is not one with the name <NAME>. Look:
https://www.w3schools.com/TAGs/
https://techspirited.com/all-html-tags-list-of-all-html-tags
The name you give to tagName will be the HTML tag used for the result, ie what your blot will represent. If you want to add an image, for example, you need to give tagName the value IMG. For a header title, you could use h1, h2, h3, and so on.
Looking at your code, and seeing the name "tag" written on it, it seems to me that you just want to add some stylized text. Would it be? If this is your case, look at the following example:
let Inline = Quill.import('blots/inline');
class SchoolNameBlot extends Inline {
// Overriding this method, in this particular case, is what
// causes the Delta returned as content by Quill to have
// the desired information.
static formats(domNode) {
if(domNode.classList.contains('my-style')){
return true;
}
else{
return super.formats(domNode);
}
}
formats() {
// Returns the formats list this class (this format).
let formats = super.formats();
// Inline has the domNode reference, which in this
// case represents the SPAN, result defined in tagName.
formats['tag-name'] = SchoolNameBlot.formats(this.domNode);
// In the code above, it is as if we are adding this new format.
return formats;
}
}
SchoolNameBlot.blotName = 'tag-name';
SchoolNameBlot.tagName = 'span';
SchoolNameBlot.className = 'my-style';
Quill.register(SchoolNameBlot);
$(document).ready(function () {
var toolbarOptions = {
container: [['bold', 'italic'], ['link', 'image', 'tag-name']],
handlers: {
'tag-name': function(){
this.quill.insertText(0, 'Hello', 'tag-name', true);
}
}
};
var quill = new Quill('#editor', {
theme: 'snow',
modules: {
'toolbar': toolbarOptions
}
});
});
.my-style{
background: rgb(254, 255, 171);
border-radius: 2px;
padding: 2px 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdn.quilljs.com/1.3.6/quill.min.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<p>Instructions:</p>
<ol>
<li>Press the invisible button (with no icon) next to the add image button.</li>
</ol>
<div id="editor">
</div>
To just style text, I do not advise creating a new Blot, as there is no need for something so complex. You could use Attributors. The previous code would look as:
const Parchment = Quill.import('parchment')
var config = {
scope: Parchment.Scope.INLINE,
whitelist: ['yellow', 'red', 'blue' , 'green']
};
var SchoolName = new Parchment.Attributor.Class('my-attributor', 'style' , config);
Quill.register(SchoolName);
$(document).ready(function () {
var toolbarOptions = {
container: [['bold', 'italic'], ['link', 'image', 'my-button'] , ['clean']] ,
handlers: {
'my-button': function () {
let range = this.quill.getSelection();
this.quill.insertText(range.index, 'Hello', 'my-attributor' , 'yellow');
}
}
};
var quill = new Quill('#editor', {
theme: 'snow',
modules: {
'toolbar': toolbarOptions
}
});
});
.style-yellow{
background: rgb(254, 255, 171);
border-radius: 2px;
padding: 2px 2px;
}
.style-red{
background: rgb(255, 171, 171);
border-radius: 2px;
padding: 2px 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdn.quilljs.com/1.3.6/quill.min.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<p>Instructions:</p>
<ol>
<li>Press the invisible button (with no icon) next to the add image button.</li>
</ol>
<div id="editor">
</div>
As a final tip, you can always get more information from Quill official website, as well as from its repositories. For even more information, examples and frequently asked questions (Quill FAQ), take a look here.

Plugin always only gets last instance, how to make it work for multiple elements

Here in the code i am trying to call this plugin for 2 div elements. But i am only able to see the effects in the last instance only. I see that all the elements coming in the each loop but when i use the window resize event i face this issue.
Can someonle please point out what the issue is? I am using the jqueryboilerplate template for this plugin
Here is the jquery plugin code. Just copy paste this in your html file and it will work.
// the semi-colon before function invocation is a safety net against concatenated
// scripts and/or other plugins which may not be closed properly.
;(function ( $, window, document, undefined ) {
"use strict";
// undefined is used here as the undefined global variable in ECMAScript 3 is
// mutable (ie. it can be changed by someone else). undefined isn't really being
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
// can no longer be modified.
// window and document are passed through as local variable rather than global
// as this (slightly) quickens the resolution process and can be more efficiently
// minified (especially when both are regularly referenced in your plugin).
// Create the defaults once
var pluginName = "vf_resizer",
defaults = {
propertyName: "value"
};
// The actual plugin constructor
function Plugin ( element, options ) {
this.element = element;
this.$element = $( element );
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.settings = $.extend( {}, defaults, options );
this._defaults = defaults;
this._name = pluginName;
this.init();
}
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
// Place initialization logic here
// You already have access to the DOM element and
// the options via the instance, e.g. this.element
// and this.settings
// you can add more functions like the one below and
// call them like so: this.yourOtherFunction(this.element, this.settings).
// console.log(this);
this.cycle();
},
cycle: function () {
// some logic
//console.log(this);
this.resize_calculator();
},
resize_calculator : function (){
self = this
$(window).resize(function() {
console.log(self);
self.$element.each(function (index, value){
console.log(value);
})
self.$element.children().each(function (index, value){
var $parent_selector = self.$element[0].getBoundingClientRect();
var factors = {};
var parent = {};
var current_dimensions = {};
factors.w = $(this).data('w-factor');
factors.h = $(this).data('h-factor');
factors.posx = $(this).data('posx-factor');
factors.posy = $(this).data('posy-factor');
parent.width = $parent_selector.width;
parent.height = $parent_selector.width/2.4;
current_dimensions.left = parent.width * factors.posx;
current_dimensions.top = parent.height * factors.posy;
current_dimensions.width = parent.width * factors.w;
current_dimensions.height = parent.height * factors.h;
self.resize_elements(this, current_dimensions, parent);
})
});
},
resize_elements : function (element, dimensions, parent){
// console.log(element);
self = this;
console.log(self);
self.$element.css({height: parent.height})
$( element ).css({
position : "absolute",
left : dimensions.left,
top: dimensions.top,
height: dimensions.height,
width: dimensions.width
});
}
});
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function ( options ) {
return this.each(function() {
//console.log($.data);
if ( !$.data( this, "plugin_" + pluginName ) ) {
// console.log(this);
$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
}
});
};
})( jQuery, window, document );
here is the html code.
<body>
<style>
.resizer{ position : relative; border: 1px solid black; width: 100%; height:300px;}
.deeplink1{position: absolute; top:0; left: 300px; border: 1px solid blue; width: 50%; height: 100px;}
.deeplink2{position: absolute; top:100px; left: 0; border: 1px solid blue; width: 50%; height: 100px;}
</style>
<script>
$(function() {
$("#one").vf_resizer();
$("#two").vf_resizer();
/* $(".resizer").vf_resizer();*/
});
</script>
<div id="one" class="resizer">
<div id="drag1" class="deeplink1" data-posx-factor='0.25' data-posy-factor='0' data-h-factor='0.33' data-w-factor='0.5'></div>
<div id="drag2" class="deeplink2" data-posx-factor='0' data-posy-factor='0.33' data-h-factor='0.33' data-w-factor='0.5'></div>
<!--<div id="drag3" class="deeplink" data-posx-factor='0.5' data-posy-factor='0.5' data-h-factor='0.1' data-w-factor='0.2'></div>-->
</div>
<div id="two" class="resizer">
<div id="drag3" class="deeplink1" data-posx-factor='0.25' data-posy-factor='0' data-h-factor='0.33' data-w-factor='0.5'></div>
<div id="drag4" class="deeplink2" data-posx-factor='0' data-posy-factor='0.33' data-h-factor='0.33' data-w-factor='0.5'></div>
<!--<div id="drag3" class="deeplink" data-posx-factor='0.5' data-posy-factor='0.5' data-h-factor='0.1' data-w-factor='0.2'></div>-->
</div>
</body>
UPDATE 1: This plugin is supposed to resize the elements in the div resizer according to the windows size. I have added their factors in the data attributes to pick them up from there.
UPDATE 2: Here is the JS fiddle http://jsfiddle.net/DelightedDoD/5he2n2rb/
Not sure but in the plugin i found a ; at a place where it does not seems to be:
current_dimensions.width = parent.width * factors.w;
current_dimensions.height = parent.height * factors.h;
; // <------this one should not have to be here.
self.resize_elements(this, current_dimensions, parent);
and i can see you don't have jquery reference on your html page.

Extend Select2 defaults

I create some default select2 behavior: each select is select2
$('select').not('.notSelect2').select2({
width: "150px",
allowClear: true,
placeholder: "EMPTY"
});
And now i want to change settings for some inputs:
function setSelect2Width(control, width) {
$.extend(true, control.select2.defaults, { width: width });
}
This code do nothing for select2. How to change default settings?
jsfiddle.net/JpvDt/389
The default values are exactly what the name suggests; values used when nothing else is specified. You are editing the default values after initializing, so the value will not be used for those selects (they will only be used for new selects without an width specified).
So instead do this:
function setSelect2Width(control, width) {
$(control).width(width).select2();
}

Mootools class - storing reference to document body in a class property

Greetings all! I'm trying to learn Mootools classes. I've made this class to add a div to the page.
var F = new Class({
Implements: [Options, Events],
options: {
container: document.body,
width: '250px',
background: '#ccc'
},
initialize: function(options) {
this.setOptions(options);
this.addDemoDiv();
},
addDemoDiv: function() {
var dDiv = new Element('div', {
'class': 'myClass',
html: 'Click me!',
styles: {
padding: '20px',
border: '1px solid #999',
width: this.options.width,
background: this.options.background
},
events: {
click: this.animate
}
});
dDiv.inject(this.options.container);
},
animate: function() {
alert('Hello world');
}
});
window.addEvent('domready', function() {
var item = new F();
});
It's supposed to allow the user to specify the container to inject the div into, with the document body being the default. When I do it like above, the code validates OK, but the script fails to add the div - Firebug and Chrome complain about the container being null or undefined.
I have to change dDiv.inject(this.options.container); to this
if (!this.container) {
dDiv.inject(document.body);
} else {
dDiv.inject(this.container);
}
to make it work.
Can any wise Mootools ninja tell me why inject works when I pass document.body in directly, but breaks when I try to pass it a reference to document.body supposedly stored in the class's container option? I've tried variations on document.body, like 'document.body' and $$('document.body') and $$(document.body).
My guess is that document.body is not available when your class code gets interpreted, this usually occurs when your script is placed in the <head> tags. Moving your script(s) to the bottom of the document (just before </body>) solves a lot and is good practise since your script(s) won't block HTML rendering anymore either.
It's also better to avoid putting a static default DOM references in your class as their availability is always questionable. You can keep options.container null and change your method to:
... code ...
dDiv.inject( this.options.container || document.body );
... code ...
So if this.options.container is not set (falsy) it will default to document.body, this way you can also keep your script(s) in the <head> if you really want to.

Categories