Monday, 18 January 2021

Parsing CREATE TABLE statement with Regular Expression

Overview

Usually, we start developing a new system with designing database and then writing codes. If you are not a fan of ORM, you will have to manually writing the code for the data objects and it is very time consuming. To avoid writing the data objects manually, we develop code generator that will generate the basic codes and then we customize it.

To develop code generator that generate data object code, the generator must first understand the table structure. There are two ways to do that.

  1. For MSSQL, we query the INFORMATION_SCHEMA view for gathering the field name, data type and it's attributes.
  2. Parse the CREATE TABLE statement.

The first option is quite easy and straight forward. The catch is that it is database dependant and might not supported in certain database engine. The second option should be more viable because of the CREATE TABLE statement is very much following the ANSI-SQL standard with some minor database dependant feature.

In this article, we will focus in parsing the CREATE TABLE statement with RegEx using JavaScript.

Ways of parsing text

Let's see how many ways of parsing text:

  1. Munching the CREATE TABLE statement character by character

    The naive way of parsing text is to write a program to check one character after another and then look for the "terminator" (i.e., a symbol that mark the end of the current section or statement). Parsing text in this way is error prone and it will take a lot efforts in guessing and testing.

  2. Using RegEx

    With RegEx, it requires to find the pattern in the text and then come out with the expression. Luckily, SQL syntax is well defined and writing the expression should be easier.

    The good thing about this method is that you are focusing on finding a better expression instead of deciding how many characters to be read.

Here it goes

We are going to develop the parser using JavaScript which runs in Node.js and it parses SQLite CREATE TABLE statement. Let's create a .js file, copy the codes and run it in Node.js.


let sql = `   create table if not exists tb_sales (
    id integer primary   key
    , dt date
    , prod_id integer   not   null
    , qty integer default (0) not null
    , unit_price   real
    , amt real 
    , doc_no text null
, cust_code text

, modified_on datetime default current_timestamp,
modified_by text
);
`;

let result;

