Migrating OOP knowledge to JavaScript and jQuery

  • (2 Pages)
  • +
  • 1
  • 2

22 Replies - 1736 Views - Last Post: 25 September 2015 - 04:06 PM

#1 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 04:56 PM

I've been using OOP in C#. However, as an effort to learn more about Javascript and jQuery I'm in the process of taking a project I've been regularly contributing to and make it follow the OOP principals so we can implement unit tests in the future. I've created my class's constructor and have added some of the functions, but the browser keeps saying that the constructor function is not defined. Could you please look over what I have and point me in the right direction? I'd love to know what I'm overlooking.

<!DOCTYPE html>
<html lang="en">
  	<head>
    	<meta charset="utf-8">
    	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    	<meta name="viewport" content="width=device-width, initial-scale=1">
		<title>A tiny, opensource, Bootstrap WYSIWYG rich text editor</title>
		<link href="../bower_components/google-code-prettify/src/prettify.css" rel="stylesheet" />
		<link href="../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
		<link href="../bower_components/fontawesome/css/font-awesome.min.css" rel="stylesheet" />
		<link href="../css/style.css" rel="stylesheet" />
	</head>

	<body>
		<div class="container">
			<h1>Simple Editor with Toolbar</h1>
			<div class="btn-toolbar" data-role="editor-toolbar"
				data-target="#editor">
				<div class="btn-group">
					<a class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="Font Size"><i class="fa fa-text-height"></i>&nbsp;<b class="caret"></b></a>
					<ul class="dropdown-menu">
						<li><a data-edit="fontSize 5" class="fs-Five">Huge</a></li>
						<li><a data-edit="fontSize 3" class="fs-Three">Normal</a></li>
						<li><a data-edit="fontSize 1" class="fs-One">Small</a></li>
					</ul>
				</div>
				<div class="btn-group">
					<a class="btn btn-default" data-edit="bold" title="Bold (Ctrl/Cmd+B)/>/>"><i class="fa fa-bold"></i></a>
					<a class="btn btn-default" data-edit="italic" title="Italic (Ctrl/Cmd+I)"><i class="fa fa-italic"></i></a>
					<a class="btn btn-default" data-edit="strikethrough" title="Strikethrough"><i class="fa fa-strikethrough"></i></a>
					<a class="btn btn-default" data-edit="underline" title="Underline (Ctrl/Cmd+U)"><i class="fa fa-underline"></i></a>
				</div>
				<div class="btn-group">
					<a class="btn btn-default" data-edit="insertunorderedlist" title="Bullet list"><i class="fa fa-list-ul"></i></a>
					<a class="btn btn-default" data-edit="insertorderedlist" title="Number list"><i class="fa fa-list-ol"></i></a>
					<a class="btn btn-default" data-edit="outdent" title="Reduce indent (Shift+Tab)"><i class="fa fa-outdent"></i></a>
					<a class="btn btn-default" data-edit="indent" title="Indent (Tab)"><i class="fa fa-indent"></i></a>
				</div>
				<div class="btn-group">
					<a class="btn btn-default" data-edit="justifyleft" title="Align Left (Ctrl/Cmd+L)"><i class="fa fa-align-left"></i></a>
					<a class="btn btn-default" data-edit="justifycenter" title="Center (Ctrl/Cmd+E)"><i class="fa fa-align-center"></i></a>
					<a class="btn btn-default" data-edit="justifyright" title="Align Right (Ctrl/Cmd+R)"><i class="fa fa-align-right"></i></a>
					<a class="btn btn-default" data-edit="justifyfull" title="Justify (Ctrl/Cmd+J)"><i class="fa fa-align-justify"></i></a>
				</div>
				<div class="btn-group">
						<a class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="Hyperlink"><i class="fa fa-link"></i></a>
						<div class="dropdown-menu input-append">
							<input placeholder="URL" type="text" data-edit="createLink" />
							<button class="btn" type="button">Add</button>
						</div>
					</div>
					<div class="btn-group">
						<a class="btn btn-default" data-edit="unlink" title="Remove Hyperlink"><i class="fa fa-unlink"></i></a>
						<span class="btn btn-default" title="Insert picture (or just drag & drop)" id="pictureBtn"> <i class="fa fa-picture-o"></i>
							<input type="file" data-role="magic-overlay" data-target="#pictureBtn" data-edit="insertImage" />
						</span>
					</div>
				<div class="btn-group">
					<a class="btn btn-default" data-edit="undo" title="Undo (Ctrl/Cmd+Z)"><i class="fa fa-undo"></i></a>
					<a class="btn btn-default" data-edit="redo" title="Redo (Ctrl/Cmd+Y)"><i class="fa fa-repeat"></i></a>
				</div>
			</div>
			<div id="editor" class="lead" data-placeholder="This is a basic example with a simple toolbar."></div>
			<div id="editorPreview"></div>
			<p style="text-align: center;">
				<a class="btn btn-large btn-default jumbo" href="#!" onclick="$('#editorPreview').html($('#editor').html());">Submit</a>
			</p>
		</div>

		<script src="../bower_components/jquery/dist/jquery.min.js"></script>
		<script src="../bower_components/jquery.hotkeys/jquery.hotkeys.js"></script>
		<script src="../bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
		<script src="../bower_components/google-code-prettify/src/prettify.js"></script>
		<script src="../src/bootstrap-wysiwyg.js"></script>
		<script>
			var editor = Object.create(Wysiwyg());
			$('#editor').editor();
		</script>
	</body>
