javascript

development, document

 

 

 

 

Company / Organization: becke.ch
(I suggest to use here your domain name (or company name) which is registered and globally unique)

Scope: 0.0 (language=en;language=default;technology=js;organization=becke.ch;)
(ID and key/values of the scope this Module / Artifact / Component / Work-Product is valid for. The ID is as well part of the name of this Module / Artifact / Component / Work-Product i.e. is exposed towards outside of the Module / Artifact / Component / Work-Product. See as well: [1] and [2])

Version: 1.0.0
(Major[.Minor[.Patch[Build]]] – e.g. 2.3.5-0041 – the Major[.Minor] version is as well exposed towards outside of the Module / Artifact / Component / Work-Product. Different “.Patches” respective “.Build” versions are described in the same Major[.Minor] Module / Artifact / Component / Work-Product using substructures. In the current context the substructures would be reflected in sub-chapters. See as well: [1] and [2])

File-name: becke-ch--javascript--s0-0-v1-0.odt

 

Document Version History

Version

Date

Author

Description

1.0.0

15.11.2015

Raoul Becke

Initial version

 

 

Module / Artifact / Component / Work-Product Version History

Version

Date

Author

Requirements

Components Changed

1.0.0

15.11.2015

Raoul Becke

Create documentation on JavaScript with the following content: Directory & Naming Convention, NPM (Package Manager for Java-Script) (Installation, Setup, Directory Structure, Unit Testing, Intellij, Workflow, Publishing), YARN, Private registry/repository (Nexus Repository OSS), Separate File versus In-Line HTML, Data Structure (Types, Pointers, String, Function, DOM), Object Orientation (Inheritance), Functionality (Parameters, Recursive Function, Nested Function, Copy-Paste, Log, RegExp, Cursor Positioning, Contenteditable), Performance, JSON, TypeScript, AngularJS 1 (Download, Documentation, Java, View, Controller, Scope, Filter, Directive, JSON, TreeView, Call Function, Server Communication), Angular 2

This document

 

 

 

 

 

Table of Contents

1. Introduction

2. Directory & Naming Convention

3. NPM (Package Manager for Java-Script)

3.1. Node.js

3.2. Installing Node.js and updating npm

3.3. Setup

3.4. npm install

3.5. Directory Structure

3.6. Documentation

3.6.1. API Reference

3.6.1.1. Modify Home Text

3.6.1.2. Change method name (aliasing)

3.6.1.3. Intellij

3.6.1.4. NPM

3.6.2. README.md

3.6.2.1. Command Line & NPM

3.7. Unit Testing

3.7.1. Assertions

3.8. IntelliJ

3.8.1. Intellij Settings

3.9. Workflow

3.9.1. package.json

3.9.2. Create a new Node.js module

3.9.2.1. Intellij – option a) new (npm) module from existing sources

3.9.2.2. Intellij – option b) new (npm) module from static we

3.9.3. Publishing a package

3.9.3.1. Create an NPM account (optional)

3.9.3.2. Logging into npm (optional)

3.9.3.3. Logging into nexus – authentication

3.9.3.4. Publishing the package

3.9.3.4.1. ERROR

3.9.3.5. Deleting a published package (nexus repository)

3.10. Publishing Node.js Module To Ivy Repository

4. YARN

4.1. Getting started

4.1.1. Installation

4.1.2. Setup

4.1.3. Intellij Settings

4.2. Workflow

4.2.1. Create a new project

4.2.1.1. Intellij – new (npm) module

4.2.2. Publishing a package

4.2.2.1. Create an NPM account (optional)

4.2.2.2. Logging into npm (optional)

4.2.2.3. Publishing the package

4.2.2.3.1. ERROR

4.2.3. Upgrade packages

4.2.3.1. ERROR

5. Private registry/repository

5.1. CouchDB

5.1.1. Installation

5.1.1.1. Source

5.1.1.2. Binary

5.1.2. Setup

5.2. Nexus Repository OSS

5.2.1. Prerequisites and Conventions

5.2.2. Installation

5.2.3. Setup

5.2.4. Start

5.2.5. Proxying npm Registries

5.2.6. Private npm Registries

5.2.7. Grouping npm Registries

5.2.8. Security

5.2.8.1. Create User

5.2.9. Error

6. Separate File versus In-Line HTML

6.1. In-Line HTML

6.2. Separate File

7. Data structure

7.1. Types

7.1.1. typeof and instanceof (checking for array or function type)

7.2. Pointers

7.3. String

7.3.1. string.charAt(position)

7.3.2. Check if character is string

7.3.3. Empty string

7.3.4. indexOf (check for substring)

7.3.5. Escape Characters

7.3.6. Convert Octal to Hexadecimal

7.4. Function

7.4.1. Reflection – invoke function and parameters dynamically: call & apply

7.5. HTML DOM

7.5.1. nodeType Property

7.5.2. nodeName Property

8. Object Orientation (OO)

8.1. Inheritance

8.1.1. ERROR

9. Functionality

9.1. Function parameters

9.2. Recursive function and for loop

9.2.1. Error JavaScript - cannot set property of undefined

9.3. Nested function

9.3.1. Performance

9.4. Copy - Paste

9.5. console.log

9.5.1. Chrome

9.6. Regular Expression - RegExp

9.6.1. Unicode Support

9.6.2. Unicode Character 'EM SPACE' (U+2003) versus tabulator

9.6.3. Back-Reference

9.7. Cursor position & positioning

9.7.1. Retrieve entire text

9.7.2. Calculate Position of selected text

9.7.3. Retrieve the position (X,Y) of an HTML element

9.8. contenteditable

9.9. Creating a link without underscore

9.10. Error

10. Performance

11. JSON

11.1. Escape Characters

12. Typescript

12.1. ERROR

13. AngularJS 1

13.1. Downloading

13.2. Documentation (offline)

13.2.1. Error GET /angular.min.js" Error (404): "Not found"

13.3. Setup rich client (java)

13.4. Setup web client

13.5. Sample Hello World

13.6. Module

13.6.1. Error: $injector:unpr - Unknown Provider

13.7. View

13.7.1. Invoke function after view initialization / page load: ngInit & angular.element(document).ready

13.7.2. Key Event Listening

13.7.2.1. Cursor Key Listening

13.7.2.2. Watch for a key-combination

13.7.3. ng-repeat

13.7.3.1. ERROR: [ngRepeat:dupes]

13.8. Controller

13.8.1. Share data between controllers

13.9. Scope

13.9.1. Watch multiple $scope attributes

13.10. Filter

13.10.1. AngularJS : Insert HTML into view

13.11. Directive

13.11.1. Passing objects to directives via isolated scope

13.11.2. Acting on events

13.11.3. contenteditable

13.11.4. Errors

13.11.5. Error: $digest already in progress

13.12. JSON

13.12.1. json

13.12.2. angular.fromJson

13.12.3. How should I escape strings in JSON?

13.13. Tree View

13.14. Use button to navigate page as a link

13.15. Call angularjs function using jquery/javascript

13.16. Server communication

13.16.1. Multipart Upload & File Upload

13.16.2. Session

13.16.3. ERROR

14. Angular 2

14.1. Setup

14.1.1. Initial Setup

14.1.2. Project Setup

14.2. Development

14.2.1. app.component.ts

14.2.2. npm start

14.2.3. Typescript - tsconfig.json

14.2.4. boot.js

14.2.5. index.html

14.2.6. Import Libraries & Modules

14.2.6.1. Add TypeScript Definitions

14.2.6.2. Import JS Files/Libraries

14.2.6.3. Import NPM Modules

14.2.6.4. ERROR

14.2.7. Html Elements: Textarea, Button, Input, Binding

14.3. Build & Deploy

14.4. Typescript - tsconfig.json

14.5. package.json

14.6. Migration AngularJS1 -> AngularJS2

15. Landscape

16. References and glossary

16.1. References

16.2. Glossary (terms, abbreviations, acronyms)

A. Appendix

A.1. Appendix A1

 

 

Illustration Index

Illustration Index

Illustration 1: Illustration sample        6

 

 

Index of Tables

Index of Tables

Table 1: Table sample        6

Table 2: References        9

Table 3: Glossary        9

 

1. Introduction

This document captures all the issues and solutions I’ve come across so far during my JavaScript path.

 

2. Directory & Naming Convention

AngularJS: angularjs/controller/becke-ch--PRODUCT--sX-Y-Z-vA-B--USECASE--pl--client.js

Further context root sub-directories:

 

 

3. NPM (Package Manager for Java-Script)

https://ponyfoo.com/articles/choose-grunt-gulp-or-npm

https://www.npmjs.com/

npm makes it easy for JavaScript developers to share and reuse code, and it makes it easy to update the code that you're sharing.

 

3.1. Node.js

https://nodejs.org/en/

...

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.

http://openmymind.net/2012/2/3/Node-Require-and-Exports/

http://wesbos.com/javascript-modules/

In Node, things are only visible to other things in the same file. By things, I mean variables, functions, classes and class members.

 

the fundamental Node building block is called a module which maps directly to a file

 

To expose things we use module.exports and export everything we want:

becke-ch--regex--s0-0-v1--base--pl--lib.js:

function Regex(pattern, flags) {

    this.pattern = pattern;

    this.flags = flags;

    if (!pattern) {

        this.regex = new RegExp(pattern, flags);

    }

    this.regexGroupStructure = getRegexCompleteGroupingStructure(pattern);

    try {

        this.regex = new RegExp(this.regexGroupStructure[0][2], flags);

    } catch (e) {

        new RegExp(pattern, flags);

    }

}

 

function initialize() {

    if (!(typeof module === "undefined")) {

        module.exports = Regex;

    }

}

initialize();

Important to mention here is that I want to use the JavaScript as well outside of Node in plain old JavaScript environment and therefore I put the module-export into an initializer function which checks whether we are in a Node environment or a plain JavaScript environment!

 

require is used to load a module, which is why its return value is typically assigned to a variable:

var assert = require('assert');

var Regex = require('../src/becke-ch--regex--s0-0-v1--base--pl--lib');

describe('exec', function () {

    it('regex abcdef applied on abcdef', function () {

        var pattern = 'abcdef';

        var str = 'abcdef';

        var regex = new Regex(pattern);

        var result = regex.exec(str);

        var regexp = new RegExp(pattern);

        var resultp = regexp.exec(str);

        //console.log(result);

        assert.equal(resultp.length, result.length);

        assert.equal(resultp.input, result.input);

        for (var i = 0; i < resultp.length; i++) {

            assert.equal(resultp[i], result[i]);

        }

        assert.equal(1, result.index.length);

        assert.equal(0, result.index[0]);

    });

});

 

 

3.2. Installing Node.js and updating npm

https://docs.npmjs.com/getting-started/installing-node

https://nodejs.org/en/download/

Download to: /tool/node-v4.2.4-linux-x64.tar.gz

Extract to: /tool/node-v4.2.4-linux-x64

Installing Node.js

 

If you're using Mac or Windows, the best way to install Node.js is to use one of the installers from nodejs.org. If you're using Linux, you can use the installer, or you can check NodeSource's binary distributions to see whether or not there's a more recent version that works with your system.

 

Test: Run node -v. The version should be higher than v0.10.32.

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v1:/tool/node-v4.2.4-linux-x64/bin$ ./node -v

v4.2.4

https://github.com/nodejs/node-v0.x-archive/issues/3911

admin--s0-v1@hp-elitebook-840-g1--s0-v1:/tool/node-v4.2.4-linux-x64/bin$ sudo ln -s /tool/node-v4.2.4-linux-x64/bin/node /usr/bin/

Or alternatively:

root@hp-elitebook-840-g1--s0-v1:~# vi /etc/profile

...

export PATH=/tool/node-v4.2.4-linux-x64/bin:$PATH

...

Installing new version of Node.js