// The regex for each component:
let rg_tb = /(create\s+table\s+if\s+not\s+exists|create\s+table)\s(?<tb>.*)\s*\(/gim;
let rg_fld = /(\w+\s+text.*|\w+\s+varchar.*|\w+\s+char.*|\w+\s+real.*|\w+\s+float.*|\w+\s+integer.*|\w+\s+int.*|\w+\s+datetime.*|\w+\s+date.*)/gim;
let rg_fld2 = /(?<fname>\w+)\s+(?<ftype>\w+)(?<fattr>.*)/gi;
let rg_not_null = /not\s+null/i
let rg_pk = /primary\s+key/i
let rg_fld_def = /default\s(.+)/gi

// look for table name
result = rg_tb.exec(sql);
console.log('TABLE NAME:', result.groups.tb);

let fld_list = [];

while ((result = rg_fld.exec(sql)) != null) {
    let f = result[0];

    //reset
    rg_fld2.lastIndex = 0;
    let fld_def = rg_fld2.exec(f);

    // remove the field definition terminator.
    let attr = fld_def.groups.fattr.replace(',', '').trim();

    // look for NOT NULL.
    let nullable = !rg_not_null.test(attr);

    // remove NOT NULL.
    let attr2 = attr.replace(rg_not_null, '');

    // look for PRIMARY KEY
    let is_pk = rg_pk.test(attr2);

    // look for DEFAULT
    let def = rg_fld_def.exec(attr2);
    if (def && def.length > 0) {
        def = def[1].trim();
    }
    else {
        def = null;
    }

    // append to the arr
    fld_list.push({
        name: fld_def.groups.fname.trim(),
        type: fld_def.groups.ftype.trim(),
        nullable: nullable,
        pk: is_pk,
        def: def,
        //attr0: attr
    });
}

console.table(fld_list);

Code explains:

  • The CREATE TABLE statement in the above code has a few different formatting, some extra spaces, the comma (field definition terminator) is not always at the beginning of the line and extra blank line. Our target is to make it harder to parse so that we can find out how robust is our expressions.

  • Below the CREATE TABLE statement, we are declaring all the necessary RegEx for each 'section' in the statement. The expression includes,

    • rg_tb - this expression searches for 'CREATE TABLE' and extract the table name.
    • rg_fld - this expression searches for the field definition. The caveat of this expression is that it is able to extract the field definition on per line basis. If any one line contains more than one field, then, it won't work properly.
    • rg_fld2 - this expression is for extracting the field name, data type and other attributes. The most important is that we must set 'rg_fld2.lastIndex=0' before we call rg_fld2.exec(f). This is because after exec(), the lastIndex will be set. The next call to exec() will continue from where it was earlier.
    • rg_not_null - this expression is for detecting NOT NULL keyword. By definition, all fields are nullable (NULL keyword is optional). But for non-nullable field, NOT NULL keyword must exist. This is the reason why we are detecting NOT NULL.
    • rg_pk - this expression is for look for PRIMARY KEY keyword that appear in the field attribute section. In case you have a composite key, this expression will not work properly.
    • rg_fld_def - this expression is to extract the DEFAULT attribute.
  • The result of the above code looks like this:

TABLE NAME: tb_sales
┌─────────┬───────────────┬────────────┬──────────┬───────┬─────────────────────┐
│ (index) │     name      │    type    │ nullable │  pk   │         def         │
├─────────┼───────────────┼────────────┼──────────┼───────┼─────────────────────┤
│    0    │     'id'      │ 'integer'  │   true   │ true  │        null         │
│    1    │     'dt'      │   'date'   │   true   │ false │        null         │
│    2    │   'prod_id'   │ 'integer'  │  false   │ false │        null         │
│    3    │     'qty'     │ 'integer'  │  false   │ false │        '(0)'        │
│    4    │ 'unit_price'  │   'real'   │   true   │ false │        null         │
│    5    │     'amt'     │   'real'   │   true   │ false │        null         │
│    6    │   'doc_no'    │   'text'   │   true   │ false │        null         │
│    7    │  'cust_code'  │   'text'   │   true   │ false │        null         │
│    8    │ 'modified_on' │ 'datetime' │   true   │ false │ 'current_timestamp' │
│    9    │ 'modified_by' │   'text'   │   true   │ false │        null         │
└─────────┴───────────────┴────────────┴──────────┴───────┴─────────────────────┘

So, everything looks good except that the rg_fld is not able to extract multiple fields that appears on a single line. Let's try to solve it by adjusting the expression rg_fld for more than one field definition in the same line. Consider that the paid_amt real appear next to the qty real. The code will look like this:

let sql2 = `unit_price   real
    , amt real 
, qty real, paid_amt real	 
`;

let r2;
while ((r2 = rg_fld.exec(sql2)) != null) {
    console.log('=>', r2[0])
}

And the result shown below is not what we are expecting. The problem is that qty real, paid_amt real was treated as one field instead of two fields.

=> unit_price   real
=> amt real 
=> qty real, paid_amt real

Let's tweak the expression by declaring a new one so that it look for the field definition with terminator (comma symbol) or without the terminator (i.e., the last field definition does not have terminator).

let sql2 = `unit_price   real
    , amt real 
, qty real, paid_amt real	 
`;

let r2;

let t2 = /\w+\s+real\s*,|\w+\s+real.*/gim
while ((r2 = t2.exec(sql2)) != null) {
    console.log('=>', r2[0])
}

And the result is close to what we are looking for and the comma was included in the result which we don't want.

=> unit_price   real
    ,
=> amt real 
,
=> qty real,
=> paid_amt real

Now, let's remove the comma and next line symbol manually.

let sql2 = `unit_price   real
    , amt real 
, qty real, paid_amt real	 
`;

let r2;

let t2 = /\w+\s+real\s*,|\w+\s+real.*/gim
while ((r2 = t2.exec(sql2)) != null) {
    let f = r2[0].replace('\r', '').replace('\n', '').replace(',', '');    
    console.log('=>', f)
}

The following result is clean and ready to apply rg_fld2 expression.

=> unit_price   real    
=> amt real 
=> qty real
=> paid_amt real

By the way, this parser has not been completed. You may have to figure out how to incorporate t2 expression into rg_fld.

Useful links

You will find the CREATE TABLE statement in detail in the following link,

https://sqlite.org/lang_createtable.html

There are many sites in the Internet which explains RegEx in details. Here's two of it which I find very helpful.

https://flaviocopes.com/javascript-regular-expressions/

https://javascript.info/regular-expressions

To test the regular expression that you have written, you may rely on this tool,

https://regexr.com/

Short note for RegEx

  • \w - ASCII alphanumeric.
  • "." - matches any character except newline.
  • \s - white space
  • "+" - one or more occurrence.
  • "*" - zero or more occurrence.
  • "(..)" - the bracket is for creating a 'group'. Please refers to rg_fld2 variable in the above code.

Friday, 13 September 2019

Vertical scrollbar causing column width different between header and cell in spreadsheet

Vertical scrollbar causing column width different between header and cell in spreadsheet. This is a common issue when the HTML page that display on a computer. Whereas, it won't have issue if it is on Android or iOS because the scrollbar is floating on top of the content.

To explain this issue, let says we have a spreadsheet (or "table" view) built with DIV which looks like below:

<style>
.header {
  display:flex;
  flex-direction:row;
}

.item {
  display:flex;
  flex-direction:row;
}

.c1 {
  width:50%;
}

.item-list {
  overflow: hidden;
  overflow-y: scroll;
  height: 80px;
}
</style>

<div class="my-table">

<div class="header">
  <div class="c1">Date</div>
  <div class="c1">Ref #</div> 
</div> 
<div class="item-list">
  <div class="item">
    <div class="c1">1 Sep 2019</div>
    <div class="c1">0001</div> 
  </div>
  <div class="item">
    <div class="c1">1 Sep 2019</div>
    <div class="c1">0002</div> 
  </div>
  <div class="item">
    <div class="c1">1 Sep 2019</div>
    <div class="c1">0003</div> 
  </div>
  <div class="item">
    <div class="c1">1 Sep 2019</div>
    <div class="c1">0004</div>
  </div>
  <div class="item">
    <div class="c1">1 Sep 2019</div>
    <div class="c1">0005</div>
  </div>
</div>
</div>


With the CSS for item-list, a vertical scrollbar will appear once the number of items increased.

The problem with this CSS is that the date and reference number column in the header will have a different width if you compared it with the column in the items.

To solve this, you need to use this style:

(1) you have to use "sticky:

.header{
  position: sticky;
  top: 0;
  left: 0;
  background-color: white;
}

(2) Move the overflow attribute for "item-list" to "my-table":

.my-table {
  position:relative;
  overflow: hidden;
  overflow-y: scroll;
  height: 80px;
}

And that solves the column width issue when there is a vertical scrollbar.


Monday, 27 May 2019

Server-sent event

Server sent event supports the server push from server to browser only.

In Javascript

var sse = null;

function runNow() {
    if (!sse) {
        sse = new EventSource('/sse_stream');

        sse.addEventListener('message',
            function (e) {
                document.getElementById('lbl1').innerText = e.data;
            });

    }
}

function stop() {
    if (sse) {
        sse.close();
        sse = null;
    }
}


Reference:

https://www.html5rocks.com/en/tutorials/eventsource/basics/
https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

Web worker

Summary of web worker

  • Every web worker is a thread on it's own!! Instantiate too many worker instances might degrade your computer performance.
  • The worker will not be able to access the HTML page.
  • All data exchange/communication must be done through postMessage().
  • With web worker, the communication between the HTML/JS and the worker will be more complex.
  • Good thing is that process in the web worker won't affect the HTML page update/redraw.


The JavaScript to that create a web worker 

This script will be added to the HTML page like a normal JS file.

var w;
var lbl1;

function onStart() {
    if (w) {
        return;
    }

    w = new Worker('demo_worker.js');

    lbl1 = $('#lbl1');

    w.onmessage = function (e) {
        if (e.data.t == 'number') {
            lbl1.text('running value=' + e.data.i);
        }
        else {
            console.log(e.data)
        }
    }
}


function onStop() {
    if (w != null) {
        w.terminate();
        w = null;
    }
}

function onSayHelo() {
    if (w) {
        w.postMessage('helo from tab...' + (new Date()));
    }
}

The web worker Javascript file "demo_worker.js"

  • This file will run in it's own thread. 
  • All data exchange must be done through postMessage().
  • The worker is able to execute AJAX call.
  • The worker will not be able to access the HTML page.

var i = 0;

function timedCount() {
    i = i + 1;

    postMessage({
        t: 'number',
        i: '<b>'+ i + '</b>',
        ts: new Date()
    });

    setTimeout("timedCount()", 1000);   
}

function testAjax() {
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function (e) {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // upon loaded succesfully, pass it to the HTML page.
            postMessage({
                t: 'data',
                data: xhr.response
            });
        }
    }

    xhr.open('get', 'test-data.txt');
    xhr.send();   
}