</html>



(function ($) {
	'use strict';

	/**
	 * 	Represenets an editor
	 *  @constructor
	 *  @param {object} userOptions - The default options selected by the user.
	 */
	function Wysiwyg (userOptions) {

		Wysiwyg.editor = this;
		Wysiwyg.wrapper = $(Wysiwyg.editor).parent();
		Wysiwyg.selectedRange = null;

		var defaults =
		{
			hotKeys:
			{
				'Ctrl+b meta+b': 'bold',
				'Ctrl+i meta+i': 'italic',
				'Ctrl+u meta+u': 'underline',
				'Ctrl+z': 'undo',
				'Ctrl+y meta+y meta+shift+z': 'redo',
				'Ctrl+l meta+l': 'justifyleft',
				'Ctrl+r meta+r': 'justifyright',
				'Ctrl+e meta+e': 'justifycenter',
				'Ctrl+j meta+j': 'justifyfull',
				'Shift+tab': 'outdent',
				'tab': 'indent'
			},
			toolbarSelector: '[data-role=editor-toolbar]',
			commandRole: 'edit',
			activeToolbarClass: 'btn-info',
			selectionMarker: 'edit-focus-marker',
			selectionColor: 'darkgrey',
			dragAndDropImages: true,
			keypressTimeout: 200,
			fileUploadError: function (reason, detail) { console.log("File upload error", reason, detail); }
		};

		Wysiwyg.options = $.extend(true, {}, defaults, userOptions);
		Wysiwyg.toolbarBtnSelector = 'a[data-' + Wysiwyg.options.commandRole + '],button[data-' + Wysiwyg.options.commandRole + '],input[type=button][data-' + Wysiwyg.options.commandRole + ']';
		Wysiwyg.prototype.bindHotkeys(Wysiwyg.options.hotKeys);

		// Support placeholder attribute on the DIV
		if ($(this).attr('placeholder') !== '')
		{
			$(this).addClass('placeholderText');
			$(this).html($(this).attr('placeholder'));
			$(this).bind('focus',function()
			{
				if ( $(this).attr('placeholder') !== '' && $(this).text() === $(this).attr('placeholder') )
				{
					$(this).removeClass('placeholderText');
					$(this).html('');
				}
			});
			$(this).bind('blur',function()
			{
				if ( $(this).attr('placeholder') !== '' && $(this).text() === '' )
				{
					$(this).addClass('placeholderText');
					$(this).html($(this).attr('placeholder'));
				}
			});
		}

		if (Wysiwyg.options.dragAndDropImages)
		{
			Wysiwyg.prototype.initFileDrops();
		}

		Wysiwyg.prototype.bindToolbar($(Wysiwyg.options.toolbarSelector), Wysiwyg.options);

		Wysiwyg.editor.attr('contenteditable', true)
			.on('mouseup keyup mouseout', function ()
			{
				Wysiwyg.prototype.saveSelection();
				Wysiwyg.prototype.updateToolbar();
			});
		$(window).bind('touchend', function (e)
		{
			var isInside = (Wysiwyg.editor.is(e.target) || Wysiwyg.editor.has(e.target).length > 0),
				currentRange = this.getCurrentRange(),
				clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
			if (!clear || isInside)
			{
				Wysiwyg.prototype.saveSelection();
				Wysiwyg.prototype.updateToolbar();
			}
		});
	}
})(window.jQuery);


This post has been edited by RandomlyKnighted: 14 September 2015 - 05:03 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Migrating OOP knowledge to JavaScript and jQuery

#2 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 05:30 PM

Which line causes the error?

Object.create() expects a prototype as first argument.

Quote

Could you please look over what I have and point me in the right direction?

That's a lot of code. Have you been building it and testing it in stages? If so (hopefully) then you should be able to narrow down the problem.
Was This Post Helpful? 0
  • +
  • -

#3 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 05:41 PM

I wasn't using Object.create() at first. When learning how to create a constructor I read that you generally use the new keyword. So in this case it would be

var editor = new Wysiwyg();
$('#editor').editor();



