From fa612b221d2d7d4309c0d48ef8bdfc1756054ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=20=D0=9C=D0=B5=D0=B7=D0=B8?= =?UTF-8?q?=D0=BD?= Date: Fri, 15 Apr 2016 20:43:09 +0300 Subject: [PATCH 1/2] templates --- Dropdown.js | 15 ++++++++++++++- index.html | 32 ++++++++++++++++++++------------ main.js | 43 ++++++++++++++++++++++++++++++++++++++++--- style.css | 2 ++ 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/Dropdown.js b/Dropdown.js index 9f46766..1fc456c 100644 --- a/Dropdown.js +++ b/Dropdown.js @@ -2,18 +2,28 @@ 'use strict'; class Dropdown { - constructor (options) { + constructor (options, data) { this.el = options.el; + this._template = document.getElementById(options.template).innerHTML; + this.data = data; + this._itemSelectCallbacks = []; this._initEvents(); } + + render () { + this.el.innerHTML = TemplateEngine(this._template, this.data); + } /** * Add classname dropdown_open to element */ open () { this.el.classList.add('dropdown_open'); + setTimeout(() => { + document.body.addEventListener('click', this._onBodyClick); + }, 50); } /** @@ -21,6 +31,7 @@ */ close () { this.el.classList.remove('dropdown_open'); + document.body.removeEventListener('click', this._onBodyClick); } /** @@ -47,6 +58,8 @@ } _initEvents () { + this._onBodyClick = this.close.bind(this); + this.el.addEventListener('click', this._onClick.bind(this)); } diff --git a/index.html b/index.html index 2792f09..6998283 100644 --- a/index.html +++ b/index.html @@ -4,19 +4,27 @@ My first menu - - + + diff --git a/main.js b/main.js index 8f771c9..9996992 100644 --- a/main.js +++ b/main.js @@ -1,7 +1,44 @@ (function () { + 'use strict'; + var TemplateEngine = function(html, options) { + var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0, match; + var add = function(line, js) { + js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') : + (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : ''); + return add; + } + while(match = re.exec(html)) { + add(html.slice(cursor, match.index))(match[1], true); + cursor = match.index + match[0].length; + } + add(html.substr(cursor, html.length - cursor)); + code += 'return r.join("");'; + return new Function(code.replace(/[\r\t\n]/g, '')).apply(options); + } + + window.TemplateEngine = TemplateEngine; +})(); + +(function () { + 'use strict'; //Use our component - window.menu = new Dropdown({ - el: document.querySelector('.js-dropdown') - }); + let els = document.querySelectorAll('.js-dropdown'), + instances = []; + + [1,2,3,4].forEach(num => { + let dropdown = new Dropdown({ + el: document.createElement('div'), + template: 'DropdownTmpl' + }, { + title: `My ${num} title`, + items: [ + 'first', + 'second' + ] + }); + + document.body.appendChild(dropdown.el); + dropdown.render(); + }) })(); \ No newline at end of file diff --git a/style.css b/style.css index bdf31fa..4ae3240 100644 --- a/style.css +++ b/style.css @@ -1,6 +1,8 @@ .dropdown { --fz: 40px; --width: 10em; + display: inline-block; + -webkit-user-select: none; } .dropdown, .dropdown__list { From dd7ea9ba86d9604bbd44fd658df7006ed6ed8dc9 Mon Sep 17 00:00:00 2001 From: Artem Mezin Date: Sat, 2 Jul 2016 19:10:23 +0300 Subject: [PATCH 2/2] smth --- 1.bundle.js | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++ Dropdown.js | 9 ++- Gruntfile.js | 0 bundle.js | 140 ++++++++++++++++++++++++++++++++ index.html | 3 +- main.js | 48 ++++++----- model.js | 83 +++++++++++++++++++ template.js | 20 +++++ 8 files changed, 491 insertions(+), 32 deletions(-) create mode 100644 1.bundle.js create mode 100644 Gruntfile.js create mode 100644 bundle.js create mode 100644 model.js create mode 100644 template.js diff --git a/1.bundle.js b/1.bundle.js new file mode 100644 index 0000000..47a24b3 --- /dev/null +++ b/1.bundle.js @@ -0,0 +1,220 @@ +webpackJsonp([1],[ +/* 0 */, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function () { + 'use strict'; + var TemplateEngine = function(html, options) { + var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0, match; + var add = function(line, js) { + js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') : + (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : ''); + return add; + } + while(match = re.exec(html)) { + add(html.slice(cursor, match.index))(match[1], true); + cursor = match.index + match[0].length; + } + add(html.substr(cursor, html.length - cursor)); + code += 'return r.join("");'; + return new Function(code.replace(/[\r\t\n]/g, '')).apply(options); + } + + return TemplateEngine; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function () { + 'use strict'; + + class Model { + constructor(options, data) { + this.id = options.id || null; + this.url = this._makeUrl(); + + this.data = data || { foo: 'bar' }; + } + + _makeUrl () { + return 'https://jsru.firebaseio.com/rest/model' + (this.id ? `/${this.id}/` : '/') +'data.json'; + } + + save () { + // 1. Создаём новый объект XMLHttpRequest + var XHR = (window.XMLHttpRequest && "onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; + + var xhr = new XHR(); + + // 2. Конфигурируем его + xhr.open('POST', this.url, true); + + // 3. Отсылаем запрос + xhr.send(JSON.stringify(this.data)); + + xhr.onreadystatechange = function() { // (3) + if (xhr.readyState != 4) return; + + if (xhr.status != 200) { + alert(xhr.status + ': ' + xhr.statusText); + } else { + this.id = JSON.parse(xhr.responseText).name + // this.url = this._makeUrl(); + } + }.bind(this); + + return xhr; + } + + fetch () { + + if (!this.id) { + return alert('Нечего загружать!') + } + + // 1. Создаём новый объект XMLHttpRequest + var XHR = (window.XMLHttpRequest && "onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; + + var xhr = new XHR(); + + // 2. Конфигурируем его + xhr.open('GET', this.url, true); + + // 3. Отсылаем запрос + xhr.send(); + + xhr.onreadystatechange = function() { // (3) + if (xhr.readyState != 4) return; + + if (xhr.status != 200) { + alert(xhr.status + ': ' + xhr.statusText); + } else { + var data = JSON.parse(xhr.responseText); + + if (data[this.id]) { + this.setData(data[this.id]); + } + } + }.bind(this) + + return xhr; + } + + setData (data) { + this.data = data; + } + } + + //Export + return Model; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function (TemplateEngine) { + + 'use strict'; + + class Dropdown { + constructor (options, data) { + this.el = options.el; + + this._template = document.getElementById('DropdownTmpl').innerHTML; + this.data = data; + + this._itemSelectCallbacks = []; + this._initEvents(); + } + + render () { + this.el.innerHTML = TemplateEngine(this._template, this.data); + } + + /** + * Add classname dropdown_open to element + */ + open () { + this.el.classList.add('dropdown_open'); + setTimeout(() => { + document.body.addEventListener('click', this._onBodyClick); + }, 50); + } + + /** + * Remove classname dropdown_open to element + */ + close () { + this.el.classList.remove('dropdown_open'); + document.body.removeEventListener('click', this._onBodyClick); + } + + /** + * Open or close? + */ + toggle () { + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + } + + /** + * Set callback on user select event + * @param {Function} callback + */ + onSelect (callback) { + this._itemSelectCallbacks.push(callback); + } + + isOpen () { + return this.el.classList.contains('dropdown_open'); + } + + _initEvents () { + this._onBodyClick = this.close.bind(this); + + this.el.addEventListener('click', this._onClick.bind(this)); + } + + _onClick (event) { + if (event.target.classList.contains('dropdown__item')) { + event.preventDefault(); + this._onItemClick(event); + } else { + this.toggle(); + } + } + + _onItemClick (event) { + var itemHtml = event.target.innerHTML; + this.el.querySelector('.js-title').innerHTML = itemHtml; + + this._itemSelectCallbacks.forEach(callback => { + callback({ + el: this.el, + item: this, + text: itemHtml + }); + }); + + this.close(); + } + + + + //TODO: method addItem + } + + //EXPORT + return Dropdown; + + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + +/***/ } +]); \ No newline at end of file diff --git a/Dropdown.js b/Dropdown.js index 1fc456c..4161d18 100644 --- a/Dropdown.js +++ b/Dropdown.js @@ -1,11 +1,12 @@ -(function () { +define('./template', function (TemplateEngine) { + 'use strict'; class Dropdown { constructor (options, data) { this.el = options.el; - this._template = document.getElementById(options.template).innerHTML; + this._template = document.getElementById('DropdownTmpl').innerHTML; this.data = data; this._itemSelectCallbacks = []; @@ -93,6 +94,6 @@ } //EXPORT - window.Dropdown = Dropdown; + return Dropdown; -})(); \ No newline at end of file +}); \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..e69de29 diff --git a/bundle.js b/bundle.js new file mode 100644 index 0000000..44eb949 --- /dev/null +++ b/bundle.js @@ -0,0 +1,140 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // install a JSONP callback for chunk loading +/******/ var parentJsonpFunction = window["webpackJsonp"]; +/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) { +/******/ // add "moreModules" to the modules object, +/******/ // then flag all "chunkIds" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0, callbacks = []; +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(installedChunks[chunkId]) +/******/ callbacks.push.apply(callbacks, installedChunks[chunkId]); +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ for(moduleId in moreModules) { +/******/ modules[moduleId] = moreModules[moduleId]; +/******/ } +/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules); +/******/ while(callbacks.length) +/******/ callbacks.shift().call(null, __webpack_require__); + +/******/ }; + +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // object to store loaded and loading chunks +/******/ // "0" means "already loaded" +/******/ // Array means "loading", array contains callbacks +/******/ var installedChunks = { +/******/ 0:0 +/******/ }; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = function requireEnsure(chunkId, callback) { +/******/ // "0" is the signal for "already loaded" +/******/ if(installedChunks[chunkId] === 0) +/******/ return callback.call(null, __webpack_require__); + +/******/ // an array means "currently loading". +/******/ if(installedChunks[chunkId] !== undefined) { +/******/ installedChunks[chunkId].push(callback); +/******/ } else { +/******/ // start chunk loading +/******/ installedChunks[chunkId] = [callback]; +/******/ var head = document.getElementsByTagName('head')[0]; +/******/ var script = document.createElement('script'); +/******/ script.type = 'text/javascript'; +/******/ script.charset = 'utf-8'; +/******/ script.async = true; + +/******/ script.src = __webpack_require__.p + "" + chunkId + ".bundle.js"; +/******/ head.appendChild(script); +/******/ } +/******/ }; + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + __webpack_require__.e/* require */(1, function(__webpack_require__) { var __WEBPACK_AMD_REQUIRE_ARRAY__ = [__webpack_require__(1), __webpack_require__(2), __webpack_require__(3)]; (function (TemplateEngine, Model, Dropdown) { + 'use strict'; + //Use our component + let els = document.querySelectorAll('.js-dropdown'), + instances = []; + + [1,2,3,4].forEach(num => { + let dropdown = new Dropdown({ + el: document.createElement('div') + }, { + title: `My ${num} title`, + items: [ + 'first', + 'second' + ] + }); + + document.body.appendChild(dropdown.el); + dropdown.render(); + }); + + + let myModel = new Model({}, { + someStr: '123' + }); + console.log('set: ', myModel.data, myModel.id); + + myModel.save(); + console.log('saved: ', myModel.data, myModel.id); + + myModel.fetch(); + console.log('fetched: ', myModel.data, myModel.id); + + + + }.apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__));}); + + + + + +/***/ } +/******/ ]); \ No newline at end of file diff --git a/index.html b/index.html index 6998283..9c13564 100644 --- a/index.html +++ b/index.html @@ -26,7 +26,6 @@ - - + \ No newline at end of file diff --git a/main.js b/main.js index 9996992..4b5aaa9 100644 --- a/main.js +++ b/main.js @@ -1,25 +1,5 @@ -(function () { - 'use strict'; - var TemplateEngine = function(html, options) { - var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0, match; - var add = function(line, js) { - js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') : - (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : ''); - return add; - } - while(match = re.exec(html)) { - add(html.slice(cursor, match.index))(match[1], true); - cursor = match.index + match[0].length; - } - add(html.substr(cursor, html.length - cursor)); - code += 'return r.join("");'; - return new Function(code.replace(/[\r\t\n]/g, '')).apply(options); - } - - window.TemplateEngine = TemplateEngine; -})(); - -(function () { +require(['./template', './model', './Dropdown'], +function (TemplateEngine, Model, Dropdown) { 'use strict'; //Use our component let els = document.querySelectorAll('.js-dropdown'), @@ -27,8 +7,7 @@ [1,2,3,4].forEach(num => { let dropdown = new Dropdown({ - el: document.createElement('div'), - template: 'DropdownTmpl' + el: document.createElement('div') }, { title: `My ${num} title`, items: [ @@ -39,6 +18,23 @@ document.body.appendChild(dropdown.el); dropdown.render(); - }) + }); + + + let myModel = new Model({}, { + someStr: '123' + }); + console.log('set: ', myModel.data, myModel.id); + + myModel.save(); + console.log('saved: ', myModel.data, myModel.id); + + myModel.fetch(); + console.log('fetched: ', myModel.data, myModel.id); + + + +}); + + -})(); \ No newline at end of file diff --git a/model.js b/model.js new file mode 100644 index 0000000..9c7b56e --- /dev/null +++ b/model.js @@ -0,0 +1,83 @@ +define(function () { + 'use strict'; + + class Model { + constructor(options, data) { + this.id = options.id || null; + this.url = this._makeUrl(); + + this.data = data || { foo: 'bar' }; + } + + _makeUrl () { + return 'https://jsru.firebaseio.com/rest/model' + (this.id ? `/${this.id}/` : '/') +'data.json'; + } + + save () { + // 1. Создаём новый объект XMLHttpRequest + var XHR = (window.XMLHttpRequest && "onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; + + var xhr = new XHR(); + + // 2. Конфигурируем его + xhr.open('POST', this.url, true); + + // 3. Отсылаем запрос + xhr.send(JSON.stringify(this.data)); + + xhr.onreadystatechange = function() { // (3) + if (xhr.readyState != 4) return; + + if (xhr.status != 200) { + alert(xhr.status + ': ' + xhr.statusText); + } else { + this.id = JSON.parse(xhr.responseText).name + // this.url = this._makeUrl(); + } + }.bind(this); + + return xhr; + } + + fetch () { + + if (!this.id) { + return alert('Нечего загружать!') + } + + // 1. Создаём новый объект XMLHttpRequest + var XHR = (window.XMLHttpRequest && "onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; + + var xhr = new XHR(); + + // 2. Конфигурируем его + xhr.open('GET', this.url, true); + + // 3. Отсылаем запрос + xhr.send(); + + xhr.onreadystatechange = function() { // (3) + if (xhr.readyState != 4) return; + + if (xhr.status != 200) { + alert(xhr.status + ': ' + xhr.statusText); + } else { + var data = JSON.parse(xhr.responseText); + + if (data[this.id]) { + this.setData(data[this.id]); + } + } + }.bind(this) + + return xhr; + } + + setData (data) { + this.data = data; + } + } + + //Export + return Model; +}) \ No newline at end of file diff --git a/template.js b/template.js new file mode 100644 index 0000000..159b889 --- /dev/null +++ b/template.js @@ -0,0 +1,20 @@ +define(function () { + 'use strict'; + var TemplateEngine = function(html, options) { + var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0, match; + var add = function(line, js) { + js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') : + (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : ''); + return add; + } + while(match = re.exec(html)) { + add(html.slice(cursor, match.index))(match[1], true); + cursor = match.index + match[0].length; + } + add(html.substr(cursor, html.length - cursor)); + code += 'return r.join("");'; + return new Function(code.replace(/[\r\t\n]/g, '')).apply(options); + } + + return TemplateEngine; +}) \ No newline at end of file