// message from the HTML page.
self.onmessage = function (e) {
    console.log('worker...', e.data)
}

timedCount();
setTimeout(testAjax, 3000)

Monday, 29 October 2018

Print the call stack in console

Here's the code in printing the call stack in console:

var stack = new Error().stack;   
console.log(stack);

Tuesday, 21 November 2017

CSS fill pattern

To create the fill pattern image, check out the following website:

     http://www.patternify.com/

/*dots*/

.inactive_cell2 {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAEklEQVQImWNgYGD4z0AswK4SAFXuAf8EPy+xAAAAAElFTkSuQmCC");
    background-repeat: repeat;
}

To create strips without using any image data,

    https://css-tricks.com/stripes-css/

/*stripes*/
.inactive_cell {   
    background: repeating-linear-gradient( 48deg, #fefefe, #e0e0e1 5px, #eaeaea 5px, #eaeaea 10px );
}

Friday, 17 November 2017

Simple pie chart & doughnut chart with SVG + CSS

You can draw a simple pie chart & doughnut chart with SVG + CSS. This is quite simple and straight forward. But the limitation is that it is able to show 2 sections only.

To change the value of the section, look for stroke-dasharray and change the first value.

.pie2 {
        fill: yellow;
        stroke: green;

        /* max=50 (radius x 2) */
        stroke-width: 50;

        /* 158 = (radius x 2) x 3.142 = 25 x 2 x 3.142 */
        stroke-dasharray: 40 158;

    }
    .chart2 {
        background-color: yellow;
        border-radius: 50%;

        -webkit-transform: rotate(-90deg);
                transform: rotate(-90deg);
    }


    <svg width="100" height="100" class="chart2">    
        <circle r="25" cx="50" cy="50" class="pie2"/>  

    </svg>

To draw a doughnut chart,  

    .doghnut {
        fill: yellow;
        stroke: green;

        stroke-width: 20;
        stroke-dasharray: 180 251;

    }
    .doghnut_chart {
        background-color: yellow;
        border-radius: 50%;

        -webkit-transform: rotate(-90deg);
                transform: rotate(-90deg);
    }

    <svg width="100" height="100" class="doghnut_chart">    
        <circle r="40" cx="50" cy="50" class="doghnut"/>  
    </svg>

Wednesday, 15 November 2017

Javascript that prevents double click on submit button

This is what happening:
  • The user loves "double clicking" on any button even though single click will trigger the action.
  • The Internet connection slows down and the user thought that he did not click on the correct button. So, he decided to click it again even though the waiting time is lesser than 1 second (?!).
To solve this, you need the following JavaScript to ensure that the submit is working with single click only. Note: you may adjust the value of "500" (ms) to whatever value that you want.

var _prev_save_click_ts = null;

function beforeSubmit() {

    if (_prev_save_click_ts != null) {
        var ts = new Date();

        if (ts - _prev_save_click_ts < 500) {
            // user is double clicking.
            return false;
        }
    }

    _prev_save_click_ts = new Date();
    return true;
}

Thursday, 9 November 2017

Easiest way to search without using loop

If you have two sets of data and one set is referencing the other set, you will need to do a "double loop" to iterating through the data. But, there is a way to eliminate one loop and shorten the code.

For example, set 1 is the list of employees and set 2 is the list of working shift.

If you are using FOR loop, your codes will look similar to the following:

var employees = [];
employees.push({name: 'Mike', shift_id:'A'});
employees.push({name: 'Micky', shift_id:'B'});
employees.push({name: 'Mini', shift_id:'C'});

var shifts = [];
shifts.push({id: 'A', start_time: '08:00', end_time: '17:00'});
shifts.push({id: 'B', start_time: '09:00', end_time: '18:00'});

var s;

for (var i = 0; i < employees.length; i++) {
    s = null;

    // look for the shift:
    for (var j = 0; j < shifts.length; j++) {
         if (shifts[j].id == employees[i].shift_id) {
            s = shifts[j];
            break;
        }
    }

     if (s != null){
           console.log(employees[i].name, s.start_time);
     } else {
           console.log(employees[i].name, 'Cannot find the shift record');
     }
}

The JavaScript object is a key value collection:

   o = {};
   o['a'] = 'Apple';
   o['b'] = 'Banana';

And you can access the value:

   console.log(o['b']);

Below is the code that uses the key value collection to store the shift information and it will save us from writing one FOR loop.

var employees = [];
employees.push({name: 'Mike', shift_id:'A'});
employees.push({name: 'Micky', shift_id:'B'});
employees.push({name: 'Mini', shift_id:'C'});

var shifts = {};
shifts['A'] = {id: 'A', start_time: '08:00', end_time: '17:00'};
shifts['B'] = {id: 'B', start_time: '09:00', end_time: '18:00'};

var s;

for (var i = 0; i < employees.length; i++) {
    s = null;

    // look for the shift:
    if (shifts.hasOwnProperty(employees[i].shift_id)) {
            s = shifts[employees[i].shift_id];
           console.log(employees[i].name, s.start_time);
     } else {
           console.log(employees[i].name, 'Cannot find the shift record');
     }
}

Thursday, 2 November 2017

Printing HTML with JavaScript

You want to allow the user from printing current page directly to the printer and here is the recipe:


1. A print button that calls your print function (written in JavaScript).

2. In your print function, you need to do the following thing:

2.1. Inject a hidden iFrame.

2.2. Set the "src" to the page that you have to print. If you are developing a POS (Point of Sales), you may specify the URL of the receipt page to the "src" together with the  receipt number in the query string. For example,

<iframe id="receipt-frame" style="display:none;" src="myReceipt.aspx?refno=123456"/>

Note: the page that you call should return the contents to be printed out. You have two choices to merge the data into the receipt format: (1) do everything at the server side (2) execute client side JavaScript upon page loaded.

2.3. Once you have the content to be printed, you need to call the following function (upon page loaded). This function will send the content to the printer.

  window.onafterprint = function() {
      window.parent.myPrintJobCompleted();
  }

  window.print();

In case you want to inform the parent page that the user has printed the content, you must handle the window.onafterprint event. In the example above, it executes the function myPrintJobCompleted (this function will load with the main page).

Tuesday, 3 October 2017

JavaScript - sending raw text to printer

While I'm working on the receipt printer, I found this nice code to send the raw text to printer. You will have more freedom and control over the print out.

function doPrint(rawText) {
  var printWindow = window.open();
  printWindow.document.open('text/plain')
  printWindow.document.write(rawText);
  printWindow.document.close();
  printWindow.focus();
  printWindow.print();
  printWindow.close();
}


Reference

https://stackoverflow.com/questions/36570689/javascript-send-raw-text-to-printer-no-server-requests-method-calls-able-to

Notes

In the receipt printer driver, goto Advanced tab and change the driver to "generic/text only". Then, the following codes will print the raw text.

Tuesday, 26 September 2017

Decoupling the development of front end and back end

We used to develop the entire system using ASP.Net web form or MVC. It sounds logical to build everything with the back end coding except for some validation processes using JavaScript (which runs in the client browser).

The problem with this approach is that it's very hard to shorten the development time because the file sharing is the big headache when the team gets bigger. Parallel development requires massive collaboration.

For example, you want to develop an Online Shopping cart which has the catalog for public access. If you are using ASP.Net web form to develop the system, the front end and the back end will be either in one file (ASPX) or two files (ASPX + ASPX.CS). If you are using MVC, it's very hard to to sync the source codes among the programmer because it has controller, page, style, etc.

To enable the parallel development, the front end and the back end should be decoupled.
  • The front end should be build from the scratch with HTML, CSS + JavaScript. 
  • The back end will be develop in Generic Handler (ASHX) in ASP.Net/C#. This ASHX provides an interface for the client to submit their query, processes by the web server and then response back to the client.
The benefits with this approach:
  • The front end developer will have the freedom changing the CSS styles without affecting the back end coding. Rearranging the layout without have to get permission from the back end programmer.
  • The back end developer will have to focus on processing the incoming request and response with the appropriate data. Any changes in the back end will not affect the front end.
There is only one thing that both the front end and back end developers must agree: the API style. Whether you want the REST API or a simple URL API (please refers to System design with ASHX web services (JQuery + AJAX + partial HTML UI) ).
 
This is great. Isn't it?


Wednesday, 23 August 2017

Something about the z-index

In CSS, z-index is the property to control the 3D Z position of the element (for example DIV). This property is useful when you have element that has absolute or fixed position.

In the real work application, we use z-index for the date picker, time picker, numeric keypad, any popup list, prompt, etc.

Here is the find out:


1. If you set the z-index for the DIV, it works as expected. Not strange thing will happen in this simplest case.

<body>
   <div class="container1">helo</div>
<body> 

2.But, if you have the following structure, then, it might work unexpectedly.

First of all, if you set the z-index for the inner1 & inner2, the z-index is relative to container1. While container2 is relative to the body.


<body>
   <div class="container1">Container 1
      <div class="inner1">Inner 1</div>
      <div class="inner2">Inner 2</div>
   </div>

    <div class="container2">Container 2
    </div>
<body>

For example, you have the following settings for the z-index where the final output is container2 is always at the top that covers container1 and hence it covers inner1 and inner2.

container1 - z-index: 100
    inner1 - z-index: 300
    inner2 - z-index: 400

container2 - z-index: 200

All DIV elements have the following settings.

position: absolute;
top: 0;
left:0;
width:100px;
height:100px;
overflow:hidden;

Calculating age

Calculating age using moment.js is very simple:

   var birth_date = new Date(1966,1,1)
   var age = moment().diff(birth_date, 'years', true);


Thursday, 17 August 2017

User interface with HTML+CSS+JS

Let's build the user interface with HTML+CSS+JS and then build the back end program with any web programming language (ASP.Net, PHP, etc) or objective-C for iOS.

This strategy decouple the front end and back end which leads to shorter development and higher customer satisfaction.

From the front end aspect:
  • We build the prototype in a shorter time.
  • We build a back end program using Javascript that simulate the AJAX call between the front end and back end. This script does not rely on any database and web server. It will be loaded and running within the browser context. So, the AJAX call simulation does not required a complex development environment setup.
  • The prototype can be build with any tool as simple as a text file editor + a browser to test the prototype.
  • The user can "see' and "feel" the prototype. It's not talking on a "paper" and the user must "imagine" how it works.
  • This prototype will be uploaded to any web server for discussion purpose.
  • Now, we build a more stable front end regardless of which OS platform.
  • It solves the problem with "installation".
From the back end aspect:
  • The back end can be built with any programming language (ASP.Net, PHP, etc) or Objective-C for iOS.
  • The back end program should only provides the correct API for AJAX request and response.
  • The back end program can be build parallel with the front end.
Finally, we are reusing the HTML+CSS+JS to build front for web app, mobile app and Windows client. Now, our front end designer and back end programmer can work parallel which really cut down lots of time in sync the shared source files.

Cheers!!


Wednesday, 12 July 2017

Avoiding uncertainty with "this"

Most of the time, we don't know what is "this"? Is it a "window", jQuery object, or what is it. It is difficult to debug and make the code to work.

One of the easiest solution that I found is to capture the context into "self" and then all public functions to be declared with the object function. For example, sayHelo() will always referring to the same context as you call the setMyName().

function myClass() {
  var self = this;
  var name;

  this.setMyName = function (s) { name = s; };
  this.getMyName = function() { return name; };
 
  this.sayHelo = function() { return self.getMyName(); };

}

var c = new myClass();
c.setMyName('Mickey');
console.log(c.sayHelo());


Wednesday, 18 January 2017

Spinner generator

The following website provides an easy way to generate the spinner animation in 3 output: SVG, CSS and GIF. This tool is great and very helpful.

http://loading.io/

Wednesday, 14 December 2016

TinyMCE


If you allow user from uploading file, you need the following code to initialize the uploading process where '#sel_file' is "<input type='file'>":

    var my_file_callback = null;

    var uf = $('#sel_file');
    uf.change(function (e) {
        var c0 = $(this);
        var f2 = c0[0].files[0];
       
        // use XMLHttpRequest to upload the image file to the server.

        //<<------//<<------//<<------//<<------
        // then, show the image file on the browser.
        // we need to specify the full url of the file.
        my_file_callback('http://localhost/test/' + f2.name, { alt: 'you have selected a image file' });

        //<<------//<<------//<<------//<<------
    });


To initialize the TinyMCE:

    tinymce.init({
        //selector: 'textarea',
        selector: '.template_div .msg_body',
        plugins: [
               'advlist autolink lists link image charmap anchor',
               'searchreplace visualblocks code fullscreen',
               'insertdatetime table contextmenu paste code'
        ],
        toolbar: 'undo redo | bold italic underline fontsizeselect | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',

        fontsize_formats: '8pt 10pt 12pt 14pt 18pt 24pt 36pt',
        height: '200',
        removed_menuitems: 'newdocument',
        relative_urls: false,
        remove_script_host: false,
        convert_urls: true,

        file_browser_callback_types: 'image',
        file_picker_callback: function (callback, value, meta) {
            // get the callback reference
            my_file_callback = callback;

            // show the file selection browser.
            $('#sel_file').trigger('click');
        },

        setup: function (editor) {
            editor.on('init', function () {
                // this will be call for the initial setup.
                // call your function OR below code to set the the contents.

                 tinymce.get('your textarea control-id').setContent('this is my contents....', { format: 'raw' });
            });
       }

    });

Thursday, 1 December 2016

Changing the URL in the address bar with JQuery

Changing the URL in the address bar with JQuery is quite straight forward. The purpose of this technique is to resolve the user support for the "single page application" (i.e., all contents were loaded by JQuery).

I have modified the technique used by the following article in order to avoid the security error raised by the browser. It appends the "anchor" to the URL.

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script type="text/javascript">
        function ChangeUrl(page, url) {
            if (typeof (history.pushState) != "undefined") {
                var i = window.location.href.indexOf('#');
                if (i > 0) {
                    url = window.location.href.substring(0, i) + url;
                }
                else {
                    url = window.location.href + url;
                }
               
                var obj = { Page: page, Url: url };
                history.pushState(obj, obj.Page, obj.Url);
            } else {
                alert("Browser does not support HTML5.");
            }
        }
        $(function () {
            $("#button1").click(function () {
                ChangeUrl('Page1', '#Page1');
            });
            $("#button2").click(function () {
                ChangeUrl('Page2', '#Page2');
            });
            $("#button3").click(function () {
                ChangeUrl('Page3', '#Page3');
            });
        });
    </script>
    <input type="button" value="Page1" id="button1" />
    <input type="button" value="Page2" id="button2" />
    <input type="button" value="Page3" id="button3" />


Reference

http://www.aspsnippets.com/Articles/Change-URL-in-Browser-Address-Bar-without-reloading-using-JavaScript-and-jQuery.aspx

We are moving

We are moving this blog to our new blog site: https://ciysys.com/blog/nodejs.htm