I have and it appears to be entirely to do with my constructor. I even removed all functions except for the constructor to verify that the issue was not somewhere else and I continued to get the same error. When I go through the code via debugging it will hit the line for the constructor and then skips everything inside of it. It then goes straight to the first method created after that.

This post has been edited by RandomlyKnighted: 14 September 2015 - 05:47 PM

Was This Post Helpful? 0
  • +
  • -

#4 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 06:11 PM

I have lots of confusion.
var editor = new Wysiwyg();
$('#editor').editor();

You have attached bootstrap-wysiwyg. If it's this one then this code initiates it:
$('#editor').wysiwyg();

But it seems most likely that you are using your own Wysiwyg object, so the bootstrap version is a red herring.

The editor in the first line is just an object, not a jQuery method. Have you somewhere included a jQuery method named editor()? If not then the second line doesn't make sense. It's not the the samed editor as on the first line. Edited: I might be wrong about this as I see that, for example, you use $.extend, and that you seem to be wrapping the jQuery version of wysiswyg. Still, some clarification would help.

Quote

When I go through the code via debugging it will hit the line for the constructor

Do you mean that it hits line 9? JS doesn't have a constructor method in the way that other languages do so I'm finding your use of the term a little unusual in JS terms.

Object.prototype.constructor:

Quote

Returns a reference to the Object function that created the instance's prototype.


In JS essentially all of the code inside a function can be considered as constructor code, although sometimes we intend this to mean, more specifically, executable statements within the function, rather than code that attaches properties and methods to this.

This post has been edited by andrewsw: 14 September 2015 - 06:18 PM

Was This Post Helpful? 0
  • +
  • -

#5 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 06:21 PM

You still haven't said what line causes the error?

it would be helpful if you could create a minimal, runnable, version of your code that demonstrates the problem.
Was This Post Helpful? 0
  • +
  • -

#6 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 06:30 PM

Actually, this is the correct link. Though the JS for that is what I started with. I wouldn't say that it's my own Wysiwyg object. It's the same code just reorganized to include a constructor and the scopes have changed a bit so that we have public and private variables.

Quote

Do you mean that it hits line 9? JS doesn't have a constructor method in the way that other languages do so I'm finding your use of the term a little unusual in JS terms.


Yes, it hits line 9 but never hits anything else inside that method.

Quote

You still haven't said what line causes the error?

The error occurs on this line:
var editor = new  Wysiwyg();



Quote

It would be helpful if you could create a minimal, runnable, version of your code that demonstrates the problem.

Any recommendations on how you would like this done? I do have my code on GitHub if that helps any.

This post has been edited by RandomlyKnighted: 14 September 2015 - 06:38 PM
Reason for edit:: Removed previous quote, just press REPLY

Was This Post Helpful? 0
  • +
  • -

#7 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 06:47 PM

Does the error disappear if you remove "use strict"? Try adding
Wysiwyg.prototype.constructor = Wysiwyg

Quote

Any recommendations on how you would like this done?

Remove all unnecessary code, leaving enough code to reproduce the problem. Note that I am not necessarily asking for this for myself.

The SSCCE

This post has been edited by andrewsw: 14 September 2015 - 06:56 PM

Was This Post Helpful? 0
  • +
  • -

#8 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 07:10 PM

I'm trimmed my code down to just this:

JS
(function ($) {

	function Wysiwyg (userOptions) {

		Wysiwyg.prototype.constructor = Wysiwyg;
	}
})(window.jQuery);



HTML

<!DOCTYPE html>
<html lang="en">
  	<head>
    	<meta charset="utf-8">
    	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    	<meta name="viewport" content="width=device-width, initial-scale=1">
		<title>A tiny, opensource, Bootstrap WYSIWYG rich text editor</title>
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
		<link href="style.css" rel="stylesheet" />
		<!--[if lt IE 9]>
			<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
			<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
		<![endif]-->
	</head>

	<body>
		<div class="container">
			<h1>Basic editor, no fancy bits.</h1>
			<div id="editor" class="lead" data-placeholder="This is a basic example with no toolbars."></div>
			<div id="editorPreview"></div>
			<p style="text-align: center;">
					<a class="btn btn-large btn-default jumbo"
						href="#!" onclick="$('#editorPreview').html($('#editor').html());">Submit</a>
				</p>
		</div>

		<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
		<script src="https://cdn.jsdelivr.net/jquery.hotkeys/0.2.0/jquery.hotkeys.min.js"></script>
		<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
		<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
		<script src="bootstrap-wysiwyg.js"></script>
		<script>
			var editor = new Wysiwyg();
			$('#editor').editor();
		</script>
	</body>
</html>



CSS