The same steps as mentioned above can be performed and the /etc/profile needs to be update to point to the new path (alternatively the following approach can be used to support multiple Node.js versions: https://nodecasts.io/update-node-js/ )

 

 

Updating npm

 

Node comes with npm installed so you should have a version of npm. However, npm gets updated more frequently than Node does, so you'll want to make sure it's the latest version.

 

 

Test: Run npm -v. The version should be higher than 2.1.8.

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v1:/tool/node-v4.2.4-linux-x64/bin$ ./npm -v

2.14.12

The current stable version of npm is 3.5.2

To upgrade, run: [sudo] npm install npm@latest -g

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v1:/tool/node-v4.2.4-linux-x64/bin$ ./npm install npm@latest -g

/tool/node-v4.2.4-linux-x64/bin/npm -> /tool/node-v4.2.4-linux-x64/lib/node_modules/npm/bin/npm-cli.js

npm@3.5.2 /tool/node-v4.2.4-linux-x64/lib/node_modules/npm

 

And then everything looks fine (but you first need to log-out-log-in or restart in order that the changes in profile are picked up!):

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v1:~$ node -v

v4.2.4

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v1:~$ npm -v

3.5.2

 

3.3. Setup

Once the local/custom registry is set up – see chapter 5.2 - point yarn to local/custom registry (https://github.com/yarnpkg/yarn/issues/606):

npm config set registry http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm config set registry http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group

 

Double check your local “.yarnrc” file to make sure everything worked fine:

vi .npmrc

...

registry=http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group

...

 

3.4. npm install

https://docs.npmjs.com/getting-started/installing-npm-packages-locally

There are two ways to install npm packages: locally or globally. You choose which kind of installation to use based on how you want to use the package.

 

If you want to depend on the package from your own module using something like Node.js' require, then you want to install locally, which is npm install's default behavior. On the other hand, if you want to use it as a command line tool, something like the grunt CLI, then you want to install it globally.

http://stackoverflow.com/questions/5926672/where-does-npm-install-packages

Global libraries

 

You can run npm list -g to see where global libraries are installed.

 

On Unix systems they are normally placed in /usr/local/lib/node or /usr/local/lib/node_modules when installed globally. If you set the NODE_PATH environment variable to this path, the modules can be found by node.

 

Windows XP - %USERPROFILE%\Application Data\npm\node_modules

Windows 7 - %AppData%\npm\node_modules

 

Non-global libraries

 

Non-global libraries are installed the node_modules sub folder in the folder you are currently in.

 

You can run npm list to see the installed non-global libraries for your current location.

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm list -g

/media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/lib

└─┬ npm@3.5.2

  ├── abbrev@1.0.7

  ├── ansi-regex@2.0.0

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm –help

npm@3.5.2 /media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/lib/node_modules/npm

...

 

 

3.5. Directory Structure

For now and for npm modules I go with a very simple directory structure: “src” and “test” as follows:

 

3.6. Documentation

3.6.1. API Reference

http://usejsdoc.org/

/**

 * This class is an extension of the standard {@link RegExp} class adding missing functionality.

 * For further descriptions see the corresponding overridden methods.

 * @param {string|RegExp} [pattern]

 * @param {string} [options]

 * @constructor

 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-regexp-regular-expression-objects

 */

function Regex(pattern, options) {

/**

 * Based on {@link RegExp#exec} but instead of simply getting "index" in the return which only tells the starting of

 * the first group (0 group) we are getting "index[0..n]" which tells us the starting index of each matching group.

 * @param {string} [str]

 * @return {Object} {string[0..n], index:number[0..n], input:string}

 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

 */

Regex.prototype.exec = function (str) {

 

3.6.1.1. Modify Home Text

http://stackoverflow.com/questions/30716438/default-home-text-and-content-for-jsdoc

  1. 1.Create directory “template” in module root folder (e.g. “/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib/template”) 

  2. 2.Copy directory “node_modules/jsdoc/templates/default” to “template” 

  3. 3.Edit “template/default/publish.js 

Replace:

    generate('Home',

        packages.concat(

            [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]

        ).concat(files),

    indexUrl);

With:

    generate('<a href="http://www--s0-v1.becke.ch/tool/becke-ch--regex--s0-v1/becke-ch--regex--s0-0-v1--homepage--pl--client/" style="font-family: Neuropol; font-size: 50pt">becke.ch</a>',

        packages.concat(

            [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]

        ).concat(files),

    indexUrl);

Pro: We now have the correct header, font and hyperlink!

Cons: The whole URL is as well put in the window title :-(

 
  1. 4.From directory “data/becke-ch--style--s0-v1/font” copy the fonts: neuropol-webfont.eot, neuropol-webfont.ttf and neuropol-webfont.woff to directory “template/default/static/fonts 

  2. 5.Edit “template/default/static/styles/jsdoc-default.css 

Insert on top the following font definition:

@font-face {

    font-family: 'Neuropol';

    src: url('../fonts/neuropol-webfont.eot?') format('eot'), url('../fonts/neuropol-webfont.woff') format('woff'), url('../fonts/neuropol-webfont.ttf') format('truetype');

}

 

3.6.1.2. Change method name (aliasing)

The following JSDoc:

/**

 * Simply invokes the inherited method {@linkcode RegExp[Symbol.search]}.

 * @param {string} str

 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@search

 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-regexp.prototype-@@search

 */

Regex.prototype[Symbol.search] = function (str) {

Will produce the following result:

 

This is a problem because [undefined] does not tell us which function we are looking at!

To fix this put an alias for the function name:

/**

 * Simply invokes the inherited method {@linkcode RegExp[Symbol.search]}.

 * @param {string} str

 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@search

 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-regexp.prototype-@@search

 * @alias Regex.search

 */

Regex.prototype[Symbol.search] = function (str) {

And now the result looks as follows:

 

At least we know which function we are looking at. The only cons here is that there is (static) written in front of the function name which is not correct.

 

3.6.1.3. Intellij

https://www.jetbrains.com/help/idea/2017.1/creating-documentation-comments.html

  1. 6.    Place the caret before the declaration. 

  2. 7.    Type the opening block comment /**, and press Enter. 

  3. 8.    Add meaningful description of parameters and return values. 

 

3.6.1.4. NPM

https://www.npmjs.com/package/jsdoc

package.json

  "scripts": {

    "build": "jsdoc src -d doc -R README.md"

  },

    "devDependencies": {

    ...

    "jsdoc": "latest"

  }

Installation:

npm install

Generate:

npm run build

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm run build

 

> becke-ch--regex--s0-0-v1--base--pl--lib@1.0.20 build /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib

> jsdoc src -d doc

 

3.6.2. README.md

https://gist.github.com/jxson/1784669#file-readme-md

3.6.2.1. Command Line & NPM

http://usejsdoc.org/about-including-readme.html

package.json

  "scripts": {

    "build": "jsdoc src -d doc -R README.md"

  },

    "devDependencies": {

    ...

    "jsdoc": "latest"

  }

 

 

3.7. Unit Testing

https://mochajs.org/

https://glebbahmutov.com/blog/unit-test-node-code-in-10-seconds/

https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha

 

  1. 9.Edit the current package.json file and add the following development dependency: 

{

  "name": "becke-ch--regex--s0-0-v1--base--pl--lib",

  "version": "1.0.0",

  "description": "Extension of JavaScript RegExp adding missing functionality",

  "keywords": ["Regular Expression", "RegExp", "Regex", "exec"],

  "main": "./src/becke-ch--regex--s0-0-v1--base--pl--lib.js",

  "repository": {

    "url": "file:///ws/tool/becke-ch--regex--s0-v1",

    "type": "git"

  },

  "author": "Raoul Becke <regex--s0-v1@becke.ch> (http://becke.ch/tool/becke-ch--regex--s0-v1/)",

  "license": "SEE LICENSE IN LICENSE",

  "publishConfig": {

    "registry": "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted/"

  },

  "files": [

    "./src"

  ],

  "devDependencies": {

    "mocha": "^3.2.0"

  }

}

  1. 10.run “yarn” (or “npm install”) to download and install the package 

Alternatively you can install the module from the command line:

npm install --save-dev mocha

  1. 11.Change into the test directory: “cd test” and run “../node_modules/mocha/bin/mocha becke-ch--regex--s0-0-v1--base--pl--lib--test.js” 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib/test$ ../node_modules/mocha/bin/mocha becke-ch--regex--s0-0-v1--base--pl--lib--test.js

 

 

  exec

    ✓ regex abcdef applied on abcdef

    ✓ regex abcdef applied on 00abcdef

  52 passing (18ms)

 

3.7.1. Assertions

Mocha allows you to use any assertion library you wish. Currently, we’re using Node.js’ built-in assert module:

var assert = require('assert');

var Regex = require('../src/becke-ch--regex--s0-0-v1--base--pl--lib');

describe('exec', function () {

    it('regex abcdef applied on abcdef', function () {

        var pattern = 'abcdef';

        var str = 'abcdef';

        var regex = new Regex(pattern);

        var result = regex.exec(str);

        var regexp = new RegExp(pattern);

        var resultp = regexp.exec(str);

        //console.log(result);

        assert.equal(resultp.length, result.length);

        assert.equal(resultp.input, result.input);

        for (var i = 0; i < resultp.length; i++) {

            assert.equal(resultp[i], result[i]);

        }

        assert.equal(1, result.index.length);

        assert.equal(0, result.index[0]);

    });

});

 

 

3.8. IntelliJ

After the steps above haven been performed and once NPM and Node.js are on the PATH, IntelliJ IDEA discovers them automatically and the user can go ahead creating a “Node.js and NPM” Project/Module - see IntelliJ Documentation.

 

3.8.1. Intellij Settings

in File | Settings | Languages & Frameworks | Node.js and NPM, press ellipsis button next to 'Node interpreter' field

in Node.js Interpreters dialog that opens, open 'Node Interpreter' dropdown, choose latest node interpreter  

 

3.9. Workflow

https://docs.npmjs.com/getting-started/creating-node-modules#  

3.9.1. package.json

https://docs.npmjs.com/files/package.json

name

The most important things in your package.json are the name and version fields. Those are actually required, and your package won't install without them. The name and version together form an identifier that is assumed to be completely unique.

Some rules:

    The name must be less than or equal to 214 characters. This includes the scope for scoped packages.

    The name can't start with a dot or an underscore.

    New packages must not have uppercase letters in the name.

    The name ends up being part of a URL, an argument on the command line, and a folder name. Therefore, the name can't contain any non-URL-safe characters.

A name can be optionally prefixed by a scope, e.g. @myorg/mypackage. See npm-scope for more detail.

Npm-scope, Scoped packages

All npm packages have a name. Some package names also have a scope. A scope follows the usual rules for package names (url-safe characters, no leading dots or underscores). When used in package names, preceded by an @-symbol and followed by a slash, e.g.

 @somescope/somepackagename

Installing scoped packages

Scoped packages are installed to a sub-folder of the regular installation folder, e.g. if your other packages are installed in node_modules/packagename, scoped modules will be in node_modules/@myorg/packagename.

 

npm install:

 npm install @myorg/mypackage

Or in package.json:

"dependencies": {

  "@myorg/mypackage": "^1.3.0"

}

 

Actually I prefer to have the organization as part of the name (becke-ch--regex--s0-0-v1--base--pl--lib) and not working with scoped packages because this is more portable when moving away from npm or simply working on javascript files!

 

 

description

Put a description in it. It's a string. This helps people discover your package, as it's listed in npm search.

 

keywords

Put keywords in it. It's an array of strings. This helps people discover your package as it's listed in npm search.

 

homepage

The url to the project homepage.

 

bugs

The url to your project's issue tracker and / or the email address to which issues should be reported.

{ "url" : "https://github.com/owner/project/issues"

, "email" : "project@hostname.com"

}

 

license

You should specify a license for your package so that people know how they are permitted to use it, and any restrictions you're placing on it.

https://spdx.org/licenses/

{ "license" : "(ISC OR GPL-3.0)" }

If you are using a license that hasn't been assigned an SPDX identifier, or if you are using a custom license, use a string value like this one:

{ "license" : "SEE LICENSE IN <filename>" }

Then include a file named <filename> at the top level of the package.

Finally, if you do not wish to grant others the right to use a private or unpublished package under any terms:

{ "license": "UNLICENSED"}

 

people fields: author, contributors

The "author" is one person. "contributors" is an array of people. A "person" is an object with a "name" field and optionally "url" and "email", like this:

{ "name" : "Barney Rubble"

, "email" : "b@rubble.com"

, "url" : "http://barnyrubble.tumblr.com/"

}

 

files

The "files" field is an array of files to include in your project.

You can also provide a ".npmignore" file in the root of your package or in subdirectories, which will keep files from being included, even if they would be picked up by the files array. The .npmignore file works just like a .gitignore.

Certain files are always included, regardless of settings:

    package.json

    README (and its variants)

    CHANGELOG (and its variants)

    LICENSE / LICENCE

 

repository

Specify the place where your code lives. This is helpful for people who want to contribute. If the git repo is on GitHub, then the npm docs command will be able to find you.

Do it like this:

"repository" :

  { "type" : "git"

  , "url" : "https://github.com/npm/npm.git"

  }

 

"repository" :

  { "type" : "svn"

  , "url" : "https://v8.googlecode.com/svn/trunk/"

  }

Private modules respective source code that should not (yet) be published public should point to the local code repository as follows:

  "repository": {"url":"file:///ws/tool/becke-ch--regex--s0-v1","type":"git"},

Once the module is published public a next step could be to publish as well the source code public.

http://stackoverflow.com/questions/18128863/should-node-modules-folder-be-included-in-the-git-repository

Imagine that you have just finished enterprise app and you will have to support it for 3-5 years. You definitely don't want to depend on someone's npm module which can tomorrow disappear and you can't update your app anymore.

 

Or you have your private modules which are not accessible from internet and you can't build your app on Internet. Or maybe you don't want to depend with your final build on npm service for some reasons.

 

You can find pros and cons in this Addy Osmani article (although it is about Bower, it is almost the same situation). And I will end with quote from Bower homepage and Addy's article:

 

    “If you aren’t authoring a package that is intended to be consumed by others (e.g., you’re building a web app), you should always check installed packages into source control.”

I would recommend against checking in node_modules because of packages like PhantomJS and node-sass for example, which install the appropriate binary for the current system.

 

This means that if one Dev runs npm install on Linux and checks in node_modules – it won't work for another Dev who clones the repo on Windows.

...

 

dependencies

Dependencies are specified in a simple object that maps a package name to a version range.

{ "dependencies" :

  { "foo" : "1.0.0 - 2.9999.9999"

  , "bar" : ">=1.0.2 <2.1.2"

  , "baz" : ">1.0.2 <=2.3.4"

  , "boo" : "2.0.1"

  , "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"

  , "asd" : "http://asdf.com/asdf.tar.gz"

  , "til" : "~1.2"

  , "elf" : "~1.2.3"

  , "two" : "2.x"

  , "thr" : "3.3.x"

  , "lat" : "latest"

  , "dyl" : "file:../dyl"

  }

}

 

URLs as Dependencies

You may specify a tarball URL in place of a version range.

 

devDependencies

If someone is planning on downloading and using your module in their program, then they probably don't want or need to download and build the external test or documentation framework that you use.

 

peerDependencies

In some cases, you want to express the compatibility of your package with a host tool or library, while not necessarily doing a require of this host.

 

bundledDependencies

Array of package names that will be bundled when publishing the package.

 

optionalDependencies

If a dependency can be used, but you would like npm to proceed if it cannot be found or fails to install, then you may put it in the optionalDependencies object.

 

engines

You can specify the version of node that your stuff works on:

{ "engines" : { "node" : ">=0.10.3 <0.12" } }

 

os

You can specify which operating systems your module will run on:

"os" : [ "darwin", "linux" ]

 

cpu

If your code only runs on certain cpu architectures, you can specify which ones.

"cpu" : [ "x64", "ia32" ]

 

preferGlobal

If your package is primarily a command-line application that should be installed globally, then set this value to true to provide a warning if it is installed locally.

 

private

If you set "private": true in your package.json, then npm will refuse to publish it.

 

publishConfig

This is a set of config values that will be used at publish-time. It's especially handy if you want to set the tag, registry or access, so that you can ensure that a given package is not tagged with "latest", published to the global public registry or that a scoped module is private by default.

Any config values can be overridden, but of course only "tag", "registry" and "access" probably matter for the purposes of publishing.

registry

    Default: https://registry.npmjs.org/

    Type: url

The base URL of the npm package registry.

 

Private modules respective modules that should not (yet) be published public I would point to the local repository as follows:

  "publishConfig" : {

    "registry" : "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted/"

  }

 

 

OPTIONAL

main

The main field is a module ID that is the primary entry point to your program.

 

bin

A lot of packages have one or more executable files that they'd like to install into the PATH.

 

man

Specify either a single file or an array of filenames to put in place for the man program to find.

 

directories

The CommonJS Packages spec details a few ways that you can indicate the structure of your package using a directories object.

 

scripts

The "scripts" property is a dictionary containing script commands that are run at various times in the lifecycle of your package.

 

config

A "config" object can be used to set configuration parameters used in package scripts that persist across upgrades.

 

...

 

3.9.2. Create a new Node.js module

https://docs.npmjs.com/getting-started/creating-node-modules

npm init

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm init

This utility will walk you through creating a package.json file.

It only covers the most common items, and tries to guess sensible defaults.

 

See `npm help json` for definitive documentation on these fields

and exactly what they do.

 

Use `npm install <pkg> --save` afterwards to install a package and

save it as a dependency in the package.json file.

 

Press ^C at any time to quit.

name: (becke-ch--regex--s0-0-v1--base--pl--lib)

version: (1.0.0)

description: Extension of JavaScript RegExp adding missing functionality

entry point: (index.js)

test command:

git repository:

keywords: Regular Expression, RegExp, Regex, exec

author: Raoul Becke <regex--s0-v1@becke.ch> (http://becke.ch/tool/becke-ch--regex--s0-v1/)

license: (ISC) SEE LICENSE IN LICENSE

About to write to /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v2--base--pl--lib/package.json:

{

  "name": "becke-ch--regex--s0-0-v1--base--pl--lib",

  "version": "1.0.0",

  "description": "Extension of JavaScript RegExp adding missing functionality",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [

    "Regular",

    "Expression",

    "RegExp",

    "Regex",

    "exec"

  ],

  "author": "Raoul Becke <regex--s0-v1@becke.ch> (http://becke.ch/tool/becke-ch--regex--s0-v1/)",

  "license": "SEE LICENSE IN LICENSE"

}

 

Is this ok? (yes) yes

 

Adapt & extend the missing properties:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ vi package.json

 

{

  "name": "becke-ch--regex--s0-0-v1--base--pl--lib",

  "version": "1.0.0",

  "description": "Extension of JavaScript RegExp adding missing functionality",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [

    "Regular",

    "Expression",

    "RegExp",

    "Regex",

    "exec"

  ],

  "repository": "file:///ws/tool/becke-ch--regex--s0-v1",

  "repository": {"url":"file:///ws/tool/becke-ch--regex--s0-v1","type":"git"},

  "author": "Raoul Becke <regex--s0-v1@becke.ch> (http://becke.ch/tool/becke-ch--regex--s0-v1/)",

  "license": "SEE LICENSE IN becke-ch—regex--s0-v1--license.txt"

  "publishConfig" : {

    "registry" : "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted/"

  }

}

 

3.9.2.1. Intellij – option a) new (npm) module from existing sources

Creating a new npm module from scratch is not well supported respective see https://intellij-support.jetbrains.com/hc/requests/907710 : “When going to "New Module", selecting "Node.js and NPM" I only have the choice "Node.js Express App" and when I choose that I get a lot of node-modules downloaded and "dependencies" that I don't need

Therefore there are 2 possibilities:

  1. 1.File → New Module → From Existing Sources … 

  2. 2.Select the directory where you invoked previously “yarn init” e.g. /ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib 

 

 
  1. 3.Select “Create module from existing sources” 

 
  1. 4.Source files for project have been found. Leave default which is all directories selected. 

 
  1. 5.No Frameworks detected. Click Finish. 

 

3.9.2.2. Intellij – option b) new (npm) module from static we

This is an alternative installation procedure which actually brings no additional benefit. There exists currently no option to create an empty/minimal npm module:

  1. 1.Select “Static Web 

  2. 2.Select “Static Web 

 
  1. 3.Enter module name: becke-ch--<element>--sX-Y-vZ--<UseCase>--pl--client|clientlib|server|serverlib|lib (e.g. becke-ch--regex--s0-0-v1--base--pl--lib) 

 
  1. 4.And finally go into this new empty directory and create a new npm-/yarn-module as described above 

 

3.9.3. Publishing a package

https://docs.npmjs.com/getting-started/publishing-npm-packages

3.9.3.1. Create an NPM account (optional)

This step is only required when publishing to central NPM repository:

Create an NPM Account: https://www.npmjs.com/signup

Create an NPM Account: https://www.npmjs.com/signup

Alternatively you can create a user with:

npm adduser

Alternatively you can create a user with:

npm adduser

Adding user to default repository:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm adduser

Username: becke-ch--npm--s0-v1

Password:

Email: (this IS public) npm--s0-v1@becke.ch

Logged in as becke-ch--npm--s0-v1 on http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group.

Adding user to private repository: http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted

npm adduser --registry=http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm adduser --registry=http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted

Username: becke-ch--npm--s0-v1

Password:

Email: (this IS public) npm--s0-v1@becke.ch

Logged in as becke-ch--npm--s0-v1 on http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted.

 

3.9.3.2. Logging into npm (optional)

This step is only required when publishing to central NPM repository:

If you created a user on the web-site, use npm login to store the credentials on the client:

npm login

 

3.9.3.3. Logging into nexus – authentication

Make sure you created a user – see chapter: 5.2.8.1.

https://books.sonatype.com/nexus-book/reference/npm-deploying-packages.html

Since the .npmrc file usually contains a registry value intended only for getting new packages, a simple way to override this value is to provide a registry to the publish command:

npm publish --registry http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted/

Alternately, you can edit your package.json file and add a publishConfig section:

vi package.json

  "publishConfig": {

    "registry": "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted/"

  },

...

Publishing requires authentication. It can be configured by adding an _auth value to .npmrc. The value has to be generated by base64-encoding the string of username:password. You can create this encoded string with the command line call openssl e.g.: for the default admin user:

echo -n 'admin:admin123' | openssl base64

echo -n 'becke-ch--npm--s0-v1:y...' | openssl base64

After this the base64 encoded credentials can be found in between the begin and end certificate lines in the output file:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ echo -n 'admin:admin123' | openssl base64

YWRtaW46YWRtaW4xMjM=

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/download/becke-ch--repo-nexus--s1-0-v3/log$ echo -n 'becke-ch--npm--s0-v1:y...' | openssl base64

YmVja2UtY2gtLW5wbS0tczAtdjE6eXMxNTExNjI=

Once you have the encoded credentials the value as well as author information can then be added to the .npmrc file:

vi .npmrc

#registry=http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group

init.author.name = becke.ch

init.author.email = npm--s0-v1@becke.ch

init.author.url = http://becke.ch

# an email is required to publish npm packages

email=npm--s0-v1@becke.ch

always-auth=true

_auth=YmVja2UtY2gtLW5wbS0tczAtdjE6eXMxNTExNjI=

 

 

3.9.3.4. Publishing the package

Use npm publish to publish the package.

Note that everything in the directory will be included unless it is ignored by a local .gitignore or .npmignore file as described in npm-developers.

Also make sure there isn't already a package with the same name, owned by somebody else.

npm publish

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm publish

+ becke-ch--regex--s0-0-v1--base--pl--lib@1.0.15

Once a package is published to the private registry in the repository manager, any other developers or build servers, that access it via the repository group have instant access to the packages.

 

3.9.3.4.1. ERROR

ERROR: npm ERR! need auth You need to authorize this machine using `npm adduser`

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm publish

npm ERR! Linux 4.9.0-040900-generic

npm ERR! argv "/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/bin/node" "/tool/node-v6.10.1-linux-x64/bin/npm" "publish"

npm ERR! node v6.10.1

npm ERR! npm  v3.10.10

npm ERR! code ENEEDAUTH

 

npm ERR! need auth auth required for publishing

npm ERR! need auth You need to authorize this machine using `npm adduser`

 

npm ERR! Please include the following file with any support request:

npm ERR!     /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib/npm-debug.log

SOLUTION: https://books.sonatype.com/nexus-book/reference/npm-deploying-packages.html

See chapter: 3.9.3.3 and 3.9.3.4

 

ERROR: npm ERR! publish Failed PUT 400

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ npm publish

npm ERR! publish Failed PUT 400

npm ERR! Linux 4.9.0-040900-generic

npm ERR! argv "/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/bin/node" "/tool/node-v6.10.1-linux-x64/bin/npm" "publish"

npm ERR! node v6.10.1

npm ERR! npm  v3.10.10

npm ERR! code E400

 

npm ERR! Repository does not allow updating assets: becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted : repository

npm ERR!

npm ERR! If you need help, you may report this error at:

npm ERR!     <https://github.com/npm/npm/issues>

 

npm ERR! Please include the following file with any support request:

npm ERR!     /media/disk-ssd—s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib/npm-debug.log

When consulting the nexus trace log:

2017-04-12 15:53:56,688+0200 WARN  [qtp2010031162-54] becke-ch--npm--s0-v1 com.sonatype.nexus.repository.npm.internal.NpmHandlers - Error: PUT /becke-ch--regex--s0-0-v1--base--pl--lib: Status{successful=false, code=400, message='null'} - Repository does not allow updating assets: becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted

org.sonatype.nexus.repository.IllegalOperationException: Repository does not allow updating assets: becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted

 at org.sonatype.nexus.repository.storage.StorageTxImpl.attachBlob(StorageTxImpl.java:622) [org.sonatype.nexus.repository:3.2.1.01]

 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [na:1.8.0_92]

 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [na:1.8.0_92]

 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [na:1.8.0_92]

 at java.lang.reflect.Method.invoke(Method.java:498) [na:1.8.0_92]

 at org.sonatype.nexus.common.stateguard.SimpleMethodInvocation.proceed(SimpleMethodInvocation.java:53) [org.sonatype.nexus.common:3.2.1.01]

...

SOLUTION: The version number needs to be incremented:

package.json:

  "version": "1.0.21",

 

3.9.3.5. Deleting a published package (nexus repository)

In the NPM repository a package can only be deprecated: https://docs.npmjs.com/cli/deprecate

To delete a package in the nexus repository:

  1. 1.Go to “Browse → Components” and select the repository where the component should be deleted (e.g. “http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-hosted”): 

 
  1. 2.Select the component in the version that should get deleted (e.g. name: “becke-ch—regex--s0-0-v1--base--pl--lib” & version: “1.0.15”): 

 
  1. 3.And click “Delete Component”: 

 
  1. 4.And confirm with “Yes” 

 
  1. 5.If not already logged in, log in as admin user (actually you will get an error that you do not have the required privileges and therefore after logging in as administrator click again on “Delete component”): 

 

3.10. Publishing Node.js Module To Ivy Repository

http://blog.cliffano.com/2012/06/13/publishing-node-js-module-to-ivy-repository/

 

Update (23/08/2012): The instruction below is for Bob v0.5.x or newer.

 

    Create an ivy.xml file template in your Node.js module project’s root directory If you’re upgrading from Bob v0.4.x, all you need to do is remove the $ from the parameter syntax.

 

[code lang=“xml”] <?xml version=“1.0” encoding=“ISO-8859-1”?> [/code]

 

    Create a .bob.json file in your project directory, specifying ivy.xml location and details of the Ivy repository server If you’re upgrading from Bob v0.4.x, you need to move ivy.xml to the project’s root directory, and modify .bob.json by removing packagemeta, change template structure, renaming deploy to publish, adding publish.type: ivy .

 

[code lang=“javascript”] { “template”: [“.bob/artifact/ivy.xml”], “publish”: { “type”: “ivy”, “user”: “username”, “key”: “path/to/keyfile”, “host”: “hostname”, “port”: portnumber, “dir”: “/path/to/ivy/repo/${name}/${version}” } } [/code]

 

    Run Bob If you’re upgrading from Bob v0.4.x, simply replace template package package-meta ssh-mkdir deploy targets, with package publish

 

bob package publish

 

This will create /path/to/ivy/repo/modulename/version/ directory with the following files:

 

    modulename.tar.gz

 

    modulename.tar.gz.md5

 

    modulename.tar.gz.sha1

 

    ivy.xml

 

    ivy.xml.md5

 

    ivy.xml.sha1

 

This module can then be referenced as com.company.modulename, and used just like any other artifact using Ivy.

 

If the repository is accessible via HTTP, then you can also specify the Ivy artifact as a dependency of another Node.js module in its package.json file:

 

[code lang=“javascript”] { “dependencies”: { “modulename”: “http://ivyserver/com/company/modulename/version/modulename-version.tar.gz", } } [/code]

 

Despite my dislike towards XML configuration files, Ivy has worked just fine all these years and I’ve been using it to store various types of artifacts. Even though its main popularity is within the Java community, you can store pretty much anything there (YMMV).

 

https://github.com/cliffano/bob

 

4. YARN

 

https://yarnpkg.com/en/

Ultra Fast. Yarn caches every package it downloads so it never needs to download it again. It also parallelizes operations to maximize resource utilization so install times are faster than ever.

 

 

Mega Secure. Yarn uses checksums to verify the integrity of every installed package before its code is executed.

 

 

Super Reliable. Using a detailed, but concise, lockfile format, and a deterministic algorithm for installs, Yarn is able to guarantee that an install that worked on one system will work exactly the same way on any other system.

...

https://www.slant.co/topics/1488/versus/~npm-browserify_vs_yarn_vs_bower

...

4.1. Getting started

https://yarnpkg.com/en/docs/getting-started

4.1.1. Installation

https://yarnpkg.com/en/docs/install#linux-tab

Debian / Ubuntu:

  1. 1.Configure the repository (because yarn is not in the default repository list): 

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

 

admin--s0-v1@hp-elitebook-840-g1--s0-v3:~$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

[sudo] password for admin--s0-v1:

OK

admin--s0-v1@hp-elitebook-840-g1--s0-v3:~$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

deb https://dl.yarnpkg.com/debian/ stable main

 

  1. 2.Install 

sudo apt-get update && sudo apt-get install yarn

 

admin--s0-v1@hp-elitebook-840-g1--s0-v3:~$ sudo apt-get update && sudo apt-get install yarn

The following additional packages will be installed:

  libuv1 nodejs

The following NEW packages will be installed:

  libuv1 nodejs yarn

0 upgraded, 3 newly installed, 0 to remove and 15 not upgraded.

Need to get 4'958 kB of archives.

After this operation, 39.4 MB of additional disk space will be used.

Do you want to continue? [Y/n] Y

Setting up libuv1:amd64 (1.8.0-1) ...

Setting up yarn (0.20.3-1) ...

Setting up nodejs (4.2.6~dfsg-1ubuntu4.1) ...

update-alternatives: using /usr/bin/nodejs to provide /usr/bin/js (js) in auto mode

Processing triggers for libc-bin (2.23-0ubuntu5) ...

 

  1. 3.Test that Yarn is installed by running:  

yarn --version

 

admin--s0-v1@hp-elitebook-840-g1--s0-v3:~$ yarn --version

0.20.3

 

4.1.2. Setup

Once the local/custom registry is set up – see chapter 5.2 - point yarn to local/custom registry (https://github.com/yarnpkg/yarn/issues/606):

yarn config set registry http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ yarn config set registry http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//

yarn config v0.20.3

success Set "registry" to "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//".

Done in 0.05s.

IMPORTANT – the URL needs to end with double slash “…//”!

Double check your local “.yarnrc” file to make sure everything worked fine:

vi .yarnrc

...

registry "http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//"

...

 

 

4.1.3. Intellij Settings

in File | Settings | Languages & Frameworks | Node.js and NPM, press ellipsis button next to 'Node interpreter' field

in Node.js Interpreters dialog that opens, open 'NPM package:' dropdown, choose your Yarn package there (see screenshot); if it's not there, use browse button to choose Yarn package folder

 

4.2. Workflow

https://yarnpkg.com/en/docs/yarn-workflow

4.2.1. Create a new project

Regarding package.json format see chapter: 3.9.1

https://yarnpkg.com/en/docs/creating-a-project

yarn init

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ yarn init

 

yarn init v0.20.3

question name (becke-ch--regex--s0-0-v1--base--pl--lib): [enter]

question version (1.0.0): [enter]

question description: Extension of JavaScript RegExp adding missing functionality

question entry point (index.js): [enter]

question repository url: file:///ws/tool/becke-ch--regex--s0-v1

question author: Raoul Becke <regex--s0-v1@becke.ch>

question license (MIT): SEE LICENSE IN becke-ch--regex--s0-v1--license.txt

success Saved package.json

Done in 236.27s.

 

Adapt & extend the missing properties: See chapter: 3.9.2

 

4.2.1.1. Intellij – new (npm) module

See chapter 3.9.2.1 respective 3.9.2.2.

 

4.2.2. Publishing a package

After many attempts I gave up publishing a package to my private repository with “yarn publish” and instead now using “npm publish” to publish my package! See chapter: 3.9.3

See long discussions on: https://github.com/yarnpkg/yarn/issues/521

https://yarnpkg.com/en/docs/publishing-a-package

4.2.2.1. Create an NPM account (optional)

This step is only required when publishing to central NPM repository:

Create an NPM Account: https://www.npmjs.com/signup

 

4.2.2.2. Logging into npm (optional)

This step is only required when publishing to central NPM repository:

yarn login

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ yarn login

yarn login v0.22.0

question npm username: becke-ch--npm--s0-v1

question npm email: npm--s0-v1@becke.ch

Done in 36.23s.

 

4.2.2.3. Publishing the package

 

yarn publish

First you will be asked to enter a new version to publish:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ yarn publish

yarn publish v0.20.3

[1/4] Bumping version...

info Current version: 1.0.0

question New version: 1.0.1

Next you will be asked to enter your npm username, email and password:

question npm username: becke.ch

question npm email: npm--s0-v1@becke.ch

question npm password:

 

4.2.2.3.1. ERROR

ERROR Incorrect username or password.

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--base--pl--lib$ yarn publish

yarn publish v0.20.3

[1/4] Bumping version...

info Current version: 1.0.0

question New version: 1.0.1

info New version: 1.0.1

[2/4] Logging in...

question npm username: becke.ch

question npm email: npm--s0-v1@becke.ch

question npm password:

error Incorrect username or password.

info Visit https://yarnpkg.com/en/docs/cli/publish for documentation about this command.

The nexus repository request log, error message looks as follows:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/download/becke-ch--repo-nexus--s1-0-v3/log$ tail -f request.log

127.0.0.1 - - [06/Apr/2017:18:46:54 +0200] "PUT /repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//-/user/org.couchdb.user:becke.ch HTTP/1.1" 401 0 1 "yarn/0.20.3 npm/? node/v6.10.1 linux x64"

After adding user “becke.ch” to the nexus repository (see 5.2.8) the error message looks as follows:

127.0.0.1 - - [06/Apr/2017:20:53:43 +0200] "POST /service/extdirect/poll/rapture_State_get HTTP/1.1" 200 77 3 "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"

127.0.0.1 - becke.ch [06/Apr/2017:20:53:57 +0200] "PUT /repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//-/user/org.couchdb.user:becke.ch HTTP/1.1" 201 129 15 "yarn/0.20.3 npm/? node/v6.10.1 linux x64"

127.0.0.1 - - [06/Apr/2017:20:53:57 +0200] "PUT /repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group//becke-ch--regex--s0-0-v1--base--pl--lib HTTP/1.1" 401 0 1 "yarn/0.20.3 npm/? node/v6.10.1 linux x64"

 

4.2.3. Upgrade packages

https://yarnpkg.com/en/docs/cli/upgrade

Upgrades packages to their latest version based on the specified range.

Important: Nexus needs to be running because we are using Nexus as our private & proxy repository!

yarn upgrade

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client$ yarn upgrade

yarn upgrade v0.22.0

[1/4] Resolving packages...

warning protractor > jasmine > glob > minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

warning lite-server > browser-sync > localtunnel > request > node-uuid@1.4.8: Use uuid module instead

[2/4] Fetching packages...

warning fsevents@1.1.1: The platform "linux" is incompatible with this module.

info "fsevents@1.1.1" is an optional dependency and failed compatibility check. Excluding it from installation.

[3/4] Linking dependencies...

[4/4] Rebuilding all packages...

success Saved lockfile.

success Saved 380 new dependencies.

├─ @angular/common@4.0.2

└─ zone.js@0.8.5

Done in 12.14s.

 

4.2.3.1. ERROR

ERROR: Couldn't find package "..." on the "npm" registry.

SOLUTION: Check and fix the .npmrc configuration

vi /home/raoul-becke--s0-v1/.npmrc

init.author.name=becke.ch

init.author.email=npm--s0-v1@becke.ch

init.author.url=http://becke.ch

email=npm--s0-v1@becke.ch

//registry.npmjs.org/:_authToken=163827b9-2ea0-49ec-9ade-fdca02068065

registry=http://localhost:8081/repository/becke-ch--repo-nexus--s1-0-2-v3-0--npm-group

always-auth=true

_auth=YmVja2UtY2gtLW5wbS0tczAtdjE6eXMxNTExNjI=

 

5. Private registry/repository

There exists different private npm registry/repository implementations but none of them is fully supported anymore which is a problem considering the NPM API changes. I started with the “official” “npm-registry-couchapp” but besides that the installation is a little bit complex the first thing that is mentioned is that it is deprecated:

http://www.clock.co.uk/blog/how-to-create-a-private-npmjs-repository

https://github.com/npm/npm-registry-couchapp/blob/master/README.md

https://docs.npmjs.com/misc/registry

deprecation notice: as npm has scaled, the registry architecture has gradually migrated towards a complex distributed architecture, of which npm-registry-couchapp is only a small part. FOSS is an important part of npm, and over time we plan on exposing more APIs, and better documenting the existing API.

...

Then I almost started using “sinopia”:

https://www.npmjs.com/package/sinopia

https://entwickler.de/online/javascript/sinopia-184560.html

which has some good resonance in the NPM community BUT again it is deprecated and the fork “verdaccio” had a lot of discussions but not so much progress:

https://github.com/rlidwka/sinopia/issues/376

And therefore finally I switched over to “Nexus 3” which:

See as well: http://larrymyers.com/tech/2016/06/05/private-npm-with-nexus.html

In past years I would have recommended using Sinopia, or something like Nodejitsu. In two years the landscape has changed quite a bit and there are better alternatives now.

 

While you can pay npm, Inc (i.e. npm the company) $7/month to host your private packages, my recommendation would be to host Nexus 3 yourself. It provides all the functionality of NPM, while giving you more control and flexibility over how you would like to host your private npm modules.

...

5.1. CouchDB

5.1.1. Installation

http://couchdb.apache.org/

5.1.1.1. Source

Required packages:

 

apt list --installed | grep -E 'build-essential|autoconf|automake|libtool|erlang|libicu-dev|libmozjs185-dev|libcurl4-openssl-dev'

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/data/db/apache-couchdb-1.6.1$ apt list --installed | grep -E 'build-essential|autoconf|automake|libtool|erlang|libicu-dev|libmozjs-dev|libcurl4-openssl-dev'

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

build-essential/xenial,now 12.1ubuntu2 amd64 [installed,automatic]

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/data/db/apache-couchdb-1.6.1$ apt search .*libmoz.*

Sorting... Done

Full Text Search... Done

libmozilla-ldap-perl/xenial 1.5.3-2build2 amd64

  LDAP Perl module for the OpenLDAP C SDK

libmozjs185-dev/xenial 1.8.5-1.0.0+dfsg-4.5 amd64

  Spidermonkey javascript library - development headers

sudo apt-get install  build-essential autoconf automake libtool erlang libicu-dev libmozjs185-dev libcurl4-openssl-dev

admin--s0-v1@hp-elitebook-840-g1--s0-v3:~$ sudo apt-get install  build-essential autoconf automake libtool erlang libicu-dev libcurl4-openssl-dev

Reading package lists... Done

Building dependency tree      

Reading state information... Done

build-essential is already the newest version (12.1ubuntu2).

build-essential set to manually installed.

The following packages were automatically installed and are no longer required:

  linux-headers-4.4.0-53 linux-headers-4.4.0-53-generic linux-headers-4.4.0-57 linux-headers-4.4.0-57-generic linux-headers-4.4.0-59 linux-headers-4.4.0-59-generic linux-image-4.4.0-53-generic

  linux-image-4.4.0-57-generic linux-image-4.4.0-59-generic linux-image-extra-4.4.0-53-generic linux-image-extra-4.4.0-57-generic linux-image-extra-4.4.0-59-generic linux-signed-image-4.4.0-53-generic

  linux-signed-image-4.4.0-57-generic linux-signed-image-4.4.0-59-generic

Use 'sudo apt autoremove' to remove them.

The following additional packages will be installed:

  autotools-dev ca-certificates-java default-jre-headless erlang-asn1 erlang-base erlang-common-test erlang-corba erlang-crypto erlang-debugger erlang-dev erlang-dialyzer erlang-diameter erlang-edoc

  erlang-eldap erlang-erl-docgen erlang-et erlang-eunit erlang-examples erlang-gs erlang-ic erlang-ic-java erlang-inets erlang-jinterface erlang-megaco erlang-mnesia erlang-mode erlang-observer erlang-odbc

  erlang-os-mon erlang-parsetools erlang-percept erlang-public-key erlang-reltool erlang-runtime-tools erlang-snmp erlang-src erlang-ssh erlang-ssl erlang-syntax-tools erlang-test-server erlang-tools

  erlang-typer erlang-webtool erlang-wx erlang-xmerl icu-devtools java-common libjs-jquery-metadata libjs-jquery-tablesorter libltdl-dev libodbc1 libsctp1 libwxbase3.0-0v5 libwxgtk3.0-0v5 m4

  openjdk-8-jre-headless

Suggested packages:

  autoconf-archive gnu-standards autoconf-doc default-jre erlang-manpages erlang-doc xsltproc fop libcurl4-doc libcurl3-dbg libidn11-dev libkrb5-dev libldap2-dev librtmp-dev libssl-dev zlib1g-dev icu-doc

  libtool-doc libmyodbc odbc-postgresql tdsodbc unixodbc-bin lksctp-tools gfortran | fortran95-compiler gcj-jdk openjdk-8-jre-jamvm fonts-ipafont-gothic fonts-ipafont-mincho ttf-wqy-microhei | ttf-wqy-zenhei

  fonts-indic

The following NEW packages will be installed:

  autoconf automake autotools-dev ca-certificates-java default-jre-headless erlang erlang-asn1 erlang-base erlang-common-test erlang-corba erlang-crypto erlang-debugger erlang-dev erlang-dialyzer

  erlang-diameter erlang-edoc erlang-eldap erlang-erl-docgen erlang-et erlang-eunit erlang-examples erlang-gs erlang-ic erlang-ic-java erlang-inets erlang-jinterface erlang-megaco erlang-mnesia erlang-mode

  erlang-observer erlang-odbc erlang-os-mon erlang-parsetools erlang-percept erlang-public-key erlang-reltool erlang-runtime-tools erlang-snmp erlang-src erlang-ssh erlang-ssl erlang-syntax-tools

  erlang-test-server erlang-tools erlang-typer erlang-webtool erlang-wx erlang-xmerl icu-devtools java-common libcurl4-openssl-dev libicu-dev libjs-jquery-metadata libjs-jquery-tablesorter libltdl-dev libodbc1

  libsctp1 libtool libwxbase3.0-0v5 libwxgtk3.0-0v5 m4 openjdk-8-jre-headless

0 upgraded, 62 newly installed, 0 to remove and 2 not upgraded.

Need to get 81.3 MB of archives.

After this operation, 286 MB of additional disk space will be used.

Get source:

cd /data/db

wget http://mirror.switch.ch/mirror/apache/dist/couchdb/source/2.0.0/apache-couchdb-2.0.0.tar.gz

Extract:

tar xvzf apache-couchdb-2.0.0.tar.gz

Compile:

cd apache-couchdb-2.0.0

./configure

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/data/db/apache-couchdb-2.0.0$ ./configure

==> configuring couchdb in rel/couchdb.config

You have configured Apache CouchDB, time to relax. Relax.

 

make release

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/data/db/apache-couchdb-2.0.0$ make release

==> couch_epi (compile)

==> rel (generate)

ERROR: Unable to generate spec: read file info /usr/lib/erlang/man/man1/x86_64-linux-gnu-gcov-tool.1.gz failed

ERROR: Unexpected error: rebar_abort

ERROR: generate failed while processing /media/disk-ssd--s0-v1/data/db/apache-couchdb-2.0.0/rel: rebar_abort

Makefile:234: recipe for target 'release' failed

make: *** [release] Error 1

https://github.com/emqtt/emqttd/issues/530

https://bugs.launchpad.net/ubuntu/+source/erlang/+bug/1600780

Temporary solution:

 

$ sudo touch /usr/lib/erlang/man/man1/gcov-tool-5.1.gz

WARN:  'generate' command does not apply to directory /media/disk-ssd--s0-v1/data/db/apache-couchdb-2.0.0

... done

 

    You can now copy the rel/couchdb directory anywhere on your system.

    Start CouchDB with ./bin/couchdb from within that directory.

Add couch db system user for NPM repository:

adduser --system \

        --shell /bin/bash \

        --group --gecos \

        "CouchDB v2.0 Administrator for NPM repository" apache-couchdb—npm--s0-v2

root@hp-elitebook-840-g1--s0-v3:~# adduser --system \

>         --shell /bin/bash \

>         --group --gecos \

>         "CouchDB v2.0 Administrator for NPM repository" apache-couchdb--npm--s0-v2

Adding system user `apache-couchdb--npm--s0-v2' (UID 128) ...

Adding new group `apache-couchdb--npm--s0-v2' (GID 134) ...

Adding new user `apache-couchdb--npm--s0-v2' (UID 128) with group `apache-couchdb--npm--s0-v2' ...

Creating home directory `/home/apache-couchdb--npm--s0-v2' ...

Copy, change owner, change permission and update permissions for ini files:

cp -r /data/db/apache-couchdb-2.0.0/rel/couchdb /home/apache-couchdb—npm--s0-v2

chown -R apache-couchdb--npm--s0-v2:apache-couchdb--npm--s0-v2 /home/apache-couchdb—npm—s0-v2/couchdb

find /home/apache-couchdb--npm--s0-v2/couchdb -type d -exec chmod 0770 {} \;

chmod 0644 /home/apache-couchdb--npm--s0-v2/couchdb/etc/*

 

5.1.1.2. Binary

Todo

 

5.1.2. Setup

Add couch db system user for NPM repository:

adduser --system \

        --shell /bin/bash \

        --group --gecos \

        "CouchDB v2.0 Administrator for NPM repository" apache-couchdb—npm--s0-v2

root@hp-elitebook-840-g1--s0-v3:~# adduser --system \

>         --shell /bin/bash \

>         --group --gecos \

>         "CouchDB v2.0 Administrator for NPM repository" apache-couchdb--npm--s0-v2

Adding system user `apache-couchdb--npm--s0-v2' (UID 128) ...

Adding new group `apache-couchdb--npm--s0-v2' (GID 134) ...

Adding new user `apache-couchdb--npm--s0-v2' (UID 128) with group `apache-couchdb--npm--s0-v2' ...

Creating home directory `/home/apache-couchdb--npm--s0-v2' ...

Copy, change owner, change permission and update permissions for ini files:

cp -r /data/db/apache-couchdb-2.0.0/rel/couchdb /home/apache-couchdb—npm--s0-v2

chown -R apache-couchdb--npm--s0-v2:apache-couchdb--npm--s0-v2 /home/apache-couchdb—npm—s0-v2/couchdb

find /home/apache-couchdb--npm--s0-v2/couchdb -type d -exec chmod 0770 {} \;

chmod 0644 /home/apache-couchdb--npm--s0-v2/couchdb/etc/*

Start:

sudo -i -u apache-couchdb--npm--s0-v2 couchdb/bin/couchdb

apache-couchdb--npm--s0-v2@hp-elitebook-840-g1--s0-v3:~/couchdb$ ./bin/couchdb

[info] 2017-02-12T19:46:57.535421Z couchdb@localhost <0.7.0> -------- Application couch_log started on node couchdb@localhost

[error] 2017-02-12T19:47:02.783205Z couchdb@localhost emulator -------- Error in process <0.456.0> on node couchdb@localhost with exit value:

{database_does_not_exist,[{mem3_shards,load_shards_from_db,"_users",[{file,"src/mem3_shards.erl"},{line,327}]},{mem3_shards,load_shards_from_disk,1,[{file,"src/mem3_shards.erl"},{line,315}]},{mem3_shards,load_shards_from_disk,2,[{file,"src/mem3_shards.erl"},{line,331}]},{mem3_shards,for_docid,3,[{file,"src/mem3_shards.erl"},{line,87}]},{fabric_doc_open,go,3,[{file,"src/fabric_doc_open.erl"},{line,38}]},{chttpd_auth_cache,ensure_auth_ddoc_exists,2,[{file,"src/chttpd_auth_cache.erl"},{line,187}]},{chttpd_auth_cache,listen_for_changes,1,[{file,"src/chttpd_auth_cache.erl"},{line,134}]}]}

Single Node Setup: Will fix the error: “couchdb@localhost emulator -------- Error in process <0.456.0> on node couchdb@localhost with exit value: {database_does_not_exist” ...”

http://stackoverflow.com/questions/41553458/couchdb-2-0-installation-error

curl -X PUT http://127.0.0.1:5984/_users

curl -X PUT http://127.0.0.1:5984/_replicator

curl -X PUT http://127.0.0.1:5984/_global_changes

root@hp-elitebook-840-g1--s0-v3:~# curl -X PUT http://127.0.0.1:5984/_users

{"ok":true}

root@hp-elitebook-840-g1--s0-v3:~# curl -X PUT http://127.0.0.1:5984/_replicator

{"ok":true}

root@hp-elitebook-840-g1--s0-v3:~# curl -X PUT http://127.0.0.1:5984/_global_changes

{"ok":true}

secure_rewrites: This option allow to isolate databases via subdomains:

    [httpd]

    secure_rewrites = true

root@hp-elitebook-840-g1--s0-v3:/home/apache-couchdb--npm--s0-v2/couchdb/etc# vi local.ini

[httpd]

...

secure_rewrites = true

...

Ready, set, link, defaults.

sudo ln -s /usr/local/etc/init.d/couchdb /etc/init.d

sudo update-rc.d couchdb defaults

 

 

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ cd /app

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/app$ git clone git://github.com/npm/npm-registry-couchapp

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/app/npm-registry-couchapp$ npm install

loadDep:underscore → 200  ▀ ╢████████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░╟

npm WARN deprecated node-uuid@1.4.7: use uuid module instead

npm WARN prefer global coffee-script@1.12.3 should be installed with -g

npm-registry-couchapp@2.6.12 /media/disk-ssd--s0-v1/app/npm-registry-couchapp

├─┬ couchapp@0.11.0

│ ├── coffee-script@1.12.3

│ ├─┬ connect@3.5.1

│ │ ├─┬ debug@2.2.0

│ │ │ └── ms@0.7.1

│ │ ├─┬ finalhandler@0.5.1

│ │ │ ├── escape-html@1.0.3

│ │ │ ├─┬ on-finished@2.3.0

│ ├── tmatch@3.0.0

│ ├── trivial-deferred@1.0.1

│ └── yapool@1.0.0

└─┬ which@1.2.12

  └── isexe@1.1.2

 

5.2. Nexus Repository OSS

Based on the documentation: http://books.sonatype.com/nexus-book/3.2/pdf/nxbook-pdf.pdf

5.2.1. Prerequisites and Conventions

Java: Nexus Repository Manager requires Java 8.

NFS: Mounting the storage directory via NFS can have negative performance and stability effects.

Component: A component is a resource like a library or a framework that is used as part of your software application at run-time, integration or unit test execution time or required as part of your build process. It could be an entire application or a static resource like an image.

Assets Assets are the material addition to all this metadata. The actual archive file is an asset associated

with the component. Many formats have a one-to-one mapping for component to asset.
For example a typical JAR component in a Maven repository is defined at least by the POM and the JAR files - both of which constitute separate assets belonging to the same components.

 

Components in Repositories A wide variety of components exists and more are continuously created by the open source community as well as proprietary vendors. There are libraries and frameworks written in various languages on different platforms that are used for application development every day. It has become a default pattern to build applications by combining the features of multiple components with your own custom components containing your application code to create an application for a specific domain.

In order to ease the consumption and usage of components, they are aggregated into collections of components. These are called a repository and are typically available on the internet as a service. On different platforms terms such as registry and others are used for the same concept.

 

 

5.2.2. Installation

  1. 1.Download: https://www.sonatype.com/download-oss-sonatype 

  2. 2.Extract e.g. into directory: /app/nexus-3.2.1-01-unix 

  3. 3.mv folder up: mv /app/nexus-3.2.1-01-unix/nexus-3.2.1-01 /app/nexus-3.2.1-01 

  4. 4.vi /app/nexus-3.2.1-01/bin/nexus 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ vi /app/nexus-3.2.1-01/bin/nexus

# Uncomment the following line to override the JVM search sequence

INSTALL4J_JAVA_HOME_OVERRIDE=/tool/jdk1.8.0_92/

...

  1. 5.(Optional) Install nexus as a service 

vi /etc/systemd/system/nexus.service

 

[Unit]

Description=nexus service

After=network.target

[Service]

Type=forking

ExecStart=/app/nexus-3.2.1-01/bin/nexus start

ExecStop=/app/nexus-3.2.1-01/bin/nexus stop

User=nexus

Restart=on-abort

[Install]

WantedBy=multi-user.target

 

sudo systemctl daemon-reload

sudo systemctl enable nexus.service

 

5.2.3. Setup

  1. 1.Configuring the Data Directory 

In the configuration file change the values of -Dkaraf.data, -Djava.io.tmpdir, and -XX:LogFile to designate an absolute path you prefer to use.

 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ vi /app/nexus-3.2.1-01/bin/nexus.vmoptions

...

#-XX:LogFile=../sonatype-work/nexus3/log/jvm.log

-XX:LogFile=/download/becke-ch--repo-nexus--s1-0-v3/log/jvm.log

#-Dkaraf.data=../sonatype-work/nexus3

-Dkaraf.data=/download/becke-ch--repo-nexus--s1-0-v3

#-Djava.io.tmpdir=../sonatype-work/nexus3/tmp

-Djava.io.tmpdir=/download/becke-ch--repo-nexus--s1-0-v3/tmp

 

5.2.4. Start

  1. 1.Start nexus on the command-line versus as a service 

    1. a.nexus command-line 

cd /app/nexus-3.2.1-01/bin

./nexus run

    1. b.nexus as a service 

sudo systemctl start nexus.service

  1. 2.The start was successful if we get the following output: 

2017-02-24 06:22:51,667+0100 INFO  [jetty-main-1] *SYSTEM org.eclipse.jetty.server.ServerConnector - Started ServerConnector@1fe50351{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}

2017-02-24 06:22:51,667+0100 INFO  [jetty-main-1] *SYSTEM org.eclipse.jetty.server.Server - Started @31558ms

2017-02-24 06:22:51,668+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer -

-------------------------------------------------

 

Started Sonatype Nexus OSS 3.2.1-01

 

-------------------------------------------------

...

You can as well check the log file for this output:

vi /download/repo--s1-0-v3/log/nexus.log

  1. 3.And when logging into http://localhost:8081 you should get the following web page: 

 
  1. 4.The login / sign-in into the administration console is as follows: Click on “Sign In”: 

    1. a.Login: admin 

    2. b.Password: admin123 

 

5.2.5. Proxying npm Registries

 

  1. 1.Select the Repositories item in the Repository sub menu of the Administration menu. 

 
  1. 2.Click “Create repository” and select “npm (proxy)”: 

 
  1. 3.Enter the following values and leave the rest default: 

    1. a.Name: Use the name given in the setup (becke-ch--repo-nexus--s1-0-v3) with additional scope, version and use-case classification:  becke-ch--repo-nexus--s1-0-0-v3-0--npm-proxy 

    2. b.Remote Storage: https://registry.npmjs.org/ 

 

5.2.6. Private npm Registries

Follow step 1. of the previous chapter and then:

  1. 1.Click “Create repository” and select “npm (hosted)” 

  2. 2.Enter the following values and leave the rest default: 

    1. a.Name: Use the name given in the setup (becke-ch--repo-nexus--s1-0-v3) with additional scope, version and use-case classification:  becke-ch--repo-nexus--s1-0-1-v3-0--npm-hosted 

       

 
 

5.2.7. Grouping npm Registries

Follow step 1. of the previous chapter and then:

  1. 1.Click “Create repository” and select “npm (group)” 

  2. 2.Enter the following values and leave the rest default: 

    1. a.Name: Use the name given in the setup (becke-ch--repo-nexus--s1-0-v3) with additional scope, version and use-case classification:  becke-ch--repo-nexus--s1-0-2-v3-0--npm-group 

    2. b.Choose Member Repositories: Select the repositories that should be member of this group 

       

 

5.2.8. Security

5.2.8.1. Create User

 

 

 

 

5.2.9. Error

ERROR: http://localhost:8081/ not working!

SOLUTION: REBOOT?! OR “/etc/init.d/network-manager restart”?!

I could not find the solution to the problem until I restarted my computer. I only saw that the log got stuck:

...

2017-02-23 05:30:19,306+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.extender.NexusLifecycleManager - Start SERVICES

2017-02-23 05:30:19,363+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.blobstore.file.internal.BlobStoreMetricsStoreImpl - Blob store metrics file /media/disk-ssd--s0-v1/app/tmp/sonatype-work/nexus3/blobs/default/557F8812-3A328744-044A793D-F4658F72-ACF89806-metrics.properties not found - initializing at zero.

2017-02-23 05:30:19,768+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.internal.httpclient.HttpClientManagerImpl - Using default configuration: HttpClientConfiguration{connection=null, proxy=null, authentication=null}

2017-02-23 05:30:19,912+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.elasticsearch.internal.NodeProvider - Creating node with config: /media/disk-ssd—s0-v1/app/tmp/nexus-3.2.1-01/etc/fabric/elasticsearch.yml

INSTEAD I should have got:

...

2017-02-23 06:00:00,249+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.extender.NexusLifecycleManager - Start SERVICES

2017-02-23 06:00:00,330+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.blobstore.file.internal.BlobStoreMetricsStoreImpl - Blob store metrics file /media/disk-ssd--s0-v1/app/tmp/sonatype-work/nexus3/blobs/default/4717CE09-220528FD-A966D80E-6FF3B018-AB79E310-metrics.properties not found - initializing at zero.

2017-02-23 06:00:00,795+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.internal.httpclient.HttpClientManagerImpl - Using default configuration: HttpClientConfiguration{connection=null, proxy=null, authentication=null}

2017-02-23 06:00:00,949+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.elasticsearch.internal.NodeProvider - Creating node with config: /media/disk-ssd--s0-v1/app/tmp/nexus-3.2.1-01/etc/fabric/elasticsearch.yml

2017-02-23 06:00:01,045+0100 WARN  [FelixStartLevel] *SYSTEM org.elasticsearch.common - Unable to get a valid mac address, will use a dummy address

2017-02-23 06:00:01,456+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.node - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] version[2.4.3], pid[4855], build[d38a34e/2016-12-07T16:28:56Z]

2017-02-23 06:00:01,456+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.node - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] initializing ...

2017-02-23 06:00:01,460+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.plugins - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] modules [], plugins [content-auth-plugin], sites []

2017-02-23 06:00:01,478+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.env - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] using [1] data paths, mounts [[/media/disk-ssd--s0-v1 (/dev/sda3)]], net usable_space [78.5gb], net total_space [441.3gb], spins? [no], types [ext4]

2017-02-23 06:00:01,478+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.env - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] heap size [1.1gb], compressed ordinary object pointers [true]

2017-02-23 06:00:02,533+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.node - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] initialized

2017-02-23 06:00:02,534+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.node - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] starting ...

2017-02-23 06:00:02,536+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.transport - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] publish_address {local[1]}, bound_addresses {local[1]}

2017-02-23 06:00:02,540+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.discovery - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] nexus/9tg5_g-aQlqnLCStYqrE8g

2017-02-23 06:00:02,546+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.service - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] new_master {4717CE09-220528FD-A966D80E-6FF3B018-AB79E310}{9tg5_g-aQlqnLCStYqrE8g}{local}{local[1]}{local=true, master=true}, reason: local-disco-initial_connect(master)

2017-02-23 06:00:02,551+0100 INFO  [FelixStartLevel] *SYSTEM org.elasticsearch.node - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] started

2017-02-23 06:00:02,595+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.gateway - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] recovered [0] indices into cluster_state

2017-02-23 06:00:02,816+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.metadata - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] [2e9a1e67e8a325bcd6ee9f6790ff6c769e791d56] creating index, cause [api], templates [], shards [1]/[0], mappings [component]

2017-02-23 06:00:02,950+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.metadata - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] [73ae44bc066b6a7a33b4435641d8229b9b66495a] creating index, cause [api], templates [], shards [1]/[0], mappings [component]

2017-02-23 06:00:03,054+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.routing.allocation - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] Cluster health status changed from [RED] to [GREEN] (reason: [shards started [[2e9a1e67e8a325bcd6ee9f6790ff6c769e791d56][0], [2e9a1e67e8a325bcd6ee9f6790ff6c769e791d56][0]] ...]).

2017-02-23 06:00:03,096+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.metadata - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] [51196dce51055df9247e1973e443b68c84549dd9] creating index, cause [api], templates [], shards [1]/[0], mappings [component]

2017-02-23 06:00:03,143+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.routing.allocation - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] Cluster health status changed from [RED] to [GREEN] (reason: [shards started [[51196dce51055df9247e1973e443b68c84549dd9][0]] ...]).

2017-02-23 06:00:03,178+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.metadata - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] [3d781e8165513bfe7db3d7eaab3991b9ebec763b] creating index, cause [api], templates [], shards [1]/[0], mappings [component]

2017-02-23 06:00:03,238+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.metadata - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] [b2b9b8f06274052a44b61ef3c7e887f0961d99c6] creating index, cause [api], templates [], shards [1]/[0], mappings [component]

2017-02-23 06:00:03,296+0100 INFO  [elasticsearch[4717CE09-220528FD-A966D80E-6FF3B018-AB79E310][clusterService#updateTask][T#1]] *SYSTEM org.elasticsearch.cluster.routing.allocation - [4717CE09-220528FD-A966D80E-6FF3B018-AB79E310] Cluster health status changed from [RED] to [GREEN] (reason: [shards started [[b2b9b8f06274052a44b61ef3c7e887f0961d99c6][0]] ...]).

2017-02-23 06:00:03,324+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.quartz.internal.orient.JobStoreImpl - Instance name: nexus; ID: 4717CE09-220528FD-A966D80E-6FF3B018-AB79E310

2017-02-23 06:00:03,324+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.quartz.internal.orient.JobStoreImpl - Initialized

2017-02-23 06:00:03,331+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.quartz.internal.QuartzSchedulerSPI - Quartz Scheduler v2.2.2

2017-02-23 06:00:03,335+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.extender.NexusLifecycleManager - Start CAPABILITIES

2017-02-23 06:00:03,591+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.extender.NexusLifecycleManager - Start TASKS

2017-02-23 06:00:03,594+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.quartz.internal.QuartzSchedulerSPI - Scheduler put into ready mode

2017-02-23 06:00:03,716+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.quartz.internal.task.QuartzTaskInfo - Task 'Storage facet cleanup' [repository.storage-facet-cleanup] : state=WAITING

2017-02-23 06:00:03,792+0100 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.scheduling.internal.TaskSchedulerImpl - Task 'Storage facet cleanup' [repository.storage-facet-cleanup] scheduled: cron

2017-02-23 06:00:03,834+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.bootstrap.osgi.BootstrapListener - Initialized

2017-02-23 06:00:03,848+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.rapture.internal.RaptureWebResourceBundle - UI plugin descriptors:

2017-02-23 06:00:03,849+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.rapture.internal.RaptureWebResourceBundle -   nexus-rapture

2017-02-23 06:00:03,850+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.rapture.internal.RaptureWebResourceBundle -   nexus-proximanova-plugin

2017-02-23 06:00:03,850+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.rapture.internal.RaptureWebResourceBundle -   nexus-coreui-plugin

2017-02-23 06:00:03,851+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.rapture.internal.RaptureWebResourceBundle -   nexus-proui-plugin

2017-02-23 06:00:03,861+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.internal.webresources.WebResourceServlet - Max-age: 30 days (2592000 seconds)

2017-02-23 06:00:03,884+0100 INFO  [jetty-main-1] *SYSTEM com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - Servlet GLOBAL configuration: debug=false, providersUrl=service/extdirect, minify=false, batchRequestsMultithreadingEnabled=true, batchRequestsMinThreadsPoolSize=16, batchRequestsMaxThreadsPoolSize=80, batchRequestsMaxThreadsPerRequest=8, batchRequestsMaxThreadKeepAliveSeconds=60, gsonBuilderConfiguratorClass=org.sonatype.nexus.extdirect.internal.ExtDirectGsonBuilderConfigurator, dispatcherClass=com.softwarementors.extjs.djn.servlet.ssm.SsmDispatcher, jsonRequestProcessorThreadClass=org.sonatype.nexus.extdirect.internal.ExtDirectJsonRequestProcessorThread, contextPath=--not specified: calculated via Javascript--, createSourceFiles=true

2017-02-23 06:00:03,894+0100 INFO  [jetty-main-1] *SYSTEM com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - Servlet GLOBAL configuration: registryConfiguratorClass=

2017-02-23 06:00:03,913+0100 INFO  [jetty-main-1] *SYSTEM com.softwarementors.extjs.djn.jscodegen.CodeFileGenerator - Creating source files for APIs...

2017-02-23 06:00:04,062+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.siesta.SiestaServlet - JAX-RS RuntimeDelegate: org.sonatype.nexus.siesta.internal.resteasy.SisuResteasyProviderFactory@25045fce

2017-02-23 06:00:04,110+0100 INFO  [jetty-main-1] *SYSTEM org.jboss.resteasy.plugins.validation.i18n - RESTEASY008550: Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory

2017-02-23 06:00:04,153+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.siesta.SiestaServlet - Initialized

2017-02-23 06:00:04,156+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Initialized

2017-02-23 06:00:04,192+0100 INFO  [jetty-main-1] *SYSTEM org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@5aa5841c{/,file:///media/disk-ssd--s0-v1/app/tmp/nexus-3.2.1-01/public/,AVAILABLE}

2017-02-23 06:00:04,230+0100 INFO  [jetty-main-1] *SYSTEM org.eclipse.jetty.server.ServerConnector - Started ServerConnector@5e5b5f24{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}

2017-02-23 06:00:04,230+0100 INFO  [jetty-main-1] *SYSTEM org.eclipse.jetty.server.Server - Started @35364ms

2017-02-23 06:00:04,230+0100 INFO  [jetty-main-1] *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer -

-------------------------------------------------

 

Started Sonatype Nexus OSS 3.2.1-01

 

So basically it seems that if there are issue with the network card respective rather the (blody) OS (Ubuntu 16.04.2 LTS) connecting to the network card (see http://askubuntu.com/questions/761180/wifi-doesnt-work-after-suspend-after-16-04-upgrade ) that the NEXUS cannot start respective that the “org.elasticsearch.common” is blocking the startup process! In this case either restart the network-manager “/etc/init.d/network-manager restart” or if this does not help reboot the computer.

 

ERROR: 4.3.1.  NpmProxyFacetImpl - Failed to fetch: https://registry.npmjs.org/...

2017-04-01 20:47:00,082+0200 WARN  [qtp239892311-148] *UNKNOWN com.sonatype.nexus.repository.npm.internal.NpmProxyFacetImpl - Failed to fetch: https://registry.npmjs.org/when/-/when-3.7.8.tgz

java.net.SocketTimeoutException: Read timed out

2017-04-01 20:47:00,962+0200 WARN  [qtp239892311-47] *UNKNOWN org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Service failure

org.sonatype.nexus.blobstore.api.BlobStoreException: java.net.SocketTimeoutException: Read timed out

        at org.sonatype.nexus.blobstore.file.internal.FileBlobStore.create(FileBlobStore.java:316) [na:na]

Caused by: java.net.SocketTimeoutException: Read timed out

        at java.net.SocketInputStream.socketRead0(Native Method) [na:1.8.0_92]

        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) [na:1.8.0_92]

2017-04-01 20:47:01,459+0200 WARN  [qtp239892311-48] *UNKNOWN org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Service failure

org.eclipse.jetty.io.EofException: null

        at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:197) [org.eclipse.jetty.io:9.3.7.v20160115]

        at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:419) [org.eclipse.jetty.io:9.3.7.v20160115]

...

SOLUTION”: I had to stop and restart nexus several times and even had to reboot the computer :-(

 

 

 

6. Separate File versus In-Line HTML

6.1. In-Line HTML

file:///data/doc/html/SELFHTML/tq.htm

...

Mit <script language="JavaScript"> leiten Sie einen Bereich für JavaScript innerhalb einer HTML-Datei ein (script = Quelltext, language = Sprache). Dahinter - am besten in der nächsten Zeile - sollten Sie mit <!-- einen  Kommentar einleiten. Dadurch erreichen Sie, daß ältere WWW-Browser, die JavaScript nicht kennen, den folgenden JavaScript-Code ignorieren und nicht irrtümlich als Text innerhalb der HTML-Datei interpretieren.

 

Am Ende eines JavaScript-Bereichs schließen Sie mit //--> den Kommentar und mit </script> den Bereich für den Programmcode.

...

HTML:

<html>

<head>

...

<script language="JavaScript">

    <!--

...

    //-->

</script>

...

</head>

<body>

...

</body>

</html>

6.2. Separate File

file:///data/doc/html/SELFHTML/tq.htm

...

Der Unterschied ist lediglich, daß der JavaScript-Code in einer separaten Datei steht. Dazu notieren Sie im einleitenden <script>-Tag die Angabe src= (src = source = Quelle). Dahinter folgt, in Anführungszeichen, der Name der separaten Datei mit dem Quellcode. Ebenfalls notieren sollten Sie die Angabe zum  Mime-Type der eingebundenen Datei. Mit type="text/javascript" bestimmen Sie den Mime-Type für JavaScript-Dateien.

 

Die Datei mit dem Quellcode muß eine reine ASCII-Datei sein und sollte die Dateinamenerweiterung .js erhalten. Die Datei sollte nichts anderes als JavaScript-Code enthalten.

...

HTML:

<html>

<head>

...

<script language="JavaScript" src="quadrat.js" type="text/javascript">

...

</head>

<body>

...

</body>

</html>

 

7. Data structure

http://stackoverflow.com/questions/11922383/access-process-nested-objects-arrays-or-json

JavaScript has only one data type which can contain multiple values: Object. An Array is a special form of object.

(Plain) Objects have the form

{key: value, key: value, ...}

Arrays have the form

[value, value, ...]

Both arrays and objects expose a key -> value structure. Keys in an array must be numeric, whereas any string can be used as key in objects. The key-value pairs are also called the "properties".

Properties can be accessed either using dot notation

var value = obj.someProperty;

or bracket notation, if the property name would not be a valid JavaScript identifier name [spec], or the name is the value of a variable:

// the space is not a valid character in identifier names

var value = obj["some Property"];

 

// property name as variable

var name = "some Property";

var value = obj[name];

For that reason, array elements can only be accessed using bracket notation:

var value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable

var x = 5;

var value = arr[x];

 

7.1. Types

7.1.1. typeof and instanceof (checking for array or function type)

http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-type

http://stackoverflow.com/questions/899574/which-is-best-to-use-typeof-or-instanceof

 

    if (!(newSubstringFunctionArray instanceof Array)) {

        newSubstringFunctionArray = [newSubstringFunctionArray];

    }

        if (typeof newSubstringFunction === 'string') {

...

        } else if (newSubstringFunction instanceof Function) {

            var args = [resultExec[newSubstringFunctionIndex]];

            for (var j = 0; j < resultExec.length; j++) {

                args.push(resultExec[j]);

            }

            for (var k = 0; j < resultExec.index.length; k++) {

                args.push(resultExec.index[k]);

            }

            args.push(str);

            computedString += newSubstringFunction.apply(this, args);

        }

 

 

7.2. Pointers

Object (pointer) comparison: ==: Object pointers can be compared using the double equal sign: ==

BUT there is no way to get the numerical value of a pointer and using this for example in a hash-map - see the following articles:

http://stackoverflow.com/questions/1068834/object-comparison-in-javascript

http://stackoverflow.com/questions/17382427/are-there-pointers-in-javascript

http://stackoverflow.com/questions/10892322/javascript-hashtable-use-object-key

http://stackoverflow.com/questions/8931967/is-there-a-deterministic-equivalent-of-json-stringify

http://stackoverflow.com/questions/10892322/javascript-hashtable-use-object-key/10908885#10908885

http://stackoverflow.com/questions/17872317/javascript-variables-as-object-pointers

http://stackoverflow.com/questions/201183/how-to-determine-equality-for-two-javascript-objects

http://stackoverflow.com/questions/10231868/pointers-in-javascript

 

7.3. String

http://www.w3schools.com/js/js_strings.asp

7.3.1. string.charAt(position)

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/charAt

index

    An integer between 0 and 1-less-than the length of the string. If no index is provided, charAt() will use 0.

 

Return value

 

A string representing the character at the specified index; empty string if index is out of range.

 

 

7.3.2. Check if character is string

http://stackoverflow.com/questions/8935632/check-if-character-is-number

            while (charAt >= '0' && charAt <= '9') {

                int += charAt;

                posIndexOrigIndex[0]++;

                charAt = regex.charAt(posIndexOrigIndex[0]);

            }

 

7.3.3. Empty string

http://stackoverflow.com/questions/154059/how-do-you-check-for-an-empty-string-in-javascript

http://stackoverflow.com/questions/2381456/javascript-how-to-check-if-a-string-is-empty

Check for empty string:

if (newSubstringFunctionArray[0] || newSubstringFunctionArray[0] === "")

 

7.3.4. indexOf (check for substring)

http://stackoverflow.com/questions/1789945/how-to-check-whether-a-string-contains-a-substring-in-javascript

if (int.indexOf('8') >= 0 || int.indexOf('9') >= 0) {

    //if it is a non octal digit then treat it as simple number

    tmpStr += int;

} else {

    //otherwise it is a character escape

    tmpStr += '\\' + 'x' + ("0" + (parseInt(int, 8).toString(16))).slice(-2).toUpperCase();

}

 

7.3.5. Escape Characters

http://www.w3schools.com/js/js_strings.asp

 

Code

Outputs

\'

single quote

\"

double quote

\\

backslash

\n

new line

\r

carriage return

\t

tab

\b

backspace

\f

form feed

 

https://mathiasbynens.be/notes/javascript-escapes

Octal escape sequences

 

Any character with a character code lower than 256 (i.e. any character in the extended ASCII range) can be escaped using its octal-encoded character code, prefixed with \. (Note that this is the same range of characters that can be escaped through hexadecimal escapes.)

 

To use the same example, the copyright symbol ('©') has character code 169, which gives 251 in octal notation, so you could write it as '\251'.

 

Hexadecimal escape sequences

 

Any character with a character code lower than 256 (i.e. any character in the extended ASCII range) can be escaped using its hex-encoded character code, prefixed with \x. (Note that this is the same range of characters that can be escaped through octal escapes.)

 

Hexadecimal escapes are four characters long. They require exactly two characters following \x. If the hexadecimal character code is only one character long (this is the case for all character codes smaller than 16, or 10 in hex), you’ll need to pad it with a leading 0.

 

For example, the copyright symbol ('©') has character code 169, which gives A9 in hex, so you could write it as '\xA9'.

 

7.3.6. Convert Octal to Hexadecimal

http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript

http://jsfiddle.net/t3z4tqy5/

if (int.indexOf('8') >= 0 || int.indexOf('9') >= 0) {

    //if it is a non octal digit then treat it as simple number

    tmpStr += int;

} else {

    //otherwise it is a character escape

    tmpStr += '\\' + 'x' + ("0" + (parseInt(int, 8).toString(16))).slice(-2).toUpperCase();

}

 

 

 

7.4. Function

7.4.1. Reflection – invoke function and parameters dynamically: call & apply

https://www.w3schools.com/js/js_function_invocation.asp

http://stackoverflow.com/questions/6001149/how-to-execute-a-method-passed-as-parameter-to-function

http://adripofjavascript.com/blog/drips/invoking-javascript-functions-with-call-and-apply.html

 

        } else if (newSubstringFunction instanceof Function) {

            var args = [resultExec[newSubstringFunctionIndex]];

            for (var j = 0; j < resultExec.length; j++) {

                args.push(resultExec[j]);

            }

            for (var k = 0; j < resultExec.index.length; k++) {

                args.push(resultExec.index[k]);

            }

            args.push(str);

            computedString += newSubstringFunction.apply(this, args);

        }

 

call & apply: https://www.w3schools.com/js/js_function_invocation.asp

 Both methods take an owner object as the first argument. The only difference is that call() takes the function arguments separately, and apply() takes the function arguments in an array.

 

In JavaScript strict mode, the first argument becomes the value of this in the invoked function, even if the argument is not an object.

 

In "non-strict" mode, if the value of the first argument is null or undefined, it is replaced with the global object.

 

With call() or apply() you can set the value of this, and invoke a function as a new method of an existing object.

 

 

7.5. HTML DOM

http://www.w3schools.com/jsref/dom_obj_all.asp

 

Property / Method

Description

element.accessKey

Sets or returns the accesskey attribute of an element

element.addEventListener()

Attaches an event handler to the specified element

element.appendChild()

Adds a new child node, to an element, as the last child node

element.attributes

Returns a NamedNodeMap of an element's attributes

element.blur()

Removes focus from an element

element.childElementCount

Returns the number of child elements an element has

element.childNodes

Returns a collection of an element's child nodes (including text and comment nodes)

element.children

Returns a collection of an element's child element (excluding text and comment nodes)

element.classList

Returns the class name(s) of an element

element.className

Sets or returns the value of the class attribute of an element

element.click()

Simulates a mouse-click on an element

element.clientHeight

Returns the height of an element, including padding

element.clientLeft

Returns the width of the left border of an element

element.clientTop

Returns the width of the top border of an element

element.clientWidth

Returns the width of an element, including padding

element.cloneNode()

Clones an element

element.compareDocumentPosition()

Compares the document position of two elements

element.contains()

Returns true if a node is a descendant of a node, otherwise false

element.contentEditable

Sets or returns whether the content of an element is editable or not

element.dir

Sets or returns the value of the dir attribute of an element

element.firstChild

Returns the first child node of an element

element.firstElementChild

Returns the first child element of an element

element.focus()

Gives focus to an element

element.getAttribute()

Returns the specified attribute value of an element node

element.getAttributeNode()

Returns the specified attribute node

element.getElementsByClassName()

Returns a collection of all child elements with the specified class name

element.getElementsByTagName()

Returns a collection of all child elements with the specified tag name

element.getFeature()

Returns an object which implements the APIs of a specified feature

element.hasAttribute()

Returns true if an element has the specified attribute, otherwise false

element.hasAttributes()

Returns true if an element has any attributes, otherwise false

element.hasChildNodes()

Returns true if an element has any child nodes, otherwise false

element.id

Sets or returns the value of the id attribute of an element

element.innerHTML

Sets or returns the content of an element

element.insertBefore()

Inserts a new child node before a specified, existing, child node

element.isContentEditable

Returns true if the content of an element is editable, otherwise false

element.isDefaultNamespace()

Returns true if a specified namespaceURI is the default, otherwise false

element.isEqualNode()

Checks if two elements are equal

element.isSameNode()

Checks if two elements are the same node

element.isSupported()

Returns true if a specified feature is supported on the element

element.lang

Sets or returns the value of the lang attribute of an element

element.lastChild

Returns the last child node of an element

element.lastElementChild

Returns the last child element of an element

element.namespaceURI

Returns the namespace URI of an element

element.nextSibling

Returns the next node at the same node tree level

element.nextElementSibling

Returns the next element at the same node tree level

element.nodeName

Returns the name of a node

element.nodeType

Returns the node type of a node

element.nodeValue

Sets or returns the value of a node

element.normalize()

Joins adjacent text nodes and removes empty text nodes in an element

element.offsetHeight

Returns the height of an element, including padding, border and scrollbar

element.offsetWidth

Returns the width of an element, including padding, border and scrollbar

element.offsetLeft

Returns the horizontal offset position of an element

element.offsetParent

Returns the offset container of an element

element.offsetTop

Returns the vertical offset position of an element

element.ownerDocument

Returns the root element (document object) for an element

element.parentNode

Returns the parent node of an element

element.parentElement

Returns the parent element node of an element

element.previousSibling

Returns the previous node at the same node tree level

element.previousElementSibling

Returns the previous element at the same node tree level

element.querySelector()

Returns the first child element that matches a specified CSS selector(s) of an element

element.querySelectorAll()

Returns all child elements that matches a specified CSS selector(s) of an element

element.removeAttribute()

Removes a specified attribute from an element

element.removeAttributeNode()

Removes a specified attribute node, and returns the removed node

element.removeChild()

Removes a child node from an element

element.replaceChild()

Replaces a child node in an element

element.removeEventListener()

Removes an event handler that has been attached with the addEventListener() method

element.scrollHeight

Returns the entire height of an element, including padding

element.scrollIntoView()

Scrolls the specified element into the visible area of the browser window

element.scrollLeft

Sets or returns the number of pixels an element's content is scrolled horizontally

element.scrollTop

Sets or returns the number of pixels an element's content is scrolled vertically

element.scrollWidth

Returns the entire width of an element, including padding

element.setAttribute()

Sets or changes the specified attribute, to the specified value

element.setAttributeNode()

Sets or changes the specified attribute node

element.style

Sets or returns the value of the style attribute of an element

element.tabIndex

Sets or returns the value of the tabindex attribute of an element

element.tagName

Returns the tag name of an element

element.textContent

Sets or returns the textual content of a node and its descendants

element.title

Sets or returns the value of the title attribute of an element

element.toString()

Converts an element to a string

 

 

nodelist.item()

Returns the node at the specified index in a NodeList

nodelist.length

Returns the number of nodes in a NodeList

 

 

 

7.5.1. nodeType Property

http://www.w3schools.com/jsref/prop_node_nodetype.asp

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

            function getCursorOffset(elem, anchorNode, cursorOffset) {

                if (elem == anchorNode) {

                    if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                        newLine++;

                    }

                    return [cursorOffset, true];

                }

                if (elem.nodeType == 3) {

                    return [cursorOffset + elem.length, false];

                }

                if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                    newLine++;

                }

                var children = elem.childNodes;

                if (children) {

                    for (var i = 0; i < children.length; i++) {

                        var result = getCursorOffset(children[i], anchorNode, cursorOffset);

                        if (result[1]) {

                            return result;

                        }

                        cursorOffset = result[0];

                    }

                }

                return [cursorOffset, false];

            }

...

7.5.2. nodeName Property

http://www.w3schools.com/jsref/prop_node_nodename.asp  

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

            function getCursorOffset(elem, anchorNode, cursorOffset) {

                if (elem == anchorNode) {

                    if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                        newLine++;

                    }

                    return [cursorOffset, true];

                }

                if (elem.nodeType == 3) {

                    return [cursorOffset + elem.length, false];

                }

                if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                    newLine++;

                }

                var children = elem.childNodes;

                if (children) {

                    for (var i = 0; i < children.length; i++) {

                        var result = getCursorOffset(children[i], anchorNode, cursorOffset);

                        if (result[1]) {

                            return result;

                        }

                        cursorOffset = result[0];

                    }

                }

                return [cursorOffset, false];

            }

...

 

8. Object Orientation (OO)

8.1. Inheritance

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance

 

function Regex(pattern, options) {

    RegExp.call(pattern, options);

    if (pattern instanceof RegExp) {

        pattern = pattern.source;

    }

    if (pattern) {

        this.regexGroupStructure = getRegexCompleteGroupingStructure(pattern);

        this.regex = new RegExp(this.regexGroupStructure[0][2], options);

    } else {

        this.regex = new RegExp(pattern, options);

    }

}

 

Regex.prototype = Object.create(RegExp.prototype);

 

Regex.prototype.constructor = Regex;

Regex.prototype.exec = function (str) {

}

 

8.1.1. ERROR

ERROR: Uncaught TypeError: RegExp.prototype.source getter called on non-RegExp object

CAUSE:

function Regex(pattern, options) {

    RegExp.call(this, pattern, options);

    if (this.source) {

        this.regexGroupStructure = getRegexCompleteGroupingStructure(this.source);

        this.regex = new RegExp(this.regexGroupStructure[0][2], options);

    } else {

        this.regex = new RegExp(this.source, options);

    }

}

 

Regex.prototype = Object.create(RegExp.prototype);

Regex.prototype.constructor = Regex;

ALL ATTEMPTS: “Object.getOwnPropertyDescriptor(RegExp.prototype, 'source').get.call(this)” or similar according to http://stackoverflow.com/questions/23077569/proper-way-to-call-superclass-functions-from-subclass failed. Actually already just “this.source” should already have been working! So it seems something is preventing this.

SOLUTION (WORKAROUND): COMPOSITION:

function Regex(pattern, options) {

    if (pattern instanceof RegExp) {

        this.source = pattern.source;

    } else {

        this.source = pattern;

    }

    if (this.source) {

        this.regexGroupStructure = getRegexCompleteGroupingStructure(this.source);

        try {

            this.regex = new RegExp(this.regexGroupStructure[0][2], options);

        } catch (e) {

            new RegExp(this.source, flags);

        }

    } else {

        this.regex = new RegExp(this.source, options);

    }

    this.ignoreCase = this.regex.ignoreCase;

}

 

Regex.prototype = Object.create(RegExp.prototype, {

    source: {

        value: null,

        enumerable: true,

        configurable: true,

        writable: true

    },

    ignoreCase: {

        value: null,

        enumerable: true,

        configurable: true,

        writable: true

    }

});

 

Regex.prototype.constructor = Regex;

 

Regex.prototype.constructor = Regex;

 

 

9. Functionality

 

9.1. Function parameters

http://www.w3schools.com/js/js_function_parameters.asp

Arguments are Passed by Value

The parameters, in a function call, are the function's arguments.

JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations.

If a function changes an argument's value, it does not change the parameter's original value.

Changes to arguments are not visible (reflected) outside the function.

Objects are Passed by Reference

In JavaScript, object references are values.

Because of this, objects will behave like they are passed by reference:

If a function changes an object property, it changes the original value.

Changes to object properties are visible (reflected) outside the function.

...

Parameter Rules

JavaScript function definitions do not specify data types for parameters.

JavaScript functions do not perform type checking on the passed arguments.

JavaScript functions do not check the number of arguments received.

...

Parameter Defaults

If a function is called with missing arguments (less than declared), the missing values are set to: undefined

...

 

 

9.2. Recursive function and for loop

http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript

For example transforming the following data structure:

        $scope.leftTreeData =

                [

                    {

                        "label": "User Left", "id": "role1", "children": [

                        {"label": "subUser1", "id": "role11", "children": []},

                        {

                            "label": "subUser2 Left", "id": "role12", "children": [

                            {

                                "label": "subUser2-1", "id": "role121", "children": [

                                {"label": "subUser2-1-1", "id": "role1211", "children": []},

                                {"label": "subUser2-1-2", "id": "role1212", "children": []}

                            ]

                            }

                        ]

                        }

                    ]

                    },

                    {"label": "Admin", "id": "role2", "children": []},

                    {"label": "Guest", "id": "role3", "children": []}

                ];

Into a map using the “id” field as index:

    function resolve(treeStructure, treeMap) {

        for (var i = 0; i < treeStructure.length; i++) {

            console.log(treeStructure[i].id);

            treeMap[treeStructure[i].id] = treeStructure[i];

            if (treeStructure[i].children.length > 0) {

                resolve(treeStructure[i].children, treeMap)

            }

        }

        return treeMap;

    };

 

9.2.1. Error JavaScript - cannot set property of undefined

TypeError: Cannot set property 'role11' of undefined

    at resolve (two_tree_test_selection_button_map.html:107)

    at resolve (two_tree_test_selection_button_map.html:109)

    at new <anonymous> (two_tree_test_selection_button_map.html:147)

    at Object.e [as invoke] (angular.min.js:39)

    at L.instance (angular.min.js:81)

    at M (angular.min.js:61)

    at h (angular.min.js:54)

    at h (angular.min.js:54)

    at angular.min.js:54

    at angular.min.js:20

CAUSE & SOLUTION: The cause for this error was that in the recursive function see above I forgot 1 parameter:

    function resolve(treeStructure, treeMap) {

        for (var i = 0; i < treeStructure.length; i++) {

            console.log(treeStructure[i].id);

            treeMap[treeStructure[i].id] = treeStructure[i];

            if (treeStructure[i].children.length > 0) {

                resolve(treeStructure[i].children, treeMap)

            }

        }

        return treeMap;

    };

Therefore the first invocation from outside was working fine but the second recursive invocation failed. This is the problem in JavaScript: http://www.w3schools.com/js/js_function_parameters.asp

...

Parameter Rules

JavaScript function definitions do not specify data types for parameters.

JavaScript functions do not perform type checking on the passed arguments.

JavaScript functions do not check the number of arguments received.

...

Parameter Defaults

If a function is called with missing arguments (less than declared), the missing values are set to: undefined

...

 

9.3. Nested function

 

Regex.prototype.exec = function (str) {

    var result = [];

    result.index = [];

    var resultRegex = this.regex.exec(str);

 

    if (!resultRegex) {

        return resultRegex;

    }

    result[0] = resultRegex[0];

    result.index[0] = resultRegex.index;

    result.input = str;

 

    var execInternal = function (strPosition, regexGroupStructureChildren) {

        var currentStrPos = strPosition;

        for (var i = 0; i < regexGroupStructureChildren.length; i++) {

            var index = regexGroupStructureChildren[i][0];

            var originalIndex = regexGroupStructureChildren[i][1];

            if (originalIndex) {

                result[originalIndex] = resultRegex[index];

                if (typeof result[originalIndex] === "undefined") {

                    result.index[originalIndex] = undefined;

                } else {

                    result.index[originalIndex] = currentStrPos;

                }

            }

            if (regexGroupStructureChildren[i][3]) {

                execInternal(currentStrPos, regexGroupStructureChildren[i][3]);

            }

            if (typeof resultRegex[index] !== "undefined") {

                currentStrPos += resultRegex[index].length;

            }

        }

    };

    if (this.regexGroupStructure[0][3]) {

        execInternal(0, this.regexGroupStructure[0][3]);

    }

    return result;

};

 

9.3.1. Performance

The inner function is created / allocated each time the outer function is called.

http://stackoverflow.com/questions/19779752/javascript-nested-function-performance

No. There is no "wasting" problem without an actual test-case that shows otherwise. This idiom (of nested and anonymous functions) is very common in JavaScript and very well-optimized for.

 

Nested functions provide many benefits including self-documenting code, smaller self-contained lexical scopes, and other code isolation/organization advantages.

...

http://stackoverflow.com/questions/28652563/nested-helper-functions-and-performance

In the case of simple helpers, it's good to keep them local because it means you can make them suitable just for your special case and not worry about the extra cruft of a general function

...

 

 

9.4. Copy - Paste

Is based on https://w3c.github.io/editing/execCommand.html

http://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript

...

The JavaScript document.execCommand('copy') support has grown, see the links below for browser updates:

 

    IE10+ (although this document indicates some support was there from IE5.5+).

    Google Chrome 43+ (~April 2015)

    Mozilla Firefox 41+ (shipping ~September 2015)

    Opera 29+ (based on Chromium 42, ~April 2015)

...

JavaScript library: https://github.com/zenorocha/clipboard.js

<!-- 1. Define some markup -->

<button class="btnnn" data-clipboard-text="1">Copy</button>

<button class="btnnn" data-clipboard-text="2">Copy</button>

<button class="btnnn" data-clipboard-text="3">Copy</button>

 

<!-- 2. Include library -->

<script src="../lib/clipboard.min.js"></script>

 

<!-- 3. Instantiate clipboard by passing a string selector -->

<script>

    var clipboard = new Clipboard('.btnnn');

    clipboard.on('success', function (e) {

        console.log(e);

    });

    clipboard.on('error', function (e) {

        console.log(e);

    });

</script>

...

http://www.sitepoint.com/javascript-copy-to-clipboard/

 

 

9.5. console.log

The output of console.log e.g.

        $scope.$watch( 'abc.currentNode', function( newObj, oldObj ) {

            console.log('hello');

            if( $scope.abc && angular.isObject($scope.abc.currentNode) ) {

                console.log( 'Node Selected!!' );

                console.log( $scope.abc.currentNode );

                window.alert($scope.abc.currentNode);

            }

        }, false);

Is displayed browser specific:

9.5.1. Chrome

Open the: Developer Tools: Ctrl+Shift+I: And on the top select the tab “Console”:

 

9.6. Regular Expression - RegExp

file:///media/disk-ssd--s0-v1/data/doc/html/SELFHTML/tgcg.htm

http://www.w3schools.com/js/js_regexp.asp

http://www.w3schools.com/jsref/jsref_obj_regexp.asp

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace

http://stackoverflow.com/questions/2593637/how-to-escape-regular-expression-in-javascript

http://stackoverflow.com/questions/520611/how-can-i-match-multiple-occurrences-with-a-regex-in-javascript-similar-to-phps

becke-ch—js--s0-0-0-v1-0--util--pl--client--regex.js:

//(\u{2003}) - is the unicode value for &emsp; - Unicode in Regular Expression (flag 'u') is supported in ECMAScript 6!!!

// https://mathiasbynens.be/notes/es6-unicode-regex

var regexHtmlToText = RegExp('(&nbsp;)|(\u{2003})|(&emsp;)|(&amp;)|(&lt;)|(&gt;)|(<br>)|(<div>)|(<[^>]*>)', 'gmu');

// In Java respective Web-Kit the unicode regex support is a little bit different i.e. instead of '\u{2003}' and flag 'u' it is '\u2003' without any flag

var regexHtmlToText = RegExp('(&nbsp;)|(\u2003)|(&emsp;)|(&amp;)|(&lt;)|(&gt;)|(<br>)|(<div>)|(<[^>]*>)', 'gm');

var regexHtmlToTextStringArray = [undefined, ' ', '\t', '\t', '&', '<', '>', '\n', '\n', ''];

    var groupStringArray = regex.exec(string);

    while (groupStringArray) {

        if (lastIndex < groupStringArray.index) {

...

        }

        //We ignore the matching group 0 which is matching the whole expression

        for (var i = 1; i < groupStringArray.length; i++) {

...

        }

        lastIndex = regex.lastIndex;

        groupStringArray = regex.exec(string);

    }

9.6.1. Unicode Support

https://mathiasbynens.be/notes/es6-unicode-regex

Unicode-aware regular expressions in ECMAScript 6

 

ECMAScript 6 introduces two new flags for regular expressions:

 

    y enables ‘sticky’ matching.

    u enables various Unicode-related features.

...

becke-ch—js--s0-0-0-v1-0--util--pl--client--regex.js:

//(\u{2003}) - is the unicode value for &emsp; - Unicode in Regular Expression (flag 'u') is supported in ECMAScript 6!!!

// https://mathiasbynens.be/notes/es6-unicode-regex

//(\u{00A0}) - is the unicode value for Line-Feed which is the equivalent to &nbsp;

// http://www.adamkoch.com/2009/07/25/white-space-and-character-160/var regexHtmlToText = RegExp('(&nbsp;)|(\u{2003})|(&emsp;)|(&amp;)|(&lt;)|(&gt;)|(<br>)|(<div>)|(<[^>]*>)', 'gmu');

// In Java respective Web-Kit the unicode regex support is a little bit different i.e. instead of '\u{2003}' and flag 'u' it is '\u2003' without any flag

var regexHtmlToText = RegExp('(&nbsp;)|(\u2003)|(&emsp;)|(&amp;)|(&lt;)|(&gt;)|(<br>)|(<div>)|(<[^>]*>)', 'gm');

 

9.6.2. Unicode Character 'EM SPACE' (U+2003) versus tabulator

http://stackoverflow.com/questions/1571648/html-tab-space-instead-of-multiple-non-breaking-spaces-nbsp

Because in HTML the tabulator ‘\t’ is not supported we use the EM space instead: &emsp;

BUT when copying “&emsp;” into a text field it is converted to an EM-Space character: \u{2003}

 

9.6.3. Back-Reference

http://www.rexegg.com/regex-capture.html

Back references above \9 behave strange and different in every language. In Java-Script they are treated as back-reference if the group is existing otherwise they are treated as character escape sequence.

 

9.7. Cursor position & positioning

http://help.dottoro.com/ljikwsqs.php

https://developer.mozilla.org/en-US/docs/Web/API/Range/setStart

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange

http://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div

http://stackoverflow.com/questions/3972014/get-caret-position-in-contenteditable-div

http://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container/4812022#4812022

http://stackoverflow.com/questions/6249095/how-to-set-caretcursor-position-in-contenteditable-element-div

 

http://stackoverflow.com/questions/7991474/calculate-position-of-selected-text-javascript-jquery

document object: http://help.dottoro.com/ljwxewvs.php

getRangeAt method (selectionRange): http://help.dottoro.com/ljjmnrqr.php

createRange method (document, XMLDocument): http://help.dottoro.com/ljhcexoj.php

Range object: http://help.dottoro.com/ljxsqnoi.php

TextRange object (Only IE & Opera): http://help.dottoro.com/ljgbbkjf.php

 

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

                var windowSelection = window.getSelection();

                if (windowSelection && windowSelection.rangeCount > 0) {

                    cursorPosition = windowSelection.getRangeAt(0).startOffset;

                    newLine = 0;

                    if (element[0] == windowSelection.anchorNode) {

                        //special handling on top node i.e. dealing with empty new-lines

                        topNodeCursorPosition = cursorPosition;

                    } else {

                        topNodeCursorPosition = -1;

                        cursorPosition += getCursorOffset(element[0], windowSelection.anchorNode, 0)[0];

                    }

                }

 

                    var windowSelection = window.getSelection();

                    if (windowSelection && windowSelection.rangeCount > 0) {

                        if (topNodeCursorPosition >= 0) {

                            //special handling on top node i.e. dealing with empty new-lines

                            var range = document.createRange();

                            var sel = window.getSelection();

                            range.setStart(element[0], topNodeCursorPosition);

                            range.collapse(true);

                            sel.removeAllRanges();

                            sel.addRange(range);

                        } else {

                            setCursor(element[0], cursorPosition);

                        }

                    }

 

            function getCursorOffset(elem, anchorNode, cursorOffset) {

                if (elem == anchorNode) {

                    if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                        newLine++;

                    }

                    return [cursorOffset, true];

                }

                if (elem.nodeType == 3) {

                    return [cursorOffset + elem.length, false];

                }

                if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                    newLine++;

                }

                var children = elem.childNodes;

                if (children) {

                    for (var i = 0; i < children.length; i++) {

                        var result = getCursorOffset(children[i], anchorNode, cursorOffset);

                        if (result[1]) {

                            return result;

                        }

                        cursorOffset = result[0];

                    }

                }

                return [cursorOffset, false];

            }

 

            function setCursor(elem, cursorPos) {

                if (elem.nodeType == 3) {

                    if (elem.length > cursorPos || (elem.length == cursorPos && newLine == 0)) {

                        var range = document.createRange();

                        var sel = window.getSelection();

                        range.setStart(elem, cursorPos);

                        range.collapse(true);

                        sel.removeAllRanges();

                        sel.addRange(range);

                        return [cursorPos, true];

                    }

                    return [cursorPos - elem.length, false];

                }

                if (elem.nodeName === 'DIV' || elem.nodeName === 'BR') {

                    if (newLine == 0 && cursorPos == 0) {

                        var range = document.createRange();

                        var sel = window.getSelection();

                        range.setStart(elem, cursorPos);

                        range.collapse(true);

                        sel.removeAllRanges();

                        sel.addRange(range);

                        return [cursorPos, true];

                    }

                    newLine--;

                }

                var children = elem.childNodes;

                if (children) {

                    for (var i = 0; i < children.length; i++) {

                        var result = setCursor(children[i], cursorPos);

                        if (result[1]) {

                            return result;

                        }

                        cursorPos = result[0];

                    }

                }

                return [cursorPos, false];

            }

 

 

9.7.1. Retrieve entire text

The following function retrieves the entire text of a HTML page:

<script type="text/javascript">

function getBodyText(element) {

    if (typeof window.getSelection != "undefined") {

        bodyRange = document.createRange();

        bodyRange.selectNodeContents(document.body);

        bodyText = bodyRange.toString();

    } else if (typeof document.selection != "undefined" &&

            (sel = document.selection).type != "Control") {

        bodyRange = document.body.createTextRange();

        bodyText = bodyRange.text;

    }

    BodyTextTO.setText(bodyText);

    BodyTextTO.markTransferCompleted();

}

</script>

The text is then stored in the transfer object: “BodyTextTO.setText(bodyText); ” which was initially injected from the underlying framework: JavaFX (see “becke-ch--java--s0-0-v1-0”) or Android (see “”) or ...

The function itself is invoked as follows: “getBodyText(document.body)

 

9.7.2. Calculate Position of selected text

The following function the start and end of the selected text:

<script type="text/javascript">

function getSelectionStartEnd(element) {

    var start = 0, end = 0;

    var sel, range, priorRange;

    if (typeof window.getSelection != "undefined") {

        range = window.getSelection().getRangeAt(0);

        priorRange = range.cloneRange();

        priorRange.selectNodeContents(element);

        priorRange.setEnd(range.startContainer, range.startOffset);

        start = priorRange.toString().length;

        end = start + range.toString().length;

    } else if (typeof document.selection != "undefined" &&

            (sel = document.selection).type != "Control") {

        range = sel.createRange();

        priorRange = document.body.createTextRange();

        priorRange.moveToElementText(element);

        priorRange.setEndPoint("EndToStart", range);

        start = priorRange.text.length;

        end = start + range.text.length;

    }

    SelectionStartEndTO.setStart(start);

    SelectionStartEndTO.setEnd(end);

    SelectionStartEndTO.markTransferCompleted();

}

</script>

The text is then stored in the transfer object: “SelectionStartEndTO.setStart(start); ” which was initially injected from the underlying framework: JavaFX (see “becke-ch--java--s0-0-v1-0”) or Android (see “”) or ...

The function itself is invoked as follows: “getSelectionStartEnd(document.body)

 

9.7.3. Retrieve the position (X,Y) of an HTML element

http://stackoverflow.com/questions/442404/retrieve-the-position-x-y-of-an-html-element

http://help.dottoro.com/ljvmcrrn.php

http://xahlee.info/js/js_get_elements.html

http://www.w3schools.com/jsref/met_element_getattribute.asp

http://www.w3schools.com/jsref/dom_obj_all.asp

http://www.w3schools.com/jsref/met_document_getelementsbytagname.asp

...

<script type="text/javascript">

//<![CDATA[

function getReferencesInformation() {

 var reference = document.getElementsByTagName("a");

 for (i = 0; i < reference.length; i++) {

  referenceHref = reference[i].getAttribute("href");

  referenceText = reference[i].innerHTML;

  var rect = reference[i].getBoundingClientRect();

  referenceXPosition = rect.left;

  ReferenceListTO.add(referenceHref,referenceText,referenceXPosition);

 }

}

//]]>

</script>

...

 

 

9.8. contenteditable

http://www.w3schools.com/tags/att_global_contenteditable.asp

http://html5doctor.com/the-contenteditable-attribute/

https://medium.engineering/why-contenteditable-is-terrible-122d8a40e480#.s1lea1mj6

The contenteditable attribute specifies whether the content of an element is editable or not.

 

Note: When the contenteditable attribute is not set on an element, the element will inherit it from its parent.

...

 

9.9. Creating a link without underscore

http://www.computerhope.com/issues/ch000074.htm

becke-ch—diff--s0-0-1-v1-0--singlepage--pl--client--main.html

            <td class="logo-header"><a href="http://www.becke.ch" style="text-decoration: none">becke.ch</a></td>

 

9.10. Error

 

ERROR: Error: [ng:areq] Argument 'GreetingController' is not a function, got undefined

http://errors.angularjs.org/1.5.0-beta.1/ng/areq?p0=GreetingController&p1=not%20a%20function%2C%20got%20undefined

    at angular.js:68

    at assertArg (angular.js:1796)

    at assertArgFn (angular.js:1806)

    at angular.js:9173

    at setupControllers (angular.js:8237)

    at nodeLinkFn (angular.js:8277)

    at compositeLinkFn (angular.js:7687)

    at compositeLinkFn (angular.js:7691)

    at compositeLinkFn (angular.js:7691)

    at compositeLinkFn (angular.js:7691)

 

REASON & SOLUTION: http://stackoverflow.com/questions/25895235/angularjs-error-ngareq-argument-homecontroller-is-not-a-function-got-und

The reason and solution was that I had 2 times “ng-app” defined!

<html lang="en" ng-app>

<head>

    <meta charset="UTF-8">

    <title>Title</title>

    <!--script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js"

            type="text/javascript"></script-->

    <script language="JavaScript" src="../lib/angular.min.js"

            type="text/javascript"></script>

</head>

<body>

<div ng-app="jsonApp">

    <div ng-controller="jsonController">

...

 

10. Performance

https://developers.google.com/web/tools/chrome-devtools/rendering-tools/

 

11. JSON

http://www.w3schools.com/js/js_json.asp

JSON is a format for storing and transporting data.

JSON is often used when data is sent from a server to a web page.

What is JSON?

 

 

JSON Example

var text = '{ "employees" : [' +

'{ "firstName":"John" , "lastName":"Doe" },' +

'{ "firstName":"Anna" , "lastName":"Smith" },' +

'{ "firstName":"Peter" , "lastName":"Jones" } ]}';

The JSON Format Evaluates to JavaScript Objects

The JSON format is syntactically identical to the code for creating JavaScript objects.

Because of this similarity, a JavaScript program can easily convert JSON data into native JavaScript objects.

 

Converting a JSON Text to a JavaScript Object

Use the JavaScript built-in function JSON.parse() to convert the string into a JavaScript object:

var obj = JSON.parse(text);

 

11.1. Escape Characters

http://stackoverflow.com/questions/19176024/how-to-escape-special-characters-in-building-a-json-string

http://www.json.org/

https://www.ietf.org/rfc/rfc4627.txt

 

Code

Outputs

\"

double quote

\\

backslash

\n

new line

\r

carriage return

\t

tab

\b

backspace

\f

form feed

\/

forward slash

 

 

 

 

The representation of strings is similar to conventions used in the C

   family of programming languages.  A string begins and ends with

   quotation marks.  All Unicode characters may be placed within the

   quotation marks except for the characters that must be escaped:

   quotation mark, reverse solidus, and the control characters (U+0000

   through U+001F).

         string = quotation-mark *char quotation-mark

 

         char = unescaped /

                escape (

                    %x22 /          ; "    quotation mark  U+0022

                    %x5C /          ; \    reverse solidus U+005C

                    %x2F /          ; /    solidus         U+002F

                    %x62 /          ; b    backspace       U+0008

                    %x66 /          ; f    form feed       U+000C

                    %x6E /          ; n    line feed       U+000A

                    %x72 /          ; r    carriage return U+000D

                    %x74 /          ; t    tab             U+0009

                    %x75 4HEXDIG )  ; uXXXX                U+XXXX

 

         escape = %x5C              ; \

 

         quotation-mark = %x22      ; "

 

         unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

...

 

 

12. Typescript

https://de.wikipedia.org/wiki/TypeScript

...

TypeScript ist eine vom Unternehmen Microsoft entwickelte Programmiersprache, die auf den Vorschlägen zum zukünftigen ECMAScript-6-Standard[2](JavaScript) basiert. Sprachkonstrukte von Typescript, wie Klassen, Interfaces, Vererbung, Module, anonyme Funktionen, Generics und eine statische Typisierung sollen auch in ECMAScript 6 übernommen werden.[3]

 

Der von Microsoft entwickelte TypeScript-Compiler kompiliert TypeScript-Code nach ECMA Script 3 (ES3), optional auch nach ECMA Script 5 (ES5). Jeder JavaScript-Code ist auch gültiger TypeScript-Code, sodass gängige JavaScript-Bibliotheken (wie z. B. jQuery oder AngularJS) auch in Typescript verwendet werden können.[3]

 

TypeScript unterstützt mit Modulen das Kapseln von Klassen, Interfaces, Funktionen und Variablen in eigene Namensräume. Dabei wird zwischen internen und externen Modulen unterschieden. Interne Module lehnen sich an die Modul-Spezifikation aus ECMAScript 6 an, wohingegen externe Module eine JavaScript-Bibliothek (AMD oder CommonJS) nutzen.

...

https://en.wikipedia.org/wiki/TypeScript

...

TypeScript is a free and open source programming language developed and maintained by Microsoft. It is a strict superset of JavaScript, and adds optional static typing and class-based object-oriented programming to the language. Anders Hejlsberg, lead architect of C# and creator of Delphi and Turbo Pascal, has worked on the development of TypeScript.[2][3][4][5] TypeScript may be used to develop JavaScript applications for client-side or server-side (Node.js) execution.

 

TypeScript is designed for development of large applications and transcompiles to JavaScript.[6] As TypeScript is a superset of JavaScript, any existing JavaScript programs are also valid TypeScript programs.

 

In this sense TypeScript is a preview of what to expect of ECMAScript 6. A unique aspect not in the proposal, but added to TypeScript, is optional static typing that enables static language analysis, which facilitates tooling and IDE support.

 

TypeScript is a language extension that adds features to ECMAScript 5. Additional features include:

 

    Type annotations and compile-time type checking

    Type inference

    Type erasure

    Interfaces

    Enumerated type

    Mixin

    Generic

    Namespaces

    Tuple

    Await

 

The following features are backported from ECMAScript 6:

 

    Classes

    Modules[23]

    Abbreviated "arrow" syntax for anonymous functions

    Optional parameters and default parameters

 

TypeScript compiles to ES3-compatible JavaScript.[24] By default the compiler targets ECMAScript 3, the current prevailing standard, and is also able to generate constructs used in ECMAScript 5.

 

Type annotations

 

TypeScript provides static typing through type annotations to enable type checking at compile time. This is optional and can be ignored to use the regular dynamic typing of JavaScript.

 

function add(left: number, right: number): number {

 return left + right;

}

 

The annotations for the primitive types are number, boolean and string. Weakly- or dynamically-typed structures are of type any.

 

The TypeScript compiler makes use of type inference to infer types when types are not given.

 

Declaration files

When a TypeScript script gets compiled there is an option to generate a declaration file (with the extension .d.ts) that functions as an interface to the components in the compiled JavaScript. In the process the compiler strips away all function and method bodies and preserves only the signatures of the types that are exported. The resulting declaration file can then be used to describe the exported virtual TypeScript types of a JavaScript library or module when a third-party developer consumes it from TypeScript.

 

The concept of declaration files is analogous to the concept of header file found in C/C++.

 

declare module arithmetics {

    add(left: number, right: number): number;

    subtract(left: number, right: number): number;

    multiply(left: number, right: number): number;

    divide(left: number, right: number): number;

}

 

Classes

TypeScript supports ECMAScript 6 classes that integrate the optional type annotations support.

 

class Person {

    private name: string;

    private age: number;

    private salary: number;

 

    constructor(name: string, age: number, salary: number) {

        this.name = name;

        this.age = age;

        this.salary = salary;

    }

   

    toString(): string {

        return `${this.name} (${this.age}) (${this.salary})`; // As of version 1.4

    }

}

 

Generics

TypeScript supports generic programming.[26]

 

Modules and namespaces

TypeScript distinguishes between modules and namespaces. Both features in TypeScript support encapsulation of classes, interfaces, functions and variables into containers. Namespaces (formerly internal modules) utilizes immediately-invoked function expression of JavaScript to encapsulate code, whereas modules (formerly external modules) leverage JavaScript library patterns to do so (AMD or CommonJS).

 

Compiler

The TypeScript compiler, named tsc, is written in TypeScript that can be compiled into regular JavaScript that can be executed in any JavaScript engine in any host, such as a browser.

 

IDE and editor support

 

    JetBrains supports TypeScript with code completion, refactoring and debugging in its IDEs built on IntelliJ platform, such as PhpStorm 6, WebStorm 6, and IntelliJ IDEA,[30] as well as their Visual Studio Add-in and extension, ReSharper 8.1.[31]

 

Integration with build automation tools

 

Using plug-ins, TypeScript can be integrated with build automation tools, including Grunt (grunt-ts[32]), Apache Maven (TypeScript Maven Plugin[33]) and Gradle (TypeScript Gradle Plugin[34]).

 

12.1. ERROR

ERROR: error TS2345: Argument of type ... is not assignable to parameter of type ...

src/app/app.component.ts(76,280): error TS2345: Argument of type 'string[]' is not assignable to parameter of type '(substring: string, ...args: any[]) => string'.

  Type 'string[]' provides no match for the signature '(substring: string, ...args: any[]): string'

src/app/app.component.ts

...

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: string[];

  result: string;

}

...

this.replace.str.replace(new Regex(this.replace.pattern, this.replace.flags), (this.replace.replacementStringArray));

SOLUTION: any

...

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: any;

  result: string;

}

...

this.replace.str.replace(new Regex(this.replace.pattern, this.replace.flags), (this.replace.replacementStringArray));

 

 

13. AngularJS 1

13.1. Downloading

 

Build:

CDN: Why Google CDN?

While downloading and using the AngularJS source code is great for development, we recommend that you source the script from Google's CDN (Content Delivery Network) in your deployed, customer facing app whenever possible. You get the following advantages for doing so:

 

What is Bower?

Bower is a package manager for client-side JavaScript components. For more info please see: https://github.com/bower/bower

 

13.2. Documentation (offline)

http://stackoverflow.com/questions/16263195/how-to-run-angularjs-documentation-localy

 

1. Download the zipped version of the Angular.JS Build, which contains both the builds of AngularJS, as well as documentation and other extras.

2. Unzip the Angular.JS docs folder.

3. Download and install Node.JS.

    Using Mac Terminal, install the npm package http-server globally so that it can be run from the command line.

 

$ npm install -g http-server

 

    cd to the Angular.JS docs folder and start-up http-server.

 

$ http-server -a 127.0.0.1

Starting up http-server, serving ./ on: http://127.0.0.1:8080

 

    Use your browser to view the docs @ http://127.0.0.1:8080/index-production.html

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm install -g http-server

/media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/bin/http-server -> /media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/lib/node_modules/http-server/bin/http-server

/media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/bin/hs -> /media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/lib/node_modules/http-server/bin/http-server

/media/disk-ssd--s0-v1/tool/node-v4.2.4-linux-x64/lib

└─┬ http-server@0.9.0

  ├── colors@1.0.3

  ├── corser@2.0.1

  ├─┬ ecstatic@1.4.1

  │ ├── he@0.5.0

  │ ├── mime@1.3.4

  │ ├── minimist@1.2.0

  │ └── url-join@1.1.0

  ├─┬ http-proxy@1.14.0

  │ ├── eventemitter3@1.2.0

  │ └── requires-port@1.0.0

  ├── opener@1.4.1

  ├─┬ optimist@0.6.1

  │ ├── minimist@0.0.10

  │ └── wordwrap@0.0.3

  ├─┬ portfinder@0.4.0

  │ ├── async@0.9.0

  │ └─┬ mkdirp@0.5.1

  │   └── minimist@0.0.8

  └─┬ union@0.4.4

    └── qs@2.3.3

 

13.2.1. Error GET /angular.min.js" Error (404): "Not found"

ERROR: "GET /angular.min.js" Error (404): "Not found"

[Tue Aug 23 2016 18:10:11 GMT+0200 (CEST)] "GET /angular.min.js" Error (404): "Not found"

[Tue Aug 23 2016 18:10:11 GMT+0200 (CEST)] "GET /angular-animate.js" Error (404): "Not found"

[Tue Aug 23 2016 18:10:11 GMT+0200 (CEST)] "GET /angular-animate.js" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/51.0.2704.79 Chrome/51.0.2704.79 Safari/537.36"

[Tue Aug 23 2016 18:10:11 GMT+0200 (CEST)] "GET /angular-animate.js" Error (404): "Not found"

SOLUTION: Copy these files from the parent-directory into the docs directory.

 

13.3. Setup rich client (java)

  1. 1.Create a gradle java module e.g.  

    1. a.group 'ch.becke' 

    2. b.artifact id 'becke-ch--test--s0-0-v1--angularjs--pl' 

  2. 2.Create the following folder respective sub-folder “/.../becke-ch--test--s0-0-v1--angularjs--pl/src/main/resources/lib(the subfolder “lib” is not required i.e. the resources respective javascript files could as well be placed directly into the directory “resources” but in order to have a clean structure I suggest to put them into a sub-folder called “lib”):  

    1. a.Copy the angularjs javascript library “angular.js(for development and debugging) or “angular.min.js” into this folder.
      Actually I suggest in the application i.e. html file to reference “angular.min.js” and in the IDE use the “angular.js” if possible 

  3. 3.Alternatively (but not suggested because of off-line capability) if the JavaFX (or Swing) client supports remote loading of Java-Script add the following (google) CDN directive to the html page: 

    1. a.<script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js" type="text/javascript"></script> 

    2. b.<script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.js" type="text/javascript"></script> 

 

13.4. Setup web client

Same procedure as “setup rich client” with the following differences:

1. Create a gradle web module. (artifact id I used “becke-ch--test--s0-1-v1--angularjs--pl” (i.e. scope S0-1 to differentiate from rich client)

2./3. In a web application I suggest to use the (google) CDN because of caching and performance or alternatively create a folder “/.../becke-ch--test--s0-1-v1--angularjs--pl/src/main/webapp/resources” and put the JS file there.

 

13.5. Sample Hello World

 

<!DOCTYPE html>

<html lang="en" ng-app>

<head>

    <meta charset="UTF-8">

    <title>Title</title>

    <script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.js"

            type="text/javascript"></script>

</head>

<body>

<div>

    <label>Name:</label>

    <input type="text" ng-model="yourName" placeholder="Enter a name here">

    <hr>

    <h1>Hello {{yourName}}!</h1>

</div>

</body>

</html>

 

13.6. Module

Modularization:

 

becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--main.html:

<head>

    <meta charset="UTF-8">

    <title>becke.ch compare tool</title>

    <script language="JavaScript">

        var url = "http://www--s0-v1.becke.ch/becke-ch--diff--s0-0-v1--singlepage--pl--server-1.1/main-view-json/";

        var downloadUrl = "http://www--s0-v1.becke.ch/becke-ch--diff--s0-0-v1--singlepage--pl--server-1.1/download-result";

        //-->

    </script>

    <script language="JavaScript" src="../lib/angular.js" type="text/javascript"></script>

    <script language="JavaScript" src="../lib/angular.treeview.js" type="text/javascript"></script>

    <script language="JavaScript" src="../lib/angular-sanitize.min.js" type="text/javascript"></script>

    <script language="JavaScript" src="../js/util/becke-ch--js--s0-0-0-v1-0--util--pl--client--regex.js"

            type="text/javascript"></script>

    <script language="JavaScript" src="../angularjs/becke-ch--angularjs--s0-0-0-v1-0--module--pl--client.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../becke-ch--diff--s0-0-v1--singlepage--pl--client/becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../becke-ch--diff--s0-0-v1--singlepage--pl--client/model/becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--model.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../becke-ch--diff--s0-0-v1--singlepage--pl--client/service/becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--service.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../angularjs/filter/becke-ch--angularjs--s0-0-0-v1-0--filter--pl--client--trust-html.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../angularjs/directive/becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--file-model.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../angularjs/directive/becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js"

            type="text/javascript"></script>

    <script language="JavaScript"

            src="../becke-ch--diff--s0-0-v1--singlepage--pl--client/controller/becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--controller.js"

            type="text/javascript"></script>

    <link rel="stylesheet" media="all" type="text/css" id="angular.treeview" href="../css/angular.treeview.css">

    <link rel="stylesheet" media="all" type="text/css" id="default-styles" href="../css/default-styles.css">

 

</head>

...

 

becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client.js:

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client', ['becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module', 'becke-ch--angularjs--s0-0-0-v1-0--filter--pl--module', 'angularTreeview', 'ngSanitize']);

 

becke-ch--angularjs--s0-0-0-v1-0--module--pl--client.js:

angular.module('becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module', []);

angular.module('becke-ch--angularjs--s0-0-0-v1-0--filter--pl--module', []);

 

13.6.1. Error: $injector:unpr - Unknown Provider

https://docs.angularjs.org/error/$injector/unpr

This error results from the $injector being unable to resolve a required dependency. To fix this, make sure the dependency is defined and spelled correctly.

 

 

13.7. View

 

13.7.1. Invoke function after view initialization / page load: ngInit & angular.element(document).ready

https://docs.angularjs.org/api/ng/directive/ngInit

The ngInit directive allows you to evaluate an expression in the current scope.

This directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit, such as for aliasing special properties of ngRepeat, as seen in the demo below; and for injecting data via server side scripting. Besides these few cases, you should use controllers rather than ngInit to initialize values on a scope.

The problem actually is that the module and its structure which is located in the view part of the controller:

...

<html lang="en" ng-app="treeApp">

...

    <div ng-controller="treeController">

...

        <div

                data-angular-treeview="true"

                data-tree-id="abc"

                data-tree-model="treedata"

                data-node-id="id"

                data-node-label="label"

                data-node-children="children">

        </div>

        <div ng-init="childTreeArray.push(abc)"></div>

...

Is initialized after the controller was initialized and therefore the module structure and its variables are empty at the time the controller is initialized and the solution is to put ng-init after the module initialization in the view part.

OR better: http://stackoverflow.com/questions/15458609/execute-function-on-page-load

Use: angular.element(document).ready(function () { ... });

    var treeApp = angular.module('treeApp', ['angularTreeview']);

...

    treeApp.controller('treeController', function ($scope) {

...

        angular.element(document).ready(function () {

            $scope.childTreeArray.push($scope.abc);

        });

    });

 

13.7.2. Key Event Listening

 

13.7.2.1. Cursor Key Listening

http://stackoverflow.com/questions/25464579/is-it-possible-to-listen-for-arrow-keyspress-using-ng-keypress

Change it from ng-keypress to ng-keydown!

...

<html lang="en" ng-app="treeApp">

<head>

...

</head>

<body ng-controller="parentTreeController" ng-keydown="keydownEvent($event)">

...

 

13.7.2.2. Watch for a key-combination

http://stackoverflow.com/questions/19911378/how-to-watch-for-a-keypress-combination-in-angularjs

http://stackoverflow.com/questions/23651954/how-to-detect-pressed-keys-on-the-click-of-angularjs

HTML: becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--main.html

<html lang="en" ng-app="becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client">

<head>

    <script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"

            type="text/javascript"></script>

</head>

<body id="diffControllerId" ng-controller="diffController" ng-keydown="keydownEvent($event)"

      style="font-family: Arial;">

</body>

</html>

 

Controller:  

 

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client').controller('diffController', ['$scope', 'diffService', function ($scope, diffService) {

    //Keydown event function

    $scope.keydownEvent = function (clickEvent) {

        //$scope.clickEvent = simpleKeys(clickEvent);

        for (i = 0; i < $scope.childTreeArray.length; i++) {

            if ($scope.childTreeArray[i]) {

                if (clickEvent.shiftKey && clickEvent.ctrlKey && clickEvent.keyCode == 38) {

                    //cursor up

                    $scope.childTreeArray[i].moveSelectionUp();

                } else if (clickEvent.shiftKey && clickEvent.ctrlKey && clickEvent.keyCode == 40) {

                    //cursor down

                    $scope.childTreeArray[i].moveSelectionDown();

                } else if (clickEvent.shiftKey && clickEvent.ctrlKey && clickEvent.keyCode == 39) {

                    //cursor right

                    $scope.childTreeArray[i].expandSelection();

                } else if (clickEvent.shiftKey && clickEvent.ctrlKey && clickEvent.keyCode == 37) {

                    //cursor left

                    $scope.childTreeArray[i].collapseSelection();

                } else if (clickEvent.shiftKey && clickEvent.ctrlKey && clickEvent.keyCode == 13) {

                    //enter

                    //$scope.childTreeArray[i].collapseSelection();

                    if ($scope.childTreeArray[i].currentNode &&

                        $scope.childTreeArray[i].currentNode.selected == 'selected') {

                        $scope.showHideTree();

                        if ($scope.hideTree) {

                            $scope.showProgressIcon[0] = true;

                            $scope.diffInput.absolutePath = $scope.childTreeArray[i].currentNode.absolutePath;

                            $scope.diffInput.diffAction = 'diffTreeEntry';

                            $scope.diffOutput.treeFrom = $scope.treeFrom;

                            $scope.diffOutput.treeTo = $scope.treeTo;

                            //diffService.post($scope.sessionId, $scope.diffOption, $scope.securityQuestion,

                            //        $scope.diffInput, $scope.diffOutput, $scope.url, $scope.showProgressIcon);

                            diffService.post($scope.sessionId, $scope.diffOption, $scope.securityQuestion,

                                $scope.diffInput, $scope.diffOutput, url, $scope.showProgressIcon);

                        }

                        break;

                    }

                }

            }

        }

    };

}]);

13.7.3. ng-repeat

https://docs.angularjs.org/api/ng/directive/ngRepeat

...

The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.

...

 

HTML: becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--main.html

<html lang="en" ng-app="becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client">

<head>

    <script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"

            type="text/javascript"></script>

</head>

<body id="diffControllerId" ng-controller="diffController" ng-keydown="keydownEvent($event)"

      style="font-family: Arial;">

    <table border width="100%"

           style="font-family:'Courier New', Courier, monospace; table-layout: fixed; word-wrap: break-word;">

        <colgroup>

            <col width="50%">

            <col width="50%">

        </colgroup>

        <tr>

            <th>{{diffInput.fileFrom}}</th>

            <th>{{diffInput.fileTo}}</th>

        </tr>

        <tr ng-repeat="resultTableRowJson in diffOutput.resultTableRowsJson">

            <td>

                <div ng-bind-html="resultTableRowJson.fromHtmlText | trust_html"></div>

            </td>

            <td>

                <div ng-bind-html="resultTableRowJson.toHtmlText | trust_html"></div>

            </td>

        </tr>

    </table>

</body>

</html>

Alternative solutions:

https://docs.angularjs.org/api/ng/directive/ngRepeat

ngRepeat uses $watchCollection to detect changes in the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:

 

When an item is added, a new instance of the template is added to the DOM.

When an item is removed, its template instance is removed from the DOM.

When items are reordered, their respective templates are reordered in the DOM.

To minimize creation of DOM elements, ngRepeat uses a function to "keep track" of all items in the collection and their corresponding DOM elements. For example, if an item is added to the collection, ngRepeat will know that all other items already have DOM elements, and will not re-render them.

 

The default tracking function (which tracks items by their identity) does not allow duplicate items in arrays. This is because when there are duplicates, it is not possible to maintain a one-to-one mapping between collection items and DOM elements.

 

If you do need to repeat duplicate items, you can substitute the default tracking behavior with your own using the track by expression.

 

For example, you may track items by the index of each item in the collection, using the special scope property $index:

 

<div ng-repeat="n in [42, 42, 43, 43] track by $index">

  {{n}}

</div>

...

        <tr ng-repeat="resultTableRowJson in diffOutput.resultTableRowsJson track by $index">

 

http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/

Why would Angular do this? Behind the scenes ngRepeat adds a $$hashKey property to each task to keep track of it. If you replace the original tasks with new tasks objects from the server, even if those are in fact totally identical to your original tasks, they won’t have the $$hashKey property and so ngRepeat won’t know they represent the same elements.

If the records have a unique id then “track by” this id to make sure that only the records that have been added or removed are added or removed from the list and not the whole list is rebuilt:

        <tr ng-repeat="resultTableRowJson in diffOutput.resultTableRowsJson track by resultTableRowJson.id">

 

 

Service:  becke-ch—diff--s0-0-0-v1-0--singlepage--pl--client--service.js:

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client').service('diffService', ['$http', function ($http) {

    this.post = function (sessionId, diffOption, securityQuestion, diffInput, diffOutput, url,

                          showProgressIcon) {

        $http.post(url, fd, {

            transformRequest: angular.identity,

            headers: {'Content-Type': undefined}

        })

            .then(function successCallback(response) {

                    diffOutput.resultTableRowsJson = response.data['resultTableRowsJson'];

    };

}]);

 

13.7.3.1. ERROR: [ngRepeat:dupes]

 

Error: [ngRepeat:dupes] http://errors.angularjs.org/1.5.0/ngRepeat/dupes?p0=resultTableRowJson%20in…sultTableRowsJson%20track%20by%20resultTableRowJson.id&p1=undefined&p2=%7B

    at Error (native)

    at https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:6:416

    at https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:292:254

    at https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:137:302

    at m.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:138:399)

    at m.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:141:341)

    at g (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:94:139)

    at t (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:98:260)

    at XMLHttpRequest.u.onload (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js:99:297)

 

SOLUTION: http://stackoverflow.com/questions/24977103/duplicates-in-a-repeater-are-not-allowed-on-ng-repeat

If I may add an additional reason as to why this can occur...

 

If you are doing this with a JS object [] or {}

 

and you are passing it in to a directive like this

 

<my-directive my-attribute="{{ myObject }}"></my-directive>

Inside the directive you must turn myObject back into an object by doing this

 

...

controller: function( $scope ){

 

  $scope.links = $scope.$eval( $scope.myObject );

....

Then the HTML and ng-repeat will work

 

...

<span class="" ng-repeat="link in links">

...

ngRepeat does not know how to repeat over a single string.

Service:  becke-ch—diff—s0-0-0-v1-0--singlepage--pl--client--service.js:

Instead of:

                    diffOutput.resultTableRowsJson = response.data['resultTableRowsJson'];

Use:

                    diffOutput.resultTableRowsJson = eval(response.data['resultTableRowsJson']);

 

http://webiks.com/the-war-of-good-vs-eval-or-eval-vs-eval/

Eval… the ultimate bane. Nothing can be said that wasn’t said before.  The bottom line is – stay away from it.  Ok, so you don’t know why it is bad for mankind (or JS apps)? Do you know what’s it good for?

 

Security issue – someone can inject a code that would be eval‘d and then executed…

1. Performance – no optimization until runtime, caching issues – you name it.

2. Bad architecture – debugging becomes a mess…

3. These are the 3 major issues mentioned over the web. You can look for more and post below.

 

Ok, now to the point – this is an angular post, and there’s a $ sign in the title, so this means angular has some solution for us, right?

 

Angular’s $scope has a very powerful function that’s called… $eval.  Now, this function works much like the (bad) old eval, only it is good 🙂

 

In short, instead of this:

 

 eval('myObj.' + property);

 

Use the angular $eval:

 

$scope.$eval(property, myObj)

...

 

13.8. Controller

https://docs.angularjs.org/guide/controller

 

13.8.1. Share data between controllers

http://stackoverflow.com/questions/16802857/angularjs-saving-data-between-routes/16806510#16806510

http://stackoverflow.com/questions/22584342/how-do-i-access-the-scope-variable-of-one-controller-from-another-in-angular-js

http://stackoverflow.com/questions/17229256/using-scope-functions-from-a-different-controller-in-angularjs

There exist 2 ways to share data between controllers:

I prefer due to simplicity using scope inheritance - placing the scope objects to be shared into the parent controller.

 

13.9. Scope

 

13.9.1. Watch multiple $scope attributes

http://stackoverflow.com/questions/11952579/watch-multiple-scope-attributes

https://docs.angularjs.org/api/ng/type/%24rootScope.Scope#%24watchGroup

...

        $scope.$watchGroup(['tree_id.currentNodeHead', 'tree_id.currentNodeHead.collapsed'], function

                (newObj, oldObj) {

            console.log('hello currentNodeHead');

            if ($scope.tree_id && angular.isObject($scope.tree_id.currentNodeHead)) {

                console.log('currentNodeHead Node Selected!!');

                console.log($scope.tree_id.currentNodeHead);

            }

        }, false);

...

 

13.10. Filter

13.10.1. AngularJS : Insert HTML into view

http://stackoverflow.com/questions/9381926/angularjs-insert-html-into-view

 

 

 

You can also create a filter like so:

var app = angular.module("demoApp", ['ngResource']);

 

app.filter("trust_html", ['$sce', function($sce) {

  return function(htmlCode){

    return $sce.trustAsHtml(htmlCode);

  }

}]);

Then in the view

<div ng-bind-html="whatever_needs_to_be_sanitized | trust_html"></div>

 

 

 

13.11. Directive

https://docs.angularjs.org/guide/directive

Directives enable the user to create new HTML tags and accordingly create new reusable components.

directive: To create a directive use the function “directive” which takes as input:

 

JavaScript:

...

        var myApp = angular.module('testApp', []);

 

        myApp.directive('fileModel', ['$parse', function ($parse) {

            return {

                restrict: 'A',

                link: function (scope, element, attrs) {

                    var model = $parse(attrs.fileModel);

                    var modelSetter = model.assign;

 

                    element.bind('change', function () {

                        scope.$apply(function () {

                            modelSetter(scope, element[0].files[0]);

                        });

                    });

                }

            };

        }]);

...

HTML:

            <input type="file" file-model="myFile"/>

13.11.1. Passing objects to directives via isolated scope

http://outbottle.com/angularjs-isolate-scope-pass-by-reference/

https://docs.angularjs.org/api/ng/service/$compile#-scope-

https://jsfiddle.net/joshdmiller/FHVD9/

http://stackoverflow.com/questions/14619884/angularjs-passing-object-to-directive

http://stackoverflow.com/questions/32052984/define-function-inside-angular-directives-isolated-scope

http://stackoverflow.com/questions/16546771/how-do-i-pass-multiple-attributes-into-an-angular-js-attribute-directive

The scope property can be false, true, or an object:

 

    false (default): No scope will be created for the directive. The directive will use its parent's scope.

 

    true: A new child scope that prototypically inherits from its parent will be created for the directive's element. If multiple directives on the same element request a new scope, only one new scope is created.

 

    {...} (an object hash): A new "isolate" scope is created for the directive's element. The 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent scope. This is useful when creating reusable components, which should not accidentally read or modify data in the parent scope.

...

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = undefined;

//contenteditable directive: http://stackoverflow.com/questions/14561676/angularjs-and-contenteditable-two-way-binding-doesnt-work-as-expected

angular.module('becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module').directive('contenteditable', function () {

    return {

        restrict: 'A', // only activate on element attribute

        scope: {

            tablemodel: '=', // a pointer to the table-model / table-data we are working on

            tableFunctionHtmlModelRowColumn: '=' // the function that should be executed

            // the function takes as input parameter the html of the current cell, the table-model, the row and column

            // we are currently working on. And returns the modified html that we use to update the cell

            // OR if nothing/undefined is returned then the cell is not updated

        },

        require: '?ngModel', // get a hold of NgModelController

        link: function (scope, element, attrs, ngModel) {

...

            // Listen for change events to enable binding

            element.on('blur keyup change', function () {

                becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = element;

                scope.$apply(read);

            });

 

            function read() {

                var html = element.html();

                if (attrs.stripBr && html == '<br>') {

                    html = '';

                }

 

                var htmlNew = scope.tableFunctionHtmlModelRowColumn(html, scope.tablemodel, attrs.row, attrs.column);

                if (htmlNew) {

                    ngModel.$setViewValue(htmlNew);

                }

            }

        }

    };

});

becke-ch--diff--s0-0-1-v1-0--singlepage--pl--client--main.html:

                        <div contenteditable ng-model="resultTableRowJson.fromToHtmlText[0]"

                             tablemodel="diffOutput.resultTableRowsJson" row="{{$index}}" column="0"

                             table-function-html-model-row-column="diffResultHtmlTableRowJson"></div>

 

 

13.11.2. Acting on events

 

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = undefined;

//contenteditable directive: http://stackoverflow.com/questions/14561676/angularjs-and-contenteditable-two-way-binding-doesnt-work-as-expected

angular.module('becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module').directive('contenteditable', function () {

    return {

        restrict: 'A', // only activate on element attribute

        scope: {

            tablemodel: '=', // a pointer to the table-model / table-data we are working on

            tableFunctionHtmlModelRowColumn: '=' // the function that should be executed

            // the function takes as input parameter the html of the current cell, the table-model, the row and column

            // we are currently working on. And returns the modified html that we use to update the cell

            // OR if nothing/undefined is returned then the cell is not updated

        },

        require: '?ngModel', // get a hold of NgModelController

        link: function (scope, element, attrs, ngModel) {

...

 

            // Listen for change events to enable binding

            element.on('blur keyup change', function (event) {

                var keyCode = event.which || event.keyCode;

                console.log(keyCode);            element.on('blur keyup change', function () {

                if (keyCode === 13) {

                   cursorPosition++;

                }

                becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = element;

                scope.$apply(read);

            });

        }

    };

});

13.11.3. contenteditable

http://stackoverflow.com/questions/28583651/contenteditable-with-ng-model-doesnt-work

http://mehrantm.blogspot.ch/2013/10/how-make-two-way-binding-to-your.html

http://stackoverflow.com/questions/23445516/how-do-i-achieve-two-way-binding-for-a-contenteditable-element-using-ng-bind-htm

http://stackoverflow.com/questions/14561676/angularjs-and-contenteditable-two-way-binding-doesnt-work-as-expected

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = undefined;

//contenteditable directive: http://stackoverflow.com/questions/14561676/angularjs-and-contenteditable-two-way-binding-doesnt-work-as-expected

angular.module('becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module').directive('contenteditable', function () {

    return {

        restrict: 'A', // only activate on element attribute

        scope: {

            tablemodel: '=', // a pointer to the table-model / table-data we are working on

            tableFunctionHtmlModelRowColumn: '=' // the function that should be executed

            // the function takes as input parameter the html of the current cell, the table-model, the row and column

            // we are currently working on. And returns the modified html that we use to update the cell

            // OR if nothing/undefined is returned then the cell is not updated

        },

        require: '?ngModel', // get a hold of NgModelController

        link: function (scope, element, attrs, ngModel) {

...

 

            if (!ngModel) return; // do nothing if no ng-model

            // Specify how UI should be updated

            ngModel.$render = function () {

                element.html(ngModel.$viewValue || '');

                if (becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element == element) {

                    var windowSelection = window.getSelection();

                    if (windowSelection && windowSelection.rangeCount > 0) {

                        if (topNodeCursorPosition >= 0) {

                            //special handling on top node i.e. dealing with empty new-lines

                            var range = document.createRange();

                            var sel = window.getSelection();

                            range.setStart(element[0], topNodeCursorPosition);

                            range.collapse(true);

                            sel.removeAllRanges();

                            sel.addRange(range);

                        } else {

                            setCursor(element[0], cursorPosition);

                        }

                    }

                }

            };

 

            // Listen for change events to enable binding

            element.on('blur keyup change', function () {

                becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = element;

                scope.$apply(read);

            });

        }

    };

});

becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client--main.html:

                        <div contenteditable ng-model="resultTableRowJson.fromToHtmlText[0]"

                             tablemodel="diffOutput.resultTableRowsJson" row="{{$index}}" column="0"

                             table-function-html-model-row-column="diffResultHtmlTableRowJson"></div>

 

13.11.4. Errors

ERROR: Error: [$injector:unpr] Unknown provider: trust_htmlFilterProvider <- trust_htmlFilter

angular.js:12546 Error: [$injector:unpr] Unknown provider: trust_htmlFilterProvider <- trust_htmlFilter

http://errors.angularjs.org/1.5.0-beta.1/$injector/unpr?p0=trust_htmlFilterProvider%20%3C-%20trust_htmlFilter

    at http://localhost:8080/becke-ch--diff--s0-0-v1--singlepage--pl--server-1.1/lib/angular.js:68:12

SOLUTION: https://docs.angularjs.org/error/$injector/unpr

Instead of:

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client', []).directive('contenteditable', function () {…

Use:

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client').directive('contenteditable', function () {...

An unknown provider error can also be caused by accidentally redefining a module using the angular.module API, as shown in the following example.

 

angular.module('myModule', [])

  .service('myCoolService', function () { /* ... */ });

 

angular.module('myModule', [])

  // myModule has already been created! This is not what you want!

  .directive('myDirective', ['myCoolService', function (myCoolService) {

    // This directive definition throws unknown provider, because myCoolService

    // has been destroyed.

  }]);

 

To fix this problem, make sure you only define each module with the angular.module(name, [requires]) syntax once across your entire project. Retrieve it for subsequent use with angular.module(name). The fixed example is shown below.

 

angular.module('myModule', [])

  .service('myCoolService', function () { /* ... */ });

 

angular.module('myModule')

  .directive('myDirective', ['myCoolService', function (myCoolService) {

    // This directive definition does not throw unknown provider.

  }]);

...

 

13.11.5. Error: $digest already in progress

http://stackoverflow.com/questions/12729122/angularjs-prevent-error-digest-already-in-progress-when-calling-scope-apply

ERROR: angular.js:12546 Error: [$rootScope:inprog] $digest already in progress

http://errors.angularjs.org/1.5.0-beta.1/$rootScope/inprog?p0=%24digest

    at angular.js:68

    at beginPhase (angular.js:16415)

    at Scope.$apply (angular.js:16156)

    at HTMLDivElement.<anonymous> (becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:54)

    at HTMLDivElement.eventHandler (angular.js:3299)

    at setCursor (becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:148)

    at setCursor (becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:168)

    at ngModel.$render (becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:42)

    at Object.ngModelWatch (angular.js:25508)

    at Scope.$digest (angular.js:15887)

ISSUE: The issue here is that one directive cell influences the other and they both fire a $digest simultaneously!

SOLUTION: Introduce global locking variable:

becke-ch--angularjs--s0-0-0-v1-0--directive--pl--client--contenteditable-table.js:

becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = undefined;

//contenteditable directive: http://stackoverflow.com/questions/14561676/angularjs-and-contenteditable-two-way-binding-doesnt-work-as-expected

angular.module('becke-ch--angularjs--s0-0-0-v1-0--directive--pl--module').directive('contenteditable', function () {

    return {

        restrict: 'A', // only activate on element attribute

        scope: {

            tablemodel: '=', // a pointer to the table-model / table-data we are working on

            tableFunctionHtmlModelRowColumn: '=' // the function that should be executed

            // the function takes as input parameter the html of the current cell, the table-model, the row and column

            // we are currently working on. And returns the modified html that we use to update the cell

            // OR if nothing/undefined is returned then the cell is not updated

        },

        require: '?ngModel', // get a hold of NgModelController

        link: function (scope, element, attrs, ngModel) {

            // Specify how UI should be updated

            ngModel.$render = function () {

                element.html(ngModel.$viewValue || '');

                if (becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element == element) {

                    var windowSelection = window.getSelection();

                    if (windowSelection && windowSelection.rangeCount > 0) {

                        if (topNodeCursorPosition >= 0) {

                            //special handling on top node i.e. dealing with empty new-lines

                            var range = document.createRange();

                            var sel = window.getSelection();

                            range.setStart(element[0], topNodeCursorPosition);

                            range.collapse(true);

                            sel.removeAllRanges();

                            sel.addRange(range);

                        } else {

                            setCursor(element[0], cursorPosition);

                        }

                    }

                    // $timeout(function () {

                    //     // anything you want can go here and will safely be run on the next digest.

                    // });

                }

            };

...

            // Listen for change events to enable binding

            element.on('blur keyup change', function (event) {

                var keyCode = event.which || event.keyCode;

                becke_ch__angularjs__s0_0_0_v1_0__directive__pl__client__contenteditable_modified_element = element;

                scope.$apply(read);

            });

        }

    };

});

 

 

 

 

13.12. JSON

13.12.1. json

https://docs.angularjs.org/api/ng/filter/json

Allows you to convert a JavaScript object into JSON string.

This filter is mostly useful for debugging. When using the double curly notation the binding is automatically converted to JSON.

Usage

In HTML Template Binding

{{ json_expression | json : spacing}}

In JavaScript

$filter('json')(object, spacing)

Arguments

Returns: string: JSON string.

13.12.2. angular.fromJson

Deserializes a JSON string.

Usage

angular.fromJson(json);

Arguments

json: string: JSON string to deserialize.

Returns: Object, Array, string, number: Deserialized JSON string.

 

13.12.3. How should I escape strings in JSON?

http://stackoverflow.com/questions/3020094/how-should-i-escape-strings-in-json

http://www.ietf.org/rfc/rfc4627.txt

...

Escape it according to the RFC. JSON is pretty liberal: The only characters you must escape are \, ", and control codes (anything less than U+0020).

 

This structure of escaping is specific to JSON. You'll need a JSON specific function. All of the escapes can be written as \uXXXX where XXXX is the UTF-16 code unit¹ for that character. There are a few shortcuts, such as \\, which work as well. (And they result in a smaller and clearer output.)

 

For full details, see the RFC.

 

¹JSON's escaping is built on JS, so it uses \uXXXX, where XXXX is a UTF-16 code unit. For code points outside the BMP, this means encoding surrogate pairs, which can get a bit hairy. (Or, you can just output the character directly, since JSON's encoded for is Unicode text, and allows these particular characters.)

...

    public static String getJsonString(String str) {

        if (str == null) {

            return null;

        }

//        str = str.replace("\\", "\\\\");

//        str = str.replace("\"", "\\\"");

//        str = str.replace("\n", "");

//        return str;

        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < str.length(); i++) {

            switch (str.charAt(i)) {

                case '\\':

                    stringBuilder.append("\\\\");

                    break;

                case '"':

                    stringBuilder.append("\\\"");

                    break;

                case '\n':

                    break;

                default:

                    if (str.charAt(i) <= 20) {

                        stringBuilder.append("\\u").append(String.format("%04d", ((int) str.charAt(i))));

                    } else {

                        stringBuilder.append(str.charAt(i));

                    }

            }

        }

        return stringBuilder.toString();

    }

 

Converting characters to integers in Java

http://stackoverflow.com/questions/19388037/converting-characters-to-integers-in-java

http://stackoverflow.com/questions/275711/add-leading-zeroes-to-number-in-java

                        stringBuilder.append("\\u").append(String.format("%04d", ((int) str.charAt(i))));

 

 

13.13. Tree View

https://github.com/eu81273/angular.treeview

http://jsfiddle.net/eu81273/8LWUc/

 

13.14. Use button to navigate page as a link

http://stackoverflow.com/questions/15847726/is-there-a-simple-way-to-use-button-to-navigate-page-as-a-link-does-in-angularjs 

http://www.w3schools.com/jsref/prop_loc_href.asp

...

    <button ng-click="download('unifiedDiff')">download</button>

 

    $scope.download = function (format){

        location.href = downloadUrl+'?sessionId='+$scope.sessionId[0]+'&format='+format;

    };

...

 

13.15. Call angularjs function using jquery/javascript

http://stackoverflow.com/questions/23648458/call-angularjs-function-using-jquery-javascript

http://stackoverflow.com/questions/16709373/angularjs-how-to-call-controller-function-from-outside-of-controller-component

http://stackoverflow.com/questions/18758997/call-angular-function-with-jquery

 

HTML:

<html lang="en" ng-app="becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client">

<head>

...

    <script language="JavaScript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js" type="text/javascript"></script>

...

</head>

<body id="diffControllerId" ng-controller="diffController" ng-keydown="keydownEvent($event)" style="font-family: Arial;">

...

</body>

</html>

 

AngularJS: Controller: Method:

angular.module('becke-ch--diff--s0-0-0-v1-0--singlepage--pl--client').controller('diffController', ['$scope', 'diffService', function ($scope, diffService) {

...

    $scope.diffFromTo = function (diffAction,fileFrom,fileTo) {

        $scope.diffInput.fileFrom = fileFrom;

        $scope.diffInput.fileTo = fileTo;

        $scope.diff(diffAction);

    };

...

}]);

 

Java-Script (JavaFX):

...

        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {

            @Override

            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State state, Worker.State newState) {

                if (newState == Worker.State.SUCCEEDED) {

                    JSObject jsobj = (JSObject) webEngine.executeScript("window");

                    jsobj.setMember("java", new Bridge(primaryStage));

 

                    webEngine.executeScript("console.log = function(message)\n" +

                            "{\n" +

                            "    java.log(message);\n" +

                            "};");

 

                    File f;

                    String leftFileCmd = getParameters().getNamed().get(LEFT_FILE_CMD);

                    if (leftFileCmd != null) {

                        f = new File(leftFileCmd);

                        if (f.canRead()) {

                            Preferences.userRoot().node(USER_PREFERENCES_ROOT).put(LEFT_FILE, f.getParent());

                        } else {

                            leftFileCmd = null;

                        }

                    }

                    String rightFileCmd = getParameters().getNamed().get(RIGHT_FILE_CMD);

                    if (rightFileCmd != null) {

                        f = new File(rightFileCmd);

                        if (f.canRead()) {

                            Preferences.userRoot().node(USER_PREFERENCES_ROOT).put(RIGHT_FILE, f.getParent());

                        } else {

                            rightFileCmd = null;

                        }

                    }

                    if(leftFileCmd!=null & rightFileCmd!=null){

                        webEngine.executeScript("angular.element(document.getElementById('diffControllerId')).scope()" +

                                ".diffFromTo('diffFiles','"+leftFileCmd+"','"+rightFileCmd+"');");

                        webEngine.executeScript("angular.element(document.getElementById('diffControllerId')).scope()" +

                                ".$apply();");

                    }

                }

            }

        });

 

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        URL location = classLoader.getResource("view/becke-ch--diff--s0-0-1-v1-0--singlepage--pl--client--main.html");

        webEngine.load(location.toString());

...

 

$apply(): The final invocation of “$apply()” is very important in JavaFX otherwise the AngularJS method is not correctly invoked!

 

 

13.16. Server communication

 

13.16.1. Multipart Upload & File Upload

https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

 

HTML:

        <div ng-controller="diffController">

            <td><input type="file" file-model="diffInput.fileFrom"/></td>

            <td><input type="file" file-model="diffInput.fileTo"/></td>

        </div>

JavaScript:

        myApp.directive('fileModel', ['$parse', function ($parse) {

            return {

                restrict: 'A',

                link: function (scope, element, attrs) {

                    var model = $parse(attrs.fileModel);

                    var modelSetter = model.assign;

 

                    element.bind('change', function () {

                        scope.$apply(function () {

                            modelSetter(scope, element[0].files[0]);

                        });

                    });

                }

            };

        }]);

 

 

    diffApp.service('diffService', ['$http', function ($http) {

        this.post = function (sessionId, diffOption, securityQuestion, diffInput, diffOutput, url,

                              showProgressIcon) {

            if (!diffInput.diffAction) {

                return;

            }

            var fd = new FormData();

            fd.append('sessionId', sessionId[0]);

 

            fd.append('lineFilterPatternFrom', diffOption.lineFilterPatternFrom);

            fd.append('lineFilterPatternTo', diffOption.lineFilterPatternTo);

            fd.append('lineFilterCapturingGroupsFrom', diffOption.lineFilterCapturingGroupsFrom);

            fd.append('lineFilterCapturingGroupsTo', diffOption.lineFilterCapturingGroupsTo);

            fd.append('lineFilterCapturingGroupsActionFrom', diffOption.lineFilterCapturingGroupsActionFrom);

            fd.append('lineFilterCapturingGroupsActionTo', diffOption.lineFilterCapturingGroupsActionTo);

 

            fd.append('overallFilterPatternFrom', diffOption.overallFilterPatternFrom);

            fd.append('overallFilterPatternTo', diffOption.overallFilterPatternTo);

            fd.append('overallFilterCapturingGroupsFrom', diffOption.overallFilterCapturingGroupsFrom);

            fd.append('overallFilterCapturingGroupsTo', diffOption.overallFilterCapturingGroupsTo);

            fd.append('overallFilterCapturingGroupsActionFrom', diffOption.overallFilterCapturingGroupsActionFrom);

            fd.append('overallFilterCapturingGroupsActionTo', diffOption.overallFilterCapturingGroupsActionTo);

 

            fd.append('secureQuestionResult', securityQuestion.secureQuestionResult);

            if (diffInput.diffAction == 'diffText') {

                fd.append('fromText', diffInput.fromText);

                fd.append('toText', diffInput.toText);

                diffOutput.treedataFrom[0] = undefined;

                diffOutput.treedataTo[0] = undefined;

            } else if (diffInput.diffAction == 'diffFiles') {

                fd.append('fileFrom', diffInput.fileFrom);

                fd.append('fileTo', diffInput.fileTo);

                diffOutput.treedataFrom[0] = undefined;

                diffOutput.treedataTo[0] = undefined;

            } else if (diffInput.diffAction == 'diffTreeEntry') {

                fd.append('relativePath', diffInput.relativePath);

            } else {

                return;

            }

 

            $http.post(url, fd, {

                        transformRequest: angular.identity,

                        headers: {'Content-Type': undefined}

                    })

                    .then(function successCallback(response) {

                                sessionId[0] = response.data['sessionId'];

                                securityQuestion.leftOperand = response.data['secureQuestionOperandLeft'];

                                securityQuestion.operator = response.data['secureQuestionOperation'];

                                securityQuestion.rightOperand = response.data['secureQuestionOperandRight'];

                                diffOutput.message = response.data['messageResult'];

                                diffOutput.html = response.data['htmlResult'];

                                if (response.data['messageResult']) {

                                    diffOutput.treedataFrom[0] = undefined;

                                    diffOutput.treedataTo[0] = undefined;

                                }

                                if (response.data['fileEntryLinkedJsonFrom']) {

                                    diffOutput.treedataFrom[0] = response.data['fileEntryLinkedJsonFrom'][0];

                                    //treeFrom.calculateTreeNavigationStructure();

                                    diffOutput.treeFrom.calculateTreeNavigationStructure();

                                }

                                if (response.data['fileEntryLinkedJsonTo']) {

                                    diffOutput.treedataTo[0] = response.data['fileEntryLinkedJsonTo'][0];

                                    //treeTo.calculateTreeNavigationStructure();

                                    diffOutput.treeTo.calculateTreeNavigationStructure();

                                }

                                showProgressIcon[0] = false;

                            }

                            , function errorCallback(response) {

                                diffOutput.message = response.statusText;

                                showProgressIcon[0] = false;

                            });

        };

        myApp.controller('myCtrl', ['$scope', 'fileUpload', function ($scope, fileUpload) {

        $scope.diff = function (diffAction) {

            $scope.showProgressIcon[0] = true;

            $scope.diffInput.diffAction = diffAction;

            $scope.diffOutput.treeFrom = $scope.treeFrom;

            $scope.diffOutput.treeTo = $scope.treeTo;

            diffService.post($scope.sessionId, $scope.diffOption, $scope.securityQuestion,

                    $scope.diffInput, $scope.diffOutput, $scope.url, $scope.showProgressIcon);

        };

 

 

 

13.16.2. Session

$http: session: When uploading using $http service the session construct is not working:

        myApp.service('fileUpload', ['$http', function ($http) {

            this.uploadFileToUrl = function (file, uploadUrl) {

                var fd = new FormData();

                fd.append('text','this is some text');

                fd.append('file', file);

                $http.post(uploadUrl, fd, {

                            transformRequest: angular.identity,

                            headers: {'Content-Type': undefined}

                        })

                        .success(function (data) {

                            console.log('success');

                            console.log(data);

                        })

                        .error(function () {

                            console.log('error');

                        });

            }

        }]);

Servlet: Session:

        Integer counter = (Integer) req.getSession().getAttribute("counter");

        if(counter == null){

            counter = 1;

            req.getSession().setAttribute("counter", counter);

        } else {

            counter ++;

            System.out.println("counter" + counter);

        }

Instead create an own session store using static variables:

        String sessionId = req.getParameter("sessionId");

        Map<String, Object> session = SESSION_STORE.get(sessionId);

        if (sessionId == null || session == null) {

            sessionId = UUID.randomUUID().toString();

            session = new HashMap<String, Object>();

            SESSION_STORE.put(sessionId, session);

        }

 

        Integer counter = (Integer) session.get("counter");

        if (counter == null) {

            System.out.println("Initialize counter");

            counter = 1;

            session.put("counter", counter);

        } else {

            counter++;

            System.out.println("counter" + counter);

        }

AngularJS:

        myApp.service('fileUpload', ['$http', function ($http) {

            this.uploadFileToUrl = function (sessionId, file, uploadUrl) {

                var fd = new FormData();

                fd.append('sessionId',sessionId[0]);

                fd.append('text','this is some text');

                fd.append('file', file);

                $http.post(uploadUrl, fd, {

                            transformRequest: angular.identity,

                            headers: {'Content-Type': undefined}

                        })

                        .success(function (data) {

                            console.log('success');

                            sessionId[0] = data['sessionId'];

                        })

                        .error(function () {

                            console.log('error');

                        });

            }

        }]);

 

 

13.16.3. ERROR

 

AngularJS: JavaScript: Issue Client Side: XMLHttpRequest cannot load http://localhost:8080/becke-ch--test--s0-0-v1--json--sl-1.0/jsonservice. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access.

    myApp.controller('jsonController', function ($scope, $http) {

        //myApp.controller('jsonController', function ($scope) {

        $http.get('http://localhost:8080/becke-ch--test--s0-0-v1--json--sl-1.0/jsonservice').success(function (data) {

            $scope.phones = data;

        });

//        $http({method: 'GET', url: 'http://localhost:8080/becke-ch--test--s0-0-v1--json--sl-1.0/jsonservice',

//            headers:{

//                'Access-Control-Allow-Origin': '*',

//                'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',

//                'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',

//                'X-Random-Shit':'123123123'

//            }})

//                .success(function(d){ console.log( "yay" ); })

//                .error(function(d){ console.log( "nope" ); });

    });

SOLUTION: The solution here was to add a header on the server side to allow CORS - details see document “becke-ch--java--s0-0-v1-0”

The approach to fix the header on Client Side DID NOT WORK! I.e. the following apporaches were a waste of time:

        $http({method: 'GET', url: 'http://localhost:8080/becke-ch--test--s0-0-v1--json--sl-1.0/jsonservice',

            headers:{

                'Access-Control-Allow-Origin': '*',

                'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',

                'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',

                'X-Random-Shit':'123123123'

            }})

                .success(function(d){ console.log( "yay" ); })

                .error(function(d){ console.log( "nope" ); });

Respective:

    myApp.config(['$httpProvider', function($httpProvider) {

        $httpProvider.defaults.useXDomain = true;

        delete $httpProvider.defaults.headers.common['X-Requested-With'];

    }

    ]);

SOLUTION” (not recommended): Disable CORS in Web-Browser:

:~$ /opt/google/chrome/chrome --disable-web-security

 
 

14. Angular 2

https://angular.io/

http://jimfrenette.com/2015/04/angularjs-version-2/

At ng-conf 2015 last month it was announced that AngularJS 1.X will continue to reside at angularjs.org and Angular 2.0 will be hosted at angular.io. The new version of Angular is not a major update, it is a complete rewrite.

http://angularjs.blogspot.ch/

Quickstart: Typescript: https://angular.io/docs/ts/latest/quickstart.html

Alternatively you can use Java-Script: https://angular.io/docs/js/latest/quickstart.html

Typescript: Typescript is probably the best way to develop larger Java-Script applications!

In the remaining chapters we will try to develop Angular 2 using typescript!

 

14.1. Setup

There are 2 different ways to perform the setup: Quickstart and CLI. I first started with the quickstart but then encountered issues with deployment and therefore decided to go with CLI. BUT with CLI I encountered issues during setup: “Project name "becke-ch--regex--s0-0-v1--homepage--pl--client" is not valid. New project names must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.”. And therefore I finally decided to go with Quickstart.

14.1.1. Initial Setup

 

Quickstart Setup:

  1. 1.Download & Extract https://github.com/angular/quickstart/archive/master.zip  

  2. 2.Delete the non essential files: 

    1. a.xargs rm -rf < non-essential-files.osx.txt 

      1. i.“.git”: The .git directory only exists if we clone it. If we download then there is no such directory. 

      2. ii..gitignore”: Actually I would not delete this file because it tells which file should not be removed! 

      3. iii.LICENSE”: We can remove the license file respective replace it with our own license file or alternatively update the package.json file with “{ "license": "UNLICENSED"} 

      4. iv.src/favicon.ico”: There is a bug in the “non-essential-files.osx.txt” file. The favicon.ico is removed in the wrong location. 

      5. v.“.travis.yml”, “bs-config.e2e.json”, “CHANGELOG.md”, “e2e”, “favicon.ico”, “karma.conf.js”, “karma-test-shim.js”, “non-essential-files.txt”, “protractor.config.js”, “README.md”: These files can be deleted without any further comment. 

    2. b.rm src/app/*.spec*.ts 

    3. c.rm non-essential-files.osx.txt 

 

CLI Setup:

  1. 1.Verify that you are running at least node 6.9.x and npm 3.x.x by running node -v and npm -v in a terminal/console window. Older versions produce errors, but newer versions are fine. 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ node -v

v4.2.4

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm -v

3.5.2

  1. 2.Update respective install new version according to chapter 3.2 (and don’t forget to update /etc/profiles and restart). 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ node -v

v6.10.1

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm -v

3.10.10

  1. 3.Install the Angular CLI globally: npm install -g @angular/cli 

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:~$ npm install -g @angular/cli

/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/bin/ng -> /media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib/node_modules/@angular/cli/bin/ng

 

> node-sass@4.5.2 install /media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib/node_modules/@angular/cli/node_modules/node-sass

> node scripts/install.js

 

Downloading binary from https://github.com/sass/node-sass/releases/download/v4.5.2/linux-x64-48_binding.node

Download complete  ] - :

Binary saved to /media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib/node_modules/@angular/cli/node_modules/node-sass/vendor/linux-x64-48/binding.node

Caching binary to /home/raoul-becke--s0-v1/.npm/node-sass/4.5.2/linux-x64-48_binding.node

 

> node-sass@4.5.2 postinstall /media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib/node_modules/@angular/cli/node_modules/node-sass

> node scripts/build.js

 

Binary found at /media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib/node_modules/@angular/cli/node_modules/node-sass/vendor/linux-x64-48/binding.node

Testing binary

Binary is fine

/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/lib

└─┬ @angular/cli@1.0.0

  ├── @ngtools/json-schema@1.0.5

  ├─┬ @ngtools/webpack@1.3.0

  │ ├── enhanced-resolve@3.1.0

  ├── webpack-merge@2.6.1

  └── zone.js@0.7.8

 

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0 (node_modules/@angular/cli/node_modules/chokidar/node_modules/fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.1.1: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

 

 

14.1.2. Project Setup

Node.js and npm are essential to modern web development with Angular and other platforms. Node powers client development and build tools. The npm package manager, itself a node application, installs JavaScript libraries.

 

npm is a popular package manager and Angular application developers rely on it to acquire and manage the libraries their apps require.

 

We specify the packages we need in an npm package.json file.

 

To install the package manager NPM (and Node.js) - follow instructions in chapter 3.

 

Quickstart Setup:

  1. 1.Copy the (essential) files from the initial setup (see previous chapter) into the the project folder:  

  2. 2.Edit the package.json file. IntelliJ: When using IntelliJ then TSC (TypeScript) is not really needed because it is already built into intellij – but nevertheless it does not harm. 

{

  "name": "becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client",

  "version": "1.0.0",

  "description": "becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client description",

  "scripts": {

    "build": "tsc -p src/",

    "build:watch": "tsc -p src/ -w",

    "build:e2e": "tsc -p e2e/",

    "serve": "lite-server -c=bs-config.json",

    "serve:e2e": "lite-server -c=bs-config.e2e.json",

    "prestart": "npm run build",

    "start": "concurrently \"npm run build:watch\" \"npm run serve\"",

    "pree2e": "npm run build:e2e",

    "e2e": "concurrently \"npm run serve:e2e\" \"npm run protractor\" --kill-others --success first",

    "preprotractor": "webdriver-manager update",

    "protractor": "protractor protractor.config.js",

    "pretest": "npm run build",

    "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",

    "pretest:once": "npm run build",

    "test:once": "karma start karma.conf.js --single-run",

    "lint": "tslint ./src/**/*.ts -t verbose"

  },

  "keywords": [becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client keywords],

  "author": "Raoul Becke <PRODUCT--sX-vZ@becke.ch> (http://becke.ch/tool/becke-ch--PRODUCT--sX-vZ/)",

  "license": "UNLICENSED",

  "dependencies": {

    "@angular/common": "~4.0.0",

    "@angular/compiler": "~4.0.0",

    "@angular/core": "~4.0.0",

    "@angular/forms": "~4.0.0",

    "@angular/http": "~4.0.0",

    "@angular/platform-browser": "~4.0.0",

    "@angular/platform-browser-dynamic": "~4.0.0",

    "@angular/router": "~4.0.0",

 

    "angular-in-memory-web-api": "~0.3.0",

    "systemjs": "0.19.40",

    "core-js": "^2.4.1",

    "rxjs": "5.0.1",

    "zone.js": "^0.8.4"

  },

  "devDependencies": {

    "concurrently": "^3.2.0",

    "lite-server": "^2.2.2",

    "typescript": "~2.1.0",

 

    "canonical-path": "0.0.2",

    "tslint": "^3.15.1",

    "lodash": "^4.16.4",

    "jasmine-core": "~2.4.1",

    "karma": "^1.3.0",

    "karma-chrome-launcher": "^2.0.0",

    "karma-cli": "^1.0.1",

    "karma-jasmine": "^1.0.2",

    "karma-jasmine-html-reporter": "^0.2.2",

    "protractor": "~4.0.14",

    "rimraf": "^2.5.4",

 

    "@types/node": "^6.0.46",

    "@types/jasmine": "2.5.36"

  },

  "repository": {

    "url": "file:///ws/tool|app/becke-ch--PRODUCT--sX-vZ",

    "type": "git"

  }

}

 

  1. 3.Run “yarn” (or “npm install”) to install all packages used for development
    The size used for development (devDependencies) is very large! 154MB! 

 

CLI Setup:

  1. 1.Change into the parent of the project directory 

  2. 2.Generate a new project and skeleton application by running the following commands: ng new becke-ch—PRODUCT--sX-Y-vZ--USECASE--pl--client  

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij$ ng new becke-ch--regex--s0-0-v1--homepage--pl--client

Project name "becke-ch--regex--s0-0-v1--homepage--pl--client" is not valid. New project names must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.

becke-ch--regex--s0-0-v1--homepage--pl--client

                                       ^

And due to this error we fall back again to quickstart sample! I’ve reported this problem here: https://github.com/angular/angular-cli/issues/3680

Nevertheless if we would have proceeded we would have got the following:

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij$ ng new becke-ch-regex-s00-v1-homepage-pl-client

installing ng

  create .editorconfig

  create README.md

  create src/app/app.component.css

  create src/app/app.component.html

  create src/app/app.component.spec.ts

  create src/app/app.component.ts

  create src/app/app.module.ts

  create src/assets/.gitkeep

  create src/environments/environment.prod.ts

  create src/environments/environment.ts

  create src/favicon.ico

  create src/index.html

  create src/main.ts

  create src/polyfills.ts

  create src/styles.css

  create src/test.ts

  create src/tsconfig.app.json

  create src/tsconfig.spec.json

  create src/typings.d.ts

  create .angular-cli.json

  create e2e/app.e2e-spec.ts

  create e2e/app.po.ts

  create e2e/tsconfig.e2e.json

  create .gitignore

  create karma.conf.js

  create package.json

  create protractor.conf.js

  create tsconfig.json

  create tslint.json

Directory is already under version control. Skipping initialization of git.

Installing packages for tooling via npm.

Installed packages for tooling via npm.

You can `ng set --global packageManager=yarn`.

Project 'becke-ch-regex-s00-v1-homepage-pl-client' successfully created.

 

 

 

 

14.2. Development

All guides and cookbooks have at least 3 core files:

Files outside src/ concern building, deploying, and testing your app. They include configuration files and external dependencies.

Files inside src/ "belong" to your app. Add new Typescript, HTML and CSS files inside the src/ directory, most of them inside src/app, unless told to do otherwise.

14.2.1. app.component.ts

The Component is the most fundamental of Angular concepts. A component manages a view - a piece of the web page where we display information to the user and respond to user feedback.

 

Technically, a component is a class that controls a view template. We'll write a lot of them as we build Angular apps. This is our first attempt so we'll keep it ridiculously simple.

Create an application source sub-folder

 

We like to keep our application code in a sub-folder off the root called app/. Execute the following command in the console window.

 

mkdir app

cd    app

 

Add the component file

 

Now add a file named app.component.ts and paste the following lines:

app/app.component.ts

 

import {Component} from '@angular/core';

 

@Component({

    selector: 'my-app',

    template: '<h1>Hello {{name}}</h1>'

})

export class AppComponent { name = 'Angular'; }

 

Let's review this file in detail, starting at the bottom where we define a class.

 

The Component class

At the bottom of the file is an empty, do-nothing class named AppComponent. When we're ready to build a substantive application, we can expand this class with properties and application logic. Our AppComponent class is empty because we don't need it to do anything in this QuickStart.

 

Modules

Angular apps are modular. They consist of many files each dedicated to a purpose.

 

Most application files export one thing such as a component. Our app.component file exports the AppComponent.

app/app.component.ts (export)

 

export class AppComponent { name = 'Angular'; }

 

The act of exporting turns the file into a module. The name of the file (without extension) is usually the name of the module. Accordingly, 'app.component' is the name of our first module.

 

A more sophisticated application would have child components that descended from AppComponent in a visual tree. A more sophisticated app would have more files and modules, at least as many as it had components.

 

Quickstart isn't sophisticated; one component is all we need. Yet modules play a fundamental organizational role in even this small app.

 

Modules rely on other modules. In TypeScript Angular apps, when we need something provided by another module, we import it. When another module needs to refer to AppComponent, it imports the AppComponent symbol like this:

app/boot.ts (import)

 

import {AppComponent} from './app.component'

 

Angular is also modular. It is a collection of library modules. Each library is itself a module made up of several, related feature modules.

 

When we need something from Angular, we import it from an Angular library module. We need something from Angular right now to help us define metadata about our component.

 

Component Metadata

 

A class becomes an Angular component when we give it metadata. Angular needs the metadata to understand how to construct the view and how the component interacts with other parts of the application.

 

We define a component's metadata with the Angular Component function. We access that function by importing it from the primary Angular library,angular2/core.

app/app.component.ts (import)

 

import {Component} from '@angular/core';

 

In TypeScript we apply that function to the class as a decorator by prefixing it with the @ symbol and invoking it just above the component class:

app/app.component.ts (metadata)

 

    @Component({

        selector: 'my-app',

        template: '<h1>My First Angular 2 App</h1>'

    })

 

@Component tells Angular that this class is an Angular component. The configuration object passed to the @Component method has two fields, a selector and a template.

 

The selector specifies a simple CSS selector for a host HTML element named my-app. Angular creates and displays an instance of our AppComponent wherever it encounters a my-app element in the host HTML.

 

Remember the my-app selector! We'll need that information when we write our index.html

 

The template property holds the component's companion template. A template is a form of HTML that tells Angular how to render a view. Our template is a single line of HTML announcing "My First Angular App".

 

Now we need something to tell Angular to load this component.

 

 

14.2.2. npm start

  1. 1.npm start 

This command runs the TypeScript compiler in "watch mode", recompiling automatically when the code changes. The command simultaneously launches the app in a browser and refreshes the browser when the code changes.

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client$ npm start

 

> becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 prestart /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

> npm run build

 

 

> becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 build /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

> tsc -p src/

 

 

> becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 start /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

> concurrently "npm run build:watch" "npm run serve"

 

[0]

[0] > becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 build:watch /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

[0] > tsc -p src/ -w

[0]

[1]

[1] > becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 serve /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

[1] > lite-server -c=bs-config.json

[1]

[1] ** browser-sync config **

[1] { injectChanges: false,

[1]   files: [ './**/*.{html,htm,css,js}' ],

[1]   watchOptions: { ignored: 'node_modules' },

[1]   server:

[1]    { baseDir: 'src',

[1]      middleware: [ [Function], [Function] ],

[1]      routes: { '/node_modules': 'node_modules' } } }

[1] [BS] Access URLs:

[1]  -------------------------------------

[1]        Local: http://localhost:3000

[1]     External: http://10.255.8.221:3000

[1]  -------------------------------------

[1]           UI: http://localhost:3001

[1]  UI External: http://10.255.8.221:3001

[1]  -------------------------------------

[1] [BS] Serving files from: src

[1] [BS] Watching files...

[1] 17.04.01 21:46:39 200 GET /index.html

[1] 17.04.01 21:46:39 200 GET /styles.css

[1] 17.04.01 21:46:39 200 GET /core-js/client/shim.min.js

 

 

 

14.2.3. Typescript - tsconfig.json

http://www.codelord.net/2015/09/10/angular-2-migration-path-what-we-know/

ES5, ES6 and TypeScript: The core team highly recommends doing Angular 2 in TypeScript. How hard will the conversion be? What will happen to those of us that decide to stay with ES5/6? They say all options will work, but we haven’t seen a lot of love for these setups yet.

https://angular.io/docs/ts/latest/quickstart.html

We must guide the TypeScript compiler with very specific settings.

Add a tsconfig.json file to the project folder and copy/paste the following:

{

  "compilerOptions": {

    "target": "ES5",

    "module": "system",

    "moduleResolution": "node",

    "sourceMap": true,

    "emitDecoratorMetadata": true,

    "experimentalDecorators": true,

    "removeComments": false,

    "noImplicitAny": false

  },

  "exclude": [

    "node_modules"

  ]

}

14.2.4. boot.js

 

Add a new file , boot.ts, to the app/ folder as follows:

app/boot.ts

 

import {bootstrap}    from 'angular2/platform/browser'

import {AppComponent} from './app.component'

 

bootstrap(AppComponent);

 

We need two things to launch the application:

 

    Angular's browser bootstrap function

    The application root component that we just wrote.

 

We import both. Then we call bootstrap, passing in the root component type, AppComponent.

 

Learn why we import bootstrap from angular2/platform/browser and why we create a separate boot.ts file in the appendix below.

 

We've asked Angular to launch the app in a browser with our component at the root. Where will Angular put it?

 

14.2.5. index.html

 

Angular displays our application in a specific location on our index.html. It's time to create that file.

 

We won't put our index.html in the app/ folder. We'll locate it up one level, in the project root folder.

 

cd ..

 

Now create theindex.html file and paste the following lines:

index.html

 

<html>

 

  <head>

    <title>Angular 2 QuickStart</title>

 

    <!-- 1. Load libraries -->

    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>

    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="node_modules/rxjs/bundles/Rx.js"></script>

    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>

 

    <!-- 2. Configure SystemJS -->

    <script>

      System.config({

        packages: {        

          app: {

            format: 'register',

            defaultExtension: 'js'

          }

        }

      });

      System.import('app/boot')

            .then(null, console.error.bind(console));

    </script>

 

  </head>

 

  <!-- 3. Display the application -->

  <body>

    <my-app>Loading...</my-app>

  </body>

 

</html>

 

There are three noteworthy sections of HTML:

 

    We load the JavaScript libraries we need. angular2-polyfills.js and Rx.js are needed by Angular 2.

 

    We configure something called System and ask it to import the boot file we just wrote.

 

    We add the <my-app> tag in the <body>. This is where our app lives!

 

Something has to find and load our application modules. We're using SystemJS to do that. There are other choices and we're not saying SystemJS is the best. We like it and it works.

 

The specifics of SystemJS configuration are out of bounds. We'll briefly describe this particular configuration in the appendix below.

 

When Angular calls the bootstrap function in boot.ts, it reads the AppComponent metadata, finds the my-app selector, locates an element tag named my-app, and loads our application between those tags.

 

14.2.6. Import Libraries & Modules

http://stackoverflow.com/questions/36155723/how-to-import-a-npm-package-in-an-angular2-component

https://medium.com/@s_eschweiler/using-external-libraries-with-angular-2-87e06db8e5d1

http://stackoverflow.com/questions/36772710/how-to-import-non-core-npm-modules-in-angular-2-e-g-to-use-an-encryption-libra

 

14.2.6.1. Add TypeScript Definitions

Create typings file: src/app/custom.typings.d.ts

declare module 'Regex'

Import typings file into: src/main.ts

///<reference path="./app/custom.typings.d.ts"/>

 

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

 

import { AppModule } from './app/app.module';

 

platformBrowserDynamic().bootstrapModule(AppModule);

14.2.6.2. Import JS Files/Libraries

The following is not working!

src/index.html

<!DOCTYPE html>

<html>

<head>

  <base href="/">

  <!--link rel="stylesheet" media="all" type="text/css" id="default-styles"

        href="http://becke.ch/data/becke-ch--style--s0-v1/style/default-styles.css"-->

 

  <link rel="stylesheet" media="all" type="text/css" id="default-styles"

        href="http://localhost/data/becke-ch--style--s0-v1/style/default-styles.css">

  <!--<link rel="stylesheet" media="all" type="text/css" id="default-styles"-->

  <!--href="http://becke.ch/data/becke-ch&#45;&#45;style&#45;&#45;s0-v1/style/default-styles.css">-->

 

  <!--<link rel="stylesheet" media="all" type="text/css" id="custom-styles" href="styles.css">-->

 

  <script src="node_modules/becke-ch--regex--s0-0-v1--base--pl--lib/src/becke-ch--regex--s0-0-v1--base--pl--lib.js"></script>

  <script>

    System.import('main.js').catch(function (err) {

      console.error(err);

    });

  </script>

</head>

 

<body>

        <my-app>Loading AppComponent content here ...</my-app>

</body>

</html>

 

src/app/app.component.ts

import {Component} from '@angular/core';

 

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: string[];

}

 

@Component({

  selector: 'my-app',

  template: `"<code><input [(ngModel)]="replace.str" placeholder="string">".replace(new Regex("<input [(ngModel)]="replace.pattern" placeholder="pattern">", "<input [(ngModel)]="replace.flags" placeholder="flags">"), [<input [(ngModel)]="replace.replacementStrings" placeholder='undefined, replacementString1, undefined, replacementString3, ...'>]) <button (click)="replaceClicked()">Replace</button></code>`

  //template: `hello`

})

export class AppComponent {

  replace: Replace = {

    str: "",

    pattern: "",

    flags: "",

    replacementStrings: "",

    replacementStringArray: []

  };

 

  replaceClicked() {

    console.log('"' + this.replace.str + '".replace(new Regex(' + '"' + this.replace.pattern + '", ' + '"' + this.replace.flags + '"), [' + this.replace.replacementStrings + '])');

    console.log(new Regex('([ ]*,)|([ ]*undefined[ ]*,)|([ ]*undefined[ ]*,)'));

  }

}

 

 

14.2.6.3. Import NPM Modules

Option A is not working!

Option A: This is the preferred method because everything is located in one place!

src/app/app.component.ts

import {Component} from '@angular/core';

import * as Regex from 'node_modules/becke-ch--regex--s0-0-v1--base--pl--lib/src/becke-ch--regex--s0-0-v1--base--pl--lib.js';

 

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: string[];

}

 

@Component({

  selector: 'my-app',

  template: `"<code><input [(ngModel)]="replace.str" placeholder="string">".replace(new Regex("<input [(ngModel)]="replace.pattern" placeholder="pattern">", "<input [(ngModel)]="replace.flags" placeholder="flags">"), [<input [(ngModel)]="replace.replacementStrings" placeholder='undefined, replacementString1, undefined, replacementString3, ...'>]) <button (click)="replaceClicked()">Replace</button></code>`

  //template: `hello`

})

export class AppComponent {

  replace: Replace = {

    str: "",

    pattern: "",

    flags: "",

    replacementStrings: "",

    replacementStringArray: []

  };

 

  replaceClicked() {

    console.log('"' + this.replace.str + '".replace(new Regex(' + '"' + this.replace.pattern + '", ' + '"' + this.replace.flags + '"), [' + this.replace.replacementStrings + '])');

    console.log(new Regex('([ ]*,)|([ ]*undefined[ ]*,)|([ ]*undefined[ ]*,)'));

  }

}

Option B: Map Declaration in systemjs.config.js

src/systemjs.config.js

/**

 * System configuration for Angular samples

 * Adjust as necessary for your application needs.

 */

(function (global) {

  System.config({

    paths: {

      // paths serve as alias

      'npm:': 'node_modules/'

    },

    // map tells the System loader where to look for things

    map: {

      // our app is within the app folder

      'app': 'app',

 

      // angular bundles

      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',

      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',

      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',

      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',

      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',

      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',

      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',

      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

 

      // other libraries

      'rxjs':                      'npm:rxjs',

      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',

 

      // private libraries

      'Regex': 'npm:becke-ch--regex--s0-0-v1--base--pl--lib/src/becke-ch--regex--s0-0-v1--base--pl--lib.js'

    },

    // packages tells the System loader how to load when no filename and/or no extension

    packages: {

      app: {

        defaultExtension: 'js',

        meta: {

          './*.js': {

            loader: 'systemjs-angular-loader.js'

          }

        }

      },

      rxjs: {

        defaultExtension: 'js'

      }

    }

  });

})(this);

src/app/app.component.ts

import {Component} from '@angular/core';

import * as Regex from 'Regex';

 

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: string[];

}

 

@Component({

  selector: 'my-app',

  template: `"<code><input [(ngModel)]="replace.str" placeholder="string">".replace(new Regex("<input [(ngModel)]="replace.pattern" placeholder="pattern">", "<input [(ngModel)]="replace.flags" placeholder="flags">"), [<input [(ngModel)]="replace.replacementStrings" placeholder='undefined, replacementString1, undefined, replacementString3, ...'>]) <button (click)="replaceClicked()">Replace</button></code>`

  //template: `hello`

})

export class AppComponent {

  replace: Replace = {

    str: "",

    pattern: "",

    flags: "",

    replacementStrings: "",

    replacementStringArray: []

  };

 

  replaceClicked() {

    var regex: any;

    console.log('"' + this.replace.str + '".replace(new Regex(' + '"' + this.replace.pattern + '", ' + '"' + this.replace.flags + '"), [' + this.replace.replacementStrings + '])');

    console.log(new Regex('([ ]*,)|([ ]*undefined[ ]*,)|([ ]*undefined[ ]*,)'));

  }

}

 

14.2.6.4. ERROR

ERROR: src/app/app.component.ts(2,19): error TS2307: Cannot find module ...

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client$ npm start

 

> becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 prestart /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

> npm run build

 

 

> becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 build /media/disk-ssd--s0-v1/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch--regex--s0-0-v1--homepage--pl--client

> tsc -p src/

 

src/app/app.component.ts(2,19): error TS2307: Cannot find module 'rgx'.

 

npm ERR! Linux 4.9.0-040900-generic

npm ERR! argv "/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/bin/node" "/media/disk-ssd--s0-v1/tool/node-v6.10.1-linux-x64/bin/npm" "run" "build"

npm ERR! node v6.10.1

npm ERR! npm  v3.10.10

npm ERR! code ELIFECYCLE

npm ERR! becke-ch--regex--s0-0-v1--homepage--pl--client@1.0.0 build: `tsc -p src/`

npm ERR! Exit status 2

...

SOLUTION: See chapters above! First the Typescript definitions needs to be solved!

AND the following import statement is not allowed: import * as Regex from 'node_modules/becke-ch--regex--s0-0-v1--base--pl--lib/src/becke-ch--regex--s0-0-v1--base--pl--lib.js';

 

ERROR: Browser: ERROR TypeError: Regex_1.default is not a constructor

ERROR TypeError: Regex_1.default is not a constructor

Stack trace:

AppComponent.prototype.replaceClicked@http://localhost:3000/app/app.component.js:37:17

View_AppComponent_0/<@ng:///AppModule/AppComponent.ngfactory.js:592:21

viewDef/handleEvent@http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:11812:98

callWithDebugContext@http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:13020:39

...

CAUSE: import Regex from 'Regex';

SOLUTION: import * as Regex from 'Regex';

 

14.2.7. Html Elements: Textarea, Button, Input, Binding

src/app/app.module.ts

import {NgModule}      from '@angular/core';

import {BrowserModule} from '@angular/platform-browser';

import {FormsModule}   from '@angular/forms'; // <-- NgModel lives here

 

import {AppComponent}  from './app.component';

 

@NgModule({

  imports: [

    BrowserModule,

    FormsModule // <-- import the FormsModule before binding with [(ngModel)]

  ],

  declarations: [AppComponent],

  bootstrap: [AppComponent]

})

export class AppModule {

}

src/app/app.component.ts

import {Component} from '@angular/core';

import * as Regex from 'Regex';

 

export class Replace {

  str: string;

  pattern: string;

  flags: string;

  replacementStrings: string;

  replacementStringArray: any;

  result: string;

}

 

@Component({

  selector: 'my-app',

  template: `

<code>"<textarea [(ngModel)]="replace.str" placeholder="string"></textarea>".replace(new

Regex("<input [(ngModel)]="replace.pattern" placeholder="pattern">", "<input maxlength="5" size="5" [(ngModel)]="replace.flags" placeholder="flags">"),

[<input [(ngModel)]="replace.replacementStrings" placeholder='array of replacement strings'>])

<button (click)="replaceClicked()">Replace</button><br>{{replace.result}}

</code>

`

  //template: `hello`

})

export class AppComponent {

  replace: Replace = {

    str: "",

    pattern: "",

    flags: "g",

    replacementStrings: "",

    replacementStringArray: undefined,

    result: ""

  };

 

  replaceClicked() {

    var pattern: string;

    var regex: any;

    var match: any;

 

    pattern = '((,)|([ ]+,)|([ ]*undefined[ ]*,)|([ ]*null[ ]*,)|([ ]*(\'|")(.*?[^\\\\])\\7[ ]*,)|(.*?,))|(($)|([ ]+$)|([ ]*undefined[ ]*$)|([ ]*null[ ]*$)|([ ]*(\'|")(.*?[^\\\\])\\16[ ]*$)|(.*?$))';

 

    regex = new Regex(pattern, 'g');

 

    this.replace.replacementStringArray = [];

    for (var i = 0; i < match.length; i++) {

      if (match[i][2] || match[i][3] || match[i][4]) {

        this.replace.replacementStringArray.push(undefined);

      } else if (match[i][11] === "" || match[i][12] || match[i][13]) {

        this.replace.replacementStringArray.push(undefined);

        break;

      } else if (match[i][5]) {

        this.replace.replacementStringArray.push(null);

      } else if (match[i][14]) {

        this.replace.replacementStringArray.push(null);

        break;

      } else if (match[i][8]) {

        this.replace.replacementStringArray.push(match[i][8]);

      } else if (match[i][17]) {

        this.replace.replacementStringArray.push(match[i][17]);

        break;

      } else {

        var errorStr = 'Error: The replacement string: [' + this.replace.replacementStrings + '] has wrong format! The array of replacement strings needs to be separated by ", " commas and the replacement strings need to be enclosed with double quote: " or single quote: \'. Empty, undefined and null replacement strings are allowed.';

        console.error(errorStr);

        this.replace.result = errorStr;

        return;

      }

    }

    this.replace.result = '"' + this.replace.str + '".replace(new Regex(' + '"' + this.replace.pattern + '", ' + '"' + this.replace.flags + '"), [' + this.replace.replacementStringArray + '])' + '=' + this.replace.str.replace(new Regex(this.replace.pattern, this.replace.flags), (this.replace.replacementStringArray));

  }

 

}

 

 

 

14.3. Build & Deploy

 

Quickstart: https://angular.io/docs/ts/latest/guide/deployment.html

First time steps:

  1. 1.Create project folder in apache htdocs: mkdir .../htdocs/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client 

 

 

Repetitive steps:

  1. 1.In the project folder: .../becke-ch--PRODUCT--sX-vZ/intellij/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client 

    1. a.Edit "./src/index.html": 

Replace:

    <base href="/">

With:

    <base href="/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client/">

https://wiki.selfhtml.org/wiki/HTML/Kopfdaten/base

The HTML <base href="..."/> specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. For example, given the <base href="/my/app/">, the browser resolves a URL such as some/place/foo.jpg into a server request for my/app/some/place/foo.jpg. During navigation, the Angular router uses the base href as the base path to component, template, and module files.

 

    1. b.Synchronize the files: rsync -rt --include="*.js" --include="*.html" --include="*.css" --exclude="*.*" ./src/ $HTDOCS_DIR/$PROJECT_NAME/ 

    2. c.Synchronize the package.json file: rsync -rt ./package.json .../htdocs/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client/ 

    3. d.Apache: Routed apps must fallback to index.html: rsync -rt ./.htaccess .../htdocs/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client/ 

 

Angular apps are perfect candidates for serving with a simple static HTML server. You don't need a server-side engine to dynamically compose application pages because Angular does that on the client-side.

If the app uses the Angular router, you must configure the server to return the application's host page (index.html) when asked for a file that it does not have.

A routed application should support "deep links". A deep link is a URL that specifies a path to a component inside the app. For example, http://www.mysite.com/heroes/42 is a deep link to the hero detail page that displays the hero with id: 42.

.htaccess:

RewriteEngine On  

# If an existing asset or directory is requested go to it as it is

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d

RewriteRule ^ - [L]

 

# If the requested resource doesn't exist, use index.html

RewriteRule ^ /index.html

 

  1. 2.In the apache htdocs project folder: ../htdocs/becke-ch--PRODUCT--sX-Y-vZ--USECASE--pl--client/ 

    1. a.Run the npm/yarn install: yarn install --prod 

 

CLI:

Regular build: ng build

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch-regex-s00-v1-homepage-pl-client$ ng build

Hash: 22ab123030d28682903e                                                              

Time: 6201ms

chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 158 kB {4} [initial] [rendered]

chunk    {1} main.bundle.js, main.bundle.js.map (main) 3.61 kB {3} [initial] [rendered]

chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 9.77 kB {4} [initial] [rendered]

chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.07 MB [initial] [rendered]

chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]

 

Production build: ng build -prod

raoul-becke--s0-v1@hp-elitebook-840-g1--s0-v3:/ws/tool/becke-ch--regex--s0-v1/intellij/becke-ch-regex-s00-v1-homepage-pl-client$ ng build -prod

Hash: 4b374a830ac5dda3f509                                                              

Time: 6845ms

chunk    {0} polyfills.2d45a4c73c85e24fe474.bundle.js (polyfills) 158 kB {4} [initial] [rendered]

chunk    {1} main.784fc4769c9bf48884ad.bundle.js (main) 21.5 kB {3} [initial] [rendered]

chunk    {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 69 bytes {4} [initial] [rendered]

chunk    {3} vendor.57570798817e1962b74d.bundle.js (vendor) 1.1 MB [initial] [rendered]

chunk    {4} inline.5dee7671c6f764541e4f.bundle.js (inline) 0 bytes [entry] [rendered]

 

 

 

 

14.4. Typescript - tsconfig.json

http://www.typescriptlang.org/

 

http://www.codelord.net/2015/09/10/angular-2-migration-path-what-we-know/

ES5, ES6 and TypeScript: The core team highly recommends doing Angular 2 in TypeScript. How hard will the conversion be? What will happen to those of us that decide to stay with ES5/6? They say all options will work, but we haven’t seen a lot of love for these setups yet.

 

http://blog.thoughtram.io/angular/2015/10/24/upgrading-apps-to-angular-2-using-ngupgrade.html

This is an interesting one. When we saw Angular 2 code the very first time, some of us were scared because all of a sudden there were classes and decorators. Despite the fact that we don’t have have to write our Angular 2 apps in TypeScript (as explained in this article), ES2015 is the next standardized version, which means we will write it sooner or later anyways.

 

We wrote about how to write Angular in ES2015 today and if we do plan to upgrade but can’t do it right now, we should definitely write our new components in ES2015 or TypeScript.

 

That being said, it doesn’t really make sense to upgrade existing code to ES2015 or TypeScript. Even though it seems to be a logical step in preparation for upgrade, it doesn’t help us in any way to take the existing and large code base and upgrade it to ES2015 or TypeScript first, before we upgrade the application to Angular 2.

 

If we have to upgrade to Angular 2, it probably makes more sense to just rewrite component by component, without touching the existing code base. But this of course depends on how big our application is.

 

Again, this is just a language upgrade and it doesn’t really help with the upgrade itself, however, it helps us and our team to get used to the new languages features as we’re building components with it.

 

14.5. package.json

http://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies

https://github.com/npm/npm/blob/2e3776bf5676bc24fec6239a3420f377fe98acde/doc/files/package.json.md#devdependencies

 

    dependencies are installed on both:

        npm install from a directory that contains package.json

        npm install $package on any other directory

 

    devDependencies are:

        also installed on npm install on a directory that contains package.json, unless you pass the --production flag (go upvote Gayan Charith's answer)

        not installed on npm install "$package" on any other directory, unless you give it the --dev option.

 

    peerDependencies:

        before 3.0: are always installed if missing, and raise an error if multiple incompatible versions of the dependency would be used by different dependencies.

        expected starting on 3.0 (untested): give a warning if missing on npm install, and you have to solve the dependency yourself manually. When running, if the dependency is missing, you get an error (mentioned by @nextgentech)

 

14.6. Migration AngularJS1 -> AngularJS2

http://angularjs.blogspot.ch/2015/08/angular-1-and-angular-2-coexistence.html

https://docs.google.com/document/d/1xvBZoFuNq9hsgRhPPZOJC-Z48AHEbIBPlOCBTSD8m0Y/edit#

 

http://www.codelord.net/2015/09/10/angular-2-migration-path-what-we-know/

http://www.codelord.net/2015/10/07/angular-2-preparation-killing-controllers/

 

http://blog.thoughtram.io/angular/2015/10/24/upgrading-apps-to-angular-2-using-ngupgrade.html

Here’s a list of changes that are crucial when thinking about upgrading:

 

    Components - Components are the new building blocks when creating applications with Angular 2. Almost everything is a component, even our application itself.

    Inputs/Outputs - Components communicate via inputs and outputs, if they run in the Browser, these are element properties and events. Our article on demystifying Angular 2’s Template syntax explains how they work.

    Content Projection - Basically the new transclusion, but more aligned with the Web Components standard.

    Dependency Injection - Instead of having a single injector for our entire application, in Angular 2 each component comes with its own injector. We have a dedicated article on that too.

 

 

 

15. Landscape

 

 

16. References and glossary

16.1. References

Reference

Location

Remarks

[1]

http://www.becke.ch/convention/naming/ch_becke_convention_naming_s1_v0_9.pdf

Describes the naming convention that should be used.

[2]

http://www.becke.ch/convention/scopeandversion/ch_becke_convention_scope_and_version_s1_v0_9.pdf

Describes the scope and version convention that should be applied.

Table 1: References

16.2. Glossary (terms, abbreviations, acronyms)

Terms / Abbreviations / Acronyms

Description

 

 

Table 2: Glossary

 

 

P.B.0.0.0.0.0.0.A. Appendix

 

16.2.0.0.0.0.0.0.1.1. Appendix A1