#editor {
	max-height: 250px;
	height: 250px;
	background-color: white;
	border-collapse: separate;
  	border: 1px solid rgb(204, 204, 204);
 	padding: 4px;
 	box-sizing: content-box;
 	-webkit-box-shadow: rgba(0, 0, 0, 0.0745098) 0 1px 1px 0 inset;
 	box-shadow: rgba(0, 0, 0, 0.0745098) 0 1px 1px 0 inset;
	border-top-right-radius: 3px; border-bottom-right-radius: 3px;
	border-bottom-left-radius: 3px; border-top-left-radius: 3px;
	overflow: scroll;
	outline: none;
}
#editor:focus{
    border-color:rgba(82, 168, 236, 0.8);
    outline:0;
    outline:thin dotted \9;
    -webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
    -moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
    box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
}



Even after trimming my JS down to the bare minimum I continue to get the error.
Was This Post Helpful? 0
  • +
  • -

#9 Dormilich   User is offline

  • 痛覚残留
  • member icon

Reputation: 4246
  • View blog
  • Posts: 13,461
  • Joined: 08-June 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 14 September 2015 - 11:14 PM

Quote

I've been using OOP in C#. However, as an effort to learn more about Javascript and jQuery I'm in the process of taking a project I've been regularly contributing to and make it follow the OOP principals so we can implement unit tests in the future.

A word of caution: While Java­Script is an OO language, it differs greatly from the class-based lanuages you know. Therefore the same OOP principles apply but their implementations do not /1/. I have found it easiest to work without having classes in mind (and therefore the whole constructor business could be left out) in favour of prototypal object creation methods like Object.create().



1 - e.g. Singleton Pattern in JS: var singleton = { foo: "bar" };
Was This Post Helpful? 1
  • +
  • -

#10 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 01:35 AM

I don't know what browser you are using but, with the reduced code, I get the error "Wysiwyg is undefined" in GC. This is what I was expecting because Wysiwyg is hidden away inside the IIFE.

So move the code inside the IIFE:
        <script>
        (function ($) {

            function Wysiwyg (userOptions) {

                Wysiwyg.prototype.constructor = Wysiwyg;
            }
            
            var editor = new Wysiwyg();
            $('#editor').editor();
            
        })(window.jQuery);


        </script>

Okay, so now I get the error "$(...) editor is not a function", as expected.

So now add back the shortest code necessary to define editor(). You will now either get a different error, or editor() works but you have reduced functionality. Keep re-inserting your code, testing it, fixing any errors as you progress.
Was This Post Helpful? 0
  • +
  • -

#11 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6831
  • View blog
  • Posts: 28,338
  • Joined: 12-December 12

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 01:46 AM

I echo Dormilich 's post. Your statement "I've created my class's constructor" and your usage of the term constructor as though it were a method (public ClassName()) concerned me. That is, that you might be taking your class-based code and trying to directly port it, line by line, to JS.

Hint: Avoid the word "class". JS doesn't have classes and the effort to not use this term will force you to think prototypically.

This post has been edited by andrewsw: 15 September 2015 - 01:46 AM

Was This Post Helpful? 0
  • +
  • -

#12 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 04:20 AM

I've been testing using Chrome. I just opened it in Firefox and got the same error but it pointed to editor.

Quote

Hint: Avoid the word "class". JS doesn't have classes and the effort to not use this term will force you to think prototypically.


Then why do people use the term in their tutorials if JS doesn't have it?
Was This Post Helpful? 0
  • +
  • -

#13 Dormilich   User is offline

  • 痛覚残留
  • member icon

Reputation: 4246
  • View blog
  • Posts: 13,461
  • Joined: 08-June 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 04:37 AM

View PostRandomlyKnighted, on 15 September 2015 - 01:20 PM, said:

Then why do people use the term in their tutorials if JS doesn't have it?

because they may
- feel more comfortable with classes
- think that the relatively common knowledge of classes helps readers to understand the programming principles
- donít know better /1/
- refer to the class keyword introduced in Java­Script2015
- Ö


/1/ - mind that most of the JS coders have a strong class-based background and are not familiar with prototypal (Lua) or functional (Scheme, Haskell) languages
Was This Post Helpful? 0
  • +
  • -

#14 RandomlyKnighted   User is offline

  • D.I.C Lover
  • member icon

Reputation: 119
  • View blog
  • Posts: 1,384
  • Joined: 14-January 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 04:52 AM

Quote

So move the code inside the IIFE


That code is not part of the library itself. It's how the developer will be using the library. Should it not stay outside the IIFE?
Was This Post Helpful? 0
  • +
  • -

#15 Dormilich   User is offline

  • 痛覚残留
  • member icon

Reputation: 4246
  • View blog
  • Posts: 13,461
  • Joined: 08-June 10

Re: Migrating OOP knowledge to JavaScript and jQuery

Posted 15 September 2015 - 05:04 AM

IIFEs allow you to decouple code from the global scope (to a certain degree), which is an invaluable tool while debugging.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2